From edaa7a1ba1ace689c3c44a3b3820b56fd83945df Mon Sep 17 00:00:00 2001 From: Ichito Nagata Date: Sun, 3 Jun 2018 19:40:33 +0900 Subject: fix env->stack misadjusting --- src/vm.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/vm.c b/src/vm.c index c9e923ee0..ba2c32972 100644 --- a/src/vm.c +++ b/src/vm.c @@ -141,7 +141,7 @@ stack_init(mrb_state *mrb) } static inline void -envadjust(mrb_state *mrb, mrb_value *oldbase, mrb_value *newbase, size_t size) +envadjust(mrb_state *mrb, mrb_value *oldbase, mrb_value *newbase, size_t oldsize) { mrb_callinfo *ci = mrb->c->cibase; @@ -151,7 +151,7 @@ envadjust(mrb_state *mrb, mrb_value *oldbase, mrb_value *newbase, size_t size) mrb_value *st; if (e && MRB_ENV_STACK_SHARED_P(e) && - (st = e->stack) && oldbase <= st && st < oldbase+size) { + (st = e->stack) && oldbase <= st && st < oldbase+oldsize) { ptrdiff_t off = e->stack - oldbase; e->stack = newbase + off; @@ -161,7 +161,7 @@ envadjust(mrb_state *mrb, mrb_value *oldbase, mrb_value *newbase, size_t size) e = MRB_PROC_ENV(ci->proc); if (e && MRB_ENV_STACK_SHARED_P(e) && - (st = e->stack) && oldbase <= st && st < oldbase+size) { + (st = e->stack) && oldbase <= st && st < oldbase+oldsize) { ptrdiff_t off = e->stack - oldbase; e->stack = newbase + off; @@ -205,7 +205,7 @@ stack_extend_alloc(mrb_state *mrb, int room) mrb_exc_raise(mrb, mrb_obj_value(mrb->stack_err)); } stack_clear(&(newstack[oldsize]), size - oldsize); - envadjust(mrb, oldbase, newstack, size); + envadjust(mrb, oldbase, newstack, oldsize); mrb->c->stbase = newstack; mrb->c->stack = mrb->c->stbase + off; mrb->c->stend = mrb->c->stbase + size; -- cgit v1.2.3 From e7a46991353b3ab5aa0bc45403b87beacca3c31c Mon Sep 17 00:00:00 2001 From: Sebastián Katzer Date: Tue, 5 Jun 2018 15:59:12 +0200 Subject: Declare inet_ntop and inet_pton as static To avoid conflicts with multiple definitions of inet_ntop and inet_pton if compiled with # define _WIN32_WINNT _WIN32_WINNT_VISTA C:/mingw-w64/x86_64-7.2.0-posix-seh-rt_v5-rev1/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/7.2.0/../../../../x86_64-w64-mingw32/lib/../lib/libWs2_32.a(dghfs00169.o):(.text+0x0): multiple definition of `inet_pton' 722C:/projects/iss/mruby/build/host/lib/libmruby.a(socket.o):C:/projects/iss/mruby/mrbgems/mruby-socket/src/socket.c:80: first defined here define _WIN32_WINNT _WIN32_WINNT_VISTA --- mrbgems/mruby-socket/src/socket.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mrbgems/mruby-socket/src/socket.c b/mrbgems/mruby-socket/src/socket.c index 4d56d5374..037400077 100644 --- a/mrbgems/mruby-socket/src/socket.c +++ b/mrbgems/mruby-socket/src/socket.c @@ -51,7 +51,7 @@ #endif #ifdef _WIN32 -const char *inet_ntop(int af, const void *src, char *dst, socklen_t cnt) +static const char *inet_ntop(int af, const void *src, char *dst, socklen_t cnt) { if (af == AF_INET) { @@ -76,7 +76,7 @@ const char *inet_ntop(int af, const void *src, char *dst, socklen_t cnt) return NULL; } -int inet_pton(int af, const char *src, void *dst) +static int inet_pton(int af, const char *src, void *dst) { struct addrinfo hints, *res, *ressave; -- cgit v1.2.3 From c2b2bec9e239cb9bca1186e546fe6483ca9e2024 Mon Sep 17 00:00:00 2001 From: Ichito Nagata Date: Wed, 6 Jun 2018 15:04:58 +0900 Subject: Revert "Fix heap use after free on mruby-aws-sigv4." This reverts commit b8869498b7b1458af1cf2a5ccc7644849f826230. --- src/vm.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/vm.c b/src/vm.c index ba2c32972..f1eae5ba5 100644 --- a/src/vm.c +++ b/src/vm.c @@ -528,8 +528,6 @@ mrb_exec_irep(mrb_state *mrb, mrb_value self, struct RProc *p) return MRB_PROC_CFUNC(p)(mrb, self); } ci->nregs = p->body.irep->nregs; - ci->env = MRB_PROC_ENV(p); - if (ci->env) ci->env->stack[0] = self; if (ci->argc < 0) keep = 3; else keep = ci->argc + 2; if (ci->nregs < keep) { -- cgit v1.2.3 From 1dbeda5c9cfe60b0dbdf94a8fea7e12a721ff162 Mon Sep 17 00:00:00 2001 From: Ichito Nagata Date: Wed, 6 Jun 2018 15:35:41 +0900 Subject: add test for eval --- mrbgems/mruby-eval/test/eval.rb | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/mrbgems/mruby-eval/test/eval.rb b/mrbgems/mruby-eval/test/eval.rb index 66ca1fcdb..be43412f7 100644 --- a/mrbgems/mruby-eval/test/eval.rb +++ b/mrbgems/mruby-eval/test/eval.rb @@ -99,3 +99,19 @@ assert('Object#instance_eval with begin-rescue-ensure execution order') do hell_raiser = HellRaiser.new assert_equal([:enter_raise_hell, :begin, :rescue, :ensure], hell_raiser.raise_hell) end + +assert('Kernel.#eval(strinng) Issue #4021') do + assert_equal('FOO') { (eval <<'EOS').call } +foo = "FOO" +Proc.new { foo } +EOS + assert_equal('FOO') { + def do_eval(code) + eval(code) + end + do_eval(<<'EOS').call +foo = "FOO" +Proc.new { foo } +EOS + } +end -- cgit v1.2.3 From ff0a4f78674308b7643db1da9b9dc591f25c21d0 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Thu, 7 Jun 2018 15:55:20 +0900 Subject: Export `stack_extend` function (renamed `mrb_stack_extend`); fix #3219 This change is required to support #4038. --- include/mruby.h | 1 + src/vm.c | 46 +++++++++++++++++++++++----------------------- 2 files changed, 24 insertions(+), 23 deletions(-) diff --git a/include/mruby.h b/include/mruby.h index 3b953a327..8c4f9280b 100644 --- a/include/mruby.h +++ b/include/mruby.h @@ -1235,6 +1235,7 @@ MRB_API mrb_value mrb_fiber_alive_p(mrb_state *mrb, mrb_value fib); * @mrbgem mruby-fiber */ #define E_FIBER_ERROR (mrb_exc_get(mrb, "FiberError")) +MRB_API void mrb_stack_extend(mrb_state*, int); /* memory pool implementation */ typedef struct mrb_pool mrb_pool; diff --git a/src/vm.c b/src/vm.c index ba2c32972..3ebdea310 100644 --- a/src/vm.c +++ b/src/vm.c @@ -217,8 +217,8 @@ stack_extend_alloc(mrb_state *mrb, int room) } } -static inline void -stack_extend(mrb_state *mrb, int room) +MRB_API void +mrb_stack_extend(mrb_state *mrb, int room) { if (mrb->c->stack + room >= mrb->c->stend) { stack_extend_alloc(mrb, room); @@ -446,7 +446,7 @@ mrb_funcall_with_block(mrb_state *mrb, mrb_value self, mrb_sym mid, mrb_int argc mrb_method_missing(mrb, mid, self, args); } mrb_ary_unshift(mrb, args, mrb_symbol_value(mid)); - stack_extend(mrb, n+2); + mrb_stack_extend(mrb, n+2); mrb->c->stack[n+1] = args; argc = -1; } @@ -464,11 +464,11 @@ mrb_funcall_with_block(mrb_state *mrb, mrb_value self, mrb_sym mid, mrb_int argc } if (MRB_METHOD_CFUNC_P(m)) { ci->nregs = (int)(argc + 2); - stack_extend(mrb, ci->nregs); + mrb_stack_extend(mrb, ci->nregs); } else if (argc >= CALL_MAXARGS) { mrb_value args = mrb_ary_new_from_values(mrb, argc, argv); - stack_extend(mrb, ci->nregs+2); + mrb_stack_extend(mrb, ci->nregs+2); mrb->c->stack[1] = args; ci->argc = -1; argc = 1; @@ -478,7 +478,7 @@ mrb_funcall_with_block(mrb_state *mrb, mrb_value self, mrb_sym mid, mrb_int argc ci->proc = p; if (argc < 0) argc = 1; ci->nregs = (int)(p->body.irep->nregs + argc); - stack_extend(mrb, ci->nregs); + mrb_stack_extend(mrb, ci->nregs); } if (voff >= 0) { argv = mrb->c->stbase + voff; @@ -533,10 +533,10 @@ mrb_exec_irep(mrb_state *mrb, mrb_value self, struct RProc *p) if (ci->argc < 0) keep = 3; else keep = ci->argc + 2; if (ci->nregs < keep) { - stack_extend(mrb, keep); + mrb_stack_extend(mrb, keep); } else { - stack_extend(mrb, ci->nregs); + mrb_stack_extend(mrb, ci->nregs); stack_clear(mrb->c->stack+keep, ci->nregs-keep); } @@ -635,14 +635,14 @@ eval_under(mrb_state *mrb, mrb_value self, mrb_value blk, struct RClass *c) ci->argc = 1; ci->mid = ci[-1].mid; if (MRB_PROC_CFUNC_P(p)) { - stack_extend(mrb, 3); + mrb_stack_extend(mrb, 3); mrb->c->stack[0] = self; mrb->c->stack[1] = self; mrb->c->stack[2] = mrb_nil_value(); return MRB_PROC_CFUNC(p)(mrb, self); } ci->nregs = p->body.irep->nregs; - stack_extend(mrb, (ci->nregs < 3) ? 3 : ci->nregs); + mrb_stack_extend(mrb, (ci->nregs < 3) ? 3 : ci->nregs); mrb->c->stack[0] = self; mrb->c->stack[1] = self; mrb->c->stack[2] = mrb_nil_value(); @@ -749,7 +749,7 @@ mrb_yield_with_class(mrb_state *mrb, mrb_value b, mrb_int argc, const mrb_value ci->acc = CI_ACC_SKIP; mrb->c->stack = mrb->c->stack + n; ci->nregs = MRB_PROC_CFUNC_P(p) ? (int)(argc+2) : p->body.irep->nregs; - stack_extend(mrb, ci->nregs); + mrb_stack_extend(mrb, ci->nregs); mrb->c->stack[0] = self; if (argc > 0) { @@ -800,7 +800,7 @@ mrb_yield_cont(mrb_state *mrb, mrb_value b, mrb_value self, mrb_int argc, const p = mrb_proc_ptr(b); ci = mrb->c->ci; - stack_extend(mrb, 3); + mrb_stack_extend(mrb, 3); mrb->c->stack[1] = mrb_ary_new_from_values(mrb, argc, argv); mrb->c->stack[2] = mrb_nil_value(); ci->argc = -1; @@ -944,7 +944,7 @@ mrb_vm_run(mrb_state *mrb, struct RProc *proc, mrb_value self, unsigned int stac } if (stack_keep > nregs) nregs = stack_keep; - stack_extend(mrb, nregs); + mrb_stack_extend(mrb, nregs); stack_clear(c->stack + stack_keep, nregs - stack_keep); c->stack[0] = self; result = mrb_vm_exec(mrb, proc, irep->iseq); @@ -1373,7 +1373,7 @@ RETRY_TRY_BLOCK: ci->pc = pc; ci->acc = ci[-1].nregs; mrb->c->stack += ci->acc; - stack_extend(mrb, ci->nregs); + mrb_stack_extend(mrb, ci->nregs); regs[0] = self; pc = irep->iseq; } @@ -1437,7 +1437,7 @@ RETRY_TRY_BLOCK: } if (argc >= 0) { if (a+2 >= irep->nregs) { - stack_extend(mrb, a+3); + mrb_stack_extend(mrb, a+3); } regs[a+1] = mrb_ary_new_from_values(mrb, n, regs+a+1); regs[a+2] = blk; @@ -1510,7 +1510,7 @@ RETRY_TRY_BLOCK: pool = irep->pool; syms = irep->syms; ci->nregs = irep->nregs; - stack_extend(mrb, (argc < 0 && ci->nregs < 3) ? 3 : ci->nregs); + mrb_stack_extend(mrb, (argc < 0 && ci->nregs < 3) ? 3 : ci->nregs); pc = irep->iseq; JUMP; } @@ -1571,7 +1571,7 @@ RETRY_TRY_BLOCK: pool = irep->pool; syms = irep->syms; ci->nregs = irep->nregs; - stack_extend(mrb, ci->nregs); + mrb_stack_extend(mrb, ci->nregs); if (ci->argc < 0) { if (irep->nregs > 3) { stack_clear(regs+3, irep->nregs-3); @@ -1648,7 +1648,7 @@ RETRY_TRY_BLOCK: mid = missing; if (argc >= 0) { if (a+2 >= ci->nregs) { - stack_extend(mrb, a+3); + mrb_stack_extend(mrb, a+3); } regs[a+1] = mrb_ary_new_from_values(mrb, n, regs+a+1); regs[a+2] = blk; @@ -1709,7 +1709,7 @@ RETRY_TRY_BLOCK: pool = irep->pool; syms = irep->syms; ci->nregs = irep->nregs; - stack_extend(mrb, (argc < 0 && ci->nregs < 3) ? 3 : ci->nregs); + mrb_stack_extend(mrb, (argc < 0 && ci->nregs < 3) ? 3 : ci->nregs); pc = irep->iseq; JUMP; } @@ -1967,7 +1967,7 @@ RETRY_TRY_BLOCK: if (ci < ci0) { mrb->c->stack = ci[1].stackent; } - stack_extend(mrb, irep->nregs); + mrb_stack_extend(mrb, irep->nregs); pc = mrb->c->rescue[--ci->ridx]; } else { @@ -2200,10 +2200,10 @@ RETRY_TRY_BLOCK: pool = irep->pool; syms = irep->syms; if (ci->argc < 0) { - stack_extend(mrb, (irep->nregs < 3) ? 3 : irep->nregs); + mrb_stack_extend(mrb, (irep->nregs < 3) ? 3 : irep->nregs); } else { - stack_extend(mrb, irep->nregs); + mrb_stack_extend(mrb, irep->nregs); } pc = irep->iseq; } @@ -2877,7 +2877,7 @@ RETRY_TRY_BLOCK: pool = irep->pool; syms = irep->syms; ci->nregs = irep->nregs; - stack_extend(mrb, ci->nregs); + mrb_stack_extend(mrb, ci->nregs); stack_clear(regs+1, ci->nregs-1); pc = irep->iseq; JUMP; -- cgit v1.2.3 From 778500563a9f7ceba996937dc886bd8cde29b42b Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Thu, 7 Jun 2018 15:59:00 +0900 Subject: Extend stack when pushing arguments that does not fit in; fix #4038 --- mrbgems/mruby-fiber/src/fiber.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/mrbgems/mruby-fiber/src/fiber.c b/mrbgems/mruby-fiber/src/fiber.c index 83153a9df..b88fa4949 100644 --- a/mrbgems/mruby-fiber/src/fiber.c +++ b/mrbgems/mruby-fiber/src/fiber.c @@ -184,26 +184,27 @@ fiber_switch(mrb_state *mrb, mrb_value self, mrb_int len, const mrb_value *a, mr { struct mrb_context *c = fiber_check(mrb, self); struct mrb_context *old_c = mrb->c; + enum mrb_fiber_state status; mrb_value value; fiber_check_cfunc(mrb, c); - if (resume && c->status == MRB_FIBER_TRANSFERRED) { + status = c->status; + if (resume && status == MRB_FIBER_TRANSFERRED) { mrb_raise(mrb, E_FIBER_ERROR, "resuming transferred fiber"); } - if (c->status == MRB_FIBER_RUNNING || c->status == MRB_FIBER_RESUMED) { + if (status == MRB_FIBER_RUNNING || status == MRB_FIBER_RESUMED) { mrb_raise(mrb, E_FIBER_ERROR, "double resume (fib)"); } - if (c->status == MRB_FIBER_TERMINATED) { + if (status == MRB_FIBER_TERMINATED) { mrb_raise(mrb, E_FIBER_ERROR, "resuming dead fiber"); } - mrb->c->status = resume ? MRB_FIBER_RESUMED : MRB_FIBER_TRANSFERRED; + old_c->status = resume ? MRB_FIBER_RESUMED : MRB_FIBER_TRANSFERRED; c->prev = resume ? mrb->c : (c->prev ? c->prev : mrb->root_c); - if (c->status == MRB_FIBER_CREATED) { + fiber_switch_context(mrb, c); + if (status == MRB_FIBER_CREATED) { mrb_value *b, *e; - if (len >= c->stend - c->stack) { - mrb_raise(mrb, E_FIBER_ERROR, "too many arguments to fiber"); - } + mrb_stack_extend(mrb, len+2); /* for receiver and (optional) block */ b = c->stack+1; e = b + len; while (bvmexec = TRUE; -- cgit v1.2.3 From 55edae0226409de25e59922807cb09acb45731a2 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Thu, 7 Jun 2018 16:17:00 +0900 Subject: Allow `Object#clone` to copy frozen status only; fix #4036 Copying all flags from the original object may overwrite the clone's flags e.g. the embedded flag. --- src/kernel.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/kernel.c b/src/kernel.c index f378004cb..bbe6e8bb7 100644 --- a/src/kernel.c +++ b/src/kernel.c @@ -348,7 +348,7 @@ mrb_obj_clone(mrb_state *mrb, mrb_value self) mrb_field_write_barrier(mrb, (struct RBasic*)p, (struct RBasic*)p->c); clone = mrb_obj_value(p); init_copy(mrb, clone, self); - p->flags = mrb_obj_ptr(self)->flags; + p->flags |= mrb_obj_ptr(self)->flags & MRB_FLAG_IS_FROZEN; return clone; } -- cgit v1.2.3 From faa4eaf6803bd11669bc324b4c34e7162286bfa3 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Fri, 8 Jun 2018 14:13:06 +0900 Subject: `mrb_class_real()` did not work for `BasicObject`; fix #4037 --- src/class.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/class.c b/src/class.c index c761f46af..a9439d7d7 100644 --- a/src/class.c +++ b/src/class.c @@ -1763,10 +1763,10 @@ mrb_class_path(mrb_state *mrb, struct RClass *c) MRB_API struct RClass* mrb_class_real(struct RClass* cl) { - if (cl == 0) - return NULL; + if (cl == 0) return NULL; while ((cl->tt == MRB_TT_SCLASS) || (cl->tt == MRB_TT_ICLASS)) { cl = cl->super; + if (cl == 0) return NULL; } return cl; } -- cgit v1.2.3 From a9b740b36b4518552d61f349afc02c325413d2ad Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Mon, 11 Jun 2018 14:50:03 +0900 Subject: Retrieve `b` operand from the instruction (for debugging); ref #4020 --- src/vm.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/vm.c b/src/vm.c index 59ae57c32..552bc8072 100644 --- a/src/vm.c +++ b/src/vm.c @@ -1398,6 +1398,7 @@ RETRY_TRY_BLOCK: CASE(OP_SEND) { /* A B C R(A) := call(R(A),Syms(B),R(A+1),...,R(A+C)) */ int a = GETARG_A(i); + int b = GETARG_B(i); int n = GETARG_C(i); int argc = (n == CALL_MAXARGS) ? -1 : n; int bidx = (argc < 0) ? a+2 : a+n+1; @@ -1405,7 +1406,7 @@ RETRY_TRY_BLOCK: struct RClass *c; mrb_callinfo *ci = mrb->c->ci; mrb_value recv, blk; - mrb_sym mid = syms[GETARG_B(i)]; + mrb_sym mid = syms[b]; mrb_assert(bidx < ci->nregs); -- cgit v1.2.3 From 23a4e7149dc4253caf5ed0a528ffe5c21c4afb80 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Mon, 11 Jun 2018 14:50:42 +0900 Subject: Revert "No longer need to insert write barriers for fibers." This reverts commit c6736357a72049a0eb2a31ccabcc3cd2baba7c9e. The assumption was wrong and caused the issue; fix #4020 --- mrbgems/mruby-fiber/src/fiber.c | 3 +++ src/vm.c | 10 +++++++++- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/mrbgems/mruby-fiber/src/fiber.c b/mrbgems/mruby-fiber/src/fiber.c index b88fa4949..bff8726a7 100644 --- a/mrbgems/mruby-fiber/src/fiber.c +++ b/mrbgems/mruby-fiber/src/fiber.c @@ -175,6 +175,9 @@ fiber_check_cfunc(mrb_state *mrb, struct mrb_context *c) static void fiber_switch_context(mrb_state *mrb, struct mrb_context *c) { + if (mrb->c->fib) { + mrb_write_barrier(mrb, (struct RBasic*)mrb->c->fib); + } c->status = MRB_FIBER_RUNNING; mrb->c = c; } diff --git a/src/vm.c b/src/vm.c index 552bc8072..43efaa669 100644 --- a/src/vm.c +++ b/src/vm.c @@ -949,7 +949,12 @@ mrb_vm_run(mrb_state *mrb, struct RProc *proc, mrb_value self, unsigned int stac if (c->ci - c->cibase > cioff) { c->ci = c->cibase + cioff; } - mrb->c = c; + if (mrb->c != c) { + if (mrb->c->fib) { + mrb_write_barrier(mrb, (struct RBasic*)mrb->c->fib); + } + mrb->c = c; + } return result; } @@ -1942,6 +1947,9 @@ RETRY_TRY_BLOCK: while (c->eidx > ci->epos) { ecall_adjust(); } + if (c->fib) { + mrb_write_barrier(mrb, (struct RBasic*)c->fib); + } mrb->c->status = MRB_FIBER_TERMINATED; mrb->c = c->prev; c->prev = NULL; -- cgit v1.2.3 From f715f2ddeacdf6301e8882b771252080b90d2b18 Mon Sep 17 00:00:00 2001 From: take-cheeze Date: Wed, 13 Jun 2018 23:32:08 +0900 Subject: Fix unnecessary rebuild of tests. --- mrbgems/mruby-test/mrbgem.rake | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/mrbgems/mruby-test/mrbgem.rake b/mrbgems/mruby-test/mrbgem.rake index 7da0b5e50..27c635a5d 100644 --- a/mrbgems/mruby-test/mrbgem.rake +++ b/mrbgems/mruby-test/mrbgem.rake @@ -155,14 +155,18 @@ MRuby::Gem::Specification.new('mruby-test') do |spec| # store the last gem selection and make the re-build # of the test gem depending on a change to the gem # selection - active_gems = "#{build_dir}/active_gems.lst" - FileUtils.mkdir_p File.dirname(active_gems) - open(active_gems, 'w+') do |f| - build.gems.each do |g| - f.puts g.name - end + active_gems_path = "#{build_dir}/active_gems_path.lst" + active_gem_list = if File.exist? active_gems_path + File.read active_gems_path + else + FileUtils.mkdir_p File.dirname(active_gems_path) + nil + end + current_gem_list = build.gems.map(&:name).join("\n") + if active_gem_list != current_gem_list + File.write active_gems_path, current_gem_list end - file clib => active_gems + file clib => active_gems_path file mlib => clib file clib => init do |t| -- cgit v1.2.3 From a7f77fefa9842f6a46734caea800250f0be8588c Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Thu, 14 Jun 2018 11:13:50 +0900 Subject: Check for switching to uninitialized fiber; fix #4041 The problem was caused by `Fiber.current.resume'. --- mrbgems/mruby-fiber/src/fiber.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/mrbgems/mruby-fiber/src/fiber.c b/mrbgems/mruby-fiber/src/fiber.c index bff8726a7..27b74dba5 100644 --- a/mrbgems/mruby-fiber/src/fiber.c +++ b/mrbgems/mruby-fiber/src/fiber.c @@ -196,7 +196,7 @@ fiber_switch(mrb_state *mrb, mrb_value self, mrb_int len, const mrb_value *a, mr mrb_raise(mrb, E_FIBER_ERROR, "resuming transferred fiber"); } if (status == MRB_FIBER_RUNNING || status == MRB_FIBER_RESUMED) { - mrb_raise(mrb, E_FIBER_ERROR, "double resume (fib)"); + mrb_raise(mrb, E_FIBER_ERROR, "double resume"); } if (status == MRB_FIBER_TERMINATED) { mrb_raise(mrb, E_FIBER_ERROR, "resuming dead fiber"); @@ -207,6 +207,9 @@ fiber_switch(mrb_state *mrb, mrb_value self, mrb_int len, const mrb_value *a, mr if (status == MRB_FIBER_CREATED) { mrb_value *b, *e; + if (!c->ci->proc) { + mrb_raise(mrb, E_FIBER_ERROR, "double resume (current)"); + } mrb_stack_extend(mrb, len+2); /* for receiver and (optional) block */ b = c->stack+1; e = b + len; -- cgit v1.2.3 From ba090a46af56355d8c4a458f8000cceae26d1c4f Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Thu, 14 Jun 2018 11:25:12 +0900 Subject: Need to add a write barrier for ranges; fix #4042 Ranges are almost immutable but `initialize` and `initialize_copy` modify the receiver so that we need to add a write barrier. --- src/range.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/range.c b/src/range.c index 0360b48ae..e45308d35 100644 --- a/src/range.c +++ b/src/range.c @@ -120,6 +120,7 @@ range_init(mrb_state *mrb, mrb_value range, mrb_value beg, mrb_value end, mrb_bo } r->edges->beg = beg; r->edges->end = end; + mrb_write_barrier(mrb, (struct RBasic*)r); } /* * call-seq: -- cgit v1.2.3 From 97933665b6c427348983bab936a5d855f1384712 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Thu, 14 Jun 2018 11:42:34 +0900 Subject: Restore GC arena after raised exceptions; ref #4042 --- src/vm.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/vm.c b/src/vm.c index 43efaa669..7a436828a 100644 --- a/src/vm.c +++ b/src/vm.c @@ -1002,6 +1002,7 @@ RETRY_TRY_BLOCK: if (exc_catched) { exc_catched = FALSE; + mrb_gc_arena_restore(mrb, ai); if (mrb->exc && mrb->exc->tt == MRB_TT_BREAK) goto L_BREAK; goto L_RAISE; -- cgit v1.2.3 From 3618556a95957f82f6fd853af239eb8ce9fa689b Mon Sep 17 00:00:00 2001 From: Tomoyuki Sahara Date: Thu, 14 Jun 2018 13:25:57 +0900 Subject: struct sockaddr_un can be shorter than struct sockaddr. ref: https://github.com/iij/mruby-socket/issues/45 --- mrbgems/mruby-socket/src/socket.c | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/mrbgems/mruby-socket/src/socket.c b/mrbgems/mruby-socket/src/socket.c index 037400077..5a8db93d7 100644 --- a/mrbgems/mruby-socket/src/socket.c +++ b/mrbgems/mruby-socket/src/socket.c @@ -664,19 +664,15 @@ mrb_socket_listen(mrb_state *mrb, mrb_value klass) static mrb_value mrb_socket_sockaddr_family(mrb_state *mrb, mrb_value klass) { - mrb_value sa; + const struct sockaddr *sa; + mrb_value str; - mrb_get_args(mrb, "S", &sa); -#ifdef __linux__ - if ((size_t)RSTRING_LEN(sa) < offsetof(struct sockaddr, sa_family) + sizeof(sa_family_t)) { - mrb_raisef(mrb, E_SOCKET_ERROR, "invalid sockaddr (too short)"); - } -#else - if ((size_t)RSTRING_LEN(sa) < sizeof(struct sockaddr)) { + mrb_get_args(mrb, "S", &str); + if ((size_t)RSTRING_LEN(str) < offsetof(struct sockaddr, sa_family) + sizeof(sa_family_t)) { mrb_raisef(mrb, E_SOCKET_ERROR, "invalid sockaddr (too short)"); } -#endif - return mrb_fixnum_value(((struct sockaddr *)RSTRING_PTR(sa))->sa_family); + sa = (const struct sockaddr *)RSTRING_PTR(str); + return mrb_fixnum_value(sa->sa_family); } static mrb_value -- cgit v1.2.3 From 5013d2b20f85819f78c5b5bc4f2f3b8cfc17d89f Mon Sep 17 00:00:00 2001 From: Tomoyuki Sahara Date: Thu, 14 Jun 2018 13:28:32 +0900 Subject: struct sockaddr_un can be truncated. When we have "struct sockaddr_un *s_un", we could not assume *s_un points to a memory region which size is at least sizeof(*s_un). Even worse, it may be shorter than sizeof(struct sockaddr) on some systems. --- mrbgems/mruby-socket/src/socket.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/mrbgems/mruby-socket/src/socket.c b/mrbgems/mruby-socket/src/socket.c index 5a8db93d7..33c8d4455 100644 --- a/mrbgems/mruby-socket/src/socket.c +++ b/mrbgems/mruby-socket/src/socket.c @@ -214,7 +214,11 @@ mrb_addrinfo_unix_path(mrb_state *mrb, mrb_value self) sastr = mrb_iv_get(mrb, self, mrb_intern_lit(mrb, "@sockaddr")); if (((struct sockaddr *)RSTRING_PTR(sastr))->sa_family != AF_UNIX) mrb_raise(mrb, E_SOCKET_ERROR, "need AF_UNIX address"); - return mrb_str_new_cstr(mrb, ((struct sockaddr_un *)RSTRING_PTR(sastr))->sun_path); + if (RSTRING_LEN(sastr) < offsetof(struct sockaddr_un, sun_path) + 1) { + return mrb_str_new(mrb, "", 0); + } else { + return mrb_str_new_cstr(mrb, ((struct sockaddr_un *)RSTRING_PTR(sastr))->sun_path); + } } #endif -- cgit v1.2.3 From 2eeac910988d9fa4b4e0f19992e8ce3be1d768e9 Mon Sep 17 00:00:00 2001 From: Tomoyuki Sahara Date: Thu, 14 Jun 2018 13:36:01 +0900 Subject: set sockaddr_un.sun_len on the systems that have sockaddr.sa_len. If your system has sa_len but is not BSD-derived, define HAVE_SA_LEN=1 on mrbgem.rake or build_config.rb. --- mrbgems/mruby-socket/mrbgem.rake | 1 + mrbgems/mruby-socket/src/socket.c | 12 ++++++++++++ 2 files changed, 13 insertions(+) diff --git a/mrbgems/mruby-socket/mrbgem.rake b/mrbgems/mruby-socket/mrbgem.rake index 8096815eb..b0894e095 100644 --- a/mrbgems/mruby-socket/mrbgem.rake +++ b/mrbgems/mruby-socket/mrbgem.rake @@ -4,6 +4,7 @@ MRuby::Gem::Specification.new('mruby-socket') do |spec| spec.summary = 'standard socket class' spec.cc.include_paths << "#{build.root}/src" + #spec.cc.defines << "HAVE_SA_LEN=0" # If Windows, use winsock if ( /mswin|mingw|win32/ =~ RUBY_PLATFORM ) then diff --git a/mrbgems/mruby-socket/src/socket.c b/mrbgems/mruby-socket/src/socket.c index 33c8d4455..951bece75 100644 --- a/mrbgems/mruby-socket/src/socket.c +++ b/mrbgems/mruby-socket/src/socket.c @@ -19,6 +19,7 @@ #else #include #include + #include #include #include #include @@ -42,6 +43,14 @@ #include "mruby/ext/io.h" +#if !defined(HAVE_SA_LEN) +#if (defined(BSD) && (BSD >= 199006)) +#define HAVE_SA_LEN 1 +#else +#define HAVE_SA_LEN 0 +#endif +#endif + #define E_SOCKET_ERROR (mrb_class_get(mrb, "SocketError")) #if !defined(mrb_cptr) @@ -695,6 +704,9 @@ mrb_socket_sockaddr_un(mrb_state *mrb, mrb_value klass) } s = mrb_str_buf_new(mrb, sizeof(struct sockaddr_un)); sunp = (struct sockaddr_un *)RSTRING_PTR(s); +#if HAVE_SA_LEN + sunp->sun_len = sizeof(struct sockaddr_un); +#endif sunp->sun_family = AF_UNIX; memcpy(sunp->sun_path, RSTRING_PTR(path), RSTRING_LEN(path)); sunp->sun_path[RSTRING_LEN(path)] = '\0'; -- cgit v1.2.3 From af8020e7fd6e85672ce41698469f4bacf1f424c2 Mon Sep 17 00:00:00 2001 From: Tomoyuki Sahara Date: Thu, 14 Jun 2018 13:52:37 +0900 Subject: sa_family_t is not defined on windows. --- mrbgems/mruby-socket/src/socket.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mrbgems/mruby-socket/src/socket.c b/mrbgems/mruby-socket/src/socket.c index 951bece75..89c31c767 100644 --- a/mrbgems/mruby-socket/src/socket.c +++ b/mrbgems/mruby-socket/src/socket.c @@ -681,7 +681,7 @@ mrb_socket_sockaddr_family(mrb_state *mrb, mrb_value klass) mrb_value str; mrb_get_args(mrb, "S", &str); - if ((size_t)RSTRING_LEN(str) < offsetof(struct sockaddr, sa_family) + sizeof(sa_family_t)) { + if ((size_t)RSTRING_LEN(str) < offsetof(struct sockaddr, sa_family) + sizeof(sa->sa_family)) { mrb_raisef(mrb, E_SOCKET_ERROR, "invalid sockaddr (too short)"); } sa = (const struct sockaddr *)RSTRING_PTR(str); -- cgit v1.2.3 From 70600c3ba80c4aa212dbc1e57b2c12472b04d1de Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Thu, 14 Jun 2018 14:16:04 +0900 Subject: Resolve sign comparison warning; ref #4044 --- mrbgems/mruby-socket/src/socket.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mrbgems/mruby-socket/src/socket.c b/mrbgems/mruby-socket/src/socket.c index 89c31c767..6c765c5cb 100644 --- a/mrbgems/mruby-socket/src/socket.c +++ b/mrbgems/mruby-socket/src/socket.c @@ -223,7 +223,7 @@ mrb_addrinfo_unix_path(mrb_state *mrb, mrb_value self) sastr = mrb_iv_get(mrb, self, mrb_intern_lit(mrb, "@sockaddr")); if (((struct sockaddr *)RSTRING_PTR(sastr))->sa_family != AF_UNIX) mrb_raise(mrb, E_SOCKET_ERROR, "need AF_UNIX address"); - if (RSTRING_LEN(sastr) < offsetof(struct sockaddr_un, sun_path) + 1) { + if (RSTRING_LEN(sastr) < (mrb_int)offsetof(struct sockaddr_un, sun_path) + 1) { return mrb_str_new(mrb, "", 0); } else { return mrb_str_new_cstr(mrb, ((struct sockaddr_un *)RSTRING_PTR(sastr))->sun_path); -- cgit v1.2.3 From a9abf65f033b080cae018c5f4a9b4987e2138af6 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Fri, 15 Jun 2018 07:47:18 +0900 Subject: Fixed wrong usages of `mrb_raisef()`; ref #4043 `mrb_raisef()` only takes `%S` specifier. If you don't have extra arguments, use `mrb_raise()`. --- mrbgems/mruby-inline-struct/test/inline.c | 2 +- mrbgems/mruby-pack/src/pack.c | 4 ++-- mrbgems/mruby-socket/src/socket.c | 12 ++++++------ 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/mrbgems/mruby-inline-struct/test/inline.c b/mrbgems/mruby-inline-struct/test/inline.c index 0baaab617..95341d348 100644 --- a/mrbgems/mruby-inline-struct/test/inline.c +++ b/mrbgems/mruby-inline-struct/test/inline.c @@ -47,7 +47,7 @@ istruct_test_test_receive(mrb_state *mrb, mrb_value self) mrb_get_args(mrb, "o", &object); if (mrb_obj_class(mrb, object) != mrb_class_get(mrb, "InlineStructTest")) { - mrb_raisef(mrb, E_TYPE_ERROR, "Expected InlineStructTest"); + mrb_raise(mrb, E_TYPE_ERROR, "Expected InlineStructTest"); } return mrb_bool_value(((char*)mrb_istruct_ptr(object))[0] == 's'); } diff --git a/mrbgems/mruby-pack/src/pack.c b/mrbgems/mruby-pack/src/pack.c index d96ef1002..841a98f58 100644 --- a/mrbgems/mruby-pack/src/pack.c +++ b/mrbgems/mruby-pack/src/pack.c @@ -510,7 +510,7 @@ utf8_to_uv(mrb_state *mrb, const char *p, long *lenp) } if (n > *lenp) { mrb_raisef(mrb, E_ARGUMENT_ERROR, "malformed UTF-8 character (expected %S bytes, given %S bytes)", - mrb_fixnum_value(n), mrb_fixnum_value(*lenp)); + mrb_fixnum_value(n), mrb_fixnum_value(*lenp)); } *lenp = n--; if (n != 0) { @@ -1055,7 +1055,7 @@ alias: while (tmpl->idx < tlen && isdigit(tptr[tmpl->idx])) { count = count * 10 + (tptr[tmpl->idx++] - '0'); if (count < 0) { - mrb_raisef(mrb, E_RUNTIME_ERROR, "too big template length"); + mrb_raise(mrb, E_RUNTIME_ERROR, "too big template length"); } } continue; /* special case */ diff --git a/mrbgems/mruby-socket/src/socket.c b/mrbgems/mruby-socket/src/socket.c index 6c765c5cb..b3ca8b1c9 100644 --- a/mrbgems/mruby-socket/src/socket.c +++ b/mrbgems/mruby-socket/src/socket.c @@ -203,8 +203,8 @@ mrb_addrinfo_getnameinfo(mrb_state *mrb, mrb_value self) mrb_raise(mrb, E_SOCKET_ERROR, "invalid sockaddr"); } error = getnameinfo((struct sockaddr *)RSTRING_PTR(sastr), (socklen_t)RSTRING_LEN(sastr), RSTRING_PTR(host), NI_MAXHOST, RSTRING_PTR(serv), NI_MAXSERV, (int)flags); - if (error != 0) { - mrb_raisef(mrb, E_SOCKET_ERROR, "getnameinfo: %s", gai_strerror(error)); + if (error) { + mrb_raisef(mrb, E_SOCKET_ERROR, "getnameinfo: %S", mrb_str_new_cstr(mrb, gai_strerror(error))); } ary = mrb_ary_new_capa(mrb, 2); mrb_str_resize(mrb, host, strlen(RSTRING_PTR(host))); @@ -469,12 +469,12 @@ mrb_basicsocket_setsockopt(mrb_state *mrb, mrb_value self) } } else if (argc == 1) { if (strcmp(mrb_obj_classname(mrb, so), "Socket::Option") != 0) - mrb_raisef(mrb, E_ARGUMENT_ERROR, "not an instance of Socket::Option"); + mrb_raise(mrb, E_ARGUMENT_ERROR, "not an instance of Socket::Option"); level = mrb_fixnum(mrb_funcall(mrb, so, "level", 0)); optname = mrb_fixnum(mrb_funcall(mrb, so, "optname", 0)); optval = mrb_funcall(mrb, so, "data", 0); } else { - mrb_raisef(mrb, E_ARGUMENT_ERROR, "wrong number of arguments (%d for 3)", argc); + mrb_raisef(mrb, E_ARGUMENT_ERROR, "wrong number of arguments (%S for 3)", mrb_fixnum_value(argc)); } s = socket_fd(mrb, self); @@ -682,7 +682,7 @@ mrb_socket_sockaddr_family(mrb_state *mrb, mrb_value klass) mrb_get_args(mrb, "S", &str); if ((size_t)RSTRING_LEN(str) < offsetof(struct sockaddr, sa_family) + sizeof(sa->sa_family)) { - mrb_raisef(mrb, E_SOCKET_ERROR, "invalid sockaddr (too short)"); + mrb_raise(mrb, E_SOCKET_ERROR, "invalid sockaddr (too short)"); } sa = (const struct sockaddr *)RSTRING_PTR(str); return mrb_fixnum_value(sa->sa_family); @@ -700,7 +700,7 @@ mrb_socket_sockaddr_un(mrb_state *mrb, mrb_value klass) mrb_get_args(mrb, "S", &path); if ((size_t)RSTRING_LEN(path) > sizeof(sunp->sun_path) - 1) { - mrb_raisef(mrb, E_ARGUMENT_ERROR, "too long unix socket path (max: %ubytes)", (unsigned int)sizeof(sunp->sun_path) - 1); + mrb_raisef(mrb, E_ARGUMENT_ERROR, "too long unix socket path (max: %S bytes)", mrb_fixnum_value(sizeof(sunp->sun_path) - 1)); } s = mrb_str_buf_new(mrb, sizeof(struct sockaddr_un)); sunp = (struct sockaddr_un *)RSTRING_PTR(s); -- cgit v1.2.3 From fb9358206e29c8b018b3b8553e96bf35eb9a4a63 Mon Sep 17 00:00:00 2001 From: Kouhei Sutou Date: Tue, 19 Jun 2018 17:25:38 +0900 Subject: Fix wrong free function mrb_locale_free() should be used for the return value of mrb_locale_from_utf8(). --- mrbgems/mruby-bin-mirb/tools/mirb/mirb.c | 4 ++-- mrbgems/mruby-io/src/file.c | 4 ++-- mrbgems/mruby-io/src/io.c | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/mrbgems/mruby-bin-mirb/tools/mirb/mirb.c b/mrbgems/mruby-bin-mirb/tools/mirb/mirb.c index b494b13c9..5b77f5bac 100644 --- a/mrbgems/mruby-bin-mirb/tools/mirb/mirb.c +++ b/mrbgems/mruby-bin-mirb/tools/mirb/mirb.c @@ -599,13 +599,13 @@ done: /* warning */ char* msg = mrb_locale_from_utf8(parser->warn_buffer[0].message, -1); printf("line %d: %s\n", parser->warn_buffer[0].lineno, msg); - mrb_utf8_free(msg); + mrb_locale_free(msg); } if (0 < parser->nerr) { /* syntax error */ char* msg = mrb_locale_from_utf8(parser->error_buffer[0].message, -1); printf("line %d: %s\n", parser->error_buffer[0].lineno, msg); - mrb_utf8_free(msg); + mrb_locale_free(msg); } else { /* generate bytecode */ diff --git a/mrbgems/mruby-io/src/file.c b/mrbgems/mruby-io/src/file.c index 3dcfe3a0b..b3ad49297 100644 --- a/mrbgems/mruby-io/src/file.c +++ b/mrbgems/mruby-io/src/file.c @@ -310,7 +310,7 @@ mrb_file__gethome(mrb_state *mrb, mrb_value klass) } home = mrb_locale_from_utf8(home, -1); path = mrb_str_new_cstr(mrb, home); - mrb_utf8_free(home); + mrb_locale_free(home); return path; #else argc = mrb_get_argc(mrb); @@ -327,7 +327,7 @@ mrb_file__gethome(mrb_state *mrb, mrb_value klass) } home = mrb_locale_from_utf8(home, -1); path = mrb_str_new_cstr(mrb, home); - mrb_utf8_free(home); + mrb_locale_free(home); return path; #endif } diff --git a/mrbgems/mruby-io/src/io.c b/mrbgems/mruby-io/src/io.c index 38b0b06c2..67c57a08e 100644 --- a/mrbgems/mruby-io/src/io.c +++ b/mrbgems/mruby-io/src/io.c @@ -780,7 +780,7 @@ reopen: mrb_str_modify(mrb, mrb_str_ptr(emsg)); mrb_sys_fail(mrb, RSTRING_PTR(emsg)); } - mrb_utf8_free(fname); + mrb_locale_free(fname); if (fd <= 2) { mrb_fd_cloexec(mrb, fd); -- cgit v1.2.3 From 33c8c8f8a62c4fb00f30e4a4554ed4a912c69b7b Mon Sep 17 00:00:00 2001 From: Kouhei Sutou Date: Tue, 19 Jun 2018 17:27:34 +0900 Subject: Stop to use freed value --- mrbgems/mruby-io/src/file.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/mrbgems/mruby-io/src/file.c b/mrbgems/mruby-io/src/file.c index 3dcfe3a0b..2daa3294a 100644 --- a/mrbgems/mruby-io/src/file.c +++ b/mrbgems/mruby-io/src/file.c @@ -114,11 +114,13 @@ mrb_file_s_unlink(mrb_state *mrb, mrb_value obj) mrb_get_args(mrb, "*", &argv, &argc); for (i = 0; i < argc; i++) { + const char *utf8_path; pathv = mrb_convert_type(mrb, argv[i], MRB_TT_STRING, "String", "to_str"); - path = mrb_locale_from_utf8(mrb_string_value_cstr(mrb, &pathv), -1); + utf8_path = mrb_string_value_cstr(mrb, &pathv); + path = mrb_locale_from_utf8(utf8_path, -1); if (UNLINK(path) < 0) { mrb_locale_free(path); - mrb_sys_fail(mrb, path); + mrb_sys_fail(mrb, utf8_path); } mrb_locale_free(path); } @@ -415,10 +417,11 @@ mrb_file_s_chmod(mrb_state *mrb, mrb_value klass) { mrb_get_args(mrb, "i*", &mode, &filenames, &argc); for (i = 0; i < argc; i++) { - char *path = mrb_locale_from_utf8(mrb_str_to_cstr(mrb, filenames[i]), -1); + const char *utf8_path = mrb_str_to_cstr(mrb, filenames[i]); + char *path = mrb_locale_from_utf8(utf8_path, -1); if (CHMOD(path, mode) == -1) { mrb_locale_free(path); - mrb_sys_fail(mrb, path); + mrb_sys_fail(mrb, utf8_path); } mrb_locale_free(path); } -- cgit v1.2.3 From e38d1d278b14073761e5c7c4cc95487919c3fc9e Mon Sep 17 00:00:00 2001 From: Kouhei Sutou Date: Wed, 20 Jun 2018 11:45:15 +0900 Subject: Export mrb_utf8_from_locale() and mrb_locale_from_utf8() --- include/mruby.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/mruby.h b/include/mruby.h index 8c4f9280b..b0bfe78b5 100644 --- a/include/mruby.h +++ b/include/mruby.h @@ -994,8 +994,8 @@ MRB_API mrb_value mrb_str_new_static(mrb_state *mrb, const char *p, size_t len); #define mrb_str_new_lit(mrb, lit) mrb_str_new_static(mrb, (lit), mrb_strlen_lit(lit)) #ifdef _WIN32 -char* mrb_utf8_from_locale(const char *p, int len); -char* mrb_locale_from_utf8(const char *p, int len); +MRB_API char* mrb_utf8_from_locale(const char *p, int len); +MRB_API char* mrb_locale_from_utf8(const char *p, int len); #define mrb_locale_free(p) free(p) #define mrb_utf8_free(p) free(p) #else -- cgit v1.2.3 From 54cd2623b3c93c26d5496e6b5c546c99639b3d3b Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Tue, 19 Jun 2018 17:17:24 +0900 Subject: Turn off `enable_debug` flag in `build_config.rb` by default. This will improve the default performance of mruby; fix #4045 --- build_config.rb | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/build_config.rb b/build_config.rb index 1429837be..7f52b5ee9 100644 --- a/build_config.rb +++ b/build_config.rb @@ -8,7 +8,8 @@ MRuby::Build.new do |conf| toolchain :gcc end - enable_debug + # Turn on `enable_debug` for better debugging + # enable_debug # Use mrbgems # conf.gem 'examples/mrbgems/ruby_extension_example' -- cgit v1.2.3 From f29bc4607a0d89f717671092b9abcde16ef28dd0 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Wed, 20 Jun 2018 15:21:16 +0900 Subject: Add test_dependency from mruby-io to mruby-time. --- mrbgems/mruby-io/mrbgem.rake | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/mrbgems/mruby-io/mrbgem.rake b/mrbgems/mruby-io/mrbgem.rake index 50fa49678..d79964590 100644 --- a/mrbgems/mruby-io/mrbgem.rake +++ b/mrbgems/mruby-io/mrbgem.rake @@ -4,7 +4,7 @@ MRuby::Gem::Specification.new('mruby-io') do |spec| spec.summary = 'IO and File class' spec.cc.include_paths << "#{build.root}/src" - + case RUBY_PLATFORM when /mingw|mswin/ spec.linker.libraries += ['Ws2_32'] @@ -14,4 +14,5 @@ MRuby::Gem::Specification.new('mruby-io') do |spec| if build.kind_of?(MRuby::CrossBuild) && %w(x86_64-w64-mingw32 i686-w64-mingw32).include?(build.host_target) spec.linker.libraries += ['ws2_32'] end + spec.add_test_dependency 'mruby-time', core: 'mruby-time' end -- cgit v1.2.3 From 26d143bda810a9f32361224533997dca303f248c Mon Sep 17 00:00:00 2001 From: take-cheeze Date: Wed, 20 Jun 2018 18:15:04 +0900 Subject: Fix memory leaks in mirb. --- mrbgems/mruby-bin-mirb/tools/mirb/mirb.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/mrbgems/mruby-bin-mirb/tools/mirb/mirb.c b/mrbgems/mruby-bin-mirb/tools/mirb/mirb.c index 5b77f5bac..5c2b58da5 100644 --- a/mrbgems/mruby-bin-mirb/tools/mirb/mirb.c +++ b/mrbgems/mruby-bin-mirb/tools/mirb/mirb.c @@ -661,6 +661,12 @@ done: if (args.rfp) fclose(args.rfp); mrb_free(mrb, args.argv); + if (args.libv) { + for (i = 0; i < args.libc; ++i) { + mrb_free(mrb, args.libv[i]); + } + mrb_free(mrb, args.libv); + } mrbc_context_free(mrb, cxt); mrb_close(mrb); -- cgit v1.2.3 From e050cfb349ba11f7962df70dbff953daf456b68e Mon Sep 17 00:00:00 2001 From: take-cheeze Date: Wed, 20 Jun 2018 18:20:26 +0900 Subject: Add forgotten `mkdir_p`s. --- mrbgems/mruby-compiler/mrbgem.rake | 1 + tasks/libmruby.rake | 1 + tasks/mrbgems.rake | 1 + 3 files changed, 3 insertions(+) diff --git a/mrbgems/mruby-compiler/mrbgem.rake b/mrbgems/mruby-compiler/mrbgem.rake index 3bf6d6ae3..6decd643b 100644 --- a/mrbgems/mruby-compiler/mrbgem.rake +++ b/mrbgems/mruby-compiler/mrbgem.rake @@ -27,6 +27,7 @@ MRuby::Gem::Specification.new 'mruby-compiler' do |spec| # Parser file "#{current_build_dir}/core/y.tab.c" => ["#{current_dir}/core/parse.y"] do |t| + FileUtils.mkdir_p File.dirname t.name yacc.run t.name, t.prerequisites.first end diff --git a/tasks/libmruby.rake b/tasks/libmruby.rake index 540aa3eb5..b6ef29986 100644 --- a/tasks/libmruby.rake +++ b/tasks/libmruby.rake @@ -4,6 +4,7 @@ MRuby.each_target do end file "#{build_dir}/lib/libmruby.flags.mak" => [__FILE__, libfile("#{build_dir}/lib/libmruby")] do |t| + FileUtils.mkdir_p File.dirname t.name open(t.name, 'w') do |f| f.puts "MRUBY_CFLAGS = #{cc.all_flags}" diff --git a/tasks/mrbgems.rake b/tasks/mrbgems.rake index 1b964524c..64e5b0353 100644 --- a/tasks/mrbgems.rake +++ b/tasks/mrbgems.rake @@ -53,6 +53,7 @@ MRuby.each_target do # legal documents file "#{build_dir}/LEGAL" => [MRUBY_CONFIG, __FILE__] do |t| + FileUtils.mkdir_p File.dirname t.name open(t.name, 'w+') do |f| f.puts < Date: Wed, 20 Jun 2018 18:21:33 +0900 Subject: Fix dependencies. --- mrbgems/mruby-bin-mruby-config/mrbgem.rake | 5 +++-- mrbgems/mruby-compiler/mrbgem.rake | 3 +-- mrbgems/mruby-test/mrbgem.rake | 6 +++--- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/mrbgems/mruby-bin-mruby-config/mrbgem.rake b/mrbgems/mruby-bin-mruby-config/mrbgem.rake index 66d6ef80b..32ae2164b 100644 --- a/mrbgems/mruby-bin-mruby-config/mrbgem.rake +++ b/mrbgems/mruby-bin-mruby-config/mrbgem.rake @@ -19,9 +19,10 @@ MRuby.each_target do mruby_config_path = "#{build_dir}/bin/#{mruby_config}" @bins << mruby_config - file mruby_config_path => libfile("#{build_dir}/lib/libmruby") do |t| + make_cfg = "#{build_dir}/lib/libmruby.flags.mak" + file mruby_config_path => [libfile("#{build_dir}/lib/libmruby"), make_cfg] do |t| FileUtils.copy "#{File.dirname(__FILE__)}/#{mruby_config}", t.name - config = Hash[open("#{build_dir}/lib/libmruby.flags.mak").read.split("\n").map {|x| a = x.split(/\s*=\s*/, 2); [a[0], a[1].gsub('\\"', '"') ]}] + config = Hash[open(make_cfg).read.split("\n").map {|x| a = x.split(/\s*=\s*/, 2); [a[0], a[1].gsub('\\"', '"') ]}] IO.write(t.name, File.open(t.name) {|f| f.read.gsub (/echo (MRUBY_CFLAGS|MRUBY_LIBS|MRUBY_LDFLAGS_BEFORE_LIBS|MRUBY_LDFLAGS|MRUBY_LIBMRUBY_PATH)/) {|x| config[$1].empty? ? '' : "echo #{config[$1]}"} }) diff --git a/mrbgems/mruby-compiler/mrbgem.rake b/mrbgems/mruby-compiler/mrbgem.rake index 6decd643b..e9e0cc2c7 100644 --- a/mrbgems/mruby-compiler/mrbgem.rake +++ b/mrbgems/mruby-compiler/mrbgem.rake @@ -23,10 +23,9 @@ MRuby::Gem::Specification.new 'mruby-compiler' do |spec| cc.run t.name, t.prerequisites.first, [], ["#{current_dir}/core"] end end - file objfile("#{current_build_dir}/core/y.tab") => lex_def # Parser - file "#{current_build_dir}/core/y.tab.c" => ["#{current_dir}/core/parse.y"] do |t| + file "#{current_build_dir}/core/y.tab.c" => ["#{current_dir}/core/parse.y", lex_def] do |t| FileUtils.mkdir_p File.dirname t.name yacc.run t.name, t.prerequisites.first end diff --git a/mrbgems/mruby-test/mrbgem.rake b/mrbgems/mruby-test/mrbgem.rake index 27c635a5d..b9b10fc60 100644 --- a/mrbgems/mruby-test/mrbgem.rake +++ b/mrbgems/mruby-test/mrbgem.rake @@ -31,7 +31,7 @@ MRuby::Gem::Specification.new('mruby-test') do |spec| mrbtest_objs << assert_lib file assert_lib => assert_c - file assert_c => assert_rb do |t| + file assert_c => [assert_rb, build.mrbcfile] do |t| open(t.name, 'w') do |f| mrbc.run f, assert_rb, 'mrbtest_assert_irep' end @@ -45,7 +45,7 @@ MRuby::Gem::Specification.new('mruby-test') do |spec| dep_list = build.gems.tsort_dependencies(g.test_dependencies, gem_table).select(&:generate_functions) file test_rbobj => g.test_rbireps - file g.test_rbireps => [g.test_rbfiles].flatten do |t| + file g.test_rbireps => [g.test_rbfiles, build.mrbcfile].flatten do |t| FileUtils.mkdir_p File.dirname(t.name) open(t.name, 'w') do |f| g.print_gem_test_header(f) @@ -169,7 +169,7 @@ MRuby::Gem::Specification.new('mruby-test') do |spec| file clib => active_gems_path file mlib => clib - file clib => init do |t| + file clib => [init, build.mrbcfile] do |t| _pp "GEN", "*.rb", "#{clib.relative_path}" FileUtils.mkdir_p File.dirname(clib) open(clib, 'w') do |f| -- cgit v1.2.3 From 633599a2cb90ff5b7eb7259e0247c3220b048d85 Mon Sep 17 00:00:00 2001 From: take-cheeze Date: Wed, 20 Jun 2018 18:21:57 +0900 Subject: Fix forgotten argument passing. --- mrbgems/mruby-test/mrbgem.rake | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/mrbgems/mruby-test/mrbgem.rake b/mrbgems/mruby-test/mrbgem.rake index b9b10fc60..01835c542 100644 --- a/mrbgems/mruby-test/mrbgem.rake +++ b/mrbgems/mruby-test/mrbgem.rake @@ -146,7 +146,8 @@ MRuby::Gem::Specification.new('mruby-test') do |spec| gem_flags_after_libraries = build.gems.map { |g| g.linker.flags_after_libraries } gem_libraries = build.gems.map { |g| g.linker.libraries } gem_library_paths = build.gems.map { |g| g.linker.library_paths } - build.linker.run t.name, t.prerequisites, gem_libraries, gem_library_paths, gem_flags, gem_flags_before_libraries + build.linker.run t.name, t.prerequisites, gem_libraries, gem_library_paths, gem_flags, + gem_flags_before_libraries, gem_flags_after_libraries end end -- cgit v1.2.3 From a212428fede9fd05c118b5153936af7560b0a8eb Mon Sep 17 00:00:00 2001 From: take-cheeze Date: Wed, 20 Jun 2018 18:22:50 +0900 Subject: Comment out unused variable. --- mrbgems/mruby-test/mrbgem.rake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mrbgems/mruby-test/mrbgem.rake b/mrbgems/mruby-test/mrbgem.rake index 01835c542..ac9c2fe21 100644 --- a/mrbgems/mruby-test/mrbgem.rake +++ b/mrbgems/mruby-test/mrbgem.rake @@ -23,7 +23,7 @@ MRuby::Gem::Specification.new('mruby-test') do |spec| mrbtest_objs = [] driver_obj = objfile("#{build_dir}/driver") - driver = "#{spec.dir}/driver.c" + # driver = "#{spec.dir}/driver.c" assert_c = "#{build_dir}/assert.c" assert_rb = "#{MRUBY_ROOT}/test/assert.rb" -- cgit v1.2.3 From 1d7c69a7cb9d58a8d6b9754fa45e2cad2dca64fa Mon Sep 17 00:00:00 2001 From: take-cheeze Date: Wed, 20 Jun 2018 18:23:08 +0900 Subject: Fix dependencies. --- mrbgems/mruby-test/mrbgem.rake | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/mrbgems/mruby-test/mrbgem.rake b/mrbgems/mruby-test/mrbgem.rake index ac9c2fe21..0aecae274 100644 --- a/mrbgems/mruby-test/mrbgem.rake +++ b/mrbgems/mruby-test/mrbgem.rake @@ -164,10 +164,11 @@ MRuby::Gem::Specification.new('mruby-test') do |spec| nil end current_gem_list = build.gems.map(&:name).join("\n") - if active_gem_list != current_gem_list - File.write active_gems_path, current_gem_list + task active_gems_path do |t| + FileUtils.mkdir_p File.dirname t.name + File.write t.name, current_gem_list end - file clib => active_gems_path + file clib => active_gems_path if active_gem_list != current_gem_list file mlib => clib file clib => [init, build.mrbcfile] do |t| -- cgit v1.2.3 From b8fec13cabc8ee306c9bde530a89878fb8d29284 Mon Sep 17 00:00:00 2001 From: take-cheeze Date: Wed, 20 Jun 2018 18:29:11 +0900 Subject: Make codacy happy. --- mrbgems/mruby-test/mrbgem.rake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mrbgems/mruby-test/mrbgem.rake b/mrbgems/mruby-test/mrbgem.rake index 0aecae274..11d780f75 100644 --- a/mrbgems/mruby-test/mrbgem.rake +++ b/mrbgems/mruby-test/mrbgem.rake @@ -171,7 +171,7 @@ MRuby::Gem::Specification.new('mruby-test') do |spec| file clib => active_gems_path if active_gem_list != current_gem_list file mlib => clib - file clib => [init, build.mrbcfile] do |t| + file clib => [init, build.mrbcfile] do |_t| _pp "GEN", "*.rb", "#{clib.relative_path}" FileUtils.mkdir_p File.dirname(clib) open(clib, 'w') do |f| -- cgit v1.2.3 From c3ac33d9cd532aa80b8595d460eac745712b4042 Mon Sep 17 00:00:00 2001 From: take-cheeze Date: Wed, 20 Jun 2018 18:17:38 +0900 Subject: Make minirake parallel. --- minirake | 129 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 116 insertions(+), 13 deletions(-) diff --git a/minirake b/minirake index 542c37a79..ae3d53ca0 100755 --- a/minirake +++ b/minirake @@ -6,6 +6,12 @@ require 'getoptlong' require 'fileutils' +require 'fiber' + +$rake_fiber_table = {} +$rake_jobs = 1 +$rake_failed = [] +$rake_root_fiber = Fiber.current class String def ext(newext='') @@ -86,14 +92,31 @@ module MiniRake @name.to_s end + def done?; @done end + def running?; @running end + # Invoke the task if it is needed. Prerequites are invoked first. def invoke puts "Invoke #{name} (already=[#{@already_invoked}], needed=[#{needed?}])" if $trace return if @already_invoked - @already_invoked = true prerequisites = @prerequisites.collect{ |n| n.is_a?(Proc) ? n.call(name) : n }.flatten - prerequisites.each { |n| Task[n].invoke } - execute if needed? + prerequisites.each do |n| + t = Task[n] + unless t.done? + return prerequisites.select{|v| v = Task[v]; v && (!v.done? || !v.running?) } + end + end + + @already_invoked = true + + if needed? + @running = true + return Fiber.new do + self.execute + end + end + + @done = true end # Execute the actions associated with this task. @@ -103,6 +126,8 @@ module MiniRake unless $dryrun @actions.each { |act| act.call(self) } end + @done = true + @running = false end # Is this task needed? @@ -281,7 +306,19 @@ module MiniRake # Run the system command +cmd+. def sh(cmd) puts cmd if $verbose - system(cmd) or fail "Command Failed: [#{cmd}]" + + if $rake_jobs == 1 || Fiber.current == $rake_root_fiber + system(cmd) or fail "Command Failed: [#{cmd}]" + return + end + + pid = Process.spawn(cmd) + $rake_fiber_table[pid] = { + fiber: Fiber.current, + command: cmd, + process_waiter: Process.detach(pid) + } + Fiber.yield end def desc(text) @@ -329,7 +366,9 @@ class RakeApp ['--verbose', '-v', GetoptLong::NO_ARGUMENT, "Log message to standard output."], ['--directory', '-C', GetoptLong::REQUIRED_ARGUMENT, - "Change executing directory of rakefiles."] + "Change executing directory of rakefiles."], + ['--jobs', '-j', GetoptLong::REQUIRED_ARGUMENT, + 'Execute rake with parallel jobs.'] ] # Create a RakeApp object. @@ -422,6 +461,8 @@ class RakeApp exit when '--directory' Dir.chdir value + when '--jobs' + $rake_jobs = [value.to_i, 1].max else fail "Unknown option: #{opt}" end @@ -447,12 +488,12 @@ class RakeApp end here = Dir.pwd end - tasks = [] + root_tasks = [] ARGV.each do |task_name| if /^(\w+)=(.*)/.match(task_name) ENV[$1] = $2 else - tasks << task_name + root_tasks << task_name end end puts "(in #{Dir.pwd})" @@ -461,20 +502,82 @@ class RakeApp if $show_tasks display_tasks else - tasks.push("default") if tasks.size == 0 - tasks.each do |task_name| - MiniRake::Task[task_name].invoke + root_tasks.push("default") if root_tasks.empty? + # revese tasks for popping + root_tasks.reverse! + + tasks = [] + until root_tasks.empty? + root_name = root_tasks.pop + tasks << root_name + until tasks.empty? + task_name = tasks.pop + t = MiniRake::Task[task_name] + f = t.invoke + + # append additional tasks to task queue + if f.kind_of?(Array) + tasks.push(*f) + tasks.uniq! + end + + unless f.kind_of? Fiber + tasks.insert 0, task_name unless t.done? + if root_name == task_name + wait_process + end + next + end + + f.resume + end end + + wait_process until $rake_fiber_table.empty? + end + rescue Exception => e + begin + $rake_failed << e + wait_process until $rake_fiber_table.empty? + rescue Exception => next_e + e = next_e + retry end - rescue Exception => ex - puts "rake aborted!" + end + + return if $rake_failed.empty? + + puts "rake aborted!" + $rake_failed.each do |ex| puts ex.message if $trace puts ex.backtrace.join("\n") else puts ex.backtrace.find {|str| str =~ /#{@rakefile}/ } || "" end - exit 1 + end + exit 1 + end + + def wait_process + sleep 0.1 + + exited = [] + $rake_fiber_table.each do |pid, v| + exited << pid unless v[:process_waiter].alive? + end + + exited.each do |pid| + ent = $rake_fiber_table.delete pid + st = ent[:process_waiter].value + + # ignore process that isn't created by `sh` method + return if ent.nil? + + if st.exitstatus != 0 + raise "Command Failed: [#{ent[:command]}]" + end + ent[:fiber].resume end end end -- cgit v1.2.3 From 33f72bb038febf90c3f6b6fa1420ce29f2fbeaf1 Mon Sep 17 00:00:00 2001 From: take-cheeze Date: Wed, 20 Jun 2018 21:23:48 +0900 Subject: disable sudo. --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 56c54914a..73d328440 100644 --- a/.travis.yml +++ b/.travis.yml @@ -5,7 +5,7 @@ sudo: false matrix: include: - os: linux - sudo: 9000 + sudo: false - os: osx osx_image: xcode7.1 -- cgit v1.2.3 From 8f808cc9b148710617e840f8ff589709b7fc1fff Mon Sep 17 00:00:00 2001 From: take-cheeze Date: Wed, 20 Jun 2018 21:42:48 +0900 Subject: Use temporary name for `File#mtime` test to avoid conflicts. --- mrbgems/mruby-io/test/file.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mrbgems/mruby-io/test/file.rb b/mrbgems/mruby-io/test/file.rb index dc6fe369a..ab4678fe9 100644 --- a/mrbgems/mruby-io/test/file.rb +++ b/mrbgems/mruby-io/test/file.rb @@ -75,12 +75,12 @@ assert('File#mtime') do begin now = Time.now.to_i mt = 0 - File.open('mtime-test', 'w') do |f| + File.open("#{$mrbtest_io_wfname}.mtime", 'w') do |f| mt = f.mtime.to_i end assert_equal true, mt >= now ensure - File.delete('mtime-test') + File.delete("#{$mrbtest_io_wfname}.mtime") end end -- cgit v1.2.3 From 7bb2fc70f297a3b5e10c516bf211fb2a04a65a40 Mon Sep 17 00:00:00 2001 From: take-cheeze Date: Wed, 20 Jun 2018 20:53:01 +0900 Subject: Set jobs to 4 since it have 2 CPUs. --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 73d328440..d8c22c046 100644 --- a/.travis.yml +++ b/.travis.yml @@ -17,4 +17,4 @@ addons: env: MRUBY_CONFIG=travis_config.rb env: MRUBY_CONFIG=travis_config.rb -script: "./minirake all test" +script: "./minirake -j4 all test" -- cgit v1.2.3 From 6f35b07fabb150ead959889d0833cf9b10c9712c Mon Sep 17 00:00:00 2001 From: take-cheeze Date: Thu, 21 Jun 2018 11:26:55 +0900 Subject: Use Fiber#transfer instead in minirake. --- minirake | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/minirake b/minirake index ae3d53ca0..43a669f8e 100755 --- a/minirake +++ b/minirake @@ -113,6 +113,7 @@ module MiniRake @running = true return Fiber.new do self.execute + $rake_root_fiber.transfer end end @@ -318,7 +319,7 @@ module MiniRake command: cmd, process_waiter: Process.detach(pid) } - Fiber.yield + $rake_root_fiber.transfer end def desc(text) @@ -529,7 +530,7 @@ class RakeApp next end - f.resume + f.transfer end end @@ -577,7 +578,7 @@ class RakeApp if st.exitstatus != 0 raise "Command Failed: [#{ent[:command]}]" end - ent[:fiber].resume + ent[:fiber].transfer end end end -- cgit v1.2.3 From c90dbd12ef41f3451e3e1dadaed8269d30df7da3 Mon Sep 17 00:00:00 2001 From: take-cheeze Date: Thu, 21 Jun 2018 11:29:50 +0900 Subject: Show minirake backtrace in verbose mode. --- minirake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/minirake b/minirake index ae3d53ca0..6f772cb3d 100755 --- a/minirake +++ b/minirake @@ -550,7 +550,7 @@ class RakeApp puts "rake aborted!" $rake_failed.each do |ex| puts ex.message - if $trace + if $trace || $verbose puts ex.backtrace.join("\n") else puts ex.backtrace.find {|str| str =~ /#{@rakefile}/ } || "" -- cgit v1.2.3 From acd04ad519355882d42a00cf78926bb32b591509 Mon Sep 17 00:00:00 2001 From: take-cheeze Date: Thu, 21 Jun 2018 11:33:34 +0900 Subject: Support verbose mode in bintest. --- lib/mruby/build.rb | 8 ++++++-- test/bintest.rb | 4 ++++ 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/lib/mruby/build.rb b/lib/mruby/build.rb index 57bd9c51e..affff9df0 100644 --- a/lib/mruby/build.rb +++ b/lib/mruby/build.rb @@ -293,10 +293,14 @@ EOS @build_mrbtest_lib_only end + def verbose_flag + $verbose ? ' -v' : '' + end + def run_test puts ">>> Test #{name} <<<" mrbtest = exefile("#{build_dir}/bin/mrbtest") - sh "#{filename mrbtest.relative_path}#{$verbose ? ' -v' : ''}" + sh "#{filename mrbtest.relative_path}#{verbose_flag}" puts run_bintest if bintest_enabled? end @@ -304,7 +308,7 @@ EOS def run_bintest targets = @gems.select { |v| File.directory? "#{v.dir}/bintest" }.map { |v| filename v.dir } targets << filename(".") if File.directory? "./bintest" - sh "ruby test/bintest.rb #{targets.join ' '}" + sh "ruby test/bintest.rb#{verbose_flag} #{targets.join ' '}" end def print_build_summary diff --git a/test/bintest.rb b/test/bintest.rb index 12971a9d9..b62419d44 100644 --- a/test/bintest.rb +++ b/test/bintest.rb @@ -20,6 +20,10 @@ def shellquote(s) end ARGV.each do |gem| + case gem + when '-v'; $mrbtest_verbose = true + end + case RbConfig::CONFIG['host_os'] when /mswin(?!ce)|mingw|bccwin/ gem = gem.gsub('\\', '/') -- cgit v1.2.3 From 7c246cb9db375c30490cc62da1c7138d54e6d441 Mon Sep 17 00:00:00 2001 From: take-cheeze Date: Thu, 21 Jun 2018 12:45:55 +0900 Subject: Fix job waiter. --- minirake | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/minirake b/minirake index ae3d53ca0..343978d77 100755 --- a/minirake +++ b/minirake @@ -529,6 +529,8 @@ class RakeApp next end + wait_process while $rake_fiber_table.size >= $rake_jobs + f.resume end end @@ -577,6 +579,9 @@ class RakeApp if st.exitstatus != 0 raise "Command Failed: [#{ent[:command]}]" end + + wait_process while $rake_fiber_table.size >= $rake_jobs + ent[:fiber].resume end end -- cgit v1.2.3 From 61e8f831dd0d8936087b2d3be9a135e0802d3d64 Mon Sep 17 00:00:00 2001 From: take-cheeze Date: Fri, 22 Jun 2018 09:29:59 +0900 Subject: Use `Thread.pass` instead of sleeping. --- minirake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/minirake b/minirake index 09592980f..00675ba39 100755 --- a/minirake +++ b/minirake @@ -562,7 +562,7 @@ class RakeApp end def wait_process - sleep 0.1 + Thread.pass exited = [] $rake_fiber_table.each do |pid, v| -- cgit v1.2.3 From 48ba7c7bb0ccf146921e585c6ce2f5a0e1afff0f Mon Sep 17 00:00:00 2001 From: take-cheeze Date: Fri, 22 Jun 2018 11:41:12 +0900 Subject: Increase sleep duration exponentially instead of `Thread.pass`. --- minirake | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/minirake b/minirake index e16dd5bcf..8b6bfa296 100755 --- a/minirake +++ b/minirake @@ -562,8 +562,9 @@ class RakeApp exit 1 end - def wait_process - Thread.pass + def wait_process(count = 0) + dur = [0.0001 * (10 ** count), 1].min + sleep dur exited = [] $rake_fiber_table.each do |pid, v| @@ -581,10 +582,12 @@ class RakeApp raise "Command Failed: [#{ent[:command]}]" end - wait_process while $rake_fiber_table.size >= $rake_jobs + fail 'task scheduling bug!' if $rake_fiber_table.size >= $rake_jobs ent[:fiber].transfer end + + wait_process(count + 1) if !$rake_fiber_table.empty? && exited.empty? end end -- cgit v1.2.3 From eaf463ada3d28cfb62f59137e59246827bb287e7 Mon Sep 17 00:00:00 2001 From: take-cheeze Date: Fri, 22 Jun 2018 11:43:14 +0900 Subject: Run tests parallelly for each target. --- Rakefile | 17 ++++++++++++++--- lib/mruby/build.rb | 1 - 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/Rakefile b/Rakefile index 2f6fa056f..d2ad9044c 100644 --- a/Rakefile +++ b/Rakefile @@ -118,10 +118,21 @@ task :all => depfiles do end desc "run all mruby tests" -task :test => ["all"] do - MRuby.each_target do - run_test if test_enabled? +MRuby.each_target do + next unless test_enabled? + + t = :"test_#{self.name}" + task t => ["all"] do + run_test + end + task :test => t + + next unless bintest_enabled? + t = :"bintest_#{self.name}" + task t => ["all"] do + run_bintest end + task :test => t end desc "clean all built and in-repo installed artifacts" diff --git a/lib/mruby/build.rb b/lib/mruby/build.rb index 57bd9c51e..83c7404b8 100644 --- a/lib/mruby/build.rb +++ b/lib/mruby/build.rb @@ -298,7 +298,6 @@ EOS mrbtest = exefile("#{build_dir}/bin/mrbtest") sh "#{filename mrbtest.relative_path}#{$verbose ? ' -v' : ''}" puts - run_bintest if bintest_enabled? end def run_bintest -- cgit v1.2.3 From 7e798405874ee3a4e3019436d8560641a5048dd3 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Fri, 22 Jun 2018 12:03:52 +0900 Subject: initialize a local variable to avoid warning --- src/enum.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/enum.c b/src/enum.c index ea05777b3..03508953e 100644 --- a/src/enum.c +++ b/src/enum.c @@ -27,6 +27,8 @@ enum_update_hash(mrb_state *mrb, mrb_value self) #endif else { mrb_raise(mrb, E_TYPE_ERROR, "can't calculate hash"); + /* not reached */ + hv = 0; } hash ^= (hv << (index % 16)); -- cgit v1.2.3 From 695f29cd604787f43be1af16e38d13610bf8312b Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Wed, 27 Jun 2018 16:32:24 +0900 Subject: Add negative check in `mrb_str_resize`; fix #4062 --- src/string.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/string.c b/src/string.c index 5cca6d460..fd09e05dc 100644 --- a/src/string.c +++ b/src/string.c @@ -708,6 +708,9 @@ mrb_str_resize(mrb_state *mrb, mrb_value str, mrb_int len) mrb_int slen; struct RString *s = mrb_str_ptr(str); + if (len < 0) { + mrb_raisef(mrb, E_ARGUMENT_ERROR, "negative (or overflowed) string size"); + } mrb_str_modify(mrb, s); slen = RSTR_LEN(s); if (len != slen) { -- cgit v1.2.3 From 3116d0600386aacce315f33a92ca4145961f275a Mon Sep 17 00:00:00 2001 From: W Date: Wed, 27 Jun 2018 12:20:24 +0000 Subject: Add information about Kernel#binding --- doc/limitations.md | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/doc/limitations.md b/doc/limitations.md index 9d8924cff..afcb7b56e 100644 --- a/doc/limitations.md +++ b/doc/limitations.md @@ -185,3 +185,23 @@ The re-defined ```+``` operator does not accept any arguments. ``` 'ab' ``` Behavior of the operator wasn't changed. + +## Kernel#binding is not supported + +`Kernel#binding` method is not supported. + +#### Ruby [ruby 2.5.1p57 (2018-03-29 revision 63029)] + +``` +$ ruby -e 'puts Proc.new {}.binding' +# +``` + +#### mruby [1.4.1 (2018-4-27)] + +``` +$ ./bin/mruby -e 'puts Proc.new {}.binding' +trace (most recent call last): + [0] -e:1 +-e:1: undefined method 'binding' (NoMethodError) +``` -- cgit v1.2.3 From adb1eae912659d680a9c5b7832e22cf73d36a69a Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Thu, 28 Jun 2018 22:40:24 +0900 Subject: Use `mrb_raise()` instead of `mrb_raisef()`; ref #4062 --- src/string.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/string.c b/src/string.c index fd09e05dc..b7abfb762 100644 --- a/src/string.c +++ b/src/string.c @@ -709,7 +709,7 @@ mrb_str_resize(mrb_state *mrb, mrb_value str, mrb_int len) struct RString *s = mrb_str_ptr(str); if (len < 0) { - mrb_raisef(mrb, E_ARGUMENT_ERROR, "negative (or overflowed) string size"); + mrb_raise(mrb, E_ARGUMENT_ERROR, "negative (or overflowed) string size"); } mrb_str_modify(mrb, s); slen = RSTR_LEN(s); -- cgit v1.2.3 From 7917b7f8bf40f0a824130f2569744df3109081ec Mon Sep 17 00:00:00 2001 From: Yusuke Endoh Date: Mon, 2 Jul 2018 10:47:56 +0900 Subject: Support MRB_WITHOUT_FLOAT to mruby-io --- mrbgems/mruby-io/src/file.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/mrbgems/mruby-io/src/file.c b/mrbgems/mruby-io/src/file.c index e5cf53488..ca21256cc 100644 --- a/mrbgems/mruby-io/src/file.c +++ b/mrbgems/mruby-io/src/file.c @@ -345,7 +345,11 @@ mrb_file_mtime(mrb_state *mrb, mrb_value self) fd = (int)mrb_fixnum(mrb_io_fileno(mrb, self)); if (fstat(fd, &st) == -1) return mrb_false_value(); +#ifndef MRB_WITHOUT_FLOAT return mrb_funcall(mrb, obj, "at", 1, mrb_float_value(mrb, st.st_mtime)); +#else + return mrb_funcall(mrb, obj, "at", 1, mrb_fixnum_value(st.st_mtime)); +#endif } mrb_value -- cgit v1.2.3 From 06428059f67e018c52a088faad40166956142b27 Mon Sep 17 00:00:00 2001 From: duangsuse <10570123+duangsuse@users.noreply.github.com> Date: Wed, 4 Jul 2018 19:33:11 +0800 Subject: Add ~/Android/Sdk/ndk-bundle as default NDK home --- tasks/toolchains/android.rake | 1 + 1 file changed, 1 insertion(+) diff --git a/tasks/toolchains/android.rake b/tasks/toolchains/android.rake index c59da7fcb..c7df9ef80 100644 --- a/tasks/toolchains/android.rake +++ b/tasks/toolchains/android.rake @@ -7,6 +7,7 @@ class MRuby::Toolchain::Android DEFAULT_NDK_HOMES = %w{ /usr/local/opt/android-sdk/ndk-bundle /usr/local/opt/android-ndk + ~/Android/Sdk/ndk-bundle %LOCALAPPDATA%/Android/android-sdk/ndk-bundle %LOCALAPPDATA%/Android/android-ndk ~/Library/Android/sdk/ndk-bundle -- cgit v1.2.3 From b1f1fe2f81f4b8a236c8fb8dbd5bea0aec25ee54 Mon Sep 17 00:00:00 2001 From: Sebastián Katzer Date: Sun, 8 Jul 2018 13:51:00 +0200 Subject: Fix task name is not necessarily a valid path Errno::ENOENT: No such file or directory @ dir_s_mkdir - mruby:Z:/Documents --- mrbgems/mruby-test/mrbgem.rake | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/mrbgems/mruby-test/mrbgem.rake b/mrbgems/mruby-test/mrbgem.rake index 11d780f75..589fc688a 100644 --- a/mrbgems/mruby-test/mrbgem.rake +++ b/mrbgems/mruby-test/mrbgem.rake @@ -164,9 +164,9 @@ MRuby::Gem::Specification.new('mruby-test') do |spec| nil end current_gem_list = build.gems.map(&:name).join("\n") - task active_gems_path do |t| - FileUtils.mkdir_p File.dirname t.name - File.write t.name, current_gem_list + task active_gems_path do |_t| + FileUtils.mkdir_p File.dirname(active_gems_path) + File.write active_gems_path, current_gem_list end file clib => active_gems_path if active_gem_list != current_gem_list -- cgit v1.2.3 From dabb20ddbb51e6dac3bb6a8bac6dfcfd76808ac0 Mon Sep 17 00:00:00 2001 From: yuri Date: Tue, 10 Jul 2018 01:42:33 +0900 Subject: add mrbc option `--remove-lv` * refactor: move `irep_remove_lv` from `mruby-bin-strip` gem to src/dump and rename to `mrb_irep_remove_lv` * add: mrbc option `--remove-lv` to remove LVAR section --- include/mruby/dump.h | 1 + mrbgems/mruby-bin-mrbc/tools/mrbc/mrbc.c | 9 +++++++++ .../mruby-bin-strip/tools/mruby-strip/mruby-strip.c | 18 +----------------- src/dump.c | 15 +++++++++++++++ 4 files changed, 26 insertions(+), 17 deletions(-) diff --git a/include/mruby/dump.h b/include/mruby/dump.h index f56d66a32..39a99e97b 100644 --- a/include/mruby/dump.h +++ b/include/mruby/dump.h @@ -31,6 +31,7 @@ MRB_API mrb_value mrb_load_irep_file(mrb_state*,FILE*); MRB_API mrb_value mrb_load_irep_file_cxt(mrb_state*, FILE*, mrbc_context*); #endif MRB_API mrb_irep *mrb_read_irep(mrb_state*, const uint8_t*); +void mrb_irep_remove_lv(mrb_state *mrb, mrb_irep *irep); /* dump/load error code * diff --git a/mrbgems/mruby-bin-mrbc/tools/mrbc/mrbc.c b/mrbgems/mruby-bin-mrbc/tools/mrbc/mrbc.c index 580c2e25b..2fd9da77d 100644 --- a/mrbgems/mruby-bin-mrbc/tools/mrbc/mrbc.c +++ b/mrbgems/mruby-bin-mrbc/tools/mrbc/mrbc.c @@ -18,6 +18,7 @@ struct mrbc_args { const char *initname; mrb_bool check_syntax : 1; mrb_bool verbose : 1; + mrb_bool remove_lv : 1; unsigned int flags : 4; }; @@ -33,6 +34,7 @@ usage(const char *name) "-B binary output in C language format", "-e generate little endian iseq data", "-E generate big endian iseq data", + "--remove-lv remove local variables", "--verbose run at verbose mode", "--version print the version", "--copyright print the copyright", @@ -142,6 +144,10 @@ parse_args(mrb_state *mrb, int argc, char **argv, struct mrbc_args *args) mrb_show_copyright(mrb); exit(EXIT_SUCCESS); } + else if (strcmp(argv[i] + 2, "remove-lv") == 0) { + args->remove_lv = TRUE; + break; + } return -1; default: return i; @@ -232,6 +238,9 @@ dump_file(mrb_state *mrb, FILE *wfp, const char *outfile, struct RProc *proc, st int n = MRB_DUMP_OK; mrb_irep *irep = proc->body.irep; + if (args->remove_lv) { + mrb_irep_remove_lv(mrb, irep); + } if (args->initname) { n = mrb_dump_irep_cfunc(mrb, irep, args->flags, wfp, args->initname); if (n == MRB_DUMP_INVALID_ARGUMENT) { diff --git a/mrbgems/mruby-bin-strip/tools/mruby-strip/mruby-strip.c b/mrbgems/mruby-bin-strip/tools/mruby-strip/mruby-strip.c index deb66d54c..fb78b0c3b 100644 --- a/mrbgems/mruby-bin-strip/tools/mruby-strip/mruby-strip.c +++ b/mrbgems/mruby-bin-strip/tools/mruby-strip/mruby-strip.c @@ -12,22 +12,6 @@ struct strip_args { mrb_bool lvar; }; - -static void -irep_remove_lv(mrb_state *mrb, mrb_irep *irep) -{ - int i; - - if (irep->lv) { - mrb_free(mrb, irep->lv); - irep->lv = NULL; - } - - for (i = 0; i < irep->rlen; ++i) { - irep_remove_lv(mrb, irep->reps[i]); - } -} - static void print_usage(const char *f) { @@ -99,7 +83,7 @@ strip(mrb_state *mrb, struct strip_args *args) /* clear lv if --lvar is enabled */ if (args->lvar) { - irep_remove_lv(mrb, irep); + mrb_irep_remove_lv(mrb, irep); } wfile = fopen(filename, "wb"); diff --git a/src/dump.c b/src/dump.c index df1e171e4..d0f0850fe 100644 --- a/src/dump.c +++ b/src/dump.c @@ -1103,4 +1103,19 @@ mrb_dump_irep_cfunc(mrb_state *mrb, mrb_irep *irep, uint8_t flags, FILE *fp, con return result; } +void +mrb_irep_remove_lv(mrb_state *mrb, mrb_irep *irep) +{ + int i; + + if (irep->lv) { + mrb_free(mrb, irep->lv); + irep->lv = NULL; + } + + for (i = 0; i < irep->rlen; ++i) { + mrb_irep_remove_lv(mrb, irep->reps[i]); + } +} + #endif /* MRB_DISABLE_STDIO */ -- cgit v1.2.3 From 5fef38e4c77cb3700750fe0020063289a49242d6 Mon Sep 17 00:00:00 2001 From: yuri Date: Tue, 10 Jul 2018 15:44:25 +0900 Subject: move mrb_irep_remove_lv to codegen.c in mruby-compiler --- mrbgems/mruby-compiler/core/codegen.c | 15 +++++++++++++++ src/dump.c | 15 --------------- 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/mrbgems/mruby-compiler/core/codegen.c b/mrbgems/mruby-compiler/core/codegen.c index f71de9b4b..fec747f0c 100644 --- a/mrbgems/mruby-compiler/core/codegen.c +++ b/mrbgems/mruby-compiler/core/codegen.c @@ -3092,3 +3092,18 @@ mrb_generate_code(mrb_state *mrb, parser_state *p) { return generate_code(mrb, p, VAL); } + +void +mrb_irep_remove_lv(mrb_state *mrb, mrb_irep *irep) +{ + int i; + + if (irep->lv) { + mrb_free(mrb, irep->lv); + irep->lv = NULL; + } + + for (i = 0; i < irep->rlen; ++i) { + mrb_irep_remove_lv(mrb, irep->reps[i]); + } +} diff --git a/src/dump.c b/src/dump.c index d0f0850fe..df1e171e4 100644 --- a/src/dump.c +++ b/src/dump.c @@ -1103,19 +1103,4 @@ mrb_dump_irep_cfunc(mrb_state *mrb, mrb_irep *irep, uint8_t flags, FILE *fp, con return result; } -void -mrb_irep_remove_lv(mrb_state *mrb, mrb_irep *irep) -{ - int i; - - if (irep->lv) { - mrb_free(mrb, irep->lv); - irep->lv = NULL; - } - - for (i = 0; i < irep->rlen; ++i) { - mrb_irep_remove_lv(mrb, irep->reps[i]); - } -} - #endif /* MRB_DISABLE_STDIO */ -- cgit v1.2.3 From a921b936d6370794d4d66c23a4863507e013becb Mon Sep 17 00:00:00 2001 From: yuri Date: Wed, 11 Jul 2018 14:14:12 +0900 Subject: move declaration of mrb_irep_remove_lv from dump.h to irep.h --- include/mruby/dump.h | 1 - include/mruby/irep.h | 1 + 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/include/mruby/dump.h b/include/mruby/dump.h index 39a99e97b..f56d66a32 100644 --- a/include/mruby/dump.h +++ b/include/mruby/dump.h @@ -31,7 +31,6 @@ MRB_API mrb_value mrb_load_irep_file(mrb_state*,FILE*); MRB_API mrb_value mrb_load_irep_file_cxt(mrb_state*, FILE*, mrbc_context*); #endif MRB_API mrb_irep *mrb_read_irep(mrb_state*, const uint8_t*); -void mrb_irep_remove_lv(mrb_state *mrb, mrb_irep *irep); /* dump/load error code * diff --git a/include/mruby/irep.h b/include/mruby/irep.h index efd226793..ad227be5d 100644 --- a/include/mruby/irep.h +++ b/include/mruby/irep.h @@ -56,6 +56,7 @@ void mrb_irep_free(mrb_state*, struct mrb_irep*); void mrb_irep_incref(mrb_state*, struct mrb_irep*); void mrb_irep_decref(mrb_state*, struct mrb_irep*); void mrb_irep_cutref(mrb_state*, struct mrb_irep*); +void mrb_irep_remove_lv(mrb_state *mrb, mrb_irep *irep); MRB_END_DECL -- cgit v1.2.3 From 0bc8d1979c30738485404dc502c0a4ea0719dd12 Mon Sep 17 00:00:00 2001 From: Sebastián Katzer Date: Sat, 21 Jul 2018 10:18:22 +0200 Subject: Network services might not be available --- mrbgems/mruby-socket/test/addrinfo.rb | 10 +++++----- mrbgems/mruby-socket/test/socket.rb | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/mrbgems/mruby-socket/test/addrinfo.rb b/mrbgems/mruby-socket/test/addrinfo.rb index 3ae46cd7b..491656179 100644 --- a/mrbgems/mruby-socket/test/addrinfo.rb +++ b/mrbgems/mruby-socket/test/addrinfo.rb @@ -7,7 +7,7 @@ assert('super class of Addrinfo') do end assert('Addrinfo.getaddrinfo') do - ary = Addrinfo.getaddrinfo("localhost", "domain", Socket::AF_INET, Socket::SOCK_STREAM) + ary = Addrinfo.getaddrinfo("localhost", 53, Socket::AF_INET, Socket::SOCK_STREAM) assert_true(ary.size >= 1) ai = ary[0] assert_equal(ai.afamily, Socket::AF_INET) @@ -19,9 +19,9 @@ end assert('Addrinfo.foreach') do # assume Addrinfo.getaddrinfo works well - a = Addrinfo.getaddrinfo("localhost", "domain") + a = Addrinfo.getaddrinfo("localhost", 80) b = [] - Addrinfo.foreach("localhost", "domain") { |ai| b << ai } + Addrinfo.foreach("localhost", 80) { |ai| b << ai } assert_equal(a.size, b.size) end @@ -35,7 +35,7 @@ assert('Addrinfo.ip') do end assert('Addrinfo.tcp') do - ai = Addrinfo.tcp('127.0.0.1', 'smtp') + ai = Addrinfo.tcp('127.0.0.1', 25) assert_equal('127.0.0.1', ai.ip_address) assert_equal(Socket::AF_INET, ai.afamily) assert_equal(25, ai.ip_port) @@ -44,7 +44,7 @@ assert('Addrinfo.tcp') do end assert('Addrinfo.udp') do - ai = Addrinfo.udp('127.0.0.1', 'domain') + ai = Addrinfo.udp('127.0.0.1', 53) assert_equal('127.0.0.1', ai.ip_address) assert_equal(Socket::AF_INET, ai.afamily) assert_equal(53, ai.ip_port) diff --git a/mrbgems/mruby-socket/test/socket.rb b/mrbgems/mruby-socket/test/socket.rb index aa893588f..efd8fc28e 100644 --- a/mrbgems/mruby-socket/test/socket.rb +++ b/mrbgems/mruby-socket/test/socket.rb @@ -5,7 +5,7 @@ assert('Socket.gethostname') do end assert('Socket::getaddrinfo') do - ret = Socket.getaddrinfo("localhost", "domain", Socket::AF_INET, Socket::SOCK_DGRAM) + ret = Socket.getaddrinfo("localhost", 53, Socket::AF_INET, Socket::SOCK_DGRAM) assert_true ret.size >= 1 a = ret[0] assert_equal "AF_INET", a[0] -- cgit v1.2.3 From b09d2eb90074c50ed83d4d10d3fe0393bc9e43da Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Mon, 23 Jul 2018 18:26:24 +0900 Subject: Kernel#instance_eval should define singleton methods; fix #4069 --- mrbgems/mruby-eval/src/eval.c | 1 + mrbgems/mruby-eval/test/eval.rb | 17 ++++++++++++++++- 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/mrbgems/mruby-eval/src/eval.c b/mrbgems/mruby-eval/src/eval.c index 14e89ac14..5c8e78acd 100644 --- a/mrbgems/mruby-eval/src/eval.c +++ b/mrbgems/mruby-eval/src/eval.c @@ -325,6 +325,7 @@ f_instance_eval(mrb_state *mrb, mrb_value self) proc = create_proc_from_string(mrb, s, len, mrb_nil_value(), file, line); MRB_PROC_SET_TARGET_CLASS(proc, mrb_class_ptr(cv)); mrb_assert(!MRB_PROC_CFUNC_P(proc)); + mrb->c->ci->target_class = mrb_class_ptr(cv); return exec_irep(mrb, self, proc); } else { diff --git a/mrbgems/mruby-eval/test/eval.rb b/mrbgems/mruby-eval/test/eval.rb index be43412f7..8cf658f29 100644 --- a/mrbgems/mruby-eval/test/eval.rb +++ b/mrbgems/mruby-eval/test/eval.rb @@ -100,7 +100,22 @@ assert('Object#instance_eval with begin-rescue-ensure execution order') do assert_equal([:enter_raise_hell, :begin, :rescue, :ensure], hell_raiser.raise_hell) end -assert('Kernel.#eval(strinng) Issue #4021') do +assert('Kernel#instance_eval() to define singleton methods Issue #3141') do + foo_class = Class.new do + def bar(x) + instance_eval "def baz; #{x}; end" + end + end + + f1 = foo_class.new + f2 = foo_class.new + f1.bar 1 + f2.bar 2 + assert_equal(1){f1.baz} + assert_equal(2){f2.baz} +end + +assert('Kernel.#eval(string) Issue #4021') do assert_equal('FOO') { (eval <<'EOS').call } foo = "FOO" Proc.new { foo } -- cgit v1.2.3 From 891839b976c75c77f238931123ac472e3284e95d Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Thu, 24 May 2018 15:19:06 +0900 Subject: New bytecode implementation of mruby VM. --- .gitignore | 1 + doc/opcode.md | 260 +++++ include/mruby.h | 16 +- include/mruby/class.h | 3 +- include/mruby/compile.h | 2 + include/mruby/irep.h | 2 +- include/mruby/opcode.h | 186 +--- include/mruby/ops.h | 116 +++ mrbgems/mruby-bin-debugger/tools/mrdb/mrdb.c | 2 +- mrbgems/mruby-compiler/core/codegen.c | 1351 +++++++++++++------------- mrbgems/mruby-compiler/core/parse.y | 15 + mrbgems/mruby-eval/src/eval.c | 112 ++- mrbgems/mruby-method/src/method.c | 6 +- mrbgems/mruby-proc-ext/src/proc.c | 12 +- mrbgems/mruby-string-ext/src/string.c | 4 +- src/class.c | 8 +- src/codedump.c | 772 ++++++++------- src/kernel.c | 2 +- src/load.c | 2 +- src/proc.c | 10 +- src/vm.c | 986 ++++++++----------- 21 files changed, 2072 insertions(+), 1796 deletions(-) create mode 100644 doc/opcode.md create mode 100644 include/mruby/ops.h diff --git a/.gitignore b/.gitignore index bccfaf218..9c34b5f29 100644 --- a/.gitignore +++ b/.gitignore @@ -15,6 +15,7 @@ .DS_Store .ccmalloc .svn +.vscode /.git cscope.files cscope.out diff --git a/doc/opcode.md b/doc/opcode.md new file mode 100644 index 000000000..d904256e5 --- /dev/null +++ b/doc/opcode.md @@ -0,0 +1,260 @@ +<<<<<<< HEAD +# The new bytecode + +We will reimplement VM to use 8bit instruction code. By +bytecode, we mean real byte code. The whole purpose is +reducing the memory consumption of mruby VM. + +# Instructions + +Instructions are bytes. There can be 256 instructions. Currently we +have 94 instructions. Instructions can take 0 to 3 operands. + +## operands + +The size of operands can be either 8bits, 16bits or 24bits. +In the table.1 below, the second field describes the size (and +sign) of operands. + +* B: 8bit +* sB: signed 8bit +* S: 16bit +* sS: signed 16bit +* W: 24bit + +First two byte operands may be extended to 16bit. When those byte +operands are bigger than 256, the instruction will be prefixed by +`OP_EXT1` (means 1st operand is 16bit) or `OP_EXT2` (means 2nd operand +is 16bit) or `OP_EXT3` (means 1st and 2nd operands are 16bit). + +For instructions marked by `'`, `OP_EXT1` can be prefixed. For those +with `"`, either `OP_EXT1` or `OP_EXT2` or `OP_EXT2` can be prefixed. + +## table.1 Instruction Table + +|Instruction Name |Operand type |Semantics +|-----------------|-------------|----------------- +|OP_NOP | - | +|OP_MOVE" |BB |R(a) = R(b) +|OP_LOADL" |BB |R(a) = Pool(b) +|OP_LOADI" |BsB |R(a) = mrb_int(b) +|OP_LOADI_0' |B |R(a) = 0 +|OP_LOADI_1' |B |R(a) = 1 +|OP_LOADI_2' |B |R(a) = 2 +|OP_LOADI_3' |B |R(a) = 3 +|OP_LOADSYM" |BB |R(a) = Syms(b) +|OP_LOADNIL' |B |R(a) = nil +|OP_LOADSELF' |B |R(a) = self +|OP_LOADT' |B |R(a) = true +|OP_LOADF' |B |R(a) = false +|OP_GETGV" |BB |R(a) = getglobal(Syms(b)) +|OP_SETGV" |BB |setglobal(Syms(b), R(a)) +|OP_GETSV" |BB |R(a) = Special[b] +|OP_SETSV" |BB |Special[b] = R(a) +|OP_GETIV" |BB |R(a) = ivget(Syms(b)) +|OP_SETIV" |BB |ivset(Syms(b),R(a)) +|OP_GETCV" |BB |R(a) = cvget(Syms(b)) +|OP_SETCV" |BB |cvset(Syms(b),R(a)) +|OP_GETCONST" |BB |R(a) = constget(Syms(b)) +|OP_SETCONST" |BB |constset(Syms(b),R(a)) +|OP_GETMCNST" |BB |R(a) = R(a)::Syms(b) +|OP_SETMCNST" |BB |R(a+1)::Syms(b) = R(a) +|OP_GETUPVAR' |BBB |R(a) = uvget(b,c) +|OP_SETUPVAR' |BBB |uvset(b,c,R(a)) +|OP_JMP |S |pc+=a +|OP_JMPIF' |SB |if R(b) pc+=a +|OP_JMPNOT' |SB |if !R(b) pc+=a +|OP_ONERR |sS |rescue_push(pc+a) +|OP_EXCEPT' |B |R(a) = exc +|OP_RESCUE" |BB |R(b) = R(a).isa?(R(b)) +|OP_POPERR |B |a.times{rescue_pop()} +|OP_RAISE' |B |raise(R(a)) +|OP_EPUSH' |B |ensure_push(SEQ[a]) +|OP_EPOP |B |A.times{ensure_pop().call} +|OP_SENDV" |BB |R(a) = call(R(a),Syms(b),*R(a+1)) +|OP_SENDVB" |BB |R(a) = call(R(a),Syms(b),*R(a+1),&R(a+2)) +|OP_SEND" |BBB |R(a) = call(R(a),Syms(b),R(a+1),...,R(a+c)) +|OP_SENDB" |BBB |R(a) = call(R(a),Syms(Bx),R(a+1),...,R(a+c),&R(a+c+1)) +|OP_CALL' |B |R(a) = self.call(frame.argc, frame.argv) +|OP_SUPER' |BB |R(a) = super(R(a+1),... ,R(a+b+1)) +|OP_ARGARY' |BS |R(a) = argument array (16=6:1:5:4) +|OP_ENTER |W |arg setup according to flags (23=5:5:1:5:5:1:1) +|OP_KARG" |BB |R(a) = kdict[Syms(Bx)] # todo +|OP_KARG2" |BB |R(a) = kdict[Syms(Bx)]; kdict.rm(Syms(b)) # todo +|OP_KDICT' |B |R(a) = kdict # todo +|OP_RETURN' |B |return R(a) (normal) +|OP_RETURN_BLK' |B |return R(a) (in-block return) +|OP_BREAK' |B |break R(a) +|OP_BLKPUSH' |BS |R(a) = block (16=6:1:5:4) +|OP_ADD" |BB |R(a) = R(a)+R(a+1) (Syms[b]=:+) +|OP_ADDI" |BBB |R(a) = R(a)+mrb_int(c) (Syms[b]=:+) +|OP_SUB" |BB |R(a) = R(a)-R(a+1) (Syms[b]=:-) +|OP_SUBI" |BB |R(a) = R(a)-C (Syms[b]=:-) +|OP_MUL" |BB |R(a) = R(a)*R(a+1) (Syms[b]=:*) +|OP_DIV" |BB |R(a) = R(a)/R(a+1) (Syms[b]=:/) +|OP_EQ" |BB |R(a) = R(a)==R(a+1) (Syms[b]=:==) +|OP_LT" |BB |R(a) = R(a)R(a+1) (Syms[b]=:>) +|OP_GE" |BB |R(a) = R(a)>=R(a+1) (Syms[b]=:>=) +|OP_ARRAY' |BB |R(a) = ary_new(R(a),R(a+1)..R(a+b)) +|OP_ARRAY2" |BB |R(a) = ary_new(R(b),R(b+1)..R(b+c)) +|OP_ARYCAT' |B |ary_cat(R(a),R(a+1)) +|OP_ARYPUSH' |B |ary_push(R(a),R(a+1)) +|OP_AREF' |BB |R(a) = R(a)[b] +|OP_ASET' |BB |R(a)[b] = R(a+1) +|OP_APOST' |BB |*R(a),R(A+1)..R(A+C) = R(a)[B..] +|OP_STRING" |BB |R(a) = str_dup(Lit(b)) +|OP_STRCAT' |B |str_cat(R(a),R(a+1)) +|OP_HASH' |BB |R(a) = hash_new(R(a),R(a+1)..R(a+b)) +|OP_HASHADD' |BB |R(a) = hash_push(R(a),R(a+1)..R(a+b)) +|OP_LAMBDA" |BB |R(a) = lambda(SEQ[b],OP_L_LAMBDA) +|OP_BLOCK" |BB |R(a) = lambda(SEQ[b],OP_L_BLOCK) +|OP_METHOD" |BB |R(a) = lambda(SEQ[b],OP_L_METHOD) +|OP_RANGE_INC' |B |R(a) = range_new(R(a),R(a+1),FALSE) +|OP_RANGE_EXC' |B |R(a) = range_new(R(a),R(a+1),TRUE) +|OP_OCLASS' |B |R(a) = ::Object +|OP_CLASS" |BB |R(a) = newclass(R(a),Syms(b),R(a+1)) +|OP_MODULE" |BB |R(a) = newmodule(R(a),Syms(b)) +|OP_EXEC" |BB |R(a) = blockexec(R(a),SEQ[b]) +|OP_DEF" |BB |R(a).newmethod(Syms(b),R(a+1)) +|OP_ALIAS' |B |alias_method(R(a),R(a+1),R(a+2)) +|OP_UNDEF" |BB |undef_method(R(a),Syms(b)) +|OP_SCLASS' |B |R(a) = R(a).singleton_class +|OP_TCLASS' |B |R(a) = target_class +|OP_ERR' |B |raise(RuntimeError, Lit(Bx)) +|OP_EXT1 |- |make 1st operand 16bit +|OP_EXT2 |- |make 2nd operand 16bit +|OP_EXT3 |- |make 1st and 2nd operands 16bit +|OP_STOP |- |stop VM +||||||| parent of b6821923... New bytecode implementation of mruby VM. +======= +# The new bytecode + +We will reimplement VM to use 8bit instruction code. By +bytecode, we mean real byte code. The whole purpose is +reducing the memory consumption of mruby VM. + +# Instructions + +Instructions are bytes. There can be 256 instructions. Currently we +have 94 instructions. Instructions can take 0 to 3 operands. + +## operands + +The size of operands can be either 8bits, 16bits or 24bits. +In the table.1 below, the second field describes the size (and +sign) of operands. + +* B: 8bit +* sB: signed 8bit +* S: 16bit +* sS: signed 16bit +* W: 24bit + +First two byte operands may be extended to 16bit. When those byte +operands are bigger than 256, the instruction will be prefixed by +`OP_EXT1` (means 1st operand is 16bit) or `OP_EXT2` (means 2nd operand +is 16bit) or `OP_EXT3` (means 1st and 2nd operands are 16bit). + +For instructions marked by `'`, `OP_EXT1` can be prefixed. For those +with `"`, either `OP_EXT1` or `OP_EXT2` or `OP_EXT2` can be prefixed. + +## table.1 Instruction Table + +|Instruction Name |Operand type |Semantics +|-----------------|-------------|----------------- +|OP_NOP | - | +|OP_MOVE" |BB |R(a) = R(b) +|OP_LOADL" |BB |R(a) = Pool(b) +|OP_LOADI" |BsB |R(a) = mrb_int(b) +|OP_LOADI_0' |B |R(a) = 0 +|OP_LOADI_1' |B |R(a) = 1 +|OP_LOADI_2' |B |R(a) = 2 +|OP_LOADI_3' |B |R(a) = 3 +|OP_LOADSYM" |BB |R(a) = Syms(b) +|OP_LOADNIL' |B |R(a) = nil +|OP_LOADSELF' |B |R(a) = self +|OP_LOADT' |B |R(a) = true +|OP_LOADF' |B |R(a) = false +|OP_GETGV" |BB |R(a) = getglobal(Syms(b)) +|OP_SETGV" |BB |setglobal(Syms(b), R(a)) +|OP_GETSV" |BB |R(a) = Special[b] +|OP_SETSV" |BB |Special[b] = R(a) +|OP_GETIV" |BB |R(a) = ivget(Syms(b)) +|OP_SETIV" |BB |ivset(Syms(b),R(a)) +|OP_GETCV" |BB |R(a) = cvget(Syms(b)) +|OP_SETCV" |BB |cvset(Syms(b),R(a)) +|OP_GETCONST" |BB |R(a) = constget(Syms(b)) +|OP_SETCONST" |BB |constset(Syms(b),R(a)) +|OP_GETMCNST" |BB |R(a) = R(a)::Syms(b) +|OP_SETMCNST" |BB |R(a+1)::Syms(b) = R(a) +|OP_GETUPVAR' |BBB |R(a) = uvget(b,c) +|OP_SETUPVAR' |BBB |uvset(b,c,R(a)) +|OP_JMP |S |pc+=a +|OP_JMPIF' |SB |if R(b) pc+=a +|OP_JMPNOT' |SB |if !R(b) pc+=a +|OP_ONERR |sS |rescue_push(pc+a) +|OP_EXCEPT' |B |R(a) = exc +|OP_RESCUE" |BB |R(b) = R(a).isa?(R(b)) +|OP_POPERR |B |a.times{rescue_pop()} +|OP_RAISE' |B |raise(R(a)) +|OP_EPUSH' |B |ensure_push(SEQ[a]) +|OP_EPOP |B |A.times{ensure_pop().call} +|OP_SENDV" |BB |R(a) = call(R(a),Syms(b),*R(a+1)) +|OP_SENDVB" |BB |R(a) = call(R(a),Syms(b),*R(a+1),&R(a+2)) +|OP_SEND" |BBB |R(a) = call(R(a),Syms(b),R(a+1),...,R(a+c)) +|OP_SENDB" |BBB |R(a) = call(R(a),Syms(Bx),R(a+1),...,R(a+c),&R(a+c+1)) +|OP_CALL' |B |R(a) = self.call(frame.argc, frame.argv) +|OP_SUPER' |BB |R(a) = super(R(a+1),... ,R(a+b+1)) +|OP_ARGARY' |BS |R(a) = argument array (16=6:1:5:4) +|OP_ENTER |W |arg setup according to flags (23=5:5:1:5:5:1:1) +|OP_KARG" |BB |R(a) = kdict[Syms(Bx)] # todo +|OP_KARG2" |BB |R(a) = kdict[Syms(Bx)]; kdict.rm(Syms(b)) # todo +|OP_KDICT' |B |R(a) = kdict # todo +|OP_RETURN' |B |return R(a) (normal) +|OP_RETURN_BLK' |B |return R(a) (in-block return) +|OP_BREAK' |B |break R(a) +|OP_BLKPUSH' |BS |R(a) = block (16=6:1:5:4) +|OP_ADD" |BB |R(a) = R(a)+R(a+1) (Syms[b]=:+) +|OP_ADDI" |BBB |R(a) = R(a)+mrb_int(c) (Syms[b]=:+) +|OP_SUB" |BB |R(a) = R(a)-R(a+1) (Syms[b]=:-) +|OP_SUBI" |BB |R(a) = R(a)-C (Syms[b]=:-) +|OP_MUL" |BB |R(a) = R(a)*R(a+1) (Syms[b]=:*) +|OP_DIV" |BB |R(a) = R(a)/R(a+1) (Syms[b]=:/) +|OP_EQ" |BB |R(a) = R(a)==R(a+1) (Syms[b]=:==) +|OP_LT" |BB |R(a) = R(a)R(a+1) (Syms[b]=:>) +|OP_GE" |BB |R(a) = R(a)>=R(a+1) (Syms[b]=:>=) +|OP_ARRAY' |BB |R(a) = ary_new(R(a),R(a+1)..R(a+b)) +|OP_ARRAY2" |BB |R(a) = ary_new(R(b),R(b+1)..R(b+c)) +|OP_ARYCAT' |B |ary_cat(R(a),R(a+1)) +|OP_ARYPUSH' |B |ary_push(R(a),R(a+1)) +|OP_AREF' |BB |R(a) = R(a)[b] +|OP_ASET' |BB |R(a)[b] = R(a+1) +|OP_APOST' |BB |*R(a),R(A+1)..R(A+C) = R(a)[B..] +|OP_STRING" |BB |R(a) = str_dup(Lit(b)) +|OP_STRCAT' |B |str_cat(R(a),R(a+1)) +|OP_HASH' |BB |R(a) = hash_new(R(a),R(a+1)..R(a+b)) +|OP_HASHADD' |BB |R(a) = hash_push(R(a),R(a+1)..R(a+b)) +|OP_LAMBDA" |BB |R(a) = lambda(SEQ[b],OP_L_LAMBDA) +|OP_BLOCK" |BB |R(a) = lambda(SEQ[b],OP_L_BLOCK) +|OP_METHOD" |BB |R(a) = lambda(SEQ[b],OP_L_METHOD) +|OP_RANGE_INC' |B |R(a) = range_new(R(a),R(a+1),FALSE) +|OP_RANGE_EXC' |B |R(a) = range_new(R(a),R(a+1),TRUE) +|OP_OCLASS' |B |R(a) = ::Object +|OP_CLASS" |BB |R(a) = newclass(R(a),Syms(b),R(a+1)) +|OP_MODULE" |BB |R(a) = newmodule(R(a),Syms(b)) +|OP_EXEC" |BB |R(a) = blockexec(R(a),SEQ[b]) +|OP_DEF" |BB |R(a).newmethod(Syms(b),R(a+1)) +|OP_ALIAS' |B |alias_method(R(a),R(a+1),R(a+2)) +|OP_UNDEF" |BB |undef_method(R(a),Syms(b)) +|OP_SCLASS' |B |R(a) = R(a).singleton_class +|OP_TCLASS' |B |R(a) = target_class +|OP_ERR' |B |raise(RuntimeError, Lit(Bx)) +|OP_EXT1 |- |make 1st operand 16bit +|OP_EXT2 |- |make 2nd operand 16bit +|OP_EXT3 |- |make 1st and 2nd operands 16bit +|OP_STOP |- |stop VM +>>>>>>> b6821923... New bytecode implementation of mruby VM. diff --git a/include/mruby.h b/include/mruby.h index b0bfe78b5..7cbc690b3 100644 --- a/include/mruby.h +++ b/include/mruby.h @@ -93,7 +93,7 @@ */ MRB_BEGIN_DECL -typedef uint32_t mrb_code; +typedef uint8_t mrb_code; /** * Required arguments signature type. @@ -123,9 +123,9 @@ typedef struct { mrb_sym mid; struct RProc *proc; mrb_value *stackent; - int nregs; - int ridx; - int epos; + uint16_t nregs; + uint16_t ridx; + uint16_t epos; struct REnv *env; mrb_code *pc; /* return address */ mrb_code *err; /* error position */ @@ -152,10 +152,10 @@ struct mrb_context { mrb_callinfo *ci; mrb_callinfo *cibase, *ciend; - mrb_code **rescue; /* exception handler stack */ + uint16_t *rescue; /* exception handler stack */ int rsize; struct RProc **ensure; /* ensure handler stack */ - int esize, eidx; + uint8_t esize, eidx; enum mrb_fiber_state status; mrb_bool vmexec; @@ -486,9 +486,10 @@ MRB_API void mrb_define_const(mrb_state*, struct RClass*, const char *name, mrb_ * } * @param [mrb_state*] mrb_state* The mruby state reference. * @param [struct RClass*] RClass* A class the method will be undefined from. - * @param [const char*] constchar* The name of the method to be undefined. + * @param [const char] const char* The name of the method to be undefined. */ MRB_API void mrb_undef_method(mrb_state*, struct RClass*, const char*); +MRB_API void mrb_undef_method_id(mrb_state*, struct RClass*, mrb_sym); /** * Undefine a class method. @@ -1197,7 +1198,6 @@ typedef enum call_type { CALL_TYPE_MAX } call_type; -MRB_API void mrb_define_alias(mrb_state *mrb, struct RClass *klass, const char *name1, const char *name2); MRB_API const char *mrb_class_name(mrb_state *mrb, struct RClass* klass); MRB_API void mrb_define_global_const(mrb_state *mrb, const char *name, mrb_value val); diff --git a/include/mruby/class.h b/include/mruby/class.h index ea35d8e17..706a4d37c 100644 --- a/include/mruby/class.h +++ b/include/mruby/class.h @@ -76,7 +76,8 @@ MRB_API struct RClass *mrb_vm_define_class(mrb_state*, mrb_value, mrb_value, mrb MRB_API struct RClass *mrb_vm_define_module(mrb_state*, mrb_value, mrb_sym); MRB_API void mrb_define_method_raw(mrb_state*, struct RClass*, mrb_sym, mrb_method_t); MRB_API void mrb_define_method_id(mrb_state *mrb, struct RClass *c, mrb_sym mid, mrb_func_t func, mrb_aspec aspec); -MRB_API void mrb_alias_method(mrb_state *mrb, struct RClass *c, mrb_sym a, mrb_sym b); +MRB_API void mrb_alias_method(mrb_state*, struct RClass *c, mrb_sym a, mrb_sym b); +MRB_API void mrb_define_alias(mrb_state*, struct RClass *c, const char* a, const char* b); MRB_API mrb_method_t mrb_method_search_vm(mrb_state*, struct RClass**, mrb_sym); MRB_API mrb_method_t mrb_method_search(mrb_state*, struct RClass*, mrb_sym); diff --git a/include/mruby/compile.h b/include/mruby/compile.h index d7d029616..a85460415 100644 --- a/include/mruby/compile.h +++ b/include/mruby/compile.h @@ -33,6 +33,7 @@ typedef struct mrbc_context { mrb_bool no_exec:1; mrb_bool keep_lv:1; mrb_bool no_optimize:1; + mrb_bool on_eval:1; size_t parser_nerr; } mrbc_context; @@ -151,6 +152,7 @@ struct mrb_parser_state { mrb_ast_node *tree; mrb_bool no_optimize:1; + mrb_bool on_eval:1; mrb_bool capture_errors:1; struct mrb_parser_message error_buffer[10]; struct mrb_parser_message warn_buffer[10]; diff --git a/include/mruby/irep.h b/include/mruby/irep.h index ad227be5d..c98d008db 100644 --- a/include/mruby/irep.h +++ b/include/mruby/irep.h @@ -44,7 +44,7 @@ typedef struct mrb_irep { uint16_t *lines; struct mrb_irep_debug_info* debug_info; - int ilen, plen, slen, rlen, refcnt; + uint16_t ilen, plen, slen, rlen, refcnt; } mrb_irep; #define MRB_ISEQ_NO_FREE 1 diff --git a/include/mruby/opcode.h b/include/mruby/opcode.h index a5e3af158..d513ca472 100644 --- a/include/mruby/opcode.h +++ b/include/mruby/opcode.h @@ -7,145 +7,10 @@ #ifndef MRUBY_OPCODE_H #define MRUBY_OPCODE_H -#define MAXARG_Bx (0xffff) -#define MAXARG_sBx (MAXARG_Bx>>1) /* 'sBx' is signed */ - -/* instructions: packed 32 bit */ -/* ------------------------------- */ -/* A:B:C:OP = 9: 9: 7: 7 */ -/* A:Bx:OP = 9:16: 7 */ -/* Ax:OP = 25: 7 */ -/* A:Bz:Cz:OP = 9:14: 2: 7 */ - -#define GET_OPCODE(i) ((int)(((mrb_code)(i)) & 0x7f)) -#define GETARG_A(i) ((int)((((mrb_code)(i)) >> 23) & 0x1ff)) -#define GETARG_B(i) ((int)((((mrb_code)(i)) >> 14) & 0x1ff)) -#define GETARG_C(i) ((int)((((mrb_code)(i)) >> 7) & 0x7f)) -#define GETARG_Bx(i) ((int)((((mrb_code)(i)) >> 7) & 0xffff)) -#define GETARG_sBx(i) ((int)(GETARG_Bx(i)-MAXARG_sBx)) -#define GETARG_Ax(i) ((int32_t)((((mrb_code)(i)) >> 7) & 0x1ffffff)) -#define GETARG_UNPACK_b(i,n1,n2) ((int)((((mrb_code)(i)) >> (7+(n2))) & (((1<<(n1))-1)))) -#define GETARG_UNPACK_c(i,n1,n2) ((int)((((mrb_code)(i)) >> 7) & (((1<<(n2))-1)))) -#define GETARG_b(i) GETARG_UNPACK_b(i,14,2) -#define GETARG_c(i) GETARG_UNPACK_c(i,14,2) - -#define MKOPCODE(op) ((op) & 0x7f) -#define MKARG_A(c) ((mrb_code)((c) & 0x1ff) << 23) -#define MKARG_B(c) ((mrb_code)((c) & 0x1ff) << 14) -#define MKARG_C(c) (((c) & 0x7f) << 7) -#define MKARG_Bx(v) ((mrb_code)((v) & 0xffff) << 7) -#define MKARG_sBx(v) MKARG_Bx((v)+MAXARG_sBx) -#define MKARG_Ax(v) ((mrb_code)((v) & 0x1ffffff) << 7) -#define MKARG_PACK(b,n1,c,n2) ((((b) & ((1<R(A+1) (Syms[B]=:>,C=1) */ - OP_GE,/* A B C R(A) := R(A)>=R(A+1) (Syms[B]=:>=,C=1) */ - - OP_ARRAY,/* A B C R(A) := ary_new(R(B),R(B+1)..R(B+C)) */ - OP_ARYCAT,/* A B ary_cat(R(A),R(B)) */ - OP_ARYPUSH,/* A B ary_push(R(A),R(B)) */ - OP_AREF,/* A B C R(A) := R(B)[C] */ - OP_ASET,/* A B C R(B)[C] := R(A) */ - OP_APOST,/* A B C *R(A),R(A+1)..R(A+C) := R(A)[B..] */ - - OP_STRING,/* A Bx R(A) := str_dup(Lit(Bx)) */ - OP_STRCAT,/* A B str_cat(R(A),R(B)) */ - - OP_HASH,/* A B C R(A) := hash_new(R(B),R(B+1)..R(B+C)) */ - OP_LAMBDA,/* A Bz Cz R(A) := lambda(SEQ[Bz],Cz) */ - OP_RANGE,/* A B C R(A) := range_new(R(B),R(B+1),C) */ - - OP_OCLASS,/* A R(A) := ::Object */ - OP_CLASS,/* A B R(A) := newclass(R(A),Syms(B),R(A+1)) */ - OP_MODULE,/* A B R(A) := newmodule(R(A),Syms(B)) */ - OP_EXEC,/* A Bx R(A) := blockexec(R(A),SEQ[Bx]) */ - OP_METHOD,/* A B R(A).newmethod(Syms(B),R(A+1)) */ - OP_SCLASS,/* A B R(A) := R(B).singleton_class */ - OP_TCLASS,/* A R(A) := target_class */ - - OP_DEBUG,/* A B C print R(A),R(B),R(C) */ - OP_STOP,/* stop VM */ - OP_ERR,/* Bx raise RuntimeError with message Lit(Bx) */ - - OP_RSVD1,/* reserved instruction #1 */ - OP_RSVD2,/* reserved instruction #2 */ - OP_RSVD3,/* reserved instruction #3 */ - OP_RSVD4,/* reserved instruction #4 */ - OP_RSVD5,/* reserved instruction #5 */ +enum mrb_insn { +#define OPCODE(x,_) OP_ ## x, +#include "mruby/ops.h" +#undef OPCODE }; #define OP_L_STRICT 1 @@ -158,4 +23,47 @@ enum { #define OP_R_BREAK 1 #define OP_R_RETURN 2 +#define PEEK_B(pc) (*(pc)) +#define PEEK_S(pc) ((pc)[0]<<8|(pc)[1]) +#define PEEK_W(pc) ((pc)[0]<<16|(pc)[1]<<8|(pc)[2]) + +#define READ_B() PEEK_B(pc++) +#define READ_S() (pc+=2, PEEK_S(pc-2)) +#define READ_W() (pc+=3, PEEK_W(pc-3)) + +#define FETCH_Z() /* nothing */ +#define FETCH_B() do {a=READ_B();} while (0) +#define FETCH_BB() do {a=READ_B(); b=READ_B();} while (0) +#define FETCH_BBB() do {a=READ_B(); b=READ_B(); c=READ_B();} while (0) +#define FETCH_BS() do {a=READ_B(); b=READ_S();} while (0) +#define FETCH_S() do {a=READ_S();} while (0) +#define FETCH_W() do {a=READ_W();} while (0) + +/* with OP_EXT1 (1st 16bit) */ +#define FETCH_Z_1() FETCH_Z() +#define FETCH_B_1() FETCH_S() +#define FETCH_BB_1() do {a=READ_S(); b=READ_B();} while (0) +#define FETCH_BBB_1() do {a=READ_S(); b=READ_B(); c=READ_B();} while (0) +#define FETCH_BS_1() do {a=READ_S(); b=READ_S();} while (0) +#define FETCH_S_1() FETCH_S() +#define FETCH_W_1() FETCH_W() + +/* with OP_EXT2 (2nd 16bit) */ +#define FETCH_Z_2() FETCH_Z() +#define FETCH_B_2() FETCH_B() +#define FETCH_BB_2() do {a=READ_B(); b=READ_S();} while (0) +#define FETCH_BBB_2() do {a=READ_B(); b=READ_S(); c=READ_B();} while (0) +#define FETCH_BS_2() FETCH_BS() +#define FETCH_S_2() FETCH_S() +#define FETCH_W_2() FETCH_W() + +/* with OP_EXT3 (1st & 2nd 16bit) */ +#define FETCH_Z_3() FETCH_Z() +#define FETCH_B_3() FETCH_B() +#define FETCH_BB_3() do {a=READ_S(); b=READ_S();} while (0) +#define FETCH_BBB_3() do {a=READ_S(); b=READ_S(); c=READ_B();} while (0) +#define FETCH_BS_3() do {a=READ_S(); b=READ_S();} while (0) +#define FETCH_S_3() FETCH_S() +#define FETCH_W_3() FETCH_W() + #endif /* MRUBY_OPCODE_H */ diff --git a/include/mruby/ops.h b/include/mruby/ops.h new file mode 100644 index 000000000..882ad6f25 --- /dev/null +++ b/include/mruby/ops.h @@ -0,0 +1,116 @@ +/* operand types: + + Z: no operand (Z,Z,Z,Z) + + B: 8bit (B,S,B,B) + + BB: 8+8bit (BB,SB,BS,SS) + + BBB: 8+8+8bit (BBB,SBB,BSB,SSB) + + BS: 8+16bit (BS,SS,BS,BS) + + S: 16bit (S,S,S,S) + + W: 24bit (W,W,W,W) +*/ + +/*----------------------------------------------------------------------- +operation code operands semantics +------------------------------------------------------------------------*/ +OPCODE(NOP, Z) /* no operation */ +OPCODE(MOVE, BB) /* R(a) = R(b) */ +OPCODE(LOADL, BB) /* R(a) = Pool(b) */ +OPCODE(LOADI, BB) /* R(a) = mrb_int(b) */ +OPCODE(LOADINEG, BB) /* R(a) = mrb_int(-b) */ +OPCODE(LOADI__1, B) /* R(a) = mrb_int(-1) */ +OPCODE(LOADI_0, B) /* R(a) = mrb_int(0) */ +OPCODE(LOADI_1, B) /* R(a) = mrb_int(1) */ +OPCODE(LOADI_2, B) /* R(a) = mrb_int(2) */ +OPCODE(LOADI_3, B) /* R(a) = mrb_int(3) */ +OPCODE(LOADI_4, B) /* R(a) = mrb_int(4) */ +OPCODE(LOADI_5, B) /* R(a) = mrb_int(5) */ +OPCODE(LOADI_6, B) /* R(a) = mrb_int(6) */ +OPCODE(LOADI_7, B) /* R(a) = mrb_int(7) */ +OPCODE(LOADSYM, BB) /* R(a) = Syms(b) */ +OPCODE(LOADNIL, B) /* R(a) = nil */ +OPCODE(LOADSELF, B) /* R(a) = self */ +OPCODE(LOADT, B) /* R(a) = true */ +OPCODE(LOADF, B) /* R(a) = false */ +OPCODE(GETGV, BB) /* R(a) = getglobal(Syms(b)) */ +OPCODE(SETGV, BB) /* setglobal(Syms(b), R(a)) */ +OPCODE(GETSV, BB) /* R(a) = Special[Syms(b)] */ +OPCODE(SETSV, BB) /* Special[Syms(b)] = R(a) */ +OPCODE(GETIV, BB) /* R(a) = ivget(Syms(b)) */ +OPCODE(SETIV, BB) /* ivset(Syms(b),R(a)) */ +OPCODE(GETCV, BB) /* R(a) = cvget(Syms(b)) */ +OPCODE(SETCV, BB) /* cvset(Syms(b),R(a)) */ +OPCODE(GETCONST, BB) /* R(a) = constget(Syms(b)) */ +OPCODE(SETCONST, BB) /* constset(Syms(b),R(a)) */ +OPCODE(GETMCNST, BB) /* R(a) = R(a)::Syms(b) */ +OPCODE(SETMCNST, BB) /* R(a+1)::Syms(b) = R(a) */ +OPCODE(GETUPVAR, BBB) /* R(a) = uvget(b,c) */ +OPCODE(SETUPVAR, BBB) /* uvset(b,c,R(a)) */ +OPCODE(JMP, S) /* pc=a */ +OPCODE(JMPIF, BS) /* if R(b) pc=a */ +OPCODE(JMPNOT, BS) /* if !R(b) pc=a */ +OPCODE(JMPNIL, BS) /* if R(b)==nil pc=a */ +OPCODE(ONERR, S) /* rescue_push(a) */ +OPCODE(EXCEPT, B) /* R(a) = exc */ +OPCODE(RESCUE, BB) /* R(b) = R(a).isa?(R(b)) */ +OPCODE(POPERR, B) /* a.times{rescue_pop()} */ +OPCODE(RAISE, B) /* raise(R(a)) */ +OPCODE(EPUSH, B) /* ensure_push(SEQ[a]) */ +OPCODE(EPOP, B) /* A.times{ensure_pop().call} */ +OPCODE(SENDV, BB) /* R(a) = call(R(a),Syms(b),*R(a+1)) */ +OPCODE(SENDVB, BB) /* R(a) = call(R(a),Syms(b),*R(a+1),&R(a+2)) */ +OPCODE(SEND, BBB) /* R(a) = call(R(a),Syms(b),R(a+1),...,R(a+c)) */ +OPCODE(SENDB, BBB) /* R(a) = call(R(a),Syms(Bx),R(a+1),...,R(a+c),&R(a+c+1)) */ +OPCODE(CALL, Z) /* R(0) = self.call(frame.argc, frame.argv) */ +OPCODE(SUPER, BB) /* R(a) = super(R(a+1),... ,R(a+b+1)) */ +OPCODE(ARGARY, BS) /* R(a) = argument array (16=6:1:5:4) */ +OPCODE(ENTER, W) /* arg setup according to flags (23=5:5:1:5:5:1:1) */ +OPCODE(KARG, BB) /* R(a) = kdict[Syms(Bx)] # todo */ +OPCODE(KARG2, BB) /* R(a) = kdict[Syms(Bx)]; kdict.rm(Syms(b)) # todo */ +OPCODE(KDICT, B) /* R(a) = kdict # todo */ +OPCODE(RETURN, B) /* return R(a) (normal) */ +OPCODE(RETURN_BLK, B) /* return R(a) (in-block return) */ +OPCODE(BREAK, B) /* break R(a) */ +OPCODE(BLKPUSH, BS) /* R(a) = block (16=6:1:5:4) */ +OPCODE(ADD, BB) /* R(a) = R(a)+R(a+1) (Syms[b]=:+) */ +OPCODE(ADDI, BBB) /* R(a) = R(a)+mrb_int(c) (Syms[b]=:+) */ +OPCODE(SUB, BB) /* R(a) = R(a)-R(a+1) (Syms[b]=:-) */ +OPCODE(SUBI, BBB) /* R(a) = R(a)-C (Syms[b]=:-) */ +OPCODE(MUL, BB) /* R(a) = R(a)*R(a+1) (Syms[b]=:*) */ +OPCODE(DIV, BB) /* R(a) = R(a)/R(a+1) (Syms[b]=:/) */ +OPCODE(EQ, BB) /* R(a) = R(a)==R(a+1) (Syms[b]=:==) */ +OPCODE(LT, BB) /* R(a) = R(a)R(a+1) (Syms[b]=:>) */ +OPCODE(GE, BB) /* R(a) = R(a)>=R(a+1) (Syms[b]=:>=) */ +OPCODE(ARRAY, BB) /* R(a) = ary_new(R(a),R(a+1)..R(a+b)) */ +OPCODE(ARRAY2, BBB) /* R(a) = ary_new(R(b),R(b+1)..R(b+c)) */ +OPCODE(ARYCAT, B) /* ary_cat(R(a),R(a+1)) */ +OPCODE(ARYPUSH, B) /* ary_push(R(a),R(a+1)) */ +OPCODE(ARYDUP, B) /* R(a) = ary_dup(R(a)) */ +OPCODE(AREF, BBB) /* R(a) = R(b)[c] */ +OPCODE(ASET, BBB) /* R(a)[c] = R(b) */ +OPCODE(APOST, BBB) /* *R(a),R(a+1)..R(a+C) = R(a)[b..] */ +OPCODE(INTERN, B) /* R(a) = intern(R(a)) */ +OPCODE(STRING, BB) /* R(a) = str_dup(Lit(b)) */ +OPCODE(STRCAT, B) /* str_cat(R(a),R(a+1)) */ +OPCODE(HASH, BB) /* R(a) = hash_new(R(a),R(a+1)..R(a+b)) */ +OPCODE(HASHADD, BB) /* R(a) = hash_push(R(a),R(a+1)..R(a+b)) */ +OPCODE(LAMBDA, BB) /* R(a) = lambda(SEQ[b],L_LAMBDA) */ +OPCODE(BLOCK, BB) /* R(a) = lambda(SEQ[b],L_BLOCK) */ +OPCODE(METHOD, BB) /* R(a) = lambda(SEQ[b],L_METHOD) */ +OPCODE(RANGE_INC, B) /* R(a) = range_new(R(a),R(a+1),FALSE) */ +OPCODE(RANGE_EXC, B) /* R(a) = range_new(R(a),R(a+1),TRUE) */ +OPCODE(OCLASS, B) /* R(a) = ::Object */ +OPCODE(CLASS, BB) /* R(a) = newclass(R(a),Syms(b),R(a+1)) */ +OPCODE(MODULE, BB) /* R(a) = newmodule(R(a),Syms(b)) */ +OPCODE(EXEC, BB) /* R(a) = blockexec(R(a),SEQ[b]) */ +OPCODE(DEF, BB) /* R(a).newmethod(Syms(b),R(a+1)) */ +OPCODE(ALIAS, BB) /* alias_method(target_class,Syms(a),Syms(b)) */ +OPCODE(UNDEF, B) /* undef_method(target_class,Syms(a)) */ +OPCODE(SCLASS, B) /* R(a) = R(a).singleton_class */ +OPCODE(TCLASS, B) /* R(a) = target_class */ +OPCODE(DEBUG, BBB) /* print a,b,c */ +OPCODE(ERR, B) /* raise(LocalJumpError, Lit(a)) */ +OPCODE(EXT1, Z) /* make 1st operand 16bit */ +OPCODE(EXT2, Z) /* make 2nd operand 16bit */ +OPCODE(EXT3, Z) /* make 1st and 2nd operands 16bit */ +OPCODE(STOP, Z) /* stop VM */ diff --git a/mrbgems/mruby-bin-debugger/tools/mrdb/mrdb.c b/mrbgems/mruby-bin-debugger/tools/mrdb/mrdb.c index 0588dfca5..1b17128fd 100644 --- a/mrbgems/mruby-bin-debugger/tools/mrdb/mrdb.c +++ b/mrbgems/mruby-bin-debugger/tools/mrdb/mrdb.c @@ -517,7 +517,7 @@ check_method_breakpoint(mrb_state *mrb, mrb_irep *irep, mrb_code *pc, mrb_value bpno = dbg->method_bpno; dbg->method_bpno = 0; - switch(GET_OPCODE(*pc)) { + switch(*pc) { case OP_SEND: case OP_SENDB: c = mrb_class(mrb, regs[GETARG_A(*pc)]); diff --git a/mrbgems/mruby-compiler/core/codegen.c b/mrbgems/mruby-compiler/core/codegen.c index fec747f0c..3ba2324fb 100644 --- a/mrbgems/mruby-compiler/core/codegen.c +++ b/mrbgems/mruby-compiler/core/codegen.c @@ -23,6 +23,8 @@ #define MRB_CODEGEN_LEVEL_MAX 1024 #endif +#define MAXARG_S (1<<16) + typedef mrb_ast_node node; typedef struct mrb_parser_state parser_state; @@ -36,7 +38,7 @@ enum looptype { struct loopinfo { enum looptype type; - int pc1, pc2, pc3, acc; + int pc0, pc1, pc2, pc3, acc; int ensure_level; struct loopinfo *prev; }; @@ -50,9 +52,10 @@ typedef struct scope { node *lv; - int sp; - int pc; - int lastlabel; + uint16_t sp; + uint16_t pc; + uint16_t lastpc; + uint16_t lastlabel; int ainfo:15; mrb_bool mscope:1; @@ -63,10 +66,10 @@ typedef struct scope { mrb_code *iseq; uint16_t *lines; - int icapa; + uint32_t icapa; mrb_irep *irep; - int pcapa, scapa, rcapa; + uint32_t pcapa, scapa, rcapa; uint16_t nlocals; uint16_t nregs; @@ -142,38 +145,141 @@ codegen_realloc(codegen_scope *s, void *p, size_t len) static int new_label(codegen_scope *s) { - s->lastlabel = s->pc; - return s->pc; + return s->lastlabel = s->pc; } -static inline int -genop(codegen_scope *s, mrb_code i) +static void +emit_B(codegen_scope *s, uint32_t pc, uint8_t i) { - if (s->pc >= s->icapa) { + if (pc >= s->icapa) { s->icapa *= 2; - if (s->pc >= MAXARG_sBx) { + if (pc >= MAXARG_S) { codegen_error(s, "too big code block"); } - if (s->icapa > MAXARG_sBx) { - s->icapa = MAXARG_sBx; + if (s->icapa > MAXARG_S) { + s->icapa = MAXARG_S; } s->iseq = (mrb_code *)codegen_realloc(s, s->iseq, sizeof(mrb_code)*s->icapa); if (s->lines) { - s->lines = (uint16_t*)codegen_realloc(s, s->lines, sizeof(short)*s->icapa); + s->lines = (uint16_t*)codegen_realloc(s, s->lines, sizeof(uint16_t)*s->icapa); s->irep->lines = s->lines; } } - s->iseq[s->pc] = i; if (s->lines) { - s->lines[s->pc] = s->lineno; + s->lines[pc] = s->lineno; + } + s->iseq[pc] = i; +} + +static void +emit_S(codegen_scope *s, int pc, uint16_t i) +{ + uint8_t hi = i>>8; + uint8_t lo = i&0xff; + + emit_B(s, pc, hi); + emit_B(s, pc+1, lo); +} + +static void +gen_B(codegen_scope *s, uint8_t i) +{ + emit_B(s, s->pc++, i); +} + +static void +gen_S(codegen_scope *s, uint16_t i) +{ + emit_S(s, s->pc, i); + s->pc += 2; +} + +static void +genop_0(codegen_scope *s, mrb_code i) +{ + s->lastpc = s->pc; + gen_B(s, i); +} + +static void +genop_1(codegen_scope *s, mrb_code i, uint16_t a) +{ + s->lastpc = s->pc; + if (a > 0xff) { + gen_B(s, OP_EXT1); + gen_B(s, i); + gen_S(s, a); + } + else { + gen_B(s, i); + gen_B(s, (uint8_t)a); + } +} + +static void +genop_2(codegen_scope *s, mrb_code i, uint16_t a, uint16_t b) +{ + s->lastpc = s->pc; + if (a > 0xff && b > 0xff) { + gen_B(s, OP_EXT3); + gen_B(s, i); + gen_S(s, a); + gen_S(s, b); + } + else if (b > 0xff) { + gen_B(s, OP_EXT2); + gen_B(s, i); + gen_B(s, (uint8_t)a); + gen_S(s, b); + } + else if (a > 0xff) { + gen_B(s, OP_EXT1); + gen_B(s, i); + gen_S(s, a); + gen_B(s, (uint8_t)b); + } + else { + gen_B(s, i); + gen_B(s, (uint8_t)a); + gen_B(s, (uint8_t)b); } - return s->pc++; +} + +static void +genop_3(codegen_scope *s, mrb_code i, uint16_t a, uint16_t b, uint8_t c) +{ + s->lastpc = s->pc; + genop_2(s, i, a, b); + gen_B(s, c); +} + +static void +genop_2S(codegen_scope *s, mrb_code i, uint16_t a, uint16_t b) +{ + s->lastpc = s->pc; + genop_1(s, i, a); + gen_S(s, b); +} + +static void +genop_W(codegen_scope *s, mrb_code i, uint32_t a) +{ + uint8_t a1 = (a>>16) & 0xff; + uint8_t a2 = (a>>8) & 0xff; + uint8_t a3 = a & 0xff; + + s->lastpc = s->pc; + gen_B(s, i); + gen_B(s, a1); + gen_B(s, a2); + gen_B(s, a3); } #define NOVAL 0 #define VAL 1 -static mrb_bool +//static +mrb_bool no_optimize(codegen_scope *s) { if (s && s->parser && s->parser->no_optimize) @@ -181,269 +287,228 @@ no_optimize(codegen_scope *s) return FALSE; } -static int -genop_peep(codegen_scope *s, mrb_code i, int val) +static +mrb_bool +on_eval(codegen_scope *s) { - /* peephole optimization */ - if (!no_optimize(s) && s->lastlabel != s->pc && s->pc > 0) { - mrb_code i0 = s->iseq[s->pc-1]; - int c1 = GET_OPCODE(i); - int c0 = GET_OPCODE(i0); + if (s && s->parser && s->parser->on_eval) + return TRUE; + return FALSE; +} - switch (c1) { - case OP_MOVE: - if (GETARG_A(i) == GETARG_B(i)) { - /* skip useless OP_MOVE */ - return 0; - } - if (val) break; - switch (c0) { - case OP_MOVE: - if (GETARG_A(i) == GETARG_A(i0)) { - /* skip overriden OP_MOVE */ - s->pc--; - s->iseq[s->pc] = i; - } - if (GETARG_B(i) == GETARG_A(i0) && GETARG_A(i) == GETARG_B(i0)) { - /* skip swapping OP_MOVE */ - return 0; - } - if (GETARG_B(i) == GETARG_A(i0) && GETARG_A(i0) >= s->nlocals) { - s->pc--; - return genop_peep(s, MKOP_AB(OP_MOVE, GETARG_A(i), GETARG_B(i0)), val); - } - break; - case OP_LOADI: - if (GETARG_B(i) == GETARG_A(i0) && GETARG_A(i0) >= s->nlocals) { - s->iseq[s->pc-1] = MKOP_AsBx(OP_LOADI, GETARG_A(i), GETARG_sBx(i0)); - return 0; - } - break; - case OP_ARRAY: - case OP_HASH: - case OP_RANGE: - case OP_AREF: - case OP_GETUPVAR: - if (GETARG_B(i) == GETARG_A(i0) && GETARG_A(i0) >= s->nlocals) { - s->iseq[s->pc-1] = MKOP_ABC(c0, GETARG_A(i), GETARG_B(i0), GETARG_C(i0)); - return 0; - } - break; - case OP_LOADSYM: - case OP_GETGLOBAL: - case OP_GETIV: - case OP_GETCV: - case OP_GETCONST: - case OP_GETSPECIAL: - case OP_LOADL: - case OP_STRING: - if (GETARG_B(i) == GETARG_A(i0) && GETARG_A(i0) >= s->nlocals) { - s->iseq[s->pc-1] = MKOP_ABx(c0, GETARG_A(i), GETARG_Bx(i0)); - return 0; - } - break; - case OP_SCLASS: - if (GETARG_B(i) == GETARG_A(i0) && GETARG_A(i0) >= s->nlocals) { - s->iseq[s->pc-1] = MKOP_AB(c0, GETARG_A(i), GETARG_B(i0)); - return 0; - } - break; - case OP_LOADNIL: - case OP_LOADSELF: - case OP_LOADT: - case OP_LOADF: - case OP_OCLASS: - if (GETARG_B(i) == GETARG_A(i0) && GETARG_A(i0) >= s->nlocals) { - s->iseq[s->pc-1] = MKOP_A(c0, GETARG_A(i)); - return 0; - } - break; - default: - break; - } - break; - case OP_SETIV: - case OP_SETCV: - case OP_SETCONST: - case OP_SETMCNST: - case OP_SETGLOBAL: - if (val) break; - if (c0 == OP_MOVE) { - if (GETARG_A(i) == GETARG_A(i0)) { - s->iseq[s->pc-1] = MKOP_ABx(c1, GETARG_B(i0), GETARG_Bx(i)); - return 0; - } - } - break; - case OP_SETUPVAR: - if (val) break; - if (c0 == OP_MOVE) { - if (GETARG_A(i) == GETARG_A(i0)) { - s->iseq[s->pc-1] = MKOP_ABC(c1, GETARG_B(i0), GETARG_B(i), GETARG_C(i)); - return 0; - } - } - break; - case OP_GETUPVAR: - if (c0 == OP_SETUPVAR) { - if (GETARG_B(i) == GETARG_B(i0) && GETARG_C(i) == GETARG_C(i0)) { - if (GETARG_A(i) == GETARG_A(i0)) { - /* just skip OP_SETUPVAR */ - return 0; - } - else { - return genop(s, MKOP_AB(OP_MOVE, GETARG_A(i), GETARG_A(i0))); - } - } - } - break; - case OP_EPOP: - if (c0 == OP_EPOP) { - s->iseq[s->pc-1] = MKOP_A(OP_EPOP, GETARG_A(i0)+GETARG_A(i)); - return 0; - } - break; - case OP_POPERR: - if (c0 == OP_POPERR) { - s->iseq[s->pc-1] = MKOP_A(OP_POPERR, GETARG_A(i0)+GETARG_A(i)); - return 0; - } - break; - case OP_RETURN: - switch (c0) { - case OP_RETURN: - return 0; - case OP_MOVE: - if (GETARG_A(i0) >= s->nlocals) { - s->iseq[s->pc-1] = MKOP_AB(OP_RETURN, GETARG_B(i0), OP_R_NORMAL); - return 0; - } - break; - case OP_SETIV: - case OP_SETCV: - case OP_SETCONST: - case OP_SETMCNST: - case OP_SETUPVAR: - case OP_SETGLOBAL: - s->pc--; - genop_peep(s, i0, NOVAL); - i0 = s->iseq[s->pc-1]; - return genop(s, MKOP_AB(OP_RETURN, GETARG_A(i0), OP_R_NORMAL)); -#if 0 - case OP_SEND: - if (GETARG_B(i) == OP_R_NORMAL && GETARG_A(i) == GETARG_A(i0)) { - s->iseq[s->pc-1] = MKOP_ABC(OP_TAILCALL, GETARG_A(i0), GETARG_B(i0), GETARG_C(i0)); - return; - } - break; -#endif - default: - break; - } - break; - case OP_ADD: - case OP_SUB: - if (c0 == OP_LOADI) { - int c = GETARG_sBx(i0); - - if (c1 == OP_SUB) c = -c; - if (c > 127 || c < -127) break; - if (0 <= c) - s->iseq[s->pc-1] = MKOP_ABC(OP_ADDI, GETARG_A(i), GETARG_B(i), c); - else - s->iseq[s->pc-1] = MKOP_ABC(OP_SUBI, GETARG_A(i), GETARG_B(i), -c); - return 0; - } - break; - case OP_ARYCAT: - case OP_ARYPUSH: - if (c0 == OP_MOVE && GETARG_A(i0) >= s->nlocals) { - s->iseq[s->pc-1] = MKOP_AB(c1, GETARG_A(i), GETARG_B(i0)); - return 0; - } - break; - case OP_STRCAT: - if (c0 == OP_STRING) { - mrb_value v = s->irep->pool[GETARG_Bx(i0)]; +struct mrb_insn_data { + uint8_t insn; + uint16_t a; + uint16_t b; + uint8_t c; +}; - if (mrb_string_p(v) && RSTRING_LEN(v) == 0) { - s->pc--; - return 0; - } - } - if (c0 == OP_LOADNIL) { - if (GETARG_B(i) == GETARG_A(i0)) { - s->pc--; - return 0; - } - } - break; - case OP_JMPIF: - case OP_JMPNOT: - if (c0 == OP_MOVE && GETARG_A(i) == GETARG_A(i0)) { - s->iseq[s->pc-1] = MKOP_AsBx(c1, GETARG_B(i0), GETARG_sBx(i)); - return s->pc-1; - } - break; - default: - break; +struct mrb_insn_data +mrb_decode_insn(codegen_scope *s, mrb_code *pc) +{ + struct mrb_insn_data data = { 0 }; + mrb_code insn = READ_B(); + uint16_t a = 0; + uint16_t b = 0; + uint8_t c = 0; + + switch (insn) { +#define FETCH_Z() /* empty */ +#define OPCODE(i,x) case OP_ ## i: FETCH_ ## x (); break; +#include "mruby/ops.h" +#undef OPCODE + } + switch (insn) { + case OP_EXT1: + insn = READ_B(); + switch (insn) { +#define OPCODE(i,x) case OP_ ## i: FETCH_ ## x ## _1 (); break; +#include "mruby/ops.h" +#undef OPCODE + } + break; + case OP_EXT2: + insn = READ_B(); + switch (insn) { +#define OPCODE(i,x) case OP_ ## i: FETCH_ ## x ## _2 (); break; +#include "mruby/ops.h" +#undef OPCODE + } + break; + case OP_EXT3: + insn = READ_B(); + switch (insn) { +#define OPCODE(i,x) case OP_ ## i: FETCH_ ## x ## _3 (); break; +#include "mruby/ops.h" +#undef OPCODE + } + break; + default: + break; + } + data.insn = insn; + data.a = a; + data.b = b; + data.c = c; + return data; +} + +struct mrb_insn_data +mrb_last_insn(codegen_scope *s) +{ + if (s->pc == s->lastpc) { + struct mrb_insn_data data; + + data.insn = OP_NOP; + return data; + } + return mrb_decode_insn(s, &s->iseq[s->lastpc]); +} + +static mrb_bool +no_peephole(codegen_scope *s) +{ + return no_optimize(s) || s->lastlabel == s->pc || s->pc == 0 || s->pc == s->lastpc; +} + +static uint16_t +genjmp(codegen_scope *s, mrb_code i, uint16_t pc) +{ + uint16_t pos; + + s->lastpc = s->pc; + gen_B(s, i); + pos = s->pc; + gen_S(s, pc); + return pos; +} + +static uint16_t +genjmp2(codegen_scope *s, mrb_code i, uint16_t a, int pc, int val) +{ + uint16_t pos; + + if (!no_peephole(s) && !val) { + struct mrb_insn_data data = mrb_last_insn(s); + + if (data.insn == OP_MOVE && data.a == a) { + s->pc = s->lastpc; + a = data.b; } } - return genop(s, i); + + s->lastpc = s->pc; + if (a > 0xff) { + gen_B(s, OP_EXT1); + gen_B(s, i); + gen_S(s, a); + pos = s->pc; + gen_S(s, pc); + } + else { + gen_B(s, i); + gen_B(s, a); + pos = s->pc; + gen_S(s, pc); + } + return pos; } static void -scope_error(codegen_scope *s) +gen_move(codegen_scope *s, uint16_t dst, uint16_t src, int nopeep) { - exit(EXIT_FAILURE); + if (no_peephole(s)) { + normal: + genop_2(s, OP_MOVE, dst, src); + return; + } + else { + struct mrb_insn_data data = mrb_last_insn(s); + + switch (data.insn) { + case OP_MOVE: + if (dst == src) return; /* remove useless MOVE */ + if (data.b == dst && data.a == src) /* skip swapping MOVE */ + return; + goto normal; + case OP_LOADNIL: case OP_LOADSELF: case OP_LOADT: case OP_LOADF: + case OP_LOADI__1: + case OP_LOADI_0: case OP_LOADI_1: case OP_LOADI_2: case OP_LOADI_3: + case OP_LOADI_4: case OP_LOADI_5: case OP_LOADI_6: case OP_LOADI_7: + if (nopeep || data.a != src || data.a < s->nlocals) goto normal; + s->pc = s->lastpc; + genop_1(s, data.insn, dst); + break; + case OP_LOADI: case OP_LOADINEG: case OP_LOADL: case OP_LOADSYM: + case OP_GETGV: case OP_GETSV: case OP_GETIV: case OP_GETCV: + case OP_GETCONST: case OP_STRING: + case OP_LAMBDA: case OP_BLOCK: case OP_METHOD: case OP_BLKPUSH: + if (nopeep || data.a != src || data.a < s->nlocals) goto normal; + s->pc = s->lastpc; + genop_2(s, data.insn, dst, data.b); + break; + default: + goto normal; + } + } } static void -distcheck(codegen_scope *s, int diff) +gen_addsub(codegen_scope *s, uint8_t op, uint16_t dst, uint16_t idx) { - if (diff > MAXARG_sBx || diff < -MAXARG_sBx) { - codegen_error(s, "too distant jump address"); + if (no_peephole(s)) { + normal: + genop_2(s, op, dst, idx); + return; + } + else { + struct mrb_insn_data data = mrb_last_insn(s); + + switch (data.insn) { + case OP_LOADI__1: + if (op == OP_ADD) op = OP_SUB; + else op = OP_ADD; + data.b = 1; + goto replace; + case OP_LOADI_0: case OP_LOADI_1: case OP_LOADI_2: case OP_LOADI_3: + case OP_LOADI_4: case OP_LOADI_5: case OP_LOADI_6: case OP_LOADI_7: + data.b = data.insn - OP_LOADI_0; + /* fall through */ + case OP_LOADI: + replace: + if (data.b >= 128) goto normal; + s->pc = s->lastpc; + if (op == OP_ADD) { + genop_3(s, OP_ADDI, dst, idx, data.b); + } + else { + genop_3(s, OP_SUBI, dst, idx, data.b); + } + break; + default: + goto normal; + } } } -static inline void -dispatch(codegen_scope *s, int pc) +static int +dispatch(codegen_scope *s, uint16_t pos0) { - int diff = s->pc - pc; - mrb_code i = s->iseq[pc]; - int c = GET_OPCODE(i); + uint16_t newpos; s->lastlabel = s->pc; - switch (c) { - case OP_JMP: - case OP_JMPIF: - case OP_JMPNOT: - case OP_ONERR: - break; - default: -#ifndef MRB_DISABLE_STDIO - fprintf(stderr, "bug: dispatch on non JMP op\n"); -#endif - scope_error(s); - break; - } - distcheck(s, diff); - s->iseq[pc] = MKOP_AsBx(c, GETARG_A(i), diff); + newpos = PEEK_S(s->iseq+pos0); + emit_S(s, pos0, s->pc); + return newpos; } static void -dispatch_linked(codegen_scope *s, int pc) +dispatch_linked(codegen_scope *s, uint16_t pos) { - mrb_code i; - int pos; - - if (!pc) return; + if (pos==0) return; for (;;) { - i = s->iseq[pc]; - pos = GETARG_sBx(i); - dispatch(s, pc); - if (!pos) break; - pc = pos; + pos = dispatch(s, pos); + if (pos==0) break; } } @@ -451,7 +516,7 @@ dispatch_linked(codegen_scope *s, int pc) static void push_(codegen_scope *s) { - if (s->sp > 511) { + if (s->sp >= 0xffff) { codegen_error(s, "too complex expression"); } s->sp++; @@ -461,7 +526,7 @@ push_(codegen_scope *s) static void push_n_(codegen_scope *s, int n) { - if (s->sp+n > 511) { + if (s->sp+n >= 0xffff) { codegen_error(s, "too complex expression"); } s->sp+=n; @@ -545,52 +610,23 @@ new_lit(codegen_scope *s, mrb_value val) return i; } -/* method symbols should be fit in 9 bits */ -#define MAXMSYMLEN 512 /* maximum symbol numbers */ -#define MAXSYMLEN 65536 +#define MAXSYMLEN 0x10000 static int -new_msym(codegen_scope *s, mrb_sym sym) +new_sym(codegen_scope *s, mrb_sym sym) { int i, len; mrb_assert(s->irep); len = s->irep->slen; - if (len > MAXMSYMLEN) len = MAXMSYMLEN; for (i=0; iirep->syms[i] == sym) return i; - if (s->irep->syms[i] == 0) break; } - if (i == MAXMSYMLEN) { - codegen_error(s, "too many symbols (max " MRB_STRINGIZE(MAXMSYMLEN) ")"); - } - s->irep->syms[i] = sym; - if (i == s->irep->slen) s->irep->slen++; - return i; -} - -static int -new_sym(codegen_scope *s, mrb_sym sym) -{ - int i; - - for (i=0; iirep->slen; i++) { - if (s->irep->syms[i] == sym) return i; - } - if (s->irep->slen == MAXSYMLEN) { - codegen_error(s, "too many symbols (max " MRB_STRINGIZE(MAXSYMLEN) ")"); - } - - if (s->irep->slen > MAXMSYMLEN/2 && s->scapa == MAXMSYMLEN) { - s->scapa = MAXSYMLEN; - s->irep->syms = (mrb_sym *)codegen_realloc(s, s->irep->syms, sizeof(mrb_sym)*MAXSYMLEN); - for (i = s->irep->slen; i < MAXMSYMLEN; i++) { - static const mrb_sym mrb_sym_zero = { 0 }; - s->irep->syms[i] = mrb_sym_zero; - } - s->irep->slen = MAXMSYMLEN; + if (s->irep->slen >= s->scapa) { + s->scapa *= 2; + s->irep->syms = (mrb_sym*)codegen_realloc(s, s->irep->syms, sizeof(mrb_sym)*s->scapa); } s->irep->syms[s->irep->slen] = sym; return s->irep->slen++; @@ -631,7 +667,6 @@ for_body(codegen_scope *s, node *tree) int idx; struct loopinfo *lp; node *n2; - mrb_code c; /* generate receiver */ codegen(s, tree->cdr->car, VAL); @@ -645,7 +680,7 @@ for_body(codegen_scope *s, node *tree) /* generate loop variable */ n2 = tree->car; - genop(s, MKOP_Ax(OP_ENTER, 0x40000)); + genop_W(s, OP_ENTER, 0x40000); if (n2->car && !n2->car->cdr && !n2->cdr) { gen_assignment(s, n2->car->car, 1, NOVAL); } @@ -659,25 +694,20 @@ for_body(codegen_scope *s, node *tree) /* loop body */ codegen(s, tree->cdr->cdr->car, VAL); pop(); - if (s->pc > 0) { - c = s->iseq[s->pc-1]; - if (GET_OPCODE(c) != OP_RETURN || GETARG_B(c) != OP_R_NORMAL || s->pc == s->lastlabel) - genop_peep(s, MKOP_AB(OP_RETURN, cursp(), OP_R_NORMAL), NOVAL); - } + genop_1(s, OP_RETURN, cursp()); loop_pop(s, NOVAL); scope_finish(s); s = prev; - genop(s, MKOP_Abc(OP_LAMBDA, cursp(), s->irep->rlen-1, OP_L_BLOCK)); + genop_2(s, OP_BLOCK, cursp(), s->irep->rlen-1); push();pop(); /* space for a block */ pop(); - idx = new_msym(s, mrb_intern_lit(s->mrb, "each")); - genop(s, MKOP_ABC(OP_SENDB, cursp(), idx, 0)); + idx = new_sym(s, mrb_intern_lit(s->mrb, "each")); + genop_3(s, OP_SENDB, cursp(), idx, 0); } static int lambda_body(codegen_scope *s, node *tree, int blk) { - mrb_code c; codegen_scope *parent = s; s = scope_new(s->mrb, s, tree->car); if (s == NULL) { @@ -688,7 +718,7 @@ lambda_body(codegen_scope *s, node *tree, int blk) if (blk) { struct loopinfo *lp = loop_push(s, LOOP_BLOCK); - lp->pc1 = new_label(s); + lp->pc0 = new_label(s); } tree = tree->cdr; if (tree->car) { @@ -721,45 +751,36 @@ lambda_body(codegen_scope *s, node *tree, int blk) s->ainfo = (((ma+oa) & 0x3f) << 6) /* (12bits = 6:1:5) */ | ((ra & 1) << 5) | (pa & 0x1f); - genop(s, MKOP_Ax(OP_ENTER, a)); + genop_W(s, OP_ENTER, a); pos = new_label(s); for (i=0; i 0) { - genop(s, MKOP_sBx(OP_JMP, 0)); + genjmp(s, OP_JMP, 0); } opt = tree->car->cdr->car; i = 0; while (opt) { int idx; - dispatch(s, pos+i); + dispatch(s, pos+i*3+1); codegen(s, opt->car->cdr, VAL); - idx = lv_idx(s, nsym(opt->car->car)); pop(); - genop_peep(s, MKOP_AB(OP_MOVE, idx, cursp()), NOVAL); + idx = lv_idx(s, nsym(opt->car->car)); + gen_move(s, idx, cursp(), 0); i++; opt = opt->cdr; } if (oa > 0) { - dispatch(s, pos+i); + dispatch(s, pos+i*3+1); } } codegen(s, tree->cdr->car, VAL); pop(); if (s->pc > 0) { - c = s->iseq[s->pc-1]; - if (GET_OPCODE(c) != OP_RETURN || GETARG_B(c) != OP_R_NORMAL || s->pc == s->lastlabel) { - if (s->nregs == 0) { - genop(s, MKOP_A(OP_LOADNIL, 0)); - genop(s, MKOP_AB(OP_RETURN, 0, OP_R_NORMAL)); - } - else { - genop_peep(s, MKOP_AB(OP_RETURN, cursp(), OP_R_NORMAL), NOVAL); - } - } + genop_1(s, OP_RETURN, cursp()); } if (blk) { loop_pop(s, NOVAL); @@ -773,24 +794,13 @@ scope_body(codegen_scope *s, node *tree, int val) { codegen_scope *scope = scope_new(s->mrb, s, tree->car); if (scope == NULL) { - raise_error(s, "unexpected scope"); + codegen_error(s, "unexpected scope"); } codegen(scope, tree->cdr, VAL); + genop_1(scope, OP_RETURN, scope->sp-1); if (!s->iseq) { - genop(scope, MKOP_A(OP_STOP, 0)); - } - else if (!val) { - genop(scope, MKOP_AB(OP_RETURN, 0, OP_R_NORMAL)); - } - else { - if (scope->nregs == 0) { - genop(scope, MKOP_A(OP_LOADNIL, 0)); - genop(scope, MKOP_AB(OP_RETURN, 0, OP_R_NORMAL)); - } - else { - genop_peep(scope, MKOP_AB(OP_RETURN, scope->sp-1, OP_R_NORMAL), NOVAL); - } + genop_0(scope, OP_STOP); } scope_finish(scope); if (!s->irep) { @@ -854,15 +864,15 @@ gen_values(codegen_scope *s, node *t, int val, int extra) } else { pop_n(n); - genop(s, MKOP_ABC(OP_ARRAY, cursp(), cursp(), n)); + genop_2(s, OP_ARRAY, cursp(), n); push(); codegen(s, t->car, VAL); pop(); pop(); if (is_splat) { - genop_peep(s, MKOP_AB(OP_ARYCAT, cursp(), cursp()+1), NOVAL); + genop_1(s, OP_ARYCAT, cursp()); } else { - genop_peep(s, MKOP_AB(OP_ARYPUSH, cursp(), cursp()+1), NOVAL); + genop_1(s, OP_ARYPUSH, cursp()); } } t = t->cdr; @@ -871,10 +881,10 @@ gen_values(codegen_scope *s, node *t, int val, int extra) codegen(s, t->car, VAL); pop(); pop(); if (nint(t->car->car) == NODE_SPLAT) { - genop_peep(s, MKOP_AB(OP_ARYCAT, cursp(), cursp()+1), NOVAL); + genop_1(s, OP_ARYCAT, cursp()); } else { - genop_peep(s, MKOP_AB(OP_ARYPUSH, cursp(), cursp()+1), NOVAL); + genop_1(s, OP_ARYPUSH, cursp()); } t = t->cdr; } @@ -905,16 +915,10 @@ gen_call(codegen_scope *s, node *tree, mrb_sym name, int sp, int val, int safe) codegen(s, tree->car, VAL); /* receiver */ if (safe) { int recv = cursp()-1; - genop(s, MKOP_A(OP_LOADNIL, cursp())); - push(); - genop(s, MKOP_AB(OP_MOVE, cursp(), recv)); - push_n(2); pop_n(2); /* space for one arg and a block */ - pop(); - idx = new_msym(s, mrb_intern_lit(s->mrb, "==")); - genop(s, MKOP_ABC(OP_EQ, cursp(), idx, 1)); - skip = genop(s, MKOP_AsBx(OP_JMPIF, cursp(), 0)); + gen_move(s, cursp(), recv, 0); + skip = genjmp2(s, OP_JMPNIL, cursp(), 0, val); } - idx = new_msym(s, sym); + idx = new_sym(s, sym); tree = tree->cdr->cdr->car; if (tree) { n = gen_values(s, tree->car, VAL, sp?1:0); @@ -923,14 +927,15 @@ gen_call(codegen_scope *s, node *tree, mrb_sym name, int sp, int val, int safe) push(); } } - if (sp) { + if (sp) { /* last argument pushed (attr=) */ if (sendv) { + gen_move(s, cursp(), sp, 0); pop(); - genop(s, MKOP_AB(OP_ARYPUSH, cursp(), sp)); + genop_1(s, OP_ARYPUSH, cursp()); push(); } else { - genop(s, MKOP_AB(OP_MOVE, cursp(), sp)); + gen_move(s, cursp(), sp, 0); push(); n++; } @@ -939,9 +944,7 @@ gen_call(codegen_scope *s, node *tree, mrb_sym name, int sp, int val, int safe) noop = 1; codegen(s, tree->cdr, VAL); pop(); - } - else { - blk = cursp(); + blk = 1; } push();pop(); pop_n(n+1); @@ -950,39 +953,38 @@ gen_call(codegen_scope *s, node *tree, mrb_sym name, int sp, int val, int safe) const char *symname = mrb_sym2name_len(s->mrb, sym, &symlen); if (!noop && symlen == 1 && symname[0] == '+' && n == 1) { - genop_peep(s, MKOP_ABC(OP_ADD, cursp(), idx, n), val); + gen_addsub(s, OP_ADD, cursp(), idx); } else if (!noop && symlen == 1 && symname[0] == '-' && n == 1) { - genop_peep(s, MKOP_ABC(OP_SUB, cursp(), idx, n), val); + gen_addsub(s, OP_SUB, cursp(), idx); } else if (!noop && symlen == 1 && symname[0] == '*' && n == 1) { - genop(s, MKOP_ABC(OP_MUL, cursp(), idx, n)); + genop_2(s, OP_MUL, cursp(), idx); } else if (!noop && symlen == 1 && symname[0] == '/' && n == 1) { - genop(s, MKOP_ABC(OP_DIV, cursp(), idx, n)); + genop_2(s, OP_DIV, cursp(), idx); } else if (!noop && symlen == 1 && symname[0] == '<' && n == 1) { - genop(s, MKOP_ABC(OP_LT, cursp(), idx, n)); + genop_2(s, OP_LT, cursp(), idx); } else if (!noop && symlen == 2 && symname[0] == '<' && symname[1] == '=' && n == 1) { - genop(s, MKOP_ABC(OP_LE, cursp(), idx, n)); + genop_2(s, OP_LE, cursp(), idx); } else if (!noop && symlen == 1 && symname[0] == '>' && n == 1) { - genop(s, MKOP_ABC(OP_GT, cursp(), idx, n)); + genop_2(s, OP_GT, cursp(), idx); } else if (!noop && symlen == 2 && symname[0] == '>' && symname[1] == '=' && n == 1) { - genop(s, MKOP_ABC(OP_GE, cursp(), idx, n)); + genop_2(s, OP_GE, cursp(), idx); } else if (!noop && symlen == 2 && symname[0] == '=' && symname[1] == '=' && n == 1) { - genop(s, MKOP_ABC(OP_EQ, cursp(), idx, n)); + genop_2(s, OP_EQ, cursp(), idx); } else { - if (sendv) n = CALL_MAXARGS; - if (blk > 0) { /* no block */ - genop(s, MKOP_ABC(OP_SEND, cursp(), idx, n)); + if (sendv) { + genop_2(s, blk ? OP_SENDVB : OP_SENDV, cursp(), idx); } else { - genop(s, MKOP_ABC(OP_SENDB, cursp(), idx, n)); + genop_3(s, blk ? OP_SENDB : OP_SEND, cursp(), idx, n); } } } @@ -1004,13 +1006,14 @@ gen_assignment(codegen_scope *s, node *tree, int sp, int val) switch (type) { case NODE_GVAR: idx = new_sym(s, nsym(tree)); - genop_peep(s, MKOP_ABx(OP_SETGLOBAL, sp, idx), val); + genop_2(s, OP_SETGV, sp, idx); break; case NODE_LVAR: idx = lv_idx(s, nsym(tree)); if (idx > 0) { if (idx != sp) { - genop_peep(s, MKOP_AB(OP_MOVE, idx, sp), val); + gen_move(s, idx, sp, val); + if (val && on_eval(s)) genop_0(s, OP_NOP); } break; } @@ -1021,7 +1024,7 @@ gen_assignment(codegen_scope *s, node *tree, int sp, int val) while (up) { idx = lv_idx(up, nsym(tree)); if (idx > 0) { - genop_peep(s, MKOP_ABC(OP_SETUPVAR, sp, idx, lv), val); + genop_3(s, OP_SETUPVAR, sp, idx, lv); break; } lv++; @@ -1031,23 +1034,23 @@ gen_assignment(codegen_scope *s, node *tree, int sp, int val) break; case NODE_IVAR: idx = new_sym(s, nsym(tree)); - genop_peep(s, MKOP_ABx(OP_SETIV, sp, idx), val); + genop_2(s, OP_SETIV, sp, idx); break; case NODE_CVAR: idx = new_sym(s, nsym(tree)); - genop_peep(s, MKOP_ABx(OP_SETCV, sp, idx), val); + genop_2(s, OP_SETCV, sp, idx); break; case NODE_CONST: idx = new_sym(s, nsym(tree)); - genop_peep(s, MKOP_ABx(OP_SETCONST, sp, idx), val); + genop_2(s, OP_SETCONST, sp, idx); break; case NODE_COLON2: - idx = new_sym(s, nsym(tree->cdr)); - genop_peep(s, MKOP_AB(OP_MOVE, cursp(), sp), NOVAL); + gen_move(s, cursp(), sp, 0); push(); codegen(s, tree->car, VAL); pop_n(2); - genop_peep(s, MKOP_ABx(OP_SETMCNST, cursp(), idx), val); + idx = new_sym(s, nsym(tree->cdr)); + genop_2(s, OP_SETMCNST, sp, idx); break; case NODE_CALL: @@ -1057,7 +1060,7 @@ gen_assignment(codegen_scope *s, node *tree, int sp, int val) type == NODE_SCALL); pop(); if (val) { - genop_peep(s, MKOP_AB(OP_MOVE, cursp(), sp), val); + gen_move(s, cursp(), sp, 0); } break; @@ -1090,7 +1093,7 @@ gen_vmassignment(codegen_scope *s, node *tree, int rhs, int val) while (t) { int sp = cursp(); - genop(s, MKOP_ABC(OP_AREF, sp, rhs, n)); + genop_3(s, OP_AREF, sp, rhs, n); push(); gen_assignment(s, t->car, sp, NOVAL); pop(); @@ -1107,10 +1110,10 @@ gen_vmassignment(codegen_scope *s, node *tree, int rhs, int val) p = p->cdr; } } - genop(s, MKOP_AB(OP_MOVE, cursp(), rhs)); + gen_move(s, cursp(), rhs, val); push_n(post+1); pop_n(post+1); - genop(s, MKOP_ABC(OP_APOST, cursp(), n, post)); + genop_3(s, OP_APOST, cursp(), n, post); n = 1; if (t->car) { /* rest */ gen_assignment(s, t->car, cursp(), NOVAL); @@ -1124,19 +1127,19 @@ gen_vmassignment(codegen_scope *s, node *tree, int rhs, int val) } } if (val) { - genop(s, MKOP_AB(OP_MOVE, cursp(), rhs)); + gen_move(s, cursp(), rhs, 0); } } } static void -gen_send_intern(codegen_scope *s) +gen_intern(codegen_scope *s) { - push();pop(); /* space for a block */ pop(); - genop(s, MKOP_ABC(OP_SEND, cursp(), new_msym(s, mrb_intern_lit(s->mrb, "intern")), 0)); + genop_1(s, OP_INTERN, cursp()); push(); } + static void gen_literal_array(codegen_scope *s, node *tree, mrb_bool sym, int val) { @@ -1159,25 +1162,25 @@ gen_literal_array(codegen_scope *s, node *tree, mrb_bool sym, int val) j = 0; ++i; if (sym) - gen_send_intern(s); + gen_intern(s); } break; } - if (j >= 2) { + while (j >= 2) { pop(); pop(); - genop_peep(s, MKOP_AB(OP_STRCAT, cursp(), cursp()+1), VAL); + genop_1(s, OP_STRCAT, cursp()); push(); - j = 1; + j--; } tree = tree->cdr; } if (j > 0) { ++i; if (sym) - gen_send_intern(s); + gen_intern(s); } pop_n(i); - genop(s, MKOP_ABC(OP_ARRAY, cursp(), cursp(), i)); + genop_2(s, OP_ARRAY, cursp(), i); push(); } else { @@ -1196,7 +1199,7 @@ raise_error(codegen_scope *s, const char *msg) { int idx = new_lit(s, mrb_str_new_cstr(s->mrb, msg)); - genop(s, MKOP_ABx(OP_ERR, 1, idx)); + genop_1(s, OP_ERR, idx); } #ifndef MRB_WITHOUT_FLOAT @@ -1274,11 +1277,9 @@ static void gen_retval(codegen_scope *s, node *tree) { if (nint(tree->car) == NODE_SPLAT) { - genop(s, MKOP_ABC(OP_ARRAY, cursp(), cursp(), 0)); - push(); codegen(s, tree, VAL); - pop(); pop(); - genop(s, MKOP_AB(OP_ARYCAT, cursp(), cursp()+1)); + pop(); + genop_1(s, OP_ARYDUP, cursp()); } else { codegen(s, tree, VAL); @@ -1294,7 +1295,7 @@ codegen(codegen_scope *s, node *tree, int val) if (!tree) { if (val) { - genop(s, MKOP_A(OP_LOADNIL, cursp())); + genop_1(s, OP_LOADNIL, cursp()); push(); } return; @@ -1318,7 +1319,7 @@ codegen(codegen_scope *s, node *tree, int val) switch (nt) { case NODE_BEGIN: if (val && !tree) { - genop(s, MKOP_A(OP_LOADNIL, cursp())); + genop_1(s, OP_LOADNIL, cursp()); push(); } while (tree) { @@ -1329,18 +1330,18 @@ codegen(codegen_scope *s, node *tree, int val) case NODE_RESCUE: { - int onerr, noexc, exend, pos1, pos2, tmp; + int noexc, exend, pos1, pos2, tmp; struct loopinfo *lp; if (tree->car == NULL) goto exit; - onerr = genop(s, MKOP_Bx(OP_ONERR, 0)); lp = loop_push(s, LOOP_BEGIN); - lp->pc1 = onerr; + lp->pc0 = new_label(s); + lp->pc1 = genjmp(s, OP_ONERR, 0); codegen(s, tree->car, VAL); pop(); lp->type = LOOP_RESCUE; - noexc = genop(s, MKOP_Bx(OP_JMP, 0)); - dispatch(s, onerr); + noexc = genjmp(s, OP_JMP, 0); + dispatch(s, lp->pc1); tree = tree->cdr; exend = 0; pos1 = 0; @@ -1348,7 +1349,7 @@ codegen(codegen_scope *s, node *tree, int val) node *n2 = tree->car; int exc = cursp(); - genop(s, MKOP_ABC(OP_RESCUE, exc, 0, 0)); + genop_1(s, OP_EXCEPT, exc); push(); while (n2) { node *n3 = n2->car; @@ -1359,30 +1360,29 @@ codegen(codegen_scope *s, node *tree, int val) do { if (n4 && n4->car && nint(n4->car->car) == NODE_SPLAT) { codegen(s, n4->car, VAL); - genop(s, MKOP_AB(OP_MOVE, cursp(), exc)); + gen_move(s, cursp(), exc, 0); push_n(2); pop_n(2); /* space for one arg and a block */ pop(); - genop(s, MKOP_ABC(OP_SEND, cursp(), new_msym(s, mrb_intern_lit(s->mrb, "__case_eqq")), 1)); + genop_3(s, OP_SEND, cursp(), new_sym(s, mrb_intern_lit(s->mrb, "__case_eqq")), 1); } else { if (n4) { codegen(s, n4->car, VAL); } else { - genop(s, MKOP_ABx(OP_GETCONST, cursp(), new_msym(s, mrb_intern_lit(s->mrb, "StandardError")))); + genop_2(s, OP_GETCONST, cursp(), new_sym(s, mrb_intern_lit(s->mrb, "StandardError"))); push(); } pop(); - genop(s, MKOP_ABC(OP_RESCUE, exc, cursp(), 1)); + genop_2(s, OP_RESCUE, exc, cursp()); } - distcheck(s, pos2); - tmp = genop(s, MKOP_AsBx(OP_JMPIF, cursp(), pos2)); + tmp = genjmp2(s, OP_JMPIF, cursp(), pos2, val); pos2 = tmp; if (n4) { n4 = n4->cdr; } } while (n4); - pos1 = genop(s, MKOP_sBx(OP_JMP, 0)); + pos1 = genjmp(s, OP_JMP, 0); dispatch_linked(s, pos2); pop(); @@ -1393,21 +1393,20 @@ codegen(codegen_scope *s, node *tree, int val) codegen(s, n3->cdr->cdr->car, val); if (val) pop(); } - distcheck(s, exend); - tmp = genop(s, MKOP_sBx(OP_JMP, exend)); + tmp = genjmp(s, OP_JMP, exend); exend = tmp; n2 = n2->cdr; push(); } if (pos1) { dispatch(s, pos1); - genop(s, MKOP_A(OP_RAISE, exc)); + genop_1(s, OP_RAISE, exc); } } pop(); tree = tree->cdr; dispatch(s, noexc); - genop(s, MKOP_A(OP_POPERR, 1)); + genop_1(s, OP_POPERR, 1); if (tree->car) { codegen(s, tree->car, val); } @@ -1424,15 +1423,13 @@ codegen(codegen_scope *s, node *tree, int val) (nint(tree->cdr->cdr->car) == NODE_BEGIN && tree->cdr->cdr->cdr)) { int idx; - int epush = s->pc; - genop(s, MKOP_Bx(OP_EPUSH, 0)); s->ensure_level++; - codegen(s, tree->car, val); idx = scope_body(s, tree->cdr, NOVAL); - s->iseq[epush] = MKOP_Bx(OP_EPUSH, idx); + genop_1(s, OP_EPUSH, idx); + codegen(s, tree->car, val); s->ensure_level--; - genop_peep(s, MKOP_A(OP_EPOP, 1), NOVAL); + genop_1(s, OP_EPOP, 1); } else { /* empty ensure ignored */ codegen(s, tree->car, val); @@ -1443,7 +1440,7 @@ codegen(codegen_scope *s, node *tree, int val) if (val) { int idx = lambda_body(s, tree, 1); - genop(s, MKOP_Abc(OP_LAMBDA, cursp(), idx, OP_L_LAMBDA)); + genop_2(s, OP_LAMBDA, cursp(), idx); push(); } break; @@ -1452,7 +1449,7 @@ codegen(codegen_scope *s, node *tree, int val) if (val) { int idx = lambda_body(s, tree, 1); - genop(s, MKOP_Abc(OP_LAMBDA, cursp(), idx, OP_L_BLOCK)); + genop_2(s, OP_BLOCK, cursp(), idx); push(); } break; @@ -1460,10 +1457,10 @@ codegen(codegen_scope *s, node *tree, int val) case NODE_IF: { int pos1, pos2; - node *e = tree->cdr->cdr->car; + node *elsepart = tree->cdr->cdr->car; if (!tree->car) { - codegen(s, e, val); + codegen(s, elsepart, val); goto exit; } switch (nint(tree->car->car)) { @@ -1474,27 +1471,27 @@ codegen(codegen_scope *s, node *tree, int val) goto exit; case NODE_FALSE: case NODE_NIL: - codegen(s, e, val); + codegen(s, elsepart, val); goto exit; } codegen(s, tree->car, VAL); pop(); - pos1 = genop_peep(s, MKOP_AsBx(OP_JMPNOT, cursp(), 0), NOVAL); + pos1 = genjmp2(s, OP_JMPNOT, cursp(), 0, val); codegen(s, tree->cdr->car, val); - if (e) { + if (elsepart) { if (val) pop(); - pos2 = genop(s, MKOP_sBx(OP_JMP, 0)); + pos2 = genjmp(s, OP_JMP, 0); dispatch(s, pos1); - codegen(s, e, val); + codegen(s, elsepart, val); dispatch(s, pos2); } else { if (val) { pop(); - pos2 = genop(s, MKOP_sBx(OP_JMP, 0)); + pos2 = genjmp(s, OP_JMP, 0); dispatch(s, pos1); - genop(s, MKOP_A(OP_LOADNIL, cursp())); + genop_1(s, OP_LOADNIL, cursp()); dispatch(s, pos2); push(); } @@ -1511,7 +1508,7 @@ codegen(codegen_scope *s, node *tree, int val) codegen(s, tree->car, VAL); pop(); - pos = genop(s, MKOP_AsBx(OP_JMPNOT, cursp(), 0)); + pos = genjmp2(s, OP_JMPNOT, cursp(), 0, val); codegen(s, tree->cdr, val); dispatch(s, pos); } @@ -1523,7 +1520,7 @@ codegen(codegen_scope *s, node *tree, int val) codegen(s, tree->car, VAL); pop(); - pos = genop(s, MKOP_AsBx(OP_JMPIF, cursp(), 0)); + pos = genjmp2(s, OP_JMPIF, cursp(), 0, val); codegen(s, tree->cdr, val); dispatch(s, pos); } @@ -1533,14 +1530,14 @@ codegen(codegen_scope *s, node *tree, int val) { struct loopinfo *lp = loop_push(s, LOOP_NORMAL); - lp->pc1 = genop(s, MKOP_sBx(OP_JMP, 0)); + lp->pc0 = new_label(s); + lp->pc1 = genjmp(s, OP_JMP, 0); lp->pc2 = new_label(s); codegen(s, tree->cdr, NOVAL); dispatch(s, lp->pc1); codegen(s, tree->car, VAL); pop(); - distcheck(s, lp->pc2 - s->pc); - genop(s, MKOP_AsBx(OP_JMPIF, cursp(), lp->pc2 - s->pc)); + genjmp2(s, OP_JMPIF, cursp(), lp->pc2, NOVAL); loop_pop(s, val); } @@ -1550,14 +1547,14 @@ codegen(codegen_scope *s, node *tree, int val) { struct loopinfo *lp = loop_push(s, LOOP_NORMAL); - lp->pc1 = genop(s, MKOP_sBx(OP_JMP, 0)); + lp->pc0 = new_label(s); + lp->pc1 = genjmp(s, OP_JMP, 0); lp->pc2 = new_label(s); codegen(s, tree->cdr, NOVAL); dispatch(s, lp->pc1); codegen(s, tree->car, VAL); pop(); - distcheck(s, lp->pc2 - s->pc); - genop(s, MKOP_AsBx(OP_JMPNOT, cursp(), lp->pc2 - s->pc)); + genjmp2(s, OP_JMPNOT, cursp(), lp->pc2, NOVAL); loop_pop(s, val); } @@ -1586,43 +1583,40 @@ codegen(codegen_scope *s, node *tree, int val) while (n) { codegen(s, n->car, VAL); if (head) { - genop(s, MKOP_AB(OP_MOVE, cursp(), head)); - push_n(2); pop_n(2); /* space for one arg and a block */ - pop(); + gen_move(s, cursp(), head, 0); + push(); push(); pop(); pop(); pop(); if (nint(n->car->car) == NODE_SPLAT) { - genop(s, MKOP_ABC(OP_SEND, cursp(), new_msym(s, mrb_intern_lit(s->mrb, "__case_eqq")), 1)); + genop_3(s, OP_SEND, cursp(), new_sym(s, mrb_intern_lit(s->mrb, "__case_eqq")), 1); } else { - genop(s, MKOP_ABC(OP_SEND, cursp(), new_msym(s, mrb_intern_lit(s->mrb, "===")), 1)); + genop_3(s, OP_SEND, cursp(), new_sym(s, mrb_intern_lit(s->mrb, "===")), 1); } } else { pop(); } - distcheck(s, pos2); - tmp = genop(s, MKOP_AsBx(OP_JMPIF, cursp(), pos2)); + tmp = genjmp2(s, OP_JMPIF, cursp(), pos2, NOVAL); pos2 = tmp; n = n->cdr; } if (tree->car->car) { - pos1 = genop(s, MKOP_sBx(OP_JMP, 0)); + pos1 = genjmp(s, OP_JMP, 0); dispatch_linked(s, pos2); } codegen(s, tree->car->cdr, val); if (val) pop(); - distcheck(s, pos3); - tmp = genop(s, MKOP_sBx(OP_JMP, pos3)); + tmp = genjmp(s, OP_JMP, pos3); pos3 = tmp; if (pos1) dispatch(s, pos1); tree = tree->cdr; } if (val) { int pos = cursp(); - genop(s, MKOP_A(OP_LOADNIL, cursp())); + genop_1(s, OP_LOADNIL, cursp()); if (pos3) dispatch_linked(s, pos3); if (head) pop(); if (cursp() != pos) { - genop(s, MKOP_AB(OP_MOVE, cursp(), pos)); + gen_move(s, cursp(), pos, 0); } push(); } @@ -1654,7 +1648,7 @@ codegen(codegen_scope *s, node *tree, int val) codegen(s, tree->cdr, val); if (val) { pop(); pop(); - genop(s, MKOP_ABC(OP_RANGE, cursp(), cursp(), FALSE)); + genop_1(s, OP_RANGE_INC, cursp()); push(); } break; @@ -1664,7 +1658,7 @@ codegen(codegen_scope *s, node *tree, int val) codegen(s, tree->cdr, val); if (val) { pop(); pop(); - genop(s, MKOP_ABC(OP_RANGE, cursp(), cursp(), TRUE)); + genop_1(s, OP_RANGE_EXC, cursp()); push(); } break; @@ -1675,7 +1669,7 @@ codegen(codegen_scope *s, node *tree, int val) codegen(s, tree->car, VAL); pop(); - genop(s, MKOP_ABx(OP_GETMCNST, cursp(), sym)); + genop_2(s, OP_GETMCNST, cursp(), sym); if (val) push(); } break; @@ -1684,8 +1678,8 @@ codegen(codegen_scope *s, node *tree, int val) { int sym = new_sym(s, nsym(tree)); - genop(s, MKOP_A(OP_OCLASS, cursp())); - genop(s, MKOP_ABx(OP_GETMCNST, cursp(), sym)); + genop_1(s, OP_OCLASS, cursp()); + genop_2(s, OP_GETMCNST, cursp(), sym); if (val) push(); } break; @@ -1698,7 +1692,7 @@ codegen(codegen_scope *s, node *tree, int val) if (n >= 0) { if (val) { pop_n(n); - genop(s, MKOP_ABC(OP_ARRAY, cursp(), cursp(), n)); + genop_2(s, OP_ARRAY, cursp(), n); push(); } } @@ -1718,12 +1712,14 @@ codegen(codegen_scope *s, node *tree, int val) codegen(s, tree->car->cdr, val); len++; tree = tree->cdr; - if (val && len == 126) { + if (val && len == 255) { pop_n(len*2); - genop(s, MKOP_ABC(OP_HASH, cursp(), cursp(), len)); - if (update) { + if (!update) { + genop_2(s, OP_HASH, cursp(), len); + } + else { pop(); - genop(s, MKOP_ABC(OP_SEND, cursp(), new_msym(s, mrb_intern_lit(s->mrb, "__update")), 1)); + genop_2(s, OP_HASHADD, cursp(), len); } push(); update = TRUE; @@ -1732,10 +1728,12 @@ codegen(codegen_scope *s, node *tree, int val) } if (val) { pop_n(len*2); - genop(s, MKOP_ABC(OP_HASH, cursp(), cursp(), len)); - if (update) { + if (!update) { + genop_2(s, OP_HASH, cursp(), len); + } + else { pop(); - genop(s, MKOP_ABC(OP_SEND, cursp(), new_msym(s, mrb_intern_lit(s->mrb, "__update")), 1)); + genop_2(s, OP_HASHADD, cursp(), len); } push(); } @@ -1776,7 +1774,7 @@ codegen(codegen_scope *s, node *tree, int val) n++; } else { - genop(s, MKOP_A(OP_LOADNIL, rhs+n)); + genop_1(s, OP_LOADNIL, rhs+n); gen_assignment(s, t->car, rhs+n, NOVAL); } t = t->cdr; @@ -1800,7 +1798,7 @@ codegen(codegen_scope *s, node *tree, int val) else { rn = len - post - n; } - genop(s, MKOP_ABC(OP_ARRAY, cursp(), rhs+n, rn)); + genop_3(s, OP_ARRAY2, cursp(), rhs+n, rn); gen_assignment(s, t->car, cursp(), NOVAL); n += rn; } @@ -1815,7 +1813,7 @@ codegen(codegen_scope *s, node *tree, int val) } pop_n(len); if (val) { - genop(s, MKOP_ABC(OP_ARRAY, rhs, rhs, len)); + genop_2(s, OP_ARRAY, rhs, len); push(); } } @@ -1843,17 +1841,17 @@ codegen(codegen_scope *s, node *tree, int val) int onerr, noexc, exc; struct loopinfo *lp; - onerr = genop(s, MKOP_Bx(OP_ONERR, 0)); + onerr = genjmp(s, OP_ONERR, 0); lp = loop_push(s, LOOP_BEGIN); lp->pc1 = onerr; exc = cursp(); codegen(s, tree->car, VAL); lp->type = LOOP_RESCUE; - genop(s, MKOP_A(OP_POPERR, 1)); - noexc = genop(s, MKOP_Bx(OP_JMP, 0)); + genop_1(s, OP_POPERR, 1); + noexc = genjmp(s, OP_JMP, 0); dispatch(s, onerr); - genop(s, MKOP_ABC(OP_RESCUE, exc, 0, 0)); - genop(s, MKOP_A(OP_LOADF, exc)); + genop_1(s, OP_EXCEPT, exc); + genop_1(s, OP_LOADF, exc); dispatch(s, noexc); loop_pop(s, NOVAL); } @@ -1867,7 +1865,7 @@ codegen(codegen_scope *s, node *tree, int val) push(); } codegen(s, n->car, VAL); /* receiver */ - idx = new_msym(s, nsym(n->cdr->car)); + idx = new_sym(s, nsym(n->cdr->car)); base = cursp()-1; if (n->cdr->cdr->car) { nargs = gen_values(s, n->cdr->cdr->car->car, VAL, 1); @@ -1881,12 +1879,12 @@ codegen(codegen_scope *s, node *tree, int val) } } /* copy receiver and arguments */ - genop(s, MKOP_AB(OP_MOVE, cursp(), base)); + gen_move(s, cursp(), base, 0); for (i=0; i= 0) { - genop(s, MKOP_AB(OP_MOVE, vsp, cursp())); + gen_move(s, vsp, cursp(), 0); } - pos = genop(s, MKOP_AsBx(name[0]=='|'?OP_JMPIF:OP_JMPNOT, cursp(), 0)); + pos = genjmp2(s, name[0]=='|'?OP_JMPIF:OP_JMPNOT, cursp(), 0, val); } else { - pos = genop_peep(s, MKOP_AsBx(name[0]=='|'?OP_JMPIF:OP_JMPNOT, cursp(), 0), NOVAL); + pos = genjmp2(s, name[0]=='|'?OP_JMPIF:OP_JMPNOT, cursp(), 0, val); } codegen(s, tree->cdr->cdr->car, VAL); pop(); if (val && vsp >= 0) { - genop(s, MKOP_AB(OP_MOVE, vsp, cursp())); + gen_move(s, vsp, cursp(), 0); } if (nint(tree->car->car) == NODE_CALL) { if (callargs == CALL_MAXARGS) { pop(); - genop(s, MKOP_AB(OP_ARYPUSH, cursp(), cursp()+1)); + genop_1(s, OP_ARYPUSH, cursp()); } else { pop_n(callargs); callargs++; } pop(); - idx = new_msym(s, attrsym(s, nsym(tree->car->cdr->cdr->car))); - genop(s, MKOP_ABC(OP_SEND, cursp(), idx, callargs)); + idx = new_sym(s, attrsym(s, nsym(tree->car->cdr->cdr->car))); + genop_3(s, OP_SEND, cursp(), idx, callargs); } else { gen_assignment(s, tree->car, cursp(), val); @@ -1935,52 +1933,52 @@ codegen(codegen_scope *s, node *tree, int val) push(); pop(); pop(); pop(); - idx = new_msym(s, sym); + idx = new_sym(s, sym); if (len == 1 && name[0] == '+') { - genop_peep(s, MKOP_ABC(OP_ADD, cursp(), idx, 1), val); + gen_addsub(s, OP_ADD, cursp(), idx); } else if (len == 1 && name[0] == '-') { - genop_peep(s, MKOP_ABC(OP_SUB, cursp(), idx, 1), val); + gen_addsub(s, OP_SUB, cursp(), idx); } else if (len == 1 && name[0] == '*') { - genop(s, MKOP_ABC(OP_MUL, cursp(), idx, 1)); + genop_2(s, OP_MUL, cursp(), idx); } else if (len == 1 && name[0] == '/') { - genop(s, MKOP_ABC(OP_DIV, cursp(), idx, 1)); + genop_2(s, OP_DIV, cursp(), idx); } else if (len == 1 && name[0] == '<') { - genop(s, MKOP_ABC(OP_LT, cursp(), idx, 1)); + genop_2(s, OP_LT, cursp(), idx); } else if (len == 2 && name[0] == '<' && name[1] == '=') { - genop(s, MKOP_ABC(OP_LE, cursp(), idx, 1)); + genop_2(s, OP_LE, cursp(), idx); } else if (len == 1 && name[0] == '>') { - genop(s, MKOP_ABC(OP_GT, cursp(), idx, 1)); + genop_2(s, OP_GT, cursp(), idx); } else if (len == 2 && name[0] == '>' && name[1] == '=') { - genop(s, MKOP_ABC(OP_GE, cursp(), idx, 1)); + genop_2(s, OP_GE, cursp(), idx); } else { - genop(s, MKOP_ABC(OP_SEND, cursp(), idx, 1)); + genop_3(s, OP_SEND, cursp(), idx, 1); } if (callargs < 0) { gen_assignment(s, tree->car, cursp(), val); } else { if (val && vsp >= 0) { - genop(s, MKOP_AB(OP_MOVE, vsp, cursp())); + gen_move(s, vsp, cursp(), 0); } if (callargs == CALL_MAXARGS) { pop(); - genop(s, MKOP_AB(OP_ARYPUSH, cursp(), cursp()+1)); + genop_1(s, OP_ARYPUSH, cursp()); } else { pop_n(callargs); callargs++; } pop(); - idx = new_msym(s, attrsym(s,nsym(tree->car->cdr->cdr->car))); - genop(s, MKOP_ABC(OP_SEND, cursp(), idx, callargs)); + idx = new_sym(s, attrsym(s,nsym(tree->car->cdr->cdr->car))); + genop_3(s, OP_SEND, cursp(), idx, callargs); } } break; @@ -1997,7 +1995,7 @@ codegen(codegen_scope *s, node *tree, int val) s2 = s2->prev; if (!s2) break; } - genop(s, MKOP_ABx(OP_ARGARY, cursp(), (lv & 0xf))); + genop_2S(s, OP_ARGARY, cursp(), (lv & 0xf)); push(); push(); /* ARGARY pushes two values */ pop(); pop(); if (tree) { @@ -2015,12 +2013,12 @@ codegen(codegen_scope *s, node *tree, int val) pop(); } else { - genop(s, MKOP_A(OP_LOADNIL, cursp())); + genop_1(s, OP_LOADNIL, cursp()); push(); pop(); } pop_n(n+1); if (sendv) n = CALL_MAXARGS; - genop(s, MKOP_ABC(OP_SUPER, cursp(), 0, n)); + genop_2(s, OP_SUPER, cursp(), n); if (val) push(); } break; @@ -2037,14 +2035,14 @@ codegen(codegen_scope *s, node *tree, int val) if (!s2) break; } if (s2) ainfo = s2->ainfo; - genop(s, MKOP_ABx(OP_ARGARY, cursp(), (ainfo<<4)|(lv & 0xf))); + genop_2S(s, OP_ARGARY, cursp(), (ainfo<<4)|(lv & 0xf)); push(); push(); pop(); /* ARGARY pushes two values */ if (tree && tree->cdr) { codegen(s, tree->cdr, VAL); pop(); } pop(); pop(); - genop(s, MKOP_ABC(OP_SUPER, cursp(), 0, CALL_MAXARGS)); + genop_2(s, OP_SUPER, cursp(), CALL_MAXARGS); if (val) push(); } break; @@ -2054,13 +2052,13 @@ codegen(codegen_scope *s, node *tree, int val) gen_retval(s, tree); } else { - genop(s, MKOP_A(OP_LOADNIL, cursp())); + genop_1(s, OP_LOADNIL, cursp()); } if (s->loop) { - genop(s, MKOP_AB(OP_RETURN, cursp(), OP_R_RETURN)); + genop_1(s, OP_RETURN_BLK, cursp()); } else { - genop_peep(s, MKOP_AB(OP_RETURN, cursp(), OP_R_NORMAL), NOVAL); + genop_1(s, OP_RETURN, cursp()); } if (val) push(); break; @@ -2087,9 +2085,9 @@ codegen(codegen_scope *s, node *tree, int val) } push();pop(); /* space for a block */ pop_n(n+1); - genop(s, MKOP_ABx(OP_BLKPUSH, cursp(), (ainfo<<4)|(lv & 0xf))); + genop_2S(s, OP_BLKPUSH, cursp(), (ainfo<<4)|(lv & 0xf)); if (sendv) n = CALL_MAXARGS; - genop(s, MKOP_ABC(OP_SEND, cursp(), new_msym(s, mrb_intern_lit(s->mrb, "call")), n)); + genop_3(s, OP_SEND, cursp(), new_sym(s, mrb_intern_lit(s->mrb, "call")), n); if (val) push(); } break; @@ -2105,11 +2103,10 @@ codegen(codegen_scope *s, node *tree, int val) } else if (s->loop->type == LOOP_NORMAL) { if (s->ensure_level > s->loop->ensure_level) { - genop_peep(s, MKOP_A(OP_EPOP, s->ensure_level - s->loop->ensure_level), NOVAL); + genop_1(s, OP_EPOP, s->ensure_level - s->loop->ensure_level); } codegen(s, tree, NOVAL); - distcheck(s, s->loop->pc1 - s->pc); - genop(s, MKOP_sBx(OP_JMP, s->loop->pc1 - s->pc)); + genjmp(s, OP_JMP, s->loop->pc0); } else { if (tree) { @@ -2117,9 +2114,9 @@ codegen(codegen_scope *s, node *tree, int val) pop(); } else { - genop(s, MKOP_A(OP_LOADNIL, cursp())); + genop_1(s, OP_LOADNIL, cursp()); } - genop_peep(s, MKOP_AB(OP_RETURN, cursp(), OP_R_NORMAL), NOVAL); + genop_1(s, OP_RETURN, cursp()); } if (val) push(); break; @@ -2130,10 +2127,9 @@ codegen(codegen_scope *s, node *tree, int val) } else { if (s->ensure_level > s->loop->ensure_level) { - genop_peep(s, MKOP_A(OP_EPOP, s->ensure_level - s->loop->ensure_level), NOVAL); + genop_1(s, OP_EPOP, s->ensure_level - s->loop->ensure_level); } - distcheck(s, s->loop->pc2 - s->pc); - genop(s, MKOP_sBx(OP_JMP, s->loop->pc2 - s->pc)); + genjmp(s, OP_JMP, s->loop->pc2); } if (val) push(); break; @@ -2160,13 +2156,12 @@ codegen(codegen_scope *s, node *tree, int val) } else { if (n > 0) { - genop_peep(s, MKOP_A(OP_POPERR, n), NOVAL); + genop_1(s, OP_POPERR, n); } if (s->ensure_level > lp->ensure_level) { - genop_peep(s, MKOP_A(OP_EPOP, s->ensure_level - lp->ensure_level), NOVAL); + genop_1(s, OP_EPOP, s->ensure_level - lp->ensure_level); } - distcheck(s, s->loop->pc1 - s->pc); - genop(s, MKOP_sBx(OP_JMP, lp->pc1 - s->pc)); + genjmp(s, OP_JMP, lp->pc0); } } if (val) push(); @@ -2178,7 +2173,8 @@ codegen(codegen_scope *s, node *tree, int val) int idx = lv_idx(s, nsym(tree)); if (idx > 0) { - genop_peep(s, MKOP_AB(OP_MOVE, cursp(), idx), NOVAL); + gen_move(s, cursp(), idx, val); + if (val && on_eval(s)) genop_0(s, OP_NOP); } else { int lv = 0; @@ -2187,7 +2183,7 @@ codegen(codegen_scope *s, node *tree, int val) while (up) { idx = lv_idx(up, nsym(tree)); if (idx > 0) { - genop_peep(s, MKOP_ABC(OP_GETUPVAR, cursp(), idx, lv), VAL); + genop_3(s, OP_GETUPVAR, cursp(), idx, lv); break; } lv++; @@ -2199,29 +2195,29 @@ codegen(codegen_scope *s, node *tree, int val) break; case NODE_GVAR: - if (val) { + { int sym = new_sym(s, nsym(tree)); - genop(s, MKOP_ABx(OP_GETGLOBAL, cursp(), sym)); - push(); + genop_2(s, OP_GETGV, cursp(), sym); + if (val) push(); } break; case NODE_IVAR: - if (val) { + { int sym = new_sym(s, nsym(tree)); - genop(s, MKOP_ABx(OP_GETIV, cursp(), sym)); - push(); + genop_2(s, OP_GETIV, cursp(), sym); + if (val) push(); } break; case NODE_CVAR: - if (val) { + { int sym = new_sym(s, nsym(tree)); - genop(s, MKOP_ABx(OP_GETCV, cursp(), sym)); - push(); + genop_2(s, OP_GETCV, cursp(), sym); + if (val) push(); } break; @@ -2229,15 +2225,13 @@ codegen(codegen_scope *s, node *tree, int val) { int sym = new_sym(s, nsym(tree)); - genop(s, MKOP_ABx(OP_GETCONST, cursp(), sym)); - if (val) { - push(); - } + genop_2(s, OP_GETCONST, cursp(), sym); + if (val) push(); } break; case NODE_DEFINED: - codegen(s, tree, VAL); + codegen(s, tree, val); break; case NODE_BACK_REF: @@ -2249,7 +2243,7 @@ codegen(codegen_scope *s, node *tree, int val) buf[1] = nchar(tree); buf[2] = 0; sym = new_sym(s, mrb_intern_cstr(s->mrb, buf)); - genop(s, MKOP_ABx(OP_GETGLOBAL, cursp(), sym)); + genop_2(s, OP_GETGV, cursp(), sym); push(); } break; @@ -2262,7 +2256,7 @@ codegen(codegen_scope *s, node *tree, int val) str = mrb_format(mrb, "$%S", mrb_fixnum_value(nint(tree))); sym = new_sym(s, mrb_intern_str(mrb, str)); - genop(s, MKOP_ABx(OP_GETGLOBAL, cursp(), sym)); + genop_2(s, OP_GETGV, cursp(), sym); push(); } break; @@ -2272,7 +2266,7 @@ codegen(codegen_scope *s, node *tree, int val) break; case NODE_BLOCK_ARG: - codegen(s, tree, VAL); + codegen(s, tree, val); break; case NODE_INT: @@ -2280,7 +2274,6 @@ codegen(codegen_scope *s, node *tree, int val) char *p = (char*)tree->car; int base = nint(tree->cdr->car); mrb_int i; - mrb_code co; mrb_bool overflow; i = readint_mrb_int(s, p, base, FALSE, &overflow); @@ -2289,19 +2282,19 @@ codegen(codegen_scope *s, node *tree, int val) double f = readint_float(s, p, base); int off = new_lit(s, mrb_float_value(s->mrb, f)); - genop(s, MKOP_ABx(OP_LOADL, cursp(), off)); + genop_2(s, OP_LOADL, cursp(), off); } else #endif { - if (i < MAXARG_sBx && i > -MAXARG_sBx) { - co = MKOP_AsBx(OP_LOADI, cursp(), i); - } + if (i == -1) genop_1(s, OP_LOADI__1, cursp()); + else if (i < 0) genop_2(s, OP_LOADINEG, cursp(), -i); + else if (i < 8) genop_1(s, OP_LOADI_0 + i, cursp()); + else if (i <= 0xffff) genop_2(s, OP_LOADI, cursp(), i); else { int off = new_lit(s, mrb_fixnum_value(i)); - co = MKOP_ABx(OP_LOADL, cursp(), off); + genop_2(s, OP_LOADL, cursp(), off); } - genop(s, co); } push(); } @@ -2314,7 +2307,7 @@ codegen(codegen_scope *s, node *tree, int val) mrb_float f = mrb_float_read(p, NULL); int off = new_lit(s, mrb_float_value(s->mrb, f)); - genop(s, MKOP_ABx(OP_LOADL, cursp(), off)); + genop_2(s, OP_LOADL, cursp(), off); push(); } break; @@ -2332,7 +2325,7 @@ codegen(codegen_scope *s, node *tree, int val) mrb_float f = mrb_float_read(p, NULL); int off = new_lit(s, mrb_float_value(s->mrb, -f)); - genop(s, MKOP_ABx(OP_LOADL, cursp(), off)); + genop_2(s, OP_LOADL, cursp(), off); push(); } break; @@ -2343,7 +2336,6 @@ codegen(codegen_scope *s, node *tree, int val) char *p = (char*)tree->car; int base = nint(tree->cdr->car); mrb_int i; - mrb_code co; mrb_bool overflow; i = readint_mrb_int(s, p, base, TRUE, &overflow); @@ -2352,18 +2344,18 @@ codegen(codegen_scope *s, node *tree, int val) double f = readint_float(s, p, base); int off = new_lit(s, mrb_float_value(s->mrb, -f)); - genop(s, MKOP_ABx(OP_LOADL, cursp(), off)); + genop_2(s, OP_LOADL, cursp(), off); } else { #endif - if (i < MAXARG_sBx && i > -MAXARG_sBx) { - co = MKOP_AsBx(OP_LOADI, cursp(), i); + if (i == -1) genop_1(s, OP_LOADI__1, cursp()); + else if (i >= -0xffff) { + genop_2(s, OP_LOADINEG, cursp(), -i); } else { int off = new_lit(s, mrb_fixnum_value(i)); - co = MKOP_ABx(OP_LOADL, cursp(), off); + genop_2(s, OP_LOADL, cursp(), off); } - genop(s, co); #ifndef MRB_WITHOUT_FLOAT } #endif @@ -2373,13 +2365,13 @@ codegen(codegen_scope *s, node *tree, int val) default: if (val) { - int sym = new_msym(s, mrb_intern_lit(s->mrb, "-")); + int sym = new_sym(s, mrb_intern_lit(s->mrb, "-")); - genop(s, MKOP_ABx(OP_LOADI, cursp(), 0)); + genop_1(s, OP_LOADI_0, cursp()); push(); codegen(s, tree, VAL); pop(); pop(); - genop(s, MKOP_ABC(OP_SUB, cursp(), sym, 2)); + genop_2(s, OP_SUB, cursp(), sym); } else { codegen(s, tree, NOVAL); @@ -2397,7 +2389,7 @@ codegen(codegen_scope *s, node *tree, int val) int off = new_lit(s, mrb_str_new(s->mrb, p, len)); mrb_gc_arena_restore(s->mrb, ai); - genop(s, MKOP_ABx(OP_STRING, cursp(), off)); + genop_2(s, OP_STRING, cursp(), off); push(); } break; @@ -2410,7 +2402,7 @@ codegen(codegen_scope *s, node *tree, int val) node *n = tree; if (!n) { - genop(s, MKOP_A(OP_LOADNIL, cursp())); + genop_1(s, OP_LOADNIL, cursp()); push(); break; } @@ -2419,7 +2411,7 @@ codegen(codegen_scope *s, node *tree, int val) while (n) { codegen(s, n->car, VAL); pop(); pop(); - genop_peep(s, MKOP_AB(OP_STRCAT, cursp(), cursp()+1), VAL); + genop_1(s, OP_STRCAT, cursp()); push(); n = n->cdr; } @@ -2450,7 +2442,7 @@ codegen(codegen_scope *s, node *tree, int val) int ai = mrb_gc_arena_save(s->mrb); int sym = new_sym(s, mrb_intern_lit(s->mrb, "Kernel")); - genop(s, MKOP_A(OP_LOADSELF, cursp())); + genop_1(s, OP_LOADSELF, cursp()); push(); codegen(s, tree->car, VAL); n = tree->cdr; @@ -2461,14 +2453,14 @@ codegen(codegen_scope *s, node *tree, int val) } codegen(s, n->car, VAL); pop(); pop(); - genop_peep(s, MKOP_AB(OP_STRCAT, cursp(), cursp()+1), VAL); + genop_1(s, OP_STRCAT, cursp()); push(); n = n->cdr; } push(); /* for block */ pop_n(3); sym = new_sym(s, mrb_intern_lit(s->mrb, "`")); - genop(s, MKOP_ABC(OP_SEND, cursp(), sym, 1)); + genop_3(s, OP_SEND, cursp(), sym, 1); if (val) push(); mrb_gc_arena_restore(s->mrb, ai); } @@ -2482,13 +2474,13 @@ codegen(codegen_scope *s, node *tree, int val) int off = new_lit(s, mrb_str_new(s->mrb, p, len)); int sym; - genop(s, MKOP_A(OP_LOADSELF, cursp())); + genop_1(s, OP_LOADSELF, cursp()); push(); - genop(s, MKOP_ABx(OP_STRING, cursp(), off)); + genop_2(s, OP_STRING, cursp(), off); push(); push(); pop_n(3); sym = new_sym(s, mrb_intern_lit(s->mrb, "`")); - genop(s, MKOP_ABC(OP_SEND, cursp(), sym, 1)); + genop_3(s, OP_SEND, cursp(), sym, 1); if (val) push(); mrb_gc_arena_restore(s->mrb, ai); } @@ -2504,24 +2496,24 @@ codegen(codegen_scope *s, node *tree, int val) int off = new_lit(s, mrb_str_new_cstr(s->mrb, p1)); int argc = 1; - genop(s, MKOP_A(OP_OCLASS, cursp())); - genop(s, MKOP_ABx(OP_GETMCNST, cursp(), sym)); + genop_1(s, OP_OCLASS, cursp()); + genop_2(s, OP_GETMCNST, cursp(), sym); push(); - genop(s, MKOP_ABx(OP_STRING, cursp(), off)); + genop_2(s, OP_STRING, cursp(), off); push(); if (p2 || p3) { if (p2) { /* opt */ off = new_lit(s, mrb_str_new_cstr(s->mrb, p2)); - genop(s, MKOP_ABx(OP_STRING, cursp(), off)); + genop_2(s, OP_STRING, cursp(), off); } else { - genop(s, MKOP_A(OP_LOADNIL, cursp())); + genop_1(s, OP_LOADNIL, cursp()); } push(); argc++; if (p3) { /* enc */ off = new_lit(s, mrb_str_new(s->mrb, p3, 1)); - genop(s, MKOP_ABx(OP_STRING, cursp(), off)); + genop_2(s, OP_STRING, cursp(), off); push(); argc++; } @@ -2529,7 +2521,7 @@ codegen(codegen_scope *s, node *tree, int val) push(); /* space for a block */ pop_n(argc+2); sym = new_sym(s, mrb_intern_lit(s->mrb, "compile")); - genop(s, MKOP_ABC(OP_SEND, cursp(), sym, argc)); + genop_3(s, OP_SEND, cursp(), sym, argc); mrb_gc_arena_restore(s->mrb, ai); push(); } @@ -2544,15 +2536,15 @@ codegen(codegen_scope *s, node *tree, int val) int off; char *p; - genop(s, MKOP_A(OP_OCLASS, cursp())); - genop(s, MKOP_ABx(OP_GETMCNST, cursp(), sym)); + genop_1(s, OP_OCLASS, cursp()); + genop_2(s, OP_GETMCNST, cursp(), sym); push(); codegen(s, n->car, VAL); n = n->cdr; while (n) { codegen(s, n->car, VAL); pop(); pop(); - genop_peep(s, MKOP_AB(OP_STRCAT, cursp(), cursp()+1), VAL); + genop_1(s, OP_STRCAT, cursp()); push(); n = n->cdr; } @@ -2561,29 +2553,29 @@ codegen(codegen_scope *s, node *tree, int val) p = (char*)n->car; off = new_lit(s, mrb_str_new_cstr(s->mrb, p)); codegen(s, tree->car, VAL); - genop(s, MKOP_ABx(OP_STRING, cursp(), off)); + genop_2(s, OP_STRING, cursp(), off); pop(); - genop_peep(s, MKOP_AB(OP_STRCAT, cursp(), cursp()+1), VAL); + genop_1(s, OP_STRCAT, cursp()); push(); } if (n->cdr->car) { /* opt */ char *p2 = (char*)n->cdr->car; off = new_lit(s, mrb_str_new_cstr(s->mrb, p2)); - genop(s, MKOP_ABx(OP_STRING, cursp(), off)); + genop_2(s, OP_STRING, cursp(), off); push(); argc++; } if (n->cdr->cdr) { /* enc */ char *p2 = (char*)n->cdr->cdr; off = new_lit(s, mrb_str_new_cstr(s->mrb, p2)); - genop(s, MKOP_ABx(OP_STRING, cursp(), off)); + genop_2(s, OP_STRING, cursp(), off); push(); argc++; } push(); /* space for a block */ pop_n(argc+2); sym = new_sym(s, mrb_intern_lit(s->mrb, "compile")); - genop(s, MKOP_ABC(OP_SEND, cursp(), sym, argc)); + genop_3(s, OP_SEND, cursp(), sym, argc); mrb_gc_arena_restore(s->mrb, ai); push(); } @@ -2603,7 +2595,7 @@ codegen(codegen_scope *s, node *tree, int val) if (val) { int sym = new_sym(s, nsym(tree)); - genop(s, MKOP_ABx(OP_LOADSYM, cursp(), sym)); + genop_2(s, OP_LOADSYM, cursp(), sym); push(); } break; @@ -2611,55 +2603,46 @@ codegen(codegen_scope *s, node *tree, int val) case NODE_DSYM: codegen(s, tree, val); if (val) { - gen_send_intern(s); + gen_intern(s); } break; case NODE_SELF: if (val) { - genop(s, MKOP_A(OP_LOADSELF, cursp())); + genop_1(s, OP_LOADSELF, cursp()); push(); } break; case NODE_NIL: if (val) { - genop(s, MKOP_A(OP_LOADNIL, cursp())); + genop_1(s, OP_LOADNIL, cursp()); push(); } break; case NODE_TRUE: if (val) { - genop(s, MKOP_A(OP_LOADT, cursp())); + genop_1(s, OP_LOADT, cursp()); push(); } break; case NODE_FALSE: if (val) { - genop(s, MKOP_A(OP_LOADF, cursp())); + genop_1(s, OP_LOADF, cursp()); push(); } break; case NODE_ALIAS: { - int a = new_msym(s, nsym(tree->car)); - int b = new_msym(s, nsym(tree->cdr)); - int c = new_msym(s, mrb_intern_lit(s->mrb, "alias_method")); + int a = new_sym(s, nsym(tree->car)); + int b = new_sym(s, nsym(tree->cdr)); - genop(s, MKOP_A(OP_TCLASS, cursp())); - push(); - genop(s, MKOP_ABx(OP_LOADSYM, cursp(), a)); - push(); - genop(s, MKOP_ABx(OP_LOADSYM, cursp(), b)); - push(); - genop(s, MKOP_A(OP_LOADNIL, cursp())); - push(); /* space for a block */ - pop_n(4); - genop(s, MKOP_ABC(OP_SEND, cursp(), c, 2)); + genop_2(s, OP_ALIAS, a, b); if (val) { + genop_1(s, OP_LOADNIL, cursp()); push(); } } @@ -2667,41 +2650,15 @@ codegen(codegen_scope *s, node *tree, int val) case NODE_UNDEF: { - int undef = new_msym(s, mrb_intern_lit(s->mrb, "undef_method")); - int num = 0; node *t = tree; - genop(s, MKOP_A(OP_TCLASS, cursp())); - push(); while (t) { - int symbol; - if (num >= CALL_MAXARGS - 1) { - pop_n(num); - genop(s, MKOP_ABC(OP_ARRAY, cursp(), cursp(), num)); - while (t) { - symbol = new_msym(s, nsym(t->car)); - push(); - genop(s, MKOP_ABx(OP_LOADSYM, cursp(), symbol)); - pop(); - genop(s, MKOP_AB(OP_ARYPUSH, cursp(), cursp()+1)); - t = t->cdr; - } - num = CALL_MAXARGS; - break; - } - symbol = new_msym(s, nsym(t->car)); - genop(s, MKOP_ABx(OP_LOADSYM, cursp(), symbol)); - push(); + int symbol = new_sym(s, nsym(t->car)); + genop_1(s, OP_UNDEF, symbol); t = t->cdr; - num++; - } - push();pop(); /* space for a block */ - pop(); - if (num < CALL_MAXARGS) { - pop_n(num); } - genop(s, MKOP_ABC(OP_SEND, cursp(), undef, num)); if (val) { + genop_1(s, OP_LOADNIL, cursp()); push(); } } @@ -2710,13 +2667,14 @@ codegen(codegen_scope *s, node *tree, int val) case NODE_CLASS: { int idx; + node *body; if (tree->car->car == (node*)0) { - genop(s, MKOP_A(OP_LOADNIL, cursp())); + genop_1(s, OP_LOADNIL, cursp()); push(); } else if (tree->car->car == (node*)1) { - genop(s, MKOP_A(OP_OCLASS, cursp())); + genop_1(s, OP_OCLASS, cursp()); push(); } else { @@ -2726,14 +2684,17 @@ codegen(codegen_scope *s, node *tree, int val) codegen(s, tree->cdr->car, VAL); } else { - genop(s, MKOP_A(OP_LOADNIL, cursp())); + genop_1(s, OP_LOADNIL, cursp()); push(); } pop(); pop(); - idx = new_msym(s, nsym(tree->car->cdr)); - genop(s, MKOP_AB(OP_CLASS, cursp(), idx)); - idx = scope_body(s, tree->cdr->cdr->car, val); - genop(s, MKOP_ABx(OP_EXEC, cursp(), idx)); + idx = new_sym(s, nsym(tree->car->cdr)); + genop_2(s, OP_CLASS, cursp(), idx); + body = tree->cdr->cdr->car; + if (!(nint(body->cdr->car) == NODE_BEGIN && body->cdr->cdr == NULL)) { + idx = scope_body(s, body, val); + genop_2(s, OP_EXEC, cursp(), idx); + } if (val) { push(); } @@ -2745,21 +2706,24 @@ codegen(codegen_scope *s, node *tree, int val) int idx; if (tree->car->car == (node*)0) { - genop(s, MKOP_A(OP_LOADNIL, cursp())); + genop_1(s, OP_LOADNIL, cursp()); push(); } else if (tree->car->car == (node*)1) { - genop(s, MKOP_A(OP_OCLASS, cursp())); + genop_1(s, OP_OCLASS, cursp()); push(); } else { codegen(s, tree->car->car, VAL); } pop(); - idx = new_msym(s, nsym(tree->car->cdr)); - genop(s, MKOP_AB(OP_MODULE, cursp(), idx)); - idx = scope_body(s, tree->cdr->car, val); - genop(s, MKOP_ABx(OP_EXEC, cursp(), idx)); + idx = new_sym(s, nsym(tree->car->cdr)); + genop_2(s, OP_MODULE, cursp(), idx); + if (!(nint(tree->cdr->car->cdr->car) == NODE_BEGIN && + tree->cdr->car->cdr->cdr == NULL)) { + idx = scope_body(s, tree->cdr->car, val); + genop_2(s, OP_EXEC, cursp(), idx); + } if (val) { push(); } @@ -2772,9 +2736,12 @@ codegen(codegen_scope *s, node *tree, int val) codegen(s, tree->car, VAL); pop(); - genop(s, MKOP_AB(OP_SCLASS, cursp(), cursp())); - idx = scope_body(s, tree->cdr->car, val); - genop(s, MKOP_ABx(OP_EXEC, cursp(), idx)); + genop_1(s, OP_SCLASS, cursp()); + if (!(nint(tree->cdr->car->cdr->car) == NODE_BEGIN && + tree->cdr->car->cdr->cdr == NULL)) { + idx = scope_body(s, tree->cdr->car, val); + genop_2(s, OP_EXEC, cursp(), idx); + } if (val) { push(); } @@ -2783,17 +2750,17 @@ codegen(codegen_scope *s, node *tree, int val) case NODE_DEF: { - int sym = new_msym(s, nsym(tree->car)); + int sym = new_sym(s, nsym(tree->car)); int idx = lambda_body(s, tree->cdr, 0); - genop(s, MKOP_A(OP_TCLASS, cursp())); + genop_1(s, OP_TCLASS, cursp()); push(); - genop(s, MKOP_Abc(OP_LAMBDA, cursp(), idx, OP_L_METHOD)); + genop_2(s, OP_METHOD, cursp(), idx); push(); pop(); pop(); - genop(s, MKOP_AB(OP_METHOD, cursp(), sym)); + genop_2(s, OP_DEF, cursp(), sym); if (val) { - genop(s, MKOP_ABx(OP_LOADSYM, cursp(), sym)); + genop_2(s, OP_LOADSYM, cursp(), sym); push(); } } @@ -2802,18 +2769,18 @@ codegen(codegen_scope *s, node *tree, int val) case NODE_SDEF: { node *recv = tree->car; - int sym = new_msym(s, nsym(tree->cdr->car)); + int sym = new_sym(s, nsym(tree->cdr->car)); int idx = lambda_body(s, tree->cdr->cdr, 0); codegen(s, recv, VAL); pop(); - genop(s, MKOP_AB(OP_SCLASS, cursp(), cursp())); + genop_1(s, OP_SCLASS, cursp()); push(); - genop(s, MKOP_Abc(OP_LAMBDA, cursp(), idx, OP_L_METHOD)); + genop_2(s, OP_METHOD, cursp(), idx); pop(); - genop(s, MKOP_AB(OP_METHOD, cursp(), sym)); + genop_2(s, OP_DEF, cursp(), sym); if (val) { - genop(s, MKOP_ABx(OP_LOADSYM, cursp(), sym)); + genop_2(s, OP_LOADSYM, cursp(), sym); push(); } } @@ -2875,7 +2842,7 @@ scope_new(mrb_state *mrb, codegen_scope *prev, node *lv) p->irep->pool = (mrb_value*)mrb_malloc(mrb, sizeof(mrb_value)*p->pcapa); p->irep->plen = 0; - p->scapa = MAXMSYMLEN; + p->scapa = 256; p->irep->syms = (mrb_sym*)mrb_malloc(mrb, sizeof(mrb_sym)*p->scapa); p->irep->slen = 0; @@ -2971,7 +2938,7 @@ loop_push(codegen_scope *s, enum looptype t) struct loopinfo *p = (struct loopinfo *)codegen_palloc(s, sizeof(struct loopinfo)); p->type = t; - p->pc1 = p->pc2 = p->pc3 = 0; + p->pc0 = p->pc1 = p->pc2 = p->pc3 = 0; p->prev = s->loop; p->ensure_level = s->ensure_level; p->acc = cursp(); @@ -3013,27 +2980,26 @@ loop_break(codegen_scope *s, node *tree) return; } if (n > 0) { - genop_peep(s, MKOP_A(OP_POPERR, n), NOVAL); + genop_1(s, OP_POPERR, n); } if (loop->type == LOOP_NORMAL) { int tmp; if (s->ensure_level > s->loop->ensure_level) { - genop_peep(s, MKOP_A(OP_EPOP, s->ensure_level - s->loop->ensure_level), NOVAL); + genop_1(s, OP_EPOP, s->ensure_level - s->loop->ensure_level); } if (tree) { - genop_peep(s, MKOP_AB(OP_MOVE, loop->acc, cursp()), NOVAL); + gen_move(s, loop->acc, cursp(), 0); } - distcheck(s, s->loop->pc3); - tmp = genop(s, MKOP_sBx(OP_JMP, loop->pc3)); + tmp = genjmp(s, OP_JMP, loop->pc3); loop->pc3 = tmp; } else { if (!tree) { - genop(s, MKOP_A(OP_LOADNIL, cursp())); + genop_1(s, OP_LOADNIL, cursp()); } - genop(s, MKOP_AB(OP_RETURN, cursp(), OP_R_BREAK)); + genop_1(s, OP_BREAK, cursp()); } } } @@ -3042,7 +3008,7 @@ static void loop_pop(codegen_scope *s, int val) { if (val) { - genop(s, MKOP_A(OP_LOADNIL, cursp())); + genop_1(s, OP_LOADNIL, cursp()); } dispatch_linked(s, s->loop->pc3); s->loop = s->loop->prev; @@ -3107,3 +3073,56 @@ mrb_irep_remove_lv(mrb_state *mrb, mrb_irep *irep) mrb_irep_remove_lv(mrb, irep->reps[i]); } } + +#undef OPCODE +#define Z 1 +#define S 3 +#define W 4 +/* instruction sizes */ +uint8_t mrb_insn_size[] = { +#define B 2 +#define BB 3 +#define BBB 4 +#define BS 4 +#define SB 4 +#define OPCODE(_,x) x, +#include "mruby/ops.h" +#undef OPCODE +#undef B +#undef BB +#undef BS +#undef SB +#undef BBB +}; +/* EXT1 instruction sizes */ +uint8_t mrb_insn_size1[] = { +#define B 3 +#define BB 4 +#define BBB 5 +#define BS 5 +#define SB 5 +#define OPCODE(_,x) x, +#include "mruby/ops.h" +#undef OPCODE +#undef B +}; +/* EXT2 instruction sizes */ +uint8_t mrb_insn_size2[] = { +#define B 2 +#define OPCODE(_,x) x, +#include "mruby/ops.h" +#undef OPCODE +#undef BB +#undef BBB +#undef BS +#undef SB +}; +/* EXT3 instruction sizes */ +#define BB 5 +#define BBB 6 +#define BS 4 +#define SB 5 +uint8_t mrb_insn_size3[] = { +#define OPCODE(_,x) x, +#include "mruby/ops.h" +}; diff --git a/mrbgems/mruby-compiler/core/parse.y b/mrbgems/mruby-compiler/core/parse.y index 7f848b4df..61d94edc9 100644 --- a/mrbgems/mruby-compiler/core/parse.y +++ b/mrbgems/mruby-compiler/core/parse.y @@ -5534,6 +5534,7 @@ parser_init_cxt(parser_state *p, mrbc_context *cxt) } p->capture_errors = cxt->capture_errors; p->no_optimize = cxt->no_optimize; + p->on_eval = cxt->on_eval; if (cxt->partial_hook) { p->cxt = cxt; } @@ -6648,6 +6649,20 @@ mrb_parser_dump(mrb_state *mrb, node *tree, int offset) dump_recur(mrb, ((parser_heredoc_info*)tree)->doc, offset+1); break; + case NODE_LITERAL_DELIM: + printf("NODE_LITERAL_DELIM\n"); + break; + + case NODE_SYMBOLS: + printf("NODE_SYMBOLS:\n"); + dump_recur(mrb, tree, offset+1); + break; + + case NODE_WORDS: + printf("NODE_SYMBOLS:\n"); + dump_recur(mrb, tree, offset+1); + break; + default: printf("node type: %d (0x%x)\n", nodetype, (unsigned)nodetype); break; diff --git a/mrbgems/mruby-eval/src/eval.c b/mrbgems/mruby-eval/src/eval.c index 5c8e78acd..42a4183b7 100644 --- a/mrbgems/mruby-eval/src/eval.c +++ b/mrbgems/mruby-eval/src/eval.c @@ -44,7 +44,7 @@ search_irep(mrb_irep *top, int bnest, int lev, mrb_irep *bottom) return NULL; } -static inline mrb_code +static uint16_t search_variable(mrb_state *mrb, mrb_sym vsym, int bnest) { mrb_irep *virep; @@ -57,7 +57,7 @@ search_variable(mrb_state *mrb, mrb_sym vsym, int bnest) } for (pos = 0; pos < virep->nlocals - 1; pos++) { if (vsym == virep->lv[pos].name) { - return (MKARG_B(pos + 1) | MKARG_C(level + bnest)); + return (pos+1)<<8 | (level+bnest); } } } @@ -71,8 +71,8 @@ irep_argc(mrb_irep *irep) mrb_code c; c = irep->iseq[0]; - if (GET_OPCODE(c) == OP_ENTER) { - mrb_aspec ax = GETARG_Ax(c); + if (c == OP_ENTER) { + mrb_aspec ax = PEEK_W(irep->iseq+1); /* extra 1 means a slot for block */ return MRB_ASPEC_REQ(ax)+MRB_ASPEC_OPT(ax)+MRB_ASPEC_REST(ax)+MRB_ASPEC_POST(ax)+1; } @@ -88,95 +88,132 @@ potential_upvar_p(struct mrb_locals *lv, uint16_t v, int argc, uint16_t nlocals) return TRUE; } +extern uint8_t mrb_insn_size[]; +extern uint8_t mrb_insn_size1[]; +extern uint8_t mrb_insn_size2[]; +extern uint8_t mrb_insn_size3[]; + static void patch_irep(mrb_state *mrb, mrb_irep *irep, int bnest, mrb_irep *top) { int i; - mrb_code c; + uint32_t a; + uint16_t b; + uint8_t c; + mrb_code insn; int argc = irep_argc(irep); - for (i = 0; i < irep->ilen; i++) { - c = irep->iseq[i]; - switch(GET_OPCODE(c)){ + for (i = 0; i < irep->ilen; ) { + insn = irep->iseq[i]; + switch(insn){ case OP_EPUSH: - patch_irep(mrb, irep->reps[GETARG_Bx(c)], bnest + 1, top); + b = PEEK_S(irep->iseq+i+1); + patch_irep(mrb, irep->reps[b], bnest + 1, top); break; case OP_LAMBDA: - { - int arg_c = GETARG_c(c); - if (arg_c & OP_L_CAPTURE) { - patch_irep(mrb, irep->reps[GETARG_b(c)], bnest + 1, top); - } - } + case OP_BLOCK: + a = PEEK_B(irep->iseq+i+1); + b = PEEK_B(irep->iseq+i+2); + patch_irep(mrb, irep->reps[b], bnest + 1, top); break; case OP_SEND: - if (GETARG_C(c) != 0) { + b = PEEK_B(irep->iseq+i+2); + c = PEEK_B(irep->iseq+i+3); + if (c != 0) { break; } else { - mrb_code arg = search_variable(mrb, irep->syms[GETARG_B(c)], bnest); + uint16_t arg = search_variable(mrb, irep->syms[b], bnest); if (arg != 0) { /* must replace */ - irep->iseq[i] = MKOPCODE(OP_GETUPVAR) | MKARG_A(GETARG_A(c)) | arg; + irep->iseq[i] = OP_GETUPVAR; + irep->iseq[i+2] = arg >> 8; + irep->iseq[i+3] = arg & 0xff; } } break; case OP_MOVE: + a = PEEK_B(irep->iseq+i+1); + b = PEEK_B(irep->iseq+i+2); /* src part */ - if (potential_upvar_p(irep->lv, GETARG_B(c), argc, irep->nlocals)) { - mrb_code arg = search_variable(mrb, irep->lv[GETARG_B(c) - 1].name, bnest); + if (potential_upvar_p(irep->lv, b, argc, irep->nlocals)) { + uint16_t arg = search_variable(mrb, irep->lv[b - 1].name, bnest); if (arg != 0) { /* must replace */ - irep->iseq[i] = MKOPCODE(OP_GETUPVAR) | MKARG_A(GETARG_A(c)) | arg; + irep->iseq[i] = insn = OP_GETUPVAR; + irep->iseq[i+2] = arg >> 8; + irep->iseq[i+3] = arg & 0xff; } } /* dst part */ - if (potential_upvar_p(irep->lv, GETARG_A(c), argc, irep->nlocals)) { - mrb_code arg = search_variable(mrb, irep->lv[GETARG_A(c) - 1].name, bnest); + if (potential_upvar_p(irep->lv, a, argc, irep->nlocals)) { + uint16_t arg = search_variable(mrb, irep->lv[a - 1].name, bnest); if (arg != 0) { /* must replace */ - irep->iseq[i] = MKOPCODE(OP_SETUPVAR) | MKARG_A(GETARG_B(c)) | arg; + irep->iseq[i] = insn = OP_SETUPVAR; + irep->iseq[i+1] = b; + irep->iseq[i+2] = arg >> 8; + irep->iseq[i+3] = arg & 0xff; } } break; case OP_GETUPVAR: + a = PEEK_B(irep->iseq+i+1); + b = PEEK_B(irep->iseq+i+2); + c = PEEK_B(irep->iseq+i+3); { - int lev = GETARG_C(c)+1; + int lev = c+1; mrb_irep *tmp = search_irep(top, bnest, lev, irep); - if (potential_upvar_p(tmp->lv, GETARG_B(c), irep_argc(tmp), tmp->nlocals)) { - mrb_code arg = search_variable(mrb, tmp->lv[GETARG_B(c)-1].name, bnest); + if (potential_upvar_p(tmp->lv, b, irep_argc(tmp), tmp->nlocals)) { + mrb_code arg = search_variable(mrb, tmp->lv[b-1].name, bnest); if (arg != 0) { /* must replace */ - irep->iseq[i] = MKOPCODE(OP_GETUPVAR) | MKARG_A(GETARG_A(c)) | arg; + irep->iseq[i] = OP_GETUPVAR; + irep->iseq[i+2] = arg >> 8; + irep->iseq[i+3] = arg & 0xff; } } } break; case OP_SETUPVAR: + a = PEEK_B(irep->iseq+i+1); + b = PEEK_B(irep->iseq+i+2); + c = PEEK_B(irep->iseq+i+3); { - int lev = GETARG_C(c)+1; + int lev = c+1; mrb_irep *tmp = search_irep(top, bnest, lev, irep); - if (potential_upvar_p(tmp->lv, GETARG_B(c), irep_argc(tmp), tmp->nlocals)) { - mrb_code arg = search_variable(mrb, tmp->lv[GETARG_B(c)-1].name, bnest); + if (potential_upvar_p(tmp->lv, b, irep_argc(tmp), tmp->nlocals)) { + mrb_code arg = search_variable(mrb, tmp->lv[b-1].name, bnest); if (arg != 0) { /* must replace */ - irep->iseq[i] = MKOPCODE(OP_SETUPVAR) | MKARG_A(GETARG_A(c)) | arg; + irep->iseq[i] = OP_SETUPVAR; + irep->iseq[i+1] = a; + irep->iseq[i+2] = arg >> 8; + irep->iseq[i+3] = arg & 0xff; } } } break; - case OP_STOP: - if (mrb->c->ci->acc >= 0) { - irep->iseq[i] = MKOP_AB(OP_RETURN, irep->nlocals, OP_R_NORMAL); - } - break; + case OP_EXT1: + insn = PEEK_B(irep->iseq+1); + i += mrb_insn_size1[insn]; + continue; + case OP_EXT2: + insn = PEEK_B(irep->iseq+1); + i += mrb_insn_size2[insn]; + continue; + case OP_EXT3: + insn = PEEK_B(irep->iseq+1); + i += mrb_insn_size3[insn]; + continue; } + i+=mrb_insn_size[insn]; } } @@ -203,6 +240,7 @@ create_proc_from_string(mrb_state *mrb, char *s, mrb_int len, mrb_value binding, mrbc_filename(mrb, cxt, file ? file : "(eval)"); cxt->capture_errors = TRUE; cxt->no_optimize = TRUE; + cxt->on_eval = TRUE; p = mrb_parse_nstring(mrb, s, len, cxt); diff --git a/mrbgems/mruby-method/src/method.c b/mrbgems/mruby-method/src/method.c index e445b34c8..600567cac 100644 --- a/mrbgems/mruby-method/src/method.c +++ b/mrbgems/mruby-method/src/method.c @@ -387,7 +387,7 @@ mrb_mruby_method_gem_init(mrb_state* mrb) mrb_define_method(mrb, unbound_method, "bind", unbound_method_bind, MRB_ARGS_REQ(1)); mrb_define_method(mrb, unbound_method, "super_method", method_super_method, MRB_ARGS_NONE()); mrb_define_method(mrb, unbound_method, "==", method_eql, MRB_ARGS_REQ(1)); - mrb_alias_method(mrb, unbound_method, mrb_intern_lit(mrb, "eql?"), mrb_intern_lit(mrb, "==")); + mrb_define_alias(mrb, unbound_method, "eql?", "=="); mrb_define_method(mrb, unbound_method, "to_s", method_to_s, MRB_ARGS_NONE()); mrb_define_method(mrb, unbound_method, "inspect", method_to_s, MRB_ARGS_NONE()); mrb_define_method(mrb, unbound_method, "arity", method_arity, MRB_ARGS_NONE()); @@ -396,11 +396,11 @@ mrb_mruby_method_gem_init(mrb_state* mrb) mrb_undef_class_method(mrb, method, "new"); mrb_define_method(mrb, method, "==", method_eql, MRB_ARGS_REQ(1)); - mrb_alias_method(mrb, method, mrb_intern_lit(mrb, "eql?"), mrb_intern_lit(mrb, "==")); + mrb_define_alias(mrb, method, "eql?", "=="); mrb_define_method(mrb, method, "to_s", method_to_s, MRB_ARGS_NONE()); mrb_define_method(mrb, method, "inspect", method_to_s, MRB_ARGS_NONE()); mrb_define_method(mrb, method, "call", method_call, MRB_ARGS_ANY()); - mrb_alias_method(mrb, method, mrb_intern_lit(mrb, "[]"), mrb_intern_lit(mrb, "call")); + mrb_define_alias(mrb, method, "[]", "call"); mrb_define_method(mrb, method, "unbind", method_unbind, MRB_ARGS_NONE()); mrb_define_method(mrb, method, "super_method", method_super_method, MRB_ARGS_NONE()); mrb_define_method(mrb, method, "arity", method_arity, MRB_ARGS_NONE()); diff --git a/mrbgems/mruby-proc-ext/src/proc.c b/mrbgems/mruby-proc-ext/src/proc.c index b13606f5f..323529dcc 100644 --- a/mrbgems/mruby-proc-ext/src/proc.c +++ b/mrbgems/mruby-proc-ext/src/proc.c @@ -109,6 +109,7 @@ mrb_proc_parameters(mrb_state *mrb, mrb_value self) mrb_aspec aspec; mrb_value sname, parameters; int i, j; + int max = -1; if (MRB_PROC_CFUNC_P(proc)) { // TODO cfunc aspec is not implemented yet @@ -120,7 +121,7 @@ mrb_proc_parameters(mrb_state *mrb, mrb_value self) if (!irep->lv) { return mrb_ary_new(mrb); } - if (GET_OPCODE(*irep->iseq) != OP_ENTER) { + if (*irep->iseq != OP_ENTER) { return mrb_ary_new(mrb); } @@ -129,7 +130,7 @@ mrb_proc_parameters(mrb_state *mrb, mrb_value self) parameters_list[3].name = "opt"; } - aspec = GETARG_Ax(*irep->iseq); + aspec = PEEK_W(irep->iseq+1); parameters_list[0].size = MRB_ASPEC_REQ(aspec); parameters_list[1].size = MRB_ASPEC_OPT(aspec); parameters_list[2].size = MRB_ASPEC_REST(aspec); @@ -138,13 +139,16 @@ mrb_proc_parameters(mrb_state *mrb, mrb_value self) parameters = mrb_ary_new_capa(mrb, irep->nlocals-1); + max = irep->nlocals-1; for (i = 0, p = parameters_list; p->name; p++) { if (p->size <= 0) continue; sname = mrb_symbol_value(mrb_intern_cstr(mrb, p->name)); for (j = 0; j < p->size; i++, j++) { - mrb_value a = mrb_ary_new(mrb); + mrb_value a; + + a = mrb_ary_new(mrb); mrb_ary_push(mrb, a, sname); - if (irep->lv[i].name) { + if (i < max && irep->lv[i].name) { mrb_ary_push(mrb, a, mrb_symbol_value(irep->lv[i].name)); } mrb_ary_push(mrb, parameters, a); diff --git a/mrbgems/mruby-string-ext/src/string.c b/mrbgems/mruby-string-ext/src/string.c index 4cab49094..142d449f4 100644 --- a/mrbgems/mruby-string-ext/src/string.c +++ b/mrbgems/mruby-string-ext/src/string.c @@ -627,8 +627,8 @@ mrb_mruby_string_ext_gem_init(mrb_state* mrb) mrb_define_method(mrb, s, "chr", mrb_str_chr, MRB_ARGS_NONE()); mrb_define_method(mrb, s, "succ", mrb_str_succ, MRB_ARGS_NONE()); mrb_define_method(mrb, s, "succ!", mrb_str_succ_bang, MRB_ARGS_NONE()); - mrb_alias_method(mrb, s, mrb_intern_lit(mrb, "next"), mrb_intern_lit(mrb, "succ")); - mrb_alias_method(mrb, s, mrb_intern_lit(mrb, "next!"), mrb_intern_lit(mrb, "succ!")); + mrb_define_alias(mrb, s, "next", "succ"); + mrb_define_alias(mrb, s, "next!", "succ!"); mrb_define_method(mrb, s, "ord", mrb_str_ord, MRB_ARGS_NONE()); mrb_define_method(mrb, s, "delete_prefix!", mrb_str_del_prefix_bang, MRB_ARGS_REQ(1)); mrb_define_method(mrb, s, "delete_prefix", mrb_str_del_prefix, MRB_ARGS_REQ(1)); diff --git a/src/class.c b/src/class.c index a9439d7d7..076280f3f 100644 --- a/src/class.c +++ b/src/class.c @@ -1953,8 +1953,8 @@ mrb_mod_alias(mrb_state *mrb, mrb_value mod) return mrb_nil_value(); } -static void -undef_method(mrb_state *mrb, struct RClass *c, mrb_sym a) +void +mrb_undef_method_id(mrb_state *mrb, struct RClass *c, mrb_sym a) { if (!mrb_obj_respond_to(mrb, c, a)) { mrb_name_error(mrb, a, "undefined method '%S' for class '%S'", mrb_sym2str(mrb, a), mrb_obj_value(c)); @@ -1970,7 +1970,7 @@ undef_method(mrb_state *mrb, struct RClass *c, mrb_sym a) MRB_API void mrb_undef_method(mrb_state *mrb, struct RClass *c, const char *name) { - undef_method(mrb, c, mrb_intern_cstr(mrb, name)); + mrb_undef_method_id(mrb, c, mrb_intern_cstr(mrb, name)); } MRB_API void @@ -1988,7 +1988,7 @@ mrb_mod_undef(mrb_state *mrb, mrb_value mod) mrb_get_args(mrb, "*", &argv, &argc); while (argc--) { - undef_method(mrb, c, to_sym(mrb, *argv)); + mrb_undef_method_id(mrb, c, to_sym(mrb, *argv)); argv++; } return mrb_nil_value(); diff --git a/src/codedump.c b/src/codedump.c index d79a65a70..22cbc59eb 100644 --- a/src/codedump.c +++ b/src/codedump.c @@ -6,451 +6,503 @@ #include #ifndef MRB_DISABLE_STDIO -static int -print_r(mrb_state *mrb, mrb_irep *irep, size_t n, int pre) +static void +print_r(mrb_state *mrb, mrb_irep *irep, size_t n) { size_t i; - if (n == 0) return 0; + if (n == 0) return; for (i=0; i+1nlocals; i++) { if (irep->lv[i].r == n) { mrb_sym sym = irep->lv[i].name; - if (pre) printf(" "); - printf("R%d:%s", (int)n, mrb_sym2name(mrb, sym)); - return 1; + printf(" R%d:%s", (int)n, mrb_sym2name(mrb, sym)); } } - return 0; } -#define RA 1 -#define RB 2 -#define RAB 3 - static void -print_lv(mrb_state *mrb, mrb_irep *irep, mrb_code c, int r) +print_lv_a(mrb_state *mrb, mrb_irep *irep, uint16_t a) { - int pre = 0; - - if (!irep->lv - || ((!(r & RA) || GETARG_A(c) >= irep->nlocals) - && (!(r & RB) || GETARG_B(c) >= irep->nlocals))) { + if (!irep->lv || a >= irep->nlocals || a == 0) { printf("\n"); return; } - printf("\t; "); - if (r & RA) { - pre = print_r(mrb, irep, GETARG_A(c), 0); - } - if (r & RB) { - print_r(mrb, irep, GETARG_B(c), pre); + printf("\t;"); + print_r(mrb, irep, a); + printf("\n"); +} + +static void +print_lv_ab(mrb_state *mrb, mrb_irep *irep, uint16_t a, uint16_t b) +{ + if (!irep->lv || (a >= irep->nlocals && b >= irep->nlocals) || a+b == 0) { + printf("\n"); + return; } + printf("\t;"); + if (a > 0) print_r(mrb, irep, a); + if (b > 0) print_r(mrb, irep, b); printf("\n"); } #endif +static void +print_header(mrb_irep *irep, int i) +{ + int32_t line; + + line = mrb_debug_get_line(irep, i); + if (line < 0) { + printf(" "); + } + else { + printf("%5d ", line); + } + + printf("%03d ", i); +} + +#define CASE(insn,ops) case insn: FETCH_ ## ops (); L_ ## insn + static void codedump(mrb_state *mrb, mrb_irep *irep) { #ifndef MRB_DISABLE_STDIO - int i; int ai; - mrb_code c; + mrb_code *pc, *pcend; + mrb_code ins; const char *file = NULL, *next_file; - int32_t line; if (!irep) return; printf("irep %p nregs=%d nlocals=%d pools=%d syms=%d reps=%d\n", (void*)irep, irep->nregs, irep->nlocals, (int)irep->plen, (int)irep->slen, (int)irep->rlen); - for (i = 0; i < (int)irep->ilen; i++) { + pc = irep->iseq; + pcend = pc + irep->ilen; + while (pc < pcend) { + int i; + uint32_t a; + uint16_t b; + uint8_t c; + ai = mrb_gc_arena_save(mrb); + i = pc - irep->iseq; next_file = mrb_debug_get_filename(irep, i); if (next_file && file != next_file) { printf("file: %s\n", next_file); file = next_file; } - line = mrb_debug_get_line(irep, i); - if (line < 0) { - printf(" "); - } - else { - printf("%5d ", line); - } - - printf("%03d ", i); - c = irep->iseq[i]; - switch (GET_OPCODE(c)) { - case OP_NOP: + print_header(irep, i); + ins = READ_B(); + switch (ins) { + CASE(OP_NOP, Z): printf("OP_NOP\n"); break; - case OP_MOVE: - printf("OP_MOVE\tR%d\tR%d\t", GETARG_A(c), GETARG_B(c)); - print_lv(mrb, irep, c, RAB); + CASE(OP_MOVE, BB): + printf("OP_MOVE\tR%d\tR%d\t", a, b); + print_lv_ab(mrb, irep, a, b); break; - case OP_LOADL: + CASE(OP_LOADL, BB): { - mrb_value v = irep->pool[GETARG_Bx(c)]; + mrb_value v = irep->pool[b]; mrb_value s = mrb_inspect(mrb, v); - printf("OP_LOADL\tR%d\tL(%d)\t; %s", GETARG_A(c), GETARG_Bx(c), RSTRING_PTR(s)); + printf("OP_LOADL\tR%d\tL(%d)\t; %s", a, b, RSTRING_PTR(s)); } - print_lv(mrb, irep, c, RA); - break; - case OP_LOADI: - printf("OP_LOADI\tR%d\t%d\t", GETARG_A(c), GETARG_sBx(c)); - print_lv(mrb, irep, c, RA); - break; - case OP_LOADSYM: - printf("OP_LOADSYM\tR%d\t:%s", GETARG_A(c), - mrb_sym2name(mrb, irep->syms[GETARG_Bx(c)])); - print_lv(mrb, irep, c, RA); - break; - case OP_LOADNIL: - printf("OP_LOADNIL\tR%d\t\t", GETARG_A(c)); - print_lv(mrb, irep, c, RA); - break; - case OP_LOADSELF: - printf("OP_LOADSELF\tR%d\t\t", GETARG_A(c)); - print_lv(mrb, irep, c, RA); - break; - case OP_LOADT: - printf("OP_LOADT\tR%d\t\t", GETARG_A(c)); - print_lv(mrb, irep, c, RA); - break; - case OP_LOADF: - printf("OP_LOADF\tR%d\t\t", GETARG_A(c)); - print_lv(mrb, irep, c, RA); - break; - case OP_GETGLOBAL: - printf("OP_GETGLOBAL\tR%d\t:%s", GETARG_A(c), - mrb_sym2name(mrb, irep->syms[GETARG_Bx(c)])); - print_lv(mrb, irep, c, RA); - break; - case OP_SETGLOBAL: - printf("OP_SETGLOBAL\t:%s\tR%d\t", - mrb_sym2name(mrb, irep->syms[GETARG_Bx(c)]), - GETARG_A(c)); - print_lv(mrb, irep, c, RA); - break; - case OP_GETCONST: - printf("OP_GETCONST\tR%d\t:%s", GETARG_A(c), - mrb_sym2name(mrb, irep->syms[GETARG_Bx(c)])); - print_lv(mrb, irep, c, RA); - break; - case OP_SETCONST: - printf("OP_SETCONST\t:%s\tR%d\t", - mrb_sym2name(mrb, irep->syms[GETARG_Bx(c)]), - GETARG_A(c)); - print_lv(mrb, irep, c, RA); - break; - case OP_GETMCNST: - printf("OP_GETMCNST\tR%d\tR%d::%s", GETARG_A(c), GETARG_A(c), - mrb_sym2name(mrb, irep->syms[GETARG_Bx(c)])); - print_lv(mrb, irep, c, RAB); - break; - case OP_SETMCNST: - printf("OP_SETMCNST\tR%d::%s\tR%d", GETARG_A(c)+1, - mrb_sym2name(mrb, irep->syms[GETARG_Bx(c)]), - GETARG_A(c)); - print_lv(mrb, irep, c, RA); - break; - case OP_GETIV: - printf("OP_GETIV\tR%d\t%s", GETARG_A(c), - mrb_sym2name(mrb, irep->syms[GETARG_Bx(c)])); - print_lv(mrb, irep, c, RA); - break; - case OP_SETIV: - printf("OP_SETIV\t%s\tR%d", - mrb_sym2name(mrb, irep->syms[GETARG_Bx(c)]), - GETARG_A(c)); - print_lv(mrb, irep, c, RA); - break; - case OP_GETUPVAR: - printf("OP_GETUPVAR\tR%d\t%d\t%d", - GETARG_A(c), GETARG_B(c), GETARG_C(c)); - print_lv(mrb, irep, c, RA); - break; - case OP_SETUPVAR: - printf("OP_SETUPVAR\tR%d\t%d\t%d", - GETARG_A(c), GETARG_B(c), GETARG_C(c)); - print_lv(mrb, irep, c, RA); - break; - case OP_GETCV: - printf("OP_GETCV\tR%d\t%s", GETARG_A(c), - mrb_sym2name(mrb, irep->syms[GETARG_Bx(c)])); - print_lv(mrb, irep, c, RA); - break; - case OP_SETCV: - printf("OP_SETCV\t%s\tR%d", - mrb_sym2name(mrb, irep->syms[GETARG_Bx(c)]), - GETARG_A(c)); - print_lv(mrb, irep, c, RA); - break; - case OP_JMP: - printf("OP_JMP\t%03d (%d)\n", i+GETARG_sBx(c), GETARG_sBx(c)); - break; - case OP_JMPIF: - printf("OP_JMPIF\tR%d\t%03d (%d)\n", GETARG_A(c), i+GETARG_sBx(c), GETARG_sBx(c)); - break; - case OP_JMPNOT: - printf("OP_JMPNOT\tR%d\t%03d (%d)\n", GETARG_A(c), i+GETARG_sBx(c), GETARG_sBx(c)); - break; - case OP_SEND: - printf("OP_SEND\tR%d\t:%s\t%d\n", GETARG_A(c), - mrb_sym2name(mrb, irep->syms[GETARG_B(c)]), - GETARG_C(c)); - break; - case OP_SENDB: - printf("OP_SENDB\tR%d\t:%s\t%d\n", GETARG_A(c), - mrb_sym2name(mrb, irep->syms[GETARG_B(c)]), - GETARG_C(c)); - break; - case OP_CALL: - printf("OP_CALL\tR%d\n", GETARG_A(c)); - break; - case OP_TAILCALL: - printf("OP_TAILCALL\tR%d\t:%s\t%d\n", GETARG_A(c), - mrb_sym2name(mrb, irep->syms[GETARG_B(c)]), - GETARG_C(c)); - break; - case OP_SUPER: - printf("OP_SUPER\tR%d\t%d\n", GETARG_A(c), - GETARG_C(c)); - break; - case OP_ARGARY: - printf("OP_ARGARY\tR%d\t%d:%d:%d:%d", GETARG_A(c), - (GETARG_Bx(c)>>10)&0x3f, - (GETARG_Bx(c)>>9)&0x1, - (GETARG_Bx(c)>>4)&0x1f, - (GETARG_Bx(c)>>0)&0xf); - print_lv(mrb, irep, c, RA); + print_lv_a(mrb, irep, a); + break; + CASE(OP_LOADI, BB): + printf("OP_LOADI\tR%d\t%d\t", a, b); + print_lv_a(mrb, irep, a); + break; + CASE(OP_LOADINEG, BB): + printf("OP_LOADI\tR%d\t-%d\t", a, b); + print_lv_a(mrb, irep, a); + break; + CASE(OP_LOADI__1, B): + printf("OP_LOADI__1\tR%d\t\t", a); + print_lv_a(mrb, irep, a); + break; + CASE(OP_LOADI_0, B): goto L_LOADI; + CASE(OP_LOADI_1, B): goto L_LOADI; + CASE(OP_LOADI_2, B): goto L_LOADI; + CASE(OP_LOADI_3, B): goto L_LOADI; + CASE(OP_LOADI_4, B): goto L_LOADI; + CASE(OP_LOADI_5, B): goto L_LOADI; + CASE(OP_LOADI_6, B): goto L_LOADI; + CASE(OP_LOADI_7, B): + L_LOADI: + printf("OP_LOADI_%d\tR%d\t\t", ins-(int)OP_LOADI_0, a); + print_lv_a(mrb, irep, a); break; - - case OP_ENTER: + CASE(OP_LOADSYM, BB): + printf("OP_LOADSYM\tR%d\t:%s\t", a, mrb_sym2name(mrb, irep->syms[b])); + print_lv_a(mrb, irep, a); + break; + CASE(OP_LOADNIL, B): + printf("OP_LOADNIL\tR%d\t\t", a); + print_lv_a(mrb, irep, a); + break; + CASE(OP_LOADSELF, B): + printf("OP_LOADSELF\tR%d\t\t", a); + print_lv_a(mrb, irep, a); + break; + CASE(OP_LOADT, B): + printf("OP_LOADT\tR%d\t\t", a); + print_lv_a(mrb, irep, a); + break; + CASE(OP_LOADF, B): + printf("OP_LOADF\tR%d\t\t", a); + print_lv_a(mrb, irep, a); + break; + CASE(OP_GETGV, BB): + printf("OP_GETGV\tR%d\t:%s", a, mrb_sym2name(mrb, irep->syms[b])); + print_lv_a(mrb, irep, a); + break; + CASE(OP_SETGV, BB): + printf("OP_SETGV\t:%s\tR%d", mrb_sym2name(mrb, irep->syms[b]), a); + print_lv_a(mrb, irep, a); + break; + CASE(OP_GETSV, BB): + printf("OP_GETSV\tR%d\t:%s", a, mrb_sym2name(mrb, irep->syms[b])); + print_lv_a(mrb, irep, a); + break; + CASE(OP_SETSV, BB): + printf("OP_SETSV\t:%s\tR%d", mrb_sym2name(mrb, irep->syms[b]), a); + print_lv_a(mrb, irep, a); + break; + CASE(OP_GETCONST, BB): + printf("OP_GETCONST\tR%d\t:%s", a, mrb_sym2name(mrb, irep->syms[b])); + print_lv_a(mrb, irep, a); + break; + CASE(OP_SETCONST, BB): + printf("OP_SETCONST\t:%s\tR%d", mrb_sym2name(mrb, irep->syms[b]), a); + print_lv_a(mrb, irep, a); + break; + CASE(OP_GETMCNST, BB): + printf("OP_GETMCNST\tR%d\tR%d::%s", a, a, mrb_sym2name(mrb, irep->syms[b])); + print_lv_a(mrb, irep, a); + break; + CASE(OP_SETMCNST, BB): + printf("OP_SETMCNST\tR%d::%s\tR%d", a+1, mrb_sym2name(mrb, irep->syms[b]), a); + print_lv_a(mrb, irep, a); + break; + CASE(OP_GETIV, BB): + printf("OP_GETIV\tR%d\t%s", a, mrb_sym2name(mrb, irep->syms[b])); + print_lv_a(mrb, irep, a); + break; + CASE(OP_SETIV, BB): + printf("OP_SETIV\t%s\tR%d", mrb_sym2name(mrb, irep->syms[b]), a); + print_lv_a(mrb, irep, a); + break; + CASE(OP_GETUPVAR, BBB): + printf("OP_GETUPVAR\tR%d\t%d\t%d", a, b, c); + print_lv_a(mrb, irep, a); + break; + CASE(OP_SETUPVAR, BBB): + printf("OP_SETUPVAR\tR%d\t%d\t%d", a, b, c); + print_lv_a(mrb, irep, a); + break; + CASE(OP_GETCV, BB): + printf("OP_GETCV\tR%d\t%s", a, mrb_sym2name(mrb, irep->syms[b])); + print_lv_a(mrb, irep, a); + break; + CASE(OP_SETCV, BB): + printf("OP_SETCV\t%s\tR%d", mrb_sym2name(mrb, irep->syms[b]), a); + print_lv_a(mrb, irep, a); + break; + CASE(OP_JMP, S): + printf("OP_JMP\t\t%03d\n", a); + break; + CASE(OP_JMPIF, BS): + printf("OP_JMPIF\tR%d\t%03d\t", a, b); + print_lv_a(mrb, irep, a); + break; + CASE(OP_JMPNOT, BS): + printf("OP_JMPNOT\tR%d\t%03d\t", a, b); + print_lv_a(mrb, irep, a); + break; + CASE(OP_JMPNIL, BS): + printf("OP_JMPNIL\tR%d\t%03d\t", a, b); + print_lv_a(mrb, irep, a); + break; + CASE(OP_SENDV, BB): + printf("OP_SENDV\tR%d\t:%s\n", a, mrb_sym2name(mrb, irep->syms[b])); + break; + CASE(OP_SENDVB, BB): + printf("OP_SENDVB\tR%d\t:%s\n", a, mrb_sym2name(mrb, irep->syms[b])); + break; + CASE(OP_SEND, BBB): + printf("OP_SEND\tR%d\t:%s\t%d\n", a, mrb_sym2name(mrb, irep->syms[b]), c); + break; + CASE(OP_SENDB, BBB): + printf("OP_SENDB\tR%d\t:%s\t%d\n", a, mrb_sym2name(mrb, irep->syms[b]), c); + break; + CASE(OP_CALL, Z): + printf("OP_CALL\n"); + break; + CASE(OP_SUPER, BB): + printf("OP_SUPER\tR%d\t%d\n", a, b); + break; + CASE(OP_ARGARY, BS): + printf("OP_ARGARY\tR%d\t%d:%d:%d:%d", a, + (b>>10)&0x3f, + (b>>9)&0x1, + (b>>4)&0x1f, + (b>>0)&0xf); + print_lv_a(mrb, irep, a); + break; + CASE(OP_ENTER, W): printf("OP_ENTER\t%d:%d:%d:%d:%d:%d:%d\n", - (GETARG_Ax(c)>>18)&0x1f, - (GETARG_Ax(c)>>13)&0x1f, - (GETARG_Ax(c)>>12)&0x1, - (GETARG_Ax(c)>>7)&0x1f, - (GETARG_Ax(c)>>2)&0x1f, - (GETARG_Ax(c)>>1)&0x1, - GETARG_Ax(c) & 0x1); - break; - case OP_RETURN: - printf("OP_RETURN\tR%d", GETARG_A(c)); - switch (GETARG_B(c)) { - case OP_R_NORMAL: - printf("\tnormal\t"); break; - case OP_R_RETURN: - printf("\treturn\t"); break; - case OP_R_BREAK: - printf("\tbreak\t"); break; - default: - printf("\tbroken\t"); break; - } - print_lv(mrb, irep, c, RA); + (a>>18)&0x1f, + (a>>13)&0x1f, + (a>>12)&0x1, + (a>>7)&0x1f, + (a>>2)&0x1f, + (a>>1)&0x1, + a & 0x1); break; - case OP_BLKPUSH: - printf("OP_BLKPUSH\tR%d\t%d:%d:%d:%d", GETARG_A(c), - (GETARG_Bx(c)>>10)&0x3f, - (GETARG_Bx(c)>>9)&0x1, - (GETARG_Bx(c)>>4)&0x1f, - (GETARG_Bx(c)>>0)&0xf); - print_lv(mrb, irep, c, RA); + CASE(OP_KARG, BB): + printf("OP_KARG\tR(%d)\tK(%d)\n", a, b); break; - - case OP_LAMBDA: - printf("OP_LAMBDA\tR%d\tI(%+d)\t", GETARG_A(c), GETARG_b(c)+1); - switch (GETARG_c(c)) { - case OP_L_METHOD: - printf("method"); break; - case OP_L_BLOCK: - printf("block"); break; - case OP_L_LAMBDA: - printf("lambda"); break; - } - print_lv(mrb, irep, c, RA); + CASE(OP_KARG2, BB): + printf("OP_KARG2\tR(%d)\tK(%d)\n", a, b); break; - case OP_RANGE: - printf("OP_RANGE\tR%d\tR%d\t%d", GETARG_A(c), GETARG_B(c), GETARG_C(c)); - print_lv(mrb, irep, c, RAB); + CASE(OP_KDICT, B): + printf("OP_KDICt\tR(%d)\n", a); break; - case OP_METHOD: - printf("OP_METHOD\tR%d\t:%s", GETARG_A(c), - mrb_sym2name(mrb, irep->syms[GETARG_B(c)])); - print_lv(mrb, irep, c, RA); + CASE(OP_RETURN, B): + printf("OP_RETURN\tR%d", a); + print_lv_a(mrb, irep, a); break; - - case OP_ADD: - printf("OP_ADD\tR%d\t:%s\t%d\n", GETARG_A(c), - mrb_sym2name(mrb, irep->syms[GETARG_B(c)]), - GETARG_C(c)); - break; - case OP_ADDI: - printf("OP_ADDI\tR%d\t:%s\t%d\n", GETARG_A(c), - mrb_sym2name(mrb, irep->syms[GETARG_B(c)]), - GETARG_C(c)); - break; - case OP_SUB: - printf("OP_SUB\tR%d\t:%s\t%d\n", GETARG_A(c), - mrb_sym2name(mrb, irep->syms[GETARG_B(c)]), - GETARG_C(c)); - break; - case OP_SUBI: - printf("OP_SUBI\tR%d\t:%s\t%d\n", GETARG_A(c), - mrb_sym2name(mrb, irep->syms[GETARG_B(c)]), - GETARG_C(c)); - break; - case OP_MUL: - printf("OP_MUL\tR%d\t:%s\t%d\n", GETARG_A(c), - mrb_sym2name(mrb, irep->syms[GETARG_B(c)]), - GETARG_C(c)); - break; - case OP_DIV: - printf("OP_DIV\tR%d\t:%s\t%d\n", GETARG_A(c), - mrb_sym2name(mrb, irep->syms[GETARG_B(c)]), - GETARG_C(c)); - break; - case OP_LT: - printf("OP_LT\t\tR%d\t:%s\t%d\n", GETARG_A(c), - mrb_sym2name(mrb, irep->syms[GETARG_B(c)]), - GETARG_C(c)); - break; - case OP_LE: - printf("OP_LE\t\tR%d\t:%s\t%d\n", GETARG_A(c), - mrb_sym2name(mrb, irep->syms[GETARG_B(c)]), - GETARG_C(c)); - break; - case OP_GT: - printf("OP_GT\t\tR%d\t:%s\t%d\n", GETARG_A(c), - mrb_sym2name(mrb, irep->syms[GETARG_B(c)]), - GETARG_C(c)); - break; - case OP_GE: - printf("OP_GE\t\tR%d\t:%s\t%d\n", GETARG_A(c), - mrb_sym2name(mrb, irep->syms[GETARG_B(c)]), - GETARG_C(c)); - break; - case OP_EQ: - printf("OP_EQ\t\tR%d\t:%s\t%d\n", GETARG_A(c), - mrb_sym2name(mrb, irep->syms[GETARG_B(c)]), - GETARG_C(c)); + CASE(OP_RETURN_BLK, B): + printf("OP_RETURN_BLK\tR%d", a); + print_lv_a(mrb, irep, a); break; - - case OP_STOP: - printf("OP_STOP\n"); + CASE(OP_BREAK, B): + printf("OP_BREAK\tR%d", a); + print_lv_a(mrb, irep, a); break; - - case OP_ARRAY: - printf("OP_ARRAY\tR%d\tR%d\t%d", GETARG_A(c), GETARG_B(c), GETARG_C(c)); - print_lv(mrb, irep, c, RAB); + CASE(OP_BLKPUSH, BS): + printf("OP_BLKPUSH\tR%d\t%d:%d:%d:%d", a, + (b>>10)&0x3f, + (b>>9)&0x1, + (b>>4)&0x1f, + (b>>0)&0xf); + print_lv_a(mrb, irep, a); + break; + CASE(OP_LAMBDA, BB): + printf("OP_LAMBDA\tR%d\tI(%d:%p)\n", a, b, irep->reps[b]); + break; + CASE(OP_BLOCK, BB): + printf("OP_BLOCK\tR%d\tI(%d:%p)\n", a, b, irep->reps[b]); + break; + CASE(OP_METHOD, BB): + printf("OP_METHOD\tR%d\tI(%d:%p)\n", a, b, irep->reps[b]); + break; + CASE(OP_RANGE_INC, B): + printf("OP_RANGE_INC\tR%d\n", a); + break; + CASE(OP_RANGE_EXC, B): + printf("OP_RANGE_EXC\tR%d\n", a); + break; + CASE(OP_DEF, BB): + printf("OP_DEF\tR%d\t:%s\n", a, mrb_sym2name(mrb, irep->syms[b])); + break; + CASE(OP_UNDEF, B): + printf("OP_UNDEF\t:%s\n", mrb_sym2name(mrb, irep->syms[a])); + break; + CASE(OP_ALIAS, BB): + printf("OP_ALIAS\t:%s\t%s\n", mrb_sym2name(mrb, irep->syms[a]), mrb_sym2name(mrb, irep->syms[b])); + break; + CASE(OP_ADD, BB): + printf("OP_ADD\tR%d\t:%s\t\n", a, mrb_sym2name(mrb, irep->syms[b])); + break; + CASE(OP_ADDI, BBB): + printf("OP_ADDI\tR%d\t:%s\t%d\n", a, mrb_sym2name(mrb, irep->syms[b]), c); + break; + CASE(OP_SUB, BB): + printf("OP_SUB\tR%d\t:%s\t\n", a, mrb_sym2name(mrb, irep->syms[b])); + break; + CASE(OP_SUBI, BBB): + printf("OP_SUBI\tR%d\t:%s\t%d\n", a, mrb_sym2name(mrb, irep->syms[b]), c); + break; + CASE(OP_MUL, BB): + printf("OP_MUL\tR%d\t:%s\t\n", a, mrb_sym2name(mrb, irep->syms[b])); + break; + CASE(OP_DIV, BB): + printf("OP_DIV\tR%d\t:%s\t\n", a, mrb_sym2name(mrb, irep->syms[b])); + break; + CASE(OP_LT, BB): + printf("OP_LT\t\tR%d\t:%s\t\n", a, mrb_sym2name(mrb, irep->syms[b])); + break; + CASE(OP_LE, BB): + printf("OP_LE\t\tR%d\t:%s\t\n", a, mrb_sym2name(mrb, irep->syms[b])); + break; + CASE(OP_GT, BB): + printf("OP_GT\t\tR%d\t:%s\t\n", a, mrb_sym2name(mrb, irep->syms[b])); + break; + CASE(OP_GE, BB): + printf("OP_GE\t\tR%d\t:%s\t\n", a, mrb_sym2name(mrb, irep->syms[b])); + break; + CASE(OP_EQ, BB): + printf("OP_EQ\t\tR%d\t:%s\t\n", a, mrb_sym2name(mrb, irep->syms[b])); break; - case OP_ARYCAT: - printf("OP_ARYCAT\tR%d\tR%d\t", GETARG_A(c), GETARG_B(c)); - print_lv(mrb, irep, c, RAB); + CASE(OP_ARRAY, BB): + printf("OP_ARRAY\tR%d\t%d\t", a, b); + print_lv_a(mrb, irep, a); break; - case OP_ARYPUSH: - printf("OP_ARYPUSH\tR%d\tR%d\t", GETARG_A(c), GETARG_B(c)); - print_lv(mrb, irep, c, RAB); + CASE(OP_ARRAY2, BBB): + printf("OP_ARRAY\tR%d\tR%d\t%d\t", a, b, c); + print_lv_ab(mrb, irep, a, b); break; - case OP_AREF: - printf("OP_AREF\tR%d\tR%d\t%d", GETARG_A(c), GETARG_B(c), GETARG_C(c)); - print_lv(mrb, irep, c, RAB); + CASE(OP_ARYCAT, B): + printf("OP_ARYCAT\tR%d\t", a); + print_lv_a(mrb, irep, a); break; - case OP_APOST: - printf("OP_APOST\tR%d\t%d\t%d", GETARG_A(c), GETARG_B(c), GETARG_C(c)); - print_lv(mrb, irep, c, RA); + CASE(OP_ARYPUSH, B): + printf("OP_ARYPUSH\tR%d\t", a); + print_lv_a(mrb, irep, a); break; - case OP_STRING: + CASE(OP_ARYDUP, B): + printf("OP_ARYDUP\tR%d\t", a); + print_lv_a(mrb, irep, a); + break; + CASE(OP_AREF, BBB): + printf("OP_AREF\tR%d\tR%d\t%d", a, b, c); + print_lv_ab(mrb, irep, a, b); + break; + CASE(OP_ASET, BBB): + printf("OP_ASET\tR%d\tR%d\t%d", a, b, c); + print_lv_ab(mrb, irep, a, b); + break; + CASE(OP_APOST, BBB): + printf("OP_APOST\tR%d\t%d\t%d", a, b, c); + print_lv_a(mrb, irep, a); + break; + CASE(OP_INTERN, B): + printf("OP_INTERN\tR%d", a); + print_lv_a(mrb, irep, a); + break; + CASE(OP_STRING, BB): { - mrb_value v = irep->pool[GETARG_Bx(c)]; + mrb_value v = irep->pool[b]; mrb_value s = mrb_str_dump(mrb, mrb_str_new(mrb, RSTRING_PTR(v), RSTRING_LEN(v))); - printf("OP_STRING\tR%d\tL(%d)\t; %s", GETARG_A(c), GETARG_Bx(c), RSTRING_PTR(s)); + printf("OP_STRING\tR%d\tL(%d)\t; %s", a, b, RSTRING_PTR(s)); } - print_lv(mrb, irep, c, RA); + print_lv_a(mrb, irep, a); + break; + CASE(OP_STRCAT, B): + printf("OP_STRCAT\tR%d\t", a); + print_lv_a(mrb, irep, a); break; - case OP_STRCAT: - printf("OP_STRCAT\tR%d\tR%d\t", GETARG_A(c), GETARG_B(c)); - print_lv(mrb, irep, c, RAB); + CASE(OP_HASH, BB): + printf("OP_HASH\tR%d\t%d\t", a, b); + print_lv_a(mrb, irep, a); break; - case OP_HASH: - printf("OP_HASH\tR%d\tR%d\t%d", GETARG_A(c), GETARG_B(c), GETARG_C(c)); - print_lv(mrb, irep, c, RAB); + CASE(OP_HASHADD, BB): + printf("OP_HASHADD\tR%d\t%d", a, b); + print_lv_a(mrb, irep, a); break; - case OP_OCLASS: - printf("OP_OCLASS\tR%d\t\t", GETARG_A(c)); - print_lv(mrb, irep, c, RA); + CASE(OP_OCLASS, B): + printf("OP_OCLASS\tR%d\t\t", a); + print_lv_a(mrb, irep, a); break; - case OP_CLASS: - printf("OP_CLASS\tR%d\t:%s", GETARG_A(c), - mrb_sym2name(mrb, irep->syms[GETARG_B(c)])); - print_lv(mrb, irep, c, RA); + CASE(OP_CLASS, BB): + printf("OP_CLASS\tR%d\t:%s", a, mrb_sym2name(mrb, irep->syms[b])); + print_lv_a(mrb, irep, a); break; - case OP_MODULE: - printf("OP_MODULE\tR%d\t:%s", GETARG_A(c), - mrb_sym2name(mrb, irep->syms[GETARG_B(c)])); - print_lv(mrb, irep, c, RA); + CASE(OP_MODULE, BB): + printf("OP_MODULE\tR%d\t:%s", a, mrb_sym2name(mrb, irep->syms[b])); + print_lv_a(mrb, irep, a); break; - case OP_EXEC: - printf("OP_EXEC\tR%d\tI(%+d)", GETARG_A(c), GETARG_Bx(c)+1); - print_lv(mrb, irep, c, RA); + CASE(OP_EXEC, BB): + printf("OP_EXEC\tR%d\tI(%d:%p)", a, b, irep->reps[b]); + print_lv_a(mrb, irep, a); break; - case OP_SCLASS: - printf("OP_SCLASS\tR%d\tR%d\t", GETARG_A(c), GETARG_B(c)); - print_lv(mrb, irep, c, RAB); + CASE(OP_SCLASS, B): + printf("OP_SCLASS\tR%d\t", a); + print_lv_a(mrb, irep, a); break; - case OP_TCLASS: - printf("OP_TCLASS\tR%d\t\t", GETARG_A(c)); - print_lv(mrb, irep, c, RA); + CASE(OP_TCLASS, B): + printf("OP_TCLASS\tR%d\t\t", a); + print_lv_a(mrb, irep, a); break; - case OP_ERR: + CASE(OP_ERR, B): { - mrb_value v = irep->pool[GETARG_Bx(c)]; + mrb_value v = irep->pool[a]; mrb_value s = mrb_str_dump(mrb, mrb_str_new(mrb, RSTRING_PTR(v), RSTRING_LEN(v))); printf("OP_ERR\t%s\n", RSTRING_PTR(s)); } break; - case OP_EPUSH: - printf("OP_EPUSH\t:I(%+d)\n", GETARG_Bx(c)+1); + CASE(OP_EPUSH, B): + printf("OP_EPUSH\t\t:I(%d:%p)\n", a, irep->reps[a]); break; - case OP_ONERR: - printf("OP_ONERR\t%03d\n", i+GETARG_sBx(c)); + CASE(OP_ONERR, S): + printf("OP_ONERR\t%03d\n", a); break; - case OP_RESCUE: - { - int a = GETARG_A(c); - int b = GETARG_B(c); - int cnt = GETARG_C(c); - - if (b == 0) { - printf("OP_RESCUE\tR%d\t\t%s", a, cnt ? "cont" : ""); - print_lv(mrb, irep, c, RA); - break; - } - else { - printf("OP_RESCUE\tR%d\tR%d\t%s", a, b, cnt ? "cont" : ""); - print_lv(mrb, irep, c, RAB); - break; - } - } + CASE(OP_EXCEPT, B): + printf("OP_EXCEPT\tR%d\t\t", a); + print_lv_a(mrb, irep, a); break; - case OP_RAISE: - printf("OP_RAISE\tR%d\t\t", GETARG_A(c)); - print_lv(mrb, irep, c, RA); + CASE(OP_RESCUE, BB): + printf("OP_RESCUE\tR%d\tR%d", a, b); + print_lv_ab(mrb, irep, a, b); break; - case OP_POPERR: - printf("OP_POPERR\t%d\t\t\n", GETARG_A(c)); + CASE(OP_RAISE, B): + printf("OP_RAISE\tR%d\t\t", a); + print_lv_a(mrb, irep, a); break; - case OP_EPOP: - printf("OP_EPOP\t%d\n", GETARG_A(c)); + CASE(OP_POPERR, B): + printf("OP_POPERR\t%d\t\t\n", a); + break; + CASE(OP_EPOP, B): + printf("OP_EPOP\t%d\n", a); break; + CASE(OP_DEBUG, BBB): + printf("OP_DEBUG\t%d\t%d\t%d\n", a, b, c); + break; + + CASE(OP_STOP, Z): + printf("OP_STOP\n"); + break; + + CASE(OP_EXT1, Z): + ins = READ_B(); + printf("OP_EXT1\n"); + print_header(irep, pc-irep->iseq-2); + switch (ins) { +#define OPCODE(i,x) case OP_ ## i: FETCH_ ## x ## _1 (); goto L_OP_ ## i; +#include "mruby/ops.h" +#undef OPCODE + } + break; + CASE(OP_EXT2, Z): + ins = READ_B(); + printf("OP_EXT2\n"); + print_header(irep, pc-irep->iseq-2); + switch (ins) { +#define OPCODE(i,x) case OP_ ## i: FETCH_ ## x ## _2 (); goto L_OP_ ## i; +#include "mruby/ops.h" +#undef OPCODE + } + break; + CASE(OP_EXT3, Z): + ins = READ_B(); + printf("OP_EXT3\n"); + print_header(irep, pc-irep->iseq-2); + switch (ins) { +#define OPCODE(i,x) case OP_ ## i: FETCH_ ## x ## _3 (); goto L_OP_ ## i; +#include "mruby/ops.h" +#undef OPCODE + } + break; + default: - printf("OP_unknown %d\t%d\t%d\t%d\n", GET_OPCODE(c), - GETARG_A(c), GETARG_B(c), GETARG_C(c)); + printf("OP_unknown (0x%x)\n", ins); break; } mrb_gc_arena_restore(mrb, ai); diff --git a/src/kernel.c b/src/kernel.c index bbe6e8bb7..155868eaa 100644 --- a/src/kernel.c +++ b/src/kernel.c @@ -1266,5 +1266,5 @@ mrb_init_kernel(mrb_state *mrb) mrb_define_method(mrb, krn, "class_defined?", mrb_krn_class_defined, MRB_ARGS_REQ(1)); mrb_include_module(mrb, mrb->object_class, mrb->kernel_module); - mrb_alias_method(mrb, mrb->module_class, mrb_intern_lit(mrb, "dup"), mrb_intern_lit(mrb, "clone")); + mrb_define_alias(mrb, mrb->module_class, "dup", "clone"); /* XXX */ } diff --git a/src/load.c b/src/load.c index ddf3cdfbf..20878aa56 100644 --- a/src/load.c +++ b/src/load.c @@ -79,7 +79,7 @@ read_irep_record_1(mrb_state *mrb, const uint8_t *bin, size_t *len, uint8_t flag if ((flags & FLAG_SRC_MALLOC) == 0 && (flags & FLAG_BYTEORDER_NATIVE)) { irep->iseq = (mrb_code*)src; - src += sizeof(uint32_t) * irep->ilen; + src += sizeof(mrb_code) * irep->ilen; irep->flags |= MRB_ISEQ_NO_FREE; } else { diff --git a/src/proc.c b/src/proc.c index c6e9be433..05b897480 100644 --- a/src/proc.c +++ b/src/proc.c @@ -10,7 +10,7 @@ #include static mrb_code call_iseq[] = { - MKOP_A(OP_CALL, 0), + OP_CALL, }; struct RProc* @@ -223,7 +223,7 @@ mrb_proc_arity(mrb_state *mrb, mrb_value self) { struct RProc *p = mrb_proc_ptr(self); struct mrb_irep *irep; - mrb_code *iseq; + mrb_code *pc; mrb_aspec aspec; int ma, op, ra, pa, arity; @@ -237,13 +237,13 @@ mrb_proc_arity(mrb_state *mrb, mrb_value self) return mrb_fixnum_value(0); } - iseq = irep->iseq; + pc = irep->iseq; /* arity is depend on OP_ENTER */ - if (GET_OPCODE(*iseq) != OP_ENTER) { + if (*pc != OP_ENTER) { return mrb_fixnum_value(0); } - aspec = GETARG_Ax(*iseq); + aspec = PEEK_W(pc+1); ma = MRB_ASPEC_REQ(aspec); op = MRB_ASPEC_OPT(aspec); ra = MRB_ASPEC_REST(aspec); diff --git a/src/vm.c b/src/vm.c index 7a436828a..b50f1ee9f 100644 --- a/src/vm.c +++ b/src/vm.c @@ -333,7 +333,7 @@ ecall(mrb_state *mrb) struct REnv *env; ptrdiff_t cioff; int ai = mrb_gc_arena_save(mrb); - int i = --c->eidx; + uint8_t i = --c->eidx; int nregs; if (i<0) return; @@ -911,18 +911,18 @@ argnum_error(mrb_state *mrb, mrb_int num) #ifndef DIRECT_THREADED -#define INIT_DISPATCH for (;;) { i = BYTECODE_DECODER(*pc); CODE_FETCH_HOOK(mrb, irep, pc, regs); switch (GET_OPCODE(i)) { -#define CASE(op) case op: -#define NEXT pc++; break -#define JUMP break +#define INIT_DISPATCH for (;;) { insn = BYTECODE_DECODER(*pc); pc++; CODE_FETCH_HOOK(mrb, irep, pc, regs); switch (insn) { +#define CASE(insn,ops) case insn: pc++; FETCH_ ## ops ();; L_ ## insn ## _BODY: +#define NEXT break +#define JUMP NEXT #define END_DISPATCH }} #else #define INIT_DISPATCH JUMP; return mrb_nil_value(); -#define CASE(op) L_ ## op: -#define NEXT i=BYTECODE_DECODER(*++pc); CODE_FETCH_HOOK(mrb, irep, pc, regs); goto *optable[GET_OPCODE(i)] -#define JUMP i=BYTECODE_DECODER(*pc); CODE_FETCH_HOOK(mrb, irep, pc, regs); goto *optable[GET_OPCODE(i)] +#define CASE(insn,ops) L_ ## insn: pc++; FETCH_ ## ops (); L_ ## insn ## _BODY: +#define NEXT insn=BYTECODE_DECODER(*pc); CODE_FETCH_HOOK(mrb, irep, pc, regs); goto *optable[insn] +#define JUMP NEXT #define END_DISPATCH @@ -958,6 +958,17 @@ mrb_vm_run(mrb_state *mrb, struct RProc *proc, mrb_value self, unsigned int stac return result; } +static mrb_bool +check_target_class(mrb_state *mrb) +{ + if (!mrb->c->ci->target_class) { + mrb_value exc = mrb_exc_new_str_lit(mrb, E_TYPE_ERROR, "no target class or module"); + mrb_exc_set(mrb, exc); + return FALSE; + } + return TRUE; +} + MRB_API mrb_value mrb_vm_exec(mrb_state *mrb, struct RProc *proc, mrb_code *pc) { @@ -965,33 +976,19 @@ mrb_vm_exec(mrb_state *mrb, struct RProc *proc, mrb_code *pc) mrb_irep *irep = proc->body.irep; mrb_value *pool = irep->pool; mrb_sym *syms = irep->syms; - mrb_code i; + mrb_code insn; int ai = mrb_gc_arena_save(mrb); struct mrb_jmpbuf *prev_jmp = mrb->jmp; struct mrb_jmpbuf c_jmp; + uint32_t a; + uint16_t b; + uint8_t c; #ifdef DIRECT_THREADED static void *optable[] = { - &&L_OP_NOP, &&L_OP_MOVE, - &&L_OP_LOADL, &&L_OP_LOADI, &&L_OP_LOADSYM, &&L_OP_LOADNIL, - &&L_OP_LOADSELF, &&L_OP_LOADT, &&L_OP_LOADF, - &&L_OP_GETGLOBAL, &&L_OP_SETGLOBAL, &&L_OP_GETSPECIAL, &&L_OP_SETSPECIAL, - &&L_OP_GETIV, &&L_OP_SETIV, &&L_OP_GETCV, &&L_OP_SETCV, - &&L_OP_GETCONST, &&L_OP_SETCONST, &&L_OP_GETMCNST, &&L_OP_SETMCNST, - &&L_OP_GETUPVAR, &&L_OP_SETUPVAR, - &&L_OP_JMP, &&L_OP_JMPIF, &&L_OP_JMPNOT, - &&L_OP_ONERR, &&L_OP_RESCUE, &&L_OP_POPERR, &&L_OP_RAISE, &&L_OP_EPUSH, &&L_OP_EPOP, - &&L_OP_SEND, &&L_OP_SENDB, &&L_OP_FSEND, - &&L_OP_CALL, &&L_OP_SUPER, &&L_OP_ARGARY, &&L_OP_ENTER, - &&L_OP_KARG, &&L_OP_KDICT, &&L_OP_RETURN, &&L_OP_TAILCALL, &&L_OP_BLKPUSH, - &&L_OP_ADD, &&L_OP_ADDI, &&L_OP_SUB, &&L_OP_SUBI, &&L_OP_MUL, &&L_OP_DIV, - &&L_OP_EQ, &&L_OP_LT, &&L_OP_LE, &&L_OP_GT, &&L_OP_GE, - &&L_OP_ARRAY, &&L_OP_ARYCAT, &&L_OP_ARYPUSH, &&L_OP_AREF, &&L_OP_ASET, &&L_OP_APOST, - &&L_OP_STRING, &&L_OP_STRCAT, &&L_OP_HASH, - &&L_OP_LAMBDA, &&L_OP_RANGE, &&L_OP_OCLASS, - &&L_OP_CLASS, &&L_OP_MODULE, &&L_OP_EXEC, - &&L_OP_METHOD, &&L_OP_SCLASS, &&L_OP_TCLASS, - &&L_OP_DEBUG, &&L_OP_STOP, &&L_OP_ERR, +#define OPCODE(x,_) &&L_OP_ ## x, +#include "mruby/ops.h" +#undef OPCODE }; #endif @@ -1013,25 +1010,19 @@ RETRY_TRY_BLOCK: #define regs (mrb->c->stack) INIT_DISPATCH { - CASE(OP_NOP) { + CASE(OP_NOP, Z) { /* do nothing */ NEXT; } - CASE(OP_MOVE) { - /* A B R(A) := R(B) */ - int a = GETARG_A(i); - int b = GETARG_B(i); + CASE(OP_MOVE, BB) { regs[a] = regs[b]; NEXT; } - CASE(OP_LOADL) { - /* A Bx R(A) := Pool(Bx) */ - int a = GETARG_A(i); - int bx = GETARG_Bx(i); + CASE(OP_LOADL, BB) { #ifdef MRB_WORD_BOXING - mrb_value val = pool[bx]; + mrb_value val = pool[b]; #ifndef MRB_WITHOUT_FLOAT if (mrb_float_p(val)) { val = mrb_float_value(mrb, mrb_float(val)); @@ -1039,125 +1030,110 @@ RETRY_TRY_BLOCK: #endif regs[a] = val; #else - regs[a] = pool[bx]; + regs[a] = pool[b]; #endif NEXT; } - CASE(OP_LOADI) { - /* A sBx R(A) := sBx */ - int a = GETARG_A(i); - mrb_int bx = GETARG_sBx(i); - SET_INT_VALUE(regs[a], bx); + CASE(OP_LOADI, BB) { + SET_INT_VALUE(regs[a], b); + NEXT; + } + + CASE(OP_LOADINEG, BB) { + SET_INT_VALUE(regs[a], -b); + NEXT; + } + + CASE(OP_LOADI__1,B) goto L_LOADI; + CASE(OP_LOADI_0,B) goto L_LOADI; + CASE(OP_LOADI_1,B) goto L_LOADI; + CASE(OP_LOADI_2,B) goto L_LOADI; + CASE(OP_LOADI_3,B) goto L_LOADI; + CASE(OP_LOADI_4,B) goto L_LOADI; + CASE(OP_LOADI_5,B) goto L_LOADI; + CASE(OP_LOADI_6,B) goto L_LOADI; + CASE(OP_LOADI_7, B) { + L_LOADI: + SET_INT_VALUE(regs[a], (mrb_int)insn - (mrb_int)OP_LOADI_0); + NEXT; + } + + CASE(OP_LOADSYM, BB) { + SET_SYM_VALUE(regs[a], syms[b]); NEXT; } - CASE(OP_LOADSYM) { - /* A Bx R(A) := Syms(Bx) */ - int a = GETARG_A(i); - int bx = GETARG_Bx(i); - SET_SYM_VALUE(regs[a], syms[bx]); + CASE(OP_LOADNIL, B) { + SET_NIL_VALUE(regs[a]); NEXT; } - CASE(OP_LOADSELF) { - /* A R(A) := self */ - int a = GETARG_A(i); + CASE(OP_LOADSELF, B) { regs[a] = regs[0]; NEXT; } - CASE(OP_LOADT) { - /* A R(A) := true */ - int a = GETARG_A(i); + CASE(OP_LOADT, B) { SET_TRUE_VALUE(regs[a]); NEXT; } - CASE(OP_LOADF) { - /* A R(A) := false */ - int a = GETARG_A(i); + CASE(OP_LOADF, B) { SET_FALSE_VALUE(regs[a]); NEXT; } - CASE(OP_GETGLOBAL) { - /* A Bx R(A) := getglobal(Syms(Bx)) */ - int a = GETARG_A(i); - int bx = GETARG_Bx(i); - mrb_value val = mrb_gv_get(mrb, syms[bx]); + CASE(OP_GETGV, BB) { + mrb_value val = mrb_gv_get(mrb, syms[b]); regs[a] = val; NEXT; } - CASE(OP_SETGLOBAL) { - /* A Bx setglobal(Syms(Bx), R(A)) */ - int a = GETARG_A(i); - int bx = GETARG_Bx(i); - mrb_gv_set(mrb, syms[bx], regs[a]); + CASE(OP_SETGV, BB) { + mrb_gv_set(mrb, syms[b], regs[a]); NEXT; } - CASE(OP_GETSPECIAL) { - /* A Bx R(A) := Special[Bx] */ - int a = GETARG_A(i); - int bx = GETARG_Bx(i); - mrb_value val = mrb_vm_special_get(mrb, bx); + CASE(OP_GETSV, BB) { + mrb_value val = mrb_vm_special_get(mrb, b); regs[a] = val; NEXT; } - CASE(OP_SETSPECIAL) { - /* A Bx Special[Bx] := R(A) */ - int a = GETARG_A(i); - int bx = GETARG_Bx(i); - mrb_vm_special_set(mrb, bx, regs[a]); + CASE(OP_SETSV, BB) { + mrb_vm_special_set(mrb, b, regs[a]); NEXT; } - CASE(OP_GETIV) { - /* A Bx R(A) := ivget(Bx) */ - int a = GETARG_A(i); - int bx = GETARG_Bx(i); - mrb_value val = mrb_vm_iv_get(mrb, syms[bx]); + CASE(OP_GETIV, BB) { + mrb_value val = mrb_vm_iv_get(mrb, syms[b]); regs[a] = val; NEXT; } - CASE(OP_SETIV) { - /* A Bx ivset(Syms(Bx),R(A)) */ - int a = GETARG_A(i); - int bx = GETARG_Bx(i); - mrb_vm_iv_set(mrb, syms[bx], regs[a]); + CASE(OP_SETIV, BB) { + mrb_vm_iv_set(mrb, syms[b], regs[a]); NEXT; } - CASE(OP_GETCV) { - /* A Bx R(A) := cvget(Syms(Bx)) */ - int a = GETARG_A(i); - int bx = GETARG_Bx(i); + CASE(OP_GETCV, BB) { mrb_value val; ERR_PC_SET(mrb, pc); - val = mrb_vm_cv_get(mrb, syms[bx]); + val = mrb_vm_cv_get(mrb, syms[b]); ERR_PC_CLR(mrb); regs[a] = val; NEXT; } - CASE(OP_SETCV) { - /* A Bx cvset(Syms(Bx),R(A)) */ - int a = GETARG_A(i); - int bx = GETARG_Bx(i); - mrb_vm_cv_set(mrb, syms[bx], regs[a]); + CASE(OP_SETCV, BB) { + mrb_vm_cv_set(mrb, syms[b], regs[a]); NEXT; } - CASE(OP_GETCONST) { - /* A Bx R(A) := constget(Syms(Bx)) */ + CASE(OP_GETCONST, BB) { mrb_value val; - int a = GETARG_A(i); - int bx = GETARG_Bx(i); - mrb_sym sym = syms[bx]; + mrb_sym sym = syms[b]; ERR_PC_SET(mrb, pc); val = mrb_vm_const_get(mrb, sym); @@ -1166,40 +1142,27 @@ RETRY_TRY_BLOCK: NEXT; } - CASE(OP_SETCONST) { - /* A Bx constset(Syms(Bx),R(A)) */ - int a = GETARG_A(i); - int bx = GETARG_Bx(i); - mrb_vm_const_set(mrb, syms[bx], regs[a]); + CASE(OP_SETCONST, BB) { + mrb_vm_const_set(mrb, syms[b], regs[a]); NEXT; } - CASE(OP_GETMCNST) { - /* A Bx R(A) := R(A)::Syms(Bx) */ + CASE(OP_GETMCNST, BB) { mrb_value val; - int a = GETARG_A(i); - int bx = GETARG_Bx(i); ERR_PC_SET(mrb, pc); - val = mrb_const_get(mrb, regs[a], syms[bx]); + val = mrb_const_get(mrb, regs[a], syms[b]); ERR_PC_CLR(mrb); regs[a] = val; NEXT; } - CASE(OP_SETMCNST) { - /* A Bx R(A+1)::Syms(Bx) := R(A) */ - int a = GETARG_A(i); - int bx = GETARG_Bx(i); - mrb_const_set(mrb, regs[a+1], syms[bx], regs[a]); + CASE(OP_SETMCNST, BB) { + mrb_const_set(mrb, regs[a+1], syms[b], regs[a]); NEXT; } - CASE(OP_GETUPVAR) { - /* A B C R(A) := uvget(B,C) */ - int a = GETARG_A(i); - int b = GETARG_B(i); - int c = GETARG_C(i); + CASE(OP_GETUPVAR, BBB) { mrb_value *regs_a = regs + a; struct REnv *e = uvenv(mrb, c); @@ -1212,12 +1175,7 @@ RETRY_TRY_BLOCK: NEXT; } - CASE(OP_SETUPVAR) { - /* A B C uvset(B,C,R(A)) */ - int a = GETARG_A(i); - int b = GETARG_B(i); - int c = GETARG_C(i); - + CASE(OP_SETUPVAR, BBB) { struct REnv *e = uvenv(mrb, c); if (e) { @@ -1231,110 +1189,86 @@ RETRY_TRY_BLOCK: NEXT; } - CASE(OP_JMP) { - /* sBx pc+=sBx */ - int sbx = GETARG_sBx(i); - pc += sbx; + CASE(OP_JMP, S) { + pc = irep->iseq+a; JUMP; } - - CASE(OP_JMPIF) { - /* A sBx if R(A) pc+=sBx */ - int a = GETARG_A(i); - int sbx = GETARG_sBx(i); + CASE(OP_JMPIF, BS) { if (mrb_test(regs[a])) { - pc += sbx; + pc = irep->iseq+b; JUMP; } NEXT; } - - CASE(OP_JMPNOT) { - /* A sBx if !R(A) pc+=sBx */ - int a = GETARG_A(i); - int sbx = GETARG_sBx(i); + CASE(OP_JMPNOT, BS) { if (!mrb_test(regs[a])) { - pc += sbx; + pc = irep->iseq+b; + JUMP; + } + NEXT; + } + CASE(OP_JMPNIL, BS) { + if (mrb_nil_p(regs[a])) { + pc = irep->iseq+b; JUMP; } NEXT; } - CASE(OP_ONERR) { - /* sBx pc+=sBx on exception */ - int sbx = GETARG_sBx(i); + CASE(OP_ONERR, S) { if (mrb->c->rsize <= mrb->c->ci->ridx) { if (mrb->c->rsize == 0) mrb->c->rsize = RESCUE_STACK_INIT_SIZE; else mrb->c->rsize *= 2; - mrb->c->rescue = (mrb_code **)mrb_realloc(mrb, mrb->c->rescue, sizeof(mrb_code*) * mrb->c->rsize); + mrb->c->rescue = (uint16_t*)mrb_realloc(mrb, mrb->c->rescue, sizeof(uint16_t) * mrb->c->rsize); } - mrb->c->rescue[mrb->c->ci->ridx++] = pc + sbx; + mrb->c->rescue[mrb->c->ci->ridx++] = a; NEXT; } - CASE(OP_RESCUE) { - /* A B R(A) := exc; clear(exc); R(B) := matched (bool) */ - int a = GETARG_A(i); - int b = GETARG_B(i); - int c = GETARG_C(i); - mrb_value exc; - - if (c == 0) { - exc = mrb_obj_value(mrb->exc); - mrb->exc = 0; - } - else { /* continued; exc taken from R(A) */ - exc = regs[a]; - } - if (b != 0) { - mrb_value e = regs[b]; - struct RClass *ec; + CASE(OP_EXCEPT, B) { + mrb_value exc = mrb_obj_value(mrb->exc); + mrb->exc = 0; + regs[a] = exc; + NEXT; + } + CASE(OP_RESCUE, BB) { + mrb_value exc = regs[a]; /* exc on stack */ + mrb_value e = regs[b]; + struct RClass *ec; - switch (mrb_type(e)) { - case MRB_TT_CLASS: - case MRB_TT_MODULE: - break; - default: - { - mrb_value exc; + switch (mrb_type(e)) { + case MRB_TT_CLASS: + case MRB_TT_MODULE: + break; + default: + { + mrb_value exc; - exc = mrb_exc_new_str_lit(mrb, E_TYPE_ERROR, - "class or module required for rescue clause"); - mrb_exc_set(mrb, exc); - goto L_RAISE; - } + exc = mrb_exc_new_str_lit(mrb, E_TYPE_ERROR, + "class or module required for rescue clause"); + mrb_exc_set(mrb, exc); + goto L_RAISE; } - ec = mrb_class_ptr(e); - regs[b] = mrb_bool_value(mrb_obj_is_kind_of(mrb, exc, ec)); - } - if (a != 0 && c == 0) { - regs[a] = exc; } + ec = mrb_class_ptr(e); + regs[b] = mrb_bool_value(mrb_obj_is_kind_of(mrb, exc, ec)); NEXT; } - CASE(OP_POPERR) { - /* A A.times{rescue_pop()} */ - int a = GETARG_A(i); - + CASE(OP_POPERR, B) { mrb->c->ci->ridx -= a; NEXT; } - CASE(OP_RAISE) { - /* A raise(R(A)) */ - int a = GETARG_A(i); - + CASE(OP_RAISE, B) { mrb_exc_set(mrb, regs[a]); goto L_RAISE; } - CASE(OP_EPUSH) { - /* Bx ensure_push(SEQ[Bx]) */ - int bx = GETARG_Bx(i); + CASE(OP_EPUSH, B) { struct RProc *p; - p = mrb_closure_new(mrb, irep->reps[bx]); + p = mrb_closure_new(mrb, irep->reps[a]); /* push ensure_stack */ if (mrb->c->esize <= mrb->c->eidx+1) { if (mrb->c->esize == 0) mrb->c->esize = ENSURE_STACK_INIT_SIZE; @@ -1347,11 +1281,9 @@ RETRY_TRY_BLOCK: NEXT; } - CASE(OP_EPOP) { - /* A A.times{ensure_pop().call} */ - int a = GETARG_A(i); + CASE(OP_EPOP, B) { mrb_callinfo *ci = mrb->c->ci; - int n, epos = ci->epos; + unsigned int n, epos = ci->epos; mrb_value self = regs[0]; struct RClass *target_class = ci->target_class; @@ -1359,9 +1291,8 @@ RETRY_TRY_BLOCK: NEXT; } - if (a > mrb->c->eidx - epos) + if (a > (int)mrb->c->eidx - epos) a = mrb->c->eidx - epos; - pc = pc + 1; for (n=0; nc->ensure[epos+n]; mrb->c->ensure[epos+n] = NULL; @@ -1387,29 +1318,32 @@ RETRY_TRY_BLOCK: JUMP; } - CASE(OP_LOADNIL) { - /* A R(A) := nil */ - int a = GETARG_A(i); + CASE(OP_SENDV, BB) { + c = CALL_MAXARGS; + goto L_SEND; + }; - SET_NIL_VALUE(regs[a]); - NEXT; - } + CASE(OP_SENDVB, BB) { + c = CALL_MAXARGS; + goto L_SENDB; + }; - CASE(OP_SENDB) { - /* A B C R(A) := call(R(A),Syms(B),R(A+1),...,R(A+C),&R(A+C+1))*/ - /* fall through */ + CASE(OP_SEND, BBB) + L_SEND: + { + /* push nil after arguments */ + int bidx = (c == CALL_MAXARGS) ? a+2 : a+c+1; + SET_NIL_VALUE(regs[bidx]); + goto L_SENDB; }; - L_SEND: - CASE(OP_SEND) { - /* A B C R(A) := call(R(A),Syms(B),R(A+1),...,R(A+C)) */ - int a = GETARG_A(i); - int b = GETARG_B(i); - int n = GETARG_C(i); - int argc = (n == CALL_MAXARGS) ? -1 : n; - int bidx = (argc < 0) ? a+2 : a+n+1; + CASE(OP_SENDB, BBB) + L_SENDB: + { + int argc = (c == CALL_MAXARGS) ? -1 : c; + int bidx = (argc < 0) ? a+2 : a+c+1; mrb_method_t m; - struct RClass *c; + struct RClass *cls; mrb_callinfo *ci = mrb->c->ci; mrb_value recv, blk; mrb_sym mid = syms[b]; @@ -1417,26 +1351,20 @@ RETRY_TRY_BLOCK: mrb_assert(bidx < ci->nregs); recv = regs[a]; - if (GET_OPCODE(i) != OP_SENDB) { - SET_NIL_VALUE(regs[bidx]); - blk = regs[bidx]; - } - else { - blk = regs[bidx]; - if (!mrb_nil_p(blk) && mrb_type(blk) != MRB_TT_PROC) { - blk = mrb_convert_type(mrb, blk, MRB_TT_PROC, "Proc", "to_proc"); - /* The stack might have been reallocated during mrb_convert_type(), - see #3622 */ - regs[bidx] = blk; - } + blk = regs[bidx]; + if (!mrb_nil_p(blk) && mrb_type(blk) != MRB_TT_PROC) { + blk = mrb_convert_type(mrb, blk, MRB_TT_PROC, "Proc", "to_proc"); + /* The stack might have been reallocated during mrb_convert_type(), + see #3622 */ + regs[bidx] = blk; } - c = mrb_class(mrb, recv); - m = mrb_method_search_vm(mrb, &c, mid); + cls = mrb_class(mrb, recv); + m = mrb_method_search_vm(mrb, &cls, mid); if (MRB_METHOD_UNDEF_P(m)) { mrb_sym missing = mrb_intern_lit(mrb, "method_missing"); - m = mrb_method_search_vm(mrb, &c, missing); + m = mrb_method_search_vm(mrb, &cls, missing); if (MRB_METHOD_UNDEF_P(m) || (missing == mrb->c->ci->mid && mrb_obj_eq(mrb, regs[0], recv))) { - mrb_value args = (argc < 0) ? regs[a+1] : mrb_ary_new_from_values(mrb, n, regs+a+1); + mrb_value args = (argc < 0) ? regs[a+1] : mrb_ary_new_from_values(mrb, c, regs+a+1); ERR_PC_SET(mrb, pc); mrb_method_missing(mrb, mid, recv, args); } @@ -1444,7 +1372,7 @@ RETRY_TRY_BLOCK: if (a+2 >= irep->nregs) { mrb_stack_extend(mrb, a+3); } - regs[a+1] = mrb_ary_new_from_values(mrb, n, regs+a+1); + regs[a+1] = mrb_ary_new_from_values(mrb, c, regs+a+1); regs[a+2] = blk; argc = -1; } @@ -1456,17 +1384,17 @@ RETRY_TRY_BLOCK: ci = cipush(mrb); ci->mid = mid; ci->stackent = mrb->c->stack; - ci->target_class = c; + ci->target_class = cls; ci->argc = argc; - ci->pc = pc + 1; + ci->pc = pc; ci->acc = a; /* prepare stack */ mrb->c->stack += a; if (MRB_METHOD_CFUNC_P(m)) { - ci->nregs = (argc < 0) ? 3 : n+2; + ci->nregs = (argc < 0) ? 3 : c+2; if (MRB_METHOD_PROC_P(m)) { struct RProc *p = MRB_METHOD_PROC(m); @@ -1480,12 +1408,10 @@ RETRY_TRY_BLOCK: mrb_gc_arena_shrink(mrb, ai); if (mrb->exc) goto L_RAISE; ci = mrb->c->ci; - if (GET_OPCODE(i) == OP_SENDB) { - if (mrb_type(blk) == MRB_TT_PROC) { - struct RProc *p = mrb_proc_ptr(blk); - if (p && !MRB_PROC_STRICT_P(p) && MRB_PROC_ENV(p) == ci[-1].env) { - p->flags |= MRB_PROC_ORPHAN; - } + if (mrb_type(blk) == MRB_TT_PROC) { + struct RProc *p = mrb_proc_ptr(blk); + if (p && !MRB_PROC_STRICT_P(p) && MRB_PROC_ENV(p) == ci[-1].env) { + p->flags |= MRB_PROC_ORPHAN; } } if (!ci->target_class) { /* return from context modifying method (resume/yield) */ @@ -1521,14 +1447,7 @@ RETRY_TRY_BLOCK: } } - CASE(OP_FSEND) { - /* A B C R(A) := fcall(R(A),Syms(B),R(A+1),... ,R(A+C-1)) */ - /* not implemented yet */ - NEXT; - } - - CASE(OP_CALL) { - /* A R(A) := self.call(frame.argc, frame.argv) */ + CASE(OP_CALL, Z) { mrb_callinfo *ci; mrb_value recv = mrb->c->stack[0]; struct RProc *m = mrb_proc_ptr(recv); @@ -1571,7 +1490,9 @@ RETRY_TRY_BLOCK: irep = m->body.irep; if (!irep) { mrb->c->stack[0] = mrb_nil_value(); - goto L_RETURN; + a = 0; + c = OP_R_NORMAL; + goto L_OP_RETURN_BODY; } pool = irep->pool; syms = irep->syms; @@ -1593,14 +1514,11 @@ RETRY_TRY_BLOCK: } } - CASE(OP_SUPER) { - /* A C R(A) := super(R(A+1),... ,R(A+C+1)) */ - int a = GETARG_A(i); - int n = GETARG_C(i); - int argc = (n == CALL_MAXARGS) ? -1 : n; - int bidx = (argc < 0) ? a+2 : a+n+1; + CASE(OP_SUPER, BB) { + int argc = (b == CALL_MAXARGS) ? -1 : b; + int bidx = (argc < 0) ? a+2 : a+b+1; mrb_method_t m; - struct RClass *c; + struct RClass *cls; mrb_callinfo *ci = mrb->c->ci; mrb_value recv, blk; mrb_sym mid = ci->mid; @@ -1636,17 +1554,17 @@ RETRY_TRY_BLOCK: regs[bidx] = blk; ci = mrb->c->ci; } - c = target_class->super; - m = mrb_method_search_vm(mrb, &c, mid); + cls = target_class->super; + m = mrb_method_search_vm(mrb, &cls, mid); if (MRB_METHOD_UNDEF_P(m)) { mrb_sym missing = mrb_intern_lit(mrb, "method_missing"); if (mid != missing) { - c = mrb_class(mrb, recv); + cls = mrb_class(mrb, recv); } - m = mrb_method_search_vm(mrb, &c, missing); + m = mrb_method_search_vm(mrb, &cls, missing); if (MRB_METHOD_UNDEF_P(m)) { - mrb_value args = (argc < 0) ? regs[a+1] : mrb_ary_new_from_values(mrb, n, regs+a+1); + mrb_value args = (argc < 0) ? regs[a+1] : mrb_ary_new_from_values(mrb, b, regs+a+1); ERR_PC_SET(mrb, pc); mrb_method_missing(mrb, mid, recv, args); } @@ -1655,7 +1573,7 @@ RETRY_TRY_BLOCK: if (a+2 >= ci->nregs) { mrb_stack_extend(mrb, a+3); } - regs[a+1] = mrb_ary_new_from_values(mrb, n, regs+a+1); + regs[a+1] = mrb_ary_new_from_values(mrb, b, regs+a+1); regs[a+2] = blk; argc = -1; } @@ -1666,8 +1584,8 @@ RETRY_TRY_BLOCK: ci = cipush(mrb); ci->mid = mid; ci->stackent = mrb->c->stack; - ci->target_class = c; - ci->pc = pc + 1; + ci->target_class = cls; + ci->pc = pc; ci->argc = argc; /* prepare stack */ @@ -1676,7 +1594,7 @@ RETRY_TRY_BLOCK: if (MRB_METHOD_CFUNC_P(m)) { mrb_value v; - ci->nregs = (argc < 0) ? 3 : n+2; + ci->nregs = (argc < 0) ? 3 : b+2; if (MRB_METHOD_PROC_P(m)) { ci->proc = MRB_METHOD_PROC(m); } @@ -1720,14 +1638,11 @@ RETRY_TRY_BLOCK: } } - CASE(OP_ARGARY) { - /* A Bx R(A) := argument array (16=6:1:5:4) */ - int a = GETARG_A(i); - int bx = GETARG_Bx(i); - int m1 = (bx>>10)&0x3f; - int r = (bx>>9)&0x1; - int m2 = (bx>>4)&0x1f; - int lv = (bx>>0)&0xf; + CASE(OP_ARGARY, BS) { + int m1 = (b>>10)&0x3f; + int r = (b>>9)&0x1; + int m2 = (b>>4)&0x1f; + int lv = (b>>0)&0xf; mrb_value *stack; if (mrb->c->ci->mid == 0 || mrb->c->ci->target_class == NULL) { @@ -1778,18 +1693,15 @@ RETRY_TRY_BLOCK: NEXT; } - CASE(OP_ENTER) { - /* Ax arg setup according to flags (23=5:5:1:5:5:1:1) */ - /* number of optional arguments times OP_JMP should follow */ - mrb_aspec ax = GETARG_Ax(i); - int m1 = MRB_ASPEC_REQ(ax); - int o = MRB_ASPEC_OPT(ax); - int r = MRB_ASPEC_REST(ax); - int m2 = MRB_ASPEC_POST(ax); + CASE(OP_ENTER, W) { + int m1 = MRB_ASPEC_REQ(a); + int o = MRB_ASPEC_OPT(a); + int r = MRB_ASPEC_REST(a); + int m2 = MRB_ASPEC_POST(a); /* unused - int k = MRB_ASPEC_KEY(ax); - int kd = MRB_ASPEC_KDICT(ax); - int b = MRB_ASPEC_BLOCK(ax); + int k = MRB_ASPEC_KEY(a); + int kd = MRB_ASPEC_KDICT(a); + int b = MRB_ASPEC_BLOCK(a); */ int argc = mrb->c->ci->argc; mrb_value *argv = regs+1; @@ -1841,9 +1753,8 @@ RETRY_TRY_BLOCK: if (r) { regs[m1+o+1] = mrb_ary_new_capa(mrb, 0); } - if (o == 0 || argc < m1+m2) pc++; - else - pc += argc - m1 - m2 + 1; + if (o > 0 && argc >= m1+m2) + pc += (argc - m1 - m2)*3; } else { int rnum = 0; @@ -1852,8 +1763,11 @@ RETRY_TRY_BLOCK: value_move(®s[1], argv, m1+o); } if (r) { + mrb_value ary; + rnum = argc-m1-o-m2; - regs[m1+o+1] = mrb_ary_new_from_values(mrb, rnum, argv+m1+o); + ary = mrb_ary_new_from_values(mrb, rnum, argv+m1+o); + regs[m1+o+1] = ary; } if (m2) { if (argc-m2 > m1) { @@ -1863,7 +1777,7 @@ RETRY_TRY_BLOCK: if (argv0 == argv) { regs[len+1] = *blk; /* move block */ } - pc += o + 1; + pc += o*3; } mrb->c->ci->argc = len; /* clear local (but non-argument) variables */ @@ -1873,24 +1787,33 @@ RETRY_TRY_BLOCK: JUMP; } - CASE(OP_KARG) { - /* A B C R(A) := kdict[Syms(B)]; if C kdict.rm(Syms(B)) */ - /* if C == 2; raise unless kdict.empty? */ - /* OP_JMP should follow to skip init code */ + CASE(OP_KARG, BB) { + /* not implemented yet */ + NEXT; + } + CASE(OP_KARG2, BB) { + /* not implemented yet */ NEXT; } - CASE(OP_KDICT) { - /* A C R(A) := kdict */ + CASE(OP_KDICT, B) { + /* not implemented yet */ NEXT; } + CASE(OP_BREAK, B) { + c = OP_R_BREAK; + goto L_RETURN; + } + CASE(OP_RETURN_BLK, B) { + c = OP_R_RETURN; + goto L_RETURN; + } + CASE(OP_RETURN, B) + c = OP_R_NORMAL; L_RETURN: - i = MKOP_AB(OP_RETURN, GETARG_A(i), OP_R_NORMAL); - /* fall through */ - CASE(OP_RETURN) { - /* A B return R(A) (B=normal,in-block return/break) */ - mrb_callinfo *ci; + { + mrb_callinfo *ci; #define ecall_adjust() do {\ ptrdiff_t cioff = ci - mrb->c->cibase;\ @@ -1976,7 +1899,7 @@ RETRY_TRY_BLOCK: mrb->c->stack = ci[1].stackent; } mrb_stack_extend(mrb, irep->nregs); - pc = mrb->c->rescue[--ci->ridx]; + pc = irep->iseq+mrb->c->rescue[--ci->ridx]; } else { int acc; @@ -1984,9 +1907,9 @@ RETRY_TRY_BLOCK: struct RProc *dst; ci = mrb->c->ci; - v = regs[GETARG_A(i)]; + v = regs[a]; mrb_gc_protect(mrb, v); - switch (GETARG_B(i)) { + switch (c) { case OP_R_RETURN: /* Fall through to OP_R_NORMAL otherwise */ if (ci->acc >=0 && MRB_PROC_ENV_P(proc) && !MRB_PROC_STRICT_P(proc)) { @@ -2021,8 +1944,7 @@ RETRY_TRY_BLOCK: struct mrb_context *c; if (!mrb->c->prev) { /* toplevel return */ - localjump_error(mrb, LOCALJUMP_ERROR_RETURN); - goto L_RAISE; + goto L_STOP; } if (mrb->c->prev->ci == mrb->c->prev->cibase) { mrb_value exc = mrb_exc_new_str_lit(mrb, E_FIBER_ERROR, "double resume"); @@ -2141,91 +2063,11 @@ RETRY_TRY_BLOCK: JUMP; } - CASE(OP_TAILCALL) { - /* A B C return call(R(A),Syms(B),R(A+1),... ,R(A+C+1)) */ - int a = GETARG_A(i); - int b = GETARG_B(i); - int n = GETARG_C(i); - mrb_method_t m; - struct RClass *c; - mrb_callinfo *ci; - mrb_value recv; - mrb_sym mid = syms[b]; - - recv = regs[a]; - c = mrb_class(mrb, recv); - m = mrb_method_search_vm(mrb, &c, mid); - if (MRB_METHOD_UNDEF_P(m)) { - mrb_value sym = mrb_symbol_value(mid); - mrb_sym missing = mrb_intern_lit(mrb, "method_missing"); - m = mrb_method_search_vm(mrb, &c, missing); - if (MRB_METHOD_UNDEF_P(m)) { - mrb_value args; - - if (n == CALL_MAXARGS) { - args = regs[a+1]; - } - else { - args = mrb_ary_new_from_values(mrb, n, regs+a+1); - } - ERR_PC_SET(mrb, pc); - mrb_method_missing(mrb, mid, recv, args); - } - mid = missing; - if (n == CALL_MAXARGS) { - mrb_ary_unshift(mrb, regs[a+1], sym); - } - else { - value_move(regs+a+2, regs+a+1, ++n); - regs[a+1] = sym; - } - } - - /* replace callinfo */ - ci = mrb->c->ci; - ci->mid = mid; - ci->target_class = c; - if (n == CALL_MAXARGS) { - ci->argc = -1; - } - else { - ci->argc = n; - } - - /* move stack */ - value_move(mrb->c->stack, ®s[a], ci->argc+1); - - if (MRB_METHOD_CFUNC_P(m)) { - mrb_value v = MRB_METHOD_CFUNC(m)(mrb, recv); - mrb->c->stack[0] = v; - mrb_gc_arena_restore(mrb, ai); - goto L_RETURN; - } - else { - /* setup environment for calling method */ - struct RProc *p = MRB_METHOD_PROC(m); - irep = p->body.irep; - pool = irep->pool; - syms = irep->syms; - if (ci->argc < 0) { - mrb_stack_extend(mrb, (irep->nregs < 3) ? 3 : irep->nregs); - } - else { - mrb_stack_extend(mrb, irep->nregs); - } - pc = irep->iseq; - } - JUMP; - } - - CASE(OP_BLKPUSH) { - /* A Bx R(A) := block (16=6:1:5:4) */ - int a = GETARG_A(i); - int bx = GETARG_Bx(i); - int m1 = (bx>>10)&0x3f; - int r = (bx>>9)&0x1; - int m2 = (bx>>4)&0x1f; - int lv = (bx>>0)&0xf; + CASE(OP_BLKPUSH, BS) { + int m1 = (b>>10)&0x3f; + int r = (b>>9)&0x1; + int m2 = (b>>4)&0x1f; + int lv = (b>>0)&0xf; mrb_value *stack; if (lv == 0) stack = regs + 1; @@ -2251,10 +2093,7 @@ RETRY_TRY_BLOCK: v1(regs[a]) = v1(regs[a]) op v2(regs[a+1]);\ } while(0) - CASE(OP_ADD) { - /* A B C R(A) := R(A)+R(A+1) (Syms[B]=:+,C=1)*/ - int a = GETARG_A(i); - + CASE(OP_ADD, BB) { /* need to check if op is overridden */ switch (TYPES2(mrb_type(regs[a]),mrb_type(regs[a+1]))) { case TYPES2(MRB_TT_FIXNUM,MRB_TT_FIXNUM): @@ -2308,16 +2147,14 @@ RETRY_TRY_BLOCK: regs[a] = mrb_str_plus(mrb, regs[a], regs[a+1]); break; default: + c = 1; goto L_SEND; } mrb_gc_arena_restore(mrb, ai); NEXT; } - CASE(OP_SUB) { - /* A B C R(A) := R(A)-R(A+1) (Syms[B]=:-,C=1)*/ - int a = GETARG_A(i); - + CASE(OP_SUB, BB) { /* need to check if op is overridden */ switch (TYPES2(mrb_type(regs[a]),mrb_type(regs[a+1]))) { case TYPES2(MRB_TT_FIXNUM,MRB_TT_FIXNUM): @@ -2367,15 +2204,13 @@ RETRY_TRY_BLOCK: break; #endif default: + c = 1; goto L_SEND; } NEXT; } - CASE(OP_MUL) { - /* A B C R(A) := R(A)*R(A+1) (Syms[B]=:*,C=1)*/ - int a = GETARG_A(i); - + CASE(OP_MUL, BB) { /* need to check if op is overridden */ switch (TYPES2(mrb_type(regs[a]),mrb_type(regs[a+1]))) { case TYPES2(MRB_TT_FIXNUM,MRB_TT_FIXNUM): @@ -2425,14 +2260,13 @@ RETRY_TRY_BLOCK: break; #endif default: + c = 1; goto L_SEND; } NEXT; } - CASE(OP_DIV) { - /* A B C R(A) := R(A)/R(A+1) (Syms[B]=:/,C=1)*/ - int a = GETARG_A(i); + CASE(OP_DIV, BB) { #ifndef MRB_WITHOUT_FLOAT double x, y, f; #endif @@ -2465,6 +2299,7 @@ RETRY_TRY_BLOCK: break; #endif default: + c = 1; goto L_SEND; } @@ -2482,16 +2317,13 @@ RETRY_TRY_BLOCK: NEXT; } - CASE(OP_ADDI) { - /* A B C R(A) := R(A)+C (Syms[B]=:+)*/ - int a = GETARG_A(i); - + CASE(OP_ADDI, BBB) { /* need to check if + is overridden */ switch (mrb_type(regs[a])) { case MRB_TT_FIXNUM: { mrb_int x = mrb_fixnum(regs[a]); - mrb_int y = GETARG_C(i); + mrb_int y = (mrb_int)c; mrb_int z; if (mrb_int_add_overflow(x, y, &z)) { @@ -2508,24 +2340,22 @@ RETRY_TRY_BLOCK: #ifdef MRB_WORD_BOXING { mrb_float x = mrb_float(regs[a]); - SET_FLOAT_VALUE(mrb, regs[a], x + GETARG_C(i)); + SET_FLOAT_VALUE(mrb, regs[a], x + c); } #else - mrb_float(regs[a]) += GETARG_C(i); + mrb_float(regs[a]) += c; #endif break; #endif default: - SET_INT_VALUE(regs[a+1], GETARG_C(i)); - i = MKOP_ABC(OP_SEND, a, GETARG_B(i), 1); + SET_INT_VALUE(regs[a+1], c); + c = 1; goto L_SEND; } NEXT; } - CASE(OP_SUBI) { - /* A B C R(A) := R(A)-C (Syms[B]=:-)*/ - int a = GETARG_A(i); + CASE(OP_SUBI, BBB) { mrb_value *regs_a = regs + a; /* need to check if + is overridden */ @@ -2533,7 +2363,7 @@ RETRY_TRY_BLOCK: case MRB_TT_FIXNUM: { mrb_int x = mrb_fixnum(regs_a[0]); - mrb_int y = GETARG_C(i); + mrb_int y = (mrb_int)c; mrb_int z; if (mrb_int_sub_overflow(x, y, &z)) { @@ -2553,13 +2383,13 @@ RETRY_TRY_BLOCK: SET_FLOAT_VALUE(mrb, regs[a], x - GETARG_C(i)); } #else - mrb_float(regs_a[0]) -= GETARG_C(i); + mrb_float(regs_a[0]) -= c; #endif break; #endif default: - SET_INT_VALUE(regs_a[1], GETARG_C(i)); - i = MKOP_ABC(OP_SEND, a, GETARG_B(i), 1); + SET_INT_VALUE(regs_a[1], c); + c = 1; goto L_SEND; } NEXT; @@ -2576,6 +2406,7 @@ RETRY_TRY_BLOCK: result = OP_CMP_BODY(op,mrb_fixnum,mrb_fixnum);\ break;\ default:\ + c = 1;\ goto L_SEND;\ }\ if (result) {\ @@ -2603,6 +2434,7 @@ RETRY_TRY_BLOCK: result = OP_CMP_BODY(op,mrb_float,mrb_float);\ break;\ default:\ + c = 1;\ goto L_SEND;\ }\ if (result) {\ @@ -2614,9 +2446,7 @@ RETRY_TRY_BLOCK: } while(0) #endif - CASE(OP_EQ) { - /* A B C R(A) := R(A)==R(A+1) (Syms[B]=:==,C=1)*/ - int a = GETARG_A(i); + CASE(OP_EQ, BB) { if (mrb_obj_eq(mrb, regs[a], regs[a+1])) { SET_TRUE_VALUE(regs[a]); } @@ -2626,68 +2456,59 @@ RETRY_TRY_BLOCK: NEXT; } - CASE(OP_LT) { - /* A B C R(A) := R(A)R(A+1) (Syms[B]=:>,C=1)*/ - int a = GETARG_A(i); + CASE(OP_GT, BB) { OP_CMP(>); NEXT; } - CASE(OP_GE) { - /* A B C R(A) := R(A)>=R(A+1) (Syms[B]=:>=,C=1)*/ - int a = GETARG_A(i); + CASE(OP_GE, BB) { OP_CMP(>=); NEXT; } - CASE(OP_ARRAY) { - /* A B C R(A) := ary_new(R(B),R(B+1)..R(B+C)) */ - int a = GETARG_A(i); - int b = GETARG_B(i); - int c = GETARG_C(i); + CASE(OP_ARRAY, BB) { + mrb_value v = mrb_ary_new_from_values(mrb, b, ®s[a]); + regs[a] = v; + mrb_gc_arena_restore(mrb, ai); + NEXT; + } + CASE(OP_ARRAY2, BBB) { mrb_value v = mrb_ary_new_from_values(mrb, c, ®s[b]); regs[a] = v; mrb_gc_arena_restore(mrb, ai); NEXT; } - CASE(OP_ARYCAT) { - /* A B mrb_ary_concat(R(A),R(B)) */ - int a = GETARG_A(i); - int b = GETARG_B(i); - mrb_value splat = mrb_ary_splat(mrb, regs[b]); + CASE(OP_ARYCAT, B) { + mrb_value splat = mrb_ary_splat(mrb, regs[a+1]); mrb_ary_concat(mrb, regs[a], splat); mrb_gc_arena_restore(mrb, ai); NEXT; } - CASE(OP_ARYPUSH) { - /* A B R(A).push(R(B)) */ - int a = GETARG_A(i); - int b = GETARG_B(i); - mrb_ary_push(mrb, regs[a], regs[b]); + CASE(OP_ARYPUSH, B) { + mrb_ary_push(mrb, regs[a], regs[a+1]); NEXT; } - CASE(OP_AREF) { - /* A B C R(A) := R(B)[C] */ - int a = GETARG_A(i); - int b = GETARG_B(i); - int c = GETARG_C(i); + CASE(OP_ARYDUP, B) { + mrb_value ary = regs[a]; + ary = mrb_ary_new_from_values(mrb, RARRAY_LEN(ary), RARRAY_PTR(ary)); + regs[a] = ary; + NEXT; + } + + CASE(OP_AREF, BBB) { mrb_value v = regs[b]; if (!mrb_array_p(v)) { @@ -2705,21 +2526,15 @@ RETRY_TRY_BLOCK: NEXT; } - CASE(OP_ASET) { - /* A B C R(B)[C] := R(A) */ - int a = GETARG_A(i); - int b = GETARG_B(i); - int c = GETARG_C(i); + CASE(OP_ASET, BBB) { mrb_ary_set(mrb, regs[b], c, regs[a]); NEXT; } - CASE(OP_APOST) { - /* A B C *R(A),R(A+1)..R(A+C) := R(A)[B..] */ - int a = GETARG_A(i); + CASE(OP_APOST, BBB) { mrb_value v = regs[a]; - int pre = GETARG_B(i); - int post = GETARG_C(i); + int pre = b; + int post = c; struct RArray *ary; int len, idx; @@ -2750,48 +2565,58 @@ RETRY_TRY_BLOCK: NEXT; } - CASE(OP_STRING) { - /* A Bx R(A) := str_new(Lit(Bx)) */ - mrb_int a = GETARG_A(i); - mrb_int bx = GETARG_Bx(i); - mrb_value str = mrb_str_dup(mrb, pool[bx]); + CASE(OP_INTERN, B) { + mrb_sym sym = mrb_intern_str(mrb, regs[a]); + + regs[a] = mrb_symbol_value(sym); + mrb_gc_arena_restore(mrb, ai); + NEXT; + } + + CASE(OP_STRING, BB) { + mrb_value str = mrb_str_dup(mrb, pool[b]); regs[a] = str; mrb_gc_arena_restore(mrb, ai); NEXT; } - CASE(OP_STRCAT) { - /* A B R(A).concat(R(B)) */ - mrb_int a = GETARG_A(i); - mrb_int b = GETARG_B(i); + CASE(OP_STRCAT, B) { + mrb_str_concat(mrb, regs[a], regs[a+1]); + NEXT; + } + + CASE(OP_HASH, BB) { + mrb_value hash = mrb_hash_new_capa(mrb, b); + int i; + int lim = a+b*2; - mrb_str_concat(mrb, regs[a], regs[b]); + for (i=a; ireps[b]; if (c & OP_L_CAPTURE) { @@ -2806,19 +2631,38 @@ RETRY_TRY_BLOCK: mrb_gc_arena_restore(mrb, ai); NEXT; } + CASE(OP_BLOCK, BB) { + c = OP_L_BLOCK; + goto L_MAKE_LAMBDA; + } + CASE(OP_METHOD, BB) { + c = OP_L_METHOD; + goto L_MAKE_LAMBDA; + } - CASE(OP_OCLASS) { - /* A R(A) := ::Object */ - regs[GETARG_A(i)] = mrb_obj_value(mrb->object_class); + CASE(OP_RANGE_INC, B) { + mrb_value val = mrb_range_new(mrb, regs[a], regs[a+1], FALSE); + regs[a] = val; + mrb_gc_arena_restore(mrb, ai); NEXT; } - CASE(OP_CLASS) { - /* A B R(A) := newclass(R(A),Syms(B),R(A+1)) */ + CASE(OP_RANGE_EXC, B) { + mrb_value val = mrb_range_new(mrb, regs[a], regs[a+1], TRUE); + regs[a] = val; + mrb_gc_arena_restore(mrb, ai); + NEXT; + } + + CASE(OP_OCLASS, B) { + regs[a] = mrb_obj_value(mrb->object_class); + NEXT; + } + + CASE(OP_CLASS, BB) { struct RClass *c = 0, *baseclass; - int a = GETARG_A(i); mrb_value base, super; - mrb_sym id = syms[GETARG_B(i)]; + mrb_sym id = syms[b]; base = regs[a]; super = regs[a+1]; @@ -2832,32 +2676,27 @@ RETRY_TRY_BLOCK: NEXT; } - CASE(OP_MODULE) { - /* A B R(A) := newmodule(R(A),Syms(B)) */ - struct RClass *c = 0, *baseclass; - int a = GETARG_A(i); + CASE(OP_MODULE, BB) { + struct RClass *cls = 0, *baseclass; mrb_value base; - mrb_sym id = syms[GETARG_B(i)]; + mrb_sym id = syms[b]; base = regs[a]; if (mrb_nil_p(base)) { baseclass = MRB_PROC_TARGET_CLASS(mrb->c->ci->proc); base = mrb_obj_value(baseclass); } - c = mrb_vm_define_module(mrb, base, id); - regs[a] = mrb_obj_value(c); + cls = mrb_vm_define_module(mrb, base, id); + regs[a] = mrb_obj_value(cls); mrb_gc_arena_restore(mrb, ai); NEXT; } - CASE(OP_EXEC) { - /* A Bx R(A) := blockexec(R(A),SEQ[Bx]) */ - int a = GETARG_A(i); - int bx = GETARG_Bx(i); + CASE(OP_EXEC, BB) { mrb_callinfo *ci; mrb_value recv = regs[a]; struct RProc *p; - mrb_irep *nirep = irep->reps[bx]; + mrb_irep *nirep = irep->reps[b]; /* prepare closure */ p = mrb_proc_new(mrb, nirep); @@ -2868,7 +2707,7 @@ RETRY_TRY_BLOCK: /* prepare call stack */ ci = cipush(mrb); - ci->pc = pc + 1; + ci->pc = pc; ci->acc = a; ci->mid = 0; ci->stackent = mrb->c->stack; @@ -2891,56 +2730,53 @@ RETRY_TRY_BLOCK: JUMP; } - CASE(OP_METHOD) { - /* A B R(A).newmethod(Syms(B),R(A+1)) */ - int a = GETARG_A(i); - struct RClass *c = mrb_class_ptr(regs[a]); + CASE(OP_DEF, BB) { + struct RClass *target = mrb_class_ptr(regs[a]); struct RProc *p = mrb_proc_ptr(regs[a+1]); mrb_method_t m; MRB_METHOD_FROM_PROC(m, p); - mrb_define_method_raw(mrb, c, syms[GETARG_B(i)], m); + mrb_define_method_raw(mrb, target, syms[b], m); mrb_gc_arena_restore(mrb, ai); NEXT; } - CASE(OP_SCLASS) { - /* A B R(A) := R(B).singleton_class */ - int a = GETARG_A(i); - int b = GETARG_B(i); - - regs[a] = mrb_singleton_class(mrb, regs[b]); + CASE(OP_SCLASS, B) { + regs[a] = mrb_singleton_class(mrb, regs[a]); mrb_gc_arena_restore(mrb, ai); NEXT; } - CASE(OP_TCLASS) { - /* A R(A) := target_class */ - if (!mrb->c->ci->target_class) { - mrb_value exc = mrb_exc_new_str_lit(mrb, E_TYPE_ERROR, "no target class or module"); - mrb_exc_set(mrb, exc); - goto L_RAISE; - } - regs[GETARG_A(i)] = mrb_obj_value(mrb->c->ci->target_class); + CASE(OP_TCLASS, B) { + if (!check_target_class(mrb)) goto L_RAISE; + regs[a] = mrb_obj_value(mrb->c->ci->target_class); NEXT; } - CASE(OP_RANGE) { - /* A B C R(A) := range_new(R(B),R(B+1),C) */ - int b = GETARG_B(i); - mrb_value val = mrb_range_new(mrb, regs[b], regs[b+1], GETARG_C(i)); - regs[GETARG_A(i)] = val; - mrb_gc_arena_restore(mrb, ai); + CASE(OP_ALIAS, BB) { + struct RClass *target; + + if (!check_target_class(mrb)) goto L_RAISE; + target = mrb->c->ci->target_class; + mrb_alias_method(mrb, target, syms[a], syms[b]); + NEXT; + } + CASE(OP_UNDEF, B) { + struct RClass *target; + + if (!check_target_class(mrb)) goto L_RAISE; + target = mrb->c->ci->target_class; + mrb_undef_method_id(mrb, target, syms[a]); NEXT; } - CASE(OP_DEBUG) { - /* A B C debug print R(A),R(B),R(C) */ + CASE(OP_DEBUG, Z) { + FETCH_BBB(); #ifdef MRB_ENABLE_DEBUG_HOOK mrb->debug_op_hook(mrb, irep, pc, regs); #else #ifndef MRB_DISABLE_STDIO - printf("OP_DEBUG %d %d %d\n", GETARG_A(i), GETARG_B(i), GETARG_C(i)); + printf("OP_DEBUG %d %d %d\n", a, b, c); #else abort(); #endif @@ -2948,7 +2784,48 @@ RETRY_TRY_BLOCK: NEXT; } - CASE(OP_STOP) { + CASE(OP_ERR, B) { + mrb_value msg = mrb_str_dup(mrb, pool[a]); + mrb_value exc; + + exc = mrb_exc_new_str(mrb, E_LOCALJUMP_ERROR, msg); + ERR_PC_SET(mrb, pc); + mrb_exc_set(mrb, exc); + goto L_RAISE; + } + + CASE(OP_EXT1, Z) { + insn = READ_B(); + switch (insn) { +#define OPCODE(insn,ops) case OP_ ## insn: FETCH_ ## ops ## _1(); goto L_OP_ ## insn ## _BODY; +#include "mruby/ops.h" +#undef OPCODE + } + pc--; + NEXT; + } + CASE(OP_EXT2, Z) { + insn = READ_B(); + switch (insn) { +#define OPCODE(insn,ops) case OP_ ## insn: FETCH_ ## ops ## _2(); goto L_OP_ ## insn ## _BODY; +#include "mruby/ops.h" +#undef OPCODE + } + pc--; + NEXT; + } + CASE(OP_EXT3, Z) { + uint8_t insn = READ_B(); + switch (insn) { +#define OPCODE(insn,ops) case OP_ ## insn: FETCH_ ## ops ## _3(); goto L_OP_ ## insn ## _BODY; +#include "mruby/ops.h" +#undef OPCODE + } + pc--; + NEXT; + } + + CASE(OP_STOP, Z) { /* stop VM */ L_STOP: while (mrb->c->eidx > 0) { @@ -2961,26 +2838,9 @@ RETRY_TRY_BLOCK: } return regs[irep->nlocals]; } - - CASE(OP_ERR) { - /* Bx raise RuntimeError with message Lit(Bx) */ - mrb_value msg = mrb_str_dup(mrb, pool[GETARG_Bx(i)]); - mrb_value exc; - - if (GETARG_A(i) == 0) { - exc = mrb_exc_new_str(mrb, E_RUNTIME_ERROR, msg); - } - else { - exc = mrb_exc_new_str(mrb, E_LOCALJUMP_ERROR, msg); - } - ERR_PC_SET(mrb, pc); - mrb_exc_set(mrb, exc); - goto L_RAISE; - } } END_DISPATCH; #undef regs - } MRB_CATCH(&c_jmp) { exc_catched = TRUE; -- cgit v1.2.3 From 8c9e7127845f84fcbb249c45936c97a89ca7a80a Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Mon, 30 Jul 2018 22:07:31 +0900 Subject: Keyword argument implemented. --- doc/opcode.md | 8 +- include/mruby/hash.h | 27 +- include/mruby/ops.h | 11 +- mrbgems/mruby-compiler/core/codegen.c | 149 +++++-- mrbgems/mruby-compiler/core/node.h | 4 + mrbgems/mruby-compiler/core/parse.y | 493 ++++++++++++++-------- mrbgems/mruby-objectspace/src/mruby_objectspace.c | 2 +- mrbgems/mruby-proc-ext/src/proc.c | 10 +- src/codedump.c | 50 ++- src/hash.c | 86 +++- src/kernel.c | 10 +- src/vm.c | 146 +++++-- test/t/syntax.rb | 183 ++++++++ 13 files changed, 887 insertions(+), 292 deletions(-) diff --git a/doc/opcode.md b/doc/opcode.md index d904256e5..54d1f0553 100644 --- a/doc/opcode.md +++ b/doc/opcode.md @@ -77,7 +77,7 @@ with `"`, either `OP_EXT1` or `OP_EXT2` or `OP_EXT2` can be prefixed. |OP_SENDB" |BBB |R(a) = call(R(a),Syms(Bx),R(a+1),...,R(a+c),&R(a+c+1)) |OP_CALL' |B |R(a) = self.call(frame.argc, frame.argv) |OP_SUPER' |BB |R(a) = super(R(a+1),... ,R(a+b+1)) -|OP_ARGARY' |BS |R(a) = argument array (16=6:1:5:4) +|OP_ARGARY' |BS |R(a) = argument array (16=5:1:5:1:4) |OP_ENTER |W |arg setup according to flags (23=5:5:1:5:5:1:1) |OP_KARG" |BB |R(a) = kdict[Syms(Bx)] # todo |OP_KARG2" |BB |R(a) = kdict[Syms(Bx)]; kdict.rm(Syms(b)) # todo @@ -85,7 +85,7 @@ with `"`, either `OP_EXT1` or `OP_EXT2` or `OP_EXT2` can be prefixed. |OP_RETURN' |B |return R(a) (normal) |OP_RETURN_BLK' |B |return R(a) (in-block return) |OP_BREAK' |B |break R(a) -|OP_BLKPUSH' |BS |R(a) = block (16=6:1:5:4) +|OP_BLKPUSH' |BS |R(a) = block (16=5:1:5:1:4) |OP_ADD" |BB |R(a) = R(a)+R(a+1) (Syms[b]=:+) |OP_ADDI" |BBB |R(a) = R(a)+mrb_int(c) (Syms[b]=:+) |OP_SUB" |BB |R(a) = R(a)-R(a+1) (Syms[b]=:-) @@ -207,7 +207,7 @@ with `"`, either `OP_EXT1` or `OP_EXT2` or `OP_EXT2` can be prefixed. |OP_SENDB" |BBB |R(a) = call(R(a),Syms(Bx),R(a+1),...,R(a+c),&R(a+c+1)) |OP_CALL' |B |R(a) = self.call(frame.argc, frame.argv) |OP_SUPER' |BB |R(a) = super(R(a+1),... ,R(a+b+1)) -|OP_ARGARY' |BS |R(a) = argument array (16=6:1:5:4) +|OP_ARGARY' |BS |R(a) = argument array (16=5:1:5:1:4) |OP_ENTER |W |arg setup according to flags (23=5:5:1:5:5:1:1) |OP_KARG" |BB |R(a) = kdict[Syms(Bx)] # todo |OP_KARG2" |BB |R(a) = kdict[Syms(Bx)]; kdict.rm(Syms(b)) # todo @@ -215,7 +215,7 @@ with `"`, either `OP_EXT1` or `OP_EXT2` or `OP_EXT2` can be prefixed. |OP_RETURN' |B |return R(a) (normal) |OP_RETURN_BLK' |B |return R(a) (in-block return) |OP_BREAK' |B |break R(a) -|OP_BLKPUSH' |BS |R(a) = block (16=6:1:5:4) +|OP_BLKPUSH' |BS |R(a) = block (16=5:1:5:1:4) |OP_ADD" |BB |R(a) = R(a)+R(a+1) (Syms[b]=:+) |OP_ADDI" |BBB |R(a) = R(a)+mrb_int(c) (Syms[b]=:+) |OP_SUB" |BB |R(a) = R(a)-R(a+1) (Syms[b]=:-) diff --git a/include/mruby/hash.h b/include/mruby/hash.h index 1a870785a..9a3812850 100644 --- a/include/mruby/hash.h +++ b/include/mruby/hash.h @@ -25,6 +25,7 @@ struct RHash { #define mrb_hash_value(p) mrb_obj_value((void*)(p)) MRB_API mrb_value mrb_hash_new_capa(mrb_state*, mrb_int); +MRB_API mrb_value mrb_check_hash_type(mrb_state *mrb, mrb_value hash); /* * Initializes a new hash. @@ -110,7 +111,19 @@ MRB_API mrb_value mrb_hash_delete_key(mrb_state *mrb, mrb_value hash, mrb_value * @return An array with the keys of the hash. */ MRB_API mrb_value mrb_hash_keys(mrb_state *mrb, mrb_value hash); -MRB_API mrb_value mrb_check_hash_type(mrb_state *mrb, mrb_value hash); +/* + * Check if the hash has the key. + * + * Equivalent to: + * + * hash.key?(key) + * + * @param mrb The mruby state reference. + * @param hash The target hash. + * @param key The key to check existence. + * @return True if the hash has the key + */ +MRB_API mrb_bool mrb_hash_key_p(mrb_state *mrb, mrb_value hash, mrb_value key); /* * Check if the hash is empty @@ -123,7 +136,7 @@ MRB_API mrb_value mrb_check_hash_type(mrb_state *mrb, mrb_value hash); * @param self The target hash. * @return True if the hash is empty, false otherwise. */ -MRB_API mrb_value mrb_hash_empty_p(mrb_state *mrb, mrb_value self); +MRB_API mrb_bool mrb_hash_empty_p(mrb_state *mrb, mrb_value self); /* * Gets an array of values. @@ -151,6 +164,16 @@ MRB_API mrb_value mrb_hash_values(mrb_state *mrb, mrb_value hash); */ MRB_API mrb_value mrb_hash_clear(mrb_state *mrb, mrb_value hash); +/* + * Copies the hash. + * + * + * @param mrb The mruby state reference. + * @param hash The target hash. + * @return The copy of the hash + */ +MRB_API mrb_value mrb_hash_dup(mrb_state *mrb, mrb_value hash); + /* declaration of struct kh_ht */ /* be careful when you touch the internal */ typedef struct { diff --git a/include/mruby/ops.h b/include/mruby/ops.h index 882ad6f25..9675d6158 100644 --- a/include/mruby/ops.h +++ b/include/mruby/ops.h @@ -61,15 +61,16 @@ OPCODE(SEND, BBB) /* R(a) = call(R(a),Syms(b),R(a+1),...,R(a+c)) */ OPCODE(SENDB, BBB) /* R(a) = call(R(a),Syms(Bx),R(a+1),...,R(a+c),&R(a+c+1)) */ OPCODE(CALL, Z) /* R(0) = self.call(frame.argc, frame.argv) */ OPCODE(SUPER, BB) /* R(a) = super(R(a+1),... ,R(a+b+1)) */ -OPCODE(ARGARY, BS) /* R(a) = argument array (16=6:1:5:4) */ -OPCODE(ENTER, W) /* arg setup according to flags (23=5:5:1:5:5:1:1) */ -OPCODE(KARG, BB) /* R(a) = kdict[Syms(Bx)] # todo */ -OPCODE(KARG2, BB) /* R(a) = kdict[Syms(Bx)]; kdict.rm(Syms(b)) # todo */ +OPCODE(ARGARY, BS) /* R(a) = argument array (16=m5:r1:m5:d1:lv4) */ +OPCODE(ENTER, W) /* arg setup according to flags (23=m5:o5:r1:m5:k5:d1:b1) */ +OPCODE(KEY_P, BB) /* R(a) = kdict.key?(Syms(b)) # todo */ +OPCODE(KEYEND, Z) /* raise unless kdict.empty? # todo */ +OPCODE(KARG, BB) /* R(a) = kdict[Syms(b)]; kdict.delete(Syms(b)) # todo */ OPCODE(KDICT, B) /* R(a) = kdict # todo */ OPCODE(RETURN, B) /* return R(a) (normal) */ OPCODE(RETURN_BLK, B) /* return R(a) (in-block return) */ OPCODE(BREAK, B) /* break R(a) */ -OPCODE(BLKPUSH, BS) /* R(a) = block (16=6:1:5:4) */ +OPCODE(BLKPUSH, BS) /* R(a) = block (16=m5:r1:m5:d1:lv4) */ OPCODE(ADD, BB) /* R(a) = R(a)+R(a+1) (Syms[b]=:+) */ OPCODE(ADDI, BBB) /* R(a) = R(a)+mrb_int(c) (Syms[b]=:+) */ OPCODE(SUB, BB) /* R(a) = R(a)-R(a+1) (Syms[b]=:-) */ diff --git a/mrbgems/mruby-compiler/core/codegen.c b/mrbgems/mruby-compiler/core/codegen.c index 3ba2324fb..070aaac51 100644 --- a/mrbgems/mruby-compiler/core/codegen.c +++ b/mrbgems/mruby-compiler/core/codegen.c @@ -420,6 +420,9 @@ gen_move(codegen_scope *s, uint16_t dst, uint16_t src, int nopeep) if (no_peephole(s)) { normal: genop_2(s, OP_MOVE, dst, src); + if (on_eval(s)) { + genop_0(s, OP_NOP); + } return; } else { @@ -453,6 +456,25 @@ gen_move(codegen_scope *s, uint16_t dst, uint16_t src, int nopeep) } } +static void +gen_return(codegen_scope *s, uint8_t op, uint16_t src) +{ + if (no_peephole(s)) { + genop_1(s, op, src); + } + else { + struct mrb_insn_data data = mrb_last_insn(s); + + if (data.insn == OP_MOVE && src == data.a) { + s->pc = s->lastpc; + genop_1(s, op, data.b); + } + else { + genop_1(s, op, src); + } + } +} + static void gen_addsub(codegen_scope *s, uint8_t op, uint16_t dst, uint16_t idx) { @@ -514,30 +536,28 @@ dispatch_linked(codegen_scope *s, uint16_t pos) #define nregs_update do {if (s->sp > s->nregs) s->nregs = s->sp;} while (0) static void -push_(codegen_scope *s) +push_n_(codegen_scope *s, int n) { - if (s->sp >= 0xffff) { + if (s->sp+n >= 0xffff) { codegen_error(s, "too complex expression"); } - s->sp++; + s->sp+=n; nregs_update; } static void -push_n_(codegen_scope *s, int n) +pop_n_(codegen_scope *s, int n) { - if (s->sp+n >= 0xffff) { - codegen_error(s, "too complex expression"); + if ((int)s->sp-n < 0) { + codegen_error(s, "stack pointer underflow"); } - s->sp+=n; - nregs_update; + s->sp-=n; } -#define push() push_(s) +#define push() push_n_(s,1) #define push_n(n) push_n_(s,n) -#define pop_(s) ((s)->sp--) -#define pop() pop_(s) -#define pop_n(n) (s->sp-=(n)) +#define pop() pop_n_(s,1) +#define pop_n(n) pop_n_(s,n) #define cursp() (s->sp) static inline int @@ -644,8 +664,12 @@ node_len(node *tree) return n; } +#define nint(x) ((int)(intptr_t)(x)) +#define nchar(x) ((char)(intptr_t)(x)) #define nsym(x) ((mrb_sym)(intptr_t)(x)) + #define lv_name(lv) nsym((lv)->car) + static int lv_idx(codegen_scope *s, mrb_sym id) { @@ -694,7 +718,7 @@ for_body(codegen_scope *s, node *tree) /* loop body */ codegen(s, tree->cdr->cdr->car, VAL); pop(); - genop_1(s, OP_RETURN, cursp()); + gen_return(s, OP_RETURN, cursp()); loop_pop(s, NOVAL); scope_finish(s); s = prev; @@ -726,32 +750,44 @@ lambda_body(codegen_scope *s, node *tree, int blk) int ma, oa, ra, pa, ka, kd, ba; int pos, i; node *n, *opt; + node *tail; + /* mandatory arguments */ ma = node_len(tree->car->car); n = tree->car->car; while (n) { n = n->cdr; } + tail = tree->car->cdr->cdr->cdr->cdr; + + /* optional arguments */ oa = node_len(tree->car->cdr->car); + /* rest argument? */ ra = tree->car->cdr->cdr->car ? 1 : 0; + /* mandatory arugments after rest argument */ pa = node_len(tree->car->cdr->cdr->cdr->car); - ka = kd = 0; - ba = tree->car->cdr->cdr->cdr->cdr ? 1 : 0; - + /* keyword arguments */ + ka = tail? node_len(tail->cdr->car) : 0; + /* keyword dictionary? */ + kd = tail && tail->cdr->cdr->car? 1 : 0; + /* block argument? */ + ba = tail && tail->cdr->cdr->cdr->car ? 1 : 0; + if (ma > 0x1f || oa > 0x1f || pa > 0x1f || ka > 0x1f) { codegen_error(s, "too many formal arguments"); } - a = ((mrb_aspec)(ma & 0x1f) << 18) - | ((mrb_aspec)(oa & 0x1f) << 13) - | ((ra & 1) << 12) - | ((pa & 0x1f) << 7) - | ((ka & 0x1f) << 2) - | ((kd & 1)<< 1) - | (ba & 1); - s->ainfo = (((ma+oa) & 0x3f) << 6) /* (12bits = 6:1:5) */ - | ((ra & 1) << 5) - | (pa & 0x1f); + a = MRB_ARGS_REQ(ma) + | MRB_ARGS_OPT(oa) + | (ra? MRB_ARGS_REST() : 0) + | MRB_ARGS_POST(pa) + | MRB_ARGS_KEY(ka, kd) + | (ba? MRB_ARGS_BLOCK() : 0); + s->ainfo = (((ma+oa) & 0x3f) << 7) /* (12bits = 5:1:5:1) */ + | ((ra & 0x1) << 6) + | ((pa & 0x1f) << 1) + | (kd & 0x1); genop_W(s, OP_ENTER, a); + /* generate jump table for optional arguments initializer */ pos = new_label(s); for (i=0; i 0) { dispatch(s, pos+i*3+1); } + + if (tail) { + node *kwds = tail->cdr->car; + int kwrest = 0; + + if (tail->cdr->cdr->car) { + kwrest = 1; + } + mrb_assert(nint(tail->car) == NODE_ARGS_TAIL); + mrb_assert(node_len(tail) == 4); + + while (kwds) { + int jmpif_key_p, jmp_def_set = -1; + node *kwd = kwds->car, *def_arg = kwd->cdr->cdr->car; + mrb_sym kwd_sym = nsym(kwd->cdr->car); + + mrb_assert(nint(kwd->car) == NODE_KW_ARG); + + if (def_arg) { + genop_2(s, OP_KEY_P, cursp(), new_sym(s, kwd_sym)); + jmpif_key_p = genjmp2(s, OP_JMPIF, cursp(), 0, 0); + codegen(s, def_arg, VAL); + pop(); + gen_move(s, lv_idx(s, kwd_sym), cursp(), 0); + jmp_def_set = genjmp(s, OP_JMP, 0); + dispatch(s, jmpif_key_p); + } + genop_2(s, OP_KARG, lv_idx(s, kwd_sym), new_sym(s, kwd_sym)); + if (jmp_def_set != -1) { + dispatch(s, jmp_def_set); + } + i++; + + kwds = kwds->cdr; + } + if (tail->cdr->car && !kwrest) { + genop_0(s, OP_KEYEND); + } + } } codegen(s, tree->cdr->car, VAL); pop(); if (s->pc > 0) { - genop_1(s, OP_RETURN, cursp()); + gen_return(s, OP_RETURN, cursp()); } if (blk) { loop_pop(s, NOVAL); @@ -798,7 +873,7 @@ scope_body(codegen_scope *s, node *tree, int val) } codegen(scope, tree->cdr, VAL); - genop_1(scope, OP_RETURN, scope->sp-1); + gen_return(scope, OP_RETURN, scope->sp-1); if (!s->iseq) { genop_0(scope, OP_STOP); } @@ -810,9 +885,6 @@ scope_body(codegen_scope *s, node *tree, int val) return s->irep->rlen - 1; } -#define nint(x) ((int)(intptr_t)(x)) -#define nchar(x) ((char)(intptr_t)(x)) - static mrb_bool nosplat(node *t) { @@ -1703,11 +1775,18 @@ codegen(codegen_scope *s, node *tree, int val) break; case NODE_HASH: + case NODE_KW_HASH: { int len = 0; mrb_bool update = FALSE; while (tree) { + if (nt == NODE_KW_HASH && + nint(tree->car->car->car) == NODE_KW_REST_ARGS) { + tree = tree->cdr; + continue; + } + codegen(s, tree->car->car, val); codegen(s, tree->car->cdr, val); len++; @@ -2055,10 +2134,10 @@ codegen(codegen_scope *s, node *tree, int val) genop_1(s, OP_LOADNIL, cursp()); } if (s->loop) { - genop_1(s, OP_RETURN_BLK, cursp()); + gen_return(s, OP_RETURN_BLK, cursp()); } else { - genop_1(s, OP_RETURN, cursp()); + gen_return(s, OP_RETURN, cursp()); } if (val) push(); break; @@ -2116,7 +2195,7 @@ codegen(codegen_scope *s, node *tree, int val) else { genop_1(s, OP_LOADNIL, cursp()); } - genop_1(s, OP_RETURN, cursp()); + gen_return(s, OP_RETURN, cursp()); } if (val) push(); break; @@ -2999,7 +3078,7 @@ loop_break(codegen_scope *s, node *tree) if (!tree) { genop_1(s, OP_LOADNIL, cursp()); } - genop_1(s, OP_BREAK, cursp()); + gen_return(s, OP_BREAK, cursp()); } } } diff --git a/mrbgems/mruby-compiler/core/node.h b/mrbgems/mruby-compiler/core/node.h index 9636dd759..af71332e7 100644 --- a/mrbgems/mruby-compiler/core/node.h +++ b/mrbgems/mruby-compiler/core/node.h @@ -46,6 +46,7 @@ enum node_type { NODE_ARRAY, NODE_ZARRAY, NODE_HASH, + NODE_KW_HASH, NODE_RETURN, NODE_YIELD, NODE_LVAR, @@ -73,6 +74,9 @@ enum node_type { NODE_DREGX_ONCE, NODE_LIST, NODE_ARG, + NODE_ARGS_TAIL, + NODE_KW_ARG, + NODE_KW_REST_ARGS, NODE_ARGSCAT, NODE_ARGSPUSH, NODE_SPLAT, diff --git a/mrbgems/mruby-compiler/core/parse.y b/mrbgems/mruby-compiler/core/parse.y index 61d94edc9..44cb28608 100644 --- a/mrbgems/mruby-compiler/core/parse.y +++ b/mrbgems/mruby-compiler/core/parse.y @@ -568,6 +568,13 @@ new_hash(parser_state *p, node *a) return cons((node*)NODE_HASH, a); } +/* (:kw_hash (k . v) (k . v)...) */ +static node* +new_kw_hash(parser_state *p, node *a) +{ + return cons((node*)NODE_KW_HASH, a); +} + /* (:sym . a) */ static node* new_sym(parser_state *p, mrb_sym sym) @@ -671,23 +678,61 @@ new_arg(parser_state *p, mrb_sym sym) return cons((node*)NODE_ARG, nsym(sym)); } -/* (m o r m2 b) */ +/* (m o r m2 tail) */ /* m: (a b c) */ /* o: ((a . e1) (b . e2)) */ /* r: a */ /* m2: (a b c) */ /* b: a */ static node* -new_args(parser_state *p, node *m, node *opt, mrb_sym rest, node *m2, mrb_sym blk) +new_args(parser_state *p, node *m, node *opt, mrb_sym rest, node *m2, node *tail) { node *n; - n = cons(m2, nsym(blk)); + n = cons(m2, tail); n = cons(nsym(rest), n); n = cons(opt, n); return cons(m, n); } +/* (:args_tail keywords rest_keywords_sym block_sym) */ +static node* +new_args_tail(parser_state *p, node *kws, node *kwrest, mrb_sym blk) +{ + node *k; + + /* allocate register for keywords hash */ + if (kws || kwrest) { + local_add_f(p, (kwrest && kwrest->cdr)? sym(kwrest->cdr) : mrb_intern_lit(p->mrb, "**")); + } + + /* allocate register for block */ + local_add_f(p, blk? blk : mrb_intern_lit(p->mrb, "&")); + + // allocate register for keywords arguments + // order is for Proc#parameters + for (k = kws; k; k = k->cdr) { + if (!k->car->cdr->cdr->car) { // allocate required keywords + local_add_f(p, sym(k->car->cdr->car)); + } + } + for (k = kws; k; k = k->cdr) { + if (k->car->cdr->cdr->car) { // allocate keywords with default + local_add_f(p, sym(k->car->cdr->car)); + } + } + + return list4((node*)NODE_ARGS_TAIL, kws, kwrest, nsym(blk)); +} + +/* (:kw_arg kw_sym def_arg) */ +static node* +new_kw_arg(parser_state *p, mrb_sym kw, node *def_arg) +{ + mrb_assert(kw); + return list3((node*)NODE_KW_ARG, nsym(kw), def_arg); +} + /* (:block_arg . a) */ static node* new_block_arg(parser_state *p, node *a) @@ -1134,6 +1179,10 @@ heredoc_end(parser_state *p) %type heredoc words symbols %type call_op call_op2 /* 0:'&.', 1:'.', 2:'::' */ +%type args_tail opt_args_tail f_kwarg f_kw arg_value f_kwrest +%type f_block_kwarg f_block_kw block_args_tail opt_block_args_tail +%type f_label + %token tUPLUS /* unary+ */ %token tUMINUS /* unary- */ %token tPOW /* ** */ @@ -1159,6 +1208,7 @@ heredoc_end(parser_state *p) %token tLBRACE /* { */ %token tLBRACE_ARG /* { */ %token tSTAR /* * */ +%token tDSTAR /* ** */ %token tAMPER /* & */ %token tLAMBDA /* -> */ %token tANDDOT /* &. */ @@ -1736,6 +1786,7 @@ op : '|' { $$ = intern_c('|'); } | '/' { $$ = intern_c('/'); } | '%' { $$ = intern_c('%'); } | tPOW { $$ = intern("**",2); } + | tDSTAR { $$ = intern("**",2); } | '!' { $$ = intern_c('!'); } | '~' { $$ = intern_c('~'); } | tUPLUS { $$ = intern("+@",2); } @@ -1944,11 +1995,11 @@ aref_args : none } | args comma assocs trailer { - $$ = push($1, new_hash(p, $3)); + $$ = push($1, new_kw_hash(p, $3)); } | assocs trailer { - $$ = cons(new_hash(p, $1), 0); + $$ = cons(new_kw_hash(p, $1), 0); NODE_LINENO($$, $1); } ; @@ -1984,12 +2035,12 @@ opt_call_args : none } | args comma assocs ',' { - $$ = cons(push($1, new_hash(p, $3)), 0); + $$ = cons(push($1, new_kw_hash(p, $3)), 0); NODE_LINENO($$, $1); } | assocs ',' { - $$ = cons(list1(new_hash(p, $1)), 0); + $$ = cons(list1(new_kw_hash(p, $1)), 0); NODE_LINENO($$, $1); } ; @@ -2007,12 +2058,12 @@ call_args : command } | assocs opt_block_arg { - $$ = cons(list1(new_hash(p, $1)), $2); + $$ = cons(list1(new_kw_hash(p, $1)), $2); NODE_LINENO($$, $1); } | args comma assocs opt_block_arg { - $$ = cons(push($1, new_hash(p, $3)), $4); + $$ = cons(push($1, new_kw_hash(p, $3)), $4); NODE_LINENO($$, $1); } | block_arg @@ -2451,23 +2502,51 @@ f_margs : f_marg_list } ; -block_param : f_arg ',' f_block_optarg ',' f_rest_arg opt_f_block_arg +block_args_tail : f_block_kwarg ',' f_kwrest opt_f_block_arg + { + $$ = new_args_tail(p, $1, $3, $4); + } + | f_block_kwarg opt_f_block_arg + { + $$ = new_args_tail(p, $1, 0, $2); + } + | f_kwrest opt_f_block_arg + { + $$ = new_args_tail(p, 0, $1, $2); + } + | f_block_arg + { + $$ = new_args_tail(p, 0, 0, $1); + } + ; + +opt_block_args_tail : ',' block_args_tail + { + $$ = $2; + } + | /* none */ + { + $$ = new_args_tail(p, 0, 0, 0); + } + ; + +block_param : f_arg ',' f_block_optarg ',' f_rest_arg opt_block_args_tail { $$ = new_args(p, $1, $3, $5, 0, $6); } - | f_arg ',' f_block_optarg ',' f_rest_arg ',' f_arg opt_f_block_arg + | f_arg ',' f_block_optarg ',' f_rest_arg ',' f_arg opt_block_args_tail { $$ = new_args(p, $1, $3, $5, $7, $8); } - | f_arg ',' f_block_optarg opt_f_block_arg + | f_arg ',' f_block_optarg opt_block_args_tail { $$ = new_args(p, $1, $3, 0, 0, $4); } - | f_arg ',' f_block_optarg ',' f_arg opt_f_block_arg + | f_arg ',' f_block_optarg ',' f_arg opt_block_args_tail { $$ = new_args(p, $1, $3, 0, $5, $6); } - | f_arg ',' f_rest_arg opt_f_block_arg + | f_arg ',' f_rest_arg opt_block_args_tail { $$ = new_args(p, $1, 0, $3, 0, $4); } @@ -2475,39 +2554,39 @@ block_param : f_arg ',' f_block_optarg ',' f_rest_arg opt_f_block_arg { $$ = new_args(p, $1, 0, 0, 0, 0); } - | f_arg ',' f_rest_arg ',' f_arg opt_f_block_arg + | f_arg ',' f_rest_arg ',' f_arg opt_block_args_tail { $$ = new_args(p, $1, 0, $3, $5, $6); } - | f_arg opt_f_block_arg + | f_arg opt_block_args_tail { $$ = new_args(p, $1, 0, 0, 0, $2); } - | f_block_optarg ',' f_rest_arg opt_f_block_arg + | f_block_optarg ',' f_rest_arg opt_block_args_tail { $$ = new_args(p, 0, $1, $3, 0, $4); } - | f_block_optarg ',' f_rest_arg ',' f_arg opt_f_block_arg + | f_block_optarg ',' f_rest_arg ',' f_arg opt_block_args_tail { $$ = new_args(p, 0, $1, $3, $5, $6); } - | f_block_optarg opt_f_block_arg + | f_block_optarg opt_block_args_tail { $$ = new_args(p, 0, $1, 0, 0, $2); } - | f_block_optarg ',' f_arg opt_f_block_arg + | f_block_optarg ',' f_arg opt_block_args_tail { $$ = new_args(p, 0, $1, 0, $3, $4); } - | f_rest_arg opt_f_block_arg + | f_rest_arg opt_block_args_tail { $$ = new_args(p, 0, 0, $1, 0, $2); } - | f_rest_arg ',' f_arg opt_f_block_arg + | f_rest_arg ',' f_arg opt_block_args_tail { $$ = new_args(p, 0, 0, $1, $3, $4); } - | f_block_arg + | block_args_tail { $$ = new_args(p, 0, 0, 0, 0, $1); } @@ -3021,65 +3100,153 @@ f_arglist : '(' f_args rparen } ; -f_args : f_arg ',' f_optarg ',' f_rest_arg opt_f_block_arg +f_label : tIDENTIFIER tLABEL_TAG + ; + +arg_value : arg + ; + +f_kw : f_label arg_value + { + $$ = new_kw_arg(p, $1, $2); + } + | f_label + { + $$ = new_kw_arg(p, $1, 0); + } + ; + +f_block_kw : f_label primary_value + { + $$ = new_kw_arg(p, $1, $2); + } + | f_label + { + $$ = new_kw_arg(p, $1, 0); + } + ; + +f_block_kwarg : f_block_kw + { + $$ = list1($1); + } + | f_block_kwarg ',' f_block_kw + { + $$ = push($1, $3); + } + ; + +f_kwarg : f_kw + { + $$ = list1($1); + } + | f_kwarg ',' f_kw + { + $$ = push($1, $3); + } + ; + +kwrest_mark : tPOW + | tDSTAR + ; + +f_kwrest : kwrest_mark tIDENTIFIER + { + $$ = cons((node*)NODE_KW_REST_ARGS, nsym($2)); + } + | kwrest_mark + { + $$ = cons((node*)NODE_KW_REST_ARGS, 0); + } + ; + +args_tail : f_kwarg ',' f_kwrest opt_f_block_arg + { + $$ = new_args_tail(p, $1, $3, $4); + } + | f_kwarg opt_f_block_arg + { + $$ = new_args_tail(p, $1, 0, $2); + } + | f_kwrest opt_f_block_arg + { + $$ = new_args_tail(p, 0, $1, $2); + } + | f_block_arg + { + $$ = new_args_tail(p, 0, 0, $1); + } + ; + +opt_args_tail : ',' args_tail + { + $$ = $2; + } + | /* none */ + { + $$ = new_args_tail(p, 0, 0, 0); + } + ; + +f_args : f_arg ',' f_optarg ',' f_rest_arg opt_args_tail { $$ = new_args(p, $1, $3, $5, 0, $6); } - | f_arg ',' f_optarg ',' f_rest_arg ',' f_arg opt_f_block_arg + | f_arg ',' f_optarg ',' f_rest_arg ',' f_arg opt_args_tail { $$ = new_args(p, $1, $3, $5, $7, $8); } - | f_arg ',' f_optarg opt_f_block_arg + | f_arg ',' f_optarg opt_args_tail { $$ = new_args(p, $1, $3, 0, 0, $4); } - | f_arg ',' f_optarg ',' f_arg opt_f_block_arg + | f_arg ',' f_optarg ',' f_arg opt_args_tail { $$ = new_args(p, $1, $3, 0, $5, $6); } - | f_arg ',' f_rest_arg opt_f_block_arg + | f_arg ',' f_rest_arg opt_args_tail { $$ = new_args(p, $1, 0, $3, 0, $4); } - | f_arg ',' f_rest_arg ',' f_arg opt_f_block_arg + | f_arg ',' f_rest_arg ',' f_arg opt_args_tail { $$ = new_args(p, $1, 0, $3, $5, $6); } - | f_arg opt_f_block_arg + | f_arg opt_args_tail { $$ = new_args(p, $1, 0, 0, 0, $2); } - | f_optarg ',' f_rest_arg opt_f_block_arg + | f_optarg ',' f_rest_arg opt_args_tail { $$ = new_args(p, 0, $1, $3, 0, $4); } - | f_optarg ',' f_rest_arg ',' f_arg opt_f_block_arg + | f_optarg ',' f_rest_arg ',' f_arg opt_args_tail { $$ = new_args(p, 0, $1, $3, $5, $6); } - | f_optarg opt_f_block_arg + | f_optarg opt_args_tail { $$ = new_args(p, 0, $1, 0, 0, $2); } - | f_optarg ',' f_arg opt_f_block_arg + | f_optarg ',' f_arg opt_args_tail { $$ = new_args(p, 0, $1, 0, $3, $4); } - | f_rest_arg opt_f_block_arg + | f_rest_arg opt_args_tail { $$ = new_args(p, 0, 0, $1, 0, $2); } - | f_rest_arg ',' f_arg opt_f_block_arg + | f_rest_arg ',' f_arg opt_args_tail { $$ = new_args(p, 0, 0, $1, $3, $4); } - | f_block_arg + | args_tail { $$ = new_args(p, 0, 0, 0, 0, $1); } | /* none */ { - local_add_f(p, 0); + local_add_f(p, mrb_intern_lit(p->mrb, "&")); $$ = new_args(p, 0, 0, 0, 0, 0); } ; @@ -3189,7 +3356,7 @@ f_rest_arg : restarg_mark tIDENTIFIER } | restarg_mark { - local_add_f(p, 0); + local_add_f(p, mrb_intern_lit(p->mrb, "*")); $$ = -1; } ; @@ -3200,7 +3367,6 @@ blkarg_mark : '&' f_block_arg : blkarg_mark tIDENTIFIER { - local_add_f(p, $2); $$ = $2; } ; @@ -3211,7 +3377,6 @@ opt_f_block_arg : ',' f_block_arg } | none { - local_add_f(p, 0); $$ = 0; } ; @@ -3285,6 +3450,10 @@ assoc : arg tASSOC arg $$ = cons(new_sym(p, new_strsym(p, $1)), $3); } } + | tDSTAR arg_value + { + $$ = cons(cons((node*)NODE_KW_REST_ARGS, 0), $2); + } ; operation : tIDENTIFIER @@ -3450,13 +3619,13 @@ backref_error(parser_state *p, node *n) { int c; - c = (int)(intptr_t)n->car; + c = intn(n->car); if (c == NODE_NTH_REF) { - yyerror_i(p, "can't set variable $%" MRB_PRId, (int)(intptr_t)n->cdr); + yyerror_i(p, "can't set variable $%" MRB_PRId, intn(n->cdr)); } else if (c == NODE_BACK_REF) { - yyerror_i(p, "can't set variable $%c", (int)(intptr_t)n->cdr); + yyerror_i(p, "can't set variable $%c", intn(n->cdr)); } else { mrb_bug(p->mrb, "Internal error in backref_error() : n=>car == %S", mrb_fixnum_value(c)); @@ -3469,7 +3638,7 @@ void_expr_error(parser_state *p, node *n) int c; if (n == NULL) return; - c = (int)(intptr_t)n->car; + c = intn(n->car); switch (c) { case NODE_BREAK: case NODE_RETURN: @@ -3508,7 +3677,7 @@ nextc(parser_state *p) if (p->pb) { node *tmp; - c = (int)(intptr_t)p->pb->car; + c = intn(p->pb->car); tmp = p->pb; p->pb = p->pb->cdr; cons_free(tmp); @@ -3557,7 +3726,7 @@ pushback(parser_state *p, int c) if (c >= 0) { p->column--; } - p->pb = cons((node*)(intptr_t)c, p->pb); + p->pb = cons(nint(c), p->pb); } static void @@ -3582,7 +3751,7 @@ peekc_n(parser_state *p, int n) c0 = nextc(p); if (c0 == -1) return c0; /* do not skip partial EOF */ if (c0 >= 0) --p->column; - list = push(list, (node*)(intptr_t)c0); + list = push(list, nint(c0)); } while(n--); if (p->pb) { p->pb = append((node*)list, p->pb); @@ -4019,11 +4188,11 @@ parse_string(parser_state *p) } else if (c == beg) { nest_level++; - p->lex_strterm->cdr->car = (node*)(intptr_t)nest_level; + p->lex_strterm->cdr->car = nint(nest_level); } else if (c == end) { nest_level--; - p->lex_strterm->cdr->car = (node*)(intptr_t)nest_level; + p->lex_strterm->cdr->car = nint(nest_level); } else if (c == '\\') { c = nextc(p); @@ -4365,7 +4534,16 @@ parser_yylex(parser_state *p) return tOP_ASGN; } pushback(p, c); - c = tPOW; + if (IS_SPCARG(c)) { + yywarning(p, "`**' interpreted as argument prefix"); + c = tDSTAR; + } + else if (IS_BEG()) { + c = tDSTAR; + } + else { + c = tPOW; /* "**", "argument prefix" */ + } } else { if (c == '=') { @@ -5547,7 +5725,7 @@ parser_update_cxt(parser_state *p, mrbc_context *cxt) int i = 0; if (!cxt) return; - if ((int)(intptr_t)p->tree->car != NODE_SCOPE) return; + if (intn(p->tree->car) != NODE_SCOPE) return; n0 = n = p->tree->cdr->car; while (n) { i++; @@ -5897,6 +6075,48 @@ dump_recur(mrb_state *mrb, node *tree, int offset) } } +static void +dump_args(mrb_state *mrb, node *n, int offset) +{ + if (n->car) { + dump_prefix(n, offset+1); + printf("mandatory args:\n"); + dump_recur(mrb, n->car, offset+2); + } + n = n->cdr; + if (n->car) { + dump_prefix(n, offset+1); + printf("optional args:\n"); + { + node *n2 = n->car; + + while (n2) { + dump_prefix(n2, offset+2); + printf("%s=\n", mrb_sym2name(mrb, sym(n2->car->car))); + mrb_parser_dump(mrb, n2->car->cdr, offset+3); + n2 = n2->cdr; + } + } + } + n = n->cdr; + if (n->car) { + dump_prefix(n, offset+1); + printf("rest=*%s\n", mrb_sym2name(mrb, sym(n->car))); + } + n = n->cdr; + if (n->car) { + dump_prefix(n, offset+1); + printf("post mandatory args:\n"); + dump_recur(mrb, n->car, offset+2); + } + + n = n->cdr; + if (n) { + mrb_assert(intn(n->car) == NODE_ARGS_TAIL); + mrb_parser_dump(mrb, n, offset); + } +} + #endif void @@ -5908,7 +6128,7 @@ mrb_parser_dump(mrb_state *mrb, node *tree, int offset) if (!tree) return; again: dump_prefix(tree, offset); - nodetype = (int)(intptr_t)tree->car; + nodetype = intn(tree->car); tree = tree->cdr; switch (nodetype) { case NODE_BEGIN: @@ -5968,7 +6188,8 @@ mrb_parser_dump(mrb_state *mrb, node *tree, int offset) break; case NODE_LAMBDA: - printf("NODE_BLOCK:\n"); + printf("NODE_LAMBDA:\n"); + dump_prefix(tree, offset); goto block; case NODE_BLOCK: @@ -5976,43 +6197,7 @@ mrb_parser_dump(mrb_state *mrb, node *tree, int offset) printf("NODE_BLOCK:\n"); tree = tree->cdr; if (tree->car) { - node *n = tree->car; - - if (n->car) { - dump_prefix(n, offset+1); - printf("mandatory args:\n"); - dump_recur(mrb, n->car, offset+2); - } - n = n->cdr; - if (n->car) { - dump_prefix(n, offset+1); - printf("optional args:\n"); - { - node *n2 = n->car; - - while (n2) { - dump_prefix(n2, offset+2); - printf("%s=", mrb_sym2name(mrb, sym(n2->car->car))); - mrb_parser_dump(mrb, n2->car->cdr, 0); - n2 = n2->cdr; - } - } - } - n = n->cdr; - if (n->car) { - dump_prefix(n, offset+1); - printf("rest=*%s\n", mrb_sym2name(mrb, sym(n->car))); - } - n = n->cdr; - if (n->car) { - dump_prefix(n, offset+1); - printf("post mandatory args:\n"); - dump_recur(mrb, n->car, offset+2); - } - if (n->cdr) { - dump_prefix(n, offset+1); - printf("blk=&%s\n", mrb_sym2name(mrb, sym(n->cdr))); - } + dump_args(mrb, tree->car, offset+1); } dump_prefix(tree, offset+1); printf("body:\n"); @@ -6164,7 +6349,7 @@ mrb_parser_dump(mrb_state *mrb, node *tree, int offset) dump_prefix(tree, offset+1); printf("method='%s' (%d)\n", mrb_sym2name(mrb, sym(tree->cdr->car)), - (int)(intptr_t)tree->cdr->car); + intn(tree->cdr->car)); tree = tree->cdr->cdr->car; if (tree) { dump_prefix(tree, offset+1); @@ -6281,7 +6466,7 @@ mrb_parser_dump(mrb_state *mrb, node *tree, int offset) mrb_parser_dump(mrb, tree->car, offset+2); tree = tree->cdr; dump_prefix(tree, offset+1); - printf("op='%s' (%d)\n", mrb_sym2name(mrb, sym(tree->car)), (int)(intptr_t)tree->car); + printf("op='%s' (%d)\n", mrb_sym2name(mrb, sym(tree->car)), intn(tree->car)); tree = tree->cdr; mrb_parser_dump(mrb, tree->car, offset+1); break; @@ -6363,11 +6548,11 @@ mrb_parser_dump(mrb_state *mrb, node *tree, int offset) break; case NODE_BACK_REF: - printf("NODE_BACK_REF: $%c\n", (int)(intptr_t)tree); + printf("NODE_BACK_REF: $%c\n", intn(tree)); break; case NODE_NTH_REF: - printf("NODE_NTH_REF: $%" MRB_PRId "\n", (mrb_int)(intptr_t)tree); + printf("NODE_NTH_REF: $%d\n", intn(tree)); break; case NODE_ARG: @@ -6380,7 +6565,7 @@ mrb_parser_dump(mrb_state *mrb, node *tree, int offset) break; case NODE_INT: - printf("NODE_INT %s base %d\n", (char*)tree->car, (int)(intptr_t)tree->cdr->car); + printf("NODE_INT %s base %d\n", (char*)tree->car, intn(tree->cdr->car)); break; case NODE_FLOAT: @@ -6393,7 +6578,7 @@ mrb_parser_dump(mrb_state *mrb, node *tree, int offset) break; case NODE_STR: - printf("NODE_STR \"%s\" len %d\n", (char*)tree->car, (int)(intptr_t)tree->cdr); + printf("NODE_STR \"%s\" len %d\n", (char*)tree->car, intn(tree->cdr)); break; case NODE_DSTR: @@ -6402,7 +6587,7 @@ mrb_parser_dump(mrb_state *mrb, node *tree, int offset) break; case NODE_XSTR: - printf("NODE_XSTR \"%s\" len %d\n", (char*)tree->car, (int)(intptr_t)tree->cdr); + printf("NODE_XSTR \"%s\" len %d\n", (char*)tree->car, intn(tree->cdr)); break; case NODE_DXSTR: @@ -6431,7 +6616,7 @@ mrb_parser_dump(mrb_state *mrb, node *tree, int offset) case NODE_SYM: printf("NODE_SYM :%s (%d)\n", mrb_sym2name(mrb, sym(tree)), - (int)(intptr_t)tree); + intn(tree)); break; case NODE_SELF: @@ -6547,43 +6732,7 @@ mrb_parser_dump(mrb_state *mrb, node *tree, int offset) } tree = tree->cdr; if (tree->car) { - node *n = tree->car; - - if (n->car) { - dump_prefix(n, offset+1); - printf("mandatory args:\n"); - dump_recur(mrb, n->car, offset+2); - } - n = n->cdr; - if (n->car) { - dump_prefix(n, offset+1); - printf("optional args:\n"); - { - node *n2 = n->car; - - while (n2) { - dump_prefix(n2, offset+2); - printf("%s=", mrb_sym2name(mrb, sym(n2->car->car))); - mrb_parser_dump(mrb, n2->car->cdr, 0); - n2 = n2->cdr; - } - } - } - n = n->cdr; - if (n->car) { - dump_prefix(n, offset+1); - printf("rest=*%s\n", mrb_sym2name(mrb, sym(n->car))); - } - n = n->cdr; - if (n->car) { - dump_prefix(n, offset+1); - printf("post mandatory args:\n"); - dump_recur(mrb, n->car, offset+2); - } - if (n->cdr) { - dump_prefix(n, offset+1); - printf("blk=&%s\n", mrb_sym2name(mrb, sym(n->cdr))); - } + dump_args(mrb, tree->car, offset); } mrb_parser_dump(mrb, tree->cdr->car, offset+1); break; @@ -6596,44 +6745,7 @@ mrb_parser_dump(mrb_state *mrb, node *tree, int offset) printf(":%s\n", mrb_sym2name(mrb, sym(tree->car))); tree = tree->cdr->cdr; if (tree->car) { - node *n = tree->car; - - if (n->car) { - dump_prefix(n, offset+1); - printf("mandatory args:\n"); - dump_recur(mrb, n->car, offset+2); - } - n = n->cdr; - if (n->car) { - dump_prefix(n, offset+1); - printf("optional args:\n"); - { - node *n2 = n->car; - - while (n2) { - dump_prefix(n2, offset+2); - printf("%s=", mrb_sym2name(mrb, sym(n2->car->car))); - mrb_parser_dump(mrb, n2->car->cdr, 0); - n2 = n2->cdr; - } - } - } - n = n->cdr; - if (n->car) { - dump_prefix(n, offset+1); - printf("rest=*%s\n", mrb_sym2name(mrb, sym(n->car))); - } - n = n->cdr; - if (n->car) { - dump_prefix(n, offset+1); - printf("post mandatory args:\n"); - dump_recur(mrb, n->car, offset+2); - } - n = n->cdr; - if (n) { - dump_prefix(n, offset+1); - printf("blk=&%s\n", mrb_sym2name(mrb, sym(n))); - } + dump_args(mrb, tree->car, offset+1); } tree = tree->cdr; mrb_parser_dump(mrb, tree->car, offset+1); @@ -6649,18 +6761,35 @@ mrb_parser_dump(mrb_state *mrb, node *tree, int offset) dump_recur(mrb, ((parser_heredoc_info*)tree)->doc, offset+1); break; - case NODE_LITERAL_DELIM: - printf("NODE_LITERAL_DELIM\n"); + case NODE_ARGS_TAIL: + printf("NODE_ARGS_TAIL:\n"); + { + node *kws = tree->car; + + while (kws) { + mrb_parser_dump(mrb, kws->car, offset+1); + kws = kws->cdr; + } + } + tree = tree->cdr; + if (tree->car) { + mrb_assert(intn(tree->car->car) == NODE_KW_REST_ARGS); + mrb_parser_dump(mrb, tree->car, offset+1); + } + tree = tree->cdr; + if (tree->car) { + dump_prefix(tree, offset+1); + printf("block='%s'\n", mrb_sym2name(mrb, sym(tree->car))); + } break; - case NODE_SYMBOLS: - printf("NODE_SYMBOLS:\n"); - dump_recur(mrb, tree, offset+1); + case NODE_KW_ARG: + printf("NODE_KW_ARG %s\n", mrb_sym2name(mrb, sym(tree->car))); + mrb_parser_dump(mrb, tree->cdr->car, offset + 1); break; - case NODE_WORDS: - printf("NODE_SYMBOLS:\n"); - dump_recur(mrb, tree, offset+1); + case NODE_KW_REST_ARGS: + printf("NODE_KW_REST_ARGS %s\n", mrb_sym2name(mrb, sym(tree))); break; default: diff --git a/mrbgems/mruby-objectspace/src/mruby_objectspace.c b/mrbgems/mruby-objectspace/src/mruby_objectspace.c index 3887091d3..b31dee04c 100644 --- a/mrbgems/mruby-objectspace/src/mruby_objectspace.c +++ b/mrbgems/mruby-objectspace/src/mruby_objectspace.c @@ -57,7 +57,7 @@ os_count_objects(mrb_state *mrb, mrb_value self) hash = mrb_hash_new(mrb); } - if (!mrb_test(mrb_hash_empty_p(mrb, hash))) { + if (!mrb_hash_empty_p(mrb, hash)) { mrb_hash_clear(mrb, hash); } diff --git a/mrbgems/mruby-proc-ext/src/proc.c b/mrbgems/mruby-proc-ext/src/proc.c index 323529dcc..9ce6c1831 100644 --- a/mrbgems/mruby-proc-ext/src/proc.c +++ b/mrbgems/mruby-proc-ext/src/proc.c @@ -149,7 +149,15 @@ mrb_proc_parameters(mrb_state *mrb, mrb_value self) a = mrb_ary_new(mrb); mrb_ary_push(mrb, a, sname); if (i < max && irep->lv[i].name) { - mrb_ary_push(mrb, a, mrb_symbol_value(irep->lv[i].name)); + mrb_sym sym = irep->lv[i].name; + const char *name = mrb_sym2name(mrb, sym); + switch (name[0]) { + case '*': case '&': + break; + default: + mrb_ary_push(mrb, a, mrb_symbol_value(sym)); + break; + } } mrb_ary_push(mrb, parameters, a); } diff --git a/src/codedump.c b/src/codedump.c index 22cbc59eb..dc0e0e548 100644 --- a/src/codedump.c +++ b/src/codedump.c @@ -78,6 +78,16 @@ codedump(mrb_state *mrb, mrb_irep *irep) printf("irep %p nregs=%d nlocals=%d pools=%d syms=%d reps=%d\n", (void*)irep, irep->nregs, irep->nlocals, (int)irep->plen, (int)irep->slen, (int)irep->rlen); + if (irep->lv) { + int i; + + printf("local variable names:\n"); + for (i = 1; i < irep->nlocals; ++i) { + char const *n = mrb_sym2name(mrb, irep->lv[i - 1].name); + printf(" R%d:%s\n", irep->lv[i - 1].r, n? n : ""); + } + } + pc = irep->iseq; pcend = pc + irep->ilen; while (pc < pcend) { @@ -246,10 +256,11 @@ codedump(mrb_state *mrb, mrb_irep *irep) printf("OP_SUPER\tR%d\t%d\n", a, b); break; CASE(OP_ARGARY, BS): - printf("OP_ARGARY\tR%d\t%d:%d:%d:%d", a, - (b>>10)&0x3f, - (b>>9)&0x1, - (b>>4)&0x1f, + printf("OP_ARGARY\tR%d\t%d:%d:%d:%d (%d)", a, + (b>>11)&0x3f, + (b>>10)&0x1, + (b>>5)&0x1f, + (b>>4)&0x1, (b>>0)&0xf); print_lv_a(mrb, irep, a); break; @@ -263,32 +274,39 @@ codedump(mrb_state *mrb, mrb_irep *irep) (a>>1)&0x1, a & 0x1); break; - CASE(OP_KARG, BB): - printf("OP_KARG\tR(%d)\tK(%d)\n", a, b); + CASE(OP_KEY_P, BB): + printf("OP_KEY_P\tR%d\t:%s\t", a, mrb_sym2name(mrb, irep->syms[b])); + print_lv_a(mrb, irep, a); break; - CASE(OP_KARG2, BB): - printf("OP_KARG2\tR(%d)\tK(%d)\n", a, b); + CASE(OP_KEYEND, Z): + printf("OP_KEYEND\n"); + break; + CASE(OP_KARG, BB): + printf("OP_KARG\tR%d\t:%s\t", a, mrb_sym2name(mrb, irep->syms[b])); + print_lv_a(mrb, irep, a); break; CASE(OP_KDICT, B): - printf("OP_KDICt\tR(%d)\n", a); + printf("OP_KDICT\tR%d\t\t", a); + print_lv_a(mrb, irep, a); break; CASE(OP_RETURN, B): - printf("OP_RETURN\tR%d", a); + printf("OP_RETURN\tR%d\t\t", a); print_lv_a(mrb, irep, a); break; CASE(OP_RETURN_BLK, B): - printf("OP_RETURN_BLK\tR%d", a); + printf("OP_RETURN_BLK\tR%d\t\t", a); print_lv_a(mrb, irep, a); break; CASE(OP_BREAK, B): - printf("OP_BREAK\tR%d", a); + printf("OP_BREAK\tR%d\t\t", a); print_lv_a(mrb, irep, a); break; CASE(OP_BLKPUSH, BS): - printf("OP_BLKPUSH\tR%d\t%d:%d:%d:%d", a, - (b>>10)&0x3f, - (b>>9)&0x1, - (b>>4)&0x1f, + printf("OP_BLKPUSH\tR%d\t%d:%d:%d:%d (%d)", a, + (b>>11)&0x3f, + (b>>10)&0x1, + (b>>5)&0x1f, + (b>>4)&0x1, (b>>0)&0xf); print_lv_a(mrb, irep, a); break; diff --git a/src/hash.c b/src/hash.c index db9d1d9c8..0dce81677 100644 --- a/src/hash.c +++ b/src/hash.c @@ -208,6 +208,54 @@ mrb_hash_init_copy(mrb_state *mrb, mrb_value self) return vret; } +void +mrb_hash_check_kdict(mrb_state *mrb, mrb_value self) +{ + khash_t(ht) *orig_h; + khiter_t k; + int nosym = FALSE; + + orig_h = RHASH_TBL(self); + if (!orig_h || kh_size(orig_h) == 0) return; + for (k = kh_begin(orig_h); k != kh_end(orig_h); k++) { + if (kh_exist(orig_h, k)) { + mrb_value key = kh_key(orig_h, k); + + if (!mrb_symbol_p(key)) nosym = TRUE; + } + } + if (nosym) { + mrb_raise(mrb, E_ARGUMENT_ERROR, "keyword argument hash with non symbol keys"); + } +} + +MRB_API mrb_value +mrb_hash_dup(mrb_state *mrb, mrb_value self) +{ + struct RHash* copy; + khash_t(ht) *orig_h; + + orig_h = RHASH_TBL(self); + copy = (struct RHash*)mrb_obj_alloc(mrb, MRB_TT_HASH, mrb->hash_class); + copy->ht = kh_init(ht, mrb); + + if (orig_h && kh_size(orig_h) > 0) { + int ai = mrb_gc_arena_save(mrb); + khash_t(ht) *copy_h = copy->ht; + khiter_t k, copy_k; + + for (k = kh_begin(orig_h); k != kh_end(orig_h); k++) { + if (kh_exist(orig_h, k)) { + copy_k = kh_put(ht, mrb, copy_h, KEY(kh_key(orig_h, k))); + mrb_gc_arena_restore(mrb, ai); + kh_val(copy_h, copy_k).v = kh_val(orig_h, k).v; + kh_val(copy_h, copy_k).n = kh_size(copy_h)-1; + } + } + } + return mrb_obj_value(copy); +} + MRB_API mrb_value mrb_hash_get(mrb_state *mrb, mrb_value hash, mrb_value key) { @@ -716,13 +764,21 @@ mrb_hash_size_m(mrb_state *mrb, mrb_value self) * {}.empty? #=> true * */ -MRB_API mrb_value +MRB_API mrb_bool mrb_hash_empty_p(mrb_state *mrb, mrb_value self) { khash_t(ht) *h = RHASH_TBL(self); - if (h) return mrb_bool_value(kh_size(h) == 0); - return mrb_true_value(); + if (h) return kh_size(h) == 0; + return TRUE; +} + +static mrb_value +mrb_hash_empty_m(mrb_state *mrb, mrb_value self) +{ + if (mrb_hash_empty_p(mrb, self)) + return mrb_true_value(); + return mrb_false_value(); } /* 15.2.13.4.29 (x)*/ @@ -833,21 +889,29 @@ mrb_hash_values(mrb_state *mrb, mrb_value hash) * */ -static mrb_value -mrb_hash_has_key(mrb_state *mrb, mrb_value hash) +MRB_API mrb_bool +mrb_hash_key_p(mrb_state *mrb, mrb_value hash, mrb_value key) { - mrb_value key; khash_t(ht) *h; khiter_t k; - mrb_get_args(mrb, "o", &key); - h = RHASH_TBL(hash); if (h) { k = kh_get(ht, mrb, h, key); - return mrb_bool_value(k != kh_end(h)); + return k != kh_end(h); } - return mrb_false_value(); + return FALSE; +} + +static mrb_value +mrb_hash_has_key(mrb_state *mrb, mrb_value hash) +{ + mrb_value key; + mrb_bool key_p; + + mrb_get_args(mrb, "o", &key); + key_p = mrb_hash_key_p(mrb, hash, key); + return mrb_bool_value(key_p); } /* 15.2.13.4.14 */ @@ -904,7 +968,7 @@ mrb_init_hash(mrb_state *mrb) mrb_define_method(mrb, h, "default_proc", mrb_hash_default_proc,MRB_ARGS_NONE()); /* 15.2.13.4.7 */ mrb_define_method(mrb, h, "default_proc=", mrb_hash_set_default_proc,MRB_ARGS_REQ(1)); /* 15.2.13.4.7 */ mrb_define_method(mrb, h, "__delete", mrb_hash_delete, MRB_ARGS_REQ(1)); /* core of 15.2.13.4.8 */ - mrb_define_method(mrb, h, "empty?", mrb_hash_empty_p, MRB_ARGS_NONE()); /* 15.2.13.4.12 */ + mrb_define_method(mrb, h, "empty?", mrb_hash_empty_m, MRB_ARGS_NONE()); /* 15.2.13.4.12 */ mrb_define_method(mrb, h, "has_key?", mrb_hash_has_key, MRB_ARGS_REQ(1)); /* 15.2.13.4.13 */ mrb_define_method(mrb, h, "has_value?", mrb_hash_has_value, MRB_ARGS_REQ(1)); /* 15.2.13.4.14 */ mrb_define_method(mrb, h, "include?", mrb_hash_has_key, MRB_ARGS_REQ(1)); /* 15.2.13.4.15 */ diff --git a/src/kernel.c b/src/kernel.c index 155868eaa..42e9ca6a4 100644 --- a/src/kernel.c +++ b/src/kernel.c @@ -1194,7 +1194,15 @@ mrb_local_variables(mrb_state *mrb, mrb_value self) if (!irep->lv) break; for (i = 0; i + 1 < irep->nlocals; ++i) { if (irep->lv[i].name) { - mrb_hash_set(mrb, vars, mrb_symbol_value(irep->lv[i].name), mrb_true_value()); + mrb_sym sym = irep->lv[i].name; + const char *name = mrb_sym2name(mrb, sym); + switch (name[0]) { + case '*': case '&': + break; + default: + mrb_hash_set(mrb, vars, mrb_symbol_value(sym), mrb_true_value()); + break; + } } } if (!MRB_PROC_ENV_P(proc)) break; diff --git a/src/vm.c b/src/vm.c index b50f1ee9f..8aeb68fc2 100644 --- a/src/vm.c +++ b/src/vm.c @@ -969,6 +969,8 @@ check_target_class(mrb_state *mrb) return TRUE; } +void mrb_hash_check_kdict(mrb_state *mrb, mrb_value self); + MRB_API mrb_value mrb_vm_exec(mrb_state *mrb, struct RProc *proc, mrb_code *pc) { @@ -1639,9 +1641,10 @@ RETRY_TRY_BLOCK: } CASE(OP_ARGARY, BS) { - int m1 = (b>>10)&0x3f; - int r = (b>>9)&0x1; - int m2 = (b>>4)&0x1f; + int m1 = (b>>11)&0x3f; + int r = (b>>10)&0x1; + int m2 = (b>>5)&0x1f; + int kd = (b>>4)&0x1; int lv = (b>>0)&0xf; mrb_value *stack; @@ -1657,12 +1660,12 @@ RETRY_TRY_BLOCK: else { struct REnv *e = uvenv(mrb, lv-1); if (!e) goto L_NOSUPER; - if (MRB_ENV_STACK_LEN(e) <= m1+r+m2+1) + if (MRB_ENV_STACK_LEN(e) <= m1+r+m2+kd+1) goto L_NOSUPER; stack = e->stack + 1; } if (r == 0) { - regs[a] = mrb_ary_new_from_values(mrb, m1+m2, stack); + regs[a] = mrb_ary_new_from_values(mrb, m1+m2+kd, stack); } else { mrb_value *pp = NULL; @@ -1675,7 +1678,7 @@ RETRY_TRY_BLOCK: pp = ARY_PTR(ary); len = (int)ARY_LEN(ary); } - regs[a] = mrb_ary_new_capa(mrb, m1+len+m2); + regs[a] = mrb_ary_new_capa(mrb, m1+len+m2+kd); rest = mrb_ary_ptr(regs[a]); if (m1 > 0) { stack_copy(ARY_PTR(rest), stack, m1); @@ -1686,7 +1689,10 @@ RETRY_TRY_BLOCK: if (m2 > 0) { stack_copy(ARY_PTR(rest)+m1+len, stack+m1+1, m2); } - ARY_SET_LEN(rest, m1+len+m2); + if (kd) { + stack_copy(ARY_PTR(rest)+m1+len+m2, stack+m1+m2+1, kd); + } + ARY_SET_LEN(rest, m1+len+m2+kd); } regs[a+1] = stack[m1+r+m2]; mrb_gc_arena_restore(mrb, ai); @@ -1698,74 +1704,114 @@ RETRY_TRY_BLOCK: int o = MRB_ASPEC_OPT(a); int r = MRB_ASPEC_REST(a); int m2 = MRB_ASPEC_POST(a); + int kd = (MRB_ASPEC_KEY(a) > 0 || MRB_ASPEC_KDICT(a))? 1 : 0; /* unused - int k = MRB_ASPEC_KEY(a); - int kd = MRB_ASPEC_KDICT(a); int b = MRB_ASPEC_BLOCK(a); */ int argc = mrb->c->ci->argc; mrb_value *argv = regs+1; - mrb_value *argv0 = argv; - int len = m1 + o + r + m2; + mrb_value * const argv0 = argv; + int const len = m1 + o + r + m2; + int const blk_pos = len + kd + 1; mrb_value *blk = &argv[argc < 0 ? 1 : argc]; + mrb_value kdict; + int kargs = kd; + /* arguments is passed with Array */ if (argc < 0) { struct RArray *ary = mrb_ary_ptr(regs[1]); argv = ARY_PTR(ary); argc = (int)ARY_LEN(ary); mrb_gc_protect(mrb, regs[1]); } + + /* strict argument check */ if (mrb->c->ci->proc && MRB_PROC_STRICT_P(mrb->c->ci->proc)) { - if (argc >= 0) { - if (argc < m1 + m2 || (r == 0 && argc > len)) { + if (argc >= 0 && !(argc <= 1 && kd)) { + if (argc < m1 + m2 + kd || (r == 0 && argc > len + kd)) { argnum_error(mrb, m1+m2); goto L_RAISE; } } } + /* extract first argument array to arguments */ else if (len > 1 && argc == 1 && mrb_array_p(argv[0])) { mrb_gc_protect(mrb, argv[0]); argc = (int)RARRAY_LEN(argv[0]); argv = RARRAY_PTR(argv[0]); } + + if (kd) { + /* check last arguments is hash if method takes keyword arguments */ + if (argc == m1+m2) { + kdict = mrb_hash_new(mrb); + kargs = 0; + } + else { + if (!mrb_hash_p(argv[argc - 1])) { + if (r) { + kdict = mrb_hash_new(mrb); + kargs = 0; + } + else { + mrb_value str = mrb_str_new_lit(mrb, "Excepcted `Hash` as last argument for keyword arguments"); + mrb_exc_set(mrb, mrb_exc_new_str(mrb, E_ARGUMENT_ERROR, str)); + goto L_RAISE; + } + } + else { + kdict = argv[argc-1]; + } + mrb_hash_check_kdict(mrb, kdict); + if (MRB_ASPEC_KEY(a) > 0) { + kdict = mrb_hash_dup(mrb, kdict); + } + } + } + + /* no rest arguments */ if (argc < len) { int mlen = m2; if (argc < m1+m2) { - if (m1 < argc) - mlen = argc - m1; - else - mlen = 0; + mlen = m1 < argc ? argc - m1 : 0; } - regs[len+1] = *blk; /* move block */ + regs[blk_pos] = *blk; /* move block */ + if (kd) regs[len + 1] = kdict; + SET_NIL_VALUE(regs[argc+1]); + /* copy mandatory and optional arguments */ if (argv0 != argv) { value_move(®s[1], argv, argc-mlen); /* m1 + o */ } if (argc < m1) { stack_clear(®s[argc+1], m1-argc); } + /* copy post mandatory arguments */ if (mlen) { value_move(®s[len-m2+1], &argv[argc-mlen], mlen); } if (mlen < m2) { stack_clear(®s[len-m2+mlen+1], m2-mlen); } + /* initalize rest arguments with empty Array */ if (r) { regs[m1+o+1] = mrb_ary_new_capa(mrb, 0); } - if (o > 0 && argc >= m1+m2) - pc += (argc - m1 - m2)*3; + /* skip initailizer of passed arguments */ + if (o > 0 && argc-kargs >= m1+m2) + pc += (argc - kargs - m1 - m2)*3; } else { int rnum = 0; if (argv0 != argv) { - regs[len+1] = *blk; /* move block */ + regs[blk_pos] = *blk; /* move block */ + if (kd) regs[len + 1] = kdict; value_move(®s[1], argv, m1+o); } if (r) { mrb_value ary; - rnum = argc-m1-o-m2; + rnum = argc-m1-o-m2-kargs; ary = mrb_ary_new_from_values(mrb, rnum, argv+m1+o); regs[m1+o+1] = ary; } @@ -1775,29 +1821,60 @@ RETRY_TRY_BLOCK: } } if (argv0 == argv) { - regs[len+1] = *blk; /* move block */ + regs[blk_pos] = *blk; /* move block */ + if (kd) regs[len + 1] = kdict; } pc += o*3; } - mrb->c->ci->argc = len; + + /* format arguments for generated code */ + mrb->c->ci->argc = len + kd; + /* clear local (but non-argument) variables */ - if (irep->nlocals-len-2 > 0) { - stack_clear(®s[len+2], irep->nlocals-len-2); + if (irep->nlocals-blk_pos-1 > 0) { + stack_clear(®s[blk_pos+1], irep->nlocals-blk_pos-1); } JUMP; } CASE(OP_KARG, BB) { - /* not implemented yet */ + mrb_value k = mrb_symbol_value(syms[b]); + mrb_value kdict = regs[mrb->c->ci->argc]; + + if (!mrb_hash_key_p(mrb, kdict, k)) { + mrb_value str = mrb_format(mrb, "missing keyword: %S", k); + mrb_exc_set(mrb, mrb_exc_new_str(mrb, E_ARGUMENT_ERROR, str)); + goto L_RAISE; + } + regs[a] = mrb_hash_get(mrb, kdict, k); + mrb_hash_delete_key(mrb, kdict, k); NEXT; } - CASE(OP_KARG2, BB) { - /* not implemented yet */ + + CASE(OP_KEY_P, BB) { + mrb_value k = mrb_symbol_value(syms[b]); + mrb_value kdict = regs[mrb->c->ci->argc]; + mrb_bool key_p = mrb_hash_key_p(mrb, kdict, k); + + regs[a] = mrb_bool_value(key_p); + NEXT; + } + + CASE(OP_KEYEND, Z) { + mrb_value kdict = regs[mrb->c->ci->argc]; + + if (mrb_hash_p(kdict) && !mrb_hash_empty_p(mrb, kdict)) { + mrb_value keys = mrb_hash_keys(mrb, kdict); + mrb_value key1 = RARRAY_PTR(keys)[0]; + mrb_value str = mrb_format(mrb, "unknown keyword: %S", key1); + mrb_exc_set(mrb, mrb_exc_new_str(mrb, E_ARGUMENT_ERROR, str)); + goto L_RAISE; + } NEXT; } CASE(OP_KDICT, B) { - /* not implemented yet */ + regs[a] = regs[mrb->c->ci->argc]; NEXT; } @@ -2064,9 +2141,10 @@ RETRY_TRY_BLOCK: } CASE(OP_BLKPUSH, BS) { - int m1 = (b>>10)&0x3f; - int r = (b>>9)&0x1; - int m2 = (b>>4)&0x1f; + int m1 = (b>>11)&0x3f; + int r = (b>>10)&0x1; + int m2 = (b>>5)&0x1f; + int kd = (b>>4)&0x1; int lv = (b>>0)&0xf; mrb_value *stack; @@ -2084,7 +2162,7 @@ RETRY_TRY_BLOCK: localjump_error(mrb, LOCALJUMP_ERROR_YIELD); goto L_RAISE; } - regs[a] = stack[m1+r+m2]; + regs[a] = stack[m1+r+m2+kd]; NEXT; } diff --git a/test/t/syntax.rb b/test/t/syntax.rb index 299394557..6392509ec 100644 --- a/test/t/syntax.rb +++ b/test/t/syntax.rb @@ -403,6 +403,9 @@ assert('External command execution.') do assert_equal 'test dynamic `', t assert_equal ['test', 'test dynamic `', 'test', 'test dynamic `'], results + results = [] + assert_equal 'test sym test sym test', `test #{:sym} test #{:sym} test` + alias_method sym, :old_cmd end true @@ -466,3 +469,183 @@ this is a comment that has extra after =begin and =end with tabs after it =end xxxxxxxxxxxxxxxxxxxxxxxxxx assert_equal(line + 4, __LINE__) end + +assert 'keyword arguments' do + def m(a, b:) [a, b] end + assert_equal [1, 2], m(1, b: 2) + assert_raise(ArgumentError) { m b: 1 } + assert_raise(ArgumentError) { m 1 } + + def m(a:) a end + assert_equal 1, m(a: 1) + assert_raise(ArgumentError) { m } + assert_raise(ArgumentError) { m 'a' => 1, a: 1 } + h = { a: 1 } + assert_equal 1, m(h) + assert_equal({ a: 1 }, h) + + def m(a: 1) a end + assert_equal 1, m + assert_equal 2, m(a: 2) + assert_raise(ArgumentError) { m 1 } + + def m(**) end + assert_nil m + assert_nil m a: 1, b: 2 + assert_raise(ArgumentError) { m 2 } + + def m(a, **) a end + assert_equal 1, m(1) + assert_equal 1, m(1, a: 2, b: 3) + assert_equal({ 'a' => 1, b: 2 }, m('a' => 1, b: 2)) + + def m(a, **k) [a, k] end + assert_equal [1, {}], m(1) + assert_equal [1, {a: 2, b: 3}], m(1, a: 2, b: 3) + assert_equal [{'a' => 1, b: 2}, {}], m('a' => 1, b: 2) + + def m(a=1, **) a end + assert_equal 1, m + assert_equal 2, m(2, a: 1, b: 0) + assert_raise(ArgumentError) { m('a' => 1, a: 2) } + + def m(a=1, **k) [a, k] end + assert_equal [1, {}], m + assert_equal [2, {a: 1, b: 2}], m(2, a: 1, b: 2) + assert_equal [{a: 1}, {b: 2}], m({a: 1}, {b: 2}) + + def m(*, a:) a end + assert_equal 1, m(a: 1) + assert_equal 3, m(1, 2, a: 3) + assert_raise(ArgumentError) { m('a' => 1, a: 2) } + + def m(*a, b:) [a, b] end + assert_equal [[], 1], m(b: 1) + assert_equal [[1, 2], 3], m(1, 2, b: 3) + assert_raise(ArgumentError) { m('a' => 1, b: 2) } + + def m(*a, b: 1) [a, b] end + assert_equal [[], 1], m + assert_equal [[1, 2, 3], 4], m(1, 2, 3, b: 4) + assert_raise(ArgumentError) { m('a' => 1, b: 2) } + + def m(*, **) end + assert_nil m() + assert_nil m(a: 1, b: 2) + assert_nil m(1, 2, 3, a: 4, b: 5) + + def m(*a, **) a end + assert_equal [], m() + assert_equal [1, 2, 3], m(1, 2, 3, a: 4, b: 5) + assert_raise(ArgumentError) { m("a" => 1, a: 1) } + assert_equal [1], m(1, **{a: 2}) + + def m(*, **k) k end + assert_equal({}, m()) + assert_equal({a: 4, b: 5}, m(1, 2, 3, a: 4, b: 5)) + assert_raise(ArgumentError) { m("a" => 1, a: 1) } + + def m(a = nil, b = nil, **k) [a, k] end + assert_equal [nil, {}], m() + assert_equal([nil, {a: 1}], m(a: 1)) + assert_raise(ArgumentError) { m("a" => 1, a: 1) } + assert_equal([{"a" => 1}, {a: 1}], m({ "a" => 1 }, a: 1)) + assert_equal([{a: 1}, {}], m({a: 1}, {})) + assert_equal([nil, {}], m({})) + + def m(*a, **k) [a, k] end + assert_equal([[], {}], m()) + assert_equal([[1], {}], m(1)) + assert_equal([[], {a: 1, b: 2}], m(a: 1, b: 2)) + assert_equal([[1, 2, 3], {a: 2}], m(1, 2, 3, a: 2)) + assert_raise(ArgumentError) { m("a" => 1, a: 1) } + assert_raise(ArgumentError) { m("a" => 1) } + assert_equal([[], {a: 1}], m(a: 1)) + assert_raise(ArgumentError) { m("a" => 1, a: 1) } + assert_equal([[{"a" => 1}], {a: 1}], m({ "a" => 1 }, a: 1)) + assert_equal([[{a: 1}], {}], m({a: 1}, {})) + assert_raise(ArgumentError) { m({a: 1}, {"a" => 1}) } + + def m(a:, b:) [a, b] end + assert_equal([1, 2], m(a: 1, b: 2)) + assert_raise(ArgumentError) { m("a" => 1, a: 1, b: 2) } + + def m(a:, b: 1) [a, b] end + assert_equal([1, 1], m(a: 1)) + assert_equal([1, 2], m(a: 1, b: 2)) + assert_raise(ArgumentError) { m("a" => 1, a: 1, b: 2) } + + def m(a:, **) a end + assert_equal(1, m(a: 1)) + assert_equal(1, m(a: 1, b: 2)) + assert_raise(ArgumentError) { m("a" => 1, a: 1, b: 2) } + + def m(a:, **k) [a, k] end + assert_equal([1, {}], m(a: 1)) + assert_equal([1, {b: 2, c: 3}], m(a: 1, b: 2, c: 3)) + assert_raise(ArgumentError) { m("a" => 1, a: 1, b: 2) } + +=begin + def m(a:, &b) [a, b] end + assert_equal([1, nil], m(a: 1)) + assert_equal([1, l], m(a: 1, &(l = ->{}))) +=end + + def m(a: 1, b:) [a, b] end + assert_equal([1, 0], m(b: 0)) + assert_equal([3, 2], m(b: 2, a: 3)) + assert_raise(ArgumentError) { m a: 1 } + + def m(a: def m(a: 1) a end, b:) + [a, b] + end + assert_equal([2, 3], m(a: 2, b: 3)) + assert_equal([:m, 1], m(b: 1)) + # Note the default value of a: in the original method. + assert_equal(1, m()) + + def m(a: 1, b: 2) [a, b] end + assert_equal([1, 2], m()) + assert_equal([4, 3], m(b: 3, a: 4)) + + def m(a: 1, **) a end + assert_equal(1, m()) + assert_equal(2, m(a: 2, b: 1)) + + def m(a: 1, **k) [a, k] end + assert_equal([1, {b: 2, c: 3}], m(b: 2, c: 3)) + + def m(a:, **) yield end + assert_raise(ArgumentError) { m { :blk } } + assert_equal :blk, m(a: 1){ :blk } + + def m(a:, **k, &b) [b.call, k] end + assert_raise(ArgumentError) { m { :blk } } + assert_equal [:blk, {b: 2}], m(a: 1, b: 2){ :blk } + + def m(**k, &b) [k, b] end + assert_equal([{ a: 1, b: 2}, nil], m(a: 1, b: 2)) + assert_equal :blk, m{ :blk }[1].call + + def m(hsh = {}) hsh end + assert_equal({ a: 1, b: 2 }, m(a: 1, b: 2)) + assert_equal({ a: 1, 'b' => 2 }, m(a: 1, 'b' => 2)) + + def m(hsh) hsh end + assert_equal({ a: 1, b: 2 }, m(a: 1, b: 2)) + assert_equal({ a: 1, 'b' => 2 }, m(a: 1, 'b' => 2)) + +=begin + def m(a, b=1, *c, (*d, (e)), f: 2, g:, h:, **k, &l) + [a, b, c, d, e, f, g, h, k, l] + end + result = m(9, 8, 7, 6, f: 5, g: 4, h: 3, &(l = ->{})) + assert_equal([9, 8, [7], [], 6, 5, 4, 3, {}, l], result) + + def m a, b=1, *c, d, e:, f: 2, g:, **k, &l + [a, b, c, d, e, f, g, k, l] + end + result = m(1, 2, e: 3, g: 4, h: 5, i: 6, &(l = ->{})) + assert_equal([1, 1, [], 2, 3, 2, 4, { h: 5, i: 6 }, l], result) +=end +end -- cgit v1.2.3 From 53e2723faede0e6f9959bd3316f4dd1e84b69609 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Tue, 31 Jul 2018 03:14:42 +0900 Subject: Fixed a small bug in keyword argument parsing. def m(a=1,**k) p [a,k] end m(a: 1) --- src/vm.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/vm.c b/src/vm.c index 8aeb68fc2..8fe7c69b0 100644 --- a/src/vm.c +++ b/src/vm.c @@ -1770,7 +1770,7 @@ RETRY_TRY_BLOCK: } /* no rest arguments */ - if (argc < len) { + if (argc-kargs < len) { int mlen = m2; if (argc < m1+m2) { mlen = m1 < argc ? argc - m1 : 0; @@ -1778,7 +1778,6 @@ RETRY_TRY_BLOCK: regs[blk_pos] = *blk; /* move block */ if (kd) regs[len + 1] = kdict; - SET_NIL_VALUE(regs[argc+1]); /* copy mandatory and optional arguments */ if (argv0 != argv) { value_move(®s[1], argv, argc-mlen); /* m1 + o */ @@ -1798,7 +1797,7 @@ RETRY_TRY_BLOCK: regs[m1+o+1] = mrb_ary_new_capa(mrb, 0); } /* skip initailizer of passed arguments */ - if (o > 0 && argc-kargs >= m1+m2) + if (o > 0 && argc-kargs > m1+m2) pc += (argc - kargs - m1 - m2)*3; } else { -- cgit v1.2.3 From 43173e129965d776791fc643aba9f4c5244d8466 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Tue, 31 Jul 2018 03:20:00 +0900 Subject: Removed unused instruction: `OP_KDICT`. --- include/mruby/ops.h | 1 - src/codedump.c | 4 ---- src/vm.c | 5 ----- 3 files changed, 10 deletions(-) diff --git a/include/mruby/ops.h b/include/mruby/ops.h index 9675d6158..b8fc89d43 100644 --- a/include/mruby/ops.h +++ b/include/mruby/ops.h @@ -66,7 +66,6 @@ OPCODE(ENTER, W) /* arg setup according to flags (23=m5:o5:r1:m5:k5: OPCODE(KEY_P, BB) /* R(a) = kdict.key?(Syms(b)) # todo */ OPCODE(KEYEND, Z) /* raise unless kdict.empty? # todo */ OPCODE(KARG, BB) /* R(a) = kdict[Syms(b)]; kdict.delete(Syms(b)) # todo */ -OPCODE(KDICT, B) /* R(a) = kdict # todo */ OPCODE(RETURN, B) /* return R(a) (normal) */ OPCODE(RETURN_BLK, B) /* return R(a) (in-block return) */ OPCODE(BREAK, B) /* break R(a) */ diff --git a/src/codedump.c b/src/codedump.c index dc0e0e548..842d40bdf 100644 --- a/src/codedump.c +++ b/src/codedump.c @@ -285,10 +285,6 @@ codedump(mrb_state *mrb, mrb_irep *irep) printf("OP_KARG\tR%d\t:%s\t", a, mrb_sym2name(mrb, irep->syms[b])); print_lv_a(mrb, irep, a); break; - CASE(OP_KDICT, B): - printf("OP_KDICT\tR%d\t\t", a); - print_lv_a(mrb, irep, a); - break; CASE(OP_RETURN, B): printf("OP_RETURN\tR%d\t\t", a); print_lv_a(mrb, irep, a); diff --git a/src/vm.c b/src/vm.c index 8fe7c69b0..d47b4c7fc 100644 --- a/src/vm.c +++ b/src/vm.c @@ -1872,11 +1872,6 @@ RETRY_TRY_BLOCK: NEXT; } - CASE(OP_KDICT, B) { - regs[a] = regs[mrb->c->ci->argc]; - NEXT; - } - CASE(OP_BREAK, B) { c = OP_R_BREAK; goto L_RETURN; -- cgit v1.2.3 From e27565152fd939ed8c17e1a4120daa69fdb3f8e4 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Tue, 31 Jul 2018 03:20:27 +0900 Subject: Removed merge hiccups in `doc/opcode.md`. --- doc/opcode.md | 133 ---------------------------------------------------------- 1 file changed, 133 deletions(-) diff --git a/doc/opcode.md b/doc/opcode.md index 54d1f0553..fea0afafd 100644 --- a/doc/opcode.md +++ b/doc/opcode.md @@ -1,4 +1,3 @@ -<<<<<<< HEAD # The new bytecode We will reimplement VM to use 8bit instruction code. By @@ -81,7 +80,6 @@ with `"`, either `OP_EXT1` or `OP_EXT2` or `OP_EXT2` can be prefixed. |OP_ENTER |W |arg setup according to flags (23=5:5:1:5:5:1:1) |OP_KARG" |BB |R(a) = kdict[Syms(Bx)] # todo |OP_KARG2" |BB |R(a) = kdict[Syms(Bx)]; kdict.rm(Syms(b)) # todo -|OP_KDICT' |B |R(a) = kdict # todo |OP_RETURN' |B |return R(a) (normal) |OP_RETURN_BLK' |B |return R(a) (in-block return) |OP_BREAK' |B |break R(a) @@ -127,134 +125,3 @@ with `"`, either `OP_EXT1` or `OP_EXT2` or `OP_EXT2` can be prefixed. |OP_EXT2 |- |make 2nd operand 16bit |OP_EXT3 |- |make 1st and 2nd operands 16bit |OP_STOP |- |stop VM -||||||| parent of b6821923... New bytecode implementation of mruby VM. -======= -# The new bytecode - -We will reimplement VM to use 8bit instruction code. By -bytecode, we mean real byte code. The whole purpose is -reducing the memory consumption of mruby VM. - -# Instructions - -Instructions are bytes. There can be 256 instructions. Currently we -have 94 instructions. Instructions can take 0 to 3 operands. - -## operands - -The size of operands can be either 8bits, 16bits or 24bits. -In the table.1 below, the second field describes the size (and -sign) of operands. - -* B: 8bit -* sB: signed 8bit -* S: 16bit -* sS: signed 16bit -* W: 24bit - -First two byte operands may be extended to 16bit. When those byte -operands are bigger than 256, the instruction will be prefixed by -`OP_EXT1` (means 1st operand is 16bit) or `OP_EXT2` (means 2nd operand -is 16bit) or `OP_EXT3` (means 1st and 2nd operands are 16bit). - -For instructions marked by `'`, `OP_EXT1` can be prefixed. For those -with `"`, either `OP_EXT1` or `OP_EXT2` or `OP_EXT2` can be prefixed. - -## table.1 Instruction Table - -|Instruction Name |Operand type |Semantics -|-----------------|-------------|----------------- -|OP_NOP | - | -|OP_MOVE" |BB |R(a) = R(b) -|OP_LOADL" |BB |R(a) = Pool(b) -|OP_LOADI" |BsB |R(a) = mrb_int(b) -|OP_LOADI_0' |B |R(a) = 0 -|OP_LOADI_1' |B |R(a) = 1 -|OP_LOADI_2' |B |R(a) = 2 -|OP_LOADI_3' |B |R(a) = 3 -|OP_LOADSYM" |BB |R(a) = Syms(b) -|OP_LOADNIL' |B |R(a) = nil -|OP_LOADSELF' |B |R(a) = self -|OP_LOADT' |B |R(a) = true -|OP_LOADF' |B |R(a) = false -|OP_GETGV" |BB |R(a) = getglobal(Syms(b)) -|OP_SETGV" |BB |setglobal(Syms(b), R(a)) -|OP_GETSV" |BB |R(a) = Special[b] -|OP_SETSV" |BB |Special[b] = R(a) -|OP_GETIV" |BB |R(a) = ivget(Syms(b)) -|OP_SETIV" |BB |ivset(Syms(b),R(a)) -|OP_GETCV" |BB |R(a) = cvget(Syms(b)) -|OP_SETCV" |BB |cvset(Syms(b),R(a)) -|OP_GETCONST" |BB |R(a) = constget(Syms(b)) -|OP_SETCONST" |BB |constset(Syms(b),R(a)) -|OP_GETMCNST" |BB |R(a) = R(a)::Syms(b) -|OP_SETMCNST" |BB |R(a+1)::Syms(b) = R(a) -|OP_GETUPVAR' |BBB |R(a) = uvget(b,c) -|OP_SETUPVAR' |BBB |uvset(b,c,R(a)) -|OP_JMP |S |pc+=a -|OP_JMPIF' |SB |if R(b) pc+=a -|OP_JMPNOT' |SB |if !R(b) pc+=a -|OP_ONERR |sS |rescue_push(pc+a) -|OP_EXCEPT' |B |R(a) = exc -|OP_RESCUE" |BB |R(b) = R(a).isa?(R(b)) -|OP_POPERR |B |a.times{rescue_pop()} -|OP_RAISE' |B |raise(R(a)) -|OP_EPUSH' |B |ensure_push(SEQ[a]) -|OP_EPOP |B |A.times{ensure_pop().call} -|OP_SENDV" |BB |R(a) = call(R(a),Syms(b),*R(a+1)) -|OP_SENDVB" |BB |R(a) = call(R(a),Syms(b),*R(a+1),&R(a+2)) -|OP_SEND" |BBB |R(a) = call(R(a),Syms(b),R(a+1),...,R(a+c)) -|OP_SENDB" |BBB |R(a) = call(R(a),Syms(Bx),R(a+1),...,R(a+c),&R(a+c+1)) -|OP_CALL' |B |R(a) = self.call(frame.argc, frame.argv) -|OP_SUPER' |BB |R(a) = super(R(a+1),... ,R(a+b+1)) -|OP_ARGARY' |BS |R(a) = argument array (16=5:1:5:1:4) -|OP_ENTER |W |arg setup according to flags (23=5:5:1:5:5:1:1) -|OP_KARG" |BB |R(a) = kdict[Syms(Bx)] # todo -|OP_KARG2" |BB |R(a) = kdict[Syms(Bx)]; kdict.rm(Syms(b)) # todo -|OP_KDICT' |B |R(a) = kdict # todo -|OP_RETURN' |B |return R(a) (normal) -|OP_RETURN_BLK' |B |return R(a) (in-block return) -|OP_BREAK' |B |break R(a) -|OP_BLKPUSH' |BS |R(a) = block (16=5:1:5:1:4) -|OP_ADD" |BB |R(a) = R(a)+R(a+1) (Syms[b]=:+) -|OP_ADDI" |BBB |R(a) = R(a)+mrb_int(c) (Syms[b]=:+) -|OP_SUB" |BB |R(a) = R(a)-R(a+1) (Syms[b]=:-) -|OP_SUBI" |BB |R(a) = R(a)-C (Syms[b]=:-) -|OP_MUL" |BB |R(a) = R(a)*R(a+1) (Syms[b]=:*) -|OP_DIV" |BB |R(a) = R(a)/R(a+1) (Syms[b]=:/) -|OP_EQ" |BB |R(a) = R(a)==R(a+1) (Syms[b]=:==) -|OP_LT" |BB |R(a) = R(a)R(a+1) (Syms[b]=:>) -|OP_GE" |BB |R(a) = R(a)>=R(a+1) (Syms[b]=:>=) -|OP_ARRAY' |BB |R(a) = ary_new(R(a),R(a+1)..R(a+b)) -|OP_ARRAY2" |BB |R(a) = ary_new(R(b),R(b+1)..R(b+c)) -|OP_ARYCAT' |B |ary_cat(R(a),R(a+1)) -|OP_ARYPUSH' |B |ary_push(R(a),R(a+1)) -|OP_AREF' |BB |R(a) = R(a)[b] -|OP_ASET' |BB |R(a)[b] = R(a+1) -|OP_APOST' |BB |*R(a),R(A+1)..R(A+C) = R(a)[B..] -|OP_STRING" |BB |R(a) = str_dup(Lit(b)) -|OP_STRCAT' |B |str_cat(R(a),R(a+1)) -|OP_HASH' |BB |R(a) = hash_new(R(a),R(a+1)..R(a+b)) -|OP_HASHADD' |BB |R(a) = hash_push(R(a),R(a+1)..R(a+b)) -|OP_LAMBDA" |BB |R(a) = lambda(SEQ[b],OP_L_LAMBDA) -|OP_BLOCK" |BB |R(a) = lambda(SEQ[b],OP_L_BLOCK) -|OP_METHOD" |BB |R(a) = lambda(SEQ[b],OP_L_METHOD) -|OP_RANGE_INC' |B |R(a) = range_new(R(a),R(a+1),FALSE) -|OP_RANGE_EXC' |B |R(a) = range_new(R(a),R(a+1),TRUE) -|OP_OCLASS' |B |R(a) = ::Object -|OP_CLASS" |BB |R(a) = newclass(R(a),Syms(b),R(a+1)) -|OP_MODULE" |BB |R(a) = newmodule(R(a),Syms(b)) -|OP_EXEC" |BB |R(a) = blockexec(R(a),SEQ[b]) -|OP_DEF" |BB |R(a).newmethod(Syms(b),R(a+1)) -|OP_ALIAS' |B |alias_method(R(a),R(a+1),R(a+2)) -|OP_UNDEF" |BB |undef_method(R(a),Syms(b)) -|OP_SCLASS' |B |R(a) = R(a).singleton_class -|OP_TCLASS' |B |R(a) = target_class -|OP_ERR' |B |raise(RuntimeError, Lit(Bx)) -|OP_EXT1 |- |make 1st operand 16bit -|OP_EXT2 |- |make 2nd operand 16bit -|OP_EXT3 |- |make 1st and 2nd operands 16bit -|OP_STOP |- |stop VM ->>>>>>> b6821923... New bytecode implementation of mruby VM. -- cgit v1.2.3 From 4ce9058f64ea9004de6adc7fff491cbdbc01bd43 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Tue, 31 Jul 2018 03:26:53 +0900 Subject: Describe the difference of the keyword argument behavior. The implementation of keyword arguments is heavily rely on the prototype made by @take-cheeze in #3629. --- doc/limitations.md | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/doc/limitations.md b/doc/limitations.md index afcb7b56e..e0c999aa6 100644 --- a/doc/limitations.md +++ b/doc/limitations.md @@ -205,3 +205,25 @@ trace (most recent call last): [0] -e:1 -e:1: undefined method 'binding' (NoMethodError) ``` + +## Keyword arguments + +mruby keyword arguments behave slightly different from CRuby 2.5 +to make the behavior simpler and less confusing. Maybe in the +future, the simpler behavior will be adopted to CRuby as well. + +#### Ruby [ruby 2.5.1p57 (2018-03-29 revision 63029)] + +``` +$ ruby -e 'def m(*r,**k) p [r,k] end; m("a"'=>1,:b=>2)' +[[{"a"=>1}], {:b=>2}] +``` + +#### mruby [] + +``` +$ ./bin/mruby -e 'def m(*r,**k) p [r,k] end; m("a"'=>1,:b=>2)' +trace (most recent call last): + [0] -e:1 +-e:1: keyword argument hash with non symbol keys (ArgumentError) +``` -- cgit v1.2.3 From 180f39bf4c5246ff77ef71011a75e7669019afab Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Tue, 31 Jul 2018 16:14:18 +0900 Subject: Check size of the integer multiply before actual overflow; fix #4062 --- mrbgems/mruby-sprintf/src/sprintf.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/mrbgems/mruby-sprintf/src/sprintf.c b/mrbgems/mruby-sprintf/src/sprintf.c index 7eea1a1f3..738c5485f 100644 --- a/mrbgems/mruby-sprintf/src/sprintf.c +++ b/mrbgems/mruby-sprintf/src/sprintf.c @@ -119,13 +119,11 @@ mrb_fix2binstr(mrb_state *mrb, mrb_value x, int base) #define FPREC0 128 #define CHECK(l) do {\ -/* int cr = ENC_CODERANGE(result);*/\ while ((l) >= bsiz - blen) {\ + if (bsiz > MRB_INT_MAX/2) mrb_raise(mrb, E_ARGUMENT_ERROR, "too big specifier"); \ bsiz*=2;\ - if (bsiz < 0) mrb_raise(mrb, E_ARGUMENT_ERROR, "too big specifier"); \ }\ mrb_str_resize(mrb, result, bsiz);\ -/* ENC_CODERANGE_SET(result, cr);*/\ buf = RSTRING_PTR(result);\ } while (0) @@ -202,11 +200,10 @@ check_name_arg(mrb_state *mrb, int posarg, const char *name, mrb_int len) #define GETNUM(n, val) \ for (; p < end && ISDIGIT(*p); p++) {\ - mrb_int next_n = 10 * n + (*p - '0'); \ - if (next_n / 10 != n) {\ + if (n > MRB_INT_MAX/10) {\ mrb_raise(mrb, E_ARGUMENT_ERROR, #val " too big"); \ } \ - n = next_n; \ + n = 10 * n + (*p - '0'); \ } \ if (p >= end) { \ mrb_raise(mrb, E_ARGUMENT_ERROR, "malformed format string - %*[0-9]"); \ -- cgit v1.2.3 From 8558627b9bb99635ebaaaa06bdbbebda4d4aef39 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Tue, 31 Jul 2018 16:48:50 +0900 Subject: Reorganize flags values for classes; fix #3975 Renamed flag macro names as well: `MRB_FLAG_IS_FROZEN` -> `MRB_FL_OBJ_FROZEN` `MRB_FLAG_IS_PREPENDED` -> `MRB_FL_CLASS_IS_PREPENDED` `MRB_FLAG_IS_ORIGIN` -> `MRB_FL_CLASS_IS_ORIGIN` `MRB_FLAG_IS_INHERITED` -> `MRB_FL_CLASS_IS_INHERITED` --- include/mruby/class.h | 20 +++++++++++++------- include/mruby/object.h | 9 ++++----- src/class.c | 24 ++++++++++++------------ src/gc.c | 4 ++-- src/kernel.c | 10 +++++----- 5 files changed, 36 insertions(+), 31 deletions(-) diff --git a/include/mruby/class.h b/include/mruby/class.h index ea35d8e17..6e6f11eb8 100644 --- a/include/mruby/class.h +++ b/include/mruby/class.h @@ -53,19 +53,25 @@ mrb_class(mrb_state *mrb, mrb_value v) } } -/* TODO: figure out where to put user flags */ -/* flags bits >= 18 is reserved */ -#define MRB_FLAG_IS_PREPENDED (1 << 19) -#define MRB_FLAG_IS_ORIGIN (1 << 20) +/* flags: + 20: frozen + 19: is_prepended + 18: is_origin + 17: is_inherited (used by method cache) + 16: unused + 0-15: instance type +*/ +#define MRB_FL_CLASS_IS_PREPENDED (1 << 19) +#define MRB_FL_CLASS_IS_ORIGIN (1 << 18) #define MRB_CLASS_ORIGIN(c) do {\ - if (c->flags & MRB_FLAG_IS_PREPENDED) {\ + if (c->flags & MRB_FL_CLASS_IS_PREPENDED) {\ c = c->super;\ - while (!(c->flags & MRB_FLAG_IS_ORIGIN)) {\ + while (!(c->flags & MRB_FL_CLASS_IS_ORIGIN)) {\ c = c->super;\ }\ }\ } while (0) -#define MRB_FLAG_IS_INHERITED (1 << 21) +#define MRB_FL_CLASS_IS_INHERITED (1 << 17) #define MRB_INSTANCE_TT_MASK (0xFF) #define MRB_SET_INSTANCE_TT(c, tt) c->flags = ((c->flags & ~MRB_INSTANCE_TT_MASK) | (char)tt) #define MRB_INSTANCE_TT(c) (enum mrb_vtype)(c->flags & MRB_INSTANCE_TT_MASK) diff --git a/include/mruby/object.h b/include/mruby/object.h index 4f2134ae2..25584a1d4 100644 --- a/include/mruby/object.h +++ b/include/mruby/object.h @@ -22,11 +22,10 @@ struct RBasic { }; #define mrb_basic_ptr(v) ((struct RBasic*)(mrb_ptr(v))) -/* flags bits >= 18 is reserved */ -#define MRB_FLAG_IS_FROZEN (1 << 18) -#define MRB_FROZEN_P(o) ((o)->flags & MRB_FLAG_IS_FROZEN) -#define MRB_SET_FROZEN_FLAG(o) ((o)->flags |= MRB_FLAG_IS_FROZEN) -#define MRB_UNSET_FROZEN_FLAG(o) ((o)->flags &= ~MRB_FLAG_IS_FROZEN) +#define MRB_FL_OBJ_IS_FROZEN (1 << 20) +#define MRB_FROZEN_P(o) ((o)->flags & MRB_FL_OBJ_IS_FROZEN) +#define MRB_SET_FROZEN_FLAG(o) ((o)->flags |= MRB_FL_OBJ_IS_FROZEN) +#define MRB_UNSET_FROZEN_FLAG(o) ((o)->flags &= ~MRB_FL_OBJ_IS_FROZEN) struct RObject { MRB_OBJECT_HEADER; diff --git a/src/class.c b/src/class.c index a9439d7d7..97b5df926 100644 --- a/src/class.c +++ b/src/class.c @@ -93,7 +93,7 @@ prepare_singleton_class(mrb_state *mrb, struct RBasic *o) if (o->c->tt == MRB_TT_SCLASS) return; sc = (struct RClass*)mrb_obj_alloc(mrb, MRB_TT_SCLASS, mrb->class_class); - sc->flags |= MRB_FLAG_IS_INHERITED; + sc->flags |= MRB_FL_CLASS_IS_INHERITED; sc->mt = kh_init(mt, mrb); sc->iv = 0; if (o->tt == MRB_TT_CLASS) { @@ -275,7 +275,7 @@ mrb_class_inherited(mrb_state *mrb, struct RClass *super, struct RClass *klass) if (!super) super = mrb->object_class; - super->flags |= MRB_FLAG_IS_INHERITED; + super->flags |= MRB_FL_CLASS_IS_INHERITED; s = mrb_obj_value(super); mc_clear_by_class(mrb, klass); mid = mrb_intern_lit(mrb, "inherited"); @@ -1061,7 +1061,7 @@ include_module_at(mrb_state *mrb, struct RClass *c, struct RClass *ins_pos, stru while (m) { int superclass_seen = 0; - if (m->flags & MRB_FLAG_IS_PREPENDED) + if (m->flags & MRB_FL_CLASS_IS_PREPENDED) goto skip; if (klass_mt && klass_mt == m->mt) @@ -1084,7 +1084,7 @@ include_module_at(mrb_state *mrb, struct RClass *c, struct RClass *ins_pos, stru } ic = include_class_new(mrb, m, ins_pos->super); - m->flags |= MRB_FLAG_IS_INHERITED; + m->flags |= MRB_FL_CLASS_IS_INHERITED; ins_pos->super = ic; mrb_field_write_barrier(mrb, (struct RBasic*)ins_pos, (struct RBasic*)ic); mc_clear_by_class(mrb, ins_pos); @@ -1111,15 +1111,15 @@ mrb_prepend_module(mrb_state *mrb, struct RClass *c, struct RClass *m) struct RClass *origin; int changed = 0; - if (!(c->flags & MRB_FLAG_IS_PREPENDED)) { + if (!(c->flags & MRB_FL_CLASS_IS_PREPENDED)) { origin = (struct RClass*)mrb_obj_alloc(mrb, MRB_TT_ICLASS, c); - origin->flags |= MRB_FLAG_IS_ORIGIN | MRB_FLAG_IS_INHERITED; + origin->flags |= MRB_FL_CLASS_IS_ORIGIN | MRB_FL_CLASS_IS_INHERITED; origin->super = c->super; c->super = origin; origin->mt = c->mt; c->mt = kh_init(mt, mrb); mrb_field_write_barrier(mrb, (struct RBasic*)c, (struct RBasic*)origin); - c->flags |= MRB_FLAG_IS_PREPENDED; + c->flags |= MRB_FL_CLASS_IS_PREPENDED; } changed = include_module_at(mrb, c, c, m, 0); if (changed < 0) { @@ -1196,7 +1196,7 @@ mrb_mod_ancestors(mrb_state *mrb, mrb_value self) if (c->tt == MRB_TT_ICLASS) { mrb_ary_push(mrb, result, mrb_obj_value(c->c)); } - else if (!(c->flags & MRB_FLAG_IS_PREPENDED)) { + else if (!(c->flags & MRB_FL_CLASS_IS_PREPENDED)) { mrb_ary_push(mrb, result, mrb_obj_value(c)); } c = c->super; @@ -1365,9 +1365,9 @@ mc_clear_by_class(mrb_state *mrb, struct RClass *c) struct mrb_cache_entry *mc = mrb->cache; int i; - if (c->flags & MRB_FLAG_IS_INHERITED) { + if (c->flags & MRB_FL_CLASS_IS_INHERITED) { mc_clear_all(mrb); - c->flags &= ~MRB_FLAG_IS_INHERITED; + c->flags &= ~MRB_FL_CLASS_IS_INHERITED; return; } for (i=0; icache; int i; - if (c->flags & MRB_FLAG_IS_INHERITED) { + if (c->flags & MRB_FL_CLASS_IS_INHERITED) { mc_clear_all(mrb); - c->flags &= ~MRB_FLAG_IS_INHERITED; + c->flags &= ~MRB_FL_CLASS_IS_INHERITED; return; } for (i=0; isuper); } @@ -761,7 +761,7 @@ obj_free(mrb_state *mrb, struct RBasic *obj, int end) mrb_gc_free_iv(mrb, (struct RObject*)obj); break; case MRB_TT_ICLASS: - if (MRB_FLAG_TEST(obj, MRB_FLAG_IS_ORIGIN)) + if (MRB_FLAG_TEST(obj, MRB_FL_CLASS_IS_ORIGIN)) mrb_gc_free_mt(mrb, (struct RClass*)obj); break; case MRB_TT_ENV: diff --git a/src/kernel.c b/src/kernel.c index bbe6e8bb7..7459c83af 100644 --- a/src/kernel.c +++ b/src/kernel.c @@ -252,18 +252,18 @@ copy_class(mrb_state *mrb, mrb_value dst, mrb_value src) struct RClass *sc = mrb_class_ptr(src); /* if the origin is not the same as the class, then the origin and the current class need to be copied */ - if (sc->flags & MRB_FLAG_IS_PREPENDED) { + if (sc->flags & MRB_FL_CLASS_IS_PREPENDED) { struct RClass *c0 = sc->super; struct RClass *c1 = dc; /* copy prepended iclasses */ - while (!(c0->flags & MRB_FLAG_IS_ORIGIN)) { + while (!(c0->flags & MRB_FL_CLASS_IS_ORIGIN)) { c1->super = mrb_class_ptr(mrb_obj_dup(mrb, mrb_obj_value(c0))); c1 = c1->super; c0 = c0->super; } c1->super = mrb_class_ptr(mrb_obj_dup(mrb, mrb_obj_value(c0))); - c1->super->flags |= MRB_FLAG_IS_ORIGIN; + c1->super->flags |= MRB_FL_CLASS_IS_ORIGIN; } if (sc->mt) { dc->mt = kh_copy(mt, mrb, sc->mt); @@ -348,7 +348,7 @@ mrb_obj_clone(mrb_state *mrb, mrb_value self) mrb_field_write_barrier(mrb, (struct RBasic*)p, (struct RBasic*)p->c); clone = mrb_obj_value(p); init_copy(mrb, clone, self); - p->flags |= mrb_obj_ptr(self)->flags & MRB_FLAG_IS_FROZEN; + p->flags |= mrb_obj_ptr(self)->flags & MRB_FL_OBJ_IS_FROZEN; return clone; } @@ -706,7 +706,7 @@ mrb_class_instance_method_list(mrb_state *mrb, mrb_bool recur, struct RClass* kl struct RClass* oldklass; khash_t(st)* set = kh_init(st, mrb); - if (!recur && (klass->flags & MRB_FLAG_IS_PREPENDED)) { + if (!recur && (klass->flags & MRB_FL_CLASS_IS_PREPENDED)) { MRB_CLASS_ORIGIN(klass); prepended = TRUE; } -- cgit v1.2.3 From 889f0f5f36212606056af4fbb7865f900c2b8af1 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Tue, 31 Jul 2018 17:27:59 +0900 Subject: Add test case corresponding to 53e2723. --- test/t/syntax.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/test/t/syntax.rb b/test/t/syntax.rb index 6392509ec..c5405aa9c 100644 --- a/test/t/syntax.rb +++ b/test/t/syntax.rb @@ -511,6 +511,7 @@ assert 'keyword arguments' do def m(a=1, **k) [a, k] end assert_equal [1, {}], m + assert_equal [1, {a: 1}], m(a: 1) assert_equal [2, {a: 1, b: 2}], m(2, a: 1, b: 2) assert_equal [{a: 1}, {b: 2}], m({a: 1}, {b: 2}) -- cgit v1.2.3 From beb6e5c299bb411a7f2a9e355e6eeca3aa785c74 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Tue, 31 Jul 2018 17:28:42 +0900 Subject: Bytecode support for `mrdb`. --- include/mruby/irep.h | 9 +++++++++ mrbgems/mruby-bin-debugger/tools/mrdb/mrdb.c | 8 +++++--- mrbgems/mruby-compiler/core/codegen.c | 13 +++---------- 3 files changed, 17 insertions(+), 13 deletions(-) diff --git a/include/mruby/irep.h b/include/mruby/irep.h index c98d008db..7dcf33735 100644 --- a/include/mruby/irep.h +++ b/include/mruby/irep.h @@ -58,6 +58,15 @@ void mrb_irep_decref(mrb_state*, struct mrb_irep*); void mrb_irep_cutref(mrb_state*, struct mrb_irep*); void mrb_irep_remove_lv(mrb_state *mrb, mrb_irep *irep); +struct mrb_insn_data { + uint8_t insn; + uint16_t a; + uint16_t b; + uint8_t c; +}; + +struct mrb_insn_data mrb_decode_insn(mrb_code *pc); + MRB_END_DECL #endif /* MRUBY_IREP_H */ diff --git a/mrbgems/mruby-bin-debugger/tools/mrdb/mrdb.c b/mrbgems/mruby-bin-debugger/tools/mrdb/mrdb.c index 1b17128fd..05a6f3622 100644 --- a/mrbgems/mruby-bin-debugger/tools/mrdb/mrdb.c +++ b/mrbgems/mruby-bin-debugger/tools/mrdb/mrdb.c @@ -510,6 +510,7 @@ check_method_breakpoint(mrb_state *mrb, mrb_irep *irep, mrb_code *pc, mrb_value mrb_sym sym; int32_t bpno; mrb_bool isCfunc; + struct mrb_insn_data insn; mrb_debug_context *dbg = mrb_debug_context_get(mrb); @@ -517,11 +518,12 @@ check_method_breakpoint(mrb_state *mrb, mrb_irep *irep, mrb_code *pc, mrb_value bpno = dbg->method_bpno; dbg->method_bpno = 0; - switch(*pc) { + insn = mrb_decode_insn(pc); + switch(insn.insn) { case OP_SEND: case OP_SENDB: - c = mrb_class(mrb, regs[GETARG_A(*pc)]); - sym = irep->syms[GETARG_B(*pc)]; + c = mrb_class(mrb, regs[insn.a]); + sym = irep->syms[insn.b]; break; case OP_SUPER: c = mrb->c->ci->target_class->super; diff --git a/mrbgems/mruby-compiler/core/codegen.c b/mrbgems/mruby-compiler/core/codegen.c index 070aaac51..b8caba3a0 100644 --- a/mrbgems/mruby-compiler/core/codegen.c +++ b/mrbgems/mruby-compiler/core/codegen.c @@ -296,15 +296,8 @@ on_eval(codegen_scope *s) return FALSE; } -struct mrb_insn_data { - uint8_t insn; - uint16_t a; - uint16_t b; - uint8_t c; -}; - struct mrb_insn_data -mrb_decode_insn(codegen_scope *s, mrb_code *pc) +mrb_decode_insn(mrb_code *pc) { struct mrb_insn_data data = { 0 }; mrb_code insn = READ_B(); @@ -353,7 +346,7 @@ mrb_decode_insn(codegen_scope *s, mrb_code *pc) return data; } -struct mrb_insn_data +static struct mrb_insn_data mrb_last_insn(codegen_scope *s) { if (s->pc == s->lastpc) { @@ -362,7 +355,7 @@ mrb_last_insn(codegen_scope *s) data.insn = OP_NOP; return data; } - return mrb_decode_insn(s, &s->iseq[s->lastpc]); + return mrb_decode_insn(&s->iseq[s->lastpc]); } static mrb_bool -- cgit v1.2.3 From 64748691dea95312c80c1fe7b9e960f53ea5b28a Mon Sep 17 00:00:00 2001 From: Kazuhiro NISHIYAMA Date: Tue, 31 Jul 2018 22:09:45 +0900 Subject: Remove unmatched quotation mark --- doc/limitations.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/limitations.md b/doc/limitations.md index e0c999aa6..92858cb1f 100644 --- a/doc/limitations.md +++ b/doc/limitations.md @@ -215,14 +215,14 @@ future, the simpler behavior will be adopted to CRuby as well. #### Ruby [ruby 2.5.1p57 (2018-03-29 revision 63029)] ``` -$ ruby -e 'def m(*r,**k) p [r,k] end; m("a"'=>1,:b=>2)' +$ ruby -e 'def m(*r,**k) p [r,k] end; m("a"=>1,:b=>2)' [[{"a"=>1}], {:b=>2}] ``` #### mruby [] ``` -$ ./bin/mruby -e 'def m(*r,**k) p [r,k] end; m("a"'=>1,:b=>2)' +$ ./bin/mruby -e 'def m(*r,**k) p [r,k] end; m("a"=>1,:b=>2)' trace (most recent call last): [0] -e:1 -e:1: keyword argument hash with non symbol keys (ArgumentError) -- cgit v1.2.3 From e89cc9b9fabd4277804fd43666b198a29c25bc34 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Wed, 1 Aug 2018 10:08:40 +0900 Subject: Should update `ci->env` to share the environment; fix #4073 --- mrbgems/mruby-eval/src/eval.c | 1 + 1 file changed, 1 insertion(+) diff --git a/mrbgems/mruby-eval/src/eval.c b/mrbgems/mruby-eval/src/eval.c index 5c8e78acd..47d029a98 100644 --- a/mrbgems/mruby-eval/src/eval.c +++ b/mrbgems/mruby-eval/src/eval.c @@ -254,6 +254,7 @@ create_proc_from_string(mrb_state *mrb, char *s, mrb_int len, mrb_value binding, if (ci->argc < 0) bidx = 2; else bidx += 1; MRB_ENV_SET_BIDX(e, bidx); + ci->env = e; } proc->e.env = e; proc->flags |= MRB_PROC_ENVSET; -- cgit v1.2.3 From b9817b00a4644bc2905be918e429fb1b78796fd4 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Wed, 1 Aug 2018 13:18:32 +0900 Subject: Remove `nregs` member from `mrb_callinfo`. This means reducing one word per a call frame. --- include/mruby.h | 1 - mrbgems/mruby-fiber/src/fiber.c | 1 - src/gc.c | 32 +++++++++++--- src/vm.c | 97 ++++++++++++++++++++++++----------------- 4 files changed, 83 insertions(+), 48 deletions(-) diff --git a/include/mruby.h b/include/mruby.h index b0bfe78b5..93fc0f010 100644 --- a/include/mruby.h +++ b/include/mruby.h @@ -123,7 +123,6 @@ typedef struct { mrb_sym mid; struct RProc *proc; mrb_value *stackent; - int nregs; int ridx; int epos; struct REnv *env; diff --git a/mrbgems/mruby-fiber/src/fiber.c b/mrbgems/mruby-fiber/src/fiber.c index 27b74dba5..17ce77c5d 100644 --- a/mrbgems/mruby-fiber/src/fiber.c +++ b/mrbgems/mruby-fiber/src/fiber.c @@ -127,7 +127,6 @@ fiber_init(mrb_state *mrb, mrb_value self) ci->proc = p; mrb_field_write_barrier(mrb, (struct RBasic*)mrb_obj_ptr(self), (struct RBasic*)p); ci->pc = p->body.irep->iseq; - ci->nregs = p->body.irep->nregs; ci[1] = ci[0]; c->ci++; /* push dummy callinfo */ diff --git a/src/gc.c b/src/gc.c index c52641959..33d83f28e 100644 --- a/src/gc.c +++ b/src/gc.c @@ -548,21 +548,39 @@ add_gray_list(mrb_state *mrb, mrb_gc *gc, struct RBasic *obj) gc->gray_list = obj; } +static int +ci_nregs(mrb_callinfo *ci) +{ + struct RProc *p = ci->proc; + int n = 0; + + if (!p) { + if (ci->argc < 0) return 3; + return ci->argc+2; + } + if (!MRB_PROC_CFUNC_P(p) && p->body.irep) { + n = p->body.irep->nregs; + } + if (ci->argc < 0) { + if (n < 3) n = 3; /* self + args + blk */ + } + if (ci->argc > n) { + n = ci->argc + 2; /* self + blk */ + } + return n; +} + static void mark_context_stack(mrb_state *mrb, struct mrb_context *c) { size_t i; size_t e; mrb_value nil; - mrb_int nregs; if (c->stack == NULL) return; e = c->stack - c->stbase; if (c->ci) { - nregs = c->ci->argc + 2; - if (c->ci->nregs > nregs) - nregs = c->ci->nregs; - e += nregs; + e += ci_nregs(c->ci); } if (c->stbase + e > c->stend) e = c->stend - c->stbase; for (i=0; istack - c->stbase; - if (c->ci) i += c->ci->nregs; + if (c->ci) { + i += ci_nregs(c->ci); + } if (c->stbase + i > c->stend) i = c->stend - c->stbase; children += i; diff --git a/src/vm.c b/src/vm.c index 7a436828a..066c6ba2e 100644 --- a/src/vm.c +++ b/src/vm.c @@ -356,7 +356,6 @@ ecall(mrb_state *mrb) ci->acc = CI_ACC_SKIP; ci->argc = 0; ci->proc = p; - ci->nregs = p->body.irep->nregs; ci->target_class = MRB_PROC_TARGET_CLASS(p); env = MRB_PROC_ENV(p); mrb_assert(env); @@ -396,6 +395,30 @@ mrb_funcall(mrb_state *mrb, mrb_value self, const char *name, mrb_int argc, ...) return mrb_funcall_argv(mrb, self, mid, argc, argv); } +static int +ci_nregs(mrb_callinfo *ci) +{ + struct RProc *p; + int n = 0; + + if (!ci) return 3; + p = ci->proc; + if (!p) { + if (ci->argc < 0) return 3; + return ci->argc+2; + } + if (!MRB_PROC_CFUNC_P(p) && p->body.irep) { + n = p->body.irep->nregs; + } + if (ci->argc < 0) { + if (n < 3) n = 3; /* self + args + blk */ + } + if (ci->argc > n) { + n = ci->argc + 2; /* self + blk */ + } + return n; +} + MRB_API mrb_value mrb_funcall_with_block(mrb_state *mrb, mrb_value self, mrb_sym mid, mrb_int argc, const mrb_value *argv, mrb_value blk) { @@ -426,13 +449,12 @@ mrb_funcall_with_block(mrb_state *mrb, mrb_value self, mrb_sym mid, mrb_int argc mrb_method_t m; struct RClass *c; mrb_callinfo *ci; - int n; + int n = ci_nregs(mrb->c->ci); ptrdiff_t voff = -1; if (!mrb->c->stack) { stack_init(mrb); } - n = mrb->c->ci->nregs; if (argc < 0) { mrb_raisef(mrb, E_ARGUMENT_ERROR, "negative argc for funcall (%S)", mrb_fixnum_value(argc)); } @@ -463,22 +485,22 @@ mrb_funcall_with_block(mrb_state *mrb, mrb_value self, mrb_sym mid, mrb_int argc voff = argv - mrb->c->stbase; } if (MRB_METHOD_CFUNC_P(m)) { - ci->nregs = (int)(argc + 2); - mrb_stack_extend(mrb, ci->nregs); + mrb_stack_extend(mrb, argc + 2); } else if (argc >= CALL_MAXARGS) { mrb_value args = mrb_ary_new_from_values(mrb, argc, argv); - mrb_stack_extend(mrb, ci->nregs+2); + + mrb_stack_extend(mrb, 3); mrb->c->stack[1] = args; ci->argc = -1; argc = 1; } else { struct RProc *p = MRB_METHOD_PROC(m); + ci->proc = p; if (argc < 0) argc = 1; - ci->nregs = (int)(p->body.irep->nregs + argc); - mrb_stack_extend(mrb, ci->nregs); + mrb_stack_extend(mrb, p->body.irep->nregs + argc); } if (voff >= 0) { argv = mrb->c->stbase + voff; @@ -520,26 +542,25 @@ mrb_value mrb_exec_irep(mrb_state *mrb, mrb_value self, struct RProc *p) { mrb_callinfo *ci = mrb->c->ci; - int keep; + int keep, nregs; mrb->c->stack[0] = self; ci->proc = p; if (MRB_PROC_CFUNC_P(p)) { return MRB_PROC_CFUNC(p)(mrb, self); } - ci->nregs = p->body.irep->nregs; + nregs = p->body.irep->nregs; if (ci->argc < 0) keep = 3; else keep = ci->argc + 2; - if (ci->nregs < keep) { + if (nregs < keep) { mrb_stack_extend(mrb, keep); } else { - mrb_stack_extend(mrb, ci->nregs); - stack_clear(mrb->c->stack+keep, ci->nregs-keep); + mrb_stack_extend(mrb, nregs); + stack_clear(mrb->c->stack+keep, nregs-keep); } ci = cipush(mrb); - ci->nregs = 0; ci->target_class = 0; ci->pc = p->body.irep->iseq; ci->stackent = mrb->c->stack; @@ -618,6 +639,7 @@ eval_under(mrb_state *mrb, mrb_value self, mrb_value blk, struct RClass *c) { struct RProc *p; mrb_callinfo *ci; + int nregs; if (mrb_nil_p(blk)) { mrb_raise(mrb, E_ARGUMENT_ERROR, "no block given"); @@ -639,13 +661,12 @@ eval_under(mrb_state *mrb, mrb_value self, mrb_value blk, struct RClass *c) mrb->c->stack[2] = mrb_nil_value(); return MRB_PROC_CFUNC(p)(mrb, self); } - ci->nregs = p->body.irep->nregs; - mrb_stack_extend(mrb, (ci->nregs < 3) ? 3 : ci->nregs); + nregs = p->body.irep->nregs; + mrb_stack_extend(mrb, (nregs < 3) ? 3 : nregs); mrb->c->stack[0] = self; mrb->c->stack[1] = self; mrb->c->stack[2] = mrb_nil_value(); ci = cipush(mrb); - ci->nregs = 0; ci->target_class = 0; ci->pc = p->body.irep->iseq; ci->stackent = mrb->c->stack; @@ -728,13 +749,15 @@ mrb_yield_with_class(mrb_state *mrb, mrb_value b, mrb_int argc, const mrb_value struct RProc *p; mrb_sym mid = mrb->c->ci->mid; mrb_callinfo *ci; - int n = mrb->c->ci->nregs; mrb_value val; + int n; if (mrb_nil_p(b)) { mrb_raise(mrb, E_ARGUMENT_ERROR, "no block given"); } - if (mrb->c->ci - mrb->c->cibase > MRB_FUNCALL_DEPTH_MAX) { + ci = mrb->c->ci; + n = ci_nregs(ci); + if (ci - mrb->c->cibase > MRB_FUNCALL_DEPTH_MAX) { mrb_exc_raise(mrb, mrb_obj_value(mrb->stack_err)); } p = mrb_proc_ptr(b); @@ -745,9 +768,9 @@ mrb_yield_with_class(mrb_state *mrb, mrb_value b, mrb_int argc, const mrb_value ci->argc = (int)argc; ci->target_class = c; ci->acc = CI_ACC_SKIP; + n = MRB_PROC_CFUNC_P(p) ? (int)(argc+2) : p->body.irep->nregs; mrb->c->stack = mrb->c->stack + n; - ci->nregs = MRB_PROC_CFUNC_P(p) ? (int)(argc+2) : p->body.irep->nregs; - mrb_stack_extend(mrb, ci->nregs); + mrb_stack_extend(mrb, n); mrb->c->stack[0] = self; if (argc > 0) { @@ -1009,7 +1032,6 @@ RETRY_TRY_BLOCK: } mrb->jmp = &c_jmp; mrb->c->ci->proc = proc; - mrb->c->ci->nregs = irep->nregs; #define regs (mrb->c->stack) INIT_DISPATCH { @@ -1363,6 +1385,8 @@ RETRY_TRY_BLOCK: a = mrb->c->eidx - epos; pc = pc + 1; for (n=0; nnregs; + proc = mrb->c->ensure[epos+n]; mrb->c->ensure[epos+n] = NULL; if (proc == NULL) continue; @@ -1372,12 +1396,11 @@ RETRY_TRY_BLOCK: ci->argc = 0; ci->proc = proc; ci->stackent = mrb->c->stack; - ci->nregs = irep->nregs; ci->target_class = target_class; ci->pc = pc; - ci->acc = ci[-1].nregs; + ci->acc = nregs; mrb->c->stack += ci->acc; - mrb_stack_extend(mrb, ci->nregs); + mrb_stack_extend(mrb, irep->nregs); regs[0] = self; pc = irep->iseq; } @@ -1414,7 +1437,7 @@ RETRY_TRY_BLOCK: mrb_value recv, blk; mrb_sym mid = syms[b]; - mrb_assert(bidx < ci->nregs); + mrb_assert(bidx < irep->nregs); recv = regs[a]; if (GET_OPCODE(i) != OP_SENDB) { @@ -1466,7 +1489,6 @@ RETRY_TRY_BLOCK: mrb->c->stack += a; if (MRB_METHOD_CFUNC_P(m)) { - ci->nregs = (argc < 0) ? 3 : n+2; if (MRB_METHOD_PROC_P(m)) { struct RProc *p = MRB_METHOD_PROC(m); @@ -1514,8 +1536,7 @@ RETRY_TRY_BLOCK: irep = proc->body.irep; pool = irep->pool; syms = irep->syms; - ci->nregs = irep->nregs; - mrb_stack_extend(mrb, (argc < 0 && ci->nregs < 3) ? 3 : ci->nregs); + mrb_stack_extend(mrb, (argc < 0 && irep->nregs < 3) ? 3 : irep->nregs); pc = irep->iseq; JUMP; } @@ -1575,8 +1596,7 @@ RETRY_TRY_BLOCK: } pool = irep->pool; syms = irep->syms; - ci->nregs = irep->nregs; - mrb_stack_extend(mrb, ci->nregs); + mrb_stack_extend(mrb, irep->nregs); if (ci->argc < 0) { if (irep->nregs > 3) { stack_clear(regs+3, irep->nregs-3); @@ -1606,7 +1626,7 @@ RETRY_TRY_BLOCK: mrb_sym mid = ci->mid; struct RClass* target_class = MRB_PROC_TARGET_CLASS(ci->proc); - mrb_assert(bidx < ci->nregs); + mrb_assert(bidx < irep->nregs); if (mid == 0 || !target_class) { mrb_value exc = mrb_exc_new_str_lit(mrb, E_NOMETHOD_ERROR, "super called outside of method"); @@ -1652,7 +1672,7 @@ RETRY_TRY_BLOCK: } mid = missing; if (argc >= 0) { - if (a+2 >= ci->nregs) { + if (a+2 >= irep->nregs) { mrb_stack_extend(mrb, a+3); } regs[a+1] = mrb_ary_new_from_values(mrb, n, regs+a+1); @@ -1676,7 +1696,7 @@ RETRY_TRY_BLOCK: if (MRB_METHOD_CFUNC_P(m)) { mrb_value v; - ci->nregs = (argc < 0) ? 3 : n+2; + if (MRB_METHOD_PROC_P(m)) { ci->proc = MRB_METHOD_PROC(m); } @@ -1713,8 +1733,7 @@ RETRY_TRY_BLOCK: irep = proc->body.irep; pool = irep->pool; syms = irep->syms; - ci->nregs = irep->nregs; - mrb_stack_extend(mrb, (argc < 0 && ci->nregs < 3) ? 3 : ci->nregs); + mrb_stack_extend(mrb, (argc < 0 && irep->nregs < 3) ? 3 : irep->nregs); pc = irep->iseq; JUMP; } @@ -2884,9 +2903,8 @@ RETRY_TRY_BLOCK: irep = p->body.irep; pool = irep->pool; syms = irep->syms; - ci->nregs = irep->nregs; - mrb_stack_extend(mrb, ci->nregs); - stack_clear(regs+1, ci->nregs-1); + mrb_stack_extend(mrb, irep->nregs); + stack_clear(regs+1, irep->nregs-1); pc = irep->iseq; JUMP; } @@ -3014,7 +3032,6 @@ mrb_top_run(mrb_state *mrb, struct RProc *proc, mrb_value self, unsigned int sta } ci = cipush(mrb); ci->mid = 0; - ci->nregs = 1; /* protect the receiver */ ci->acc = CI_ACC_SKIP; ci->target_class = mrb->object_class; v = mrb_vm_run(mrb, proc, self, stack_keep); -- cgit v1.2.3 From 4713cd9eb76bdac24201b6ef85cc3c372c393aff Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Wed, 1 Aug 2018 16:50:44 +0900 Subject: Simply use `snprintf` instead of custom `fmt_fp`, Unless `MRB_DISABLE_STDIO` is set. `snprintf` is used anyway if mruby is configured to use `stdio`. This change reduces 8KB of program size on the Linux box. --- src/fmt_fp.c | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/src/fmt_fp.c b/src/fmt_fp.c index f8a8f7904..783cc6c02 100644 --- a/src/fmt_fp.c +++ b/src/fmt_fp.c @@ -1,3 +1,5 @@ +#ifndef MRB_WITHOUT_FLOAT +#ifdef MRB_DISABLE_STDIO /* Most code in this file originates from musl (src/stdio/vfprintf.c) @@ -36,7 +38,6 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. #include #include -#ifndef MRB_WITHOUT_FLOAT struct fmt_args { mrb_state *mrb; mrb_value str; @@ -371,4 +372,17 @@ mrb_float_to_str(mrb_state *mrb, mrb_value flo, const char *fmt) } return f.str; } +#else /* MRB_DISABLE_STDIO */ +#include +#include + +mrb_value +mrb_float_to_str(mrb_state *mrb, mrb_value flo, const char *fmt) +{ + char buf[24]; + + snprintf(buf, sizeof(buf), fmt, mrb_float(flo)); + return mrb_str_new_cstr(mrb, buf); +} +#endif /* MRB_DISABLE_STDIO */ #endif -- cgit v1.2.3 From ca01c8792d300b15c3ec2605c44e04f3785921f5 Mon Sep 17 00:00:00 2001 From: dearblue Date: Sun, 5 Aug 2018 20:33:44 +0900 Subject: Fix mrb_value size with MRB_WORD_BOXING on 32-bit mode --- include/mruby/boxing_word.h | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/include/mruby/boxing_word.h b/include/mruby/boxing_word.h index b17bfc973..2ff314144 100644 --- a/include/mruby/boxing_word.h +++ b/include/mruby/boxing_word.h @@ -45,6 +45,14 @@ enum mrb_special_consts { #define MRB_SYMBOL_FLAG 0x0e #define MRB_SPECIAL_SHIFT 8 +#if defined(MRB_64BIT) +#define MRB_SYMBOL_BITSIZE (sizeof(mrb_sym) * CHAR_BIT) +#define MRB_SYMBOL_MAX UINT32_MAX +#else +#define MRB_SYMBOL_BITSIZE (sizeof(mrb_sym) * CHAR_BIT - MRB_SPECIAL_SHIFT) +#define MRB_SYMBOL_MAX (UINT32_MAX >> MRB_SPECIAL_SHIFT) +#endif + typedef union mrb_value { union { void *p; @@ -54,7 +62,7 @@ typedef union mrb_value { }; struct { unsigned int sym_flag : MRB_SPECIAL_SHIFT; - mrb_sym sym : (sizeof(mrb_sym) * CHAR_BIT); + mrb_sym sym : MRB_SYMBOL_BITSIZE; }; struct RBasic *bp; #ifndef MRB_WITHOUT_FLOAT -- cgit v1.2.3 From 005ccd9c7ec8e40ec05afd2e461566324e2d6eb6 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Wed, 1 Aug 2018 21:55:11 +0900 Subject: Small refactoring of `flodivmod()`. --- src/numeric.c | 41 ++++++++++++++++++++++++++--------------- 1 file changed, 26 insertions(+), 15 deletions(-) diff --git a/src/numeric.c b/src/numeric.c index 4e5fc394e..c3e7d77a3 100644 --- a/src/numeric.c +++ b/src/numeric.c @@ -220,29 +220,40 @@ flo_mul(mrb_state *mrb, mrb_value x) } static void -flodivmod(mrb_state *mrb, mrb_float x, mrb_float y, mrb_float *divp, mrb_float *modp) +flodivmod(mrb_state *mrb, double x, double y, mrb_float *divp, mrb_float *modp) { - mrb_float div; - mrb_float mod; + double div, mod; + if (isnan(y)) { + /* y is NaN so all results are NaN */ + div = mod = y; + goto exit; + } if (y == 0.0) { - if (x > 0.0) div = INFINITY; - else if (x < 0.0) div = -INFINITY; - else div = NAN; /* x == 0.0 */ + if (x == 0) div = NAN; + else if (x > 0.0) div = INFINITY; + else div = -INFINITY; /* x < 0.0 */ mod = NAN; + goto exit; + } + if ((x == 0.0) || (isinf(y) && !isinf(x))) { + mod = x; } else { mod = fmod(x, y); - if (isinf(x) && isfinite(y)) - div = x; - else - div = (x - mod) / y; - if (y*mod < 0) { - mod += y; - div -= 1.0; - } } - + if (isinf(x) && !isinf(y)) { + div = x; + } + else { + div = (x - mod) / y; + if (modp && divp) div = round(div); + } + if (y*mod < 0) { + mod += y; + div -= 1.0; + } + exit: if (modp) *modp = mod; if (divp) *divp = div; } -- cgit v1.2.3 From afbbc0a2cb02c6821ba77b0e19d2dbd0957e6cd9 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Thu, 2 Aug 2018 18:01:39 +0900 Subject: Small refactoring. The macro `RCLASS_SUPER`, `RCLASS_IV_TBL` and `RCLASS_M_TBL` are removed from `include/mruby/class.h`. --- include/mruby/class.h | 3 --- mrbgems/mruby-struct/src/struct.c | 11 +++++------ 2 files changed, 5 insertions(+), 9 deletions(-) diff --git a/include/mruby/class.h b/include/mruby/class.h index 6e6f11eb8..dfe63999c 100644 --- a/include/mruby/class.h +++ b/include/mruby/class.h @@ -22,9 +22,6 @@ struct RClass { }; #define mrb_class_ptr(v) ((struct RClass*)(mrb_ptr(v))) -#define RCLASS_SUPER(v) (((struct RClass*)(mrb_ptr(v)))->super) -#define RCLASS_IV_TBL(v) (((struct RClass*)(mrb_ptr(v)))->iv) -#define RCLASS_M_TBL(v) (((struct RClass*)(mrb_ptr(v)))->mt) static inline struct RClass* mrb_class(mrb_state *mrb, mrb_value v) diff --git a/mrbgems/mruby-struct/src/struct.c b/mrbgems/mruby-struct/src/struct.c index adeb09bc1..fe7e73f04 100644 --- a/mrbgems/mruby-struct/src/struct.c +++ b/mrbgems/mruby-struct/src/struct.c @@ -24,19 +24,18 @@ struct_class(mrb_state *mrb) } static inline mrb_value -struct_ivar_get(mrb_state *mrb, mrb_value c, mrb_sym id) +struct_ivar_get(mrb_state *mrb, mrb_value cls, mrb_sym id) { - struct RClass* kclass; + struct RClass* c = mrb_class_ptr(cls); struct RClass* sclass = struct_class(mrb); mrb_value ans; for (;;) { - ans = mrb_iv_get(mrb, c, id); + ans = mrb_iv_get(mrb, mrb_obj_value(c), id); if (!mrb_nil_p(ans)) return ans; - kclass = RCLASS_SUPER(c); - if (kclass == 0 || kclass == sclass) + c = c->super; + if (c == sclass || c == 0) return mrb_nil_value(); - c = mrb_obj_value(kclass); } } -- cgit v1.2.3 From 14c7a9c548ce7a1e38812fb4490e7c1a838652dc Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Thu, 2 Aug 2018 21:08:50 +0900 Subject: Revert 04dbbff. Use segment list for instance variable again to reduce memory. --- src/variable.c | 335 +++++++++++++++++++++++++++++++++++---------------------- 1 file changed, 205 insertions(+), 130 deletions(-) diff --git a/src/variable.c b/src/variable.c index de36efac6..cbfdb2f2d 100644 --- a/src/variable.c +++ b/src/variable.c @@ -12,152 +12,243 @@ typedef int (iv_foreach_func)(mrb_state*,mrb_sym,mrb_value,void*); -#include - -#ifndef MRB_IVHASH_INIT_SIZE -#define MRB_IVHASH_INIT_SIZE KHASH_MIN_SIZE +#ifndef MRB_IV_SEGMENT_SIZE +#define MRB_IV_SEGMENT_SIZE 4 #endif -KHASH_DECLARE(iv, mrb_sym, mrb_value, TRUE) -KHASH_DEFINE(iv, mrb_sym, mrb_value, TRUE, kh_int_hash_func, kh_int_hash_equal) +typedef struct segment { + mrb_sym key[MRB_IV_SEGMENT_SIZE]; + mrb_value val[MRB_IV_SEGMENT_SIZE]; + struct segment *next; +} segment; /* Instance variable table structure */ typedef struct iv_tbl { - khash_t(iv) h; + segment *rootseg; + size_t size; + size_t last_len; } iv_tbl; -/* - * Creates the instance variable table. - * - * Parameters - * mrb - * Returns - * the instance variable table. - */ +/* Creates the instance variable table. */ static iv_tbl* iv_new(mrb_state *mrb) { - return (iv_tbl*)kh_init_size(iv, mrb, MRB_IVHASH_INIT_SIZE); + iv_tbl *t; + + t = (iv_tbl*)mrb_malloc(mrb, sizeof(iv_tbl)); + t->size = 0; + t->rootseg = NULL; + t->last_len = 0; + + return t; } -/* - * Set the value for the symbol in the instance variable table. - * - * Parameters - * mrb - * t the instance variable table to be set in. - * sym the symbol to be used as the key. - * val the value to be set. - */ +/* Set the value for the symbol in the instance variable table. */ static void iv_put(mrb_state *mrb, iv_tbl *t, mrb_sym sym, mrb_value val) { - khash_t(iv) *h = &t->h; - khiter_t k; + segment *seg; + segment *prev = NULL; + segment *matched_seg = NULL; + size_t matched_idx = 0; + size_t i; - k = kh_put(iv, mrb, h, sym); - kh_value(h, k) = val; + if (t == NULL) return; + seg = t->rootseg; + while (seg) { + for (i=0; ikey[i]; + /* Found room in last segment after last_len */ + if (!seg->next && i >= t->last_len) { + seg->key[i] = sym; + seg->val[i] = val; + t->last_len = i+1; + t->size++; + return; + } + if (!matched_seg && key == 0) { + matched_seg = seg; + matched_idx = i; + } + else if (key == sym) { + seg->val[i] = val; + return; + } + } + prev = seg; + seg = seg->next; + } + + /* Not found */ + t->size++; + if (matched_seg) { + matched_seg->key[matched_idx] = sym; + matched_seg->val[matched_idx] = val; + return; + } + + seg = (segment*)mrb_malloc(mrb, sizeof(segment)); + if (!seg) return; + seg->next = NULL; + seg->key[0] = sym; + seg->val[0] = val; + t->last_len = 1; + if (prev) { + prev->next = seg; + } + else { + t->rootseg = seg; + } } -/* - * Get a value for a symbol from the instance variable table. - * - * Parameters - * mrb - * t the variable table to be searched. - * sym the symbol to be used as the key. - * vp the value pointer. Receives the value if the specified symbol is - * contained in the instance variable table. - * Returns - * true if the specified symbol is contained in the instance variable table. - */ +/* Get a value for a symbol from the instance variable table. */ static mrb_bool iv_get(mrb_state *mrb, iv_tbl *t, mrb_sym sym, mrb_value *vp) { - khash_t(iv) *h = &t->h; - khiter_t k; + segment *seg; + size_t i; - k = kh_get(iv, mrb, h, sym); - if (k != kh_end(h)) { - if (vp) *vp = kh_value(h, k); - return TRUE; + if (t == NULL) return FALSE; + seg = t->rootseg; + while (seg) { + for (i=0; ikey[i]; + + if (!seg->next && i >= t->last_len) { + return FALSE; + } + if (key == sym) { + if (vp) *vp = seg->val[i]; + return TRUE; + } + } + seg = seg->next; } return FALSE; } -/* - * Deletes the value for the symbol from the instance variable table. - * - * Parameters - * t the variable table to be searched. - * sym the symbol to be used as the key. - * vp the value pointer. Receive the deleted value if the symbol is - * contained in the instance variable table. - * Returns - * true if the specified symbol is contained in the instance variable table. - */ +/* Deletes the value for the symbol from the instance variable table. */ static mrb_bool iv_del(mrb_state *mrb, iv_tbl *t, mrb_sym sym, mrb_value *vp) { + segment *seg; + size_t i; + if (t == NULL) return FALSE; - else { - khash_t(iv) *h = &t->h; - khiter_t k; - - k = kh_get(iv, mrb, h, sym); - if (k != kh_end(h)) { - mrb_value val = kh_value(h, k); - kh_del(iv, mrb, h, k); - if (vp) *vp = val; - return TRUE; + seg = t->rootseg; + while (seg) { + for (i=0; ikey[i]; + + if (!seg->next && i >= t->last_len) { + return FALSE; + } + if (key == sym) { + t->size--; + seg->key[i] = 0; + if (vp) *vp = seg->val[i]; + return TRUE; + } } + seg = seg->next; } return FALSE; } +/* Iterates over the instance variable table. */ static mrb_bool iv_foreach(mrb_state *mrb, iv_tbl *t, iv_foreach_func *func, void *p) { - if (t == NULL) { - return TRUE; - } - else { - khash_t(iv) *h = &t->h; - khiter_t k; - int n; + segment *seg; + size_t i; + int n; + + if (t == NULL) return TRUE; + seg = t->rootseg; + while (seg) { + for (i=0; ikey[i]; - for (k = kh_begin(h); k != kh_end(h); k++) { - if (kh_exist(h, k)) { - n = (*func)(mrb, kh_key(h, k), kh_value(h, k), p); + /* no value in last segment after last_len */ + if (!seg->next && i >= t->last_len) { + return FALSE; + } + if (key != 0) { + n =(*func)(mrb, key, seg->val[i], p); if (n > 0) return FALSE; if (n < 0) { - kh_del(iv, mrb, h, k); + t->size--; + seg->key[i] = 0; } } } + seg = seg->next; } return TRUE; } +/* Get the size of the instance variable table. */ static size_t iv_size(mrb_state *mrb, iv_tbl *t) { - if (t) { - return kh_size(&t->h); + segment *seg; + size_t size = 0; + + if (t == NULL) return 0; + if (t->size > 0) return t->size; + seg = t->rootseg; + while (seg) { + if (seg->next == NULL) { + size += t->last_len; + return size; + } + seg = seg->next; + size += MRB_IV_SEGMENT_SIZE; } + /* empty iv_tbl */ return 0; } +/* Copy the instance variable table. */ static iv_tbl* iv_copy(mrb_state *mrb, iv_tbl *t) { - return (iv_tbl*)kh_copy(iv, mrb, &t->h); + segment *seg; + iv_tbl *t2; + + size_t i; + + seg = t->rootseg; + t2 = iv_new(mrb); + + while (seg != NULL) { + for (i=0; ikey[i]; + mrb_value val = seg->val[i]; + + if ((seg->next == NULL) && (i >= t->last_len)) { + return t2; + } + iv_put(mrb, t2, key, val); + } + seg = seg->next; + } + return t2; } +/* Free memory of the instance variable table. */ static void iv_free(mrb_state *mrb, iv_tbl *t) { - kh_destroy(iv, mrb, &t->h); + segment *seg; + + seg = t->rootseg; + while (seg) { + segment *p = seg; + seg = seg->next; + mrb_free(mrb, p); + } + mrb_free(mrb, t); } static int @@ -170,9 +261,7 @@ iv_mark_i(mrb_state *mrb, mrb_sym sym, mrb_value v, void *p) static void mark_tbl(mrb_state *mrb, iv_tbl *t) { - if (t) { - iv_foreach(mrb, t, iv_mark_i, 0); - } + iv_foreach(mrb, t, iv_mark_i, 0); } void @@ -258,16 +347,17 @@ mrb_iv_get(mrb_state *mrb, mrb_value obj, mrb_sym sym) MRB_API void mrb_obj_iv_set(mrb_state *mrb, struct RObject *obj, mrb_sym sym, mrb_value v) { - iv_tbl *t = obj->iv; + iv_tbl *t; if (MRB_FROZEN_P(obj)) { mrb_raisef(mrb, E_FROZEN_ERROR, "can't modify frozen %S", mrb_obj_value(obj)); } - if (!t) { - t = obj->iv = iv_new(mrb); + if (!obj->iv) { + obj->iv = iv_new(mrb); } - mrb_write_barrier(mrb, (struct RBasic*)obj); + t = obj->iv; iv_put(mrb, t, sym, v); + mrb_write_barrier(mrb, (struct RBasic*)obj); } MRB_API void @@ -401,7 +491,7 @@ mrb_iv_remove(mrb_state *mrb, mrb_value obj, mrb_sym sym) iv_tbl *t = mrb_obj_ptr(obj)->iv; mrb_value val; - if (t && iv_del(mrb, t, sym, &val)) { + if (iv_del(mrb, t, sym, &val)) { return val; } } @@ -460,7 +550,7 @@ mrb_obj_instance_variables(mrb_state *mrb, mrb_value self) mrb_value ary; ary = mrb_ary_new(mrb); - if (obj_iv_p(self) && mrb_obj_ptr(self)->iv) { + if (obj_iv_p(self)) { iv_foreach(mrb, mrb_obj_ptr(self)->iv, iv_i, &ary); } return ary; @@ -506,9 +596,7 @@ mrb_mod_class_variables(mrb_state *mrb, mrb_value mod) ary = mrb_ary_new(mrb); c = mrb_class_ptr(mod); while (c) { - if (c->iv) { - iv_foreach(mrb, c->iv, cv_i, &ary); - } + iv_foreach(mrb, c->iv, cv_i, &ary); c = c->super; } return ary; @@ -563,14 +651,12 @@ mrb_mod_cv_set(mrb_state *mrb, struct RClass *c, mrb_sym sym, mrb_value v) struct RClass * cls = c; while (c) { - if (c->iv) { - iv_tbl *t = c->iv; + iv_tbl *t = c->iv; - if (iv_get(mrb, t, sym, NULL)) { - mrb_write_barrier(mrb, (struct RBasic*)c); - iv_put(mrb, t, sym, v); - return; - } + if (iv_get(mrb, t, sym, NULL)) { + iv_put(mrb, t, sym, v); + mrb_write_barrier(mrb, (struct RBasic*)c); + return; } c = c->super; } @@ -599,8 +685,8 @@ mrb_mod_cv_set(mrb_state *mrb, struct RClass *c, mrb_sym sym, mrb_value v) c->iv = iv_new(mrb); } - mrb_write_barrier(mrb, (struct RBasic*)c); iv_put(mrb, c->iv, sym, v); + mrb_write_barrier(mrb, (struct RBasic*)c); } MRB_API void @@ -613,10 +699,8 @@ MRB_API mrb_bool mrb_mod_cv_defined(mrb_state *mrb, struct RClass * c, mrb_sym sym) { while (c) { - if (c->iv) { - iv_tbl *t = c->iv; - if (iv_get(mrb, t, sym, NULL)) return TRUE; - } + iv_tbl *t = c->iv; + if (iv_get(mrb, t, sym, NULL)) return TRUE; c = c->super; } @@ -672,7 +756,7 @@ const_get(mrb_state *mrb, struct RClass *base, mrb_sym sym, mrb_bool top) L_RETRY: while (c) { - if (c->iv && (top || c != oclass || base == oclass)) { + if (top || c != oclass || base == oclass) { if (iv_get(mrb, c->iv, sym, &v)) return v; } @@ -703,22 +787,25 @@ mrb_vm_const_get(mrb_state *mrb, mrb_sym sym) struct RProc *proc; c = MRB_PROC_TARGET_CLASS(mrb->c->ci->proc); - if (c->iv && iv_get(mrb, c->iv, sym, &v)) { + if (iv_get(mrb, c->iv, sym, &v)) { return v; } c2 = c; while (c2 && c2->tt == MRB_TT_SCLASS) { mrb_value klass; - klass = mrb_obj_iv_get(mrb, (struct RObject *)c2, - mrb_intern_lit(mrb, "__attached__")); + + if (!iv_get(mrb, c2->iv, mrb_intern_lit(mrb, "__attached__"), &klass)) { + c2 = NULL; + break; + } c2 = mrb_class_ptr(klass); } - if (c2->tt == MRB_TT_CLASS || c2->tt == MRB_TT_MODULE) c = c2; + if (c2 && (c2->tt == MRB_TT_CLASS || c2->tt == MRB_TT_MODULE)) c = c2; mrb_assert(!MRB_PROC_CFUNC_P(mrb->c->ci->proc)); proc = mrb->c->ci->proc; while (proc) { c2 = MRB_PROC_TARGET_CLASS(proc); - if (c2 && c2->iv && iv_get(mrb, c2->iv, sym, &v)) { + if (c2 && iv_get(mrb, c2->iv, sym, &v)) { return v; } proc = proc->upper; @@ -796,9 +883,7 @@ mrb_mod_constants(mrb_state *mrb, mrb_value mod) mrb_get_args(mrb, "|b", &inherit); ary = mrb_ary_new(mrb); while (c) { - if (c->iv) { - iv_foreach(mrb, c->iv, const_i, &ary); - } + iv_foreach(mrb, c->iv, const_i, &ary); if (!inherit) break; c = c->super; if (c == mrb->object_class) break; @@ -811,9 +896,6 @@ mrb_gv_get(mrb_state *mrb, mrb_sym sym) { mrb_value v; - if (!mrb->globals) { - return mrb_nil_value(); - } if (iv_get(mrb, mrb->globals, sym, &v)) return v; return mrb_nil_value(); @@ -825,20 +907,15 @@ mrb_gv_set(mrb_state *mrb, mrb_sym sym, mrb_value v) iv_tbl *t; if (!mrb->globals) { - t = mrb->globals = iv_new(mrb); - } - else { - t = mrb->globals; + mrb->globals = iv_new(mrb); } + t = mrb->globals; iv_put(mrb, t, sym, v); } MRB_API void mrb_gv_remove(mrb_state *mrb, mrb_sym sym) { - if (!mrb->globals) { - return; - } iv_del(mrb, mrb->globals, sym, NULL); } @@ -870,9 +947,7 @@ mrb_f_global_variables(mrb_state *mrb, mrb_value self) size_t i; char buf[3]; - if (t) { - iv_foreach(mrb, t, gv_i, &ary); - } + iv_foreach(mrb, t, gv_i, &ary); buf[0] = '$'; buf[2] = 0; for (i = 1; i <= 9; ++i) { @@ -892,7 +967,7 @@ mrb_const_defined_0(mrb_state *mrb, mrb_value mod, mrb_sym id, mrb_bool exclude, tmp = klass; retry: while (tmp) { - if (tmp->iv && iv_get(mrb, tmp->iv, id, NULL)) { + if (iv_get(mrb, tmp->iv, id, NULL)) { return TRUE; } if (!recurse && (klass != mrb->object_class)) break; -- cgit v1.2.3 From 8f386f7663b099ec6861ec97e2192cdd71fbf7ff Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Thu, 2 Aug 2018 21:14:52 +0900 Subject: Remove utility functions: `mrb_vm_iv_{get,set}`. --- include/mruby/variable.h | 2 -- src/variable.c | 14 -------------- src/vm.c | 4 ++-- 3 files changed, 2 insertions(+), 18 deletions(-) diff --git a/include/mruby/variable.h b/include/mruby/variable.h index 5fef83faf..a4394fbd3 100644 --- a/include/mruby/variable.h +++ b/include/mruby/variable.h @@ -31,8 +31,6 @@ struct global_entry { mrb_value mrb_vm_special_get(mrb_state*, mrb_sym); void mrb_vm_special_set(mrb_state*, mrb_sym, mrb_value); -mrb_value mrb_vm_iv_get(mrb_state*, mrb_sym); -void mrb_vm_iv_set(mrb_state*, mrb_sym, mrb_value); mrb_value mrb_vm_cv_get(mrb_state*, mrb_sym); void mrb_vm_cv_set(mrb_state*, mrb_sym, mrb_value); mrb_value mrb_vm_const_get(mrb_state*, mrb_sym); diff --git a/src/variable.c b/src/variable.c index cbfdb2f2d..6612c186f 100644 --- a/src/variable.c +++ b/src/variable.c @@ -498,20 +498,6 @@ mrb_iv_remove(mrb_state *mrb, mrb_value obj, mrb_sym sym) return mrb_undef_value(); } -mrb_value -mrb_vm_iv_get(mrb_state *mrb, mrb_sym sym) -{ - /* get self */ - return mrb_iv_get(mrb, mrb->c->stack[0], sym); -} - -void -mrb_vm_iv_set(mrb_state *mrb, mrb_sym sym, mrb_value v) -{ - /* get self */ - mrb_iv_set(mrb, mrb->c->stack[0], sym, v); -} - static int iv_i(mrb_state *mrb, mrb_sym sym, mrb_value v, void *p) { diff --git a/src/vm.c b/src/vm.c index 066c6ba2e..2bf8f965d 100644 --- a/src/vm.c +++ b/src/vm.c @@ -1141,7 +1141,7 @@ RETRY_TRY_BLOCK: /* A Bx R(A) := ivget(Bx) */ int a = GETARG_A(i); int bx = GETARG_Bx(i); - mrb_value val = mrb_vm_iv_get(mrb, syms[bx]); + mrb_value val = mrb_iv_get(mrb, regs[0], syms[bx]); regs[a] = val; NEXT; } @@ -1150,7 +1150,7 @@ RETRY_TRY_BLOCK: /* A Bx ivset(Syms(Bx),R(A)) */ int a = GETARG_A(i); int bx = GETARG_Bx(i); - mrb_vm_iv_set(mrb, syms[bx], regs[a]); + mrb_iv_set(mrb, regs[0], syms[bx], regs[a]); NEXT; } -- cgit v1.2.3 From 0dca6206c1920d388fbf4d125c5984b1af530f2b Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Fri, 3 Aug 2018 15:03:09 +0900 Subject: Rename ambiguous function names. `mrb_iv_p` -> `mrb_iv_name_sym_p` `mrb_iv_check` -> `mrb_iv_name_sym_check` --- include/mruby/variable.h | 4 ++-- src/class.c | 4 ++-- src/kernel.c | 8 ++++---- src/variable.c | 6 +++--- 4 files changed, 11 insertions(+), 11 deletions(-) diff --git a/include/mruby/variable.h b/include/mruby/variable.h index a4394fbd3..a0fbca1f9 100644 --- a/include/mruby/variable.h +++ b/include/mruby/variable.h @@ -40,8 +40,8 @@ MRB_API void mrb_const_set(mrb_state*, mrb_value, mrb_sym, mrb_value); MRB_API mrb_bool mrb_const_defined(mrb_state*, mrb_value, mrb_sym); MRB_API void mrb_const_remove(mrb_state*, mrb_value, mrb_sym); -MRB_API mrb_bool mrb_iv_p(mrb_state *mrb, mrb_sym sym); -MRB_API void mrb_iv_check(mrb_state *mrb, mrb_sym sym); +MRB_API mrb_bool mrb_iv_name_sym_p(mrb_state *mrb, mrb_sym sym); +MRB_API void mrb_iv_name_sym_check(mrb_state *mrb, mrb_sym sym); MRB_API mrb_value mrb_obj_iv_get(mrb_state *mrb, struct RObject *obj, mrb_sym sym); MRB_API void mrb_obj_iv_set(mrb_state *mrb, struct RObject *obj, mrb_sym sym, mrb_value v); MRB_API mrb_bool mrb_obj_iv_defined(mrb_state *mrb, struct RObject *obj, mrb_sym sym); diff --git a/src/class.c b/src/class.c index 97b5df926..d3a1e2fb2 100644 --- a/src/class.c +++ b/src/class.c @@ -1480,7 +1480,7 @@ mrb_mod_attr_reader(mrb_state *mrb, mrb_value mod) mrb_str_cat_lit(mrb, str, "@"); mrb_str_cat_str(mrb, str, name); sym = mrb_intern_str(mrb, str); - mrb_iv_check(mrb, sym); + mrb_iv_name_sym_check(mrb, sym); name = mrb_symbol_value(sym); p = mrb_proc_new_cfunc_with_env(mrb, attr_reader, 1, &name); MRB_METHOD_FROM_PROC(m, p); @@ -1525,7 +1525,7 @@ mrb_mod_attr_writer(mrb_state *mrb, mrb_value mod) mrb_str_cat_lit(mrb, str, "@"); mrb_str_cat_str(mrb, str, name); sym = mrb_intern_str(mrb, str); - mrb_iv_check(mrb, sym); + mrb_iv_name_sym_check(mrb, sym); attr = mrb_symbol_value(sym); /* prepare method name (name=) */ diff --git a/src/kernel.c b/src/kernel.c index 7459c83af..50ad50f00 100644 --- a/src/kernel.c +++ b/src/kernel.c @@ -575,7 +575,7 @@ mrb_obj_ivar_defined(mrb_state *mrb, mrb_value self) mrb_sym sym; mrb_get_args(mrb, "n", &sym); - mrb_iv_check(mrb, sym); + mrb_iv_name_sym_check(mrb, sym); return mrb_bool_value(mrb_iv_defined(mrb, self, sym)); } @@ -605,7 +605,7 @@ mrb_obj_ivar_get(mrb_state *mrb, mrb_value self) mrb_sym iv_name; mrb_get_args(mrb, "n", &iv_name); - mrb_iv_check(mrb, iv_name); + mrb_iv_name_sym_check(mrb, iv_name); return mrb_iv_get(mrb, self, iv_name); } @@ -636,7 +636,7 @@ mrb_obj_ivar_set(mrb_state *mrb, mrb_value self) mrb_value val; mrb_get_args(mrb, "no", &iv_name, &val); - mrb_iv_check(mrb, iv_name); + mrb_iv_name_sym_check(mrb, iv_name); mrb_iv_set(mrb, self, iv_name, val); return val; } @@ -951,7 +951,7 @@ mrb_obj_remove_instance_variable(mrb_state *mrb, mrb_value self) mrb_value val; mrb_get_args(mrb, "n", &sym); - mrb_iv_check(mrb, sym); + mrb_iv_name_sym_check(mrb, sym); val = mrb_iv_remove(mrb, self, sym); if (mrb_undef_p(val)) { mrb_name_error(mrb, sym, "instance variable %S not defined", mrb_sym2str(mrb, sym)); diff --git a/src/variable.c b/src/variable.c index 6612c186f..e753f8d29 100644 --- a/src/variable.c +++ b/src/variable.c @@ -393,7 +393,7 @@ mrb_iv_defined(mrb_state *mrb, mrb_value obj, mrb_sym sym) #define identchar(c) (ISALNUM(c) || (c) == '_' || !ISASCII(c)) MRB_API mrb_bool -mrb_iv_p(mrb_state *mrb, mrb_sym iv_name) +mrb_iv_name_sym_p(mrb_state *mrb, mrb_sym iv_name) { const char *s; mrb_int i, len; @@ -409,9 +409,9 @@ mrb_iv_p(mrb_state *mrb, mrb_sym iv_name) } MRB_API void -mrb_iv_check(mrb_state *mrb, mrb_sym iv_name) +mrb_iv_name_sym_check(mrb_state *mrb, mrb_sym iv_name) { - if (!mrb_iv_p(mrb, iv_name)) { + if (!mrb_iv_name_sym_p(mrb, iv_name)) { mrb_name_error(mrb, iv_name, "'%S' is not allowed as an instance variable name", mrb_sym2str(mrb, iv_name)); } } -- cgit v1.2.3 From 62e8e910b2905c9b7c964ad4e21c127f7ff3a706 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Mon, 6 Aug 2018 16:37:27 +0900 Subject: Reimplement `Hash#compact!` to conform the standard behavior. `Hash#compact!` should return `nil` if the receiver does not change. --- mrbgems/mruby-hash-ext/mrblib/hash.rb | 35 +++++++++++++++++++++--- mrbgems/mruby-hash-ext/src/hash-ext.c | 51 +++-------------------------------- 2 files changed, 36 insertions(+), 50 deletions(-) diff --git a/mrbgems/mruby-hash-ext/mrblib/hash.rb b/mrbgems/mruby-hash-ext/mrblib/hash.rb index 549bca0a8..eaf54b871 100644 --- a/mrbgems/mruby-hash-ext/mrblib/hash.rb +++ b/mrbgems/mruby-hash-ext/mrblib/hash.rb @@ -114,6 +114,31 @@ class Hash alias update merge! + ## + # call-seq: + # hsh.compact! -> hsh + # + # Removes all nil values from the hash. Returns the hash. + # Returns nil if the hash does not contain nil values. + # + # h = { a: 1, b: false, c: nil } + # h.compact! #=> { a: 1, b: false } + # + + def compact! + h = {} + keys = self.keys + nk = keys.select{|k| + self[k] != nil + } + return nil if (keys.size == nk.size) + nk.each {|k| + h[k] = self[k] + } + h + self.replace(h) + end + ## # call-seq: # hsh.compact -> new_hsh @@ -125,9 +150,13 @@ class Hash # h #=> { a: 1, b: false, c: nil } # def compact - result = self.dup - result.compact! - result + h = {} + self.keys.select{|k| + self[k] != nil + }.each {|k| + h[k] = self[k] + } + h end ## diff --git a/mrbgems/mruby-hash-ext/src/hash-ext.c b/mrbgems/mruby-hash-ext/src/hash-ext.c index 6619f5268..e6112667b 100644 --- a/mrbgems/mruby-hash-ext/src/hash-ext.c +++ b/mrbgems/mruby-hash-ext/src/hash-ext.c @@ -36,42 +36,6 @@ hash_values_at(mrb_state *mrb, mrb_value hash) return result; } -/* - * call-seq: - * hsh.compact! -> hsh - * - * Removes all nil values from the hash. Returns the hash. - * - * h = { a: 1, b: false, c: nil } - * h.compact! #=> { a: 1, b: false } - */ -static mrb_value -hash_compact_bang(mrb_state *mrb, mrb_value hash) -{ - khiter_t k; - khash_t(ht) *h = RHASH_TBL(hash); - mrb_int n = -1; - - if (!h) return mrb_nil_value(); - for (k = kh_begin(h); k != kh_end(h); k++) { - if (kh_exist(h, k)) { - mrb_value val = kh_value(h, k).v; - khiter_t k2; - - if (mrb_nil_p(val)) { - kh_del(ht, mrb, h, k); - n = kh_value(h, k).n; - for (k2 = kh_begin(h); k2 != kh_end(h); k2++) { - if (!kh_exist(h, k2)) continue; - if (kh_value(h, k2).n > n) kh_value(h, k2).n--; - } - } - } - } - if (n < 0) return mrb_nil_value(); - return hash; -} - /* * call-seq: * hsh.slice(*keys) -> a_hash @@ -85,28 +49,22 @@ hash_compact_bang(mrb_state *mrb, mrb_value hash) static mrb_value hash_slice(mrb_state *mrb, mrb_value hash) { - khash_t(ht) *h = RHASH_TBL(hash); mrb_value *argv, result; mrb_int argc, i; - khiter_t k; - int ai; mrb_get_args(mrb, "*", &argv, &argc); - if (argc == 0 || h == NULL) { + if (argc == 0) { return mrb_hash_new_capa(mrb, argc); } result = mrb_hash_new_capa(mrb, argc); - ai = mrb_gc_arena_save(mrb); for (i = 0; i < argc; i++) { mrb_value key = argv[i]; + mrb_value val; - k = kh_get(ht, mrb, h, key); - if (k != kh_end(h)) { - mrb_value val = kh_value(h, k).v; - + val = mrb_hash_fetch(mrb, hash, key, mrb_undef_value()); + if (!mrb_undef_p(val)) { mrb_hash_set(mrb, result, key, val); } - mrb_gc_arena_restore(mrb, ai); } return result; } @@ -118,7 +76,6 @@ mrb_mruby_hash_ext_gem_init(mrb_state *mrb) h = mrb->hash_class; mrb_define_method(mrb, h, "values_at", hash_values_at, MRB_ARGS_ANY()); - mrb_define_method(mrb, h, "compact!", hash_compact_bang, MRB_ARGS_NONE()); mrb_define_method(mrb, h, "slice", hash_slice, MRB_ARGS_ANY()); } -- cgit v1.2.3 From 54246db00aa9ae5a048d65f4263a3d14fd65d9d0 Mon Sep 17 00:00:00 2001 From: pyama86 Date: Mon, 6 Aug 2018 18:15:00 +0900 Subject: irep is released when Fiber is terminated --- src/gc.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/gc.c b/src/gc.c index 33d83f28e..9858e45fc 100644 --- a/src/gc.c +++ b/src/gc.c @@ -965,9 +965,11 @@ gc_gray_mark(mrb_state *mrb, mrb_gc *gc, struct RBasic *obj) size_t i; mrb_callinfo *ci; - if (!c) break; + if (!c || c->status == MRB_FIBER_TERMINATED) break; + /* mark stack */ i = c->stack - c->stbase; + if (c->ci) { i += ci_nregs(c->ci); } -- cgit v1.2.3 From 35be8b252495d92ca811d76996f03c470ee33380 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Tue, 7 Aug 2018 23:01:22 +0900 Subject: Fixed the corner case bug in `String#{gsub!,sub!}`. `"a".sub!("a", "a")` should not return `nil`. --- mrblib/string.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mrblib/string.rb b/mrblib/string.rb index ee98cfa0c..07b80b340 100644 --- a/mrblib/string.rb +++ b/mrblib/string.rb @@ -99,7 +99,7 @@ class String raise FrozenError, "can't modify frozen String" if frozen? return to_enum(:gsub!, *args) if args.length == 1 && !block str = self.gsub(*args, &block) - return nil if str == self + return nil unless self.index(args[0]) self.replace(str) end @@ -161,7 +161,7 @@ class String def sub!(*args, &block) raise FrozenError, "can't modify frozen String" if frozen? str = self.sub(*args, &block) - return nil if str == self + return nil unless self.index(args[0]) self.replace(str) end -- cgit v1.2.3 From e3b181586c3f433debc7b5c4b7d45f8b8fe91970 Mon Sep 17 00:00:00 2001 From: Ukrainskiy Sergey Date: Thu, 9 Aug 2018 17:14:00 +0900 Subject: Fix weird behavior of the NODE_NEGATE --- mrbgems/mruby-compiler/core/codegen.c | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/mrbgems/mruby-compiler/core/codegen.c b/mrbgems/mruby-compiler/core/codegen.c index fec747f0c..ceedb49ad 100644 --- a/mrbgems/mruby-compiler/core/codegen.c +++ b/mrbgems/mruby-compiler/core/codegen.c @@ -2323,12 +2323,11 @@ codegen(codegen_scope *s, node *tree, int val) case NODE_NEGATE: { nt = nint(tree->car); - tree = tree->cdr; switch (nt) { #ifndef MRB_WITHOUT_FLOAT case NODE_FLOAT: if (val) { - char *p = (char*)tree; + char *p = (char*)tree->cdr; mrb_float f = mrb_float_read(p, NULL); int off = new_lit(s, mrb_float_value(s->mrb, -f)); @@ -2340,6 +2339,7 @@ codegen(codegen_scope *s, node *tree, int val) case NODE_INT: if (val) { + tree = tree->cdr; char *p = (char*)tree->car; int base = nint(tree->cdr->car); mrb_int i; @@ -2373,13 +2373,10 @@ codegen(codegen_scope *s, node *tree, int val) default: if (val) { - int sym = new_msym(s, mrb_intern_lit(s->mrb, "-")); - - genop(s, MKOP_ABx(OP_LOADI, cursp(), 0)); - push(); + int sym = new_msym(s, mrb_intern_lit(s->mrb, "-@")); codegen(s, tree, VAL); - pop(); pop(); - genop(s, MKOP_ABC(OP_SUB, cursp(), sym, 2)); + pop(); + genop(s, MKOP_ABC(OP_SEND, cursp(), sym, 0)); } else { codegen(s, tree, NOVAL); -- cgit v1.2.3 From 672110dbe8b116d2ef5594d908e5e2bfe2231a18 Mon Sep 17 00:00:00 2001 From: Ukrainskiy Sergey Date: Thu, 9 Aug 2018 17:57:18 +0900 Subject: Small fix --- mrbgems/mruby-compiler/core/codegen.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/mrbgems/mruby-compiler/core/codegen.c b/mrbgems/mruby-compiler/core/codegen.c index ceedb49ad..471956f92 100644 --- a/mrbgems/mruby-compiler/core/codegen.c +++ b/mrbgems/mruby-compiler/core/codegen.c @@ -2339,9 +2339,8 @@ codegen(codegen_scope *s, node *tree, int val) case NODE_INT: if (val) { - tree = tree->cdr; - char *p = (char*)tree->car; - int base = nint(tree->cdr->car); + char *p = (char*)tree->cdr->car; + int base = nint(tree->cdr->cdr->car); mrb_int i; mrb_code co; mrb_bool overflow; -- cgit v1.2.3 From fbe876b87169c9d5c55e79cc932790297f98a1be Mon Sep 17 00:00:00 2001 From: Ukrainskiy Sergey Date: Fri, 10 Aug 2018 06:44:19 +0900 Subject: Added push() after OP_SEND --- mrbgems/mruby-compiler/core/codegen.c | 1 + 1 file changed, 1 insertion(+) diff --git a/mrbgems/mruby-compiler/core/codegen.c b/mrbgems/mruby-compiler/core/codegen.c index 471956f92..12725f4f3 100644 --- a/mrbgems/mruby-compiler/core/codegen.c +++ b/mrbgems/mruby-compiler/core/codegen.c @@ -2376,6 +2376,7 @@ codegen(codegen_scope *s, node *tree, int val) codegen(s, tree, VAL); pop(); genop(s, MKOP_ABC(OP_SEND, cursp(), sym, 0)); + push(); } else { codegen(s, tree, NOVAL); -- cgit v1.2.3 From b03f1f78e3f1bab579b21219bbecffb6eb4b7020 Mon Sep 17 00:00:00 2001 From: Kazuhiro Sera Date: Sat, 11 Aug 2018 00:28:32 +0900 Subject: Fix misspelling words in comments --- doc/guides/mrbgems.md | 4 ++-- include/mruby.h | 4 ++-- minirake | 2 +- mrbgems/mruby-bin-debugger/bintest/print.rb | 2 +- mrbgems/mruby-compiler/core/codegen.c | 2 +- mrbgems/mruby-socket/src/socket.c | 2 +- test/t/literals.rb | 2 +- test/t/module.rb | 4 ++-- 8 files changed, 11 insertions(+), 11 deletions(-) diff --git a/doc/guides/mrbgems.md b/doc/guides/mrbgems.md index 8dac0dc86..0fcc936ed 100644 --- a/doc/guides/mrbgems.md +++ b/doc/guides/mrbgems.md @@ -179,11 +179,11 @@ Version requirement supports following operators: When more than one version requirements is passed, the dependency must satisfy all of it. -You can have default gem to use as depedency when it's not defined in *build_config.rb*. +You can have default gem to use as dependency when it's not defined in *build_config.rb*. When the last argument of `add_dependency` call is `Hash`, it will be treated as default gem information. Its format is same as argument of method `MRuby::Build#gem`, expect that it can't be treated as path gem location. -When a special version of depedency is required, +When a special version of dependency is required, use `MRuby::Build#gem` in *build_config.rb* to override default gem. If you have conflicting GEMs use the following method: diff --git a/include/mruby.h b/include/mruby.h index 93fc0f010..bc6d72330 100644 --- a/include/mruby.h +++ b/include/mruby.h @@ -782,7 +782,7 @@ MRB_API struct RClass * mrb_define_module_under(mrb_state *mrb, struct RClass *o #define MRB_ARGS_REQ(n) ((mrb_aspec)((n)&0x1f) << 18) /** - * Funtion takes n optional arguments + * Function takes n optional arguments * * @param n * The number of optional arguments. @@ -790,7 +790,7 @@ MRB_API struct RClass * mrb_define_module_under(mrb_state *mrb, struct RClass *o #define MRB_ARGS_OPT(n) ((mrb_aspec)((n)&0x1f) << 13) /** - * Funtion takes n1 mandatory arguments and n2 optional arguments + * Function takes n1 mandatory arguments and n2 optional arguments * * @param n1 * The number of required arguments. diff --git a/minirake b/minirake index 8b6bfa296..ad8276a6d 100755 --- a/minirake +++ b/minirake @@ -95,7 +95,7 @@ module MiniRake def done?; @done end def running?; @running end - # Invoke the task if it is needed. Prerequites are invoked first. + # Invoke the task if it is needed. Prerequisites are invoked first. def invoke puts "Invoke #{name} (already=[#{@already_invoked}], needed=[#{needed?}])" if $trace return if @already_invoked diff --git a/mrbgems/mruby-bin-debugger/bintest/print.rb b/mrbgems/mruby-bin-debugger/bintest/print.rb index 0d4aad011..6675392b8 100644 --- a/mrbgems/mruby-bin-debugger/bintest/print.rb +++ b/mrbgems/mruby-bin-debugger/bintest/print.rb @@ -317,7 +317,7 @@ TestConstNameSubClass.new.m() bp = nil SRC - # todo: wait for 'break' to be implimented + # todo: wait for 'break' to be implemented tc = [] 9.times { tc << {:cmd=>"s"} } tc << {:cmd=>"p CONST", :exp=>"super class"} diff --git a/mrbgems/mruby-compiler/core/codegen.c b/mrbgems/mruby-compiler/core/codegen.c index fec747f0c..945ddcc1a 100644 --- a/mrbgems/mruby-compiler/core/codegen.c +++ b/mrbgems/mruby-compiler/core/codegen.c @@ -200,7 +200,7 @@ genop_peep(codegen_scope *s, mrb_code i, int val) switch (c0) { case OP_MOVE: if (GETARG_A(i) == GETARG_A(i0)) { - /* skip overriden OP_MOVE */ + /* skip overridden OP_MOVE */ s->pc--; s->iseq[s->pc] = i; } diff --git a/mrbgems/mruby-socket/src/socket.c b/mrbgems/mruby-socket/src/socket.c index b3ca8b1c9..b44371544 100644 --- a/mrbgems/mruby-socket/src/socket.c +++ b/mrbgems/mruby-socket/src/socket.c @@ -300,7 +300,7 @@ mrb_basicsocket_getpeereid(mrb_state *mrb, mrb_value self) mrb_ary_push(mrb, ary, mrb_fixnum_value((mrb_int)egid)); return ary; #else - mrb_raise(mrb, E_RUNTIME_ERROR, "getpeereid is not avaialble on this system"); + mrb_raise(mrb, E_RUNTIME_ERROR, "getpeereid is not available on this system"); return mrb_nil_value(); #endif } diff --git a/test/t/literals.rb b/test/t/literals.rb index 51a37c32d..6344219aa 100644 --- a/test/t/literals.rb +++ b/test/t/literals.rb @@ -22,7 +22,7 @@ assert('Literals Numerical', '8.7.6.2') do # decimal assert_equal 999, 0d999 assert_equal 999, 0D999 - # decimal seperator + # decimal separator assert_equal 10000000, 10_000_000 assert_equal 10, 1_0 # integer with exponent diff --git a/test/t/module.rb b/test/t/module.rb index 5a46c24ff..fb82fc934 100644 --- a/test/t/module.rb +++ b/test/t/module.rb @@ -699,7 +699,7 @@ end end end - # these assertions will not run without a #assert_seperately method + # these assertions will not run without a #assert_separately method #assert 'test_prepend_optmethod' do # bug7983 = '[ruby-dev:47124] [Bug #7983]' # assert_separately [], %{ @@ -807,7 +807,7 @@ end assert_equal([m, c2, m, c1], c2.ancestors[0, 4], "should accesisble prepended module in superclass") end - # requires #assert_seperately + # requires #assert_separately #assert 'Module#prepend call super' do # assert_separately([], <<-'end;') #do # bug10847 = '[ruby-core:68093] [Bug #10847]' -- cgit v1.2.3 From fee9ec61bb9808b5235a78b923a2b8baeebbea8c Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Mon, 13 Aug 2018 15:07:10 +0900 Subject: Make `Array.new` to accept both integers and floats. This time we used `Integral` module which is mruby specific. --- mrblib/array.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mrblib/array.rb b/mrblib/array.rb index 334f4e984..13c5d646c 100644 --- a/mrblib/array.rb +++ b/mrblib/array.rb @@ -66,7 +66,7 @@ class Array # # ISO 15.2.12.5.15 def initialize(size=0, obj=nil, &block) - raise TypeError, "expected Integer for 1st argument" unless size.kind_of? Integer + raise TypeError, "expected Integer for 1st argument" unless size.kind_of? Integral raise ArgumentError, "negative array size" if size < 0 self.clear -- cgit v1.2.3 From 1e52d47bc3e0d287e5d2cf5c61df60f8613db2aa Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Mon, 13 Aug 2018 15:24:51 +0900 Subject: Simplify `mruby-inline-struct` tests. `gcc -O3` raises error on truncation using `snprintf`. --- mrbgems/mruby-inline-struct/test/inline.c | 18 ++++---- mrbgems/mruby-inline-struct/test/inline.rb | 67 ++++++++---------------------- 2 files changed, 26 insertions(+), 59 deletions(-) diff --git a/mrbgems/mruby-inline-struct/test/inline.c b/mrbgems/mruby-inline-struct/test/inline.c index 95341d348..91c767f30 100644 --- a/mrbgems/mruby-inline-struct/test/inline.c +++ b/mrbgems/mruby-inline-struct/test/inline.c @@ -11,17 +11,17 @@ istruct_test_initialize(mrb_state *mrb, mrb_value self) mrb_value object; mrb_get_args(mrb, "o", &object); - if (mrb_float_p(object)) - { - snprintf(string, size, "float(%.3f)", mrb_float(object)); + if (mrb_float_p(object)) { + strncpy(string, "float", size-1); } - else if (mrb_fixnum_p(object)) - { - snprintf(string, size, "fixnum(%" MRB_PRId ")", mrb_fixnum(object)); + else if (mrb_fixnum_p(object)) { + strncpy(string, "fixnum", size-1); } - else if (mrb_string_p(object)) - { - snprintf(string, size, "string(%s)", mrb_string_value_cstr(mrb, &object)); + else if (mrb_string_p(object)) { + strncpy(string, "string", size-1); + } + else { + strncpy(string, "anything", size-1); } string[size - 1] = 0; // force NULL at the end diff --git a/mrbgems/mruby-inline-struct/test/inline.rb b/mrbgems/mruby-inline-struct/test/inline.rb index 495859232..f959a17c4 100644 --- a/mrbgems/mruby-inline-struct/test/inline.rb +++ b/mrbgems/mruby-inline-struct/test/inline.rb @@ -17,14 +17,14 @@ end assert('InlineStructTest#dup') do obj = InlineStructTest.new(1) - assert_equal obj.to_s, 'fixnum(1)' - assert_equal obj.dup.to_s, 'fixnum(1)' + assert_equal obj.to_s, 'fixnum' + assert_equal obj.dup.to_s, 'fixnum' end assert('InlineStructTest#clone') do obj = InlineStructTest.new(1) - assert_equal obj.to_s, 'fixnum(1)' - assert_equal obj.clone.to_s, 'fixnum(1)' + assert_equal obj.to_s, 'fixnum' + assert_equal obj.clone.to_s, 'fixnum' end assert('InlineStruct#object_id') do @@ -38,22 +38,22 @@ end assert('InlineStructTest#mutate (dup)') do obj1 = InlineStructTest.new("foo") - assert_equal obj1.to_s, "string(foo)" + assert_equal obj1.to_s, "string" obj2 = obj1.dup - assert_equal obj2.to_s, "string(foo)" + assert_equal obj2.to_s, "string" obj1.mutate - assert_equal obj1.to_s, "mutate(foo)" - assert_equal obj2.to_s, "string(foo)" + assert_equal obj1.to_s, "mutate" + assert_equal obj2.to_s, "string" end assert('InlineStructTest#mutate (clone)') do obj1 = InlineStructTest.new("foo") - assert_equal obj1.to_s, "string(foo)" + assert_equal obj1.to_s, "string" obj2 = obj1.clone - assert_equal obj2.to_s, "string(foo)" + assert_equal obj2.to_s, "string" obj1.mutate - assert_equal obj1.to_s, "mutate(foo)" - assert_equal obj2.to_s, "string(foo)" + assert_equal obj1.to_s, "mutate" + assert_equal obj2.to_s, "string" end assert('InlineStructTest#test_receive(string)') do @@ -101,26 +101,6 @@ if InlineStructTest.length == 24 assert('InlineStructTest length [64 bit]') do assert_equal InlineStructTest.length, 3 * 8 end - - assert('InlineStructTest w/float [64 bit]') do - obj = InlineStructTest.new(1.25) - assert_equal obj.to_s, "float(1.250)" - end - - assert('InlineStructTest w/fixnum [64 bit]') do - obj = InlineStructTest.new(42) - assert_equal obj.to_s, "fixnum(42)" - end - - assert('InlineStructTest w/string [64 bit]') do - obj = InlineStructTest.new("hello") - assert_equal obj.to_s, "string(hello)" - end - - assert('InlineStructTest w/long string [64 bit]') do - obj = InlineStructTest.new("this won't fit in 3 * 8 bytes available for the structure") - assert_equal obj.to_s, "string(this won't fit i" - end end # 32-bit mode @@ -128,24 +108,11 @@ if InlineStructTest.length == 12 assert('InlineStructTest length [32 bit]') do assert_equal InlineStructTest.length, 3 * 4 end +end - assert('InlineStructTest w/float [32 bit]') do - obj = InlineStructTest.new(1.25) - assert_equal obj.to_s, "float(1.250" - end - - assert('InlineStructTest w/fixnum [32 bit]') do - obj = InlineStructTest.new(42) - assert_equal obj.to_s, "fixnum(42)" - end - - assert('InlineStructTest w/string [32 bit]') do - obj = InlineStructTest.new("hello") - assert_equal obj.to_s, "string(hell" - end - - assert('InlineStructTest w/long string [32 bit]') do - obj = InlineStructTest.new("this won't fit in 3 * 4 bytes available for the structure") - assert_equal obj.to_s, "string(this" +# 16-bit mode +if InlineStructTest.length == 6 + assert('InlineStructTest length [16 bit]') do + assert_equal InlineStructTest.length, 3 * 2 end end -- cgit v1.2.3 From 14206a75a37020a3a4926b1289a1f07277b78578 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Mon, 13 Aug 2018 15:34:13 +0900 Subject: Remove potential path to avoid uninitialized variable access. --- mrbgems/mruby-struct/src/struct.c | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/mrbgems/mruby-struct/src/struct.c b/mrbgems/mruby-struct/src/struct.c index fe7e73f04..b567a00d5 100644 --- a/mrbgems/mruby-struct/src/struct.c +++ b/mrbgems/mruby-struct/src/struct.c @@ -302,17 +302,19 @@ mrb_struct_s_def(mrb_state *mrb, mrb_value klass) } } rest = mrb_ary_new_from_values(mrb, argcnt, pargv); - for (i=0; i Date: Mon, 13 Aug 2018 23:11:34 +0900 Subject: Try to fix a fragile `File#mtime` test. --- mrbgems/mruby-io/src/file.c | 4 ---- mrbgems/mruby-io/test/file.rb | 8 ++++---- 2 files changed, 4 insertions(+), 8 deletions(-) diff --git a/mrbgems/mruby-io/src/file.c b/mrbgems/mruby-io/src/file.c index ca21256cc..e65741061 100644 --- a/mrbgems/mruby-io/src/file.c +++ b/mrbgems/mruby-io/src/file.c @@ -345,11 +345,7 @@ mrb_file_mtime(mrb_state *mrb, mrb_value self) fd = (int)mrb_fixnum(mrb_io_fileno(mrb, self)); if (fstat(fd, &st) == -1) return mrb_false_value(); -#ifndef MRB_WITHOUT_FLOAT - return mrb_funcall(mrb, obj, "at", 1, mrb_float_value(mrb, st.st_mtime)); -#else return mrb_funcall(mrb, obj, "at", 1, mrb_fixnum_value(st.st_mtime)); -#endif } mrb_value diff --git a/mrbgems/mruby-io/test/file.rb b/mrbgems/mruby-io/test/file.rb index ab4678fe9..ca285f5bd 100644 --- a/mrbgems/mruby-io/test/file.rb +++ b/mrbgems/mruby-io/test/file.rb @@ -73,12 +73,12 @@ assert('File#mtime') do skip "File#mtime require Time" end begin - now = Time.now.to_i - mt = 0 File.open("#{$mrbtest_io_wfname}.mtime", 'w') do |f| - mt = f.mtime.to_i + assert_equal Time, f.mtime.class + File.open("#{$mrbtest_io_wfname}.mtime", 'r') do |f2| + assert_equal true, f.mtime == f2.mtime + end end - assert_equal true, mt >= now ensure File.delete("#{$mrbtest_io_wfname}.mtime") end -- cgit v1.2.3 From fe77272c25f3b6d91506a51d0621275074542890 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Sat, 18 Aug 2018 22:40:44 +0900 Subject: `Kernel#p` should return an array of arguments; fix #4083 Although the return value is not defined in ISO, it is better to behave as CRuby does. --- mrbgems/mruby-print/mrblib/print.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mrbgems/mruby-print/mrblib/print.rb b/mrbgems/mruby-print/mrblib/print.rb index 38a10661b..fa83c47de 100644 --- a/mrbgems/mruby-print/mrblib/print.rb +++ b/mrbgems/mruby-print/mrblib/print.rb @@ -45,7 +45,7 @@ module Kernel __printstr__ "\n" i += 1 end - args[0] + args.__svalue end unless Kernel.respond_to?(:sprintf) -- cgit v1.2.3 From bfd11aab35ab942363359a989712e9a6f35b9295 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Tue, 31 Jul 2018 16:14:18 +0900 Subject: Check size of the integer multiply before actual overflow; fix #4062 --- mrbgems/mruby-sprintf/src/sprintf.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/mrbgems/mruby-sprintf/src/sprintf.c b/mrbgems/mruby-sprintf/src/sprintf.c index 7eea1a1f3..738c5485f 100644 --- a/mrbgems/mruby-sprintf/src/sprintf.c +++ b/mrbgems/mruby-sprintf/src/sprintf.c @@ -119,13 +119,11 @@ mrb_fix2binstr(mrb_state *mrb, mrb_value x, int base) #define FPREC0 128 #define CHECK(l) do {\ -/* int cr = ENC_CODERANGE(result);*/\ while ((l) >= bsiz - blen) {\ + if (bsiz > MRB_INT_MAX/2) mrb_raise(mrb, E_ARGUMENT_ERROR, "too big specifier"); \ bsiz*=2;\ - if (bsiz < 0) mrb_raise(mrb, E_ARGUMENT_ERROR, "too big specifier"); \ }\ mrb_str_resize(mrb, result, bsiz);\ -/* ENC_CODERANGE_SET(result, cr);*/\ buf = RSTRING_PTR(result);\ } while (0) @@ -202,11 +200,10 @@ check_name_arg(mrb_state *mrb, int posarg, const char *name, mrb_int len) #define GETNUM(n, val) \ for (; p < end && ISDIGIT(*p); p++) {\ - mrb_int next_n = 10 * n + (*p - '0'); \ - if (next_n / 10 != n) {\ + if (n > MRB_INT_MAX/10) {\ mrb_raise(mrb, E_ARGUMENT_ERROR, #val " too big"); \ } \ - n = next_n; \ + n = 10 * n + (*p - '0'); \ } \ if (p >= end) { \ mrb_raise(mrb, E_ARGUMENT_ERROR, "malformed format string - %*[0-9]"); \ -- cgit v1.2.3 From fd086833ff6673ab11e6ecea573851593263ae6a Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Tue, 31 Jul 2018 16:48:50 +0900 Subject: Reorganize flags values for classes; fix #3975 Renamed flag macro names as well: `MRB_FLAG_IS_FROZEN` -> `MRB_FL_OBJ_FROZEN` `MRB_FLAG_IS_PREPENDED` -> `MRB_FL_CLASS_IS_PREPENDED` `MRB_FLAG_IS_ORIGIN` -> `MRB_FL_CLASS_IS_ORIGIN` `MRB_FLAG_IS_INHERITED` -> `MRB_FL_CLASS_IS_INHERITED` --- include/mruby/class.h | 20 +++++++++++++------- include/mruby/object.h | 9 ++++----- src/class.c | 24 ++++++++++++------------ src/gc.c | 4 ++-- src/kernel.c | 10 +++++----- 5 files changed, 36 insertions(+), 31 deletions(-) diff --git a/include/mruby/class.h b/include/mruby/class.h index 706a4d37c..ddcbd5f98 100644 --- a/include/mruby/class.h +++ b/include/mruby/class.h @@ -53,19 +53,25 @@ mrb_class(mrb_state *mrb, mrb_value v) } } -/* TODO: figure out where to put user flags */ -/* flags bits >= 18 is reserved */ -#define MRB_FLAG_IS_PREPENDED (1 << 19) -#define MRB_FLAG_IS_ORIGIN (1 << 20) +/* flags: + 20: frozen + 19: is_prepended + 18: is_origin + 17: is_inherited (used by method cache) + 16: unused + 0-15: instance type +*/ +#define MRB_FL_CLASS_IS_PREPENDED (1 << 19) +#define MRB_FL_CLASS_IS_ORIGIN (1 << 18) #define MRB_CLASS_ORIGIN(c) do {\ - if (c->flags & MRB_FLAG_IS_PREPENDED) {\ + if (c->flags & MRB_FL_CLASS_IS_PREPENDED) {\ c = c->super;\ - while (!(c->flags & MRB_FLAG_IS_ORIGIN)) {\ + while (!(c->flags & MRB_FL_CLASS_IS_ORIGIN)) {\ c = c->super;\ }\ }\ } while (0) -#define MRB_FLAG_IS_INHERITED (1 << 21) +#define MRB_FL_CLASS_IS_INHERITED (1 << 17) #define MRB_INSTANCE_TT_MASK (0xFF) #define MRB_SET_INSTANCE_TT(c, tt) c->flags = ((c->flags & ~MRB_INSTANCE_TT_MASK) | (char)tt) #define MRB_INSTANCE_TT(c) (enum mrb_vtype)(c->flags & MRB_INSTANCE_TT_MASK) diff --git a/include/mruby/object.h b/include/mruby/object.h index 4f2134ae2..25584a1d4 100644 --- a/include/mruby/object.h +++ b/include/mruby/object.h @@ -22,11 +22,10 @@ struct RBasic { }; #define mrb_basic_ptr(v) ((struct RBasic*)(mrb_ptr(v))) -/* flags bits >= 18 is reserved */ -#define MRB_FLAG_IS_FROZEN (1 << 18) -#define MRB_FROZEN_P(o) ((o)->flags & MRB_FLAG_IS_FROZEN) -#define MRB_SET_FROZEN_FLAG(o) ((o)->flags |= MRB_FLAG_IS_FROZEN) -#define MRB_UNSET_FROZEN_FLAG(o) ((o)->flags &= ~MRB_FLAG_IS_FROZEN) +#define MRB_FL_OBJ_IS_FROZEN (1 << 20) +#define MRB_FROZEN_P(o) ((o)->flags & MRB_FL_OBJ_IS_FROZEN) +#define MRB_SET_FROZEN_FLAG(o) ((o)->flags |= MRB_FL_OBJ_IS_FROZEN) +#define MRB_UNSET_FROZEN_FLAG(o) ((o)->flags &= ~MRB_FL_OBJ_IS_FROZEN) struct RObject { MRB_OBJECT_HEADER; diff --git a/src/class.c b/src/class.c index 076280f3f..660dc3b3d 100644 --- a/src/class.c +++ b/src/class.c @@ -93,7 +93,7 @@ prepare_singleton_class(mrb_state *mrb, struct RBasic *o) if (o->c->tt == MRB_TT_SCLASS) return; sc = (struct RClass*)mrb_obj_alloc(mrb, MRB_TT_SCLASS, mrb->class_class); - sc->flags |= MRB_FLAG_IS_INHERITED; + sc->flags |= MRB_FL_CLASS_IS_INHERITED; sc->mt = kh_init(mt, mrb); sc->iv = 0; if (o->tt == MRB_TT_CLASS) { @@ -275,7 +275,7 @@ mrb_class_inherited(mrb_state *mrb, struct RClass *super, struct RClass *klass) if (!super) super = mrb->object_class; - super->flags |= MRB_FLAG_IS_INHERITED; + super->flags |= MRB_FL_CLASS_IS_INHERITED; s = mrb_obj_value(super); mc_clear_by_class(mrb, klass); mid = mrb_intern_lit(mrb, "inherited"); @@ -1061,7 +1061,7 @@ include_module_at(mrb_state *mrb, struct RClass *c, struct RClass *ins_pos, stru while (m) { int superclass_seen = 0; - if (m->flags & MRB_FLAG_IS_PREPENDED) + if (m->flags & MRB_FL_CLASS_IS_PREPENDED) goto skip; if (klass_mt && klass_mt == m->mt) @@ -1084,7 +1084,7 @@ include_module_at(mrb_state *mrb, struct RClass *c, struct RClass *ins_pos, stru } ic = include_class_new(mrb, m, ins_pos->super); - m->flags |= MRB_FLAG_IS_INHERITED; + m->flags |= MRB_FL_CLASS_IS_INHERITED; ins_pos->super = ic; mrb_field_write_barrier(mrb, (struct RBasic*)ins_pos, (struct RBasic*)ic); mc_clear_by_class(mrb, ins_pos); @@ -1111,15 +1111,15 @@ mrb_prepend_module(mrb_state *mrb, struct RClass *c, struct RClass *m) struct RClass *origin; int changed = 0; - if (!(c->flags & MRB_FLAG_IS_PREPENDED)) { + if (!(c->flags & MRB_FL_CLASS_IS_PREPENDED)) { origin = (struct RClass*)mrb_obj_alloc(mrb, MRB_TT_ICLASS, c); - origin->flags |= MRB_FLAG_IS_ORIGIN | MRB_FLAG_IS_INHERITED; + origin->flags |= MRB_FL_CLASS_IS_ORIGIN | MRB_FL_CLASS_IS_INHERITED; origin->super = c->super; c->super = origin; origin->mt = c->mt; c->mt = kh_init(mt, mrb); mrb_field_write_barrier(mrb, (struct RBasic*)c, (struct RBasic*)origin); - c->flags |= MRB_FLAG_IS_PREPENDED; + c->flags |= MRB_FL_CLASS_IS_PREPENDED; } changed = include_module_at(mrb, c, c, m, 0); if (changed < 0) { @@ -1196,7 +1196,7 @@ mrb_mod_ancestors(mrb_state *mrb, mrb_value self) if (c->tt == MRB_TT_ICLASS) { mrb_ary_push(mrb, result, mrb_obj_value(c->c)); } - else if (!(c->flags & MRB_FLAG_IS_PREPENDED)) { + else if (!(c->flags & MRB_FL_CLASS_IS_PREPENDED)) { mrb_ary_push(mrb, result, mrb_obj_value(c)); } c = c->super; @@ -1365,9 +1365,9 @@ mc_clear_by_class(mrb_state *mrb, struct RClass *c) struct mrb_cache_entry *mc = mrb->cache; int i; - if (c->flags & MRB_FLAG_IS_INHERITED) { + if (c->flags & MRB_FL_CLASS_IS_INHERITED) { mc_clear_all(mrb); - c->flags &= ~MRB_FLAG_IS_INHERITED; + c->flags &= ~MRB_FL_CLASS_IS_INHERITED; return; } for (i=0; icache; int i; - if (c->flags & MRB_FLAG_IS_INHERITED) { + if (c->flags & MRB_FL_CLASS_IS_INHERITED) { mc_clear_all(mrb); - c->flags &= ~MRB_FLAG_IS_INHERITED; + c->flags &= ~MRB_FL_CLASS_IS_INHERITED; return; } for (i=0; isuper); } @@ -761,7 +761,7 @@ obj_free(mrb_state *mrb, struct RBasic *obj, int end) mrb_gc_free_iv(mrb, (struct RObject*)obj); break; case MRB_TT_ICLASS: - if (MRB_FLAG_TEST(obj, MRB_FLAG_IS_ORIGIN)) + if (MRB_FLAG_TEST(obj, MRB_FL_CLASS_IS_ORIGIN)) mrb_gc_free_mt(mrb, (struct RClass*)obj); break; case MRB_TT_ENV: diff --git a/src/kernel.c b/src/kernel.c index 42e9ca6a4..9986b0222 100644 --- a/src/kernel.c +++ b/src/kernel.c @@ -252,18 +252,18 @@ copy_class(mrb_state *mrb, mrb_value dst, mrb_value src) struct RClass *sc = mrb_class_ptr(src); /* if the origin is not the same as the class, then the origin and the current class need to be copied */ - if (sc->flags & MRB_FLAG_IS_PREPENDED) { + if (sc->flags & MRB_FL_CLASS_IS_PREPENDED) { struct RClass *c0 = sc->super; struct RClass *c1 = dc; /* copy prepended iclasses */ - while (!(c0->flags & MRB_FLAG_IS_ORIGIN)) { + while (!(c0->flags & MRB_FL_CLASS_IS_ORIGIN)) { c1->super = mrb_class_ptr(mrb_obj_dup(mrb, mrb_obj_value(c0))); c1 = c1->super; c0 = c0->super; } c1->super = mrb_class_ptr(mrb_obj_dup(mrb, mrb_obj_value(c0))); - c1->super->flags |= MRB_FLAG_IS_ORIGIN; + c1->super->flags |= MRB_FL_CLASS_IS_ORIGIN; } if (sc->mt) { dc->mt = kh_copy(mt, mrb, sc->mt); @@ -348,7 +348,7 @@ mrb_obj_clone(mrb_state *mrb, mrb_value self) mrb_field_write_barrier(mrb, (struct RBasic*)p, (struct RBasic*)p->c); clone = mrb_obj_value(p); init_copy(mrb, clone, self); - p->flags |= mrb_obj_ptr(self)->flags & MRB_FLAG_IS_FROZEN; + p->flags |= mrb_obj_ptr(self)->flags & MRB_FL_OBJ_IS_FROZEN; return clone; } @@ -706,7 +706,7 @@ mrb_class_instance_method_list(mrb_state *mrb, mrb_bool recur, struct RClass* kl struct RClass* oldklass; khash_t(st)* set = kh_init(st, mrb); - if (!recur && (klass->flags & MRB_FLAG_IS_PREPENDED)) { + if (!recur && (klass->flags & MRB_FL_CLASS_IS_PREPENDED)) { MRB_CLASS_ORIGIN(klass); prepended = TRUE; } -- cgit v1.2.3 From 8a18d1539baea29eb794e858be69913075ada869 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Wed, 1 Aug 2018 10:08:40 +0900 Subject: Should update `ci->env` to share the environment; fix #4073 --- mrbgems/mruby-eval/src/eval.c | 1 + 1 file changed, 1 insertion(+) diff --git a/mrbgems/mruby-eval/src/eval.c b/mrbgems/mruby-eval/src/eval.c index 42a4183b7..f1e50e83d 100644 --- a/mrbgems/mruby-eval/src/eval.c +++ b/mrbgems/mruby-eval/src/eval.c @@ -292,6 +292,7 @@ create_proc_from_string(mrb_state *mrb, char *s, mrb_int len, mrb_value binding, if (ci->argc < 0) bidx = 2; else bidx += 1; MRB_ENV_SET_BIDX(e, bidx); + ci->env = e; } proc->e.env = e; proc->flags |= MRB_PROC_ENVSET; -- cgit v1.2.3 From 91c08d7631e0495bf29d8b8910cca2073f8b192b Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Wed, 1 Aug 2018 13:18:32 +0900 Subject: Remove `nregs` member from `mrb_callinfo`. This means reducing one word per a call frame. --- include/mruby.h | 1 - mrbgems/mruby-fiber/src/fiber.c | 1 - src/gc.c | 32 +++++++++++--- src/vm.c | 97 ++++++++++++++++++++++++----------------- 4 files changed, 83 insertions(+), 48 deletions(-) diff --git a/include/mruby.h b/include/mruby.h index 7cbc690b3..12ddb95b3 100644 --- a/include/mruby.h +++ b/include/mruby.h @@ -123,7 +123,6 @@ typedef struct { mrb_sym mid; struct RProc *proc; mrb_value *stackent; - uint16_t nregs; uint16_t ridx; uint16_t epos; struct REnv *env; diff --git a/mrbgems/mruby-fiber/src/fiber.c b/mrbgems/mruby-fiber/src/fiber.c index 27b74dba5..17ce77c5d 100644 --- a/mrbgems/mruby-fiber/src/fiber.c +++ b/mrbgems/mruby-fiber/src/fiber.c @@ -127,7 +127,6 @@ fiber_init(mrb_state *mrb, mrb_value self) ci->proc = p; mrb_field_write_barrier(mrb, (struct RBasic*)mrb_obj_ptr(self), (struct RBasic*)p); ci->pc = p->body.irep->iseq; - ci->nregs = p->body.irep->nregs; ci[1] = ci[0]; c->ci++; /* push dummy callinfo */ diff --git a/src/gc.c b/src/gc.c index c52641959..33d83f28e 100644 --- a/src/gc.c +++ b/src/gc.c @@ -548,21 +548,39 @@ add_gray_list(mrb_state *mrb, mrb_gc *gc, struct RBasic *obj) gc->gray_list = obj; } +static int +ci_nregs(mrb_callinfo *ci) +{ + struct RProc *p = ci->proc; + int n = 0; + + if (!p) { + if (ci->argc < 0) return 3; + return ci->argc+2; + } + if (!MRB_PROC_CFUNC_P(p) && p->body.irep) { + n = p->body.irep->nregs; + } + if (ci->argc < 0) { + if (n < 3) n = 3; /* self + args + blk */ + } + if (ci->argc > n) { + n = ci->argc + 2; /* self + blk */ + } + return n; +} + static void mark_context_stack(mrb_state *mrb, struct mrb_context *c) { size_t i; size_t e; mrb_value nil; - mrb_int nregs; if (c->stack == NULL) return; e = c->stack - c->stbase; if (c->ci) { - nregs = c->ci->argc + 2; - if (c->ci->nregs > nregs) - nregs = c->ci->nregs; - e += nregs; + e += ci_nregs(c->ci); } if (c->stbase + e > c->stend) e = c->stend - c->stbase; for (i=0; istack - c->stbase; - if (c->ci) i += c->ci->nregs; + if (c->ci) { + i += ci_nregs(c->ci); + } if (c->stbase + i > c->stend) i = c->stend - c->stbase; children += i; diff --git a/src/vm.c b/src/vm.c index d47b4c7fc..91c617a83 100644 --- a/src/vm.c +++ b/src/vm.c @@ -356,7 +356,6 @@ ecall(mrb_state *mrb) ci->acc = CI_ACC_SKIP; ci->argc = 0; ci->proc = p; - ci->nregs = p->body.irep->nregs; ci->target_class = MRB_PROC_TARGET_CLASS(p); env = MRB_PROC_ENV(p); mrb_assert(env); @@ -396,6 +395,30 @@ mrb_funcall(mrb_state *mrb, mrb_value self, const char *name, mrb_int argc, ...) return mrb_funcall_argv(mrb, self, mid, argc, argv); } +static int +ci_nregs(mrb_callinfo *ci) +{ + struct RProc *p; + int n = 0; + + if (!ci) return 3; + p = ci->proc; + if (!p) { + if (ci->argc < 0) return 3; + return ci->argc+2; + } + if (!MRB_PROC_CFUNC_P(p) && p->body.irep) { + n = p->body.irep->nregs; + } + if (ci->argc < 0) { + if (n < 3) n = 3; /* self + args + blk */ + } + if (ci->argc > n) { + n = ci->argc + 2; /* self + blk */ + } + return n; +} + MRB_API mrb_value mrb_funcall_with_block(mrb_state *mrb, mrb_value self, mrb_sym mid, mrb_int argc, const mrb_value *argv, mrb_value blk) { @@ -426,13 +449,12 @@ mrb_funcall_with_block(mrb_state *mrb, mrb_value self, mrb_sym mid, mrb_int argc mrb_method_t m; struct RClass *c; mrb_callinfo *ci; - int n; + int n = ci_nregs(mrb->c->ci); ptrdiff_t voff = -1; if (!mrb->c->stack) { stack_init(mrb); } - n = mrb->c->ci->nregs; if (argc < 0) { mrb_raisef(mrb, E_ARGUMENT_ERROR, "negative argc for funcall (%S)", mrb_fixnum_value(argc)); } @@ -463,22 +485,22 @@ mrb_funcall_with_block(mrb_state *mrb, mrb_value self, mrb_sym mid, mrb_int argc voff = argv - mrb->c->stbase; } if (MRB_METHOD_CFUNC_P(m)) { - ci->nregs = (int)(argc + 2); - mrb_stack_extend(mrb, ci->nregs); + mrb_stack_extend(mrb, argc + 2); } else if (argc >= CALL_MAXARGS) { mrb_value args = mrb_ary_new_from_values(mrb, argc, argv); - mrb_stack_extend(mrb, ci->nregs+2); + + mrb_stack_extend(mrb, 3); mrb->c->stack[1] = args; ci->argc = -1; argc = 1; } else { struct RProc *p = MRB_METHOD_PROC(m); + ci->proc = p; if (argc < 0) argc = 1; - ci->nregs = (int)(p->body.irep->nregs + argc); - mrb_stack_extend(mrb, ci->nregs); + mrb_stack_extend(mrb, p->body.irep->nregs + argc); } if (voff >= 0) { argv = mrb->c->stbase + voff; @@ -520,26 +542,25 @@ mrb_value mrb_exec_irep(mrb_state *mrb, mrb_value self, struct RProc *p) { mrb_callinfo *ci = mrb->c->ci; - int keep; + int keep, nregs; mrb->c->stack[0] = self; ci->proc = p; if (MRB_PROC_CFUNC_P(p)) { return MRB_PROC_CFUNC(p)(mrb, self); } - ci->nregs = p->body.irep->nregs; + nregs = p->body.irep->nregs; if (ci->argc < 0) keep = 3; else keep = ci->argc + 2; - if (ci->nregs < keep) { + if (nregs < keep) { mrb_stack_extend(mrb, keep); } else { - mrb_stack_extend(mrb, ci->nregs); - stack_clear(mrb->c->stack+keep, ci->nregs-keep); + mrb_stack_extend(mrb, nregs); + stack_clear(mrb->c->stack+keep, nregs-keep); } ci = cipush(mrb); - ci->nregs = 0; ci->target_class = 0; ci->pc = p->body.irep->iseq; ci->stackent = mrb->c->stack; @@ -618,6 +639,7 @@ eval_under(mrb_state *mrb, mrb_value self, mrb_value blk, struct RClass *c) { struct RProc *p; mrb_callinfo *ci; + int nregs; if (mrb_nil_p(blk)) { mrb_raise(mrb, E_ARGUMENT_ERROR, "no block given"); @@ -639,13 +661,12 @@ eval_under(mrb_state *mrb, mrb_value self, mrb_value blk, struct RClass *c) mrb->c->stack[2] = mrb_nil_value(); return MRB_PROC_CFUNC(p)(mrb, self); } - ci->nregs = p->body.irep->nregs; - mrb_stack_extend(mrb, (ci->nregs < 3) ? 3 : ci->nregs); + nregs = p->body.irep->nregs; + mrb_stack_extend(mrb, (nregs < 3) ? 3 : nregs); mrb->c->stack[0] = self; mrb->c->stack[1] = self; mrb->c->stack[2] = mrb_nil_value(); ci = cipush(mrb); - ci->nregs = 0; ci->target_class = 0; ci->pc = p->body.irep->iseq; ci->stackent = mrb->c->stack; @@ -728,13 +749,15 @@ mrb_yield_with_class(mrb_state *mrb, mrb_value b, mrb_int argc, const mrb_value struct RProc *p; mrb_sym mid = mrb->c->ci->mid; mrb_callinfo *ci; - int n = mrb->c->ci->nregs; mrb_value val; + int n; if (mrb_nil_p(b)) { mrb_raise(mrb, E_ARGUMENT_ERROR, "no block given"); } - if (mrb->c->ci - mrb->c->cibase > MRB_FUNCALL_DEPTH_MAX) { + ci = mrb->c->ci; + n = ci_nregs(ci); + if (ci - mrb->c->cibase > MRB_FUNCALL_DEPTH_MAX) { mrb_exc_raise(mrb, mrb_obj_value(mrb->stack_err)); } p = mrb_proc_ptr(b); @@ -745,9 +768,9 @@ mrb_yield_with_class(mrb_state *mrb, mrb_value b, mrb_int argc, const mrb_value ci->argc = (int)argc; ci->target_class = c; ci->acc = CI_ACC_SKIP; + n = MRB_PROC_CFUNC_P(p) ? (int)(argc+2) : p->body.irep->nregs; mrb->c->stack = mrb->c->stack + n; - ci->nregs = MRB_PROC_CFUNC_P(p) ? (int)(argc+2) : p->body.irep->nregs; - mrb_stack_extend(mrb, ci->nregs); + mrb_stack_extend(mrb, n); mrb->c->stack[0] = self; if (argc > 0) { @@ -1008,7 +1031,6 @@ RETRY_TRY_BLOCK: } mrb->jmp = &c_jmp; mrb->c->ci->proc = proc; - mrb->c->ci->nregs = irep->nregs; #define regs (mrb->c->stack) INIT_DISPATCH { @@ -1296,6 +1318,8 @@ RETRY_TRY_BLOCK: if (a > (int)mrb->c->eidx - epos) a = mrb->c->eidx - epos; for (n=0; nnregs; + proc = mrb->c->ensure[epos+n]; mrb->c->ensure[epos+n] = NULL; if (proc == NULL) continue; @@ -1305,12 +1329,11 @@ RETRY_TRY_BLOCK: ci->argc = 0; ci->proc = proc; ci->stackent = mrb->c->stack; - ci->nregs = irep->nregs; ci->target_class = target_class; ci->pc = pc; - ci->acc = ci[-1].nregs; + ci->acc = nregs; mrb->c->stack += ci->acc; - mrb_stack_extend(mrb, ci->nregs); + mrb_stack_extend(mrb, irep->nregs); regs[0] = self; pc = irep->iseq; } @@ -1350,7 +1373,7 @@ RETRY_TRY_BLOCK: mrb_value recv, blk; mrb_sym mid = syms[b]; - mrb_assert(bidx < ci->nregs); + mrb_assert(bidx < irep->nregs); recv = regs[a]; blk = regs[bidx]; @@ -1396,7 +1419,6 @@ RETRY_TRY_BLOCK: mrb->c->stack += a; if (MRB_METHOD_CFUNC_P(m)) { - ci->nregs = (argc < 0) ? 3 : c+2; if (MRB_METHOD_PROC_P(m)) { struct RProc *p = MRB_METHOD_PROC(m); @@ -1442,8 +1464,7 @@ RETRY_TRY_BLOCK: irep = proc->body.irep; pool = irep->pool; syms = irep->syms; - ci->nregs = irep->nregs; - mrb_stack_extend(mrb, (argc < 0 && ci->nregs < 3) ? 3 : ci->nregs); + mrb_stack_extend(mrb, (argc < 0 && irep->nregs < 3) ? 3 : irep->nregs); pc = irep->iseq; JUMP; } @@ -1498,8 +1519,7 @@ RETRY_TRY_BLOCK: } pool = irep->pool; syms = irep->syms; - ci->nregs = irep->nregs; - mrb_stack_extend(mrb, ci->nregs); + mrb_stack_extend(mrb, irep->nregs); if (ci->argc < 0) { if (irep->nregs > 3) { stack_clear(regs+3, irep->nregs-3); @@ -1526,7 +1546,7 @@ RETRY_TRY_BLOCK: mrb_sym mid = ci->mid; struct RClass* target_class = MRB_PROC_TARGET_CLASS(ci->proc); - mrb_assert(bidx < ci->nregs); + mrb_assert(bidx < irep->nregs); if (mid == 0 || !target_class) { mrb_value exc = mrb_exc_new_str_lit(mrb, E_NOMETHOD_ERROR, "super called outside of method"); @@ -1572,7 +1592,7 @@ RETRY_TRY_BLOCK: } mid = missing; if (argc >= 0) { - if (a+2 >= ci->nregs) { + if (a+2 >= irep->nregs) { mrb_stack_extend(mrb, a+3); } regs[a+1] = mrb_ary_new_from_values(mrb, b, regs+a+1); @@ -1596,7 +1616,7 @@ RETRY_TRY_BLOCK: if (MRB_METHOD_CFUNC_P(m)) { mrb_value v; - ci->nregs = (argc < 0) ? 3 : b+2; + if (MRB_METHOD_PROC_P(m)) { ci->proc = MRB_METHOD_PROC(m); } @@ -1633,8 +1653,7 @@ RETRY_TRY_BLOCK: irep = proc->body.irep; pool = irep->pool; syms = irep->syms; - ci->nregs = irep->nregs; - mrb_stack_extend(mrb, (argc < 0 && ci->nregs < 3) ? 3 : ci->nregs); + mrb_stack_extend(mrb, (argc < 0 && irep->nregs < 3) ? 3 : irep->nregs); pc = irep->iseq; JUMP; } @@ -2795,9 +2814,8 @@ RETRY_TRY_BLOCK: irep = p->body.irep; pool = irep->pool; syms = irep->syms; - ci->nregs = irep->nregs; - mrb_stack_extend(mrb, ci->nregs); - stack_clear(regs+1, ci->nregs-1); + mrb_stack_extend(mrb, irep->nregs); + stack_clear(regs+1, irep->nregs-1); pc = irep->iseq; JUMP; } @@ -2946,7 +2964,6 @@ mrb_top_run(mrb_state *mrb, struct RProc *proc, mrb_value self, unsigned int sta } ci = cipush(mrb); ci->mid = 0; - ci->nregs = 1; /* protect the receiver */ ci->acc = CI_ACC_SKIP; ci->target_class = mrb->object_class; v = mrb_vm_run(mrb, proc, self, stack_keep); -- cgit v1.2.3 From 6681e22c71c55ae09d802dad17296a1ebe49bb13 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Wed, 1 Aug 2018 16:50:44 +0900 Subject: Simply use `snprintf` instead of custom `fmt_fp`, Unless `MRB_DISABLE_STDIO` is set. `snprintf` is used anyway if mruby is configured to use `stdio`. This change reduces 8KB of program size on the Linux box. --- src/fmt_fp.c | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/src/fmt_fp.c b/src/fmt_fp.c index f8a8f7904..783cc6c02 100644 --- a/src/fmt_fp.c +++ b/src/fmt_fp.c @@ -1,3 +1,5 @@ +#ifndef MRB_WITHOUT_FLOAT +#ifdef MRB_DISABLE_STDIO /* Most code in this file originates from musl (src/stdio/vfprintf.c) @@ -36,7 +38,6 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. #include #include -#ifndef MRB_WITHOUT_FLOAT struct fmt_args { mrb_state *mrb; mrb_value str; @@ -371,4 +372,17 @@ mrb_float_to_str(mrb_state *mrb, mrb_value flo, const char *fmt) } return f.str; } +#else /* MRB_DISABLE_STDIO */ +#include +#include + +mrb_value +mrb_float_to_str(mrb_state *mrb, mrb_value flo, const char *fmt) +{ + char buf[24]; + + snprintf(buf, sizeof(buf), fmt, mrb_float(flo)); + return mrb_str_new_cstr(mrb, buf); +} +#endif /* MRB_DISABLE_STDIO */ #endif -- cgit v1.2.3 From 322eb2328a516f7d92e35850d730b022bd948c23 Mon Sep 17 00:00:00 2001 From: dearblue Date: Sun, 5 Aug 2018 20:33:44 +0900 Subject: Fix mrb_value size with MRB_WORD_BOXING on 32-bit mode --- include/mruby/boxing_word.h | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/include/mruby/boxing_word.h b/include/mruby/boxing_word.h index b17bfc973..2ff314144 100644 --- a/include/mruby/boxing_word.h +++ b/include/mruby/boxing_word.h @@ -45,6 +45,14 @@ enum mrb_special_consts { #define MRB_SYMBOL_FLAG 0x0e #define MRB_SPECIAL_SHIFT 8 +#if defined(MRB_64BIT) +#define MRB_SYMBOL_BITSIZE (sizeof(mrb_sym) * CHAR_BIT) +#define MRB_SYMBOL_MAX UINT32_MAX +#else +#define MRB_SYMBOL_BITSIZE (sizeof(mrb_sym) * CHAR_BIT - MRB_SPECIAL_SHIFT) +#define MRB_SYMBOL_MAX (UINT32_MAX >> MRB_SPECIAL_SHIFT) +#endif + typedef union mrb_value { union { void *p; @@ -54,7 +62,7 @@ typedef union mrb_value { }; struct { unsigned int sym_flag : MRB_SPECIAL_SHIFT; - mrb_sym sym : (sizeof(mrb_sym) * CHAR_BIT); + mrb_sym sym : MRB_SYMBOL_BITSIZE; }; struct RBasic *bp; #ifndef MRB_WITHOUT_FLOAT -- cgit v1.2.3 From f3564a405ee766797be191cedd90aa3ab8b5e5c5 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Wed, 1 Aug 2018 21:55:11 +0900 Subject: Small refactoring of `flodivmod()`. --- src/numeric.c | 41 ++++++++++++++++++++++++++--------------- 1 file changed, 26 insertions(+), 15 deletions(-) diff --git a/src/numeric.c b/src/numeric.c index 4e5fc394e..c3e7d77a3 100644 --- a/src/numeric.c +++ b/src/numeric.c @@ -220,29 +220,40 @@ flo_mul(mrb_state *mrb, mrb_value x) } static void -flodivmod(mrb_state *mrb, mrb_float x, mrb_float y, mrb_float *divp, mrb_float *modp) +flodivmod(mrb_state *mrb, double x, double y, mrb_float *divp, mrb_float *modp) { - mrb_float div; - mrb_float mod; + double div, mod; + if (isnan(y)) { + /* y is NaN so all results are NaN */ + div = mod = y; + goto exit; + } if (y == 0.0) { - if (x > 0.0) div = INFINITY; - else if (x < 0.0) div = -INFINITY; - else div = NAN; /* x == 0.0 */ + if (x == 0) div = NAN; + else if (x > 0.0) div = INFINITY; + else div = -INFINITY; /* x < 0.0 */ mod = NAN; + goto exit; + } + if ((x == 0.0) || (isinf(y) && !isinf(x))) { + mod = x; } else { mod = fmod(x, y); - if (isinf(x) && isfinite(y)) - div = x; - else - div = (x - mod) / y; - if (y*mod < 0) { - mod += y; - div -= 1.0; - } } - + if (isinf(x) && !isinf(y)) { + div = x; + } + else { + div = (x - mod) / y; + if (modp && divp) div = round(div); + } + if (y*mod < 0) { + mod += y; + div -= 1.0; + } + exit: if (modp) *modp = mod; if (divp) *divp = div; } -- cgit v1.2.3 From 4c974b9523cc347a0bbcf46b759a14f0b60fdbf0 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Thu, 2 Aug 2018 18:01:39 +0900 Subject: Small refactoring. The macro `RCLASS_SUPER`, `RCLASS_IV_TBL` and `RCLASS_M_TBL` are removed from `include/mruby/class.h`. --- include/mruby/class.h | 3 --- mrbgems/mruby-struct/src/struct.c | 11 +++++------ 2 files changed, 5 insertions(+), 9 deletions(-) diff --git a/include/mruby/class.h b/include/mruby/class.h index ddcbd5f98..96a9f7f95 100644 --- a/include/mruby/class.h +++ b/include/mruby/class.h @@ -22,9 +22,6 @@ struct RClass { }; #define mrb_class_ptr(v) ((struct RClass*)(mrb_ptr(v))) -#define RCLASS_SUPER(v) (((struct RClass*)(mrb_ptr(v)))->super) -#define RCLASS_IV_TBL(v) (((struct RClass*)(mrb_ptr(v)))->iv) -#define RCLASS_M_TBL(v) (((struct RClass*)(mrb_ptr(v)))->mt) static inline struct RClass* mrb_class(mrb_state *mrb, mrb_value v) diff --git a/mrbgems/mruby-struct/src/struct.c b/mrbgems/mruby-struct/src/struct.c index adeb09bc1..fe7e73f04 100644 --- a/mrbgems/mruby-struct/src/struct.c +++ b/mrbgems/mruby-struct/src/struct.c @@ -24,19 +24,18 @@ struct_class(mrb_state *mrb) } static inline mrb_value -struct_ivar_get(mrb_state *mrb, mrb_value c, mrb_sym id) +struct_ivar_get(mrb_state *mrb, mrb_value cls, mrb_sym id) { - struct RClass* kclass; + struct RClass* c = mrb_class_ptr(cls); struct RClass* sclass = struct_class(mrb); mrb_value ans; for (;;) { - ans = mrb_iv_get(mrb, c, id); + ans = mrb_iv_get(mrb, mrb_obj_value(c), id); if (!mrb_nil_p(ans)) return ans; - kclass = RCLASS_SUPER(c); - if (kclass == 0 || kclass == sclass) + c = c->super; + if (c == sclass || c == 0) return mrb_nil_value(); - c = mrb_obj_value(kclass); } } -- cgit v1.2.3 From c88fd32713e980abe5613ae06f46d9ceaa0c063b Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Thu, 2 Aug 2018 21:08:50 +0900 Subject: Revert 04dbbff. Use segment list for instance variable again to reduce memory. --- src/variable.c | 335 +++++++++++++++++++++++++++++++++++---------------------- 1 file changed, 205 insertions(+), 130 deletions(-) diff --git a/src/variable.c b/src/variable.c index de36efac6..cbfdb2f2d 100644 --- a/src/variable.c +++ b/src/variable.c @@ -12,152 +12,243 @@ typedef int (iv_foreach_func)(mrb_state*,mrb_sym,mrb_value,void*); -#include - -#ifndef MRB_IVHASH_INIT_SIZE -#define MRB_IVHASH_INIT_SIZE KHASH_MIN_SIZE +#ifndef MRB_IV_SEGMENT_SIZE +#define MRB_IV_SEGMENT_SIZE 4 #endif -KHASH_DECLARE(iv, mrb_sym, mrb_value, TRUE) -KHASH_DEFINE(iv, mrb_sym, mrb_value, TRUE, kh_int_hash_func, kh_int_hash_equal) +typedef struct segment { + mrb_sym key[MRB_IV_SEGMENT_SIZE]; + mrb_value val[MRB_IV_SEGMENT_SIZE]; + struct segment *next; +} segment; /* Instance variable table structure */ typedef struct iv_tbl { - khash_t(iv) h; + segment *rootseg; + size_t size; + size_t last_len; } iv_tbl; -/* - * Creates the instance variable table. - * - * Parameters - * mrb - * Returns - * the instance variable table. - */ +/* Creates the instance variable table. */ static iv_tbl* iv_new(mrb_state *mrb) { - return (iv_tbl*)kh_init_size(iv, mrb, MRB_IVHASH_INIT_SIZE); + iv_tbl *t; + + t = (iv_tbl*)mrb_malloc(mrb, sizeof(iv_tbl)); + t->size = 0; + t->rootseg = NULL; + t->last_len = 0; + + return t; } -/* - * Set the value for the symbol in the instance variable table. - * - * Parameters - * mrb - * t the instance variable table to be set in. - * sym the symbol to be used as the key. - * val the value to be set. - */ +/* Set the value for the symbol in the instance variable table. */ static void iv_put(mrb_state *mrb, iv_tbl *t, mrb_sym sym, mrb_value val) { - khash_t(iv) *h = &t->h; - khiter_t k; + segment *seg; + segment *prev = NULL; + segment *matched_seg = NULL; + size_t matched_idx = 0; + size_t i; - k = kh_put(iv, mrb, h, sym); - kh_value(h, k) = val; + if (t == NULL) return; + seg = t->rootseg; + while (seg) { + for (i=0; ikey[i]; + /* Found room in last segment after last_len */ + if (!seg->next && i >= t->last_len) { + seg->key[i] = sym; + seg->val[i] = val; + t->last_len = i+1; + t->size++; + return; + } + if (!matched_seg && key == 0) { + matched_seg = seg; + matched_idx = i; + } + else if (key == sym) { + seg->val[i] = val; + return; + } + } + prev = seg; + seg = seg->next; + } + + /* Not found */ + t->size++; + if (matched_seg) { + matched_seg->key[matched_idx] = sym; + matched_seg->val[matched_idx] = val; + return; + } + + seg = (segment*)mrb_malloc(mrb, sizeof(segment)); + if (!seg) return; + seg->next = NULL; + seg->key[0] = sym; + seg->val[0] = val; + t->last_len = 1; + if (prev) { + prev->next = seg; + } + else { + t->rootseg = seg; + } } -/* - * Get a value for a symbol from the instance variable table. - * - * Parameters - * mrb - * t the variable table to be searched. - * sym the symbol to be used as the key. - * vp the value pointer. Receives the value if the specified symbol is - * contained in the instance variable table. - * Returns - * true if the specified symbol is contained in the instance variable table. - */ +/* Get a value for a symbol from the instance variable table. */ static mrb_bool iv_get(mrb_state *mrb, iv_tbl *t, mrb_sym sym, mrb_value *vp) { - khash_t(iv) *h = &t->h; - khiter_t k; + segment *seg; + size_t i; - k = kh_get(iv, mrb, h, sym); - if (k != kh_end(h)) { - if (vp) *vp = kh_value(h, k); - return TRUE; + if (t == NULL) return FALSE; + seg = t->rootseg; + while (seg) { + for (i=0; ikey[i]; + + if (!seg->next && i >= t->last_len) { + return FALSE; + } + if (key == sym) { + if (vp) *vp = seg->val[i]; + return TRUE; + } + } + seg = seg->next; } return FALSE; } -/* - * Deletes the value for the symbol from the instance variable table. - * - * Parameters - * t the variable table to be searched. - * sym the symbol to be used as the key. - * vp the value pointer. Receive the deleted value if the symbol is - * contained in the instance variable table. - * Returns - * true if the specified symbol is contained in the instance variable table. - */ +/* Deletes the value for the symbol from the instance variable table. */ static mrb_bool iv_del(mrb_state *mrb, iv_tbl *t, mrb_sym sym, mrb_value *vp) { + segment *seg; + size_t i; + if (t == NULL) return FALSE; - else { - khash_t(iv) *h = &t->h; - khiter_t k; - - k = kh_get(iv, mrb, h, sym); - if (k != kh_end(h)) { - mrb_value val = kh_value(h, k); - kh_del(iv, mrb, h, k); - if (vp) *vp = val; - return TRUE; + seg = t->rootseg; + while (seg) { + for (i=0; ikey[i]; + + if (!seg->next && i >= t->last_len) { + return FALSE; + } + if (key == sym) { + t->size--; + seg->key[i] = 0; + if (vp) *vp = seg->val[i]; + return TRUE; + } } + seg = seg->next; } return FALSE; } +/* Iterates over the instance variable table. */ static mrb_bool iv_foreach(mrb_state *mrb, iv_tbl *t, iv_foreach_func *func, void *p) { - if (t == NULL) { - return TRUE; - } - else { - khash_t(iv) *h = &t->h; - khiter_t k; - int n; + segment *seg; + size_t i; + int n; + + if (t == NULL) return TRUE; + seg = t->rootseg; + while (seg) { + for (i=0; ikey[i]; - for (k = kh_begin(h); k != kh_end(h); k++) { - if (kh_exist(h, k)) { - n = (*func)(mrb, kh_key(h, k), kh_value(h, k), p); + /* no value in last segment after last_len */ + if (!seg->next && i >= t->last_len) { + return FALSE; + } + if (key != 0) { + n =(*func)(mrb, key, seg->val[i], p); if (n > 0) return FALSE; if (n < 0) { - kh_del(iv, mrb, h, k); + t->size--; + seg->key[i] = 0; } } } + seg = seg->next; } return TRUE; } +/* Get the size of the instance variable table. */ static size_t iv_size(mrb_state *mrb, iv_tbl *t) { - if (t) { - return kh_size(&t->h); + segment *seg; + size_t size = 0; + + if (t == NULL) return 0; + if (t->size > 0) return t->size; + seg = t->rootseg; + while (seg) { + if (seg->next == NULL) { + size += t->last_len; + return size; + } + seg = seg->next; + size += MRB_IV_SEGMENT_SIZE; } + /* empty iv_tbl */ return 0; } +/* Copy the instance variable table. */ static iv_tbl* iv_copy(mrb_state *mrb, iv_tbl *t) { - return (iv_tbl*)kh_copy(iv, mrb, &t->h); + segment *seg; + iv_tbl *t2; + + size_t i; + + seg = t->rootseg; + t2 = iv_new(mrb); + + while (seg != NULL) { + for (i=0; ikey[i]; + mrb_value val = seg->val[i]; + + if ((seg->next == NULL) && (i >= t->last_len)) { + return t2; + } + iv_put(mrb, t2, key, val); + } + seg = seg->next; + } + return t2; } +/* Free memory of the instance variable table. */ static void iv_free(mrb_state *mrb, iv_tbl *t) { - kh_destroy(iv, mrb, &t->h); + segment *seg; + + seg = t->rootseg; + while (seg) { + segment *p = seg; + seg = seg->next; + mrb_free(mrb, p); + } + mrb_free(mrb, t); } static int @@ -170,9 +261,7 @@ iv_mark_i(mrb_state *mrb, mrb_sym sym, mrb_value v, void *p) static void mark_tbl(mrb_state *mrb, iv_tbl *t) { - if (t) { - iv_foreach(mrb, t, iv_mark_i, 0); - } + iv_foreach(mrb, t, iv_mark_i, 0); } void @@ -258,16 +347,17 @@ mrb_iv_get(mrb_state *mrb, mrb_value obj, mrb_sym sym) MRB_API void mrb_obj_iv_set(mrb_state *mrb, struct RObject *obj, mrb_sym sym, mrb_value v) { - iv_tbl *t = obj->iv; + iv_tbl *t; if (MRB_FROZEN_P(obj)) { mrb_raisef(mrb, E_FROZEN_ERROR, "can't modify frozen %S", mrb_obj_value(obj)); } - if (!t) { - t = obj->iv = iv_new(mrb); + if (!obj->iv) { + obj->iv = iv_new(mrb); } - mrb_write_barrier(mrb, (struct RBasic*)obj); + t = obj->iv; iv_put(mrb, t, sym, v); + mrb_write_barrier(mrb, (struct RBasic*)obj); } MRB_API void @@ -401,7 +491,7 @@ mrb_iv_remove(mrb_state *mrb, mrb_value obj, mrb_sym sym) iv_tbl *t = mrb_obj_ptr(obj)->iv; mrb_value val; - if (t && iv_del(mrb, t, sym, &val)) { + if (iv_del(mrb, t, sym, &val)) { return val; } } @@ -460,7 +550,7 @@ mrb_obj_instance_variables(mrb_state *mrb, mrb_value self) mrb_value ary; ary = mrb_ary_new(mrb); - if (obj_iv_p(self) && mrb_obj_ptr(self)->iv) { + if (obj_iv_p(self)) { iv_foreach(mrb, mrb_obj_ptr(self)->iv, iv_i, &ary); } return ary; @@ -506,9 +596,7 @@ mrb_mod_class_variables(mrb_state *mrb, mrb_value mod) ary = mrb_ary_new(mrb); c = mrb_class_ptr(mod); while (c) { - if (c->iv) { - iv_foreach(mrb, c->iv, cv_i, &ary); - } + iv_foreach(mrb, c->iv, cv_i, &ary); c = c->super; } return ary; @@ -563,14 +651,12 @@ mrb_mod_cv_set(mrb_state *mrb, struct RClass *c, mrb_sym sym, mrb_value v) struct RClass * cls = c; while (c) { - if (c->iv) { - iv_tbl *t = c->iv; + iv_tbl *t = c->iv; - if (iv_get(mrb, t, sym, NULL)) { - mrb_write_barrier(mrb, (struct RBasic*)c); - iv_put(mrb, t, sym, v); - return; - } + if (iv_get(mrb, t, sym, NULL)) { + iv_put(mrb, t, sym, v); + mrb_write_barrier(mrb, (struct RBasic*)c); + return; } c = c->super; } @@ -599,8 +685,8 @@ mrb_mod_cv_set(mrb_state *mrb, struct RClass *c, mrb_sym sym, mrb_value v) c->iv = iv_new(mrb); } - mrb_write_barrier(mrb, (struct RBasic*)c); iv_put(mrb, c->iv, sym, v); + mrb_write_barrier(mrb, (struct RBasic*)c); } MRB_API void @@ -613,10 +699,8 @@ MRB_API mrb_bool mrb_mod_cv_defined(mrb_state *mrb, struct RClass * c, mrb_sym sym) { while (c) { - if (c->iv) { - iv_tbl *t = c->iv; - if (iv_get(mrb, t, sym, NULL)) return TRUE; - } + iv_tbl *t = c->iv; + if (iv_get(mrb, t, sym, NULL)) return TRUE; c = c->super; } @@ -672,7 +756,7 @@ const_get(mrb_state *mrb, struct RClass *base, mrb_sym sym, mrb_bool top) L_RETRY: while (c) { - if (c->iv && (top || c != oclass || base == oclass)) { + if (top || c != oclass || base == oclass) { if (iv_get(mrb, c->iv, sym, &v)) return v; } @@ -703,22 +787,25 @@ mrb_vm_const_get(mrb_state *mrb, mrb_sym sym) struct RProc *proc; c = MRB_PROC_TARGET_CLASS(mrb->c->ci->proc); - if (c->iv && iv_get(mrb, c->iv, sym, &v)) { + if (iv_get(mrb, c->iv, sym, &v)) { return v; } c2 = c; while (c2 && c2->tt == MRB_TT_SCLASS) { mrb_value klass; - klass = mrb_obj_iv_get(mrb, (struct RObject *)c2, - mrb_intern_lit(mrb, "__attached__")); + + if (!iv_get(mrb, c2->iv, mrb_intern_lit(mrb, "__attached__"), &klass)) { + c2 = NULL; + break; + } c2 = mrb_class_ptr(klass); } - if (c2->tt == MRB_TT_CLASS || c2->tt == MRB_TT_MODULE) c = c2; + if (c2 && (c2->tt == MRB_TT_CLASS || c2->tt == MRB_TT_MODULE)) c = c2; mrb_assert(!MRB_PROC_CFUNC_P(mrb->c->ci->proc)); proc = mrb->c->ci->proc; while (proc) { c2 = MRB_PROC_TARGET_CLASS(proc); - if (c2 && c2->iv && iv_get(mrb, c2->iv, sym, &v)) { + if (c2 && iv_get(mrb, c2->iv, sym, &v)) { return v; } proc = proc->upper; @@ -796,9 +883,7 @@ mrb_mod_constants(mrb_state *mrb, mrb_value mod) mrb_get_args(mrb, "|b", &inherit); ary = mrb_ary_new(mrb); while (c) { - if (c->iv) { - iv_foreach(mrb, c->iv, const_i, &ary); - } + iv_foreach(mrb, c->iv, const_i, &ary); if (!inherit) break; c = c->super; if (c == mrb->object_class) break; @@ -811,9 +896,6 @@ mrb_gv_get(mrb_state *mrb, mrb_sym sym) { mrb_value v; - if (!mrb->globals) { - return mrb_nil_value(); - } if (iv_get(mrb, mrb->globals, sym, &v)) return v; return mrb_nil_value(); @@ -825,20 +907,15 @@ mrb_gv_set(mrb_state *mrb, mrb_sym sym, mrb_value v) iv_tbl *t; if (!mrb->globals) { - t = mrb->globals = iv_new(mrb); - } - else { - t = mrb->globals; + mrb->globals = iv_new(mrb); } + t = mrb->globals; iv_put(mrb, t, sym, v); } MRB_API void mrb_gv_remove(mrb_state *mrb, mrb_sym sym) { - if (!mrb->globals) { - return; - } iv_del(mrb, mrb->globals, sym, NULL); } @@ -870,9 +947,7 @@ mrb_f_global_variables(mrb_state *mrb, mrb_value self) size_t i; char buf[3]; - if (t) { - iv_foreach(mrb, t, gv_i, &ary); - } + iv_foreach(mrb, t, gv_i, &ary); buf[0] = '$'; buf[2] = 0; for (i = 1; i <= 9; ++i) { @@ -892,7 +967,7 @@ mrb_const_defined_0(mrb_state *mrb, mrb_value mod, mrb_sym id, mrb_bool exclude, tmp = klass; retry: while (tmp) { - if (tmp->iv && iv_get(mrb, tmp->iv, id, NULL)) { + if (iv_get(mrb, tmp->iv, id, NULL)) { return TRUE; } if (!recurse && (klass != mrb->object_class)) break; -- cgit v1.2.3 From 5e469d2b924a70617be75b0c765da73497d3927c Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Thu, 2 Aug 2018 21:14:52 +0900 Subject: Remove utility functions: `mrb_vm_iv_{get,set}`. --- include/mruby/variable.h | 2 -- src/variable.c | 14 -------------- src/vm.c | 3 +-- 3 files changed, 1 insertion(+), 18 deletions(-) diff --git a/include/mruby/variable.h b/include/mruby/variable.h index 5fef83faf..a4394fbd3 100644 --- a/include/mruby/variable.h +++ b/include/mruby/variable.h @@ -31,8 +31,6 @@ struct global_entry { mrb_value mrb_vm_special_get(mrb_state*, mrb_sym); void mrb_vm_special_set(mrb_state*, mrb_sym, mrb_value); -mrb_value mrb_vm_iv_get(mrb_state*, mrb_sym); -void mrb_vm_iv_set(mrb_state*, mrb_sym, mrb_value); mrb_value mrb_vm_cv_get(mrb_state*, mrb_sym); void mrb_vm_cv_set(mrb_state*, mrb_sym, mrb_value); mrb_value mrb_vm_const_get(mrb_state*, mrb_sym); diff --git a/src/variable.c b/src/variable.c index cbfdb2f2d..6612c186f 100644 --- a/src/variable.c +++ b/src/variable.c @@ -498,20 +498,6 @@ mrb_iv_remove(mrb_state *mrb, mrb_value obj, mrb_sym sym) return mrb_undef_value(); } -mrb_value -mrb_vm_iv_get(mrb_state *mrb, mrb_sym sym) -{ - /* get self */ - return mrb_iv_get(mrb, mrb->c->stack[0], sym); -} - -void -mrb_vm_iv_set(mrb_state *mrb, mrb_sym sym, mrb_value v) -{ - /* get self */ - mrb_iv_set(mrb, mrb->c->stack[0], sym, v); -} - static int iv_i(mrb_state *mrb, mrb_sym sym, mrb_value v, void *p) { diff --git a/src/vm.c b/src/vm.c index 91c617a83..b8feb52db 100644 --- a/src/vm.c +++ b/src/vm.c @@ -1131,8 +1131,7 @@ RETRY_TRY_BLOCK: } CASE(OP_GETIV, BB) { - mrb_value val = mrb_vm_iv_get(mrb, syms[b]); - regs[a] = val; + regs[a] = mrb_vm_iv_get(mrb, syms[b]); NEXT; } -- cgit v1.2.3 From 9409a2ff6d7c1467900278898d97c95dfe9ea229 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Fri, 3 Aug 2018 15:03:09 +0900 Subject: Rename ambiguous function names. `mrb_iv_p` -> `mrb_iv_name_sym_p` `mrb_iv_check` -> `mrb_iv_name_sym_check` --- include/mruby/variable.h | 4 ++-- src/class.c | 4 ++-- src/kernel.c | 8 ++++---- src/variable.c | 6 +++--- 4 files changed, 11 insertions(+), 11 deletions(-) diff --git a/include/mruby/variable.h b/include/mruby/variable.h index a4394fbd3..a0fbca1f9 100644 --- a/include/mruby/variable.h +++ b/include/mruby/variable.h @@ -40,8 +40,8 @@ MRB_API void mrb_const_set(mrb_state*, mrb_value, mrb_sym, mrb_value); MRB_API mrb_bool mrb_const_defined(mrb_state*, mrb_value, mrb_sym); MRB_API void mrb_const_remove(mrb_state*, mrb_value, mrb_sym); -MRB_API mrb_bool mrb_iv_p(mrb_state *mrb, mrb_sym sym); -MRB_API void mrb_iv_check(mrb_state *mrb, mrb_sym sym); +MRB_API mrb_bool mrb_iv_name_sym_p(mrb_state *mrb, mrb_sym sym); +MRB_API void mrb_iv_name_sym_check(mrb_state *mrb, mrb_sym sym); MRB_API mrb_value mrb_obj_iv_get(mrb_state *mrb, struct RObject *obj, mrb_sym sym); MRB_API void mrb_obj_iv_set(mrb_state *mrb, struct RObject *obj, mrb_sym sym, mrb_value v); MRB_API mrb_bool mrb_obj_iv_defined(mrb_state *mrb, struct RObject *obj, mrb_sym sym); diff --git a/src/class.c b/src/class.c index 660dc3b3d..37bc39c75 100644 --- a/src/class.c +++ b/src/class.c @@ -1480,7 +1480,7 @@ mrb_mod_attr_reader(mrb_state *mrb, mrb_value mod) mrb_str_cat_lit(mrb, str, "@"); mrb_str_cat_str(mrb, str, name); sym = mrb_intern_str(mrb, str); - mrb_iv_check(mrb, sym); + mrb_iv_name_sym_check(mrb, sym); name = mrb_symbol_value(sym); p = mrb_proc_new_cfunc_with_env(mrb, attr_reader, 1, &name); MRB_METHOD_FROM_PROC(m, p); @@ -1525,7 +1525,7 @@ mrb_mod_attr_writer(mrb_state *mrb, mrb_value mod) mrb_str_cat_lit(mrb, str, "@"); mrb_str_cat_str(mrb, str, name); sym = mrb_intern_str(mrb, str); - mrb_iv_check(mrb, sym); + mrb_iv_name_sym_check(mrb, sym); attr = mrb_symbol_value(sym); /* prepare method name (name=) */ diff --git a/src/kernel.c b/src/kernel.c index 9986b0222..fed64e9b0 100644 --- a/src/kernel.c +++ b/src/kernel.c @@ -575,7 +575,7 @@ mrb_obj_ivar_defined(mrb_state *mrb, mrb_value self) mrb_sym sym; mrb_get_args(mrb, "n", &sym); - mrb_iv_check(mrb, sym); + mrb_iv_name_sym_check(mrb, sym); return mrb_bool_value(mrb_iv_defined(mrb, self, sym)); } @@ -605,7 +605,7 @@ mrb_obj_ivar_get(mrb_state *mrb, mrb_value self) mrb_sym iv_name; mrb_get_args(mrb, "n", &iv_name); - mrb_iv_check(mrb, iv_name); + mrb_iv_name_sym_check(mrb, iv_name); return mrb_iv_get(mrb, self, iv_name); } @@ -636,7 +636,7 @@ mrb_obj_ivar_set(mrb_state *mrb, mrb_value self) mrb_value val; mrb_get_args(mrb, "no", &iv_name, &val); - mrb_iv_check(mrb, iv_name); + mrb_iv_name_sym_check(mrb, iv_name); mrb_iv_set(mrb, self, iv_name, val); return val; } @@ -951,7 +951,7 @@ mrb_obj_remove_instance_variable(mrb_state *mrb, mrb_value self) mrb_value val; mrb_get_args(mrb, "n", &sym); - mrb_iv_check(mrb, sym); + mrb_iv_name_sym_check(mrb, sym); val = mrb_iv_remove(mrb, self, sym); if (mrb_undef_p(val)) { mrb_name_error(mrb, sym, "instance variable %S not defined", mrb_sym2str(mrb, sym)); diff --git a/src/variable.c b/src/variable.c index 6612c186f..e753f8d29 100644 --- a/src/variable.c +++ b/src/variable.c @@ -393,7 +393,7 @@ mrb_iv_defined(mrb_state *mrb, mrb_value obj, mrb_sym sym) #define identchar(c) (ISALNUM(c) || (c) == '_' || !ISASCII(c)) MRB_API mrb_bool -mrb_iv_p(mrb_state *mrb, mrb_sym iv_name) +mrb_iv_name_sym_p(mrb_state *mrb, mrb_sym iv_name) { const char *s; mrb_int i, len; @@ -409,9 +409,9 @@ mrb_iv_p(mrb_state *mrb, mrb_sym iv_name) } MRB_API void -mrb_iv_check(mrb_state *mrb, mrb_sym iv_name) +mrb_iv_name_sym_check(mrb_state *mrb, mrb_sym iv_name) { - if (!mrb_iv_p(mrb, iv_name)) { + if (!mrb_iv_name_sym_p(mrb, iv_name)) { mrb_name_error(mrb, iv_name, "'%S' is not allowed as an instance variable name", mrb_sym2str(mrb, iv_name)); } } -- cgit v1.2.3 From 49d9fb8f41eff5e7d505f4be2f9d10f78188c97c Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Mon, 6 Aug 2018 16:37:27 +0900 Subject: Reimplement `Hash#compact!` to conform the standard behavior. `Hash#compact!` should return `nil` if the receiver does not change. --- mrbgems/mruby-hash-ext/mrblib/hash.rb | 35 +++++++++++++++++++++--- mrbgems/mruby-hash-ext/src/hash-ext.c | 51 +++-------------------------------- 2 files changed, 36 insertions(+), 50 deletions(-) diff --git a/mrbgems/mruby-hash-ext/mrblib/hash.rb b/mrbgems/mruby-hash-ext/mrblib/hash.rb index 549bca0a8..eaf54b871 100644 --- a/mrbgems/mruby-hash-ext/mrblib/hash.rb +++ b/mrbgems/mruby-hash-ext/mrblib/hash.rb @@ -114,6 +114,31 @@ class Hash alias update merge! + ## + # call-seq: + # hsh.compact! -> hsh + # + # Removes all nil values from the hash. Returns the hash. + # Returns nil if the hash does not contain nil values. + # + # h = { a: 1, b: false, c: nil } + # h.compact! #=> { a: 1, b: false } + # + + def compact! + h = {} + keys = self.keys + nk = keys.select{|k| + self[k] != nil + } + return nil if (keys.size == nk.size) + nk.each {|k| + h[k] = self[k] + } + h + self.replace(h) + end + ## # call-seq: # hsh.compact -> new_hsh @@ -125,9 +150,13 @@ class Hash # h #=> { a: 1, b: false, c: nil } # def compact - result = self.dup - result.compact! - result + h = {} + self.keys.select{|k| + self[k] != nil + }.each {|k| + h[k] = self[k] + } + h end ## diff --git a/mrbgems/mruby-hash-ext/src/hash-ext.c b/mrbgems/mruby-hash-ext/src/hash-ext.c index 6619f5268..e6112667b 100644 --- a/mrbgems/mruby-hash-ext/src/hash-ext.c +++ b/mrbgems/mruby-hash-ext/src/hash-ext.c @@ -36,42 +36,6 @@ hash_values_at(mrb_state *mrb, mrb_value hash) return result; } -/* - * call-seq: - * hsh.compact! -> hsh - * - * Removes all nil values from the hash. Returns the hash. - * - * h = { a: 1, b: false, c: nil } - * h.compact! #=> { a: 1, b: false } - */ -static mrb_value -hash_compact_bang(mrb_state *mrb, mrb_value hash) -{ - khiter_t k; - khash_t(ht) *h = RHASH_TBL(hash); - mrb_int n = -1; - - if (!h) return mrb_nil_value(); - for (k = kh_begin(h); k != kh_end(h); k++) { - if (kh_exist(h, k)) { - mrb_value val = kh_value(h, k).v; - khiter_t k2; - - if (mrb_nil_p(val)) { - kh_del(ht, mrb, h, k); - n = kh_value(h, k).n; - for (k2 = kh_begin(h); k2 != kh_end(h); k2++) { - if (!kh_exist(h, k2)) continue; - if (kh_value(h, k2).n > n) kh_value(h, k2).n--; - } - } - } - } - if (n < 0) return mrb_nil_value(); - return hash; -} - /* * call-seq: * hsh.slice(*keys) -> a_hash @@ -85,28 +49,22 @@ hash_compact_bang(mrb_state *mrb, mrb_value hash) static mrb_value hash_slice(mrb_state *mrb, mrb_value hash) { - khash_t(ht) *h = RHASH_TBL(hash); mrb_value *argv, result; mrb_int argc, i; - khiter_t k; - int ai; mrb_get_args(mrb, "*", &argv, &argc); - if (argc == 0 || h == NULL) { + if (argc == 0) { return mrb_hash_new_capa(mrb, argc); } result = mrb_hash_new_capa(mrb, argc); - ai = mrb_gc_arena_save(mrb); for (i = 0; i < argc; i++) { mrb_value key = argv[i]; + mrb_value val; - k = kh_get(ht, mrb, h, key); - if (k != kh_end(h)) { - mrb_value val = kh_value(h, k).v; - + val = mrb_hash_fetch(mrb, hash, key, mrb_undef_value()); + if (!mrb_undef_p(val)) { mrb_hash_set(mrb, result, key, val); } - mrb_gc_arena_restore(mrb, ai); } return result; } @@ -118,7 +76,6 @@ mrb_mruby_hash_ext_gem_init(mrb_state *mrb) h = mrb->hash_class; mrb_define_method(mrb, h, "values_at", hash_values_at, MRB_ARGS_ANY()); - mrb_define_method(mrb, h, "compact!", hash_compact_bang, MRB_ARGS_NONE()); mrb_define_method(mrb, h, "slice", hash_slice, MRB_ARGS_ANY()); } -- cgit v1.2.3 From 821135e2df838a2088ffca501403c08b21d9a8cf Mon Sep 17 00:00:00 2001 From: pyama86 Date: Mon, 6 Aug 2018 18:15:00 +0900 Subject: irep is released when Fiber is terminated --- src/gc.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/gc.c b/src/gc.c index 33d83f28e..9858e45fc 100644 --- a/src/gc.c +++ b/src/gc.c @@ -965,9 +965,11 @@ gc_gray_mark(mrb_state *mrb, mrb_gc *gc, struct RBasic *obj) size_t i; mrb_callinfo *ci; - if (!c) break; + if (!c || c->status == MRB_FIBER_TERMINATED) break; + /* mark stack */ i = c->stack - c->stbase; + if (c->ci) { i += ci_nregs(c->ci); } -- cgit v1.2.3 From b083c1351f98206aa048d0dea83b83304a1adcc4 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Tue, 7 Aug 2018 23:01:22 +0900 Subject: Fixed the corner case bug in `String#{gsub!,sub!}`. `"a".sub!("a", "a")` should not return `nil`. --- mrblib/string.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mrblib/string.rb b/mrblib/string.rb index ee98cfa0c..07b80b340 100644 --- a/mrblib/string.rb +++ b/mrblib/string.rb @@ -99,7 +99,7 @@ class String raise FrozenError, "can't modify frozen String" if frozen? return to_enum(:gsub!, *args) if args.length == 1 && !block str = self.gsub(*args, &block) - return nil if str == self + return nil unless self.index(args[0]) self.replace(str) end @@ -161,7 +161,7 @@ class String def sub!(*args, &block) raise FrozenError, "can't modify frozen String" if frozen? str = self.sub(*args, &block) - return nil if str == self + return nil unless self.index(args[0]) self.replace(str) end -- cgit v1.2.3 From 2b2ff844a17f07a80a6b8f22d8963ea050f82344 Mon Sep 17 00:00:00 2001 From: Kazuhiro Sera Date: Sat, 11 Aug 2018 00:28:32 +0900 Subject: Fix misspelling words in comments --- doc/guides/mrbgems.md | 4 ++-- include/mruby.h | 4 ++-- minirake | 2 +- mrbgems/mruby-bin-debugger/bintest/print.rb | 2 +- mrbgems/mruby-socket/src/socket.c | 2 +- test/t/literals.rb | 2 +- test/t/module.rb | 4 ++-- 7 files changed, 10 insertions(+), 10 deletions(-) diff --git a/doc/guides/mrbgems.md b/doc/guides/mrbgems.md index 8dac0dc86..0fcc936ed 100644 --- a/doc/guides/mrbgems.md +++ b/doc/guides/mrbgems.md @@ -179,11 +179,11 @@ Version requirement supports following operators: When more than one version requirements is passed, the dependency must satisfy all of it. -You can have default gem to use as depedency when it's not defined in *build_config.rb*. +You can have default gem to use as dependency when it's not defined in *build_config.rb*. When the last argument of `add_dependency` call is `Hash`, it will be treated as default gem information. Its format is same as argument of method `MRuby::Build#gem`, expect that it can't be treated as path gem location. -When a special version of depedency is required, +When a special version of dependency is required, use `MRuby::Build#gem` in *build_config.rb* to override default gem. If you have conflicting GEMs use the following method: diff --git a/include/mruby.h b/include/mruby.h index 12ddb95b3..542d7491f 100644 --- a/include/mruby.h +++ b/include/mruby.h @@ -783,7 +783,7 @@ MRB_API struct RClass * mrb_define_module_under(mrb_state *mrb, struct RClass *o #define MRB_ARGS_REQ(n) ((mrb_aspec)((n)&0x1f) << 18) /** - * Funtion takes n optional arguments + * Function takes n optional arguments * * @param n * The number of optional arguments. @@ -791,7 +791,7 @@ MRB_API struct RClass * mrb_define_module_under(mrb_state *mrb, struct RClass *o #define MRB_ARGS_OPT(n) ((mrb_aspec)((n)&0x1f) << 13) /** - * Funtion takes n1 mandatory arguments and n2 optional arguments + * Function takes n1 mandatory arguments and n2 optional arguments * * @param n1 * The number of required arguments. diff --git a/minirake b/minirake index 8b6bfa296..ad8276a6d 100755 --- a/minirake +++ b/minirake @@ -95,7 +95,7 @@ module MiniRake def done?; @done end def running?; @running end - # Invoke the task if it is needed. Prerequites are invoked first. + # Invoke the task if it is needed. Prerequisites are invoked first. def invoke puts "Invoke #{name} (already=[#{@already_invoked}], needed=[#{needed?}])" if $trace return if @already_invoked diff --git a/mrbgems/mruby-bin-debugger/bintest/print.rb b/mrbgems/mruby-bin-debugger/bintest/print.rb index 0d4aad011..6675392b8 100644 --- a/mrbgems/mruby-bin-debugger/bintest/print.rb +++ b/mrbgems/mruby-bin-debugger/bintest/print.rb @@ -317,7 +317,7 @@ TestConstNameSubClass.new.m() bp = nil SRC - # todo: wait for 'break' to be implimented + # todo: wait for 'break' to be implemented tc = [] 9.times { tc << {:cmd=>"s"} } tc << {:cmd=>"p CONST", :exp=>"super class"} diff --git a/mrbgems/mruby-socket/src/socket.c b/mrbgems/mruby-socket/src/socket.c index b3ca8b1c9..b44371544 100644 --- a/mrbgems/mruby-socket/src/socket.c +++ b/mrbgems/mruby-socket/src/socket.c @@ -300,7 +300,7 @@ mrb_basicsocket_getpeereid(mrb_state *mrb, mrb_value self) mrb_ary_push(mrb, ary, mrb_fixnum_value((mrb_int)egid)); return ary; #else - mrb_raise(mrb, E_RUNTIME_ERROR, "getpeereid is not avaialble on this system"); + mrb_raise(mrb, E_RUNTIME_ERROR, "getpeereid is not available on this system"); return mrb_nil_value(); #endif } diff --git a/test/t/literals.rb b/test/t/literals.rb index 51a37c32d..6344219aa 100644 --- a/test/t/literals.rb +++ b/test/t/literals.rb @@ -22,7 +22,7 @@ assert('Literals Numerical', '8.7.6.2') do # decimal assert_equal 999, 0d999 assert_equal 999, 0D999 - # decimal seperator + # decimal separator assert_equal 10000000, 10_000_000 assert_equal 10, 1_0 # integer with exponent diff --git a/test/t/module.rb b/test/t/module.rb index 5a46c24ff..fb82fc934 100644 --- a/test/t/module.rb +++ b/test/t/module.rb @@ -699,7 +699,7 @@ end end end - # these assertions will not run without a #assert_seperately method + # these assertions will not run without a #assert_separately method #assert 'test_prepend_optmethod' do # bug7983 = '[ruby-dev:47124] [Bug #7983]' # assert_separately [], %{ @@ -807,7 +807,7 @@ end assert_equal([m, c2, m, c1], c2.ancestors[0, 4], "should accesisble prepended module in superclass") end - # requires #assert_seperately + # requires #assert_separately #assert 'Module#prepend call super' do # assert_separately([], <<-'end;') #do # bug10847 = '[ruby-core:68093] [Bug #10847]' -- cgit v1.2.3 From b3a1d379268b3019b0f45eac8d5f10704ac99fc5 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Mon, 13 Aug 2018 15:07:10 +0900 Subject: Make `Array.new` to accept both integers and floats. This time we used `Integral` module which is mruby specific. --- mrblib/array.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mrblib/array.rb b/mrblib/array.rb index 334f4e984..13c5d646c 100644 --- a/mrblib/array.rb +++ b/mrblib/array.rb @@ -66,7 +66,7 @@ class Array # # ISO 15.2.12.5.15 def initialize(size=0, obj=nil, &block) - raise TypeError, "expected Integer for 1st argument" unless size.kind_of? Integer + raise TypeError, "expected Integer for 1st argument" unless size.kind_of? Integral raise ArgumentError, "negative array size" if size < 0 self.clear -- cgit v1.2.3 From fbfe519be77a3afbcb633b2c73709ae400d953d9 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Mon, 13 Aug 2018 15:24:51 +0900 Subject: Simplify `mruby-inline-struct` tests. `gcc -O3` raises error on truncation using `snprintf`. --- mrbgems/mruby-inline-struct/test/inline.c | 18 ++++---- mrbgems/mruby-inline-struct/test/inline.rb | 67 ++++++++---------------------- 2 files changed, 26 insertions(+), 59 deletions(-) diff --git a/mrbgems/mruby-inline-struct/test/inline.c b/mrbgems/mruby-inline-struct/test/inline.c index 95341d348..91c767f30 100644 --- a/mrbgems/mruby-inline-struct/test/inline.c +++ b/mrbgems/mruby-inline-struct/test/inline.c @@ -11,17 +11,17 @@ istruct_test_initialize(mrb_state *mrb, mrb_value self) mrb_value object; mrb_get_args(mrb, "o", &object); - if (mrb_float_p(object)) - { - snprintf(string, size, "float(%.3f)", mrb_float(object)); + if (mrb_float_p(object)) { + strncpy(string, "float", size-1); } - else if (mrb_fixnum_p(object)) - { - snprintf(string, size, "fixnum(%" MRB_PRId ")", mrb_fixnum(object)); + else if (mrb_fixnum_p(object)) { + strncpy(string, "fixnum", size-1); } - else if (mrb_string_p(object)) - { - snprintf(string, size, "string(%s)", mrb_string_value_cstr(mrb, &object)); + else if (mrb_string_p(object)) { + strncpy(string, "string", size-1); + } + else { + strncpy(string, "anything", size-1); } string[size - 1] = 0; // force NULL at the end diff --git a/mrbgems/mruby-inline-struct/test/inline.rb b/mrbgems/mruby-inline-struct/test/inline.rb index 495859232..f959a17c4 100644 --- a/mrbgems/mruby-inline-struct/test/inline.rb +++ b/mrbgems/mruby-inline-struct/test/inline.rb @@ -17,14 +17,14 @@ end assert('InlineStructTest#dup') do obj = InlineStructTest.new(1) - assert_equal obj.to_s, 'fixnum(1)' - assert_equal obj.dup.to_s, 'fixnum(1)' + assert_equal obj.to_s, 'fixnum' + assert_equal obj.dup.to_s, 'fixnum' end assert('InlineStructTest#clone') do obj = InlineStructTest.new(1) - assert_equal obj.to_s, 'fixnum(1)' - assert_equal obj.clone.to_s, 'fixnum(1)' + assert_equal obj.to_s, 'fixnum' + assert_equal obj.clone.to_s, 'fixnum' end assert('InlineStruct#object_id') do @@ -38,22 +38,22 @@ end assert('InlineStructTest#mutate (dup)') do obj1 = InlineStructTest.new("foo") - assert_equal obj1.to_s, "string(foo)" + assert_equal obj1.to_s, "string" obj2 = obj1.dup - assert_equal obj2.to_s, "string(foo)" + assert_equal obj2.to_s, "string" obj1.mutate - assert_equal obj1.to_s, "mutate(foo)" - assert_equal obj2.to_s, "string(foo)" + assert_equal obj1.to_s, "mutate" + assert_equal obj2.to_s, "string" end assert('InlineStructTest#mutate (clone)') do obj1 = InlineStructTest.new("foo") - assert_equal obj1.to_s, "string(foo)" + assert_equal obj1.to_s, "string" obj2 = obj1.clone - assert_equal obj2.to_s, "string(foo)" + assert_equal obj2.to_s, "string" obj1.mutate - assert_equal obj1.to_s, "mutate(foo)" - assert_equal obj2.to_s, "string(foo)" + assert_equal obj1.to_s, "mutate" + assert_equal obj2.to_s, "string" end assert('InlineStructTest#test_receive(string)') do @@ -101,26 +101,6 @@ if InlineStructTest.length == 24 assert('InlineStructTest length [64 bit]') do assert_equal InlineStructTest.length, 3 * 8 end - - assert('InlineStructTest w/float [64 bit]') do - obj = InlineStructTest.new(1.25) - assert_equal obj.to_s, "float(1.250)" - end - - assert('InlineStructTest w/fixnum [64 bit]') do - obj = InlineStructTest.new(42) - assert_equal obj.to_s, "fixnum(42)" - end - - assert('InlineStructTest w/string [64 bit]') do - obj = InlineStructTest.new("hello") - assert_equal obj.to_s, "string(hello)" - end - - assert('InlineStructTest w/long string [64 bit]') do - obj = InlineStructTest.new("this won't fit in 3 * 8 bytes available for the structure") - assert_equal obj.to_s, "string(this won't fit i" - end end # 32-bit mode @@ -128,24 +108,11 @@ if InlineStructTest.length == 12 assert('InlineStructTest length [32 bit]') do assert_equal InlineStructTest.length, 3 * 4 end +end - assert('InlineStructTest w/float [32 bit]') do - obj = InlineStructTest.new(1.25) - assert_equal obj.to_s, "float(1.250" - end - - assert('InlineStructTest w/fixnum [32 bit]') do - obj = InlineStructTest.new(42) - assert_equal obj.to_s, "fixnum(42)" - end - - assert('InlineStructTest w/string [32 bit]') do - obj = InlineStructTest.new("hello") - assert_equal obj.to_s, "string(hell" - end - - assert('InlineStructTest w/long string [32 bit]') do - obj = InlineStructTest.new("this won't fit in 3 * 4 bytes available for the structure") - assert_equal obj.to_s, "string(this" +# 16-bit mode +if InlineStructTest.length == 6 + assert('InlineStructTest length [16 bit]') do + assert_equal InlineStructTest.length, 3 * 2 end end -- cgit v1.2.3 From 31827189ab98a4e51c84772fd782627fc8feb8cc Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Mon, 13 Aug 2018 15:34:13 +0900 Subject: Remove potential path to avoid uninitialized variable access. --- mrbgems/mruby-struct/src/struct.c | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/mrbgems/mruby-struct/src/struct.c b/mrbgems/mruby-struct/src/struct.c index fe7e73f04..b567a00d5 100644 --- a/mrbgems/mruby-struct/src/struct.c +++ b/mrbgems/mruby-struct/src/struct.c @@ -302,17 +302,19 @@ mrb_struct_s_def(mrb_state *mrb, mrb_value klass) } } rest = mrb_ary_new_from_values(mrb, argcnt, pargv); - for (i=0; i Date: Mon, 13 Aug 2018 23:11:34 +0900 Subject: Try to fix a fragile `File#mtime` test. --- mrbgems/mruby-io/src/file.c | 4 ---- mrbgems/mruby-io/test/file.rb | 8 ++++---- 2 files changed, 4 insertions(+), 8 deletions(-) diff --git a/mrbgems/mruby-io/src/file.c b/mrbgems/mruby-io/src/file.c index ca21256cc..e65741061 100644 --- a/mrbgems/mruby-io/src/file.c +++ b/mrbgems/mruby-io/src/file.c @@ -345,11 +345,7 @@ mrb_file_mtime(mrb_state *mrb, mrb_value self) fd = (int)mrb_fixnum(mrb_io_fileno(mrb, self)); if (fstat(fd, &st) == -1) return mrb_false_value(); -#ifndef MRB_WITHOUT_FLOAT - return mrb_funcall(mrb, obj, "at", 1, mrb_float_value(mrb, st.st_mtime)); -#else return mrb_funcall(mrb, obj, "at", 1, mrb_fixnum_value(st.st_mtime)); -#endif } mrb_value diff --git a/mrbgems/mruby-io/test/file.rb b/mrbgems/mruby-io/test/file.rb index ab4678fe9..ca285f5bd 100644 --- a/mrbgems/mruby-io/test/file.rb +++ b/mrbgems/mruby-io/test/file.rb @@ -73,12 +73,12 @@ assert('File#mtime') do skip "File#mtime require Time" end begin - now = Time.now.to_i - mt = 0 File.open("#{$mrbtest_io_wfname}.mtime", 'w') do |f| - mt = f.mtime.to_i + assert_equal Time, f.mtime.class + File.open("#{$mrbtest_io_wfname}.mtime", 'r') do |f2| + assert_equal true, f.mtime == f2.mtime + end end - assert_equal true, mt >= now ensure File.delete("#{$mrbtest_io_wfname}.mtime") end -- cgit v1.2.3 From eeb6d5658d9e29ad24f211a3236eb02abcdb136c Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Thu, 24 May 2018 15:19:06 +0900 Subject: New bytecode implementation of mruby VM. --- mrbgems/mruby-compiler/core/codegen.c | 100 ++++++++++++++++++++++++++++++++++ src/vm.c | 16 +++++- 2 files changed, 113 insertions(+), 3 deletions(-) diff --git a/mrbgems/mruby-compiler/core/codegen.c b/mrbgems/mruby-compiler/core/codegen.c index b8caba3a0..8e72abda2 100644 --- a/mrbgems/mruby-compiler/core/codegen.c +++ b/mrbgems/mruby-compiler/core/codegen.c @@ -445,8 +445,108 @@ gen_move(codegen_scope *s, uint16_t dst, uint16_t src, int nopeep) break; default: goto normal; +======= +struct mrb_insn_data { + uint8_t insn; + uint16_t a; + uint16_t b; + uint8_t c; +}; + +struct mrb_insn_data +mrb_decode_insn(codegen_scope *s, mrb_code *pc) +{ + struct mrb_insn_data data = { 0 }; + mrb_code insn = READ_B(); + uint16_t a = 0; + uint16_t b = 0; + uint8_t c = 0; + + switch (insn) { +#define FETCH_Z() /* empty */ +#define OPCODE(i,x) case OP_ ## i: FETCH_ ## x (); break; +#include "mruby/ops.h" +#undef OPCODE + } + switch (insn) { + case OP_EXT1: + insn = READ_B(); + switch (insn) { +#define OPCODE(i,x) case OP_ ## i: FETCH_ ## x ## _1 (); break; +#include "mruby/ops.h" +#undef OPCODE + } + break; + case OP_EXT2: + insn = READ_B(); + switch (insn) { +#define OPCODE(i,x) case OP_ ## i: FETCH_ ## x ## _2 (); break; +#include "mruby/ops.h" +#undef OPCODE + } + break; + case OP_EXT3: + insn = READ_B(); + switch (insn) { +#define OPCODE(i,x) case OP_ ## i: FETCH_ ## x ## _3 (); break; +#include "mruby/ops.h" +#undef OPCODE + } + break; + default: + break; + } + data.insn = insn; + data.a = a; + data.b = b; + data.c = c; + return data; +} + +struct mrb_insn_data +mrb_last_insn(codegen_scope *s) +{ + if (s->pc == s->lastpc) { + struct mrb_insn_data data; + + data.insn = OP_NOP; + return data; + } + return mrb_decode_insn(s, &s->iseq[s->lastpc]); +} + +static mrb_bool +no_peephole(codegen_scope *s) +{ + return no_optimize(s) || s->lastlabel == s->pc || s->pc == 0 || s->pc == s->lastpc; +} + +static uint16_t +genjmp(codegen_scope *s, mrb_code i, uint16_t pc) +{ + uint16_t pos; + + s->lastpc = s->pc; + gen_B(s, i); + pos = s->pc; + gen_S(s, pc); + return pos; +} + +static uint16_t +genjmp2(codegen_scope *s, mrb_code i, uint16_t a, int pc, int val) +{ + uint16_t pos; + + if (!no_peephole(s) && !val) { + struct mrb_insn_data data = mrb_last_insn(s); + + if (data.insn == OP_MOVE && data.a == a) { + s->pc = s->lastpc; + a = data.b; } } + return genop(s, i); } static void diff --git a/src/vm.c b/src/vm.c index b8feb52db..d206f9675 100644 --- a/src/vm.c +++ b/src/vm.c @@ -1069,6 +1069,16 @@ RETRY_TRY_BLOCK: NEXT; } + CASE(OP_LOADI, BB) { + SET_INT_VALUE(regs[a], b); + NEXT; + } + + CASE(OP_LOADINEG, BB) { + SET_INT_VALUE(regs[a], -b); + NEXT; + } + CASE(OP_LOADI__1,B) goto L_LOADI; CASE(OP_LOADI_0,B) goto L_LOADI; CASE(OP_LOADI_1,B) goto L_LOADI; @@ -1131,12 +1141,12 @@ RETRY_TRY_BLOCK: } CASE(OP_GETIV, BB) { - regs[a] = mrb_vm_iv_get(mrb, syms[b]); + regs[a] = mrb_iv_get(mrb, regs[0], syms[b]); NEXT; } CASE(OP_SETIV, BB) { - mrb_vm_iv_set(mrb, syms[b], regs[a]); + mrb_iv_set(mrb, regs[0], syms[b], regs[a]); NEXT; } @@ -2470,7 +2480,7 @@ RETRY_TRY_BLOCK: #ifdef MRB_WORD_BOXING { mrb_float x = mrb_float(regs[a]); - SET_FLOAT_VALUE(mrb, regs[a], x - GETARG_C(i)); + SET_FLOAT_VALUE(mrb, regs[a], x - c); } #else mrb_float(regs_a[0]) -= c; -- cgit v1.2.3 From b7e56e9d20f25b472a7c4e798771f08de2db5bc2 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Thu, 16 Aug 2018 22:29:28 +0900 Subject: Add bytecode support for `MRB_WORD_BOXING`. --- src/vm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vm.c b/src/vm.c index d206f9675..5ba98ae55 100644 --- a/src/vm.c +++ b/src/vm.c @@ -2480,7 +2480,7 @@ RETRY_TRY_BLOCK: #ifdef MRB_WORD_BOXING { mrb_float x = mrb_float(regs[a]); - SET_FLOAT_VALUE(mrb, regs[a], x - c); + SET_FLOAT_VALUE(mrb, regs[a], (mrb_float)x - (mrb_float)c); } #else mrb_float(regs_a[0]) -= c; -- cgit v1.2.3 From 162243d95cb8f07f98defa5c391b3db40e784576 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Sat, 25 Aug 2018 07:40:09 +0900 Subject: Remove `arg_value` from `parse.y`. --- mrbgems/mruby-compiler/core/parse.y | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/mrbgems/mruby-compiler/core/parse.y b/mrbgems/mruby-compiler/core/parse.y index 44cb28608..28a2b8d5f 100644 --- a/mrbgems/mruby-compiler/core/parse.y +++ b/mrbgems/mruby-compiler/core/parse.y @@ -1179,7 +1179,7 @@ heredoc_end(parser_state *p) %type heredoc words symbols %type call_op call_op2 /* 0:'&.', 1:'.', 2:'::' */ -%type args_tail opt_args_tail f_kwarg f_kw arg_value f_kwrest +%type args_tail opt_args_tail f_kwarg f_kw f_kwrest %type f_block_kwarg f_block_kw block_args_tail opt_block_args_tail %type f_label @@ -3103,11 +3103,9 @@ f_arglist : '(' f_args rparen f_label : tIDENTIFIER tLABEL_TAG ; -arg_value : arg - ; - -f_kw : f_label arg_value +f_kw : f_label arg { + void_expr_error(p, $2); $$ = new_kw_arg(p, $1, $2); } | f_label @@ -3450,8 +3448,9 @@ assoc : arg tASSOC arg $$ = cons(new_sym(p, new_strsym(p, $1)), $3); } } - | tDSTAR arg_value + | tDSTAR arg { + void_expr_error(p, $2); $$ = cons(cons((node*)NODE_KW_REST_ARGS, 0), $2); } ; -- cgit v1.2.3 From e5eb7ef046f5d441bf3930666c6622b0503b7302 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Sat, 25 Aug 2018 07:40:46 +0900 Subject: Add `NODE_KW_HASH` support in `mrb_parser_dump()`. --- mrbgems/mruby-compiler/core/parse.y | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/mrbgems/mruby-compiler/core/parse.y b/mrbgems/mruby-compiler/core/parse.y index 28a2b8d5f..5e6cda236 100644 --- a/mrbgems/mruby-compiler/core/parse.y +++ b/mrbgems/mruby-compiler/core/parse.y @@ -6403,6 +6403,19 @@ mrb_parser_dump(mrb_state *mrb, node *tree, int offset) } break; + case NODE_KW_HASH: + printf("NODE_KW_HASH:\n"); + while (tree) { + dump_prefix(tree, offset+1); + printf("key:\n"); + mrb_parser_dump(mrb, tree->car->car, offset+2); + dump_prefix(tree, offset+1); + printf("value:\n"); + mrb_parser_dump(mrb, tree->car->cdr, offset+2); + tree = tree->cdr; + } + break; + case NODE_SPLAT: printf("NODE_SPLAT:\n"); mrb_parser_dump(mrb, tree, offset+1); -- cgit v1.2.3 From b06dad43fa37ea0edc870202c5d3ad271efacf03 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Sat, 25 Aug 2018 09:07:00 +0900 Subject: Remove unused `NODE_*` constants from `node.h`. --- mrbgems/mruby-compiler/core/node.h | 20 -------------------- 1 file changed, 20 deletions(-) diff --git a/mrbgems/mruby-compiler/core/node.h b/mrbgems/mruby-compiler/core/node.h index af71332e7..219bddab0 100644 --- a/mrbgems/mruby-compiler/core/node.h +++ b/mrbgems/mruby-compiler/core/node.h @@ -9,14 +9,11 @@ enum node_type { NODE_METHOD, - NODE_FBODY, - NODE_CFUNC, NODE_SCOPE, NODE_BLOCK, NODE_IF, NODE_CASE, NODE_WHEN, - NODE_OPT_N, NODE_WHILE, NODE_UNTIL, NODE_ITER, @@ -40,7 +37,6 @@ enum node_type { NODE_CALL, NODE_SCALL, NODE_FCALL, - NODE_VCALL, NODE_SUPER, NODE_ZSUPER, NODE_ARRAY, @@ -58,8 +54,6 @@ enum node_type { NODE_NTH_REF, NODE_BACK_REF, NODE_MATCH, - NODE_MATCH2, - NODE_MATCH3, NODE_INT, NODE_FLOAT, NODE_NEGATE, @@ -72,13 +66,10 @@ enum node_type { NODE_REGX, NODE_DREGX, NODE_DREGX_ONCE, - NODE_LIST, NODE_ARG, NODE_ARGS_TAIL, NODE_KW_ARG, NODE_KW_REST_ARGS, - NODE_ARGSCAT, - NODE_ARGSPUSH, NODE_SPLAT, NODE_TO_ARY, NODE_SVALUE, @@ -92,26 +83,15 @@ enum node_type { NODE_SCLASS, NODE_COLON2, NODE_COLON3, - NODE_CREF, NODE_DOT2, NODE_DOT3, - NODE_FLIP2, - NODE_FLIP3, - NODE_ATTRSET, NODE_SELF, NODE_NIL, NODE_TRUE, NODE_FALSE, NODE_DEFINED, - NODE_NEWLINE, NODE_POSTEXE, - NODE_ALLOCA, - NODE_DMETHOD, - NODE_BMETHOD, - NODE_MEMO, - NODE_IFUNC, NODE_DSYM, - NODE_ATTRASGN, NODE_HEREDOC, NODE_LITERAL_DELIM, NODE_WORDS, -- cgit v1.2.3 From 3554fc54de68e2cf92121147df071b57b50663b1 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Sat, 25 Aug 2018 09:08:16 +0900 Subject: Add a new function `mrb_hash_merge()`. --- include/mruby/hash.h | 10 ++++++++++ src/hash.c | 33 +++++++++++++++++++++++++++++++++ 2 files changed, 43 insertions(+) diff --git a/include/mruby/hash.h b/include/mruby/hash.h index 9a3812850..2026c8e0d 100644 --- a/include/mruby/hash.h +++ b/include/mruby/hash.h @@ -174,6 +174,16 @@ MRB_API mrb_value mrb_hash_clear(mrb_state *mrb, mrb_value hash); */ MRB_API mrb_value mrb_hash_dup(mrb_state *mrb, mrb_value hash); +/* + * Merges two hashes. The first hash will be modified by the + * second hash. + * + * @param mrb The mruby state reference. + * @param hash1 The target hash. + * @param hash2 Updating hash + */ +MRB_API void mrb_hash_merge(mrb_state *mrb, mrb_value hash1, mrb_value hash2); + /* declaration of struct kh_ht */ /* be careful when you touch the internal */ typedef struct { diff --git a/src/hash.c b/src/hash.c index 0dce81677..122f5b5d5 100644 --- a/src/hash.c +++ b/src/hash.c @@ -951,6 +951,39 @@ mrb_hash_has_value(mrb_state *mrb, mrb_value hash) return mrb_false_value(); } +MRB_API void +mrb_hash_merge(mrb_state *mrb, mrb_value hash1, mrb_value hash2) +{ + khash_t(ht) *h1; + khash_t(ht) *h2; + khiter_t k; + + mrb_hash_modify(mrb, hash1); + hash2 = mrb_check_hash_type(mrb, hash2); + h1 = RHASH_TBL(hash1); + h2 = RHASH_TBL(hash2); + + if (!h1) { + RHASH_TBL(hash1) = kh_copy(ht, mrb, h2); + return; + } + for (k = kh_begin(h2); k != kh_end(h2); k++) { + khiter_t k1; + int r; + + if (!kh_exist(h2, k)) continue; + k1 = kh_put2(ht, mrb, h1, kh_key(h2, k), &r); + kh_value(h1, k1).v = kh_value(h2,k).v; + if (r != 0) { + /* expand */ + kh_key(h1, k1) = kh_key(h2, k); + kh_value(h1, k1).n = kh_size(h1)-1; + } + } + mrb_write_barrier(mrb, (struct RBasic*)RHASH(hash1)); + return; +} + void mrb_init_hash(mrb_state *mrb) { -- cgit v1.2.3 From a3fb80904dcbbf2aaec0df202e343b10f0518d1c Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Sat, 25 Aug 2018 09:08:49 +0900 Subject: Remove unused `Hash#__update` method. --- mrblib/hash.rb | 5 ----- 1 file changed, 5 deletions(-) diff --git a/mrblib/hash.rb b/mrblib/hash.rb index 7e1db905f..96029a230 100644 --- a/mrblib/hash.rb +++ b/mrblib/hash.rb @@ -341,11 +341,6 @@ class Hash } self.replace(h) end - - def __update(h) - h.each_key{|k| self[k] = h[k]} - self - end end ## -- cgit v1.2.3 From 306732e02da5f0d47f44033ec1a3af1a77c5f418 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Sat, 25 Aug 2018 09:09:49 +0900 Subject: Fixed a bug in `OP_HASHADD`. --- src/vm.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/vm.c b/src/vm.c index 5ba98ae55..8332158f7 100644 --- a/src/vm.c +++ b/src/vm.c @@ -2704,9 +2704,8 @@ RETRY_TRY_BLOCK: int i; int lim = a+b*2+1; - for (i=a+1; i Date: Sat, 25 Aug 2018 09:10:37 +0900 Subject: Hash splat `**` should not be ignored. Implemented by adding `OP_HASHCAT` that merges hashes. --- include/mruby/ops.h | 1 + mrbgems/mruby-compiler/core/codegen.c | 37 ++++++++++++++++++++++++++--------- src/codedump.c | 6 +++++- src/vm.c | 5 +++++ 4 files changed, 39 insertions(+), 10 deletions(-) diff --git a/include/mruby/ops.h b/include/mruby/ops.h index b8fc89d43..f23bb1b0b 100644 --- a/include/mruby/ops.h +++ b/include/mruby/ops.h @@ -94,6 +94,7 @@ OPCODE(STRING, BB) /* R(a) = str_dup(Lit(b)) */ OPCODE(STRCAT, B) /* str_cat(R(a),R(a+1)) */ OPCODE(HASH, BB) /* R(a) = hash_new(R(a),R(a+1)..R(a+b)) */ OPCODE(HASHADD, BB) /* R(a) = hash_push(R(a),R(a+1)..R(a+b)) */ +OPCODE(HASHCAT, B) /* R(a) = hash_cat(R(a),R(a+1)) */ OPCODE(LAMBDA, BB) /* R(a) = lambda(SEQ[b],L_LAMBDA) */ OPCODE(BLOCK, BB) /* R(a) = lambda(SEQ[b],L_BLOCK) */ OPCODE(METHOD, BB) /* R(a) = lambda(SEQ[b],L_METHOD) */ diff --git a/mrbgems/mruby-compiler/core/codegen.c b/mrbgems/mruby-compiler/core/codegen.c index 8e72abda2..bf5cc14b0 100644 --- a/mrbgems/mruby-compiler/core/codegen.c +++ b/mrbgems/mruby-compiler/core/codegen.c @@ -1874,15 +1874,32 @@ codegen(codegen_scope *s, node *tree, int val) mrb_bool update = FALSE; while (tree) { - if (nt == NODE_KW_HASH && - nint(tree->car->car->car) == NODE_KW_REST_ARGS) { - tree = tree->cdr; - continue; + if (nint(tree->car->car->car) == NODE_KW_REST_ARGS) { + if (len > 0) { + pop_n(len*2); + if (!update) { + genop_2(s, OP_HASH, cursp(), len); + } + else { + pop(); + genop_2(s, OP_HASHADD, cursp(), len); + } + push(); + } + codegen(s, tree->car->cdr, VAL); + if (len > 0) { + pop(); pop(); + genop_1(s, OP_HASHCAT, cursp()); + push(); + } + update = TRUE; + len = 0; + } + else { + codegen(s, tree->car->car, VAL); + codegen(s, tree->car->cdr, VAL); + len++; } - - codegen(s, tree->car->car, val); - codegen(s, tree->car->cdr, val); - len++; tree = tree->cdr; if (val && len == 255) { pop_n(len*2); @@ -1905,7 +1922,9 @@ codegen(codegen_scope *s, node *tree, int val) } else { pop(); - genop_2(s, OP_HASHADD, cursp(), len); + if (len > 0) { + genop_2(s, OP_HASHADD, cursp(), len); + } } push(); } diff --git a/src/codedump.c b/src/codedump.c index 842d40bdf..9174ebe3d 100644 --- a/src/codedump.c +++ b/src/codedump.c @@ -416,7 +416,11 @@ codedump(mrb_state *mrb, mrb_irep *irep) print_lv_a(mrb, irep, a); break; CASE(OP_HASHADD, BB): - printf("OP_HASHADD\tR%d\t%d", a, b); + printf("OP_HASHADD\tR%d\t%d\t", a, b); + print_lv_a(mrb, irep, a); + break; + CASE(OP_HASHCAT, B): + printf("OP_HASHCAT\tR%d\t", a); print_lv_a(mrb, irep, a); break; diff --git a/src/vm.c b/src/vm.c index 8332158f7..b47469ebf 100644 --- a/src/vm.c +++ b/src/vm.c @@ -2710,6 +2710,11 @@ RETRY_TRY_BLOCK: mrb_gc_arena_restore(mrb, ai); NEXT; } + CASE(OP_HASHCAT, B) { + mrb_hash_merge(mrb, regs[a], regs[a+1]); + mrb_gc_arena_restore(mrb, ai); + NEXT; + } CASE(OP_LAMBDA, BB) c = OP_L_LAMBDA; -- cgit v1.2.3 From d79dbd92f9104712c6cf41ab3c029dec318a757d Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Sat, 25 Aug 2018 09:49:20 +0900 Subject: fixup! New bytecode implementation of mruby VM. --- mrbgems/mruby-compiler/core/codegen.c | 100 ---------------------------------- src/vm.c | 10 ---- 2 files changed, 110 deletions(-) diff --git a/mrbgems/mruby-compiler/core/codegen.c b/mrbgems/mruby-compiler/core/codegen.c index bf5cc14b0..075945b3b 100644 --- a/mrbgems/mruby-compiler/core/codegen.c +++ b/mrbgems/mruby-compiler/core/codegen.c @@ -445,108 +445,8 @@ gen_move(codegen_scope *s, uint16_t dst, uint16_t src, int nopeep) break; default: goto normal; -======= -struct mrb_insn_data { - uint8_t insn; - uint16_t a; - uint16_t b; - uint8_t c; -}; - -struct mrb_insn_data -mrb_decode_insn(codegen_scope *s, mrb_code *pc) -{ - struct mrb_insn_data data = { 0 }; - mrb_code insn = READ_B(); - uint16_t a = 0; - uint16_t b = 0; - uint8_t c = 0; - - switch (insn) { -#define FETCH_Z() /* empty */ -#define OPCODE(i,x) case OP_ ## i: FETCH_ ## x (); break; -#include "mruby/ops.h" -#undef OPCODE - } - switch (insn) { - case OP_EXT1: - insn = READ_B(); - switch (insn) { -#define OPCODE(i,x) case OP_ ## i: FETCH_ ## x ## _1 (); break; -#include "mruby/ops.h" -#undef OPCODE - } - break; - case OP_EXT2: - insn = READ_B(); - switch (insn) { -#define OPCODE(i,x) case OP_ ## i: FETCH_ ## x ## _2 (); break; -#include "mruby/ops.h" -#undef OPCODE - } - break; - case OP_EXT3: - insn = READ_B(); - switch (insn) { -#define OPCODE(i,x) case OP_ ## i: FETCH_ ## x ## _3 (); break; -#include "mruby/ops.h" -#undef OPCODE - } - break; - default: - break; - } - data.insn = insn; - data.a = a; - data.b = b; - data.c = c; - return data; -} - -struct mrb_insn_data -mrb_last_insn(codegen_scope *s) -{ - if (s->pc == s->lastpc) { - struct mrb_insn_data data; - - data.insn = OP_NOP; - return data; - } - return mrb_decode_insn(s, &s->iseq[s->lastpc]); -} - -static mrb_bool -no_peephole(codegen_scope *s) -{ - return no_optimize(s) || s->lastlabel == s->pc || s->pc == 0 || s->pc == s->lastpc; -} - -static uint16_t -genjmp(codegen_scope *s, mrb_code i, uint16_t pc) -{ - uint16_t pos; - - s->lastpc = s->pc; - gen_B(s, i); - pos = s->pc; - gen_S(s, pc); - return pos; -} - -static uint16_t -genjmp2(codegen_scope *s, mrb_code i, uint16_t a, int pc, int val) -{ - uint16_t pos; - - if (!no_peephole(s) && !val) { - struct mrb_insn_data data = mrb_last_insn(s); - - if (data.insn == OP_MOVE && data.a == a) { - s->pc = s->lastpc; - a = data.b; } } - return genop(s, i); } static void diff --git a/src/vm.c b/src/vm.c index b47469ebf..d0ea6b3bd 100644 --- a/src/vm.c +++ b/src/vm.c @@ -1069,16 +1069,6 @@ RETRY_TRY_BLOCK: NEXT; } - CASE(OP_LOADI, BB) { - SET_INT_VALUE(regs[a], b); - NEXT; - } - - CASE(OP_LOADINEG, BB) { - SET_INT_VALUE(regs[a], -b); - NEXT; - } - CASE(OP_LOADI__1,B) goto L_LOADI; CASE(OP_LOADI_0,B) goto L_LOADI; CASE(OP_LOADI_1,B) goto L_LOADI; -- cgit v1.2.3 From 471288f37d18e640f98029fabcdcb7ee16b95d93 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Sat, 25 Aug 2018 16:58:01 +0900 Subject: Reduce integer casting warnings. --- include/mruby.h | 2 +- mrbgems/mruby-compiler/core/codegen.c | 8 ++++---- mrbgems/mruby-eval/src/eval.c | 6 +++--- src/codedump.c | 6 +++--- src/load.c | 4 ++-- src/vm.c | 2 +- 6 files changed, 14 insertions(+), 14 deletions(-) diff --git a/include/mruby.h b/include/mruby.h index 542d7491f..872396899 100644 --- a/include/mruby.h +++ b/include/mruby.h @@ -1234,7 +1234,7 @@ MRB_API mrb_value mrb_fiber_alive_p(mrb_state *mrb, mrb_value fib); * @mrbgem mruby-fiber */ #define E_FIBER_ERROR (mrb_exc_get(mrb, "FiberError")) -MRB_API void mrb_stack_extend(mrb_state*, int); +MRB_API void mrb_stack_extend(mrb_state*, mrb_int); /* memory pool implementation */ typedef struct mrb_pool mrb_pool; diff --git a/mrbgems/mruby-compiler/core/codegen.c b/mrbgems/mruby-compiler/core/codegen.c index 075945b3b..a835a563e 100644 --- a/mrbgems/mruby-compiler/core/codegen.c +++ b/mrbgems/mruby-compiler/core/codegen.c @@ -400,7 +400,7 @@ genjmp2(codegen_scope *s, mrb_code i, uint16_t a, int pc, int val) } else { gen_B(s, i); - gen_B(s, a); + gen_B(s, (uint8_t)a); pos = s->pc; gen_S(s, pc); } @@ -494,10 +494,10 @@ gen_addsub(codegen_scope *s, uint8_t op, uint16_t dst, uint16_t idx) if (data.b >= 128) goto normal; s->pc = s->lastpc; if (op == OP_ADD) { - genop_3(s, OP_ADDI, dst, idx, data.b); + genop_3(s, OP_ADDI, dst, idx, (uint8_t)data.b); } else { - genop_3(s, OP_SUBI, dst, idx, data.b); + genop_3(s, OP_SUBI, dst, idx, (uint8_t)data.b); } break; default: @@ -2441,7 +2441,7 @@ codegen(codegen_scope *s, node *tree, int val) #endif if (i == -1) genop_1(s, OP_LOADI__1, cursp()); else if (i >= -0xffff) { - genop_2(s, OP_LOADINEG, cursp(), -i); + genop_2(s, OP_LOADINEG, cursp(), (uint16_t)-i); } else { int off = new_lit(s, mrb_fixnum_value(i)); diff --git a/mrbgems/mruby-eval/src/eval.c b/mrbgems/mruby-eval/src/eval.c index f1e50e83d..b9c87f6d1 100644 --- a/mrbgems/mruby-eval/src/eval.c +++ b/mrbgems/mruby-eval/src/eval.c @@ -154,7 +154,7 @@ patch_irep(mrb_state *mrb, mrb_irep *irep, int bnest, mrb_irep *top) if (arg != 0) { /* must replace */ irep->iseq[i] = insn = OP_SETUPVAR; - irep->iseq[i+1] = b; + irep->iseq[i+1] = (mrb_code)b; irep->iseq[i+2] = arg >> 8; irep->iseq[i+3] = arg & 0xff; } @@ -169,7 +169,7 @@ patch_irep(mrb_state *mrb, mrb_irep *irep, int bnest, mrb_irep *top) int lev = c+1; mrb_irep *tmp = search_irep(top, bnest, lev, irep); if (potential_upvar_p(tmp->lv, b, irep_argc(tmp), tmp->nlocals)) { - mrb_code arg = search_variable(mrb, tmp->lv[b-1].name, bnest); + uint16_t arg = search_variable(mrb, tmp->lv[b-1].name, bnest); if (arg != 0) { /* must replace */ irep->iseq[i] = OP_GETUPVAR; @@ -188,7 +188,7 @@ patch_irep(mrb_state *mrb, mrb_irep *irep, int bnest, mrb_irep *top) int lev = c+1; mrb_irep *tmp = search_irep(top, bnest, lev, irep); if (potential_upvar_p(tmp->lv, b, irep_argc(tmp), tmp->nlocals)) { - mrb_code arg = search_variable(mrb, tmp->lv[b-1].name, bnest); + uint16_t arg = search_variable(mrb, tmp->lv[b-1].name, bnest); if (arg != 0) { /* must replace */ irep->iseq[i] = OP_SETUPVAR; diff --git a/src/codedump.c b/src/codedump.c index 9174ebe3d..80802778f 100644 --- a/src/codedump.c +++ b/src/codedump.c @@ -48,7 +48,7 @@ print_lv_ab(mrb_state *mrb, mrb_irep *irep, uint16_t a, uint16_t b) #endif static void -print_header(mrb_irep *irep, int i) +print_header(mrb_irep *irep, ptrdiff_t i) { int32_t line; @@ -60,7 +60,7 @@ print_header(mrb_irep *irep, int i) printf("%5d ", line); } - printf("%03d ", i); + printf("%03d ", (int)i); } #define CASE(insn,ops) case insn: FETCH_ ## ops (); L_ ## insn @@ -91,7 +91,7 @@ codedump(mrb_state *mrb, mrb_irep *irep) pc = irep->iseq; pcend = pc + irep->ilen; while (pc < pcend) { - int i; + ptrdiff_t i; uint32_t a; uint16_t b; uint8_t c; diff --git a/src/load.c b/src/load.c index 20878aa56..54b50b14d 100644 --- a/src/load.c +++ b/src/load.c @@ -68,7 +68,7 @@ read_irep_record_1(mrb_state *mrb, const uint8_t *bin, size_t *len, uint8_t flag /* Binary Data Section */ /* ISEQ BLOCK */ - irep->ilen = (size_t)bin_to_uint32(src); + irep->ilen = (uint16_t)bin_to_uint32(src); src += sizeof(uint32_t); src += skip_padding(src); @@ -157,7 +157,7 @@ read_irep_record_1(mrb_state *mrb, const uint8_t *bin, size_t *len, uint8_t flag } /* SYMS BLOCK */ - irep->slen = (size_t)bin_to_uint32(src); /* syms length */ + irep->slen = (uint16_t)bin_to_uint32(src); /* syms length */ src += sizeof(uint32_t); if (irep->slen > 0) { if (SIZE_ERROR_MUL(irep->slen, sizeof(mrb_sym))) { diff --git a/src/vm.c b/src/vm.c index d0ea6b3bd..44472e311 100644 --- a/src/vm.c +++ b/src/vm.c @@ -218,7 +218,7 @@ stack_extend_alloc(mrb_state *mrb, int room) } MRB_API void -mrb_stack_extend(mrb_state *mrb, int room) +mrb_stack_extend(mrb_state *mrb, mrb_int room) { if (mrb->c->stack + room >= mrb->c->stend) { stack_extend_alloc(mrb, room); -- cgit v1.2.3 From 814b7b5ef8d965e1bc7e306055b9fe6971dc8698 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Wed, 29 Aug 2018 07:00:13 +0900 Subject: Move back `mrb_define_alias` to `mruby.h` to avoid breakage. --- include/mruby.h | 1 + include/mruby/class.h | 1 - 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/include/mruby.h b/include/mruby.h index 872396899..1c888bb46 100644 --- a/include/mruby.h +++ b/include/mruby.h @@ -1197,6 +1197,7 @@ typedef enum call_type { CALL_TYPE_MAX } call_type; +MRB_API void mrb_define_alias(mrb_state *mrb, struct RClass *c, const char *a, const char *b); MRB_API const char *mrb_class_name(mrb_state *mrb, struct RClass* klass); MRB_API void mrb_define_global_const(mrb_state *mrb, const char *name, mrb_value val); diff --git a/include/mruby/class.h b/include/mruby/class.h index 96a9f7f95..97b1df58a 100644 --- a/include/mruby/class.h +++ b/include/mruby/class.h @@ -80,7 +80,6 @@ MRB_API struct RClass *mrb_vm_define_module(mrb_state*, mrb_value, mrb_sym); MRB_API void mrb_define_method_raw(mrb_state*, struct RClass*, mrb_sym, mrb_method_t); MRB_API void mrb_define_method_id(mrb_state *mrb, struct RClass *c, mrb_sym mid, mrb_func_t func, mrb_aspec aspec); MRB_API void mrb_alias_method(mrb_state*, struct RClass *c, mrb_sym a, mrb_sym b); -MRB_API void mrb_define_alias(mrb_state*, struct RClass *c, const char* a, const char* b); MRB_API mrb_method_t mrb_method_search_vm(mrb_state*, struct RClass**, mrb_sym); MRB_API mrb_method_t mrb_method_search(mrb_state*, struct RClass*, mrb_sym); -- cgit v1.2.3 From bc88fc6ed15b9837659071817d93885e4910cba5 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Wed, 29 Aug 2018 12:31:48 +0900 Subject: Check iseq buffer size before code emission; fix #4090 The type of `s->pc` is now `uint16_t` that can be overflowed easily. Need more checks. --- mrbgems/mruby-compiler/core/codegen.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/mrbgems/mruby-compiler/core/codegen.c b/mrbgems/mruby-compiler/core/codegen.c index a835a563e..13f5aa053 100644 --- a/mrbgems/mruby-compiler/core/codegen.c +++ b/mrbgems/mruby-compiler/core/codegen.c @@ -151,11 +151,11 @@ new_label(codegen_scope *s) static void emit_B(codegen_scope *s, uint32_t pc, uint8_t i) { + if (pc >= MAXARG_S || s->icapa >= MAXARG_S) { + codegen_error(s, "too big code block"); + } if (pc >= s->icapa) { s->icapa *= 2; - if (pc >= MAXARG_S) { - codegen_error(s, "too big code block"); - } if (s->icapa > MAXARG_S) { s->icapa = MAXARG_S; } @@ -184,7 +184,8 @@ emit_S(codegen_scope *s, int pc, uint16_t i) static void gen_B(codegen_scope *s, uint8_t i) { - emit_B(s, s->pc++, i); + emit_B(s, s->pc, i); + s->pc++; } static void @@ -248,7 +249,6 @@ genop_2(codegen_scope *s, mrb_code i, uint16_t a, uint16_t b) static void genop_3(codegen_scope *s, mrb_code i, uint16_t a, uint16_t b, uint8_t c) { - s->lastpc = s->pc; genop_2(s, i, a, b); gen_B(s, c); } @@ -256,7 +256,6 @@ genop_3(codegen_scope *s, mrb_code i, uint16_t a, uint16_t b, uint8_t c) static void genop_2S(codegen_scope *s, mrb_code i, uint16_t a, uint16_t b) { - s->lastpc = s->pc; genop_1(s, i, a); gen_S(s, b); } -- cgit v1.2.3 From 6aa091e5aadafa11d9f10d9fa7d821cf5e5e379d Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Wed, 29 Aug 2018 12:37:07 +0900 Subject: Simplified `#ifdef` nesting in `codedump.c`; fix #4089 `printf()` and related functions should not be called when `MRB_DISABLE_STDIO` is defined. --- src/codedump.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/codedump.c b/src/codedump.c index 80802778f..454b16b36 100644 --- a/src/codedump.c +++ b/src/codedump.c @@ -45,7 +45,6 @@ print_lv_ab(mrb_state *mrb, mrb_irep *irep, uint16_t a, uint16_t b) if (b > 0) print_r(mrb, irep, b); printf("\n"); } -#endif static void print_header(mrb_irep *irep, ptrdiff_t i) @@ -68,7 +67,6 @@ print_header(mrb_irep *irep, ptrdiff_t i) static void codedump(mrb_state *mrb, mrb_irep *irep) { -#ifndef MRB_DISABLE_STDIO int ai; mrb_code *pc, *pcend; mrb_code ins; @@ -526,7 +524,6 @@ codedump(mrb_state *mrb, mrb_irep *irep) mrb_gc_arena_restore(mrb, ai); } printf("\n"); -#endif } static void @@ -539,9 +536,12 @@ codedump_recur(mrb_state *mrb, mrb_irep *irep) codedump_recur(mrb, irep->reps[i]); } } +#endif void mrb_codedump_all(mrb_state *mrb, struct RProc *proc) { +#ifndef MRB_DISABLE_STDIO codedump_recur(mrb, proc->body.irep); +#endif } -- cgit v1.2.3 From 2a88a546b220d9abe483b27c81d5f12c3342f37f Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Wed, 29 Aug 2018 13:12:03 +0900 Subject: Fix type of `eidx` and `ridx` from `uint8_t` to `uint16_t`; fix #4088 A byte was too small to hold ensure&rescue stacks indexes. --- include/mruby.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/mruby.h b/include/mruby.h index 1c888bb46..2d30d3d27 100644 --- a/include/mruby.h +++ b/include/mruby.h @@ -152,9 +152,9 @@ struct mrb_context { mrb_callinfo *cibase, *ciend; uint16_t *rescue; /* exception handler stack */ - int rsize; + uint16_t rsize; struct RProc **ensure; /* ensure handler stack */ - uint8_t esize, eidx; + uint16_t esize, eidx; enum mrb_fiber_state status; mrb_bool vmexec; -- cgit v1.2.3 From 98c759e86a73c2e2220c7b9d36a9d78177891273 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Wed, 29 Aug 2018 13:17:18 +0900 Subject: Check the size of rescue&ensure stacks; ref #4088 Those small stack indexes can cause integer overflow. --- src/vm.c | 35 ++++++++++++++++++++++++++++++----- 1 file changed, 30 insertions(+), 5 deletions(-) diff --git a/src/vm.c b/src/vm.c index 44472e311..45d2b5881 100644 --- a/src/vm.c +++ b/src/vm.c @@ -1239,11 +1239,24 @@ RETRY_TRY_BLOCK: } CASE(OP_ONERR, S) { + /* check rescue stack */ + if (mrb->c->ci->ridx == UINT16_MAX) { + mrb_value exc = mrb_exc_new_str_lit(mrb, E_RUNTIME_ERROR, "too many nested rescues"); + mrb_exc_set(mrb, exc); + goto L_RAISE; + } + /* expand rescue stack */ if (mrb->c->rsize <= mrb->c->ci->ridx) { if (mrb->c->rsize == 0) mrb->c->rsize = RESCUE_STACK_INIT_SIZE; - else mrb->c->rsize *= 2; - mrb->c->rescue = (uint16_t*)mrb_realloc(mrb, mrb->c->rescue, sizeof(uint16_t) * mrb->c->rsize); + else { + mrb->c->rsize *= 2; + if (mrb->c->rsize <= mrb->c->ci->ridx) { + mrb->c->rsize = UINT16_MAX; + } + } + mrb->c->rescue = (uint16_t*)mrb_realloc(mrb, mrb->c->rescue, sizeof(uint16_t)*mrb->c->rsize); } + /* push rescue stack */ mrb->c->rescue[mrb->c->ci->ridx++] = a; NEXT; } @@ -1292,12 +1305,24 @@ RETRY_TRY_BLOCK: struct RProc *p; p = mrb_closure_new(mrb, irep->reps[a]); - /* push ensure_stack */ + /* check ensure stack */ + if (mrb->c->eidx == UINT16_MAX) { + mrb_value exc = mrb_exc_new_str_lit(mrb, E_RUNTIME_ERROR, "too many nested ensures"); + mrb_exc_set(mrb, exc); + goto L_RAISE; + } + /* expand ensure stack */ if (mrb->c->esize <= mrb->c->eidx+1) { if (mrb->c->esize == 0) mrb->c->esize = ENSURE_STACK_INIT_SIZE; - else mrb->c->esize *= 2; - mrb->c->ensure = (struct RProc **)mrb_realloc(mrb, mrb->c->ensure, sizeof(struct RProc*) * mrb->c->esize); + else { + mrb->c->esize *= 2; + if (mrb->c->esize <= mrb->c->eidx) { + mrb->c->esize = UINT16_MAX; + } + } + mrb->c->ensure = (struct RProc**)mrb_realloc(mrb, mrb->c->ensure, sizeof(struct RProc*)*mrb->c->esize); } + /* push ensure stack */ mrb->c->ensure[mrb->c->eidx++] = p; mrb->c->ensure[mrb->c->eidx] = NULL; mrb_gc_arena_restore(mrb, ai); -- cgit v1.2.3 From f76cc483d55b58f2b5803b13cb5e528a67b39c3b Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Wed, 29 Aug 2018 23:59:20 +0900 Subject: Fix off-by-one error in `OP_EPUSH` and `OP_ONERR`; fix #4095 --- src/vm.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/vm.c b/src/vm.c index 45d2b5881..2fd1e5efa 100644 --- a/src/vm.c +++ b/src/vm.c @@ -1240,7 +1240,7 @@ RETRY_TRY_BLOCK: CASE(OP_ONERR, S) { /* check rescue stack */ - if (mrb->c->ci->ridx == UINT16_MAX) { + if (mrb->c->ci->ridx == UINT16_MAX-1) { mrb_value exc = mrb_exc_new_str_lit(mrb, E_RUNTIME_ERROR, "too many nested rescues"); mrb_exc_set(mrb, exc); goto L_RAISE; @@ -1306,7 +1306,7 @@ RETRY_TRY_BLOCK: p = mrb_closure_new(mrb, irep->reps[a]); /* check ensure stack */ - if (mrb->c->eidx == UINT16_MAX) { + if (mrb->c->eidx == UINT16_MAX-1) { mrb_value exc = mrb_exc_new_str_lit(mrb, E_RUNTIME_ERROR, "too many nested ensures"); mrb_exc_set(mrb, exc); goto L_RAISE; -- cgit v1.2.3 From 2c93e4a0a816d9c0d547a27b9f09fa61a2497d95 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Thu, 30 Aug 2018 00:15:16 +0900 Subject: The operand of `OP_ARYDUP` may not be an array; fix #4094 This commit also fix #4096. --- src/vm.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/vm.c b/src/vm.c index 2fd1e5efa..c8088d22e 100644 --- a/src/vm.c +++ b/src/vm.c @@ -2618,7 +2618,12 @@ RETRY_TRY_BLOCK: CASE(OP_ARYDUP, B) { mrb_value ary = regs[a]; - ary = mrb_ary_new_from_values(mrb, RARRAY_LEN(ary), RARRAY_PTR(ary)); + if (mrb_array_p(ary)) { + ary = mrb_ary_new_from_values(mrb, RARRAY_LEN(ary), RARRAY_PTR(ary)); + } + else { + ary = mrb_ary_new_from_values(mrb, 1, &ary); + } regs[a] = ary; NEXT; } -- cgit v1.2.3 From 500bd38dfe12899ded93f049741afffdb03974a1 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Thu, 30 Aug 2018 00:25:25 +0900 Subject: `uint16_t` is too small for reference count; fix #4093 Use `uint32_t` instead. Theoretically `uint32_t` can overflow as well, but I think it is sufficient size for embeddable Ruby VM. --- include/mruby/irep.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/include/mruby/irep.h b/include/mruby/irep.h index 7dcf33735..76bafb25c 100644 --- a/include/mruby/irep.h +++ b/include/mruby/irep.h @@ -44,7 +44,8 @@ typedef struct mrb_irep { uint16_t *lines; struct mrb_irep_debug_info* debug_info; - uint16_t ilen, plen, slen, rlen, refcnt; + uint16_t ilen, plen, slen, rlen; + uint32_t refcnt; } mrb_irep; #define MRB_ISEQ_NO_FREE 1 -- cgit v1.2.3 From 5addd5db4a59450427abae2e9925c529fd6868a1 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Thu, 30 Aug 2018 01:20:59 +0900 Subject: Need to clear `mrb->c->cibase->ridx` (toplevel ridx) at L_STOP; fix #4092 This problem only appears when `mrb` executed multiple times (i.e. `mirb`) --- src/vm.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/vm.c b/src/vm.c index c8088d22e..98e554607 100644 --- a/src/vm.c +++ b/src/vm.c @@ -2954,6 +2954,7 @@ RETRY_TRY_BLOCK: while (mrb->c->eidx > 0) { ecall(mrb); } + mrb->c->cibase->ridx = 0; ERR_PC_CLR(mrb); mrb->jmp = prev_jmp; if (mrb->exc) { -- cgit v1.2.3 From 75a01af710309e4fc53db285c9018e233c61cb56 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Thu, 30 Aug 2018 01:23:17 +0900 Subject: Remove consequent `OP_RETURN` by peephole optimization. --- mrbgems/mruby-compiler/core/codegen.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mrbgems/mruby-compiler/core/codegen.c b/mrbgems/mruby-compiler/core/codegen.c index 0d47b236d..835cee817 100644 --- a/mrbgems/mruby-compiler/core/codegen.c +++ b/mrbgems/mruby-compiler/core/codegen.c @@ -461,7 +461,7 @@ gen_return(codegen_scope *s, uint8_t op, uint16_t src) s->pc = s->lastpc; genop_1(s, op, data.b); } - else { + else if (data.insn != OP_RETURN) { genop_1(s, op, src); } } -- cgit v1.2.3 From e471d37ca5f1422860a1eaa81d4c9f1b3c8b6aed Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Thu, 30 Aug 2018 16:07:59 +0900 Subject: Separate meta-programming features to `mruby-metaprog` gem. We assume meta-programming is less used in embedded environments. We have moved following methods: * Kernel module global_variables, local_variables, singleton_class, instance_variables, instance_variables_defined?, instance_variable_get, instance_variable_set, methods, private_methods, public_methods, protected_methods, singleton_methods, define_singleton_methods * Module class class_variables, class_variables_defined?, class_variable_get, class_variable_set, remove_class_variable, included_modules, instance_methods, remove_method, method_removed, constants * Module class methods constants, nesting Note: Following meta-programming methods are kept in the core: * Module class alias_method, undef_method, ancestors, const_defined?, const_get, const_set, remove_const, method_defined?, define_method * Toplevel object define_method `mruby-metaprog` gem is linked by default (specified in default.gembox). When it is removed, it will save 40KB (stripped:8KB) on x86-64 environment last time I measured. --- mrbgems/default.gembox | 3 + mrbgems/mruby-bin-strip/bintest/mruby-strip.rb | 6 +- mrbgems/mruby-class-ext/test/module.rb | 2 +- mrbgems/mruby-eval/test/eval.rb | 2 +- mrbgems/mruby-io/test/io.rb | 2 +- mrbgems/mruby-metaprog/mrbgem.rake | 5 + mrbgems/mruby-metaprog/src/metaprog.c | 701 +++++++++++++++++++++++++ mrbgems/mruby-metaprog/test/metaprog.rb | 303 +++++++++++ mrbgems/mruby-method/mrblib/kernel.rb | 5 +- mrbgems/mruby-method/test/method.rb | 12 +- mrbgems/mruby-toplevel-ext/test/toplevel.rb | 4 +- src/class.c | 446 +++------------- src/etc.c | 1 + src/kernel.c | 401 +------------- test/t/class.rb | 25 +- test/t/codegen.rb | 2 +- test/t/kernel.rb | 91 +--- test/t/module.rb | 258 ++------- 18 files changed, 1149 insertions(+), 1120 deletions(-) create mode 100644 mrbgems/mruby-metaprog/mrbgem.rake create mode 100644 mrbgems/mruby-metaprog/src/metaprog.c create mode 100644 mrbgems/mruby-metaprog/test/metaprog.rb diff --git a/mrbgems/default.gembox b/mrbgems/default.gembox index 7ddbb16d1..23e65fcee 100644 --- a/mrbgems/default.gembox +++ b/mrbgems/default.gembox @@ -1,4 +1,7 @@ MRuby::GemBox.new do |conf| + # Meta-programming features + conf.gem :core => "mruby-metaprog" + # Use standard IO/File class conf.gem :core => "mruby-io" diff --git a/mrbgems/mruby-bin-strip/bintest/mruby-strip.rb b/mrbgems/mruby-bin-strip/bintest/mruby-strip.rb index bb664a2b1..2db3c10b1 100644 --- a/mrbgems/mruby-bin-strip/bintest/mruby-strip.rb +++ b/mrbgems/mruby-bin-strip/bintest/mruby-strip.rb @@ -67,7 +67,7 @@ EOS `#{cmd('mruby-strip')} -l #{without_lv.path}` assert_true without_lv.size < with_lv.size - - assert_equal '[:a, :b]', `#{cmd('mruby')} -b #{with_lv.path}`.chomp - assert_equal '[]', `#{cmd('mruby')} -b #{without_lv.path}`.chomp +# +# assert_equal '[:a, :b]', `#{cmd('mruby')} -b #{with_lv.path}`.chomp +# assert_equal '[]', `#{cmd('mruby')} -b #{without_lv.path}`.chomp end diff --git a/mrbgems/mruby-class-ext/test/module.rb b/mrbgems/mruby-class-ext/test/module.rb index ed6713aac..71a8da451 100644 --- a/mrbgems/mruby-class-ext/test/module.rb +++ b/mrbgems/mruby-class-ext/test/module.rb @@ -26,7 +26,7 @@ end assert 'Module#singleton_class?' do mod = Module.new cls = Class.new - scl = cls.singleton_class + scl = (class < true or false + * + * Returns true if the given instance variable is + * defined in obj. + * + * class Fred + * def initialize(p1, p2) + * @a, @b = p1, p2 + * end + * end + * fred = Fred.new('cat', 99) + * fred.instance_variable_defined?(:@a) #=> true + * fred.instance_variable_defined?("@b") #=> true + * fred.instance_variable_defined?("@c") #=> false + */ +static mrb_value +mrb_obj_ivar_defined(mrb_state *mrb, mrb_value self) +{ + mrb_sym sym; + + mrb_get_args(mrb, "n", &sym); + mrb_iv_name_sym_check(mrb, sym); + return mrb_bool_value(mrb_iv_defined(mrb, self, sym)); +} + +/* 15.3.1.3.21 */ +/* + * call-seq: + * obj.instance_variable_get(symbol) -> obj + * + * Returns the value of the given instance variable, or nil if the + * instance variable is not set. The @ part of the + * variable name should be included for regular instance + * variables. Throws a NameError exception if the + * supplied symbol is not valid as an instance variable name. + * + * class Fred + * def initialize(p1, p2) + * @a, @b = p1, p2 + * end + * end + * fred = Fred.new('cat', 99) + * fred.instance_variable_get(:@a) #=> "cat" + * fred.instance_variable_get("@b") #=> 99 + */ +static mrb_value +mrb_obj_ivar_get(mrb_state *mrb, mrb_value self) +{ + mrb_sym iv_name; + + mrb_get_args(mrb, "n", &iv_name); + mrb_iv_name_sym_check(mrb, iv_name); + return mrb_iv_get(mrb, self, iv_name); +} + +/* 15.3.1.3.22 */ +/* + * call-seq: + * obj.instance_variable_set(symbol, obj) -> obj + * + * Sets the instance variable names by symbol to + * object, thereby frustrating the efforts of the class's + * author to attempt to provide proper encapsulation. The variable + * did not have to exist prior to this call. + * + * class Fred + * def initialize(p1, p2) + * @a, @b = p1, p2 + * end + * end + * fred = Fred.new('cat', 99) + * fred.instance_variable_set(:@a, 'dog') #=> "dog" + * fred.instance_variable_set(:@c, 'cat') #=> "cat" + * fred.inspect #=> "#" + */ +static mrb_value +mrb_obj_ivar_set(mrb_state *mrb, mrb_value self) +{ + mrb_sym iv_name; + mrb_value val; + + mrb_get_args(mrb, "no", &iv_name, &val); + mrb_iv_name_sym_check(mrb, iv_name); + mrb_iv_set(mrb, self, iv_name, val); + return val; +} + +/* 15.3.1.2.7 */ +/* + * call-seq: + * local_variables -> array + * + * Returns the names of local variables in the current scope. + * + * [mruby limitation] + * If variable symbol information was stripped out from + * compiled binary files using `mruby-strip -l`, this + * method always returns an empty array. + */ +static mrb_value +mrb_local_variables(mrb_state *mrb, mrb_value self) +{ + struct RProc *proc; + mrb_irep *irep; + mrb_value vars; + size_t i; + + proc = mrb->c->ci[-1].proc; + + if (MRB_PROC_CFUNC_P(proc)) { + return mrb_ary_new(mrb); + } + vars = mrb_hash_new(mrb); + while (proc) { + if (MRB_PROC_CFUNC_P(proc)) break; + irep = proc->body.irep; + if (!irep->lv) break; + for (i = 0; i + 1 < irep->nlocals; ++i) { + if (irep->lv[i].name) { + mrb_sym sym = irep->lv[i].name; + const char *name = mrb_sym2name(mrb, sym); + switch (name[0]) { + case '*': case '&': + break; + default: + mrb_hash_set(mrb, vars, mrb_symbol_value(sym), mrb_true_value()); + break; + } + } + } + if (!MRB_PROC_ENV_P(proc)) break; + proc = proc->upper; + //if (MRB_PROC_SCOPE_P(proc)) break; + if (!proc->c) break; + } + + return mrb_hash_keys(mrb, vars); +} + +KHASH_DECLARE(st, mrb_sym, char, FALSE) + +static void +method_entry_loop(mrb_state *mrb, struct RClass* klass, khash_t(st)* set) +{ + khint_t i; + + khash_t(mt) *h = klass->mt; + if (!h || kh_size(h) == 0) return; + for (i=0;iflags & MRB_FL_CLASS_IS_PREPENDED)) { + MRB_CLASS_ORIGIN(klass); + prepended = TRUE; + } + + oldklass = 0; + while (klass && (klass != oldklass)) { + method_entry_loop(mrb, klass, set); + if ((klass->tt == MRB_TT_ICLASS && !prepended) || + (klass->tt == MRB_TT_SCLASS)) { + } + else { + if (!recur) break; + } + oldklass = klass; + klass = klass->super; + } + + ary = mrb_ary_new_capa(mrb, kh_size(set)); + for (i=0;i array + * + * Returns a list of the names of methods publicly accessible in + * obj. This will include all the methods accessible in + * obj's ancestors. + * + * class Klass + * def kMethod() + * end + * end + * k = Klass.new + * k.methods[0..9] #=> [:kMethod, :respond_to?, :nil?, :is_a?, + * # :class, :instance_variable_set, + * # :methods, :extend, :__send__, :instance_eval] + * k.methods.length #=> 42 + */ +static mrb_value +mrb_obj_methods_m(mrb_state *mrb, mrb_value self) +{ + mrb_bool recur = TRUE; + mrb_get_args(mrb, "|b", &recur); + return mrb_obj_methods(mrb, recur, self, (mrb_method_flag_t)0); /* everything but private */ +} + +/* 15.3.1.3.36 */ +/* + * call-seq: + * obj.private_methods(all=true) -> array + * + * Returns the list of private methods accessible to obj. If + * the all parameter is set to false, only those methods + * in the receiver will be listed. + */ +static mrb_value +mrb_obj_private_methods(mrb_state *mrb, mrb_value self) +{ + mrb_bool recur = TRUE; + mrb_get_args(mrb, "|b", &recur); + return mrb_obj_methods(mrb, recur, self, NOEX_PRIVATE); /* private attribute not define */ +} + +/* 15.3.1.3.37 */ +/* + * call-seq: + * obj.protected_methods(all=true) -> array + * + * Returns the list of protected methods accessible to obj. If + * the all parameter is set to false, only those methods + * in the receiver will be listed. + */ +static mrb_value +mrb_obj_protected_methods(mrb_state *mrb, mrb_value self) +{ + mrb_bool recur = TRUE; + mrb_get_args(mrb, "|b", &recur); + return mrb_obj_methods(mrb, recur, self, NOEX_PROTECTED); /* protected attribute not define */ +} + +/* 15.3.1.3.38 */ +/* + * call-seq: + * obj.public_methods(all=true) -> array + * + * Returns the list of public methods accessible to obj. If + * the all parameter is set to false, only those methods + * in the receiver will be listed. + */ +static mrb_value +mrb_obj_public_methods(mrb_state *mrb, mrb_value self) +{ + mrb_bool recur = TRUE; + mrb_get_args(mrb, "|b", &recur); + return mrb_obj_methods(mrb, recur, self, NOEX_PUBLIC); /* public attribute not define */ +} + +static mrb_value +mrb_obj_singleton_methods(mrb_state *mrb, mrb_bool recur, mrb_value obj) +{ + khint_t i; + mrb_value ary; + struct RClass* klass; + khash_t(st)* set = kh_init(st, mrb); + + klass = mrb_class(mrb, obj); + + if (klass && (klass->tt == MRB_TT_SCLASS)) { + method_entry_loop(mrb, klass, set); + klass = klass->super; + } + if (recur) { + while (klass && ((klass->tt == MRB_TT_SCLASS) || (klass->tt == MRB_TT_ICLASS))) { + method_entry_loop(mrb, klass, set); + klass = klass->super; + } + } + + ary = mrb_ary_new(mrb); + for (i=0;i array + * + * Returns an array of the names of singleton methods for obj. + * If the optional all parameter is true, the list will include + * methods in modules included in obj. + * Only public and protected singleton methods are returned. + * + * module Other + * def three() end + * end + * + * class Single + * def Single.four() end + * end + * + * a = Single.new + * + * def a.one() + * end + * + * class << a + * include Other + * def two() + * end + * end + * + * Single.singleton_methods #=> [:four] + * a.singleton_methods(false) #=> [:two, :one] + * a.singleton_methods #=> [:two, :one, :three] + */ +static mrb_value +mrb_obj_singleton_methods_m(mrb_state *mrb, mrb_value self) +{ + mrb_bool recur = TRUE; + mrb_get_args(mrb, "|b", &recur); + return mrb_obj_singleton_methods(mrb, recur, self); +} + +static mrb_value +mod_define_singleton_method(mrb_state *mrb, mrb_value self) +{ + struct RProc *p; + mrb_method_t m; + mrb_sym mid; + mrb_value blk = mrb_nil_value(); + + mrb_get_args(mrb, "n&", &mid, &blk); + if (mrb_nil_p(blk)) { + mrb_raise(mrb, E_ARGUMENT_ERROR, "no block given"); + } + p = (struct RProc*)mrb_obj_alloc(mrb, MRB_TT_PROC, mrb->proc_class); + mrb_proc_copy(p, mrb_proc_ptr(blk)); + p->flags |= MRB_PROC_STRICT; + MRB_METHOD_FROM_PROC(m, p); + mrb_define_method_raw(mrb, mrb_class_ptr(mrb_singleton_class(mrb, self)), mid, m); + return mrb_symbol_value(mid); +} + +static void +check_cv_name_str(mrb_state *mrb, mrb_value str) +{ + const char *s = RSTRING_PTR(str); + mrb_int len = RSTRING_LEN(str); + + if (len < 3 || !(s[0] == '@' && s[1] == '@')) { + mrb_name_error(mrb, mrb_intern_str(mrb, str), "'%S' is not allowed as a class variable name", str); + } +} + +static void +check_cv_name_sym(mrb_state *mrb, mrb_sym id) +{ + check_cv_name_str(mrb, mrb_sym2str(mrb, id)); +} + +/* 15.2.2.4.39 */ +/* + * call-seq: + * remove_class_variable(sym) -> obj + * + * Removes the definition of the sym, returning that + * constant's value. + * + * class Dummy + * @@var = 99 + * puts @@var + * p class_variables + * remove_class_variable(:@@var) + * p class_variables + * end + * + * produces: + * + * 99 + * [:@@var] + * [] + */ + +static mrb_value +mrb_mod_remove_cvar(mrb_state *mrb, mrb_value mod) +{ + mrb_value val; + mrb_sym id; + + mrb_get_args(mrb, "n", &id); + check_cv_name_sym(mrb, id); + + val = mrb_iv_remove(mrb, mod, id); + if (!mrb_undef_p(val)) return val; + + if (mrb_cv_defined(mrb, mod, id)) { + mrb_name_error(mrb, id, "cannot remove %S for %S", + mrb_sym2str(mrb, id), mod); + } + + mrb_name_error(mrb, id, "class variable %S not defined for %S", + mrb_sym2str(mrb, id), mod); + + /* not reached */ + return mrb_nil_value(); +} + +/* 15.2.2.4.16 */ +/* + * call-seq: + * obj.class_variable_defined?(symbol) -> true or false + * + * Returns true if the given class variable is defined + * in obj. + * + * class Fred + * @@foo = 99 + * end + * Fred.class_variable_defined?(:@@foo) #=> true + * Fred.class_variable_defined?(:@@bar) #=> false + */ + +static mrb_value +mrb_mod_cvar_defined(mrb_state *mrb, mrb_value mod) +{ + mrb_sym id; + + mrb_get_args(mrb, "n", &id); + check_cv_name_sym(mrb, id); + return mrb_bool_value(mrb_cv_defined(mrb, mod, id)); +} + +/* 15.2.2.4.17 */ +/* + * call-seq: + * mod.class_variable_get(symbol) -> obj + * + * Returns the value of the given class variable (or throws a + * NameError exception). The @@ part of the + * variable name should be included for regular class variables + * + * class Fred + * @@foo = 99 + * end + * Fred.class_variable_get(:@@foo) #=> 99 + */ + +static mrb_value +mrb_mod_cvar_get(mrb_state *mrb, mrb_value mod) +{ + mrb_sym id; + + mrb_get_args(mrb, "n", &id); + check_cv_name_sym(mrb, id); + return mrb_cv_get(mrb, mod, id); +} + +/* 15.2.2.4.18 */ +/* + * call-seq: + * obj.class_variable_set(symbol, obj) -> obj + * + * Sets the class variable names by symbol to + * object. + * + * class Fred + * @@foo = 99 + * def foo + * @@foo + * end + * end + * Fred.class_variable_set(:@@foo, 101) #=> 101 + * Fred.new.foo #=> 101 + */ + +static mrb_value +mrb_mod_cvar_set(mrb_state *mrb, mrb_value mod) +{ + mrb_value value; + mrb_sym id; + + mrb_get_args(mrb, "no", &id, &value); + check_cv_name_sym(mrb, id); + mrb_cv_set(mrb, mod, id, value); + return value; +} + +static mrb_value +mrb_mod_included_modules(mrb_state *mrb, mrb_value self) +{ + mrb_value result; + struct RClass *c = mrb_class_ptr(self); + struct RClass *origin = c; + + MRB_CLASS_ORIGIN(origin); + result = mrb_ary_new(mrb); + while (c) { + if (c != origin && c->tt == MRB_TT_ICLASS) { + if (c->c->tt == MRB_TT_MODULE) { + mrb_ary_push(mrb, result, mrb_obj_value(c->c)); + } + } + c = c->super; + } + + return result; +} + +mrb_value mrb_class_instance_method_list(mrb_state*, mrb_bool, struct RClass*, int); + +/* 15.2.2.4.33 */ +/* + * call-seq: + * mod.instance_methods(include_super=true) -> array + * + * Returns an array containing the names of the public and protected instance + * methods in the receiver. For a module, these are the public and protected methods; + * for a class, they are the instance (not singleton) methods. With no + * argument, or with an argument that is false, the + * instance methods in mod are returned, otherwise the methods + * in mod and mod's superclasses are returned. + * + * module A + * def method1() end + * end + * class B + * def method2() end + * end + * class C < B + * def method3() end + * end + * + * A.instance_methods #=> [:method1] + * B.instance_methods(false) #=> [:method2] + * C.instance_methods(false) #=> [:method3] + * C.instance_methods(true).length #=> 43 + */ + +static mrb_value +mrb_mod_instance_methods(mrb_state *mrb, mrb_value mod) +{ + struct RClass *c = mrb_class_ptr(mod); + mrb_bool recur = TRUE; + mrb_get_args(mrb, "|b", &recur); + return mrb_class_instance_method_list(mrb, recur, c, 0); +} + +static void +remove_method(mrb_state *mrb, mrb_value mod, mrb_sym mid) +{ + struct RClass *c = mrb_class_ptr(mod); + khash_t(mt) *h; + khiter_t k; + + MRB_CLASS_ORIGIN(c); + h = c->mt; + + if (h) { + k = kh_get(mt, mrb, h, mid); + if (k != kh_end(h)) { + kh_del(mt, mrb, h, k); + mrb_funcall(mrb, mod, "method_removed", 1, mrb_symbol_value(mid)); + return; + } + } + + mrb_name_error(mrb, mid, "method '%S' not defined in %S", + mrb_sym2str(mrb, mid), mod); +} + +/* 15.2.2.4.41 */ +/* + * call-seq: + * remove_method(symbol) -> self + * + * Removes the method identified by _symbol_ from the current + * class. For an example, see Module.undef_method. + */ + +static mrb_value +mrb_mod_remove_method(mrb_state *mrb, mrb_value mod) +{ + mrb_int argc; + mrb_value *argv; + + mrb_get_args(mrb, "*", &argv, &argc); + while (argc--) { + remove_method(mrb, mod, mrb_obj_to_sym(mrb, *argv)); + argv++; + } + return mod; +} + +static mrb_value +mrb_mod_s_constants(mrb_state *mrb, mrb_value mod) +{ + mrb_raise(mrb, E_NOTIMP_ERROR, "Module.constants not implemented"); + return mrb_nil_value(); /* not reached */ +} + +/* implementation of Module.nesting */ +mrb_value mrb_mod_s_nesting(mrb_state*, mrb_value); + +void +mrb_mruby_metaprog_gem_init(mrb_state* mrb) +{ + struct RClass *krn = mrb->kernel_module; + struct RClass *mod = mrb->module_class; + + mrb_define_method(mrb, krn, "global_variables", mrb_f_global_variables, MRB_ARGS_NONE()); /* 15.3.1.2.4 */ + mrb_define_method(mrb, krn, "local_variables", mrb_local_variables, MRB_ARGS_NONE()); /* 15.3.1.3.28 */ + + mrb_define_method(mrb, krn, "singleton_class", mrb_singleton_class, MRB_ARGS_NONE()); + mrb_define_method(mrb, krn, "instance_variable_defined?", mrb_obj_ivar_defined, MRB_ARGS_REQ(1)); /* 15.3.1.3.20 */ + mrb_define_method(mrb, krn, "instance_variable_get", mrb_obj_ivar_get, MRB_ARGS_REQ(1)); /* 15.3.1.3.21 */ + mrb_define_method(mrb, krn, "instance_variable_set", mrb_obj_ivar_set, MRB_ARGS_REQ(2)); /* 15.3.1.3.22 */ + mrb_define_method(mrb, krn, "instance_variables", mrb_obj_instance_variables, MRB_ARGS_NONE()); /* 15.3.1.3.23 */ + mrb_define_method(mrb, krn, "methods", mrb_obj_methods_m, MRB_ARGS_OPT(1)); /* 15.3.1.3.31 */ + mrb_define_method(mrb, krn, "private_methods", mrb_obj_private_methods, MRB_ARGS_OPT(1)); /* 15.3.1.3.36 */ + mrb_define_method(mrb, krn, "protected_methods", mrb_obj_protected_methods, MRB_ARGS_OPT(1)); /* 15.3.1.3.37 */ + mrb_define_method(mrb, krn, "public_methods", mrb_obj_public_methods, MRB_ARGS_OPT(1)); /* 15.3.1.3.38 */ + mrb_define_method(mrb, krn, "singleton_methods", mrb_obj_singleton_methods_m, MRB_ARGS_OPT(1)); /* 15.3.1.3.45 */ + mrb_define_method(mrb, krn, "define_singleton_method", mod_define_singleton_method, MRB_ARGS_ANY()); + + mrb_define_method(mrb, mod, "class_variables", mrb_mod_class_variables, MRB_ARGS_NONE()); /* 15.2.2.4.19 */ + mrb_define_method(mrb, mod, "remove_class_variable", mrb_mod_remove_cvar, MRB_ARGS_REQ(1)); /* 15.2.2.4.39 */ + mrb_define_method(mrb, mod, "class_variable_defined?", mrb_mod_cvar_defined, MRB_ARGS_REQ(1)); /* 15.2.2.4.16 */ + mrb_define_method(mrb, mod, "class_variable_get", mrb_mod_cvar_get, MRB_ARGS_REQ(1)); /* 15.2.2.4.17 */ + mrb_define_method(mrb, mod, "class_variable_set", mrb_mod_cvar_set, MRB_ARGS_REQ(2)); /* 15.2.2.4.18 */ + mrb_define_method(mrb, mod, "included_modules", mrb_mod_included_modules, MRB_ARGS_NONE()); /* 15.2.2.4.30 */ + mrb_define_method(mrb, mod, "instance_methods", mrb_mod_instance_methods, MRB_ARGS_ANY()); /* 15.2.2.4.33 */ + mrb_define_method(mrb, mod, "remove_method", mrb_mod_remove_method, MRB_ARGS_ANY()); /* 15.2.2.4.41 */ + mrb_define_method(mrb, mod, "method_removed", mrb_f_nil, MRB_ARGS_REQ(1)); + mrb_define_method(mrb, mod, "constants", mrb_mod_constants, MRB_ARGS_OPT(1)); /* 15.2.2.4.24 */ + mrb_define_class_method(mrb, mod, "constants", mrb_mod_s_constants, MRB_ARGS_ANY()); /* 15.2.2.3.1 */ + mrb_define_class_method(mrb, mod, "nesting", mrb_mod_s_nesting, MRB_ARGS_REQ(0)); /* 15.2.2.3.2 */ +} + +void +mrb_mruby_metaprog_gem_final(mrb_state* mrb) +{ +} diff --git a/mrbgems/mruby-metaprog/test/metaprog.rb b/mrbgems/mruby-metaprog/test/metaprog.rb new file mode 100644 index 000000000..587d00d6f --- /dev/null +++ b/mrbgems/mruby-metaprog/test/metaprog.rb @@ -0,0 +1,303 @@ + +assert('Kernel#instance_variable_defined?', '15.3.1.3.20') do + o = Object.new + o.instance_variable_set(:@a, 1) + + assert_true o.instance_variable_defined?("@a") + assert_false o.instance_variable_defined?("@b") + assert_true o.instance_variable_defined?("@a"[0,2]) + assert_true o.instance_variable_defined?("@abc"[0,2]) +end + +assert('Kernel#instance_variables', '15.3.1.3.23') do + o = Object.new + o.instance_eval do + @a = 11 + @b = 12 + end + ivars = o.instance_variables + + assert_equal Array, ivars.class, + assert_equal(2, ivars.size) + assert_true ivars.include?(:@a) + assert_true ivars.include?(:@b) +end + +assert('Kernel#methods', '15.3.1.3.31') do + assert_equal Array, methods.class +end + +assert('Kernel#private_methods', '15.3.1.3.36') do + assert_equal Array, private_methods.class +end + +assert('Kernel#protected_methods', '15.3.1.3.37') do + assert_equal Array, protected_methods.class +end + +assert('Kernel#public_methods', '15.3.1.3.38') do + assert_equal Array, public_methods.class + class Foo + def foo + end + end + assert_equal [:foo], Foo.new.public_methods(false) +end + +assert('Kernel#singleton_methods', '15.3.1.3.45') do + assert_equal singleton_methods.class, Array +end + +assert('Kernel.local_variables', '15.3.1.2.7') do + a, b = 0, 1 + a += b + + vars = Kernel.local_variables.sort + assert_equal [:a, :b, :vars], vars + + assert_equal [:a, :b, :c, :vars], Proc.new { |a, b| + c = 2 + # Kernel#local_variables: 15.3.1.3.28 + local_variables.sort + }.call(-1, -2) +end + +assert('Kernel#define_singleton_method') do + o = Object.new + ret = o.define_singleton_method(:test_method) do + :singleton_method_ok + end + assert_equal :test_method, ret + assert_equal :singleton_method_ok, o.test_method +end + +def labeled_module(name, &block) + Module.new do + (class <tt == MRB_TT_ICLASS) { - if (c->c->tt == MRB_TT_MODULE) { - mrb_ary_push(mrb, result, mrb_obj_value(c->c)); - } - } - c = c->super; - } - - return result; -} - static mrb_value mrb_mod_initialize(mrb_state *mrb, mrb_value mod) { @@ -1250,45 +1214,6 @@ mrb_mod_initialize(mrb_state *mrb, mrb_value mod) return mod; } -mrb_value mrb_class_instance_method_list(mrb_state*, mrb_bool, struct RClass*, int); - -/* 15.2.2.4.33 */ -/* - * call-seq: - * mod.instance_methods(include_super=true) -> array - * - * Returns an array containing the names of the public and protected instance - * methods in the receiver. For a module, these are the public and protected methods; - * for a class, they are the instance (not singleton) methods. With no - * argument, or with an argument that is false, the - * instance methods in mod are returned, otherwise the methods - * in mod and mod's superclasses are returned. - * - * module A - * def method1() end - * end - * class B - * def method2() end - * end - * class C < B - * def method3() end - * end - * - * A.instance_methods #=> [:method1] - * B.instance_methods(false) #=> [:method2] - * C.instance_methods(false) #=> [:method3] - * C.instance_methods(true).length #=> 43 - */ - -static mrb_value -mrb_mod_instance_methods(mrb_state *mrb, mrb_value mod) -{ - struct RClass *c = mrb_class_ptr(mod); - mrb_bool recur = TRUE; - mrb_get_args(mrb, "|b", &recur); - return mrb_class_instance_method_list(mrb, recur, c, 0); -} - /* implementation of module_eval/class_eval */ mrb_value mrb_mod_module_eval(mrb_state*, mrb_value); @@ -1994,270 +1919,6 @@ mrb_mod_undef(mrb_state *mrb, mrb_value mod) return mrb_nil_value(); } -static mrb_value -mod_define_method(mrb_state *mrb, mrb_value self) -{ - struct RClass *c = mrb_class_ptr(self); - struct RProc *p; - mrb_method_t m; - mrb_sym mid; - mrb_value proc = mrb_undef_value(); - mrb_value blk; - - mrb_get_args(mrb, "n|o&", &mid, &proc, &blk); - switch (mrb_type(proc)) { - case MRB_TT_PROC: - blk = proc; - break; - case MRB_TT_UNDEF: - /* ignored */ - break; - default: - mrb_raisef(mrb, E_TYPE_ERROR, "wrong argument type %S (expected Proc)", mrb_obj_value(mrb_obj_class(mrb, proc))); - break; - } - if (mrb_nil_p(blk)) { - mrb_raise(mrb, E_ARGUMENT_ERROR, "no block given"); - } - p = (struct RProc*)mrb_obj_alloc(mrb, MRB_TT_PROC, mrb->proc_class); - mrb_proc_copy(p, mrb_proc_ptr(blk)); - p->flags |= MRB_PROC_STRICT; - MRB_METHOD_FROM_PROC(m, p); - mrb_define_method_raw(mrb, c, mid, m); - return mrb_symbol_value(mid); -} - -static mrb_value -top_define_method(mrb_state *mrb, mrb_value self) -{ - return mod_define_method(mrb, mrb_obj_value(mrb->object_class)); -} - -static void -check_cv_name_str(mrb_state *mrb, mrb_value str) -{ - const char *s = RSTRING_PTR(str); - mrb_int len = RSTRING_LEN(str); - - if (len < 3 || !(s[0] == '@' && s[1] == '@')) { - mrb_name_error(mrb, mrb_intern_str(mrb, str), "'%S' is not allowed as a class variable name", str); - } -} - -static void -check_cv_name_sym(mrb_state *mrb, mrb_sym id) -{ - check_cv_name_str(mrb, mrb_sym2str(mrb, id)); -} - -/* 15.2.2.4.16 */ -/* - * call-seq: - * obj.class_variable_defined?(symbol) -> true or false - * - * Returns true if the given class variable is defined - * in obj. - * - * class Fred - * @@foo = 99 - * end - * Fred.class_variable_defined?(:@@foo) #=> true - * Fred.class_variable_defined?(:@@bar) #=> false - */ - -static mrb_value -mrb_mod_cvar_defined(mrb_state *mrb, mrb_value mod) -{ - mrb_sym id; - - mrb_get_args(mrb, "n", &id); - check_cv_name_sym(mrb, id); - return mrb_bool_value(mrb_cv_defined(mrb, mod, id)); -} - -/* 15.2.2.4.17 */ -/* - * call-seq: - * mod.class_variable_get(symbol) -> obj - * - * Returns the value of the given class variable (or throws a - * NameError exception). The @@ part of the - * variable name should be included for regular class variables - * - * class Fred - * @@foo = 99 - * end - * Fred.class_variable_get(:@@foo) #=> 99 - */ - -static mrb_value -mrb_mod_cvar_get(mrb_state *mrb, mrb_value mod) -{ - mrb_sym id; - - mrb_get_args(mrb, "n", &id); - check_cv_name_sym(mrb, id); - return mrb_cv_get(mrb, mod, id); -} - -/* 15.2.2.4.18 */ -/* - * call-seq: - * obj.class_variable_set(symbol, obj) -> obj - * - * Sets the class variable names by symbol to - * object. - * - * class Fred - * @@foo = 99 - * def foo - * @@foo - * end - * end - * Fred.class_variable_set(:@@foo, 101) #=> 101 - * Fred.new.foo #=> 101 - */ - -static mrb_value -mrb_mod_cvar_set(mrb_state *mrb, mrb_value mod) -{ - mrb_value value; - mrb_sym id; - - mrb_get_args(mrb, "no", &id, &value); - check_cv_name_sym(mrb, id); - mrb_cv_set(mrb, mod, id, value); - return value; -} - -/* 15.2.2.4.39 */ -/* - * call-seq: - * remove_class_variable(sym) -> obj - * - * Removes the definition of the sym, returning that - * constant's value. - * - * class Dummy - * @@var = 99 - * puts @@var - * p class_variables - * remove_class_variable(:@@var) - * p class_variables - * end - * - * produces: - * - * 99 - * [:@@var] - * [] - */ - -static mrb_value -mrb_mod_remove_cvar(mrb_state *mrb, mrb_value mod) -{ - mrb_value val; - mrb_sym id; - - mrb_get_args(mrb, "n", &id); - check_cv_name_sym(mrb, id); - - val = mrb_iv_remove(mrb, mod, id); - if (!mrb_undef_p(val)) return val; - - if (mrb_cv_defined(mrb, mod, id)) { - mrb_name_error(mrb, id, "cannot remove %S for %S", - mrb_sym2str(mrb, id), mod); - } - - mrb_name_error(mrb, id, "class variable %S not defined for %S", - mrb_sym2str(mrb, id), mod); - - /* not reached */ - return mrb_nil_value(); -} - -/* 15.2.2.4.34 */ -/* - * call-seq: - * mod.method_defined?(symbol) -> true or false - * - * Returns +true+ if the named method is defined by - * _mod_ (or its included modules and, if _mod_ is a class, - * its ancestors). Public and protected methods are matched. - * - * module A - * def method1() end - * end - * class B - * def method2() end - * end - * class C < B - * include A - * def method3() end - * end - * - * A.method_defined? :method1 #=> true - * C.method_defined? "method1" #=> true - * C.method_defined? "method2" #=> true - * C.method_defined? "method3" #=> true - * C.method_defined? "method4" #=> false - */ - -static mrb_value -mrb_mod_method_defined(mrb_state *mrb, mrb_value mod) -{ - mrb_sym id; - - mrb_get_args(mrb, "n", &id); - return mrb_bool_value(mrb_obj_respond_to(mrb, mrb_class_ptr(mod), id)); -} - -static void -remove_method(mrb_state *mrb, mrb_value mod, mrb_sym mid) -{ - struct RClass *c = mrb_class_ptr(mod); - khash_t(mt) *h = find_origin(c)->mt; - khiter_t k; - - if (h) { - k = kh_get(mt, mrb, h, mid); - if (k != kh_end(h)) { - kh_del(mt, mrb, h, k); - mrb_funcall(mrb, mod, "method_removed", 1, mrb_symbol_value(mid)); - return; - } - } - - mrb_name_error(mrb, mid, "method '%S' not defined in %S", - mrb_sym2str(mrb, mid), mod); -} - -/* 15.2.2.4.41 */ -/* - * call-seq: - * remove_method(symbol) -> self - * - * Removes the method identified by _symbol_ from the current - * class. For an example, see Module.undef_method. - */ - -static mrb_value -mrb_mod_remove_method(mrb_state *mrb, mrb_value mod) -{ - mrb_int argc; - mrb_value *argv; - - mrb_get_args(mrb, "*", &argv, &argc); - while (argc--) { - remove_method(mrb, mod, to_sym(mrb, *argv)); - argv++; - } - return mod; -} - - - static void check_const_name_str(mrb_state *mrb, mrb_value str) { @@ -2272,15 +1933,6 @@ check_const_name_sym(mrb_state *mrb, mrb_sym id) check_const_name_str(mrb, mrb_sym2str(mrb, id)); } -static mrb_value -const_defined(mrb_state *mrb, mrb_value mod, mrb_sym id, mrb_bool inherit) -{ - if (inherit) { - return mrb_bool_value(mrb_const_defined(mrb, mod, id)); - } - return mrb_bool_value(mrb_const_defined_at(mrb, mod, id)); -} - static mrb_value mrb_mod_const_defined(mrb_state *mrb, mrb_value mod) { @@ -2289,7 +1941,10 @@ mrb_mod_const_defined(mrb_state *mrb, mrb_value mod) mrb_get_args(mrb, "n|b", &id, &inherit); check_const_name_sym(mrb, id); - return const_defined(mrb, mod, id, inherit); + if (inherit) { + return mrb_bool_value(mrb_const_defined(mrb, mod, id)); + } + return mrb_bool_value(mrb_const_defined_at(mrb, mod, id)); } static mrb_value @@ -2379,11 +2034,79 @@ mrb_mod_const_missing(mrb_state *mrb, mrb_value mod) return mrb_nil_value(); } +/* 15.2.2.4.34 */ +/* + * call-seq: + * mod.method_defined?(symbol) -> true or false + * + * Returns +true+ if the named method is defined by + * _mod_ (or its included modules and, if _mod_ is a class, + * its ancestors). Public and protected methods are matched. + * + * module A + * def method1() end + * end + * class B + * def method2() end + * end + * class C < B + * include A + * def method3() end + * end + * + * A.method_defined? :method1 #=> true + * C.method_defined? "method1" #=> true + * C.method_defined? "method2" #=> true + * C.method_defined? "method3" #=> true + * C.method_defined? "method4" #=> false + */ + static mrb_value -mrb_mod_s_constants(mrb_state *mrb, mrb_value mod) +mrb_mod_method_defined(mrb_state *mrb, mrb_value mod) { - mrb_raise(mrb, E_NOTIMP_ERROR, "Module.constants not implemented"); - return mrb_nil_value(); /* not reached */ + mrb_sym id; + + mrb_get_args(mrb, "n", &id); + return mrb_bool_value(mrb_obj_respond_to(mrb, mrb_class_ptr(mod), id)); +} + +static mrb_value +mod_define_method(mrb_state *mrb, mrb_value self) +{ + struct RClass *c = mrb_class_ptr(self); + struct RProc *p; + mrb_method_t m; + mrb_sym mid; + mrb_value proc = mrb_undef_value(); + mrb_value blk; + + mrb_get_args(mrb, "n|o&", &mid, &proc, &blk); + switch (mrb_type(proc)) { + case MRB_TT_PROC: + blk = proc; + break; + case MRB_TT_UNDEF: + /* ignored */ + break; + default: + mrb_raisef(mrb, E_TYPE_ERROR, "wrong argument type %S (expected Proc)", mrb_obj_value(mrb_obj_class(mrb, proc))); + break; + } + if (mrb_nil_p(blk)) { + mrb_raise(mrb, E_ARGUMENT_ERROR, "no block given"); + } + p = (struct RProc*)mrb_obj_alloc(mrb, MRB_TT_PROC, mrb->proc_class); + mrb_proc_copy(p, mrb_proc_ptr(blk)); + p->flags |= MRB_PROC_STRICT; + MRB_METHOD_FROM_PROC(m, p); + mrb_define_method_raw(mrb, c, mid, m); + return mrb_symbol_value(mid); +} + +static mrb_value +top_define_method(mrb_state *mrb, mrb_value self) +{ + return mod_define_method(mrb, mrb_obj_value(mrb->object_class)); } static mrb_value @@ -2439,8 +2162,6 @@ mrb_mod_module_function(mrb_state *mrb, mrb_value mod) mrb_value mrb_obj_id_m(mrb_state *mrb, mrb_value self); /* implementation of instance_eval */ mrb_value mrb_obj_instance_eval(mrb_state*, mrb_value); -/* implementation of Module.nesting */ -mrb_value mrb_mod_s_nesting(mrb_state*, mrb_value); static mrb_value inspect_main(mrb_state *mrb, mrb_value mod) @@ -2500,9 +2221,6 @@ mrb_init_class(mrb_state *mrb) mrb_define_method(mrb, cls, "inherited", mrb_bob_init, MRB_ARGS_REQ(1)); MRB_SET_INSTANCE_TT(mod, MRB_TT_MODULE); - mrb_define_method(mrb, mod, "class_variable_defined?", mrb_mod_cvar_defined, MRB_ARGS_REQ(1)); /* 15.2.2.4.16 */ - mrb_define_method(mrb, mod, "class_variable_get", mrb_mod_cvar_get, MRB_ARGS_REQ(1)); /* 15.2.2.4.17 */ - mrb_define_method(mrb, mod, "class_variable_set", mrb_mod_cvar_set, MRB_ARGS_REQ(2)); /* 15.2.2.4.18 */ mrb_define_method(mrb, mod, "extend_object", mrb_mod_extend_object, MRB_ARGS_REQ(1)); /* 15.2.2.4.25 */ mrb_define_method(mrb, mod, "extended", mrb_bob_init, MRB_ARGS_REQ(1)); /* 15.2.2.4.26 */ mrb_define_method(mrb, mod, "prepended", mrb_bob_init, MRB_ARGS_REQ(1)); @@ -2511,18 +2229,12 @@ mrb_init_class(mrb_state *mrb) mrb_define_method(mrb, mod, "append_features", mrb_mod_append_features, MRB_ARGS_REQ(1)); /* 15.2.2.4.10 */ mrb_define_method(mrb, mod, "class_eval", mrb_mod_module_eval, MRB_ARGS_ANY()); /* 15.2.2.4.15 */ mrb_define_method(mrb, mod, "included", mrb_bob_init, MRB_ARGS_REQ(1)); /* 15.2.2.4.29 */ - mrb_define_method(mrb, mod, "included_modules", mrb_mod_included_modules, MRB_ARGS_NONE()); /* 15.2.2.4.30 */ mrb_define_method(mrb, mod, "initialize", mrb_mod_initialize, MRB_ARGS_NONE()); /* 15.2.2.4.31 */ - mrb_define_method(mrb, mod, "instance_methods", mrb_mod_instance_methods, MRB_ARGS_ANY()); /* 15.2.2.4.33 */ - mrb_define_method(mrb, mod, "method_defined?", mrb_mod_method_defined, MRB_ARGS_REQ(1)); /* 15.2.2.4.34 */ mrb_define_method(mrb, mod, "module_eval", mrb_mod_module_eval, MRB_ARGS_ANY()); /* 15.2.2.4.35 */ mrb_define_method(mrb, mod, "module_function", mrb_mod_module_function, MRB_ARGS_ANY()); mrb_define_method(mrb, mod, "private", mrb_mod_dummy_visibility, MRB_ARGS_ANY()); /* 15.2.2.4.36 */ mrb_define_method(mrb, mod, "protected", mrb_mod_dummy_visibility, MRB_ARGS_ANY()); /* 15.2.2.4.37 */ mrb_define_method(mrb, mod, "public", mrb_mod_dummy_visibility, MRB_ARGS_ANY()); /* 15.2.2.4.38 */ - mrb_define_method(mrb, mod, "remove_class_variable", mrb_mod_remove_cvar, MRB_ARGS_REQ(1)); /* 15.2.2.4.39 */ - mrb_define_method(mrb, mod, "remove_method", mrb_mod_remove_method, MRB_ARGS_ANY()); /* 15.2.2.4.41 */ - mrb_define_method(mrb, mod, "method_removed", mrb_bob_init, MRB_ARGS_REQ(1)); mrb_define_method(mrb, mod, "attr_reader", mrb_mod_attr_reader, MRB_ARGS_ANY()); /* 15.2.2.4.13 */ mrb_define_method(mrb, mod, "attr_writer", mrb_mod_attr_writer, MRB_ARGS_ANY()); /* 15.2.2.4.14 */ mrb_define_method(mrb, mod, "to_s", mrb_mod_to_s, MRB_ARGS_NONE()); @@ -2533,14 +2245,12 @@ mrb_init_class(mrb_state *mrb) mrb_define_method(mrb, mod, "const_defined?", mrb_mod_const_defined, MRB_ARGS_ARG(1,1)); /* 15.2.2.4.20 */ mrb_define_method(mrb, mod, "const_get", mrb_mod_const_get, MRB_ARGS_REQ(1)); /* 15.2.2.4.21 */ mrb_define_method(mrb, mod, "const_set", mrb_mod_const_set, MRB_ARGS_REQ(2)); /* 15.2.2.4.23 */ - mrb_define_method(mrb, mod, "constants", mrb_mod_constants, MRB_ARGS_OPT(1)); /* 15.2.2.4.24 */ mrb_define_method(mrb, mod, "remove_const", mrb_mod_remove_const, MRB_ARGS_REQ(1)); /* 15.2.2.4.40 */ mrb_define_method(mrb, mod, "const_missing", mrb_mod_const_missing, MRB_ARGS_REQ(1)); + mrb_define_method(mrb, mod, "method_defined?", mrb_mod_method_defined, MRB_ARGS_REQ(1)); /* 15.2.2.4 +.34 */ mrb_define_method(mrb, mod, "define_method", mod_define_method, MRB_ARGS_ARG(1,1)); - mrb_define_method(mrb, mod, "class_variables", mrb_mod_class_variables, MRB_ARGS_NONE()); /* 15.2.2.4.19 */ mrb_define_method(mrb, mod, "===", mrb_mod_eqq, MRB_ARGS_REQ(1)); - mrb_define_class_method(mrb, mod, "constants", mrb_mod_s_constants, MRB_ARGS_ANY()); /* 15.2.2.3.1 */ - mrb_define_class_method(mrb, mod, "nesting", mrb_mod_s_nesting, MRB_ARGS_REQ(0)); /* 15.2.2.3.2 */ mrb_undef_method(mrb, cls, "append_features"); mrb_undef_method(mrb, cls, "extend_object"); diff --git a/src/etc.c b/src/etc.c index 1b8d44a53..12d948a55 100644 --- a/src/etc.c +++ b/src/etc.c @@ -75,6 +75,7 @@ mrb_obj_to_sym(mrb_state *mrb, mrb_value name) if (mrb_nil_p(name)) { name = mrb_inspect(mrb, name); mrb_raisef(mrb, E_TYPE_ERROR, "%S is not a symbol", name); + /* not reached */ } /* fall through */ case MRB_TT_STRING: diff --git a/src/kernel.c b/src/kernel.c index fed64e9b0..db576b20d 100644 --- a/src/kernel.c +++ b/src/kernel.c @@ -14,20 +14,6 @@ #include #include -typedef enum { - NOEX_PUBLIC = 0x00, - NOEX_NOSUPER = 0x01, - NOEX_PRIVATE = 0x02, - NOEX_PROTECTED = 0x04, - NOEX_MASK = 0x06, - NOEX_BASIC = 0x08, - NOEX_UNDEF = NOEX_NOSUPER, - NOEX_MODFUNC = 0x12, - NOEX_SUPER = 0x20, - NOEX_VCALL = 0x40, - NOEX_RESPONDS = 0x80 -} mrb_method_flag_t; - MRB_API mrb_bool mrb_func_basic_p(mrb_state *mrb, mrb_value obj, mrb_sym mid, mrb_func_t func) { @@ -551,96 +537,6 @@ obj_is_instance_of(mrb_state *mrb, mrb_value self) return mrb_bool_value(mrb_obj_is_instance_of(mrb, self, mrb_class_ptr(arg))); } -/* 15.3.1.3.20 */ -/* - * call-seq: - * obj.instance_variable_defined?(symbol) -> true or false - * - * Returns true if the given instance variable is - * defined in obj. - * - * class Fred - * def initialize(p1, p2) - * @a, @b = p1, p2 - * end - * end - * fred = Fred.new('cat', 99) - * fred.instance_variable_defined?(:@a) #=> true - * fred.instance_variable_defined?("@b") #=> true - * fred.instance_variable_defined?("@c") #=> false - */ -static mrb_value -mrb_obj_ivar_defined(mrb_state *mrb, mrb_value self) -{ - mrb_sym sym; - - mrb_get_args(mrb, "n", &sym); - mrb_iv_name_sym_check(mrb, sym); - return mrb_bool_value(mrb_iv_defined(mrb, self, sym)); -} - -/* 15.3.1.3.21 */ -/* - * call-seq: - * obj.instance_variable_get(symbol) -> obj - * - * Returns the value of the given instance variable, or nil if the - * instance variable is not set. The @ part of the - * variable name should be included for regular instance - * variables. Throws a NameError exception if the - * supplied symbol is not valid as an instance variable name. - * - * class Fred - * def initialize(p1, p2) - * @a, @b = p1, p2 - * end - * end - * fred = Fred.new('cat', 99) - * fred.instance_variable_get(:@a) #=> "cat" - * fred.instance_variable_get("@b") #=> 99 - */ -static mrb_value -mrb_obj_ivar_get(mrb_state *mrb, mrb_value self) -{ - mrb_sym iv_name; - - mrb_get_args(mrb, "n", &iv_name); - mrb_iv_name_sym_check(mrb, iv_name); - return mrb_iv_get(mrb, self, iv_name); -} - -/* 15.3.1.3.22 */ -/* - * call-seq: - * obj.instance_variable_set(symbol, obj) -> obj - * - * Sets the instance variable names by symbol to - * object, thereby frustrating the efforts of the class's - * author to attempt to provide proper encapsulation. The variable - * did not have to exist prior to this call. - * - * class Fred - * def initialize(p1, p2) - * @a, @b = p1, p2 - * end - * end - * fred = Fred.new('cat', 99) - * fred.instance_variable_set(:@a, 'dog') #=> "dog" - * fred.instance_variable_set(:@c, 'cat') #=> "cat" - * fred.inspect #=> "#" - */ -static mrb_value -mrb_obj_ivar_set(mrb_state *mrb, mrb_value self) -{ - mrb_sym iv_name; - mrb_value val; - - mrb_get_args(mrb, "no", &iv_name, &val); - mrb_iv_name_sym_check(mrb, iv_name); - mrb_iv_set(mrb, self, iv_name, val); - return val; -} - /* 15.3.1.3.24 */ /* 15.3.1.3.26 */ /* @@ -681,124 +577,6 @@ mrb_obj_is_kind_of_m(mrb_state *mrb, mrb_value self) KHASH_DECLARE(st, mrb_sym, char, FALSE) KHASH_DEFINE(st, mrb_sym, char, FALSE, kh_int_hash_func, kh_int_hash_equal) -static void -method_entry_loop(mrb_state *mrb, struct RClass* klass, khash_t(st)* set) -{ - khint_t i; - - khash_t(mt) *h = klass->mt; - if (!h || kh_size(h) == 0) return; - for (i=0;iflags & MRB_FL_CLASS_IS_PREPENDED)) { - MRB_CLASS_ORIGIN(klass); - prepended = TRUE; - } - - oldklass = 0; - while (klass && (klass != oldklass)) { - method_entry_loop(mrb, klass, set); - if ((klass->tt == MRB_TT_ICLASS && !prepended) || - (klass->tt == MRB_TT_SCLASS)) { - } - else { - if (!recur) break; - } - oldklass = klass; - klass = klass->super; - } - - ary = mrb_ary_new_capa(mrb, kh_size(set)); - for (i=0;itt == MRB_TT_SCLASS)) { - method_entry_loop(mrb, klass, set); - klass = klass->super; - } - if (recur) { - while (klass && ((klass->tt == MRB_TT_SCLASS) || (klass->tt == MRB_TT_ICLASS))) { - method_entry_loop(mrb, klass, set); - klass = klass->super; - } - } - - ary = mrb_ary_new(mrb); - for (i=0;i array - * - * Returns a list of the names of methods publicly accessible in - * obj. This will include all the methods accessible in - * obj's ancestors. - * - * class Klass - * def kMethod() - * end - * end - * k = Klass.new - * k.methods[0..9] #=> [:kMethod, :respond_to?, :nil?, :is_a?, - * # :class, :instance_variable_set, - * # :methods, :extend, :__send__, :instance_eval] - * k.methods.length #=> 42 - */ -static mrb_value -mrb_obj_methods_m(mrb_state *mrb, mrb_value self) -{ - mrb_bool recur = TRUE; - mrb_get_args(mrb, "|b", &recur); - return mrb_obj_methods(mrb, recur, self, (mrb_method_flag_t)0); /* everything but private */ -} - /* 15.3.1.3.32 */ /* * call_seq: @@ -813,57 +591,6 @@ mrb_false(mrb_state *mrb, mrb_value self) return mrb_false_value(); } -/* 15.3.1.3.36 */ -/* - * call-seq: - * obj.private_methods(all=true) -> array - * - * Returns the list of private methods accessible to obj. If - * the all parameter is set to false, only those methods - * in the receiver will be listed. - */ -static mrb_value -mrb_obj_private_methods(mrb_state *mrb, mrb_value self) -{ - mrb_bool recur = TRUE; - mrb_get_args(mrb, "|b", &recur); - return mrb_obj_methods(mrb, recur, self, NOEX_PRIVATE); /* private attribute not define */ -} - -/* 15.3.1.3.37 */ -/* - * call-seq: - * obj.protected_methods(all=true) -> array - * - * Returns the list of protected methods accessible to obj. If - * the all parameter is set to false, only those methods - * in the receiver will be listed. - */ -static mrb_value -mrb_obj_protected_methods(mrb_state *mrb, mrb_value self) -{ - mrb_bool recur = TRUE; - mrb_get_args(mrb, "|b", &recur); - return mrb_obj_methods(mrb, recur, self, NOEX_PROTECTED); /* protected attribute not define */ -} - -/* 15.3.1.3.38 */ -/* - * call-seq: - * obj.public_methods(all=true) -> array - * - * Returns the list of public methods accessible to obj. If - * the all parameter is set to false, only those methods - * in the receiver will be listed. - */ -static mrb_value -mrb_obj_public_methods(mrb_state *mrb, mrb_value self) -{ - mrb_bool recur = TRUE; - mrb_get_args(mrb, "|b", &recur); - return mrb_obj_methods(mrb, recur, self, NOEX_PUBLIC); /* public attribute not define */ -} - /* 15.3.1.2.12 */ /* 15.3.1.3.40 */ /* @@ -1084,67 +811,6 @@ obj_respond_to(mrb_state *mrb, mrb_value self) return mrb_bool_value(respond_to_p); } -/* 15.3.1.3.45 */ -/* - * call-seq: - * obj.singleton_methods(all=true) -> array - * - * Returns an array of the names of singleton methods for obj. - * If the optional all parameter is true, the list will include - * methods in modules included in obj. - * Only public and protected singleton methods are returned. - * - * module Other - * def three() end - * end - * - * class Single - * def Single.four() end - * end - * - * a = Single.new - * - * def a.one() - * end - * - * class << a - * include Other - * def two() - * end - * end - * - * Single.singleton_methods #=> [:four] - * a.singleton_methods(false) #=> [:two, :one] - * a.singleton_methods #=> [:two, :one, :three] - */ -static mrb_value -mrb_obj_singleton_methods_m(mrb_state *mrb, mrb_value self) -{ - mrb_bool recur = TRUE; - mrb_get_args(mrb, "|b", &recur); - return mrb_obj_singleton_methods(mrb, recur, self); -} - -static mrb_value -mod_define_singleton_method(mrb_state *mrb, mrb_value self) -{ - struct RProc *p; - mrb_method_t m; - mrb_sym mid; - mrb_value blk = mrb_nil_value(); - - mrb_get_args(mrb, "n&", &mid, &blk); - if (mrb_nil_p(blk)) { - mrb_raise(mrb, E_ARGUMENT_ERROR, "no block given"); - } - p = (struct RProc*)mrb_obj_alloc(mrb, MRB_TT_PROC, mrb->proc_class); - mrb_proc_copy(p, mrb_proc_ptr(blk)); - p->flags |= MRB_PROC_STRICT; - MRB_METHOD_FROM_PROC(m, p); - mrb_define_method_raw(mrb, mrb_class_ptr(mrb_singleton_class(mrb, self)), mid, m); - return mrb_symbol_value(mid); -} - static mrb_value mrb_obj_ceqq(mrb_state *mrb, mrb_value self) { @@ -1162,58 +828,6 @@ mrb_obj_ceqq(mrb_state *mrb, mrb_value self) return mrb_false_value(); } -/* 15.3.1.2.7 */ -/* - * call-seq: - * local_variables -> array - * - * Returns the names of local variables in the current scope. - * - * [mruby limitation] - * If variable symbol information was stripped out from - * compiled binary files using `mruby-strip -l`, this - * method always returns an empty array. - */ -static mrb_value -mrb_local_variables(mrb_state *mrb, mrb_value self) -{ - struct RProc *proc; - mrb_irep *irep; - mrb_value vars; - size_t i; - - proc = mrb->c->ci[-1].proc; - - if (MRB_PROC_CFUNC_P(proc)) { - return mrb_ary_new(mrb); - } - vars = mrb_hash_new(mrb); - while (proc) { - if (MRB_PROC_CFUNC_P(proc)) break; - irep = proc->body.irep; - if (!irep->lv) break; - for (i = 0; i + 1 < irep->nlocals; ++i) { - if (irep->lv[i].name) { - mrb_sym sym = irep->lv[i].name; - const char *name = mrb_sym2name(mrb, sym); - switch (name[0]) { - case '*': case '&': - break; - default: - mrb_hash_set(mrb, vars, mrb_symbol_value(sym), mrb_true_value()); - break; - } - } - } - if (!MRB_PROC_ENV_P(proc)) break; - proc = proc->upper; - //if (MRB_PROC_SCOPE_P(proc)) break; - if (!proc->c) break; - } - - return mrb_hash_keys(mrb, vars); -} - mrb_value mrb_obj_equal_m(mrb_state *mrb, mrb_value); void mrb_init_kernel(mrb_state *mrb) @@ -1222,13 +836,10 @@ mrb_init_kernel(mrb_state *mrb) mrb->kernel_module = krn = mrb_define_module(mrb, "Kernel"); /* 15.3.1 */ mrb_define_class_method(mrb, krn, "block_given?", mrb_f_block_given_p_m, MRB_ARGS_NONE()); /* 15.3.1.2.2 */ - mrb_define_class_method(mrb, krn, "global_variables", mrb_f_global_variables, MRB_ARGS_NONE()); /* 15.3.1.2.4 */ mrb_define_class_method(mrb, krn, "iterator?", mrb_f_block_given_p_m, MRB_ARGS_NONE()); /* 15.3.1.2.5 */ - mrb_define_class_method(mrb, krn, "local_variables", mrb_local_variables, MRB_ARGS_NONE()); /* 15.3.1.2.7 */ ; /* 15.3.1.2.11 */ mrb_define_class_method(mrb, krn, "raise", mrb_f_raise, MRB_ARGS_OPT(2)); /* 15.3.1.2.12 */ - mrb_define_method(mrb, krn, "singleton_class", mrb_singleton_class, MRB_ARGS_NONE()); mrb_define_method(mrb, krn, "===", mrb_equal_m, MRB_ARGS_REQ(1)); /* 15.3.1.3.2 */ mrb_define_method(mrb, krn, "block_given?", mrb_f_block_given_p_m, MRB_ARGS_NONE()); /* 15.3.1.3.6 */ @@ -1245,29 +856,19 @@ mrb_init_kernel(mrb_state *mrb) mrb_define_method(mrb, krn, "initialize_copy", mrb_obj_init_copy, MRB_ARGS_REQ(1)); /* 15.3.1.3.16 */ mrb_define_method(mrb, krn, "inspect", mrb_obj_inspect, MRB_ARGS_NONE()); /* 15.3.1.3.17 */ mrb_define_method(mrb, krn, "instance_of?", obj_is_instance_of, MRB_ARGS_REQ(1)); /* 15.3.1.3.19 */ - mrb_define_method(mrb, krn, "instance_variable_defined?", mrb_obj_ivar_defined, MRB_ARGS_REQ(1)); /* 15.3.1.3.20 */ - mrb_define_method(mrb, krn, "instance_variable_get", mrb_obj_ivar_get, MRB_ARGS_REQ(1)); /* 15.3.1.3.21 */ - mrb_define_method(mrb, krn, "instance_variable_set", mrb_obj_ivar_set, MRB_ARGS_REQ(2)); /* 15.3.1.3.22 */ - mrb_define_method(mrb, krn, "instance_variables", mrb_obj_instance_variables, MRB_ARGS_NONE()); /* 15.3.1.3.23 */ + mrb_define_method(mrb, krn, "is_a?", mrb_obj_is_kind_of_m, MRB_ARGS_REQ(1)); /* 15.3.1.3.24 */ mrb_define_method(mrb, krn, "iterator?", mrb_f_block_given_p_m, MRB_ARGS_NONE()); /* 15.3.1.3.25 */ mrb_define_method(mrb, krn, "kind_of?", mrb_obj_is_kind_of_m, MRB_ARGS_REQ(1)); /* 15.3.1.3.26 */ - mrb_define_method(mrb, krn, "local_variables", mrb_local_variables, MRB_ARGS_NONE()); /* 15.3.1.3.28 */ #ifdef MRB_DEFAULT_METHOD_MISSING mrb_define_method(mrb, krn, "method_missing", mrb_obj_missing, MRB_ARGS_ANY()); /* 15.3.1.3.30 */ #endif - mrb_define_method(mrb, krn, "methods", mrb_obj_methods_m, MRB_ARGS_OPT(1)); /* 15.3.1.3.31 */ mrb_define_method(mrb, krn, "nil?", mrb_false, MRB_ARGS_NONE()); /* 15.3.1.3.32 */ mrb_define_method(mrb, krn, "object_id", mrb_obj_id_m, MRB_ARGS_NONE()); /* 15.3.1.3.33 */ - mrb_define_method(mrb, krn, "private_methods", mrb_obj_private_methods, MRB_ARGS_OPT(1)); /* 15.3.1.3.36 */ - mrb_define_method(mrb, krn, "protected_methods", mrb_obj_protected_methods, MRB_ARGS_OPT(1)); /* 15.3.1.3.37 */ - mrb_define_method(mrb, krn, "public_methods", mrb_obj_public_methods, MRB_ARGS_OPT(1)); /* 15.3.1.3.38 */ mrb_define_method(mrb, krn, "raise", mrb_f_raise, MRB_ARGS_ANY()); /* 15.3.1.3.40 */ mrb_define_method(mrb, krn, "remove_instance_variable", mrb_obj_remove_instance_variable,MRB_ARGS_REQ(1)); /* 15.3.1.3.41 */ mrb_define_method(mrb, krn, "respond_to?", obj_respond_to, MRB_ARGS_ANY()); /* 15.3.1.3.43 */ mrb_define_method(mrb, krn, "send", mrb_f_send, MRB_ARGS_ANY()); /* 15.3.1.3.44 */ - mrb_define_method(mrb, krn, "singleton_methods", mrb_obj_singleton_methods_m, MRB_ARGS_OPT(1)); /* 15.3.1.3.45 */ - mrb_define_method(mrb, krn, "define_singleton_method", mod_define_singleton_method, MRB_ARGS_ANY()); mrb_define_method(mrb, krn, "to_s", mrb_any_to_s, MRB_ARGS_NONE()); /* 15.3.1.3.46 */ mrb_define_method(mrb, krn, "__case_eqq", mrb_obj_ceqq, MRB_ARGS_REQ(1)); /* internal */ diff --git a/test/t/class.rb b/test/t/class.rb index a5118fa93..85450f200 100644 --- a/test/t/class.rb +++ b/test/t/class.rb @@ -36,7 +36,7 @@ end assert('Class#new', '15.2.3.3.3') do assert_raise(TypeError, 'Singleton should raise TypeError') do - "a".singleton_class.new + (class <<"a"; self; end).new end class TestClass @@ -293,15 +293,7 @@ assert('singleton tests') do end end - assert_false baz.singleton_methods.include? :run_foo_mod - assert_false baz.singleton_methods.include? :run_baz - - assert_raise(NoMethodError, 'should raise NoMethodError') do - baz.run_foo_mod - end - assert_raise(NoMethodError, 'should raise NoMethodError') do - baz.run_baz - end + assert_equal :run_baz, baz assert_raise(NoMethodError, 'should raise NoMethodError') do bar.run_foo_mod @@ -318,8 +310,8 @@ assert('singleton tests') do self end - assert_true baz.singleton_methods.include? :run_baz - assert_true baz.singleton_methods.include? :run_foo_mod + assert_true baz.respond_to? :run_baz + assert_true baz.respond_to? :run_foo_mod assert_equal 100, baz.run_foo_mod assert_equal 300, baz.run_baz @@ -440,12 +432,3 @@ assert('class with non-class/module outer raises TypeError') do assert_raise(TypeError) { class 0::C1; end } assert_raise(TypeError) { class []::C2; end } end - -assert("remove_method doesn't segfault if the passed in argument isn't a symbol") do - klass = Class.new - assert_raise(TypeError) { klass.remove_method nil } - assert_raise(TypeError) { klass.remove_method 123 } - assert_raise(TypeError) { klass.remove_method 1.23 } - assert_raise(NameError) { klass.remove_method "hello" } - assert_raise(TypeError) { klass.remove_method Class.new } -end diff --git a/test/t/codegen.rb b/test/t/codegen.rb index 4c9e2c594..154d44168 100644 --- a/test/t/codegen.rb +++ b/test/t/codegen.rb @@ -194,4 +194,4 @@ assert('register window of calls (#3783)') do alias send2 send end end -end \ No newline at end of file +end diff --git a/test/t/kernel.rb b/test/t/kernel.rb index 561118302..9744bddba 100644 --- a/test/t/kernel.rb +++ b/test/t/kernel.rb @@ -103,7 +103,7 @@ assert('Kernel#__send__', '15.3.1.3.4') do # test with argument assert_true __send__(:respond_to?, :nil?) # test without argument and without block - assert_equal Array, __send__(:public_methods).class + assert_equal String, __send__(:to_s).class end assert('Kernel#block_given?', '15.3.1.3.6') do @@ -278,30 +278,6 @@ assert('Kernel#inspect', '15.3.1.3.17') do assert_equal "main", s end -assert('Kernel#instance_variable_defined?', '15.3.1.3.20') do - o = Object.new - o.instance_variable_set(:@a, 1) - - assert_true o.instance_variable_defined?("@a") - assert_false o.instance_variable_defined?("@b") - assert_true o.instance_variable_defined?("@a"[0,2]) - assert_true o.instance_variable_defined?("@abc"[0,2]) -end - -assert('Kernel#instance_variables', '15.3.1.3.23') do - o = Object.new - o.instance_eval do - @a = 11 - @b = 12 - end - ivars = o.instance_variables - - assert_equal Array, ivars.class, - assert_equal(2, ivars.size) - assert_true ivars.include?(:@a) - assert_true ivars.include?(:@b) -end - assert('Kernel#is_a?', '15.3.1.3.24') do assert_true is_a?(Kernel) assert_false is_a?(Array) @@ -381,10 +357,6 @@ assert('Kernel#method_missing', '15.3.1.3.30') do end end -assert('Kernel#methods', '15.3.1.3.31') do - assert_equal Array, methods.class -end - assert('Kernel#nil?', '15.3.1.3.32') do assert_false nil? end @@ -408,23 +380,6 @@ end # Kernel#print is defined in mruby-print mrbgem. '15.3.1.3.35' -assert('Kernel#private_methods', '15.3.1.3.36') do - assert_equal Array, private_methods.class -end - -assert('Kernel#protected_methods', '15.3.1.3.37') do - assert_equal Array, protected_methods.class -end - -assert('Kernel#public_methods', '15.3.1.3.38') do - assert_equal Array, public_methods.class - class Foo - def foo - end - end - assert_equal [:foo], Foo.new.public_methods(false) -end - # Kernel#puts is defined in mruby-print mrbgem. '15.3.1.3.39' assert('Kernel#raise', '15.3.1.3.40') do @@ -496,46 +451,13 @@ assert('Kernel#send', '15.3.1.3.44') do # test with argument assert_true send(:respond_to?, :nil?) # test without argument and without block - assert_equal send(:public_methods).class, Array -end - -assert('Kernel#singleton_methods', '15.3.1.3.45') do - assert_equal singleton_methods.class, Array + assert_equal send(:to_s).class, String end assert('Kernel#to_s', '15.3.1.3.46') do assert_equal to_s.class, String end -assert('Kernel#to_s on primitives') do - begin - Fixnum.alias_method :to_s_, :to_s - Fixnum.remove_method :to_s - - assert_nothing_raised do - # segfaults if mrb_cptr is used - 1.to_s - end - ensure - Fixnum.alias_method :to_s, :to_s_ - Fixnum.remove_method :to_s_ - end -end - -assert('Kernel.local_variables', '15.3.1.2.7') do - a, b = 0, 1 - a += b - - vars = Kernel.local_variables.sort - assert_equal [:a, :b, :vars], vars - - assert_equal [:a, :b, :c, :vars], Proc.new { |a, b| - c = 2 - # Kernel#local_variables: 15.3.1.3.28 - local_variables.sort - }.call(-1, -2) -end - assert('Kernel#!=') do str1 = "hello" str2 = str1 @@ -585,15 +507,6 @@ assert('Kernel#global_variables') do end end -assert('Kernel#define_singleton_method') do - o = Object.new - ret = o.define_singleton_method(:test_method) do - :singleton_method_ok - end - assert_equal :test_method, ret - assert_equal :singleton_method_ok, o.test_method -end - assert('stack extend') do def recurse(count, stop) return count if count > stop diff --git a/test/t/module.rb b/test/t/module.rb index fb82fc934..fda375721 100644 --- a/test/t/module.rb +++ b/test/t/module.rb @@ -3,7 +3,7 @@ def labeled_module(name, &block) Module.new do - singleton_class.class_eval do + (class < Date: Thu, 30 Aug 2018 22:14:10 +0900 Subject: Add new function `mrb_ensure_hash_type()`; ref #4097 Unlike `mrb_check_hash_type()` that returns `nil` if the argument is not a `Hash`, `mrb_ensure_hash_type()` raises a `TypeError` exception. --- include/mruby/hash.h | 1 + src/hash.c | 8 +++++++- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/include/mruby/hash.h b/include/mruby/hash.h index 2026c8e0d..449a7d4bc 100644 --- a/include/mruby/hash.h +++ b/include/mruby/hash.h @@ -25,6 +25,7 @@ struct RHash { #define mrb_hash_value(p) mrb_obj_value((void*)(p)) MRB_API mrb_value mrb_hash_new_capa(mrb_state*, mrb_int); +MRB_API mrb_value mrb_ensure_hash_type(mrb_state *mrb, mrb_value hash); MRB_API mrb_value mrb_check_hash_type(mrb_state *mrb, mrb_value hash); /* diff --git a/src/hash.c b/src/hash.c index 122f5b5d5..7d81bc343 100644 --- a/src/hash.c +++ b/src/hash.c @@ -320,6 +320,12 @@ mrb_hash_set(mrb_state *mrb, mrb_value hash, mrb_value key, mrb_value val) return; } +MRB_API mrb_value +mrb_ensure_hash_type(mrb_state *mrb, mrb_value hash) +{ + return mrb_convert_type(mrb, hash, MRB_TT_HASH, "Hash", "to_hash"); +} + MRB_API mrb_value mrb_check_hash_type(mrb_state *mrb, mrb_value hash) { @@ -959,7 +965,7 @@ mrb_hash_merge(mrb_state *mrb, mrb_value hash1, mrb_value hash2) khiter_t k; mrb_hash_modify(mrb, hash1); - hash2 = mrb_check_hash_type(mrb, hash2); + hash2 = mrb_ensure_hash_type(mrb, hash2); h1 = RHASH_TBL(hash1); h2 = RHASH_TBL(hash2); -- cgit v1.2.3 From 50b840c9de7a0a37d42742a53757f2e74447c053 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Thu, 30 Aug 2018 22:18:27 +0900 Subject: Use `mrb_ensure_hash_type()` to check if an operand is a `Hash`; fix #4097 --- src/vm.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/vm.c b/src/vm.c index 98e554607..77d9316d4 100644 --- a/src/vm.c +++ b/src/vm.c @@ -2720,10 +2720,11 @@ RETRY_TRY_BLOCK: } CASE(OP_HASHADD, BB) { - mrb_value hash = regs[a]; + mrb_value hash; int i; int lim = a+b*2+1; + hash = mrb_ensure_hash_type(mrb, regs[a]); for (i=a+1; i Date: Thu, 30 Aug 2018 22:48:05 +0900 Subject: Update `RITE_BINARY_FORMAT_VER` and `RITE_VM_VER`. The bytecode format was updated so the header version constants must be updated as well. --- include/mruby/dump.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/mruby/dump.h b/include/mruby/dump.h index f56d66a32..bff838484 100644 --- a/include/mruby/dump.h +++ b/include/mruby/dump.h @@ -52,11 +52,11 @@ MRB_API mrb_irep *mrb_read_irep(mrb_state*, const uint8_t*); /* Rite Binary File header */ #define RITE_BINARY_IDENT "RITE" #define RITE_BINARY_IDENT_LIL "ETIR" -#define RITE_BINARY_FORMAT_VER "0004" +#define RITE_BINARY_FORMAT_VER "0005" #define RITE_COMPILER_NAME "MATZ" #define RITE_COMPILER_VERSION "0000" -#define RITE_VM_VER "0000" +#define RITE_VM_VER "0002" #define RITE_BINARY_EOF "END\0" #define RITE_SECTION_IREP_IDENT "IREP" -- cgit v1.2.3 From 2be42aef0f7970ba1510469e8469f3e3c2af3bd4 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Sat, 1 Sep 2018 09:35:46 +0900 Subject: Fix ISO/JIS section numbers. --- mrblib/kernel.rb | 2 +- src/class.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/mrblib/kernel.rb b/mrblib/kernel.rb index 550ae8172..4700684b6 100644 --- a/mrblib/kernel.rb +++ b/mrblib/kernel.rb @@ -6,7 +6,7 @@ module Kernel # 15.3.1.2.1 Kernel.` # provided by Kernel#` - # 15.3.1.3.5 + # 15.3.1.3.3 def `(s) raise NotImplementedError.new("backquotes not implemented") end diff --git a/src/class.c b/src/class.c index f8d60d79a..e074cbc3b 100644 --- a/src/class.c +++ b/src/class.c @@ -2210,8 +2210,8 @@ mrb_init_class(mrb_state *mrb) mrb_define_method(mrb, bob, "!", mrb_bob_not, MRB_ARGS_NONE()); mrb_define_method(mrb, bob, "==", mrb_obj_equal_m, MRB_ARGS_REQ(1)); /* 15.3.1.3.1 */ mrb_define_method(mrb, bob, "!=", mrb_obj_not_equal_m, MRB_ARGS_REQ(1)); - mrb_define_method(mrb, bob, "__id__", mrb_obj_id_m, MRB_ARGS_NONE()); /* 15.3.1.3.3 */ - mrb_define_method(mrb, bob, "__send__", mrb_f_send, MRB_ARGS_ANY()); /* 15.3.1.3.4 */ + mrb_define_method(mrb, bob, "__id__", mrb_obj_id_m, MRB_ARGS_NONE()); /* 15.3.1.3.4 */ + mrb_define_method(mrb, bob, "__send__", mrb_f_send, MRB_ARGS_ANY()); /* 15.3.1.3.5 */ mrb_define_method(mrb, bob, "instance_eval", mrb_obj_instance_eval, MRB_ARGS_ANY()); /* 15.3.1.3.18 */ mrb_define_class_method(mrb, cls, "new", mrb_class_new_class, MRB_ARGS_OPT(1)); -- cgit v1.2.3 From 0c6353aa2cf8b002d2540c8b66db7d5af730f503 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Sat, 1 Sep 2018 11:01:50 +0900 Subject: Remove `MRB_API` from `mrb_f_send` which is not API. --- include/mruby/proc.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/mruby/proc.h b/include/mruby/proc.h index aa281b6dd..f428e6666 100644 --- a/include/mruby/proc.h +++ b/include/mruby/proc.h @@ -88,7 +88,7 @@ MRB_API struct RProc *mrb_closure_new_cfunc(mrb_state *mrb, mrb_func_t func, int void mrb_proc_copy(struct RProc *a, struct RProc *b); /* implementation of #send method */ -MRB_API mrb_value mrb_f_send(mrb_state *mrb, mrb_value self); +mrb_value mrb_f_send(mrb_state *mrb, mrb_value self); /* following functions are defined in mruby-proc-ext so please include it when using */ MRB_API struct RProc *mrb_proc_new_cfunc_with_env(mrb_state*, mrb_func_t, mrb_int, const mrb_value*); -- cgit v1.2.3 From 05f377dee422d0d14ed7fda26b134a2dba8068b3 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Sat, 1 Sep 2018 11:02:59 +0900 Subject: Use `__send__` instead of `send`. --- mrbgems/mruby-proc-ext/mrblib/proc.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mrbgems/mruby-proc-ext/mrblib/proc.rb b/mrbgems/mruby-proc-ext/mrblib/proc.rb index b71663938..789b7a3ac 100644 --- a/mrbgems/mruby-proc-ext/mrblib/proc.rb +++ b/mrbgems/mruby-proc-ext/mrblib/proc.rb @@ -27,7 +27,7 @@ class Proc pproc = self make_curry = proc do |given_args=[]| - send(type) do |*args| + __send__(type) do |*args| new_args = given_args + args if new_args.size >= arity pproc[*new_args] -- cgit v1.2.3 From 593c12a5cd670cfdb45741377236207a56541d37 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Sat, 1 Sep 2018 11:18:12 +0900 Subject: Avoid `NoMethodError` exception from `mrb_func_basic_p`. --- src/kernel.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/kernel.c b/src/kernel.c index db576b20d..248fa5266 100644 --- a/src/kernel.c +++ b/src/kernel.c @@ -17,7 +17,8 @@ MRB_API mrb_bool mrb_func_basic_p(mrb_state *mrb, mrb_value obj, mrb_sym mid, mrb_func_t func) { - mrb_method_t m = mrb_method_search(mrb, mrb_class(mrb, obj), mid); + struct RClass *c = mrb_class(mrb, obj); + mrb_method_t m = mrb_method_search_vm(mrb, &c, mid); struct RProc *p; if (MRB_METHOD_UNDEF_P(m)) return FALSE; -- cgit v1.2.3 From b80e0ef7428b613a682da4d2a251c8beb24d6dd2 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Sat, 1 Sep 2018 11:20:30 +0900 Subject: Move `Kernel#send` to `mruby-metaprog` gem. But `BasicObject#__send__` is still available from the core. --- mrbgems/mruby-eval/test/eval.rb | 2 +- mrbgems/mruby-metaprog/src/metaprog.c | 1 + mrbgems/mruby-metaprog/test/metaprog.rb | 27 ++++++++ mrbgems/mruby-method/test/method.rb | 5 +- src/kernel.c | 1 - test/t/codegen.rb | 4 +- test/t/kernel.rb | 28 --------- test/t/module.rb | 106 ++++++++++++++++---------------- 8 files changed, 85 insertions(+), 89 deletions(-) diff --git a/mrbgems/mruby-eval/test/eval.rb b/mrbgems/mruby-eval/test/eval.rb index a710a1fc0..4d7dd4606 100644 --- a/mrbgems/mruby-eval/test/eval.rb +++ b/mrbgems/mruby-eval/test/eval.rb @@ -34,7 +34,7 @@ assert('Kernel.eval', '15.3.1.2.3') do } assert_equal(2) { a = 10 - Kernel.eval 'def f(a); b=a.send(:+, 1); end' + Kernel.eval 'def f(a); b=a+1; end' f(1) } end diff --git a/mrbgems/mruby-metaprog/src/metaprog.c b/mrbgems/mruby-metaprog/src/metaprog.c index 18003ef4d..25c153cee 100644 --- a/mrbgems/mruby-metaprog/src/metaprog.c +++ b/mrbgems/mruby-metaprog/src/metaprog.c @@ -680,6 +680,7 @@ mrb_mruby_metaprog_gem_init(mrb_state* mrb) mrb_define_method(mrb, krn, "public_methods", mrb_obj_public_methods, MRB_ARGS_OPT(1)); /* 15.3.1.3.38 */ mrb_define_method(mrb, krn, "singleton_methods", mrb_obj_singleton_methods_m, MRB_ARGS_OPT(1)); /* 15.3.1.3.45 */ mrb_define_method(mrb, krn, "define_singleton_method", mod_define_singleton_method, MRB_ARGS_ANY()); + mrb_define_method(mrb, krn, "send", mrb_f_send, MRB_ARGS_ANY()); /* 15.3.1.3.44 */ mrb_define_method(mrb, mod, "class_variables", mrb_mod_class_variables, MRB_ARGS_NONE()); /* 15.2.2.4.19 */ mrb_define_method(mrb, mod, "remove_class_variable", mrb_mod_remove_cvar, MRB_ARGS_REQ(1)); /* 15.2.2.4.39 */ diff --git a/mrbgems/mruby-metaprog/test/metaprog.rb b/mrbgems/mruby-metaprog/test/metaprog.rb index 587d00d6f..748fe9c6c 100644 --- a/mrbgems/mruby-metaprog/test/metaprog.rb +++ b/mrbgems/mruby-metaprog/test/metaprog.rb @@ -1,3 +1,30 @@ +assert('Kernel#__send__', '15.3.1.3.4') do + # test with block + l = __send__(:lambda) do + true + end + + assert_true l.call + assert_equal Proc, l.class + # test with argument + assert_true __send__(:respond_to?, :nil?) + # test without argument and without block + assert_equal String, __send__(:to_s).class +end + +assert('Kernel#send', '15.3.1.3.44') do + # test with block + l = send(:lambda) do + true + end + + assert_true l.call + assert_equal l.class, Proc + # test with argument + assert_true send(:respond_to?, :nil?) + # test without argument and without block + assert_equal send(:to_s).class, String +end assert('Kernel#instance_variable_defined?', '15.3.1.3.20') do o = Object.new diff --git a/mrbgems/mruby-method/test/method.rb b/mrbgems/mruby-method/test/method.rb index eb5f48341..9fd6a558e 100644 --- a/mrbgems/mruby-method/test/method.rb +++ b/mrbgems/mruby-method/test/method.rb @@ -102,10 +102,7 @@ end assert 'Method#call for regression' do obj = BasicObject.new - def obj.foo - :ok - end - assert_equal :ok, Kernel.instance_method(:send).bind(obj).call(:foo), "https://github.com/ksss/mruby-method/issues/4" + assert_equal String, Kernel.instance_method(:inspect).bind(obj).call().class, "https://github.com/ksss/mruby-method/issues/4" end assert 'Method#call with undefined method' do diff --git a/src/kernel.c b/src/kernel.c index 248fa5266..db681d510 100644 --- a/src/kernel.c +++ b/src/kernel.c @@ -869,7 +869,6 @@ mrb_init_kernel(mrb_state *mrb) mrb_define_method(mrb, krn, "raise", mrb_f_raise, MRB_ARGS_ANY()); /* 15.3.1.3.40 */ mrb_define_method(mrb, krn, "remove_instance_variable", mrb_obj_remove_instance_variable,MRB_ARGS_REQ(1)); /* 15.3.1.3.41 */ mrb_define_method(mrb, krn, "respond_to?", obj_respond_to, MRB_ARGS_ANY()); /* 15.3.1.3.43 */ - mrb_define_method(mrb, krn, "send", mrb_f_send, MRB_ARGS_ANY()); /* 15.3.1.3.44 */ mrb_define_method(mrb, krn, "to_s", mrb_any_to_s, MRB_ARGS_NONE()); /* 15.3.1.3.46 */ mrb_define_method(mrb, krn, "__case_eqq", mrb_obj_ceqq, MRB_ARGS_REQ(1)); /* internal */ diff --git a/test/t/codegen.rb b/test/t/codegen.rb index 154d44168..acb9e1bf5 100644 --- a/test/t/codegen.rb +++ b/test/t/codegen.rb @@ -184,14 +184,14 @@ assert('register window of calls (#3783)') do # NODE_UNDEF assert_nothing_raised do class << Object.new - undef send + undef inspect end end # NODE_ALIAS assert_nothing_raised do class << Object.new - alias send2 send + alias inspect2 inspect end end end diff --git a/test/t/kernel.rb b/test/t/kernel.rb index 9744bddba..a730bdb24 100644 --- a/test/t/kernel.rb +++ b/test/t/kernel.rb @@ -92,20 +92,6 @@ assert('Kernel#__id__', '15.3.1.3.3') do assert_equal Fixnum, __id__.class end -assert('Kernel#__send__', '15.3.1.3.4') do - # test with block - l = __send__(:lambda) do - true - end - - assert_true l.call - assert_equal Proc, l.class - # test with argument - assert_true __send__(:respond_to?, :nil?) - # test without argument and without block - assert_equal String, __send__(:to_s).class -end - assert('Kernel#block_given?', '15.3.1.3.6') do def bg_try(&b) if block_given? @@ -440,20 +426,6 @@ assert('Kernel#respond_to?', '15.3.1.3.43') do assert_false Test4RespondTo.new.respond_to?(:test_method) end -assert('Kernel#send', '15.3.1.3.44') do - # test with block - l = send(:lambda) do - true - end - - assert_true l.call - assert_equal l.class, Proc - # test with argument - assert_true send(:respond_to?, :nil?) - # test without argument and without block - assert_equal send(:to_s).class, String -end - assert('Kernel#to_s', '15.3.1.3.46') do assert_equal to_s.class, String end diff --git a/test/t/module.rb b/test/t/module.rb index fda375721..78cb5d07f 100644 --- a/test/t/module.rb +++ b/test/t/module.rb @@ -536,61 +536,61 @@ end #end # mruby has no visibility control - assert 'Module#prepend visibility' do - bug8005 = '[ruby-core:53106] [Bug #8005]' - c = Class.new do - prepend Module.new {} - def foo() end - protected :foo - end - a = c.new - assert_true a.respond_to?(:foo), bug8005 - assert_nothing_raised(bug8005) {a.send :foo} - end + # assert 'Module#prepend visibility' do + # bug8005 = '[ruby-core:53106] [Bug #8005]' + # c = Class.new do + # prepend Module.new {} + # def foo() end + # protected :foo + # end + # a = c.new + # assert_true a.respond_to?(:foo), bug8005 + # assert_nothing_raised(bug8005) {a.send :foo} + # end # mruby has no visibility control - assert 'Module#prepend inherited visibility' do - bug8238 = '[ruby-core:54105] [Bug #8238]' - module Test4PrependVisibilityInherited - class A - def foo() A; end - private :foo - end - class B < A - public :foo - prepend Module.new - end - end - assert_equal(Test4PrependVisibilityInherited::A, Test4PrependVisibilityInherited::B.new.foo, "#{bug8238}") - end - - assert 'Module#prepend super in alias' do - skip "super does not currently work in aliased methods" - bug7842 = '[Bug #7842]' - - p = labeled_module("P") do - def m; "P"+super; end - end - - a = labeled_class("A") do - def m; "A"; end - end - - b = labeled_class("B", a) do - def m; "B"+super; end - alias m2 m - prepend p - alias m3 m - end - - assert_nothing_raised do - assert_equal("BA", b.new.m2, bug7842) - end - - assert_nothing_raised do - assert_equal("PBA", b.new.m3, bug7842) - end - end + # assert 'Module#prepend inherited visibility' do + # bug8238 = '[ruby-core:54105] [Bug #8238]' + # module Test4PrependVisibilityInherited + # class A + # def foo() A; end + # private :foo + # end + # class B < A + # public :foo + # prepend Module.new + # end + # end + # assert_equal(Test4PrependVisibilityInherited::A, Test4PrependVisibilityInherited::B.new.foo, "#{bug8238}") + # end + + # assert 'Module#prepend super in alias' do + # skip "super does not currently work in aliased methods" + # bug7842 = '[Bug #7842]' + + # p = labeled_module("P") do + # def m; "P"+super; end + # end + + # a = labeled_class("A") do + # def m; "A"; end + # end + + # b = labeled_class("B", a) do + # def m; "B"+super; end + # alias m2 m + # prepend p + # alias m3 m + # end + + # assert_nothing_raised do + # assert_equal("BA", b.new.m2, bug7842) + # end + + # assert_nothing_raised do + # assert_equal("PBA", b.new.m3, bug7842) + # end + # end assert 'Module#prepend each class' do m = labeled_module("M") -- cgit v1.2.3 From 20c0c6330f38c6a1a969a06bc5a3bf56d39f466f Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Sat, 1 Sep 2018 17:14:54 +0900 Subject: Too much peephole optimization in `gen_call`; fix #4091 It causes trouble for safe navigation operator. --- mrbgems/mruby-compiler/core/codegen.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mrbgems/mruby-compiler/core/codegen.c b/mrbgems/mruby-compiler/core/codegen.c index 835cee817..efd20d908 100644 --- a/mrbgems/mruby-compiler/core/codegen.c +++ b/mrbgems/mruby-compiler/core/codegen.c @@ -979,7 +979,7 @@ gen_call(codegen_scope *s, node *tree, mrb_sym name, int sp, int val, int safe) codegen(s, tree->car, VAL); /* receiver */ if (safe) { int recv = cursp()-1; - gen_move(s, cursp(), recv, 0); + gen_move(s, cursp(), recv, 1); skip = genjmp2(s, OP_JMPNIL, cursp(), 0, val); } idx = new_sym(s, sym); -- cgit v1.2.3 From a657117e4e5fbde4434661794f80a93dde55d70d Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Sat, 1 Sep 2018 17:36:35 +0900 Subject: Avoid warning in MSVC compilation. --- mrbgems/mruby-compiler/core/codegen.c | 6 +++--- mrbgems/mruby-socket/test/sockettest.c | 1 + src/vm.c | 4 ++-- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/mrbgems/mruby-compiler/core/codegen.c b/mrbgems/mruby-compiler/core/codegen.c index efd20d908..98b215f6b 100644 --- a/mrbgems/mruby-compiler/core/codegen.c +++ b/mrbgems/mruby-compiler/core/codegen.c @@ -2378,9 +2378,9 @@ codegen(codegen_scope *s, node *tree, int val) #endif { if (i == -1) genop_1(s, OP_LOADI__1, cursp()); - else if (i < 0) genop_2(s, OP_LOADINEG, cursp(), -i); - else if (i < 8) genop_1(s, OP_LOADI_0 + i, cursp()); - else if (i <= 0xffff) genop_2(s, OP_LOADI, cursp(), i); + else if (i < 0) genop_2(s, OP_LOADINEG, cursp(), (uint16_t)-i); + else if (i < 8) genop_1(s, OP_LOADI_0 + (uint8_t)i, cursp()); + else if (i <= 0xffff) genop_2(s, OP_LOADI, cursp(), (uint16_t)i); else { int off = new_lit(s, mrb_fixnum_value(i)); genop_2(s, OP_LOADL, cursp(), off); diff --git a/mrbgems/mruby-socket/test/sockettest.c b/mrbgems/mruby-socket/test/sockettest.c index 086bc4892..3017c7cc1 100644 --- a/mrbgems/mruby-socket/test/sockettest.c +++ b/mrbgems/mruby-socket/test/sockettest.c @@ -12,6 +12,7 @@ #include #include +#define open _open #define close _close #define unlink _unlink diff --git a/src/vm.c b/src/vm.c index 77d9316d4..70c27da57 100644 --- a/src/vm.c +++ b/src/vm.c @@ -176,7 +176,7 @@ envadjust(mrb_state *mrb, mrb_value *oldbase, mrb_value *newbase, size_t oldsize /** def rec ; $deep =+ 1 ; if $deep > 1000 ; return 0 ; end ; rec ; end */ static void -stack_extend_alloc(mrb_state *mrb, int room) +stack_extend_alloc(mrb_state *mrb, mrb_int room) { mrb_value *oldbase = mrb->c->stbase; mrb_value *newstack; @@ -333,7 +333,7 @@ ecall(mrb_state *mrb) struct REnv *env; ptrdiff_t cioff; int ai = mrb_gc_arena_save(mrb); - uint8_t i = --c->eidx; + uint16_t i = --c->eidx; int nregs; if (i<0) return; -- cgit v1.2.3 From cbf27388619b1f3fc035b0aedf67091330ab37b5 Mon Sep 17 00:00:00 2001 From: dearblue Date: Sun, 2 Sep 2018 14:13:09 +0900 Subject: Reverse gems final --- tasks/mrbgems.rake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tasks/mrbgems.rake b/tasks/mrbgems.rake index 64e5b0353..e2aeb1514 100644 --- a/tasks/mrbgems.rake +++ b/tasks/mrbgems.rake @@ -18,7 +18,7 @@ MRuby.each_target do gem_init_calls = gem_func_gems.each_with_object('') do |g, s| s << " GENERATED_TMP_mrb_#{g.funcname}_gem_init(mrb);\n" end - gem_final_calls = gem_func_gems.each_with_object('') do |g, s| + gem_final_calls = gem_func_gems.reverse_each.with_object('') do |g, s| s << " GENERATED_TMP_mrb_#{g.funcname}_gem_final(mrb);\n" end f.puts %Q[/*] -- cgit v1.2.3 From e6357f3baa465412c521e7d4b527c868f73ec62e Mon Sep 17 00:00:00 2001 From: take-cheeze Date: Tue, 4 Sep 2018 16:16:25 +0900 Subject: Fix indent. --- minirake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/minirake b/minirake index ad8276a6d..2c93502f2 100755 --- a/minirake +++ b/minirake @@ -590,7 +590,7 @@ class RakeApp wait_process(count + 1) if !$rake_fiber_table.empty? && exited.empty? end - end +end if __FILE__ == $0 then RakeApp.new.run -- cgit v1.2.3 From 901dccb2df17cd6ebd5b9e5c7ef2734af54f0588 Mon Sep 17 00:00:00 2001 From: take-cheeze Date: Tue, 4 Sep 2018 16:16:33 +0900 Subject: Avoid root fiber initialization for CRuby workaround. closes #4085. --- minirake | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/minirake b/minirake index 2c93502f2..86c42c999 100755 --- a/minirake +++ b/minirake @@ -6,12 +6,10 @@ require 'getoptlong' require 'fileutils' -require 'fiber' $rake_fiber_table = {} $rake_jobs = 1 $rake_failed = [] -$rake_root_fiber = Fiber.current class String def ext(newext='') @@ -111,9 +109,13 @@ module MiniRake if needed? @running = true - return Fiber.new do + if $rake_root_fiber + return Fiber.new do + self.execute + $rake_root_fiber.transfer + end + else self.execute - $rake_root_fiber.transfer end end @@ -308,7 +310,7 @@ module MiniRake def sh(cmd) puts cmd if $verbose - if $rake_jobs == 1 || Fiber.current == $rake_root_fiber + if !$rake_root_fiber || Fiber.current == $rake_root_fiber system(cmd) or fail "Command Failed: [#{cmd}]" return end @@ -480,6 +482,12 @@ class RakeApp # Run the +rake+ application. def run handle_options + + if $rake_root_fiber + require 'fiber' + $rake_root_fiber = Fiber.current + end + begin here = Dir.pwd while ! have_rakefile -- cgit v1.2.3 From c2634e18b6dc8bf2b447e6f18699e3f4ed6f9474 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Mon, 3 Sep 2018 15:15:49 +0900 Subject: Add type casts to silence MSVC warnings. --- mrbgems/mruby-bin-mirb/tools/mirb/mirb.c | 2 +- src/vm.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/mrbgems/mruby-bin-mirb/tools/mirb/mirb.c b/mrbgems/mruby-bin-mirb/tools/mirb/mirb.c index 5c2b58da5..1880f22f7 100644 --- a/mrbgems/mruby-bin-mirb/tools/mirb/mirb.c +++ b/mrbgems/mruby-bin-mirb/tools/mirb/mirb.c @@ -111,7 +111,7 @@ p(mrb_state *mrb, mrb_value obj, int prompt) if (!mrb_string_p(val)) { val = mrb_obj_as_string(mrb, obj); } - msg = mrb_locale_from_utf8(RSTRING_PTR(val), RSTRING_LEN(val)); + msg = mrb_locale_from_utf8(RSTRING_PTR(val), (int)RSTRING_LEN(val)); fwrite(msg, strlen(msg), 1, stdout); mrb_locale_free(msg); putc('\n', stdout); diff --git a/src/vm.c b/src/vm.c index 70c27da57..43c3d120f 100644 --- a/src/vm.c +++ b/src/vm.c @@ -186,7 +186,7 @@ stack_extend_alloc(mrb_state *mrb, mrb_int room) if (off > size) size = off; #ifdef MRB_STACK_EXTEND_DOUBLING - if (room <= size) + if (room <= (size_t)size) size *= 2; else size += room; -- cgit v1.2.3 From 7592dfcf7dfabc5d5df26906d6571d4f61aa8de7 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Tue, 4 Sep 2018 20:50:54 +0900 Subject: Need more precise constant name check. This change was inspired by [ruby-bugs#7573] --- src/class.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/class.c b/src/class.c index e074cbc3b..22fe36fb3 100644 --- a/src/class.c +++ b/src/class.c @@ -1981,7 +1981,14 @@ mrb_mod_const_get(mrb_state *mrb, mrb_value mod) end = (end == -1) ? len : end; id = mrb_intern(mrb, ptr+off, end-off); mod = mrb_const_get_sym(mrb, mod, id); - off = (end == len) ? end : end+2; + if (end == len) + off = end; + else { + off = end + 2; + if (off == len) { /* trailing "::" */ + mrb_name_error(mrb, id, "wrong constant name '%S'", path); + } + } } return mod; -- cgit v1.2.3 From 9b5910bd0f674f5948cd1185e07d8a024477d162 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Tue, 4 Sep 2018 21:06:36 +0900 Subject: Revert "Remove top-level constant lookup; CRuby2.5"; fix #4070 This reverts commit c96def7c96c50f3b8e22e47ce31a6c5a37939dfd. This change was from my misunderstanding. --- src/variable.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/src/variable.c b/src/variable.c index e753f8d29..00bdb4b8d 100644 --- a/src/variable.c +++ b/src/variable.c @@ -732,24 +732,23 @@ mod_const_check(mrb_state *mrb, mrb_value mod) } static mrb_value -const_get(mrb_state *mrb, struct RClass *base, mrb_sym sym, mrb_bool top) +const_get(mrb_state *mrb, struct RClass *base, mrb_sym sym) { struct RClass *c = base; mrb_value v; mrb_bool retry = FALSE; mrb_value name; - struct RClass *oclass = mrb->object_class; L_RETRY: while (c) { - if (top || c != oclass || base == oclass) { + if (c->iv) { if (iv_get(mrb, c->iv, sym, &v)) return v; } c = c->super; } if (!retry && base->tt == MRB_TT_MODULE) { - c = oclass; + c = mrb->object_class; retry = TRUE; goto L_RETRY; } @@ -761,7 +760,7 @@ MRB_API mrb_value mrb_const_get(mrb_state *mrb, mrb_value mod, mrb_sym sym) { mod_const_check(mrb, mod); - return const_get(mrb, mrb_class_ptr(mod), sym, FALSE); + return const_get(mrb, mrb_class_ptr(mod), sym); } mrb_value @@ -796,7 +795,7 @@ mrb_vm_const_get(mrb_state *mrb, mrb_sym sym) } proc = proc->upper; } - return const_get(mrb, c, sym, TRUE); + return const_get(mrb, c, sym); } MRB_API void -- cgit v1.2.3 From 2a9525caabeab6a8d6cd54889d4a2b82505abb20 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Wed, 5 Sep 2018 07:06:25 +0900 Subject: Add `argv` and `argc` check in `OP_ENTER`; fix #4102 `argv` may be retrieved from an array whose `ptr` is `NULL` when it`s empty. --- src/vm.c | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/src/vm.c b/src/vm.c index 43c3d120f..9c4580fb3 100644 --- a/src/vm.c +++ b/src/vm.c @@ -1791,21 +1791,19 @@ RETRY_TRY_BLOCK: kargs = 0; } else { - if (!mrb_hash_p(argv[argc - 1])) { - if (r) { - kdict = mrb_hash_new(mrb); - kargs = 0; - } - else { - mrb_value str = mrb_str_new_lit(mrb, "Excepcted `Hash` as last argument for keyword arguments"); - mrb_exc_set(mrb, mrb_exc_new_str(mrb, E_ARGUMENT_ERROR, str)); - goto L_RAISE; - } + if (argv && argc > 0 && mrb_hash_p(argv[argc-1])) { + kdict = argv[argc-1]; + mrb_hash_check_kdict(mrb, kdict); + } + else if (r) { + kdict = mrb_hash_new(mrb); + kargs = 0; } else { - kdict = argv[argc-1]; + mrb_value str = mrb_str_new_lit(mrb, "Excepcted `Hash` as last argument for keyword arguments"); + mrb_exc_set(mrb, mrb_exc_new_str(mrb, E_ARGUMENT_ERROR, str)); + goto L_RAISE; } - mrb_hash_check_kdict(mrb, kdict); if (MRB_ASPEC_KEY(a) > 0) { kdict = mrb_hash_dup(mrb, kdict); } -- cgit v1.2.3 From b01b0d242b8f36c0a6f2de05126ce9ef87da7fc1 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Wed, 5 Sep 2018 07:58:36 +0900 Subject: Free `mrbc_context` on exit from `mruby`. --- mrbgems/mruby-bin-mruby/tools/mruby/mruby.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/mrbgems/mruby-bin-mruby/tools/mruby/mruby.c b/mrbgems/mruby-bin-mruby/tools/mruby/mruby.c index d9f90c5e1..caf8e78c2 100644 --- a/mrbgems/mruby-bin-mruby/tools/mruby/mruby.c +++ b/mrbgems/mruby-bin-mruby/tools/mruby/mruby.c @@ -258,7 +258,8 @@ main(int argc, char **argv) for (i = 0; i < args.libc; i++) { FILE *lfp = fopen(args.libv[i], args.mrbfile ? "rb" : "r"); if (lfp == NULL) { - printf("Cannot open library file. (%s)\n", args.libv[i]); + printf("Cannot open library file: %s\n", args.libv[i]); + mrbc_context_free(mrb, c); cleanup(mrb, &args); return EXIT_FAILURE; } -- cgit v1.2.3 From 44fdd53f2e5bac6fe1cbc2ceb653aa5f2de965e6 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Wed, 5 Sep 2018 13:30:14 +0900 Subject: Add `mruby-sleep` gem to the core. --- mrbgems/mruby-sleep/.gitignore | 4 + mrbgems/mruby-sleep/.travis.yml | 29 ++++++ mrbgems/mruby-sleep/.travis_build_config.rb | 6 ++ mrbgems/mruby-sleep/README.md | 27 ++++++ mrbgems/mruby-sleep/Rakefile | 29 ++++++ mrbgems/mruby-sleep/example/sleep.rb | 3 + mrbgems/mruby-sleep/mrbgem.rake | 5 + mrbgems/mruby-sleep/src/mrb_sleep.c | 137 ++++++++++++++++++++++++++++ mrbgems/mruby-sleep/src/mrb_sleep.h | 12 +++ mrbgems/mruby-sleep/test/sleep_test.rb | 36 ++++++++ 10 files changed, 288 insertions(+) create mode 100644 mrbgems/mruby-sleep/.gitignore create mode 100644 mrbgems/mruby-sleep/.travis.yml create mode 100644 mrbgems/mruby-sleep/.travis_build_config.rb create mode 100644 mrbgems/mruby-sleep/README.md create mode 100644 mrbgems/mruby-sleep/Rakefile create mode 100644 mrbgems/mruby-sleep/example/sleep.rb create mode 100644 mrbgems/mruby-sleep/mrbgem.rake create mode 100644 mrbgems/mruby-sleep/src/mrb_sleep.c create mode 100644 mrbgems/mruby-sleep/src/mrb_sleep.h create mode 100644 mrbgems/mruby-sleep/test/sleep_test.rb diff --git a/mrbgems/mruby-sleep/.gitignore b/mrbgems/mruby-sleep/.gitignore new file mode 100644 index 000000000..b9f9e71df --- /dev/null +++ b/mrbgems/mruby-sleep/.gitignore @@ -0,0 +1,4 @@ +/mruby + +*.so +*.a \ No newline at end of file diff --git a/mrbgems/mruby-sleep/.travis.yml b/mrbgems/mruby-sleep/.travis.yml new file mode 100644 index 000000000..ad6b007b6 --- /dev/null +++ b/mrbgems/mruby-sleep/.travis.yml @@ -0,0 +1,29 @@ +dist: trusty + +language: c +compiler: + - gcc + - clang +env: + - MRUBY_VERSION=1.2.0 + - MRUBY_VERSION=master +matrix: + allow_failures: + - env: MRUBY_VERSION=master +branches: + only: + - master +addons: + apt: + packages: + - rake + - bison + - git + - gperf + # - aclocal + # - automake + # - autoconf + # - autotools-dev + +script: + - rake test \ No newline at end of file diff --git a/mrbgems/mruby-sleep/.travis_build_config.rb b/mrbgems/mruby-sleep/.travis_build_config.rb new file mode 100644 index 000000000..b32e38a9d --- /dev/null +++ b/mrbgems/mruby-sleep/.travis_build_config.rb @@ -0,0 +1,6 @@ +MRuby::Build.new do |conf| + toolchain :gcc + conf.gembox 'default' + conf.gem '../mruby-sleep' + conf.enable_test +end diff --git a/mrbgems/mruby-sleep/README.md b/mrbgems/mruby-sleep/README.md new file mode 100644 index 000000000..4543c49cf --- /dev/null +++ b/mrbgems/mruby-sleep/README.md @@ -0,0 +1,27 @@ +# Sleep Module for mruby +mruby sleep module + +## install by mrbgems + - add conf.gem line to `build_config.rb` +```ruby +MRuby::Build.new do |conf| + + # ... (snip) ... + + conf.gem :git => 'https://github.com/matsumoto-r/mruby-sleep.git' +end +``` + +## example + +```ruby +Sleep::sleep(10) +Sleep::usleep(10000) +``` + +# License +under the MIT License: + +* http://www.opensource.org/licenses/mit-license.php + + diff --git a/mrbgems/mruby-sleep/Rakefile b/mrbgems/mruby-sleep/Rakefile new file mode 100644 index 000000000..5e3c46173 --- /dev/null +++ b/mrbgems/mruby-sleep/Rakefile @@ -0,0 +1,29 @@ +MRUBY_CONFIG=File.expand_path(ENV["MRUBY_CONFIG"] || ".travis_build_config.rb") +MRUBY_VERSION=ENV["MRUBY_VERSION"] || "1.2.0" + +file :mruby do + cmd = "git clone --depth=1 git://github.com/mruby/mruby.git" + if MRUBY_VERSION != 'master' + cmd << " && cd mruby" + cmd << " && git fetch --tags && git checkout $(git rev-parse #{MRUBY_VERSION})" + end + sh cmd +end + +desc "compile binary" +task :compile => :mruby do + sh "cd mruby && MRUBY_CONFIG=#{MRUBY_CONFIG} rake all" +end + +desc "test" +task :test => :mruby do + sh "cd mruby && MRUBY_CONFIG=#{MRUBY_CONFIG} rake all test" +end + +desc "cleanup" +task :clean do + exit 0 unless File.directory?('mruby') + sh "cd mruby && rake deep_clean" +end + +task :default => :compile diff --git a/mrbgems/mruby-sleep/example/sleep.rb b/mrbgems/mruby-sleep/example/sleep.rb new file mode 100644 index 000000000..dfe86af27 --- /dev/null +++ b/mrbgems/mruby-sleep/example/sleep.rb @@ -0,0 +1,3 @@ +Sleep::sleep(10) +Sleep::usleep(10000) + diff --git a/mrbgems/mruby-sleep/mrbgem.rake b/mrbgems/mruby-sleep/mrbgem.rake new file mode 100644 index 000000000..8827b3580 --- /dev/null +++ b/mrbgems/mruby-sleep/mrbgem.rake @@ -0,0 +1,5 @@ +MRuby::Gem::Specification.new('mruby-sleep') do |spec| + spec.license = 'MIT' + spec.authors = 'MATSUMOTO Ryosuke' + spec.version = '0.0.1' +end diff --git a/mrbgems/mruby-sleep/src/mrb_sleep.c b/mrbgems/mruby-sleep/src/mrb_sleep.c new file mode 100644 index 000000000..b711dd5c9 --- /dev/null +++ b/mrbgems/mruby-sleep/src/mrb_sleep.c @@ -0,0 +1,137 @@ +/* +** mrb_sleep - sleep class for mruby +** +** Copyright (c) mod_mruby developers 2012- +** +** Permission is hereby granted, free of charge, to any person obtaining +** a copy of this software and associated documentation files (the +** "Software"), to deal in the Software without restriction, including +** without limitation the rights to use, copy, modify, merge, publish, +** distribute, sublicense, and/or sell copies of the Software, and to +** permit persons to whom the Software is furnished to do so, subject to +** the following conditions: +** +** The above copyright notice and this permission notice shall be +** included in all copies or substantial portions of the Software. +** +** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +** SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +** +** [ MIT license: http://www.opensource.org/licenses/mit-license.php ] +*/ + +#include +#ifdef _WIN32 + #include + #define sleep(x) Sleep(x * 1000) + #define usleep(x) Sleep(((x)<1000) ? 1 : ((x)/1000)) +#else + #include + #include +#endif + +#include "mruby.h" + +mrb_value mrb_f_sleep_sleep(mrb_state *mrb, mrb_value self) +{ + time_t beg, end; + mrb_value *argv; + mrb_int argc; + int iargc; + + beg = time(0); + mrb_get_args(mrb, "*", &argv, &argc); + + iargc = (int)argc; + + /* not implemented forever sleep (called without an argument)*/ + if (iargc == 0 || iargc >= 2) { + mrb_raise(mrb, E_ARGUMENT_ERROR, "wrong number of arguments"); + } + + if (mrb_fixnum_p(argv[0]) && mrb_fixnum(argv[0]) >= 0) { + sleep(mrb_fixnum(argv[0])); + } else { + mrb_raise(mrb, E_ARGUMENT_ERROR, "time interval must be positive integer"); + } + end = time(0) - beg; + + return mrb_fixnum_value(end); +} + +mrb_value mrb_f_usleep_usleep(mrb_state *mrb, mrb_value self) +{ + mrb_int argc; + mrb_value *argv; +#ifdef _WIN32 + FILETIME st_ft,ed_ft; + unsigned __int64 st_time = 0; + unsigned __int64 ed_time = 0; +#else + struct timeval st_tm,ed_tm; +#endif + time_t slp_tm; + +#ifdef _WIN32 + GetSystemTimeAsFileTime(&st_ft); +#else + gettimeofday( &st_tm, NULL ); +#endif + + mrb_get_args(mrb, "*", &argv, &argc); + + /* not implemented forever sleep (called without an argument)*/ + if(argc == 0 || argc >= 2) { + mrb_raise(mrb, E_ARGUMENT_ERROR, "wrong number of arguments"); + } + + if (mrb_fixnum_p(argv[0]) && mrb_fixnum(argv[0]) >= 0) { + usleep(mrb_fixnum(argv[0])); + } else { + mrb_raise(mrb, E_ARGUMENT_ERROR, "time interval must be positive integer"); + } + +#ifdef _WIN32 + GetSystemTimeAsFileTime(&ed_ft); + + st_time |= st_ft.dwHighDateTime; + st_time <<=32; + st_time |= st_ft.dwLowDateTime; + ed_time |= ed_ft.dwHighDateTime; + ed_time <<=32; + ed_time |= ed_ft.dwLowDateTime; + + slp_tm = (ed_time - st_time) / 10; +#else + gettimeofday( &ed_tm, NULL ); + + if ( st_tm.tv_usec > ed_tm.tv_usec ) { + slp_tm = 1000000 + ed_tm.tv_usec - st_tm.tv_usec; + } else { + slp_tm = ed_tm.tv_usec - st_tm.tv_usec; + } +#endif + + return mrb_fixnum_value(slp_tm); +} + +void mrb_mruby_sleep_gem_init(mrb_state *mrb) +{ + struct RClass *sleep; + + sleep = mrb_define_module(mrb, "Sleep"); + mrb_define_class_method(mrb, sleep, "sleep", mrb_f_sleep_sleep, MRB_ARGS_REQ(1)); + mrb_define_class_method(mrb, sleep, "usleep", mrb_f_usleep_usleep, MRB_ARGS_REQ(1)); + + mrb_define_method(mrb, mrb->kernel_module, "sleep", mrb_f_sleep_sleep, MRB_ARGS_REQ(1)); + mrb_define_method(mrb, mrb->kernel_module, "usleep", mrb_f_usleep_usleep, MRB_ARGS_REQ(1)); +} + +void mrb_mruby_sleep_gem_final(mrb_state *mrb) +{ +} diff --git a/mrbgems/mruby-sleep/src/mrb_sleep.h b/mrbgems/mruby-sleep/src/mrb_sleep.h new file mode 100644 index 000000000..bf71d91f4 --- /dev/null +++ b/mrbgems/mruby-sleep/src/mrb_sleep.h @@ -0,0 +1,12 @@ +/* +// mrb_sleep.h - to provide sleep methods +// +// See Copyright Notice in mrb_sleep.c +*/ + +#ifndef MRB_SLEEP_H +#define MRB_SLEEP_H + +void mrb_mruby_sleep_gem_init(mrb_state *mrb); + +#endif diff --git a/mrbgems/mruby-sleep/test/sleep_test.rb b/mrbgems/mruby-sleep/test/sleep_test.rb new file mode 100644 index 000000000..e5ea5f69e --- /dev/null +++ b/mrbgems/mruby-sleep/test/sleep_test.rb @@ -0,0 +1,36 @@ +def run_with_catching_error &b + e = nil + begin + b.call + rescue => _e + e = _e + end + + return e +end + +assert("sleep works") do + e = run_with_catching_error { sleep 1 } + + assert_nil e +end + +assert("sleep would not accept negative value") do + e = run_with_catching_error { sleep -1 } + + assert_not_equal e, nil + assert_equal e.class, ArgumentError +end + +assert("usleep works") do + e = run_with_catching_error { usleep 100 } + + assert_nil e +end + +assert("usleep would not accept negative value") do + e = run_with_catching_error { usleep -100 } + + assert_not_equal e, nil + assert_equal e.class, ArgumentError +end -- cgit v1.2.3 From a170c1dd7072120ba2c2cae8e1ed23bdd4b7b532 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Wed, 5 Sep 2018 14:54:14 +0900 Subject: Refactored `mruby-sleep` gem. * Method implementation functions made `static`. * Function declaration style has been changed. * Unnecessary header file `mrb_sleep.h` removed. * Used `mrb_get_args()` instead of self parsing. * Indentation kept untouched. --- mrbgems/mruby-sleep/src/mrb_sleep.c | 65 ++++++++++++++++--------------------- mrbgems/mruby-sleep/src/mrb_sleep.h | 12 ------- 2 files changed, 28 insertions(+), 49 deletions(-) delete mode 100644 mrbgems/mruby-sleep/src/mrb_sleep.h diff --git a/mrbgems/mruby-sleep/src/mrb_sleep.c b/mrbgems/mruby-sleep/src/mrb_sleep.c index b711dd5c9..19a4f082f 100644 --- a/mrbgems/mruby-sleep/src/mrb_sleep.c +++ b/mrbgems/mruby-sleep/src/mrb_sleep.c @@ -37,25 +37,17 @@ #include "mruby.h" -mrb_value mrb_f_sleep_sleep(mrb_state *mrb, mrb_value self) -{ +static mrb_value +mrb_f_sleep(mrb_state *mrb, mrb_value self) +{ time_t beg, end; - mrb_value *argv; - mrb_int argc; - int iargc; - + mrb_int sec; + beg = time(0); - mrb_get_args(mrb, "*", &argv, &argc); - - iargc = (int)argc; - /* not implemented forever sleep (called without an argument)*/ - if (iargc == 0 || iargc >= 2) { - mrb_raise(mrb, E_ARGUMENT_ERROR, "wrong number of arguments"); - } - - if (mrb_fixnum_p(argv[0]) && mrb_fixnum(argv[0]) >= 0) { - sleep(mrb_fixnum(argv[0])); + mrb_get_args(mrb, "i", &sec); + if (sec >= 0) { + sleep(sec); } else { mrb_raise(mrb, E_ARGUMENT_ERROR, "time interval must be positive integer"); } @@ -64,10 +56,10 @@ mrb_value mrb_f_sleep_sleep(mrb_state *mrb, mrb_value self) return mrb_fixnum_value(end); } -mrb_value mrb_f_usleep_usleep(mrb_state *mrb, mrb_value self) -{ - mrb_int argc; - mrb_value *argv; +static mrb_value +mrb_f_usleep(mrb_state *mrb, mrb_value self) +{ + mrb_int usec; #ifdef _WIN32 FILETIME st_ft,ed_ft; unsigned __int64 st_time = 0; @@ -80,18 +72,14 @@ mrb_value mrb_f_usleep_usleep(mrb_state *mrb, mrb_value self) #ifdef _WIN32 GetSystemTimeAsFileTime(&st_ft); #else - gettimeofday( &st_tm, NULL ); + gettimeofday(&st_tm, NULL); #endif - mrb_get_args(mrb, "*", &argv, &argc); - /* not implemented forever sleep (called without an argument)*/ - if(argc == 0 || argc >= 2) { - mrb_raise(mrb, E_ARGUMENT_ERROR, "wrong number of arguments"); - } + mrb_get_args(mrb, "i", &usec); - if (mrb_fixnum_p(argv[0]) && mrb_fixnum(argv[0]) >= 0) { - usleep(mrb_fixnum(argv[0])); + if (usec >= 0) { + usleep(usec); } else { mrb_raise(mrb, E_ARGUMENT_ERROR, "time interval must be positive integer"); } @@ -108,11 +96,12 @@ mrb_value mrb_f_usleep_usleep(mrb_state *mrb, mrb_value self) slp_tm = (ed_time - st_time) / 10; #else - gettimeofday( &ed_tm, NULL ); + gettimeofday(&ed_tm, NULL); - if ( st_tm.tv_usec > ed_tm.tv_usec ) { + if (st_tm.tv_usec > ed_tm.tv_usec) { slp_tm = 1000000 + ed_tm.tv_usec - st_tm.tv_usec; - } else { + } + else { slp_tm = ed_tm.tv_usec - st_tm.tv_usec; } #endif @@ -120,18 +109,20 @@ mrb_value mrb_f_usleep_usleep(mrb_state *mrb, mrb_value self) return mrb_fixnum_value(slp_tm); } -void mrb_mruby_sleep_gem_init(mrb_state *mrb) +void +mrb_mruby_sleep_gem_init(mrb_state *mrb) { struct RClass *sleep; sleep = mrb_define_module(mrb, "Sleep"); - mrb_define_class_method(mrb, sleep, "sleep", mrb_f_sleep_sleep, MRB_ARGS_REQ(1)); - mrb_define_class_method(mrb, sleep, "usleep", mrb_f_usleep_usleep, MRB_ARGS_REQ(1)); + mrb_define_class_method(mrb, sleep, "sleep", mrb_f_sleep, MRB_ARGS_REQ(1)); + mrb_define_class_method(mrb, sleep, "usleep", mrb_f_usleep, MRB_ARGS_REQ(1)); - mrb_define_method(mrb, mrb->kernel_module, "sleep", mrb_f_sleep_sleep, MRB_ARGS_REQ(1)); - mrb_define_method(mrb, mrb->kernel_module, "usleep", mrb_f_usleep_usleep, MRB_ARGS_REQ(1)); + mrb_define_method(mrb, mrb->kernel_module, "sleep", mrb_f_sleep, MRB_ARGS_REQ(1)); + mrb_define_method(mrb, mrb->kernel_module, "usleep", mrb_f_usleep, MRB_ARGS_REQ(1)); } -void mrb_mruby_sleep_gem_final(mrb_state *mrb) +void +mrb_mruby_sleep_gem_final(mrb_state *mrb) { } diff --git a/mrbgems/mruby-sleep/src/mrb_sleep.h b/mrbgems/mruby-sleep/src/mrb_sleep.h deleted file mode 100644 index bf71d91f4..000000000 --- a/mrbgems/mruby-sleep/src/mrb_sleep.h +++ /dev/null @@ -1,12 +0,0 @@ -/* -// mrb_sleep.h - to provide sleep methods -// -// See Copyright Notice in mrb_sleep.c -*/ - -#ifndef MRB_SLEEP_H -#define MRB_SLEEP_H - -void mrb_mruby_sleep_gem_init(mrb_state *mrb); - -#endif -- cgit v1.2.3 From 4cd4c64266e7d9075b09e66c4f7b3546a76120f4 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Thu, 6 Sep 2018 14:40:21 +0900 Subject: Need to support multiple `**` splats in argument list; fix #4106 --- mrbgems/mruby-compiler/core/codegen.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mrbgems/mruby-compiler/core/codegen.c b/mrbgems/mruby-compiler/core/codegen.c index 98b215f6b..8be9a8ebe 100644 --- a/mrbgems/mruby-compiler/core/codegen.c +++ b/mrbgems/mruby-compiler/core/codegen.c @@ -1786,7 +1786,7 @@ codegen(codegen_scope *s, node *tree, int val) push(); } codegen(s, tree->car->cdr, VAL); - if (len > 0) { + if (len > 0 || update) { pop(); pop(); genop_1(s, OP_HASHCAT, cursp()); push(); -- cgit v1.2.3 From 0b44e802a95101bb7c5849382d669cf6cf4f2680 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Thu, 6 Sep 2018 23:30:32 +0900 Subject: Need to check if merging hash is empty; fix #4107 --- src/hash.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/hash.c b/src/hash.c index 7d81bc343..f6b61f4e1 100644 --- a/src/hash.c +++ b/src/hash.c @@ -969,6 +969,7 @@ mrb_hash_merge(mrb_state *mrb, mrb_value hash1, mrb_value hash2) h1 = RHASH_TBL(hash1); h2 = RHASH_TBL(hash2); + if (!h2) return; if (!h1) { RHASH_TBL(hash1) = kh_copy(ht, mrb, h2); return; -- cgit v1.2.3 From 72522f8e0ecd7a94af4df0cf7c892fb5ed971deb Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Thu, 6 Sep 2018 23:33:53 +0900 Subject: Remove `Sleep` module that does not exist in CRuby. --- mrbgems/mruby-sleep/src/mrb_sleep.c | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/mrbgems/mruby-sleep/src/mrb_sleep.c b/mrbgems/mruby-sleep/src/mrb_sleep.c index 19a4f082f..37d18e482 100644 --- a/mrbgems/mruby-sleep/src/mrb_sleep.c +++ b/mrbgems/mruby-sleep/src/mrb_sleep.c @@ -1,5 +1,5 @@ /* -** mrb_sleep - sleep class for mruby +** mrb_sleep - sleep methods for mruby ** ** Copyright (c) mod_mruby developers 2012- ** @@ -112,12 +112,6 @@ mrb_f_usleep(mrb_state *mrb, mrb_value self) void mrb_mruby_sleep_gem_init(mrb_state *mrb) { - struct RClass *sleep; - - sleep = mrb_define_module(mrb, "Sleep"); - mrb_define_class_method(mrb, sleep, "sleep", mrb_f_sleep, MRB_ARGS_REQ(1)); - mrb_define_class_method(mrb, sleep, "usleep", mrb_f_usleep, MRB_ARGS_REQ(1)); - mrb_define_method(mrb, mrb->kernel_module, "sleep", mrb_f_sleep, MRB_ARGS_REQ(1)); mrb_define_method(mrb, mrb->kernel_module, "usleep", mrb_f_usleep, MRB_ARGS_REQ(1)); } -- cgit v1.2.3 From fdaec907802c11867e977b30b2e1dddcb7a0ebcd Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Thu, 6 Sep 2018 23:42:05 +0900 Subject: Make `Kernel#sleep` to accept float as a duration time. But when `MRB_WITHOUT_FLOAT` is set, there's no way to sleep for sub seconds. So mruby specific `usleep` is provided. --- mrbgems/mruby-sleep/src/mrb_sleep.c | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/mrbgems/mruby-sleep/src/mrb_sleep.c b/mrbgems/mruby-sleep/src/mrb_sleep.c index 37d18e482..ce643cf12 100644 --- a/mrbgems/mruby-sleep/src/mrb_sleep.c +++ b/mrbgems/mruby-sleep/src/mrb_sleep.c @@ -37,25 +37,38 @@ #include "mruby.h" +/* not implemented forever sleep (called without an argument)*/ static mrb_value mrb_f_sleep(mrb_state *mrb, mrb_value self) { - time_t beg, end; + time_t beg = time(0); + time_t end; +#ifndef MRB_WITHOUT_FLOAT + mrb_float sec; + + mrb_get_args(mrb, "f", &sec); + if (sec >= 0) { + usleep(sec * 1000000); + } + else { + mrb_raise(mrb, E_ARGUMENT_ERROR, "time interval must be positive integer"); + } +#else mrb_int sec; - beg = time(0); - /* not implemented forever sleep (called without an argument)*/ mrb_get_args(mrb, "i", &sec); if (sec >= 0) { sleep(sec); } else { mrb_raise(mrb, E_ARGUMENT_ERROR, "time interval must be positive integer"); } +#endif end = time(0) - beg; return mrb_fixnum_value(end); } +/* mruby special; needed for mruby without float numbers */ static mrb_value mrb_f_usleep(mrb_state *mrb, mrb_value self) { -- cgit v1.2.3 From 04f8b0431cdad550c51ea8633c70ab62c37f1ead Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Fri, 7 Sep 2018 02:15:55 +0900 Subject: Fix heap buffer overflow in `unpack_a`; fix #4103 --- mrbgems/mruby-pack/src/pack.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/mrbgems/mruby-pack/src/pack.c b/mrbgems/mruby-pack/src/pack.c index 841a98f58..1b88d8736 100644 --- a/mrbgems/mruby-pack/src/pack.c +++ b/mrbgems/mruby-pack/src/pack.c @@ -598,19 +598,21 @@ unpack_a(mrb_state *mrb, const void *src, int slen, mrb_value ary, long count, u } copylen = slen; - if (flags & PACK_FLAG_Z) { /* "Z" */ + if (slen >= 0 && flags & PACK_FLAG_Z) { /* "Z" */ if ((cp = (const char *)memchr(sptr, '\0', slen)) != NULL) { copylen = (int)(cp - sptr); if (count == -1) { slen = copylen + 1; } } - } else if (!(flags & PACK_FLAG_a)) { /* "A" */ + } + else if (!(flags & PACK_FLAG_a)) { /* "A" */ while (copylen > 0 && (sptr[copylen - 1] == '\0' || isspace(sptr[copylen - 1]))) { copylen--; } } + if (copylen < 0) copylen = 0; dst = mrb_str_new(mrb, sptr, (mrb_int)copylen); mrb_ary_push(mrb, ary, dst); return slen; -- cgit v1.2.3 From 3447162a4c5f1e5e7a1206deaacd8cb6ad2d3897 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Fri, 7 Sep 2018 02:16:56 +0900 Subject: Add a new method `unpack1` to `mruby-pack` gem. --- mrbgems/mruby-pack/src/pack.c | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/mrbgems/mruby-pack/src/pack.c b/mrbgems/mruby-pack/src/pack.c index 1b88d8736..850462830 100644 --- a/mrbgems/mruby-pack/src/pack.c +++ b/mrbgems/mruby-pack/src/pack.c @@ -1190,7 +1190,7 @@ mrb_pack_pack(mrb_state *mrb, mrb_value ary) } static mrb_value -mrb_pack_unpack(mrb_state *mrb, mrb_value str) +pack_unpack(mrb_state *mrb, mrb_value str, int single) { mrb_value result; struct tmpl tmpl; @@ -1272,11 +1272,25 @@ mrb_pack_unpack(mrb_state *mrb, mrb_value str) count--; } } + if (single) break; } + if (single) return RARRAY_PTR(result)[0]; return result; } +static mrb_value +mrb_pack_unpack(mrb_state *mrb, mrb_value str) +{ + return pack_unpack(mrb, str, 0); +} + +static mrb_value +mrb_pack_unpack1(mrb_state *mrb, mrb_value str) +{ + return pack_unpack(mrb, str, 1); +} + void mrb_mruby_pack_gem_init(mrb_state *mrb) { @@ -1285,6 +1299,7 @@ mrb_mruby_pack_gem_init(mrb_state *mrb) mrb_define_method(mrb, mrb->array_class, "pack", mrb_pack_pack, MRB_ARGS_REQ(1)); mrb_define_method(mrb, mrb->string_class, "unpack", mrb_pack_unpack, MRB_ARGS_REQ(1)); + mrb_define_method(mrb, mrb->string_class, "unpack1", mrb_pack_unpack1, MRB_ARGS_REQ(1)); } void -- cgit v1.2.3 From 625976d7931006bae7e960e561ecdaccb0cb6a28 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Fri, 7 Sep 2018 03:16:44 +0900 Subject: Fix integer overflow issue; fix #4108 I misunderstood the return value from `snprintf()`, which is NOT number of characters written in buffer, but the number of character the buffer has to have to write the complete output. --- mrbgems/mruby-sprintf/src/sprintf.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/mrbgems/mruby-sprintf/src/sprintf.c b/mrbgems/mruby-sprintf/src/sprintf.c index 738c5485f..ea127c574 100644 --- a/mrbgems/mruby-sprintf/src/sprintf.c +++ b/mrbgems/mruby-sprintf/src/sprintf.c @@ -1057,17 +1057,21 @@ retry: need = BIT_DIGITS(i); } need += (flags&FPREC) ? prec : 6; + if (need < 0) { + too_big_width: + mrb_raise(mrb, E_ARGUMENT_ERROR, + (width > prec ? "width too big" : "prec too big")); + } if ((flags&FWIDTH) && need < width) need = width; need += 20; if (need <= 0) { - mrb_raise(mrb, E_ARGUMENT_ERROR, - (width > prec ? "width too big" : "prec too big")); + goto too_big_width; } CHECK(need); n = snprintf(&buf[blen], need, fbuf, fval); - if (n < 0) { + if (n < 0 || n >= need) { mrb_raise(mrb, E_RUNTIME_ERROR, "formatting error"); } blen += n; -- cgit v1.2.3 From 9da9e5eb4e4f0bde1279055b8f7cc1d265cfbc8a Mon Sep 17 00:00:00 2001 From: dearblue Date: Mon, 3 Sep 2018 00:04:11 +0900 Subject: Fix typo for concatenate --- include/mruby/string.h | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/include/mruby/string.h b/include/mruby/string.h index 975b1fe0d..481b2fb38 100644 --- a/include/mruby/string.h +++ b/include/mruby/string.h @@ -102,7 +102,7 @@ MRB_API mrb_int mrb_str_index(mrb_state*, mrb_value, const char*, mrb_int, mrb_i #define mrb_str_index_lit(mrb, str, lit, off) mrb_str_index(mrb, str, lit, mrb_strlen_lit(lit), off); /* - * Appends self to other. Returns self as a concatnated string. + * Appends self to other. Returns self as a concatenated string. * * * Example: @@ -126,10 +126,10 @@ MRB_API mrb_int mrb_str_index(mrb_state*, mrb_value, const char*, mrb_int, mrb_i * str1 = mrb_str_new_lit(mrb, "abc"); * str2 = mrb_str_new_lit(mrb, "def"); * - * // Concatnates str2 to str1. + * // Concatenates str2 to str1. * mrb_str_concat(mrb, str1, str2); * - * // Prints new Concatnated Ruby string. + * // Prints new Concatenated Ruby string. * mrb_p(mrb, str1); * * mrb_close(mrb); @@ -178,10 +178,10 @@ MRB_API void mrb_str_concat(mrb_state*, mrb_value, mrb_value); * mrb_p(mrb, a); * mrb_p(mrb, b); * - * // Concatnates both Ruby strings. + * // Concatenates both Ruby strings. * c = mrb_str_plus(mrb, a, b); * - * // Prints new Concatnated Ruby string. + * // Prints new Concatenated Ruby string. * mrb_p(mrb, c); * * mrb_close(mrb); @@ -193,7 +193,7 @@ MRB_API void mrb_str_concat(mrb_state*, mrb_value, mrb_value); * * => "abc" # First string * => "def" # Second string - * => "abcdef" # First & Second concatnated. + * => "abcdef" # First & Second concatenated. * * @param [mrb_state] mrb The current mruby state. * @param [mrb_value] a First string to concatenate. -- cgit v1.2.3 From 2a24b40d300b1e0072a4a0f7de43b126479bc390 Mon Sep 17 00:00:00 2001 From: dearblue Date: Wed, 5 Sep 2018 22:13:46 +0900 Subject: Not set a class/module name into anonymous class/module --- src/variable.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/variable.c b/src/variable.c index 00bdb4b8d..4bb3e4bef 100644 --- a/src/variable.c +++ b/src/variable.c @@ -1069,8 +1069,10 @@ mrb_class_find_path(mrb_state *mrb, struct RClass *c) str = mrb_sym2name_len(mrb, name, &len); mrb_str_cat(mrb, path, str, len); - iv_del(mrb, c->iv, mrb_intern_lit(mrb, "__outer__"), NULL); - iv_put(mrb, c->iv, mrb_intern_lit(mrb, "__classname__"), path); - mrb_field_write_barrier_value(mrb, (struct RBasic*)c, path); + if (RSTRING_PTR(path)[0] != '#') { + iv_del(mrb, c->iv, mrb_intern_lit(mrb, "__outer__"), NULL); + iv_put(mrb, c->iv, mrb_intern_lit(mrb, "__classname__"), path); + mrb_field_write_barrier_value(mrb, (struct RBasic*)c, path); + } return path; } -- cgit v1.2.3 From fd57af3ea4628dbb688e4380b12ac2bb06de4f5f Mon Sep 17 00:00:00 2001 From: dearblue Date: Wed, 5 Sep 2018 20:09:30 +0900 Subject: Undesirable line split --- src/class.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/class.c b/src/class.c index 22fe36fb3..76c699881 100644 --- a/src/class.c +++ b/src/class.c @@ -2254,8 +2254,7 @@ mrb_init_class(mrb_state *mrb) mrb_define_method(mrb, mod, "const_set", mrb_mod_const_set, MRB_ARGS_REQ(2)); /* 15.2.2.4.23 */ mrb_define_method(mrb, mod, "remove_const", mrb_mod_remove_const, MRB_ARGS_REQ(1)); /* 15.2.2.4.40 */ mrb_define_method(mrb, mod, "const_missing", mrb_mod_const_missing, MRB_ARGS_REQ(1)); - mrb_define_method(mrb, mod, "method_defined?", mrb_mod_method_defined, MRB_ARGS_REQ(1)); /* 15.2.2.4 -.34 */ + mrb_define_method(mrb, mod, "method_defined?", mrb_mod_method_defined, MRB_ARGS_REQ(1)); /* 15.2.2.4.34 */ mrb_define_method(mrb, mod, "define_method", mod_define_method, MRB_ARGS_ARG(1,1)); mrb_define_method(mrb, mod, "===", mrb_mod_eqq, MRB_ARGS_REQ(1)); -- cgit v1.2.3 From 9b0ef58a48aced26538f3f9ed2490ce34e2e5840 Mon Sep 17 00:00:00 2001 From: dearblue Date: Thu, 6 Sep 2018 00:09:49 +0900 Subject: A class/module name is now defined for meta programing --- src/variable.c | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/src/variable.c b/src/variable.c index 4bb3e4bef..a2d002892 100644 --- a/src/variable.c +++ b/src/variable.c @@ -344,6 +344,8 @@ mrb_iv_get(mrb_state *mrb, mrb_value obj, mrb_sym sym) return mrb_nil_value(); } +static inline void assign_class_name(mrb_state *mrb, struct RObject *obj, mrb_sym sym, mrb_value v); + MRB_API void mrb_obj_iv_set(mrb_state *mrb, struct RObject *obj, mrb_sym sym, mrb_value v) { @@ -352,6 +354,7 @@ mrb_obj_iv_set(mrb_state *mrb, struct RObject *obj, mrb_sym sym, mrb_value v) if (MRB_FROZEN_P(obj)) { mrb_raisef(mrb, E_FROZEN_ERROR, "can't modify frozen %S", mrb_obj_value(obj)); } + assign_class_name(mrb, obj, sym, v); if (!obj->iv) { obj->iv = iv_new(mrb); } @@ -360,6 +363,36 @@ mrb_obj_iv_set(mrb_state *mrb, struct RObject *obj, mrb_sym sym, mrb_value v) mrb_write_barrier(mrb, (struct RBasic*)obj); } +static inline mrb_bool +is_namespace(enum mrb_vtype tt) +{ + return tt == MRB_TT_CLASS || tt == MRB_TT_MODULE ? TRUE : FALSE; +} + +static inline void +assign_class_name(mrb_state *mrb, struct RObject *obj, mrb_sym sym, mrb_value v) +{ + if (is_namespace(obj->tt) && is_namespace(mrb_type(v)) && ISUPPER(mrb_sym2name(mrb, sym)[0])) { + struct RObject *c = mrb_obj_ptr(v); + mrb_sym id_classname = mrb_intern_lit(mrb, "__classname__"); + mrb_value o = mrb_obj_iv_get(mrb, c, id_classname); + + if (mrb_nil_p(o)) { + mrb_sym id_outer = mrb_intern_lit(mrb, "__outer__"); + o = mrb_obj_iv_get(mrb, c, id_outer); + + if (mrb_nil_p(o)) { + if ((struct RClass *)obj == mrb->object_class) { + mrb_obj_iv_set(mrb, c, id_classname, mrb_symbol_value(sym)); + } + else { + mrb_obj_iv_set(mrb, c, id_outer, mrb_obj_value(obj)); + } + } + } + } +} + MRB_API void mrb_iv_set(mrb_state *mrb, mrb_value obj, mrb_sym sym, mrb_value v) { -- cgit v1.2.3 From 1595e8368a561680f8472f2e9f5fb363dcb135b4 Mon Sep 17 00:00:00 2001 From: dearblue Date: Fri, 7 Sep 2018 00:02:46 +0900 Subject: Fix indent --- src/symbol.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/symbol.c b/src/symbol.c index 5e1f9f561..6b4c7200c 100644 --- a/src/symbol.c +++ b/src/symbol.c @@ -387,8 +387,8 @@ id: switch (*m) { case '!': case '?': case '=': ++m; default: break; - } } + } break; } return *m ? FALSE : TRUE; -- cgit v1.2.3 From 1997fcf98f596f6af2bf1d20ccde1b1abfe7324d Mon Sep 17 00:00:00 2001 From: dearblue Date: Fri, 7 Sep 2018 22:00:18 +0900 Subject: Add MRB_IMPROVE_META_PROGRAMMING configuration --- include/mrbconf.h | 3 +++ src/variable.c | 10 ++++++++++ 2 files changed, 13 insertions(+) diff --git a/include/mrbconf.h b/include/mrbconf.h index cc28acfaa..379386896 100644 --- a/include/mrbconf.h +++ b/include/mrbconf.h @@ -110,6 +110,9 @@ /* fixed size state atexit stack */ //#define MRB_FIXED_STATE_ATEXIT_STACK +/* improve meta programming support */ +//#define MRB_IMPROVE_META_PROGRAMMING + /* -DMRB_DISABLE_XXXX to drop following features */ //#define MRB_DISABLE_STDIO /* use of stdio */ diff --git a/src/variable.c b/src/variable.c index a2d002892..047c96e8a 100644 --- a/src/variable.c +++ b/src/variable.c @@ -344,7 +344,9 @@ mrb_iv_get(mrb_state *mrb, mrb_value obj, mrb_sym sym) return mrb_nil_value(); } +#ifdef MRB_IMPROVE_META_PROGRAMMING static inline void assign_class_name(mrb_state *mrb, struct RObject *obj, mrb_sym sym, mrb_value v); +#endif MRB_API void mrb_obj_iv_set(mrb_state *mrb, struct RObject *obj, mrb_sym sym, mrb_value v) @@ -354,7 +356,9 @@ mrb_obj_iv_set(mrb_state *mrb, struct RObject *obj, mrb_sym sym, mrb_value v) if (MRB_FROZEN_P(obj)) { mrb_raisef(mrb, E_FROZEN_ERROR, "can't modify frozen %S", mrb_obj_value(obj)); } +#ifdef MRB_IMPROVE_META_PROGRAMMING assign_class_name(mrb, obj, sym, v); +#endif if (!obj->iv) { obj->iv = iv_new(mrb); } @@ -363,6 +367,7 @@ mrb_obj_iv_set(mrb_state *mrb, struct RObject *obj, mrb_sym sym, mrb_value v) mrb_write_barrier(mrb, (struct RBasic*)obj); } +#ifdef MRB_IMPROVE_META_PROGRAMMING static inline mrb_bool is_namespace(enum mrb_vtype tt) { @@ -392,6 +397,7 @@ assign_class_name(mrb_state *mrb, struct RObject *obj, mrb_sym sym, mrb_value v) } } } +#endif MRB_API void mrb_iv_set(mrb_state *mrb, mrb_value obj, mrb_sym sym, mrb_value v) @@ -1102,10 +1108,14 @@ mrb_class_find_path(mrb_state *mrb, struct RClass *c) str = mrb_sym2name_len(mrb, name, &len); mrb_str_cat(mrb, path, str, len); +#ifdef MRB_IMPROVE_META_PROGRAMMING if (RSTRING_PTR(path)[0] != '#') { +#endif iv_del(mrb, c->iv, mrb_intern_lit(mrb, "__outer__"), NULL); iv_put(mrb, c->iv, mrb_intern_lit(mrb, "__classname__"), path); mrb_field_write_barrier_value(mrb, (struct RBasic*)c, path); +#ifdef MRB_IMPROVE_META_PROGRAMMING } +#endif return path; } -- cgit v1.2.3 From 366848996a6cce8e733246bce6c3f76d797003bb Mon Sep 17 00:00:00 2001 From: dearblue Date: Fri, 7 Sep 2018 00:22:36 +0900 Subject: Clear terminated space --- examples/targets/build_config_android_arm64-v8a.rb | 4 ++-- examples/targets/build_config_android_armeabi.rb | 4 ++-- mrbgems/mruby-array-ext/test/array.rb | 2 +- mrbgems/mruby-compiler/core/codegen.c | 8 ++++---- mrbgems/mruby-random/src/random.c | 2 +- src/array.c | 2 +- src/codedump.c | 2 +- src/gc.c | 2 +- src/numeric.c | 2 +- src/variable.c | 10 +++++----- src/vm.c | 4 ++-- tasks/toolchains/gcc.rake | 2 +- test/t/kernel.rb | 2 +- test/t/syntax.rb | 6 +++--- 14 files changed, 26 insertions(+), 26 deletions(-) diff --git a/examples/targets/build_config_android_arm64-v8a.rb b/examples/targets/build_config_android_arm64-v8a.rb index 6188c13ec..70b0f4b97 100644 --- a/examples/targets/build_config_android_arm64-v8a.rb +++ b/examples/targets/build_config_android_arm64-v8a.rb @@ -15,8 +15,8 @@ end # Requires Android NDK r13 or later. MRuby::CrossBuild.new('android-arm64-v8a') do |conf| - params = { - :arch => 'arm64-v8a', + params = { + :arch => 'arm64-v8a', :platform => 'android-24', :toolchain => :clang, } diff --git a/examples/targets/build_config_android_armeabi.rb b/examples/targets/build_config_android_armeabi.rb index b7eb33a92..17330242a 100644 --- a/examples/targets/build_config_android_armeabi.rb +++ b/examples/targets/build_config_android_armeabi.rb @@ -15,8 +15,8 @@ end # Requires Android NDK r13 or later. MRuby::CrossBuild.new('android-armeabi') do |conf| - params = { - :arch => 'armeabi', + params = { + :arch => 'armeabi', :platform => 'android-24', :toolchain => :clang, } diff --git a/mrbgems/mruby-array-ext/test/array.rb b/mrbgems/mruby-array-ext/test/array.rb index 7d810acc2..4f54c65c3 100644 --- a/mrbgems/mruby-array-ext/test/array.rb +++ b/mrbgems/mruby-array-ext/test/array.rb @@ -418,5 +418,5 @@ assert('Array#transpose') do assert_equal([[1], [2], [3]].transpose, [[1,2,3]]) assert_equal([[1,2], [3,4], [5,6]].transpose, [[1,3,5], [2,4,6]]) assert_raise(TypeError) { [1].transpose } - assert_raise(IndexError) { [[1], [2,3,4]].transpose } + assert_raise(IndexError) { [[1], [2,3,4]].transpose } end diff --git a/mrbgems/mruby-compiler/core/codegen.c b/mrbgems/mruby-compiler/core/codegen.c index 8be9a8ebe..74504ffd1 100644 --- a/mrbgems/mruby-compiler/core/codegen.c +++ b/mrbgems/mruby-compiler/core/codegen.c @@ -419,7 +419,7 @@ gen_move(codegen_scope *s, uint16_t dst, uint16_t src, int nopeep) } else { struct mrb_insn_data data = mrb_last_insn(s); - + switch (data.insn) { case OP_MOVE: if (dst == src) return; /* remove useless MOVE */ @@ -456,7 +456,7 @@ gen_return(codegen_scope *s, uint8_t op, uint16_t src) } else { struct mrb_insn_data data = mrb_last_insn(s); - + if (data.insn == OP_MOVE && src == data.a) { s->pc = s->lastpc; genop_1(s, op, data.b); @@ -764,7 +764,7 @@ lambda_body(codegen_scope *s, node *tree, int blk) kd = tail && tail->cdr->cdr->car? 1 : 0; /* block argument? */ ba = tail && tail->cdr->cdr->cdr->car ? 1 : 0; - + if (ma > 0x1f || oa > 0x1f || pa > 0x1f || ka > 0x1f) { codegen_error(s, "too many formal arguments"); } @@ -3118,7 +3118,7 @@ generate_code(mrb_state *mrb, parser_state *p, int val) scope->filename_index = p->current_filename_index; MRB_TRY(&scope->jmp) { - mrb->jmp = &scope->jmp; + mrb->jmp = &scope->jmp; /* prepare irep */ codegen(scope, p->tree, val); proc = mrb_proc_new(mrb, scope->irep); diff --git a/mrbgems/mruby-random/src/random.c b/mrbgems/mruby-random/src/random.c index b865244cc..5b926a228 100644 --- a/mrbgems/mruby-random/src/random.c +++ b/mrbgems/mruby-random/src/random.c @@ -219,7 +219,7 @@ mrb_ary_shuffle_bang(mrb_state *mrb, mrb_value ary) mrb_int j; mrb_value *ptr = RARRAY_PTR(ary); mrb_value tmp; - + j = mrb_fixnum(mrb_random_mt_rand(mrb, random, mrb_fixnum_value(RARRAY_LEN(ary)))); diff --git a/src/array.c b/src/array.c index 2152e292d..f0c32bc7f 100644 --- a/src/array.c +++ b/src/array.c @@ -231,7 +231,7 @@ ary_expand_capa(mrb_state *mrb, struct RArray *a, mrb_int len) static void ary_shrink_capa(mrb_state *mrb, struct RArray *a) { - + mrb_int capa; if (ARY_EMBED_P(a)) return; diff --git a/src/codedump.c b/src/codedump.c index 454b16b36..30a14f937 100644 --- a/src/codedump.c +++ b/src/codedump.c @@ -516,7 +516,7 @@ codedump(mrb_state *mrb, mrb_irep *irep) #undef OPCODE } break; - + default: printf("OP_unknown (0x%x)\n", ins); break; diff --git a/src/gc.c b/src/gc.c index 9858e45fc..e429603dd 100644 --- a/src/gc.c +++ b/src/gc.c @@ -1559,7 +1559,7 @@ mrb_objspace_each_objects(mrb_state *mrb, mrb_each_object_callback *callback, vo mrb->jmp = &c_jmp; gc_each_objects(mrb, &mrb->gc, callback, data); mrb->jmp = prev_jmp; - mrb->gc.iterating = iterating; + mrb->gc.iterating = iterating; } MRB_CATCH(&c_jmp) { mrb->gc.iterating = iterating; mrb->jmp = prev_jmp; diff --git a/src/numeric.c b/src/numeric.c index c3e7d77a3..f7f0318e8 100644 --- a/src/numeric.c +++ b/src/numeric.c @@ -433,7 +433,7 @@ flo_shift(mrb_state *mrb, mrb_value x, mrb_int width) val = trunc(val); #else if (val > 0){ - val = floor(val); + val = floor(val); } else { val = ceil(val); } diff --git a/src/variable.c b/src/variable.c index 00bdb4b8d..506b4b63e 100644 --- a/src/variable.c +++ b/src/variable.c @@ -790,7 +790,7 @@ mrb_vm_const_get(mrb_state *mrb, mrb_sym sym) proc = mrb->c->ci->proc; while (proc) { c2 = MRB_PROC_TARGET_CLASS(proc); - if (c2 && iv_get(mrb, c2->iv, sym, &v)) { + if (c2 && iv_get(mrb, c2->iv, sym, &v)) { return v; } proc = proc->upper; @@ -988,25 +988,25 @@ struct csym_arg { struct RClass *c; mrb_sym sym; }; - + static int csym_i(mrb_state *mrb, mrb_sym sym, mrb_value v, void *p) { struct csym_arg *a = (struct csym_arg*)p; struct RClass *c = a->c; - + if (mrb_type(v) == c->tt && mrb_class_ptr(v) == c) { a->sym = sym; return 1; /* stop iteration */ } return 0; } - + static mrb_sym find_class_sym(mrb_state *mrb, struct RClass *outer, struct RClass *c) { struct csym_arg arg; - + if (!outer) return 0; if (outer == c) return 0; arg.c = c; diff --git a/src/vm.c b/src/vm.c index 9c4580fb3..14c42984e 100644 --- a/src/vm.c +++ b/src/vm.c @@ -1818,7 +1818,7 @@ RETRY_TRY_BLOCK: } regs[blk_pos] = *blk; /* move block */ if (kd) regs[len + 1] = kdict; - + /* copy mandatory and optional arguments */ if (argv0 != argv) { value_move(®s[1], argv, argc-mlen); /* m1 + o */ @@ -2077,7 +2077,7 @@ RETRY_TRY_BLOCK: break; case OP_R_BREAK: if (MRB_PROC_STRICT_P(proc)) goto NORMAL_RETURN; - if (MRB_PROC_ORPHAN_P(proc)) { + if (MRB_PROC_ORPHAN_P(proc)) { mrb_value exc; L_BREAK_ERROR: diff --git a/tasks/toolchains/gcc.rake b/tasks/toolchains/gcc.rake index fc2e0bff3..e0eb36f26 100644 --- a/tasks/toolchains/gcc.rake +++ b/tasks/toolchains/gcc.rake @@ -55,7 +55,7 @@ MRuby::Toolchain.new(:gcc) do |conf, _params| @header_search_paths end end - + def conf.enable_sanitizer(*opts) fail 'sanitizer already set' if @sanitizer_list diff --git a/test/t/kernel.rb b/test/t/kernel.rb index a730bdb24..74176fbd0 100644 --- a/test/t/kernel.rb +++ b/test/t/kernel.rb @@ -157,7 +157,7 @@ assert('Kernel#clone', '15.3.1.3.8') do assert_true a.respond_to?(:test) assert_false b.respond_to?(:test) assert_true c.respond_to?(:test) - + a.freeze d = a.clone assert_true d.frozen? diff --git a/test/t/syntax.rb b/test/t/syntax.rb index c5405aa9c..883cbd1ba 100644 --- a/test/t/syntax.rb +++ b/test/t/syntax.rb @@ -454,15 +454,15 @@ assert('multiline comments work correctly') do =begin this is a comment with nothing after begin and end =end -=begin this is a comment +=begin this is a comment this is a comment with extra after =begin =end =begin this is a comment that has =end with spaces after it -=end +=end =begin this is a comment this is a comment that has extra after =begin and =end with spaces after it -=end +=end line = __LINE__ =begin this is a comment this is a comment that has extra after =begin and =end with tabs after it -- cgit v1.2.3 From 5e6cd86f6eedea213fbeb5f1e7a5aa0ab303036a Mon Sep 17 00:00:00 2001 From: dearblue Date: Fri, 7 Sep 2018 23:56:06 +0900 Subject: Fix to not define outer when outer is itself. example: a = Class.new a::A = a --- src/class.c | 2 +- src/variable.c | 26 ++++++++++++++------------ 2 files changed, 15 insertions(+), 13 deletions(-) diff --git a/src/class.c b/src/class.c index 22fe36fb3..96d32b4c5 100644 --- a/src/class.c +++ b/src/class.c @@ -65,7 +65,7 @@ mrb_class_name_class(mrb_state *mrb, struct RClass *outer, struct RClass *c, mrb else { name = mrb_class_path(mrb, outer); if (mrb_nil_p(name)) { /* unnamed outer class */ - if (outer != mrb->object_class) { + if (outer != mrb->object_class && outer != c) { mrb_obj_iv_set(mrb, (struct RObject*)c, mrb_intern_lit(mrb, "__outer__"), mrb_obj_value(outer)); } diff --git a/src/variable.c b/src/variable.c index 047c96e8a..20edd56e4 100644 --- a/src/variable.c +++ b/src/variable.c @@ -377,21 +377,23 @@ is_namespace(enum mrb_vtype tt) static inline void assign_class_name(mrb_state *mrb, struct RObject *obj, mrb_sym sym, mrb_value v) { - if (is_namespace(obj->tt) && is_namespace(mrb_type(v)) && ISUPPER(mrb_sym2name(mrb, sym)[0])) { + if (is_namespace(obj->tt) && is_namespace(mrb_type(v))) { struct RObject *c = mrb_obj_ptr(v); - mrb_sym id_classname = mrb_intern_lit(mrb, "__classname__"); - mrb_value o = mrb_obj_iv_get(mrb, c, id_classname); - - if (mrb_nil_p(o)) { - mrb_sym id_outer = mrb_intern_lit(mrb, "__outer__"); - o = mrb_obj_iv_get(mrb, c, id_outer); + if (obj != c && ISUPPER(mrb_sym2name(mrb, sym)[0])) { + mrb_sym id_classname = mrb_intern_lit(mrb, "__classname__"); + mrb_value o = mrb_obj_iv_get(mrb, c, id_classname); if (mrb_nil_p(o)) { - if ((struct RClass *)obj == mrb->object_class) { - mrb_obj_iv_set(mrb, c, id_classname, mrb_symbol_value(sym)); - } - else { - mrb_obj_iv_set(mrb, c, id_outer, mrb_obj_value(obj)); + mrb_sym id_outer = mrb_intern_lit(mrb, "__outer__"); + o = mrb_obj_iv_get(mrb, c, id_outer); + + if (mrb_nil_p(o)) { + if ((struct RClass *)obj == mrb->object_class) { + mrb_obj_iv_set(mrb, c, id_classname, mrb_symbol_value(sym)); + } + else { + mrb_obj_iv_set(mrb, c, id_outer, mrb_obj_value(obj)); + } } } } -- cgit v1.2.3 From 292ea06d4d10ca12ec931c73f0ca39db23d66b8e Mon Sep 17 00:00:00 2001 From: dearblue Date: Sat, 8 Sep 2018 10:06:09 +0900 Subject: Fix outer module name example: a = Module.new a::B = Module.new p [a, a::B] # => [#, #::B] # => [#, #::B] (Fixed) --- src/class.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/class.c b/src/class.c index 22fe36fb3..046090515 100644 --- a/src/class.c +++ b/src/class.c @@ -1701,7 +1701,8 @@ mrb_class_name(mrb_state *mrb, struct RClass* c) { mrb_value path = mrb_class_path(mrb, c); if (mrb_nil_p(path)) { - path = mrb_str_new_lit(mrb, "#tt == MRB_TT_MODULE ? mrb_str_new_lit(mrb, "#"); } -- cgit v1.2.3 From 2760cea4511135c30d6d9f6bb658ff86e62804d6 Mon Sep 17 00:00:00 2001 From: Clayton Smith Date: Fri, 14 Sep 2018 16:53:26 -0400 Subject: Prevent signed integer overflow. --- mrbgems/mruby-sprintf/src/sprintf.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/mrbgems/mruby-sprintf/src/sprintf.c b/mrbgems/mruby-sprintf/src/sprintf.c index ea127c574..15d7b5464 100644 --- a/mrbgems/mruby-sprintf/src/sprintf.c +++ b/mrbgems/mruby-sprintf/src/sprintf.c @@ -200,7 +200,7 @@ check_name_arg(mrb_state *mrb, int posarg, const char *name, mrb_int len) #define GETNUM(n, val) \ for (; p < end && ISDIGIT(*p); p++) {\ - if (n > MRB_INT_MAX/10) {\ + if (n > (MRB_INT_MAX - (*p - '0'))/10) {\ mrb_raise(mrb, E_ARGUMENT_ERROR, #val " too big"); \ } \ n = 10 * n + (*p - '0'); \ @@ -1056,18 +1056,18 @@ retry: if (i > 0) need = BIT_DIGITS(i); } - need += (flags&FPREC) ? prec : 6; - if (need < 0) { + if (need > MRB_INT_MAX - ((flags&FPREC) ? prec : 6)) { too_big_width: mrb_raise(mrb, E_ARGUMENT_ERROR, (width > prec ? "width too big" : "prec too big")); } + need += (flags&FPREC) ? prec : 6; if ((flags&FWIDTH) && need < width) need = width; - need += 20; - if (need <= 0) { + if (need > MRB_INT_MAX - 20) { goto too_big_width; } + need += 20; CHECK(need); n = snprintf(&buf[blen], need, fbuf, fval); -- cgit v1.2.3 From 2661ac70499601f28741be01e0ce82da0a4733bc Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Sun, 16 Sep 2018 00:41:48 +0900 Subject: Add support for iOS platforms that does not support `fork`; fix #4113 --- include/mruby/common.h | 5 ++ mrbgems/mruby-io/src/io.c | 209 ++++++++++++++++++++++++---------------------- 2 files changed, 113 insertions(+), 101 deletions(-) diff --git a/include/mruby/common.h b/include/mruby/common.h index d6ec78b0d..4c7d9384a 100644 --- a/include/mruby/common.h +++ b/include/mruby/common.h @@ -7,6 +7,11 @@ #ifndef MRUBY_COMMON_H #define MRUBY_COMMON_H +#ifdef __APPLE__ + #ifndef __TARGETCONDITIONALS__ + #include "TargetConditionals.h" + #endif +#endif #ifdef __cplusplus #ifdef MRB_ENABLE_CXX_ABI diff --git a/mrbgems/mruby-io/src/io.c b/mrbgems/mruby-io/src/io.c index 67c57a08e..be5c4ba68 100644 --- a/mrbgems/mruby-io/src/io.c +++ b/mrbgems/mruby-io/src/io.c @@ -305,7 +305,112 @@ option_to_fd(mrb_state *mrb, mrb_value obj, const char *key) return -1; /* never reached */ } -#ifndef _WIN32 +#ifdef _WIN32 +mrb_value +mrb_io_s_popen(mrb_state *mrb, mrb_value klass) +{ + mrb_value cmd, io; + mrb_value mode = mrb_str_new_cstr(mrb, "r"); + mrb_value opt = mrb_hash_new(mrb); + + struct mrb_io *fptr; + const char *pname; + int pid = 0, flags; + STARTUPINFO si; + PROCESS_INFORMATION pi; + SECURITY_ATTRIBUTES saAttr; + + HANDLE ifd[2]; + HANDLE ofd[2]; + + int doexec; + int opt_in, opt_out, opt_err; + + ifd[0] = INVALID_HANDLE_VALUE; + ifd[1] = INVALID_HANDLE_VALUE; + ofd[0] = INVALID_HANDLE_VALUE; + ofd[1] = INVALID_HANDLE_VALUE; + + mrb_get_args(mrb, "S|SH", &cmd, &mode, &opt); + io = mrb_obj_value(mrb_data_object_alloc(mrb, mrb_class_ptr(klass), NULL, &mrb_io_type)); + + pname = mrb_string_value_cstr(mrb, &cmd); + flags = mrb_io_modestr_to_flags(mrb, mrb_string_value_cstr(mrb, &mode)); + + doexec = (strcmp("-", pname) != 0); + opt_in = option_to_fd(mrb, opt, "in"); + opt_out = option_to_fd(mrb, opt, "out"); + opt_err = option_to_fd(mrb, opt, "err"); + + saAttr.nLength = sizeof(SECURITY_ATTRIBUTES); + saAttr.bInheritHandle = TRUE; + saAttr.lpSecurityDescriptor = NULL; + + if (flags & FMODE_READABLE) { + if (!CreatePipe(&ofd[0], &ofd[1], &saAttr, 0) + || !SetHandleInformation(ofd[0], HANDLE_FLAG_INHERIT, 0)) { + mrb_sys_fail(mrb, "pipe"); + } + } + + if (flags & FMODE_WRITABLE) { + if (!CreatePipe(&ifd[0], &ifd[1], &saAttr, 0) + || !SetHandleInformation(ifd[1], HANDLE_FLAG_INHERIT, 0)) { + mrb_sys_fail(mrb, "pipe"); + } + } + + if (doexec) { + ZeroMemory(&pi, sizeof(pi)); + ZeroMemory(&si, sizeof(si)); + si.cb = sizeof(si); + si.dwFlags |= STARTF_USESHOWWINDOW; + si.wShowWindow = SW_HIDE; + si.dwFlags |= STARTF_USESTDHANDLES; + if (flags & FMODE_READABLE) { + si.hStdOutput = ofd[1]; + si.hStdError = ofd[1]; + } + if (flags & FMODE_WRITABLE) { + si.hStdInput = ifd[0]; + } + if (!CreateProcess( + NULL, (char*)pname, NULL, NULL, + TRUE, CREATE_NEW_PROCESS_GROUP, NULL, NULL, &si, &pi)) { + CloseHandle(ifd[0]); + CloseHandle(ifd[1]); + CloseHandle(ofd[0]); + CloseHandle(ofd[1]); + mrb_raisef(mrb, E_IO_ERROR, "command not found: %S", cmd); + } + CloseHandle(pi.hThread); + CloseHandle(ifd[0]); + CloseHandle(ofd[1]); + pid = pi.dwProcessId; + } + + mrb_iv_set(mrb, io, mrb_intern_cstr(mrb, "@buf"), mrb_str_new_cstr(mrb, "")); + + fptr = mrb_io_alloc(mrb); + fptr->fd = _open_osfhandle((intptr_t)ofd[0], 0); + fptr->fd2 = _open_osfhandle((intptr_t)ifd[1], 0); + fptr->pid = pid; + fptr->readable = ((flags & FMODE_READABLE) != 0); + fptr->writable = ((flags & FMODE_WRITABLE) != 0); + fptr->sync = 0; + + DATA_TYPE(io) = &mrb_io_type; + DATA_PTR(io) = fptr; + return io; +} +#elif TARGET_OS_IPHONE +mrb_value +mrb_io_s_popen(mrb_state *mrb, mrb_value klass) +{ + mrb_raise(mrb, E_NOTIMP_ERROR, "IO#popen is not supported on the platform"); + return mrb_false_value();w +} +#else mrb_value mrb_io_s_popen(mrb_state *mrb, mrb_value klass) { @@ -440,104 +545,6 @@ mrb_io_s_popen(mrb_state *mrb, mrb_value klass) } return result; } -#else -mrb_value -mrb_io_s_popen(mrb_state *mrb, mrb_value klass) -{ - mrb_value cmd, io; - mrb_value mode = mrb_str_new_cstr(mrb, "r"); - mrb_value opt = mrb_hash_new(mrb); - - struct mrb_io *fptr; - const char *pname; - int pid = 0, flags; - STARTUPINFO si; - PROCESS_INFORMATION pi; - SECURITY_ATTRIBUTES saAttr; - - HANDLE ifd[2]; - HANDLE ofd[2]; - - int doexec; - int opt_in, opt_out, opt_err; - - ifd[0] = INVALID_HANDLE_VALUE; - ifd[1] = INVALID_HANDLE_VALUE; - ofd[0] = INVALID_HANDLE_VALUE; - ofd[1] = INVALID_HANDLE_VALUE; - - mrb_get_args(mrb, "S|SH", &cmd, &mode, &opt); - io = mrb_obj_value(mrb_data_object_alloc(mrb, mrb_class_ptr(klass), NULL, &mrb_io_type)); - - pname = mrb_string_value_cstr(mrb, &cmd); - flags = mrb_io_modestr_to_flags(mrb, mrb_string_value_cstr(mrb, &mode)); - - doexec = (strcmp("-", pname) != 0); - opt_in = option_to_fd(mrb, opt, "in"); - opt_out = option_to_fd(mrb, opt, "out"); - opt_err = option_to_fd(mrb, opt, "err"); - - saAttr.nLength = sizeof(SECURITY_ATTRIBUTES); - saAttr.bInheritHandle = TRUE; - saAttr.lpSecurityDescriptor = NULL; - - if (flags & FMODE_READABLE) { - if (!CreatePipe(&ofd[0], &ofd[1], &saAttr, 0) - || !SetHandleInformation(ofd[0], HANDLE_FLAG_INHERIT, 0)) { - mrb_sys_fail(mrb, "pipe"); - } - } - - if (flags & FMODE_WRITABLE) { - if (!CreatePipe(&ifd[0], &ifd[1], &saAttr, 0) - || !SetHandleInformation(ifd[1], HANDLE_FLAG_INHERIT, 0)) { - mrb_sys_fail(mrb, "pipe"); - } - } - - if (doexec) { - ZeroMemory(&pi, sizeof(pi)); - ZeroMemory(&si, sizeof(si)); - si.cb = sizeof(si); - si.dwFlags |= STARTF_USESHOWWINDOW; - si.wShowWindow = SW_HIDE; - si.dwFlags |= STARTF_USESTDHANDLES; - if (flags & FMODE_READABLE) { - si.hStdOutput = ofd[1]; - si.hStdError = ofd[1]; - } - if (flags & FMODE_WRITABLE) { - si.hStdInput = ifd[0]; - } - if (!CreateProcess( - NULL, (char*)pname, NULL, NULL, - TRUE, CREATE_NEW_PROCESS_GROUP, NULL, NULL, &si, &pi)) { - CloseHandle(ifd[0]); - CloseHandle(ifd[1]); - CloseHandle(ofd[0]); - CloseHandle(ofd[1]); - mrb_raisef(mrb, E_IO_ERROR, "command not found: %S", cmd); - } - CloseHandle(pi.hThread); - CloseHandle(ifd[0]); - CloseHandle(ofd[1]); - pid = pi.dwProcessId; - } - - mrb_iv_set(mrb, io, mrb_intern_cstr(mrb, "@buf"), mrb_str_new_cstr(mrb, "")); - - fptr = mrb_io_alloc(mrb); - fptr->fd = _open_osfhandle((intptr_t)ofd[0], 0); - fptr->fd2 = _open_osfhandle((intptr_t)ifd[1], 0); - fptr->pid = pid; - fptr->readable = ((flags & FMODE_READABLE) != 0); - fptr->writable = ((flags & FMODE_WRITABLE) != 0); - fptr->sync = 0; - - DATA_TYPE(io) = &mrb_io_type; - DATA_PTR(io) = fptr; - return io; -} #endif static int @@ -1004,7 +1011,7 @@ mrb_io_read_data_pending(mrb_state *mrb, mrb_value io) return 0; } -#ifndef _WIN32 +#if !defined(_WIN32) && !TARGET_OS_IPHONE static mrb_value mrb_io_s_pipe(mrb_state *mrb, mrb_value klass) { @@ -1306,7 +1313,7 @@ mrb_init_io(mrb_state *mrb) mrb_define_class_method(mrb, io, "for_fd", mrb_io_s_for_fd, MRB_ARGS_ANY()); mrb_define_class_method(mrb, io, "select", mrb_io_s_select, MRB_ARGS_ANY()); mrb_define_class_method(mrb, io, "sysopen", mrb_io_s_sysopen, MRB_ARGS_ANY()); -#ifndef _WIN32 +#if !defined(_WIN32) && !TARGET_OS_IPHONE mrb_define_class_method(mrb, io, "_pipe", mrb_io_s_pipe, MRB_ARGS_NONE()); #endif -- cgit v1.2.3 From ed4dbce052bd58a7a6d493936711f447792dec20 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Sun, 16 Sep 2018 00:58:36 +0900 Subject: fixup! Add support for iOS platforms that does not support `fork`; fix #4113 --- mrbgems/mruby-io/src/io.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mrbgems/mruby-io/src/io.c b/mrbgems/mruby-io/src/io.c index be5c4ba68..8982650dd 100644 --- a/mrbgems/mruby-io/src/io.c +++ b/mrbgems/mruby-io/src/io.c @@ -408,7 +408,7 @@ mrb_value mrb_io_s_popen(mrb_state *mrb, mrb_value klass) { mrb_raise(mrb, E_NOTIMP_ERROR, "IO#popen is not supported on the platform"); - return mrb_false_value();w + return mrb_false_value(); } #else mrb_value -- cgit v1.2.3 From 82053dd9457c8bed0b493a0e13e9c005fa9ffbb9 Mon Sep 17 00:00:00 2001 From: Tom Black Date: Sat, 15 Sep 2018 13:55:11 -0700 Subject: Exclude pipe and exec on iOS/tvOS Use of `execl()` is prohibited on these platforms --- mrbgems/mruby-io/src/io.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mrbgems/mruby-io/src/io.c b/mrbgems/mruby-io/src/io.c index 8982650dd..1ac15aab3 100644 --- a/mrbgems/mruby-io/src/io.c +++ b/mrbgems/mruby-io/src/io.c @@ -209,7 +209,7 @@ mrb_fd_cloexec(mrb_state *mrb, int fd) #endif } -#ifndef _WIN32 +#if !defined(_WIN32) && !TARGET_OS_IPHONE static int mrb_cloexec_pipe(mrb_state *mrb, int fildes[2]) { -- cgit v1.2.3 From e9b1d9dc2f1de290da4aadfd39f1957502d67e18 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Mon, 17 Sep 2018 23:52:14 +0900 Subject: Array size may be changed in `mrb_get_args()` reentry. fix #4116; fix #4117; fix #4118; fix #4119; fix #4120 --- mrbgems/mruby-array-ext/src/array.c | 5 +++-- src/array.c | 22 ++++++++++++++-------- 2 files changed, 17 insertions(+), 10 deletions(-) diff --git a/mrbgems/mruby-array-ext/src/array.c b/mrbgems/mruby-array-ext/src/array.c index 169f968f9..792eb26de 100644 --- a/mrbgems/mruby-array-ext/src/array.c +++ b/mrbgems/mruby-array-ext/src/array.c @@ -175,7 +175,7 @@ static mrb_value mrb_ary_slice_bang(mrb_state *mrb, mrb_value self) { struct RArray *a = mrb_ary_ptr(self); - mrb_int i, j, k, len, alen = ARY_LEN(a); + mrb_int i, j, k, len, alen; mrb_value val; mrb_value *ptr; mrb_value ary; @@ -188,7 +188,7 @@ mrb_ary_slice_bang(mrb_state *mrb, mrb_value self) mrb_get_args(mrb, "o|i", &index, &len); switch (mrb_type(index)) { case MRB_TT_RANGE: - if (mrb_range_beg_len(mrb, index, &i, &len, alen, TRUE) == 1) { + if (mrb_range_beg_len(mrb, index, &i, &len, ARY_LEN(a), TRUE) == 1) { goto delete_pos_len; } else { @@ -205,6 +205,7 @@ mrb_ary_slice_bang(mrb_state *mrb, mrb_value self) mrb_get_args(mrb, "ii", &i, &len); delete_pos_len: + alen = ARY_LEN(a); if (i < 0) i += alen; if (i < 0 || alen < i) return mrb_nil_value(); if (len < 0) return mrb_nil_value(); diff --git a/src/array.c b/src/array.c index f0c32bc7f..0b039a6ec 100644 --- a/src/array.c +++ b/src/array.c @@ -853,14 +853,14 @@ static mrb_value mrb_ary_aget(mrb_state *mrb, mrb_value self) { struct RArray *a = mrb_ary_ptr(self); - mrb_int i, len, alen = ARY_LEN(a); + mrb_int i, len, alen; mrb_value index; if (mrb_get_args(mrb, "o|i", &index, &len) == 1) { switch (mrb_type(index)) { /* a[n..m] */ case MRB_TT_RANGE: - if (mrb_range_beg_len(mrb, index, &i, &len, alen, TRUE) == 1) { + if (mrb_range_beg_len(mrb, index, &i, &len, ARY_LEN(a), TRUE) == 1) { return ary_subseq(mrb, a, i, len); } else { @@ -874,6 +874,7 @@ mrb_ary_aget(mrb_state *mrb, mrb_value self) } i = aget_index(mrb, index); + alen = ARY_LEN(a); if (i < 0) i += alen; if (i < 0 || alen < i) return mrb_nil_value(); if (len < 0) return mrb_nil_value(); @@ -953,9 +954,10 @@ mrb_ary_delete_at(mrb_state *mrb, mrb_value self) mrb_int index; mrb_value val; mrb_value *ptr; - mrb_int len, alen = ARY_LEN(a); + mrb_int len, alen; mrb_get_args(mrb, "i", &index); + alen = ARY_LEN(a); if (index < 0) index += alen; if (index < 0 || alen <= index) return mrb_nil_value(); @@ -980,16 +982,17 @@ static mrb_value mrb_ary_first(mrb_state *mrb, mrb_value self) { struct RArray *a = mrb_ary_ptr(self); - mrb_int size, alen = ARY_LEN(a); + mrb_int size, alen; if (mrb_get_argc(mrb) == 0) { - return (alen > 0)? ARY_PTR(a)[0]: mrb_nil_value(); + return (ARY_LEN(a) > 0)? ARY_PTR(a)[0]: mrb_nil_value(); } mrb_get_args(mrb, "|i", &size); if (size < 0) { mrb_raise(mrb, E_ARGUMENT_ERROR, "negative array size"); } + alen = ARY_LEN(a); if (size > alen) size = alen; if (ARY_SHARED_P(a)) { return ary_subseq(mrb, a, 0, size); @@ -1001,10 +1004,13 @@ static mrb_value mrb_ary_last(mrb_state *mrb, mrb_value self) { struct RArray *a = mrb_ary_ptr(self); - mrb_int size, alen = ARY_LEN(a); + mrb_int n, size, alen; - if (mrb_get_args(mrb, "|i", &size) == 0) - return (alen > 0)? ARY_PTR(a)[alen - 1]: mrb_nil_value(); + n = mrb_get_args(mrb, "|i", &size); + alen = ARY_LEN(a); + if (n == 0) { + return (alen > 0) ? ARY_PTR(a)[alen - 1]: mrb_nil_value(); + } if (size < 0) { mrb_raise(mrb, E_ARGUMENT_ERROR, "negative array size"); -- cgit v1.2.3 From 8b43754644660c9dcdc6b8b18a1917f01e77479e Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Tue, 18 Sep 2018 09:35:09 +0900 Subject: Use `mrb_to_flo()` to check return value from `to_f`; fix #4115 The ISO standard does not include implicit type conversion using `to_int`, `to_str` and sometimes `to_f`. For the compactness of the mruby implementation, maybe we should remove those implicit conversion from mruby. --- mrbgems/mruby-pack/src/pack.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/mrbgems/mruby-pack/src/pack.c b/mrbgems/mruby-pack/src/pack.c index 850462830..f970d9339 100644 --- a/mrbgems/mruby-pack/src/pack.c +++ b/mrbgems/mruby-pack/src/pack.c @@ -1127,7 +1127,8 @@ mrb_pack_pack(mrb_state *mrb, mrb_value ary) #ifndef MRB_WITHOUT_FLOAT } else if (type == PACK_TYPE_FLOAT) { if (!mrb_float_p(o)) { - o = mrb_funcall(mrb, o, "to_f", 0); + mrb_float f = mrb_to_flo(mrb, o); + o = mrb_float_value(mrb, f); } #endif } else if (type == PACK_TYPE_STRING) { -- cgit v1.2.3 From 3820ef791f3ccb766956d12534ae519f4923ac7e Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Thu, 20 Sep 2018 09:07:24 +0900 Subject: Small refactoring in `mruby-hash-ext`. --- mrbgems/mruby-hash-ext/mrblib/hash.rb | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/mrbgems/mruby-hash-ext/mrblib/hash.rb b/mrbgems/mruby-hash-ext/mrblib/hash.rb index eaf54b871..61e4c890c 100644 --- a/mrbgems/mruby-hash-ext/mrblib/hash.rb +++ b/mrbgems/mruby-hash-ext/mrblib/hash.rb @@ -126,12 +126,12 @@ class Hash # def compact! - h = {} keys = self.keys nk = keys.select{|k| self[k] != nil } return nil if (keys.size == nk.size) + h = {} nk.each {|k| h[k] = self[k] } @@ -486,6 +486,7 @@ class Hash end hash end + ## # call-seq: # hsh.transform_values! {|key| block } -> hsh -- cgit v1.2.3 From b7e5c86612908dbd670ae2c50de60a079649b7ff Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Thu, 20 Sep 2018 11:10:34 +0900 Subject: Allow nested gemboxes; fix #4124 --- lib/mruby/gem.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/mruby/gem.rb b/lib/mruby/gem.rb index a83ca639f..7e97c34f3 100644 --- a/lib/mruby/gem.rb +++ b/lib/mruby/gem.rb @@ -454,5 +454,6 @@ module MRuby def new(&block); block.call(self); end def config=(obj); @config = obj; end def gem(gemdir, &block); @config.gem(gemdir, &block); end + def gembox(gemfile); @config.gembox(gemfile); end end # GemBox end # MRuby -- cgit v1.2.3 From 19d3bb2d90f9806ea6cdef97a139de9f2050363a Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Thu, 20 Sep 2018 12:02:35 +0900 Subject: Make `#to_h` to take a block; [ruby-core:89088] --- mrbgems/mruby-array-ext/mrblib/array.rb | 25 +++++++++++++++++++ mrbgems/mruby-array-ext/src/array.c | 44 --------------------------------- mrbgems/mruby-enum-ext/mrblib/enum.rb | 21 +++++++++++----- mrbgems/mruby-enum-ext/test/enum.rb | 2 ++ 4 files changed, 42 insertions(+), 50 deletions(-) diff --git a/mrbgems/mruby-array-ext/mrblib/array.rb b/mrbgems/mruby-array-ext/mrblib/array.rb index c0995bb99..bb9e61bdd 100644 --- a/mrbgems/mruby-array-ext/mrblib/array.rb +++ b/mrbgems/mruby-array-ext/mrblib/array.rb @@ -932,4 +932,29 @@ class Array self.map { |row| row[column_index] } end end + + ## + # call-seq: + # ary.to_h -> Hash + # ary.to_h{|item| ... } -> Hash + # + # Returns the result of interpreting aray as an array of + # [key, value] pairs. If a block is given, it should + # return [key, value] pairs to construct a hash. + # + # [[:foo, :bar], [1, 2]].to_h + # # => {:foo => :bar, 1 => 2} + # [1, 2].to_h{|x| [x, x*2]} + # # => {1 => 2, 2 => 4} + # + def to_h(&blk) + h = {} + self.each do |v| + v = blk.call(v) if blk + raise TypeError, "wrong element type #{v.class}" unless Array === v + raise ArgumentError, "wrong array length (expected 2, was #{v.length})" unless v.length == 2 + h[v[0]] = v[1] + end + h + end end diff --git a/mrbgems/mruby-array-ext/src/array.c b/mrbgems/mruby-array-ext/src/array.c index 792eb26de..b6d9c9c80 100644 --- a/mrbgems/mruby-array-ext/src/array.c +++ b/mrbgems/mruby-array-ext/src/array.c @@ -106,49 +106,6 @@ mrb_ary_values_at(mrb_state *mrb, mrb_value self) return mrb_get_values_at(mrb, self, RARRAY_LEN(self), argc, argv, mrb_ary_ref); } -/* - * call-seq: - * ary.to_h -> Hash - * - * Returns the result of interpreting aray as an array of - * [key, value] paris. - * - * [[:foo, :bar], [1, 2]].to_h - * # => {:foo => :bar, 1 => 2} - * - */ - -static mrb_value -mrb_ary_to_h(mrb_state *mrb, mrb_value ary) -{ - mrb_int i; - mrb_value v, hash; - - hash = mrb_hash_new_capa(mrb, 0); - - for (i = 0; i < RARRAY_LEN(ary); ++i) { - mrb_value elt = RARRAY_PTR(ary)[i]; - v = mrb_check_array_type(mrb, elt); - - if (mrb_nil_p(v)) { - mrb_raisef(mrb, E_TYPE_ERROR, "wrong element type %S at %S (expected array)", - mrb_str_new_cstr(mrb, mrb_obj_classname(mrb, elt)), - mrb_fixnum_value(i) - ); - } - - if (RARRAY_LEN(v) != 2) { - mrb_raisef(mrb, E_ARGUMENT_ERROR, "wrong array length at %S (expected 2, was %S)", - mrb_fixnum_value(i), - mrb_fixnum_value(RARRAY_LEN(v)) - ); - } - - mrb_hash_set(mrb, hash, RARRAY_PTR(v)[0], RARRAY_PTR(v)[1]); - } - - return hash; -} /* * call-seq: @@ -237,7 +194,6 @@ mrb_mruby_array_ext_gem_init(mrb_state* mrb) mrb_define_method(mrb, a, "at", mrb_ary_at, MRB_ARGS_REQ(1)); mrb_define_method(mrb, a, "rassoc", mrb_ary_rassoc, MRB_ARGS_REQ(1)); mrb_define_method(mrb, a, "values_at", mrb_ary_values_at, MRB_ARGS_ANY()); - mrb_define_method(mrb, a, "to_h", mrb_ary_to_h, MRB_ARGS_REQ(0)); mrb_define_method(mrb, a, "slice!", mrb_ary_slice_bang, MRB_ARGS_ANY()); } diff --git a/mrbgems/mruby-enum-ext/mrblib/enum.rb b/mrbgems/mruby-enum-ext/mrblib/enum.rb index a840ade3b..6cbacdf9e 100644 --- a/mrbgems/mruby-enum-ext/mrblib/enum.rb +++ b/mrbgems/mruby-enum-ext/mrblib/enum.rb @@ -803,13 +803,22 @@ module Enumerable # # => {:hello => 0, :world => 1} # - def to_h + def to_h(&blk) h = {} - self.each do |*v| - v = v.__svalue - raise TypeError, "wrong element type #{v.class} (expected Array)" unless v.is_a? Array - raise ArgumentError, "element has wrong array length (expected 2, was #{v.size})" if v.size != 2 - h[v[0]] = v[1] + if blk + self.each do |v| + v = blk.call(v) + raise TypeError, "wrong element type #{v.class} (expected Array)" unless v.is_a? Array + raise ArgumentError, "element has wrong array length (expected 2, was #{v.size})" if v.size != 2 + h[v[0]] = v[1] + end + else + self.each do |*v| + v = v.__svalue + raise TypeError, "wrong element type #{v.class} (expected Array)" unless v.is_a? Array + raise ArgumentError, "element has wrong array length (expected 2, was #{v.size})" if v.size != 2 + h[v[0]] = v[1] + end end h end diff --git a/mrbgems/mruby-enum-ext/test/enum.rb b/mrbgems/mruby-enum-ext/test/enum.rb index 46ed5f0f9..b2d7297a4 100644 --- a/mrbgems/mruby-enum-ext/test/enum.rb +++ b/mrbgems/mruby-enum-ext/test/enum.rb @@ -188,4 +188,6 @@ assert("Enumerable#to_h") do assert_equal h0, h # mruby-enum-ext also provides nil.to_h assert_equal Hash.new, nil.to_h + + assert_equal({1=>4,3=>8}, c.new.to_h{|k,v|[k,v*2]}) end -- cgit v1.2.3 From 3a9caad8ebe63dfe2b8583c72fc5e275f13e25c3 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Thu, 20 Sep 2018 12:06:53 +0900 Subject: Move `Symbol#to_proc` to the core from `mruby-symbol-ext` gem. Even though `Symbol#to_proc` is not included in ISO standard, the `some_method(&:method_name)` is used very widely and convenient. So we moved it to the core. --- mrbgems/mruby-symbol-ext/mrblib/symbol.rb | 6 ------ mrbgems/mruby-symbol-ext/test/symbol.rb | 4 ---- mrblib/symbol.rb | 7 +++++++ test/t/symbol.rb | 4 ++++ 4 files changed, 11 insertions(+), 10 deletions(-) create mode 100644 mrblib/symbol.rb diff --git a/mrbgems/mruby-symbol-ext/mrblib/symbol.rb b/mrbgems/mruby-symbol-ext/mrblib/symbol.rb index 28cce3156..99fa275d5 100644 --- a/mrbgems/mruby-symbol-ext/mrblib/symbol.rb +++ b/mrbgems/mruby-symbol-ext/mrblib/symbol.rb @@ -3,12 +3,6 @@ class Symbol alias intern to_sym - def to_proc - ->(obj,*args,&block) do - obj.__send__(self, *args, &block) - end - end - ## # call-seq: # sym.capitalize -> symbol diff --git a/mrbgems/mruby-symbol-ext/test/symbol.rb b/mrbgems/mruby-symbol-ext/test/symbol.rb index 6070d1418..63c1bd826 100644 --- a/mrbgems/mruby-symbol-ext/test/symbol.rb +++ b/mrbgems/mruby-symbol-ext/test/symbol.rb @@ -1,10 +1,6 @@ ## # Symbol(Ext) Test -assert('Symbol#to_proc') do - assert_equal 5, :abs.to_proc[-5] -end - assert('Symbol.all_symbols') do foo = [:__symbol_test_1, :__symbol_test_2, :__symbol_test_3].sort symbols = Symbol.all_symbols.select{|sym|sym.to_s.include? '__symbol_test'}.sort diff --git a/mrblib/symbol.rb b/mrblib/symbol.rb new file mode 100644 index 000000000..9c981dd9e --- /dev/null +++ b/mrblib/symbol.rb @@ -0,0 +1,7 @@ +class Symbol + def to_proc + ->(obj,*args,&block) do + obj.__send__(self, *args, &block) + end + end +end diff --git a/test/t/symbol.rb b/test/t/symbol.rb index 9059f45c2..fdce0f378 100644 --- a/test/t/symbol.rb +++ b/test/t/symbol.rb @@ -28,3 +28,7 @@ end assert('Symbol#to_sym', '15.2.11.3.4') do assert_equal :abc, :abc.to_sym end + +assert('Symbol#to_proc') do + assert_equal 5, :abs.to_proc[-5] +end -- cgit v1.2.3 From 505e6017306e09487a4a7f1b0fb1c9976f4f5ec5 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Thu, 20 Sep 2018 13:53:55 +0900 Subject: Revert "Add MRB_IMPROVE_META_PROGRAMMING configuration" This reverts commit 1997fcf98f596f6af2bf1d20ccde1b1abfe7324d. It became the default behavior. --- include/mrbconf.h | 3 --- src/variable.c | 10 ---------- 2 files changed, 13 deletions(-) diff --git a/include/mrbconf.h b/include/mrbconf.h index 379386896..cc28acfaa 100644 --- a/include/mrbconf.h +++ b/include/mrbconf.h @@ -110,9 +110,6 @@ /* fixed size state atexit stack */ //#define MRB_FIXED_STATE_ATEXIT_STACK -/* improve meta programming support */ -//#define MRB_IMPROVE_META_PROGRAMMING - /* -DMRB_DISABLE_XXXX to drop following features */ //#define MRB_DISABLE_STDIO /* use of stdio */ diff --git a/src/variable.c b/src/variable.c index 01077a34e..cc7936a46 100644 --- a/src/variable.c +++ b/src/variable.c @@ -344,9 +344,7 @@ mrb_iv_get(mrb_state *mrb, mrb_value obj, mrb_sym sym) return mrb_nil_value(); } -#ifdef MRB_IMPROVE_META_PROGRAMMING static inline void assign_class_name(mrb_state *mrb, struct RObject *obj, mrb_sym sym, mrb_value v); -#endif MRB_API void mrb_obj_iv_set(mrb_state *mrb, struct RObject *obj, mrb_sym sym, mrb_value v) @@ -356,9 +354,7 @@ mrb_obj_iv_set(mrb_state *mrb, struct RObject *obj, mrb_sym sym, mrb_value v) if (MRB_FROZEN_P(obj)) { mrb_raisef(mrb, E_FROZEN_ERROR, "can't modify frozen %S", mrb_obj_value(obj)); } -#ifdef MRB_IMPROVE_META_PROGRAMMING assign_class_name(mrb, obj, sym, v); -#endif if (!obj->iv) { obj->iv = iv_new(mrb); } @@ -367,7 +363,6 @@ mrb_obj_iv_set(mrb_state *mrb, struct RObject *obj, mrb_sym sym, mrb_value v) mrb_write_barrier(mrb, (struct RBasic*)obj); } -#ifdef MRB_IMPROVE_META_PROGRAMMING static inline mrb_bool is_namespace(enum mrb_vtype tt) { @@ -399,7 +394,6 @@ assign_class_name(mrb_state *mrb, struct RObject *obj, mrb_sym sym, mrb_value v) } } } -#endif MRB_API void mrb_iv_set(mrb_state *mrb, mrb_value obj, mrb_sym sym, mrb_value v) @@ -1110,14 +1104,10 @@ mrb_class_find_path(mrb_state *mrb, struct RClass *c) str = mrb_sym2name_len(mrb, name, &len); mrb_str_cat(mrb, path, str, len); -#ifdef MRB_IMPROVE_META_PROGRAMMING if (RSTRING_PTR(path)[0] != '#') { -#endif iv_del(mrb, c->iv, mrb_intern_lit(mrb, "__outer__"), NULL); iv_put(mrb, c->iv, mrb_intern_lit(mrb, "__classname__"), path); mrb_field_write_barrier_value(mrb, (struct RBasic*)c, path); -#ifdef MRB_IMPROVE_META_PROGRAMMING } -#endif return path; } -- cgit v1.2.3 From 159575f63024c79592229f9c0e7da42a0075dae9 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Thu, 20 Sep 2018 13:57:43 +0900 Subject: Renamed `is_namespace()` to `namespace_p()`. --- src/variable.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/variable.c b/src/variable.c index cc7936a46..72c13aa1f 100644 --- a/src/variable.c +++ b/src/variable.c @@ -364,7 +364,7 @@ mrb_obj_iv_set(mrb_state *mrb, struct RObject *obj, mrb_sym sym, mrb_value v) } static inline mrb_bool -is_namespace(enum mrb_vtype tt) +namespace_p(enum mrb_vtype tt) { return tt == MRB_TT_CLASS || tt == MRB_TT_MODULE ? TRUE : FALSE; } @@ -372,7 +372,7 @@ is_namespace(enum mrb_vtype tt) static inline void assign_class_name(mrb_state *mrb, struct RObject *obj, mrb_sym sym, mrb_value v) { - if (is_namespace(obj->tt) && is_namespace(mrb_type(v))) { + if (namespace_p(obj->tt) && namespace_p(mrb_type(v))) { struct RObject *c = mrb_obj_ptr(v); if (obj != c && ISUPPER(mrb_sym2name(mrb, sym)[0])) { mrb_sym id_classname = mrb_intern_lit(mrb, "__classname__"); -- cgit v1.2.3 From dd346be99aaf6d0220f067c78decb29548c7dfe6 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Thu, 20 Sep 2018 23:56:53 +0900 Subject: Improve performance of `Array#uniq!`. --- mrbgems/mruby-array-ext/mrblib/array.rb | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/mrbgems/mruby-array-ext/mrblib/array.rb b/mrbgems/mruby-array-ext/mrblib/array.rb index bb9e61bdd..4f676a121 100644 --- a/mrbgems/mruby-array-ext/mrblib/array.rb +++ b/mrbgems/mruby-array-ext/mrblib/array.rb @@ -41,19 +41,22 @@ class Array # c.uniq! { |s| s.first } # => [["student", "sam"], ["teacher", "matz"]] # def uniq!(&block) - ary = self.dup - result = [] if block hash = {} - while ary.size > 0 - val = ary.shift + self.each do |val| key = block.call(val) - hash[key] = val unless hash.has_key?(key) + hash[key] = val unless hash.key?(key) end - hash.each_value do |value| - result << value + result = hash.values + elsif self.size > 20 + hash = {} + self.each do |val| + hash[val] = val end + result = hash.values else + ary = self.dup + result = [] while ary.size > 0 result << ary.shift ary.delete(result.last) -- cgit v1.2.3 From f23f2bbdad7a15bec8812b029cb23c2117d7c63c Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Fri, 21 Sep 2018 00:01:48 +0900 Subject: Implement `Array#union` which is introduced in Ruby2.6. --- mrbgems/mruby-array-ext/mrblib/array.rb | 19 +++++++++++++++++++ mrbgems/mruby-array-ext/test/array.rb | 8 ++++++++ 2 files changed, 27 insertions(+) diff --git a/mrbgems/mruby-array-ext/mrblib/array.rb b/mrbgems/mruby-array-ext/mrblib/array.rb index 4f676a121..8c2acc7ac 100644 --- a/mrbgems/mruby-array-ext/mrblib/array.rb +++ b/mrbgems/mruby-array-ext/mrblib/array.rb @@ -137,6 +137,25 @@ class Array ary.uniq! or ary end + ## + # call-seq: + # ary.union(other_ary,...) -> new_ary + # + # Set Union---Returns a new array by joining this array with + # other_ary, removing duplicates. + # + # ["a", "b", "c"].union(["c", "d", "a"], ["a", "c", "e"]) + # #=> ["a", "b", "c", "d", "e"] + # + def union(*args) + ary = self.dup + args.each_with_index do |x,i| + ary.concat(x) + ary.uniq! if i % 20 == 0 + end + ary.uniq! or ary + end + ## # call-seq: # ary & other_ary -> new_ary diff --git a/mrbgems/mruby-array-ext/test/array.rb b/mrbgems/mruby-array-ext/test/array.rb index 4f54c65c3..84f9cfeaf 100644 --- a/mrbgems/mruby-array-ext/test/array.rb +++ b/mrbgems/mruby-array-ext/test/array.rb @@ -75,6 +75,14 @@ assert("Array#|") do assert_equal [1, 2, 3, 1], a end +assert("Array#union") do + a = [1, 2, 3, 1] + b = [1, 4] + c = [1, 5] + + assert_equal [1, 2, 3, 4, 5], a.union(b,c) +end + assert("Array#&") do a = [1, 2, 3, 1] b = [1, 4] -- cgit v1.2.3 From 58ba38fe1e11828190596b44e0789dd8a0607ff3 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Thu, 20 Sep 2018 15:13:13 +0900 Subject: Add `String#tr` and `#tr!` to `mruby-string-ext` gem; fix #4086 This patch is based on `mruby/c` implementation by Hirohito Higashi. We might need to add `#tr_s`, `#squeeze` and `#delete` as well. Adding them should not be too hard using functions we implemented here. --- mrbgems/mruby-string-ext/src/string.c | 261 ++++++++++++++++++++++++++++++++ mrbgems/mruby-string-ext/test/string.rb | 13 ++ 2 files changed, 274 insertions(+) diff --git a/mrbgems/mruby-string-ext/src/string.c b/mrbgems/mruby-string-ext/src/string.c index 142d449f4..9d318cb1a 100644 --- a/mrbgems/mruby-string-ext/src/string.c +++ b/mrbgems/mruby-string-ext/src/string.c @@ -235,6 +235,265 @@ mrb_str_end_with(mrb_state *mrb, mrb_value self) return mrb_false_value(); } +/* + #tr Pattern syntax + + ::= ()* | '^' ()* + ::= | + ::= ()+ + ::= '-' +*/ +struct tr_pattern { + uint8_t type; // 1:in-order, 2:range + mrb_bool flag_reverse; + int16_t n; + struct tr_pattern *next; + char ch[]; +}; + +static void +tr_pattern_free(mrb_state *mrb, struct tr_pattern *pat) +{ + while (pat) { + struct tr_pattern *p = pat->next; + mrb_free(mrb, pat); + pat = p; + } +} + +static struct tr_pattern* +tr_parse_pattern(mrb_state *mrb, const mrb_value v_pattern, mrb_bool flag_reverse_enable) +{ + const char *pattern = RSTRING_PTR(v_pattern); + int pattern_length = RSTRING_LEN(v_pattern); + mrb_bool flag_reverse = FALSE; + struct tr_pattern *ret = NULL; + struct tr_pattern *pat1; + int i = 0; + + if(flag_reverse_enable && pattern_length >= 2 && pattern[0] == '^') { + flag_reverse = TRUE; + i++; + } + + while (i < pattern_length) { + /* is range pattern ? */ + if ((i+2) < pattern_length && pattern[i] != '\\' && pattern[i+1] == '-') { + pat1 = (struct tr_pattern*)mrb_malloc_simple(mrb, sizeof(struct tr_pattern) + 2); + if (pat1 == NULL && ret) { + nomem: + tr_pattern_free(mrb, ret); + mrb_exc_raise(mrb, mrb_obj_value(mrb->nomem_err)); + return NULL; /* not reached */ + } + pat1->type = 2; + pat1->flag_reverse = flag_reverse; + pat1->n = pattern[i+2] - pattern[i] + 1; + pat1->next = NULL; + pat1->ch[0] = pattern[i]; + pat1->ch[1] = pattern[i+2]; + i += 3; + } + else { + /* in order pattern. */ + int start_pos = i++; + int len; + + while (i < pattern_length) { + if ((i+2) < pattern_length && pattern[i] != '\\' && pattern[i+1] == '-') + break; + i++; + } + + len = i - start_pos; + pat1 = (struct tr_pattern*)mrb_malloc_simple(mrb, sizeof(struct tr_pattern) + len); + if (pat1 == NULL && ret) { + goto nomem; + } + pat1->type = 1; + pat1->flag_reverse = flag_reverse; + pat1->n = len; + pat1->next = NULL; + memcpy(pat1->ch, &pattern[start_pos], len); + } + + if (ret == NULL) { + ret = pat1; + } + else { + struct tr_pattern *p = ret; + while (p->next != NULL) { + p = p->next; + } + p->next = pat1; + } + } + + return ret; +} + +static mrb_int +tr_find_character(const struct tr_pattern *pat, int ch) +{ + mrb_int ret = -1; + mrb_int n_sum = 0; + mrb_int flag_reverse = pat ? pat->flag_reverse : 0; + + while (pat != NULL) { + if (pat->type == 1) { /* pat->type == 1 in-order */ + int i; + for (i = 0; i < pat->n; i++) { + if (pat->ch[i] == ch) ret = n_sum + i; + } + } + else { /* pat->type == 2 range */ + if (pat->ch[0] <= ch && ch <= pat->ch[1]) + ret = n_sum + ch - pat->ch[0]; + } + n_sum += pat->n; + pat = pat->next; + } + + if (flag_reverse) { + return (ret < 0) ? MRB_INT_MAX : -1; + } + return ret; +} + +static mrb_int +tr_get_character(const struct tr_pattern *pat, mrb_int n_th) +{ + mrb_int n_sum = 0; + while (pat != NULL) { + if (n_th < (n_sum + pat->n)) { + mrb_int i = (n_th - n_sum); + return (pat->type == 1) ? pat->ch[i] :pat->ch[0] + i; + } + if (pat->next == NULL) { + return (pat->type == 1) ? pat->ch[pat->n - 1] : pat->ch[1]; + } + n_sum += pat->n; + pat = pat->next; + } + + return -1; +} + +static mrb_bool +str_tr(mrb_state *mrb, mrb_value str, mrb_value p1, mrb_value p2) +{ + struct tr_pattern *pat; + struct tr_pattern *rep; + char *s; + mrb_int len; + mrb_int i; + mrb_bool flag_changed = FALSE; + + mrb_str_modify(mrb, mrb_str_ptr(str)); + pat = tr_parse_pattern(mrb, p1, TRUE); + rep = tr_parse_pattern(mrb, p2, FALSE); + s = RSTRING_PTR(str); + len = RSTRING_LEN(str); + + for (i = 0; i < len; i++) { + mrb_int n = tr_find_character(pat, s[i]); + + if (n >= 0) { + flag_changed = TRUE; + if (rep == NULL) { + memmove(s + i, s + i + 1, len - i); + len--; + i--; + } + else { + mrb_int c = tr_get_character(rep, n); + + if (c < 0 || c > 0x80) { + mrb_raisef(mrb, E_ARGUMENT_ERROR, "character (%S) out of range", + mrb_fixnum_value((mrb_int)c)); + } + s[i] = c; + } + } + } + + tr_pattern_free(mrb, pat); + if (rep) tr_pattern_free(mrb, rep); + + RSTR_SET_LEN(RSTRING(str), len); + RSTRING_PTR(str)[len] = 0; + + return flag_changed; +} + +/* + * call-seq: + * str.tr(from_str, to_str) => new_str + * + * Returns a copy of str with the characters in from_str replaced by the + * corresponding characters in to_str. If to_str is shorter than from_str, + * it is padded with its last character in order to maintain the + * correspondence. + * + * "hello".tr('el', 'ip') #=> "hippo" + * "hello".tr('aeiou', '*') #=> "h*ll*" + * "hello".tr('aeiou', 'AA*') #=> "hAll*" + * + * Both strings may use the c1-c2 notation to denote ranges of characters, + * and from_str may start with a ^, which denotes all characters except + * those listed. + * + * "hello".tr('a-y', 'b-z') #=> "ifmmp" + * "hello".tr('^aeiou', '*') #=> "*e**o" + * + * The backslash character \ can be used to escape ^ or - and is otherwise + * ignored unless it appears at the end of a range or the end of the + * from_str or to_str: + * + * + * "hello^world".tr("\\^aeiou", "*") #=> "h*ll**w*rld" + * "hello-world".tr("a\\-eo", "*") #=> "h*ll**w*rld" + * + * "hello\r\nworld".tr("\r", "") #=> "hello\nworld" + * "hello\r\nworld".tr("\\r", "") #=> "hello\r\nwold" + * "hello\r\nworld".tr("\\\r", "") #=> "hello\nworld" + * + * "X['\\b']".tr("X\\", "") #=> "['b']" + * "X['\\b']".tr("X-\\]", "") #=> "'b'" + * + * Note: conversion is effective only in ASCII region. + */ +static mrb_value +mrb_str_tr(mrb_state *mrb, mrb_value str) +{ + mrb_value dup; + mrb_value p1, p2; + + mrb_get_args(mrb, "SS", &p1, &p2); + dup = mrb_str_dup(mrb, str); + str_tr(mrb, dup, p1, p2); + return dup; +} + +/* + * call-seq: + * str.tr!(from_str, to_str) -> str or nil + * + * Translates str in place, using the same rules as String#tr. + * Returns str, or nil if no changes were made. + */ +static mrb_value +mrb_str_tr_bang(mrb_state *mrb, mrb_value str) +{ + mrb_value p1, p2; + + mrb_get_args(mrb, "SS", &p1, &p2); + if (str_tr(mrb, str, p1, p2)) { + return str; + } + return mrb_nil_value(); +} + static mrb_value mrb_str_hex(mrb_state *mrb, mrb_value self) { @@ -620,6 +879,8 @@ mrb_mruby_string_ext_gem_init(mrb_state* mrb) mrb_define_method(mrb, s, "swapcase", mrb_str_swapcase, MRB_ARGS_NONE()); mrb_define_method(mrb, s, "concat", mrb_str_concat_m, MRB_ARGS_REQ(1)); mrb_define_method(mrb, s, "<<", mrb_str_concat_m, MRB_ARGS_REQ(1)); + mrb_define_method(mrb, s, "tr", mrb_str_tr, MRB_ARGS_REQ(2)); + mrb_define_method(mrb, s, "tr!", mrb_str_tr_bang, MRB_ARGS_REQ(2)); mrb_define_method(mrb, s, "start_with?", mrb_str_start_with, MRB_ARGS_REST()); mrb_define_method(mrb, s, "end_with?", mrb_str_end_with, MRB_ARGS_REST()); mrb_define_method(mrb, s, "hex", mrb_str_hex, MRB_ARGS_NONE()); diff --git a/mrbgems/mruby-string-ext/test/string.rb b/mrbgems/mruby-string-ext/test/string.rb index b6146fb90..6b8a89c4d 100644 --- a/mrbgems/mruby-string-ext/test/string.rb +++ b/mrbgems/mruby-string-ext/test/string.rb @@ -147,6 +147,19 @@ assert('String#casecmp') do assert_equal 0, "abcdef".casecmp(o) end +assert('String#tr') do + assert_equal "ABC", "abc".tr('a-z', 'A-Z') + assert_equal "hippo", "hello".tr('el', 'ip') + assert_equal "Ruby", "Lisp".tr("Lisp", "Ruby") + assert_equal "*e**o", "hello".tr('^aeiou', '*') +end + +assert('String#tr!') do + s = "abcdefghijklmnopqR" + assert_equal "ab12222hijklmnopqR", s.tr!("cdefg", "12") + assert_equal "ab12222hijklmnopqR", s +end + assert('String#start_with?') do assert_true "hello".start_with?("heaven", "hell") assert_true !"hello".start_with?("heaven", "paradise") -- cgit v1.2.3 From c0ae8a96a1fb658b21428bee174602e9373eef3b Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Thu, 20 Sep 2018 16:46:42 +0900 Subject: Add `String#tr_s` and `String#tr_s!`; ref #4086 --- mrbgems/mruby-string-ext/src/string.c | 55 ++++++++++++++++++++++++++++++--- mrbgems/mruby-string-ext/test/string.rb | 13 ++++++++ 2 files changed, 64 insertions(+), 4 deletions(-) diff --git a/mrbgems/mruby-string-ext/src/string.c b/mrbgems/mruby-string-ext/src/string.c index 9d318cb1a..e41dde448 100644 --- a/mrbgems/mruby-string-ext/src/string.c +++ b/mrbgems/mruby-string-ext/src/string.c @@ -380,7 +380,7 @@ tr_get_character(const struct tr_pattern *pat, mrb_int n_th) } static mrb_bool -str_tr(mrb_state *mrb, mrb_value str, mrb_value p1, mrb_value p2) +str_tr(mrb_state *mrb, mrb_value str, mrb_value p1, mrb_value p2, mrb_bool squeeze) { struct tr_pattern *pat; struct tr_pattern *rep; @@ -388,6 +388,7 @@ str_tr(mrb_state *mrb, mrb_value str, mrb_value p1, mrb_value p2) mrb_int len; mrb_int i; mrb_bool flag_changed = FALSE; + mrb_int lastch = -1; mrb_str_modify(mrb, mrb_str_ptr(str)); pat = tr_parse_pattern(mrb, p1, TRUE); @@ -401,6 +402,7 @@ str_tr(mrb_state *mrb, mrb_value str, mrb_value p1, mrb_value p2) if (n >= 0) { flag_changed = TRUE; if (rep == NULL) { + compact: memmove(s + i, s + i + 1, len - i); len--; i--; @@ -408,11 +410,12 @@ str_tr(mrb_state *mrb, mrb_value str, mrb_value p1, mrb_value p2) else { mrb_int c = tr_get_character(rep, n); + if (squeeze && c == lastch) goto compact; if (c < 0 || c > 0x80) { mrb_raisef(mrb, E_ARGUMENT_ERROR, "character (%S) out of range", mrb_fixnum_value((mrb_int)c)); } - s[i] = c; + lastch = s[i] = c; } } } @@ -471,7 +474,7 @@ mrb_str_tr(mrb_state *mrb, mrb_value str) mrb_get_args(mrb, "SS", &p1, &p2); dup = mrb_str_dup(mrb, str); - str_tr(mrb, dup, p1, p2); + str_tr(mrb, dup, p1, p2, FALSE); return dup; } @@ -488,7 +491,49 @@ mrb_str_tr_bang(mrb_state *mrb, mrb_value str) mrb_value p1, p2; mrb_get_args(mrb, "SS", &p1, &p2); - if (str_tr(mrb, str, p1, p2)) { + if (str_tr(mrb, str, p1, p2, FALSE)) { + return str; + } + return mrb_nil_value(); +} + +/* + * call-seq: + * str.tr_s(from_str, to_str) -> new_str + * + * Processes a copy of str as described under String#tr, then removes + * duplicate characters in regions that were affected by the translation. + * + * "hello".tr_s('l', 'r') #=> "hero" + * "hello".tr_s('el', '*') #=> "h*o" + * "hello".tr_s('el', 'hx') #=> "hhxo" + */ +static mrb_value +mrb_str_tr_s(mrb_state *mrb, mrb_value str) +{ + mrb_value dup; + mrb_value p1, p2; + + mrb_get_args(mrb, "SS", &p1, &p2); + dup = mrb_str_dup(mrb, str); + str_tr(mrb, dup, p1, p2, TRUE); + return dup; +} + +/* + * call-seq: + * str.tr_s!(from_str, to_str) -> str or nil + * + * Performs String#tr_s processing on str in place, returning + * str, or nil if no changes were made. + */ +static mrb_value +mrb_str_tr_s_bang(mrb_state *mrb, mrb_value str) +{ + mrb_value p1, p2; + + mrb_get_args(mrb, "SS", &p1, &p2); + if (str_tr(mrb, str, p1, p2, TRUE)) { return str; } return mrb_nil_value(); @@ -881,6 +926,8 @@ mrb_mruby_string_ext_gem_init(mrb_state* mrb) mrb_define_method(mrb, s, "<<", mrb_str_concat_m, MRB_ARGS_REQ(1)); mrb_define_method(mrb, s, "tr", mrb_str_tr, MRB_ARGS_REQ(2)); mrb_define_method(mrb, s, "tr!", mrb_str_tr_bang, MRB_ARGS_REQ(2)); + mrb_define_method(mrb, s, "tr_s", mrb_str_tr_s, MRB_ARGS_REQ(2)); + mrb_define_method(mrb, s, "tr_s!", mrb_str_tr_s_bang, MRB_ARGS_REQ(2)); mrb_define_method(mrb, s, "start_with?", mrb_str_start_with, MRB_ARGS_REST()); mrb_define_method(mrb, s, "end_with?", mrb_str_end_with, MRB_ARGS_REST()); mrb_define_method(mrb, s, "hex", mrb_str_hex, MRB_ARGS_NONE()); diff --git a/mrbgems/mruby-string-ext/test/string.rb b/mrbgems/mruby-string-ext/test/string.rb index 6b8a89c4d..d50a2b3b4 100644 --- a/mrbgems/mruby-string-ext/test/string.rb +++ b/mrbgems/mruby-string-ext/test/string.rb @@ -160,6 +160,19 @@ assert('String#tr!') do assert_equal "ab12222hijklmnopqR", s end +assert('String#tr_s') do + assert_equal "hero", "hello".tr_s('l', 'r') + assert_equal "h*o", "hello".tr_s('el', '*') + assert_equal "hhxo", "hello".tr_s('el', 'hx') +end + +assert('String#tr_s!') do + s = "hello" + assert_equal "hero", s.tr_s!('l', 'r') + assert_equal "hero", s + assert_nil s.tr_s!('l', 'r') +end + assert('String#start_with?') do assert_true "hello".start_with?("heaven", "hell") assert_true !"hello".start_with?("heaven", "paradise") -- cgit v1.2.3 From 68523b4ec4a271134aae34d744582a974558c962 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Thu, 20 Sep 2018 17:14:15 +0900 Subject: Add `String#squeeze` and `#squeeze!`; ref #4086 mruby restriction: `String#squeeze` can take more than 1 pattern arguments in CRuby, in that case, the intersection of patterns will be used to match. But in mruby, it doesn't take multiple patterns. --- mrbgems/mruby-string-ext/src/string.c | 103 ++++++++++++++++++++++++++++++-- mrbgems/mruby-string-ext/test/string.rb | 12 ++++ 2 files changed, 111 insertions(+), 4 deletions(-) diff --git a/mrbgems/mruby-string-ext/src/string.c b/mrbgems/mruby-string-ext/src/string.c index e41dde448..ddc4505fc 100644 --- a/mrbgems/mruby-string-ext/src/string.c +++ b/mrbgems/mruby-string-ext/src/string.c @@ -262,12 +262,11 @@ tr_pattern_free(mrb_state *mrb, struct tr_pattern *pat) } static struct tr_pattern* -tr_parse_pattern(mrb_state *mrb, const mrb_value v_pattern, mrb_bool flag_reverse_enable) +tr_parse_pattern(mrb_state *mrb, struct tr_pattern *ret, const mrb_value v_pattern, mrb_bool flag_reverse_enable) { const char *pattern = RSTRING_PTR(v_pattern); int pattern_length = RSTRING_LEN(v_pattern); mrb_bool flag_reverse = FALSE; - struct tr_pattern *ret = NULL; struct tr_pattern *pat1; int i = 0; @@ -391,8 +390,8 @@ str_tr(mrb_state *mrb, mrb_value str, mrb_value p1, mrb_value p2, mrb_bool squee mrb_int lastch = -1; mrb_str_modify(mrb, mrb_str_ptr(str)); - pat = tr_parse_pattern(mrb, p1, TRUE); - rep = tr_parse_pattern(mrb, p2, FALSE); + pat = tr_parse_pattern(mrb, NULL, p1, TRUE); + rep = tr_parse_pattern(mrb, NULL, p2, FALSE); s = RSTRING_PTR(str); len = RSTRING_LEN(str); @@ -539,6 +538,100 @@ mrb_str_tr_s_bang(mrb_state *mrb, mrb_value str) return mrb_nil_value(); } +static mrb_bool +str_squeeze(mrb_state *mrb, mrb_value str, mrb_value v_pat) +{ + struct tr_pattern *pat = NULL; + mrb_int i; + char *s; + mrb_int len; + mrb_bool flag_changed = FALSE; + mrb_int lastch = -1; + + mrb_str_modify(mrb, mrb_str_ptr(str)); + if (!mrb_nil_p(v_pat)) { + pat = tr_parse_pattern(mrb, pat, v_pat, TRUE); + } + s = RSTRING_PTR(str); + len = RSTRING_LEN(str); + + if (pat) { + for (i = 0; i < len; i++) { + mrb_int n = tr_find_character(pat, s[i]); + + if (n >= 0 && s[i] == lastch) { + flag_changed = TRUE; + memmove(s + i, s + i + 1, len - i); + len--; + i--; + } + lastch = s[i]; + } + } + else { + for (i = 0; i < len; i++) { + if (s[i] == lastch) { + flag_changed = TRUE; + memmove(s + i, s + i + 1, len - i); + len--; + i--; + } + lastch = s[i]; + } + } + tr_pattern_free(mrb, pat); + + RSTR_SET_LEN(RSTRING(str), len); + RSTRING_PTR(str)[len] = 0; + + return flag_changed; +} + +/* + * call-seq: + * str.squeeze([other_str]) -> new_str + * + * Builds a set of characters from the other_str + * parameter(s) using the procedure described for String#count. Returns a + * new string where runs of the same character that occur in this set are + * replaced by a single character. If no arguments are given, all runs of + * identical characters are replaced by a single character. + * + * "yellow moon".squeeze #=> "yelow mon" + * " now is the".squeeze(" ") #=> " now is the" + * "putters shoot balls".squeeze("m-z") #=> "puters shot balls" + */ +static mrb_value +mrb_str_squeeze(mrb_state *mrb, mrb_value str) +{ + mrb_value pat = mrb_nil_value(); + mrb_value dup; + + mrb_get_args(mrb, "|S", &pat); + dup = mrb_str_dup(mrb, str); + str_squeeze(mrb, dup, pat); + return dup; +} + +/* + * call-seq: + * str.squeeze!([other_str]) -> str or nil + * + * Squeezes str in place, returning either str, or nil if no + * changes were made. + */ +static mrb_value +mrb_str_squeeze_bang(mrb_state *mrb, mrb_value str) +{ + mrb_value pat = mrb_nil_value(); + + mrb_get_args(mrb, "|S", &pat); + if (str_squeeze(mrb, str, pat)) { + return str; + } + return mrb_nil_value(); +} + static mrb_value mrb_str_hex(mrb_state *mrb, mrb_value self) { @@ -928,6 +1021,8 @@ mrb_mruby_string_ext_gem_init(mrb_state* mrb) mrb_define_method(mrb, s, "tr!", mrb_str_tr_bang, MRB_ARGS_REQ(2)); mrb_define_method(mrb, s, "tr_s", mrb_str_tr_s, MRB_ARGS_REQ(2)); mrb_define_method(mrb, s, "tr_s!", mrb_str_tr_s_bang, MRB_ARGS_REQ(2)); + mrb_define_method(mrb, s, "squeeze", mrb_str_squeeze, MRB_ARGS_OPT(1)); + mrb_define_method(mrb, s, "squeeze!", mrb_str_squeeze_bang, MRB_ARGS_OPT(1)); mrb_define_method(mrb, s, "start_with?", mrb_str_start_with, MRB_ARGS_REST()); mrb_define_method(mrb, s, "end_with?", mrb_str_end_with, MRB_ARGS_REST()); mrb_define_method(mrb, s, "hex", mrb_str_hex, MRB_ARGS_NONE()); diff --git a/mrbgems/mruby-string-ext/test/string.rb b/mrbgems/mruby-string-ext/test/string.rb index d50a2b3b4..fd6f83e71 100644 --- a/mrbgems/mruby-string-ext/test/string.rb +++ b/mrbgems/mruby-string-ext/test/string.rb @@ -173,6 +173,18 @@ assert('String#tr_s!') do assert_nil s.tr_s!('l', 'r') end +assert('String#squeeze') do + assert_equal "yelow mon", "yellow moon".squeeze + assert_equal " now is the", " now is the".squeeze(" ") + assert_equal "puters shot balls", "putters shoot balls".squeeze("m-z") +end + +assert('String#squeeze!') do + s = " now is the" + assert_equal " now is the", s.squeeze!(" ") + assert_equal " now is the", s +end + assert('String#start_with?') do assert_true "hello".start_with?("heaven", "hell") assert_true !"hello".start_with?("heaven", "paradise") -- cgit v1.2.3 From 58f7f2361a39ae288c4233ca434e1dbd37f127d0 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Thu, 20 Sep 2018 17:25:07 +0900 Subject: Implement `String#count`; ref #4086 mruby restriction: In mruby, `String#count` does not take multiple pattern arguments, but only one pattern. --- mrbgems/mruby-string-ext/src/string.c | 34 +++++++++++++++++++++++++++++++++ mrbgems/mruby-string-ext/test/string.rb | 9 +++++++++ 2 files changed, 43 insertions(+) diff --git a/mrbgems/mruby-string-ext/src/string.c b/mrbgems/mruby-string-ext/src/string.c index ddc4505fc..d42a5d488 100644 --- a/mrbgems/mruby-string-ext/src/string.c +++ b/mrbgems/mruby-string-ext/src/string.c @@ -632,6 +632,39 @@ mrb_str_squeeze_bang(mrb_state *mrb, mrb_value str) return mrb_nil_value(); } +/* + * call_seq: + * str.count([other_str]) -> integer + * + * Each other_str parameter defines a set of characters to count. The + * intersection of these sets defines the characters to count in str. Any + * other_str that starts with a caret ^ is negated. The sequence c1-c2 + * means all characters between c1 and c2. The backslash character \ can + * be used to escape ^ or - and is otherwise ignored unless it appears at + * the end of a sequence or the end of a other_str. + */ +static mrb_value +mrb_str_count(mrb_state *mrb, mrb_value str) +{ + mrb_value v_pat = mrb_nil_value(); + struct tr_pattern *pat = NULL; + mrb_int i; + char *s; + mrb_int len; + mrb_int count = 0; + + mrb_get_args(mrb, "S", &v_pat); + pat = tr_parse_pattern(mrb, pat, v_pat, TRUE); + s = RSTRING_PTR(str); + len = RSTRING_LEN(str); + for (i = 0; i < len; i++) { + mrb_int n = tr_find_character(pat, s[i]); + + if (n >= 0) count++; + } + return mrb_fixnum_value(count); +} + static mrb_value mrb_str_hex(mrb_state *mrb, mrb_value self) { @@ -1017,6 +1050,7 @@ mrb_mruby_string_ext_gem_init(mrb_state* mrb) mrb_define_method(mrb, s, "swapcase", mrb_str_swapcase, MRB_ARGS_NONE()); mrb_define_method(mrb, s, "concat", mrb_str_concat_m, MRB_ARGS_REQ(1)); mrb_define_method(mrb, s, "<<", mrb_str_concat_m, MRB_ARGS_REQ(1)); + mrb_define_method(mrb, s, "count", mrb_str_count, MRB_ARGS_REQ(1)); mrb_define_method(mrb, s, "tr", mrb_str_tr, MRB_ARGS_REQ(2)); mrb_define_method(mrb, s, "tr!", mrb_str_tr_bang, MRB_ARGS_REQ(2)); mrb_define_method(mrb, s, "tr_s", mrb_str_tr_s, MRB_ARGS_REQ(2)); diff --git a/mrbgems/mruby-string-ext/test/string.rb b/mrbgems/mruby-string-ext/test/string.rb index fd6f83e71..3e9ab5b1b 100644 --- a/mrbgems/mruby-string-ext/test/string.rb +++ b/mrbgems/mruby-string-ext/test/string.rb @@ -147,6 +147,15 @@ assert('String#casecmp') do assert_equal 0, "abcdef".casecmp(o) end +assert('String#count') do + s = "abccdeff123" + assert_equal 1, s.count("a") + assert_equal 2, s.count("ab") + assert_equal 9, s.count("^c") + assert_equal 8, s.count("a-z") + assert_equal 4, s.count("a0-9") +end + assert('String#tr') do assert_equal "ABC", "abc".tr('a-z', 'A-Z') assert_equal "hippo", "hello".tr('el', 'ip') -- cgit v1.2.3 From 346f154ece3bd68b63dfee4b4c4d9a20c0eee063 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Thu, 20 Sep 2018 18:05:26 +0900 Subject: Implement `String#delete` and `#delete!`; ref #4086 mruby restriction: In mruby, `String#delete` only takes single pattern argument. --- mrbgems/mruby-string-ext/src/string.c | 58 +++++++++++++++++++++++++++++++++ mrbgems/mruby-string-ext/test/string.rb | 14 ++++++++ 2 files changed, 72 insertions(+) diff --git a/mrbgems/mruby-string-ext/src/string.c b/mrbgems/mruby-string-ext/src/string.c index d42a5d488..a91b483e7 100644 --- a/mrbgems/mruby-string-ext/src/string.c +++ b/mrbgems/mruby-string-ext/src/string.c @@ -632,6 +632,62 @@ mrb_str_squeeze_bang(mrb_state *mrb, mrb_value str) return mrb_nil_value(); } +static mrb_bool +str_delete(mrb_state *mrb, mrb_value str, mrb_value v_pat) +{ + struct tr_pattern *pat = NULL; + mrb_int i; + char *s; + mrb_int len; + mrb_bool flag_changed = FALSE; + + mrb_str_modify(mrb, mrb_str_ptr(str)); + pat = tr_parse_pattern(mrb, pat, v_pat, TRUE); + s = RSTRING_PTR(str); + len = RSTRING_LEN(str); + + for (i = 0; i < len; i++) { + mrb_int n = tr_find_character(pat, s[i]); + + if (n >= 0) { + flag_changed = TRUE; + memmove(s + i, s + i + 1, len - i); + len--; + i--; + } + } + tr_pattern_free(mrb, pat); + + RSTR_SET_LEN(RSTRING(str), len); + RSTRING_PTR(str)[len] = 0; + + return flag_changed; +} + +static mrb_value +mrb_str_delete(mrb_state *mrb, mrb_value str) +{ + mrb_value pat; + mrb_value dup; + + mrb_get_args(mrb, "S", &pat); + dup = mrb_str_dup(mrb, str); + str_delete(mrb, dup, pat); + return dup; +} + +static mrb_value +mrb_str_delete_bang(mrb_state *mrb, mrb_value str) +{ + mrb_value pat; + + mrb_get_args(mrb, "S", &pat); + if (str_delete(mrb, str, pat)) { + return str; + } + return mrb_nil_value(); +} + /* * call_seq: * str.count([other_str]) -> integer @@ -1057,6 +1113,8 @@ mrb_mruby_string_ext_gem_init(mrb_state* mrb) mrb_define_method(mrb, s, "tr_s!", mrb_str_tr_s_bang, MRB_ARGS_REQ(2)); mrb_define_method(mrb, s, "squeeze", mrb_str_squeeze, MRB_ARGS_OPT(1)); mrb_define_method(mrb, s, "squeeze!", mrb_str_squeeze_bang, MRB_ARGS_OPT(1)); + mrb_define_method(mrb, s, "delete", mrb_str_delete, MRB_ARGS_REQ(1)); + mrb_define_method(mrb, s, "delete!", mrb_str_delete_bang, MRB_ARGS_REQ(1)); mrb_define_method(mrb, s, "start_with?", mrb_str_start_with, MRB_ARGS_REST()); mrb_define_method(mrb, s, "end_with?", mrb_str_end_with, MRB_ARGS_REST()); mrb_define_method(mrb, s, "hex", mrb_str_hex, MRB_ARGS_NONE()); diff --git a/mrbgems/mruby-string-ext/test/string.rb b/mrbgems/mruby-string-ext/test/string.rb index 3e9ab5b1b..36a253989 100644 --- a/mrbgems/mruby-string-ext/test/string.rb +++ b/mrbgems/mruby-string-ext/test/string.rb @@ -194,6 +194,20 @@ assert('String#squeeze!') do assert_equal " now is the", s end +assert('String#delete') do + assert_equal "he", "hello".delete("lo") + assert_equal "hll", "hello".delete("aeiou") + assert_equal "ll", "hello".delete("^l") + assert_equal "ho", "hello".delete("ej-m") +end + +assert('String#delete!') do + s = "hello" + assert_equal "he", s.delete!("lo") + assert_equal "he", s + assert_nil s.delete!("lz") +end + assert('String#start_with?') do assert_true "hello".start_with?("heaven", "hell") assert_true !"hello".start_with?("heaven", "paradise") -- cgit v1.2.3 From 9bd2a3b5d9f56d838a25e2038f948afdc4adccac Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Fri, 21 Sep 2018 00:49:40 +0900 Subject: Fixed a top-level local variable bug in `mirb`. `OP_STOP` returned a wrong value. --- src/vm.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/vm.c b/src/vm.c index 14c42984e..0192fc907 100644 --- a/src/vm.c +++ b/src/vm.c @@ -2056,6 +2056,7 @@ RETRY_TRY_BLOCK: struct mrb_context *c; if (!mrb->c->prev) { /* toplevel return */ + regs[irep->nlocals] = v; goto L_STOP; } if (mrb->c->prev->ci == mrb->c->prev->cibase) { -- cgit v1.2.3 From 8fc56f062e40ce9eaaa61ab917cfccc2c23989d1 Mon Sep 17 00:00:00 2001 From: sbsoftware Date: Fri, 21 Sep 2018 04:22:53 +0200 Subject: Add compiler flag to disable direct threading (#4075) * Add option to disable direct threading * Prepend MRB_ to option name --- src/vm.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/vm.c b/src/vm.c index 0192fc907..cba6c3924 100644 --- a/src/vm.c +++ b/src/vm.c @@ -927,10 +927,11 @@ argnum_error(mrb_state *mrb, mrb_int num) #define BYTECODE_DECODER(x) (x) #endif - +#ifndef MRB_DISABLE_DIRECT_THREADING #if defined __GNUC__ || defined __clang__ || defined __INTEL_COMPILER #define DIRECT_THREADED #endif +#endif /* ifndef MRB_DISABLE_DIRECT_THREADING */ #ifndef DIRECT_THREADED -- cgit v1.2.3 From 7b04fcd092006b6e78cd63619fb7ae972f8e0c5d Mon Sep 17 00:00:00 2001 From: Clayton Smith Date: Mon, 24 Sep 2018 18:16:12 -0400 Subject: Fix comparisons in str_squeeze. --- mrbgems/mruby-string-ext/src/string.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mrbgems/mruby-string-ext/src/string.c b/mrbgems/mruby-string-ext/src/string.c index a91b483e7..8d79c80e2 100644 --- a/mrbgems/mruby-string-ext/src/string.c +++ b/mrbgems/mruby-string-ext/src/string.c @@ -543,7 +543,7 @@ str_squeeze(mrb_state *mrb, mrb_value str, mrb_value v_pat) { struct tr_pattern *pat = NULL; mrb_int i; - char *s; + unsigned char *s; mrb_int len; mrb_bool flag_changed = FALSE; mrb_int lastch = -1; @@ -552,7 +552,7 @@ str_squeeze(mrb_state *mrb, mrb_value str, mrb_value v_pat) if (!mrb_nil_p(v_pat)) { pat = tr_parse_pattern(mrb, pat, v_pat, TRUE); } - s = RSTRING_PTR(str); + s = (unsigned char *)RSTRING_PTR(str); len = RSTRING_LEN(str); if (pat) { -- cgit v1.2.3 From 4d5e3e1e634c21452d8f1eef895b5e11ab809b56 Mon Sep 17 00:00:00 2001 From: Daniel Varga Date: Tue, 25 Sep 2018 02:14:01 +0200 Subject: Fix minor typos (#4126) --- include/mruby.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/mruby.h b/include/mruby.h index 2d30d3d27..8eff31746 100644 --- a/include/mruby.h +++ b/include/mruby.h @@ -385,7 +385,7 @@ MRB_API void mrb_define_class_method(mrb_state *, struct RClass *, const char *, MRB_API void mrb_define_singleton_method(mrb_state*, struct RObject*, const char*, mrb_func_t, mrb_aspec); /** - * Defines a module fuction. + * Defines a module function. * * Example: * @@ -530,7 +530,7 @@ MRB_API void mrb_undef_method_id(mrb_state*, struct RClass*, mrb_sym); MRB_API void mrb_undef_class_method(mrb_state*, struct RClass*, const char*); /** - * Initialize a new object instace of c class. + * Initialize a new object instance of c class. * * Example: * -- cgit v1.2.3 From 67897195deb7d7a3cc0927b0f585416153e49448 Mon Sep 17 00:00:00 2001 From: Takeshi Watanabe Date: Tue, 25 Sep 2018 11:48:59 +0900 Subject: Fix leak in `mrb_str_count` --- mrbgems/mruby-string-ext/src/string.c | 1 + 1 file changed, 1 insertion(+) diff --git a/mrbgems/mruby-string-ext/src/string.c b/mrbgems/mruby-string-ext/src/string.c index 8d79c80e2..b66ada1d2 100644 --- a/mrbgems/mruby-string-ext/src/string.c +++ b/mrbgems/mruby-string-ext/src/string.c @@ -718,6 +718,7 @@ mrb_str_count(mrb_state *mrb, mrb_value str) if (n >= 0) count++; } + tr_pattern_free(mrb, pat); return mrb_fixnum_value(count); } -- cgit v1.2.3 From 78195eb2aeb6dbb9eea7d10cd4d5ac7caaa1bab7 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Fri, 21 Sep 2018 10:27:09 +0900 Subject: Small refactoring in vm.c --- src/vm.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/vm.c b/src/vm.c index cba6c3924..9eeb388fc 100644 --- a/src/vm.c +++ b/src/vm.c @@ -2054,22 +2054,21 @@ RETRY_TRY_BLOCK: case OP_R_NORMAL: NORMAL_RETURN: if (ci == mrb->c->cibase) { - struct mrb_context *c; + struct mrb_context *c = mrb->c; - if (!mrb->c->prev) { /* toplevel return */ + if (!c->prev) { /* toplevel return */ regs[irep->nlocals] = v; goto L_STOP; } - if (mrb->c->prev->ci == mrb->c->prev->cibase) { + if (c->prev->ci == c->prev->cibase) { mrb_value exc = mrb_exc_new_str_lit(mrb, E_FIBER_ERROR, "double resume"); mrb_exc_set(mrb, exc); goto L_RAISE; } - while (mrb->c->eidx > 0) { + while (c->eidx > 0) { ecall(mrb); } /* automatic yield at the end */ - c = mrb->c; c->status = MRB_FIBER_TERMINATED; mrb->c = c->prev; c->prev = NULL; -- cgit v1.2.3 From fb49a9431482d7f60d065af68c5c0e028b130c41 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Sun, 23 Sep 2018 21:10:25 +0900 Subject: Rename `tr_pattern_free()` to `tr_free_pattern()`. --- mrbgems/mruby-string-ext/src/string.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/mrbgems/mruby-string-ext/src/string.c b/mrbgems/mruby-string-ext/src/string.c index b66ada1d2..3faa3d428 100644 --- a/mrbgems/mruby-string-ext/src/string.c +++ b/mrbgems/mruby-string-ext/src/string.c @@ -252,7 +252,7 @@ struct tr_pattern { }; static void -tr_pattern_free(mrb_state *mrb, struct tr_pattern *pat) +tr_free_pattern(mrb_state *mrb, struct tr_pattern *pat) { while (pat) { struct tr_pattern *p = pat->next; @@ -281,7 +281,7 @@ tr_parse_pattern(mrb_state *mrb, struct tr_pattern *ret, const mrb_value v_patte pat1 = (struct tr_pattern*)mrb_malloc_simple(mrb, sizeof(struct tr_pattern) + 2); if (pat1 == NULL && ret) { nomem: - tr_pattern_free(mrb, ret); + tr_free_pattern(mrb, ret); mrb_exc_raise(mrb, mrb_obj_value(mrb->nomem_err)); return NULL; /* not reached */ } @@ -419,8 +419,8 @@ str_tr(mrb_state *mrb, mrb_value str, mrb_value p1, mrb_value p2, mrb_bool squee } } - tr_pattern_free(mrb, pat); - if (rep) tr_pattern_free(mrb, rep); + tr_free_pattern(mrb, pat); + if (rep) tr_free_pattern(mrb, rep); RSTR_SET_LEN(RSTRING(str), len); RSTRING_PTR(str)[len] = 0; @@ -579,7 +579,7 @@ str_squeeze(mrb_state *mrb, mrb_value str, mrb_value v_pat) lastch = s[i]; } } - tr_pattern_free(mrb, pat); + tr_free_pattern(mrb, pat); RSTR_SET_LEN(RSTRING(str), len); RSTRING_PTR(str)[len] = 0; @@ -656,7 +656,7 @@ str_delete(mrb_state *mrb, mrb_value str, mrb_value v_pat) i--; } } - tr_pattern_free(mrb, pat); + tr_free_pattern(mrb, pat); RSTR_SET_LEN(RSTRING(str), len); RSTRING_PTR(str)[len] = 0; @@ -718,7 +718,7 @@ mrb_str_count(mrb_state *mrb, mrb_value str) if (n >= 0) count++; } - tr_pattern_free(mrb, pat); + tr_free_pattern(mrb, pat); return mrb_fixnum_value(count); } -- cgit v1.2.3 From 87ce74016894940355b402f58884c48396fcf570 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Tue, 25 Sep 2018 09:18:32 +0900 Subject: Disambiguate block braces. --- mrbgems/mruby-sleep/test/sleep_test.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mrbgems/mruby-sleep/test/sleep_test.rb b/mrbgems/mruby-sleep/test/sleep_test.rb index e5ea5f69e..74030c0d3 100644 --- a/mrbgems/mruby-sleep/test/sleep_test.rb +++ b/mrbgems/mruby-sleep/test/sleep_test.rb @@ -16,7 +16,7 @@ assert("sleep works") do end assert("sleep would not accept negative value") do - e = run_with_catching_error { sleep -1 } + e = run_with_catching_error{ sleep -1 } assert_not_equal e, nil assert_equal e.class, ArgumentError @@ -29,7 +29,7 @@ assert("usleep works") do end assert("usleep would not accept negative value") do - e = run_with_catching_error { usleep -100 } + e = run_with_catching_error{ usleep -100 } assert_not_equal e, nil assert_equal e.class, ArgumentError -- cgit v1.2.3 From 9e3cbaaacd01aa75622252fe42d35a47014da1fd Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Wed, 26 Sep 2018 12:16:07 +0900 Subject: Avoid using `memmove()` for performance; fix #4130 --- mrbgems/mruby-string-ext/src/string.c | 61 ++++++++++++++++++----------------- 1 file changed, 31 insertions(+), 30 deletions(-) diff --git a/mrbgems/mruby-string-ext/src/string.c b/mrbgems/mruby-string-ext/src/string.c index 3faa3d428..aedff7266 100644 --- a/mrbgems/mruby-string-ext/src/string.c +++ b/mrbgems/mruby-string-ext/src/string.c @@ -386,6 +386,7 @@ str_tr(mrb_state *mrb, mrb_value str, mrb_value p1, mrb_value p2, mrb_bool squee char *s; mrb_int len; mrb_int i; + mrb_int j; mrb_bool flag_changed = FALSE; mrb_int lastch = -1; @@ -395,21 +396,22 @@ str_tr(mrb_state *mrb, mrb_value str, mrb_value p1, mrb_value p2, mrb_bool squee s = RSTRING_PTR(str); len = RSTRING_LEN(str); - for (i = 0; i < len; i++) { + for (i=j=0; ij) s[j] = s[i]; if (n >= 0) { flag_changed = TRUE; if (rep == NULL) { - compact: - memmove(s + i, s + i + 1, len - i); - len--; - i--; + j--; } else { mrb_int c = tr_get_character(rep, n); - if (squeeze && c == lastch) goto compact; + if (squeeze && c == lastch) { + j--; + continue; + } if (c < 0 || c > 0x80) { mrb_raisef(mrb, E_ARGUMENT_ERROR, "character (%S) out of range", mrb_fixnum_value((mrb_int)c)); @@ -422,9 +424,10 @@ str_tr(mrb_state *mrb, mrb_value str, mrb_value p1, mrb_value p2, mrb_bool squee tr_free_pattern(mrb, pat); if (rep) tr_free_pattern(mrb, rep); - RSTR_SET_LEN(RSTRING(str), len); - RSTRING_PTR(str)[len] = 0; - + if (flag_changed) { + RSTR_SET_LEN(RSTRING(str), j); + RSTRING_PTR(str)[j] = 0; + } return flag_changed; } @@ -542,7 +545,7 @@ static mrb_bool str_squeeze(mrb_state *mrb, mrb_value str, mrb_value v_pat) { struct tr_pattern *pat = NULL; - mrb_int i; + mrb_int i, j; unsigned char *s; mrb_int len; mrb_bool flag_changed = FALSE; @@ -556,34 +559,33 @@ str_squeeze(mrb_state *mrb, mrb_value str, mrb_value v_pat) len = RSTRING_LEN(str); if (pat) { - for (i = 0; i < len; i++) { + for (i=j=0; ij) s[j] = s[i]; if (n >= 0 && s[i] == lastch) { flag_changed = TRUE; - memmove(s + i, s + i + 1, len - i); - len--; - i--; + j--; } lastch = s[i]; } } else { - for (i = 0; i < len; i++) { + for (i=j=0; ij) s[j] = s[i]; if (s[i] == lastch) { flag_changed = TRUE; - memmove(s + i, s + i + 1, len - i); - len--; - i--; + j--; } lastch = s[i]; } } tr_free_pattern(mrb, pat); - RSTR_SET_LEN(RSTRING(str), len); - RSTRING_PTR(str)[len] = 0; - + if (flag_changed) { + RSTR_SET_LEN(RSTRING(str), j); + RSTRING_PTR(str)[j] = 0; + } return flag_changed; } @@ -636,7 +638,7 @@ static mrb_bool str_delete(mrb_state *mrb, mrb_value str, mrb_value v_pat) { struct tr_pattern *pat = NULL; - mrb_int i; + mrb_int i, j; char *s; mrb_int len; mrb_bool flag_changed = FALSE; @@ -646,21 +648,20 @@ str_delete(mrb_state *mrb, mrb_value str, mrb_value v_pat) s = RSTRING_PTR(str); len = RSTRING_LEN(str); - for (i = 0; i < len; i++) { + for (i=j=0; ij) s[j] = s[i]; if (n >= 0) { flag_changed = TRUE; - memmove(s + i, s + i + 1, len - i); - len--; - i--; + j--; } } tr_free_pattern(mrb, pat); - - RSTR_SET_LEN(RSTRING(str), len); - RSTRING_PTR(str)[len] = 0; - + if (flag_changed) { + RSTR_SET_LEN(RSTRING(str), j); + RSTRING_PTR(str)[j] = 0; + } return flag_changed; } -- cgit v1.2.3 From 01c2f59e14d8483ab1dc9dc8b06d3a42f0ecc88e Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Wed, 26 Sep 2018 12:32:33 +0900 Subject: Revert "Fix comparisons in str_squeeze." This reverts commit 7b04fcd092006b6e78cd63619fb7ae972f8e0c5d. The issue was addressed by 9e3cbaa. No longer needed. --- mrbgems/mruby-string-ext/src/string.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mrbgems/mruby-string-ext/src/string.c b/mrbgems/mruby-string-ext/src/string.c index aedff7266..ea8d77249 100644 --- a/mrbgems/mruby-string-ext/src/string.c +++ b/mrbgems/mruby-string-ext/src/string.c @@ -546,7 +546,7 @@ str_squeeze(mrb_state *mrb, mrb_value str, mrb_value v_pat) { struct tr_pattern *pat = NULL; mrb_int i, j; - unsigned char *s; + char *s; mrb_int len; mrb_bool flag_changed = FALSE; mrb_int lastch = -1; @@ -555,7 +555,7 @@ str_squeeze(mrb_state *mrb, mrb_value str, mrb_value v_pat) if (!mrb_nil_p(v_pat)) { pat = tr_parse_pattern(mrb, pat, v_pat, TRUE); } - s = (unsigned char *)RSTRING_PTR(str); + s = RSTRING_PTR(str); len = RSTRING_LEN(str); if (pat) { -- cgit v1.2.3 From e8dcfe17454eb88f266f90cf31ca562e30378291 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Mon, 6 Aug 2018 16:38:38 +0900 Subject: Use segmented list to implement `Hash` [Experimental] I know it's not hash at all, but reduce memory consumption. --- include/mruby/hash.h | 5 +- src/hash.c | 634 ++++++++++++++++++++++++++++++++------------------- 2 files changed, 400 insertions(+), 239 deletions(-) diff --git a/include/mruby/hash.h b/include/mruby/hash.h index 449a7d4bc..dacdd9376 100644 --- a/include/mruby/hash.h +++ b/include/mruby/hash.h @@ -18,7 +18,7 @@ MRB_BEGIN_DECL struct RHash { MRB_OBJECT_HEADER; struct iv_tbl *iv; - struct kh_ht *ht; + struct seglist *ht; }; #define mrb_hash_ptr(v) ((struct RHash*)(mrb_ptr(v))) @@ -76,7 +76,7 @@ MRB_API mrb_value mrb_hash_get(mrb_state *mrb, mrb_value hash, mrb_value key); * * Equivalent to: * - * hash.hash_key?(key) ? hash[key] : def + * hash.key?(key) ? hash[key] : def * * @param mrb The mruby state reference. * @param hash The target hash. @@ -199,7 +199,6 @@ KHASH_DECLARE(ht, mrb_value, mrb_hash_value, TRUE) #define RHASH_TBL(h) (RHASH(h)->ht) #define RHASH_IFNONE(h) mrb_iv_get(mrb, (h), mrb_intern_lit(mrb, "ifnone")) #define RHASH_PROCDEFAULT(h) RHASH_IFNONE(h) -MRB_API struct kh_ht * mrb_hash_tbl(mrb_state *mrb, mrb_value hash); #define MRB_HASH_DEFAULT 1 #define MRB_HASH_PROC_DEFAULT 2 diff --git a/src/hash.c b/src/hash.c index f6b61f4e1..16d49af24 100644 --- a/src/hash.c +++ b/src/hash.c @@ -8,7 +8,6 @@ #include #include #include -#include #include #include @@ -47,7 +46,7 @@ mrb_hash_ht_hash_func(mrb_state *mrb, mrb_value key) return kh_int_hash_func(mrb, h); } -static inline khint_t +static inline mrb_bool mrb_hash_ht_hash_equal(mrb_state *mrb, mrb_value a, mrb_value b) { enum mrb_vtype t = mrb_type(a); @@ -89,7 +88,251 @@ mrb_hash_ht_hash_equal(mrb_state *mrb, mrb_value a, mrb_value b) } } -KHASH_DEFINE (ht, mrb_value, mrb_hash_value, TRUE, mrb_hash_ht_hash_func, mrb_hash_ht_hash_equal) +/* return non zero to break the loop */ +typedef int (sg_foreach_func)(mrb_state *mrb,mrb_value key,mrb_value val, void *data); + +#ifndef MRB_SG_SEGMENT_SIZE +#define MRB_SG_SEGMENT_SIZE 5 +#endif + +typedef struct segment { + mrb_value key[MRB_SG_SEGMENT_SIZE]; + mrb_value val[MRB_SG_SEGMENT_SIZE]; + struct segment *next; +} segment; + +/* Instance variable table structure */ +typedef struct seglist { + segment *rootseg; + size_t size; + size_t last_len; +} seglist; + +/* Creates the instance variable table. */ +static seglist* +sg_new(mrb_state *mrb) +{ + seglist *t; + + t = (seglist*)mrb_malloc(mrb, sizeof(seglist)); + t->size = 0; + t->rootseg = NULL; + t->last_len = 0; + + return t; +} + +/* Set the value for the symbol in the instance variable table. */ +static void +sg_put(mrb_state *mrb, seglist *t, mrb_value key, mrb_value val) +{ + segment *seg; + segment *prev = NULL; + size_t i; + + if (t == NULL) return; + seg = t->rootseg; + while (seg) { + for (i=0; ikey[i]; + /* Found room in last segment after last_len */ + if (!seg->next && i >= t->last_len) { + seg->key[i] = key; + seg->val[i] = val; + t->last_len = i+1; + t->size++; + return; + } + if (mrb_hash_ht_hash_equal(mrb, k, key)) { + seg->val[i] = val; + return; + } + } + prev = seg; + seg = seg->next; + } + + /* Not found */ + t->size++; + + seg = (segment*)mrb_malloc(mrb, sizeof(segment)); + if (!seg) return; + seg->next = NULL; + seg->key[0] = key; + seg->val[0] = val; + t->last_len = 1; + if (prev) { + prev->next = seg; + } + else { + t->rootseg = seg; + } +} + +/* Get a value for a symbol from the instance variable table. */ +static mrb_bool +sg_get(mrb_state *mrb, seglist *t, mrb_value key, mrb_value *vp) +{ + segment *seg; + size_t i; + + if (t == NULL) return FALSE; + seg = t->rootseg; + while (seg) { + for (i=0; ikey[i]; + + if (!seg->next && i >= t->last_len) { + return FALSE; + } + if (mrb_hash_ht_hash_equal(mrb, k, key)) { + if (vp) *vp = seg->val[i]; + return TRUE; + } + } + seg = seg->next; + } + return FALSE; +} + +/* Deletes the value for the symbol from the instance variable table. */ +static mrb_bool +sg_del(mrb_state *mrb, seglist *t, mrb_value key, mrb_value *vp) +{ + segment *seg; + size_t i; + + if (t == NULL) return FALSE; + seg = t->rootseg; + while (seg) { + for (i=0; ikey[i]; + + if (!seg->next && i >= t->last_len) { + /* not found */ + return FALSE; + } + if (mrb_hash_ht_hash_equal(mrb, k, key)) { + segment *sg0; + size_t i0; + + t->size--; + if (vp) *vp = seg->val[i]; + sg0 = seg; + i0 = i; + while (seg) { + for (i++; inext && i >= t->last_len) { + t->last_len--; + if (t->last_len == 0 && sg0 != seg) { + sg0->next = NULL; + t->last_len = MRB_SG_SEGMENT_SIZE; + mrb_free(mrb, seg); + } + return TRUE; + } + sg0->key[i0] = seg->key[i]; + sg0->val[i0] = seg->val[i]; + i0 = i; + } + sg0 = seg; + seg = seg->next; + } + t->last_len--; + return TRUE; + } + } + seg = seg->next; + } + return FALSE; +} + +/* Iterates over the instance variable table. */ +static void +sg_foreach(mrb_state *mrb, seglist *t, sg_foreach_func *func, void *p) +{ + segment *seg; + size_t i; + + if (t == NULL) return; + seg = t->rootseg; + while (seg) { + for (i=0; inext && i >= t->last_len) { + return; + } + if ((*func)(mrb, seg->key[i], seg->val[i], p) != 0) + return; + } + seg = seg->next; + } +} + +/* Get the size of the instance variable table. */ +static size_t +sg_size(mrb_state *mrb, seglist *t) +{ + segment *seg; + size_t size = 0; + + if (t == NULL) return 0; + if (t->size > 0) return t->size; + seg = t->rootseg; + while (seg) { + if (seg->next == NULL) { + size += t->last_len; + return size; + } + seg = seg->next; + size += MRB_SG_SEGMENT_SIZE; + } + /* empty seglist */ + return 0; +} + +/* Copy the instance variable table. */ +static seglist* +sg_copy(mrb_state *mrb, seglist *t) +{ + segment *seg; + seglist *t2; + + size_t i; + + seg = t->rootseg; + t2 = sg_new(mrb); + + while (seg != NULL) { + for (i=0; ikey[i]; + mrb_value val = seg->val[i]; + + if ((seg->next == NULL) && (i >= t->last_len)) { + return t2; + } + sg_put(mrb, t2, key, val); + } + seg = seg->next; + } + return t2; +} + +/* Free memory of the instance variable table. */ +static void +sg_free(mrb_state *mrb, seglist *t) +{ + segment *seg; + + if (!t) return; + seg = t->rootseg; + while (seg) { + segment *p = seg; + seg = seg->next; + mrb_free(mrb, p); + } + mrb_free(mrb, t); +} static void mrb_hash_modify(mrb_state *mrb, mrb_value hash); @@ -105,57 +348,55 @@ mrb_hash_ht_key(mrb_state *mrb, mrb_value key) #define KEY(key) mrb_hash_ht_key(mrb, key) +static int +hash_mark_i(mrb_state *mrb, mrb_value key, mrb_value val, void *p) +{ + mrb_gc_mark_value(mrb, key); + mrb_gc_mark_value(mrb, val); + return 0; +} + void mrb_gc_mark_hash(mrb_state *mrb, struct RHash *hash) { - khiter_t k; - khash_t(ht) *h = hash->ht; - - if (!h) return; - for (k = kh_begin(h); k != kh_end(h); k++) { - if (kh_exist(h, k)) { - mrb_value key = kh_key(h, k); - mrb_value val = kh_value(h, k).v; - - mrb_gc_mark_value(mrb, key); - mrb_gc_mark_value(mrb, val); - } - } + sg_foreach(mrb, hash->ht, hash_mark_i, NULL); } size_t mrb_gc_mark_hash_size(mrb_state *mrb, struct RHash *hash) { if (!hash->ht) return 0; - return kh_size(hash->ht)*2; + return sg_size(mrb, hash->ht)*2; } void mrb_gc_free_hash(mrb_state *mrb, struct RHash *hash) { - if (hash->ht) kh_destroy(ht, mrb, hash->ht); + sg_free(mrb, hash->ht); } - MRB_API mrb_value -mrb_hash_new_capa(mrb_state *mrb, mrb_int capa) +mrb_hash_new(mrb_state *mrb) { struct RHash *h; h = (struct RHash*)mrb_obj_alloc(mrb, MRB_TT_HASH, mrb->hash_class); - /* khash needs 1/4 empty space so it is not resized immediately */ - if (capa == 0) - h->ht = 0; - else - h->ht = kh_init_size(ht, mrb, (khint_t)(capa*4/3)); + h->ht = 0; h->iv = 0; return mrb_obj_value(h); } MRB_API mrb_value -mrb_hash_new(mrb_state *mrb) +mrb_hash_new_capa(mrb_state *mrb, mrb_int capa) { - return mrb_hash_new_capa(mrb, 0); + struct RHash *h; + + h = (struct RHash*)mrb_obj_alloc(mrb, MRB_TT_HASH, mrb->hash_class); + /* preallocate segment list */ + h->ht = sg_new(mrb); + /* capacity ignored */ + h->iv = 0; + return mrb_obj_value(h); } static mrb_value mrb_hash_default(mrb_state *mrb, mrb_value hash); @@ -166,7 +407,7 @@ mrb_hash_init_copy(mrb_state *mrb, mrb_value self) { mrb_value orig; struct RHash* copy; - khash_t(ht) *orig_h; + seglist *orig_h; mrb_value ifnone, vret; mrb_get_args(mrb, "o", &orig); @@ -177,22 +418,7 @@ mrb_hash_init_copy(mrb_state *mrb, mrb_value self) orig_h = RHASH_TBL(self); copy = (struct RHash*)mrb_obj_alloc(mrb, MRB_TT_HASH, mrb->hash_class); - copy->ht = kh_init(ht, mrb); - - if (orig_h && kh_size(orig_h) > 0) { - khash_t(ht) *copy_h = copy->ht; - khiter_t k, copy_k; - - for (k = kh_begin(orig_h); k != kh_end(orig_h); k++) { - if (kh_exist(orig_h, k)) { - int ai = mrb_gc_arena_save(mrb); - copy_k = kh_put(ht, mrb, copy_h, KEY(kh_key(orig_h, k))); - mrb_gc_arena_restore(mrb, ai); - kh_val(copy_h, copy_k).v = kh_val(orig_h, k).v; - kh_val(copy_h, copy_k).n = kh_size(copy_h)-1; - } - } - } + copy->ht = sg_copy(mrb, orig_h); if (MRB_RHASH_DEFAULT_P(self)) { copy->flags |= MRB_HASH_DEFAULT; @@ -208,65 +434,54 @@ mrb_hash_init_copy(mrb_state *mrb, mrb_value self) return vret; } +static int +check_kdict_i(mrb_state *mrb, mrb_value key, mrb_value val, void *data) +{ + if (!mrb_symbol_p(key)) { + mrb_raise(mrb, E_ARGUMENT_ERROR, "keyword argument hash with non symbol keys"); + } + return 0; +} + void mrb_hash_check_kdict(mrb_state *mrb, mrb_value self) { - khash_t(ht) *orig_h; - khiter_t k; - int nosym = FALSE; + seglist *sg; - orig_h = RHASH_TBL(self); - if (!orig_h || kh_size(orig_h) == 0) return; - for (k = kh_begin(orig_h); k != kh_end(orig_h); k++) { - if (kh_exist(orig_h, k)) { - mrb_value key = kh_key(orig_h, k); - - if (!mrb_symbol_p(key)) nosym = TRUE; - } - } - if (nosym) { - mrb_raise(mrb, E_ARGUMENT_ERROR, "keyword argument hash with non symbol keys"); - } + sg = RHASH_TBL(self); + if (!sg || sg_size(mrb, sg) == 0) return; + sg_foreach(mrb, sg, check_kdict_i, NULL); } MRB_API mrb_value mrb_hash_dup(mrb_state *mrb, mrb_value self) { struct RHash* copy; - khash_t(ht) *orig_h; + seglist *orig_h; orig_h = RHASH_TBL(self); copy = (struct RHash*)mrb_obj_alloc(mrb, MRB_TT_HASH, mrb->hash_class); - copy->ht = kh_init(ht, mrb); - - if (orig_h && kh_size(orig_h) > 0) { - int ai = mrb_gc_arena_save(mrb); - khash_t(ht) *copy_h = copy->ht; - khiter_t k, copy_k; - - for (k = kh_begin(orig_h); k != kh_end(orig_h); k++) { - if (kh_exist(orig_h, k)) { - copy_k = kh_put(ht, mrb, copy_h, KEY(kh_key(orig_h, k))); - mrb_gc_arena_restore(mrb, ai); - kh_val(copy_h, copy_k).v = kh_val(orig_h, k).v; - kh_val(copy_h, copy_k).n = kh_size(copy_h)-1; - } - } - } + copy->ht = orig_h ? sg_copy(mrb, orig_h) : NULL; return mrb_obj_value(copy); } +MRB_API mrb_bool +mrb_hash_has_key_p(mrb_state *mrb, mrb_value hash, mrb_value key) +{ + if (sg_get(mrb, RHASH_TBL(hash), key, NULL)) { + return TRUE; + } + return FALSE; +} + MRB_API mrb_value mrb_hash_get(mrb_state *mrb, mrb_value hash, mrb_value key) { - khash_t(ht) *h = RHASH_TBL(hash); - khiter_t k; + mrb_value val; mrb_sym mid; - if (h) { - k = kh_get(ht, mrb, h, key); - if (k != kh_end(h)) - return kh_value(h, k).v; + if (sg_get(mrb, RHASH_TBL(hash), key, &val)) { + return val; } mid = mrb_intern_lit(mrb, "default"); @@ -280,15 +495,11 @@ mrb_hash_get(mrb_state *mrb, mrb_value hash, mrb_value key) MRB_API mrb_value mrb_hash_fetch(mrb_state *mrb, mrb_value hash, mrb_value key, mrb_value def) { - khash_t(ht) *h = RHASH_TBL(hash); - khiter_t k; + mrb_value val; - if (h) { - k = kh_get(ht, mrb, h, key); - if (k != kh_end(h)) - return kh_value(h, k).v; + if (sg_get(mrb, RHASH_TBL(hash), key, &val)) { + return val; } - /* not found */ return def; } @@ -296,25 +507,9 @@ mrb_hash_fetch(mrb_state *mrb, mrb_value hash, mrb_value key, mrb_value def) MRB_API void mrb_hash_set(mrb_state *mrb, mrb_value hash, mrb_value key, mrb_value val) { - khash_t(ht) *h; - khiter_t k; - int r; - mrb_hash_modify(mrb, hash); - h = RHASH_TBL(hash); - - if (!h) h = RHASH_TBL(hash) = kh_init(ht, mrb); - k = kh_put2(ht, mrb, h, key, &r); - kh_value(h, k).v = val; - - if (r != 0) { - /* expand */ - int ai = mrb_gc_arena_save(mrb); - key = kh_key(h, k) = KEY(key); - mrb_gc_arena_restore(mrb, ai); - kh_value(h, k).n = kh_size(h)-1; - } + sg_put(mrb, RHASH_TBL(hash), key, val); mrb_field_write_barrier_value(mrb, (struct RBasic*)RHASH(hash), key); mrb_field_write_barrier_value(mrb, (struct RBasic*)RHASH(hash), val); return; @@ -332,24 +527,16 @@ mrb_check_hash_type(mrb_state *mrb, mrb_value hash) return mrb_check_convert_type(mrb, hash, MRB_TT_HASH, "Hash", "to_hash"); } -MRB_API khash_t(ht)* -mrb_hash_tbl(mrb_state *mrb, mrb_value hash) -{ - khash_t(ht) *h = RHASH_TBL(hash); - - if (!h) { - return RHASH_TBL(hash) = kh_init(ht, mrb); - } - return h; -} - static void mrb_hash_modify(mrb_state *mrb, mrb_value hash) { if (MRB_FROZEN_P(mrb_hash_ptr(hash))) { mrb_raise(mrb, E_FROZEN_ERROR, "can't modify frozen hash"); } - mrb_hash_tbl(mrb, hash); + + if (!RHASH_TBL(hash)) { + RHASH_TBL(hash) = sg_new(mrb); + } } /* 15.2.13.4.16 */ @@ -589,23 +776,11 @@ mrb_hash_set_default_proc(mrb_state *mrb, mrb_value hash) MRB_API mrb_value mrb_hash_delete_key(mrb_state *mrb, mrb_value hash, mrb_value key) { - khash_t(ht) *h = RHASH_TBL(hash); - khiter_t k; - mrb_value delVal; - mrb_int n; - - if (h) { - k = kh_get(ht, mrb, h, key); - if (k != kh_end(h)) { - delVal = kh_value(h, k).v; - n = kh_value(h, k).n; - kh_del(ht, mrb, h, k); - for (k = kh_begin(h); k != kh_end(h); k++) { - if (!kh_exist(h, k)) continue; - if (kh_value(h, k).n > n) kh_value(h, k).n--; - } - return delVal; - } + seglist *sg = RHASH_TBL(hash); + mrb_value del_val; + + if (sg_del(mrb, sg, key, &del_val)) { + return del_val; } /* not found */ @@ -657,22 +832,14 @@ mrb_hash_delete(mrb_state *mrb, mrb_value self) static mrb_value mrb_hash_shift(mrb_state *mrb, mrb_value hash) { - khash_t(ht) *h = RHASH_TBL(hash); - khiter_t k; - mrb_value delKey, delVal; + seglist *sg = RHASH_TBL(hash); mrb_hash_modify(mrb, hash); - if (h && kh_size(h) > 0) { - for (k = kh_begin(h); k != kh_end(h); k++) { - if (!kh_exist(h, k)) continue; - - delKey = kh_key(h, k); - mrb_gc_protect(mrb, delKey); - delVal = mrb_hash_delete_key(mrb, hash, delKey); - mrb_gc_protect(mrb, delVal); - - return mrb_assoc_new(mrb, delKey, delVal); - } + if (sg && sg_size(mrb, sg) > 0) { + mrb_value del_key = sg->rootseg->key[0]; + mrb_value del_val = sg->rootseg->val[0]; + sg_del(mrb, sg, del_key, NULL); + return mrb_assoc_new(mrb, del_key, del_val); } if (MRB_RHASH_DEFAULT_P(hash)) { @@ -701,10 +868,13 @@ mrb_hash_shift(mrb_state *mrb, mrb_value hash) MRB_API mrb_value mrb_hash_clear(mrb_state *mrb, mrb_value hash) { - khash_t(ht) *h = RHASH_TBL(hash); + seglist *sg = RHASH_TBL(hash); mrb_hash_modify(mrb, hash); - if (h) kh_clear(ht, mrb, h); + if (sg) { + sg_free(mrb, sg); + RHASH_TBL(hash) = NULL; + } return hash; } @@ -754,10 +924,19 @@ mrb_hash_aset(mrb_state *mrb, mrb_value self) static mrb_value mrb_hash_size_m(mrb_state *mrb, mrb_value self) { - khash_t(ht) *h = RHASH_TBL(self); + seglist *sg = RHASH_TBL(self); - if (!h) return mrb_fixnum_value(0); - return mrb_fixnum_value(kh_size(h)); + if (!sg) return mrb_fixnum_value(0); + return mrb_fixnum_value(sg_size(mrb, sg)); +} + +MRB_API mrb_bool +mrb_hash_empty_p(mrb_state *mrb, mrb_value self) +{ + seglist *sg = RHASH_TBL(self); + + if (!sg) return TRUE; + return sg_size(mrb, sg) == 0; } /* 15.2.13.4.12 */ @@ -770,21 +949,10 @@ mrb_hash_size_m(mrb_state *mrb, mrb_value self) * {}.empty? #=> true * */ -MRB_API mrb_bool -mrb_hash_empty_p(mrb_state *mrb, mrb_value self) -{ - khash_t(ht) *h = RHASH_TBL(self); - - if (h) return kh_size(h) == 0; - return TRUE; -} - static mrb_value mrb_hash_empty_m(mrb_state *mrb, mrb_value self) { - if (mrb_hash_empty_p(mrb, self)) - return mrb_true_value(); - return mrb_false_value(); + return mrb_bool_value(mrb_hash_empty_p(mrb, self)); } /* 15.2.13.4.29 (x)*/ @@ -801,6 +969,13 @@ mrb_hash_to_hash(mrb_state *mrb, mrb_value hash) return hash; } +static int +hash_keys_i(mrb_state *mrb, mrb_value key, mrb_value val, void *p) +{ + mrb_ary_push(mrb, *(mrb_value*)p, key); + return 0; +} + /* 15.2.13.4.19 */ /* * call-seq: @@ -817,33 +992,24 @@ mrb_hash_to_hash(mrb_state *mrb, mrb_value hash) MRB_API mrb_value mrb_hash_keys(mrb_state *mrb, mrb_value hash) { - khash_t(ht) *h = RHASH_TBL(hash); - khiter_t k; - mrb_int end; + seglist *sg = RHASH_TBL(hash); + size_t size; mrb_value ary; - mrb_value *p; - - if (!h || kh_size(h) == 0) return mrb_ary_new(mrb); - ary = mrb_ary_new_capa(mrb, kh_size(h)); - end = kh_size(h)-1; - mrb_ary_set(mrb, ary, end, mrb_nil_value()); - p = RARRAY_PTR(ary); - for (k = kh_begin(h); k != kh_end(h); k++) { - if (kh_exist(h, k)) { - mrb_value kv = kh_key(h, k); - mrb_hash_value hv = kh_value(h, k); - - if (hv.n <= end) { - p[hv.n] = kv; - } - else { - p[end] = kv; - } - } - } + + if (!sg || (size = sg_size(mrb, sg)) == 0) + return mrb_ary_new(mrb); + ary = mrb_ary_new_capa(mrb, size); + sg_foreach(mrb, sg, hash_keys_i, (void*)&ary); return ary; } +static int +hash_vals_i(mrb_state *mrb, mrb_value key, mrb_value val, void *p) +{ + mrb_ary_push(mrb, *(mrb_value*)p, val); + return 0; +} + /* 15.2.13.4.28 */ /* * call-seq: @@ -860,19 +1026,14 @@ mrb_hash_keys(mrb_state *mrb, mrb_value hash) MRB_API mrb_value mrb_hash_values(mrb_state *mrb, mrb_value hash) { - khash_t(ht) *h = RHASH_TBL(hash); - khiter_t k; + seglist *sg = RHASH_TBL(hash); + size_t size; mrb_value ary; - if (!h) return mrb_ary_new(mrb); - ary = mrb_ary_new_capa(mrb, kh_size(h)); - for (k = kh_begin(h); k != kh_end(h); k++) { - if (kh_exist(h, k)) { - mrb_hash_value hv = kh_value(h, k); - - mrb_ary_set(mrb, ary, hv.n, hv.v); - } - } + if (!sg || (size = sg_size(mrb, sg)) == 0) + return mrb_ary_new(mrb); + ary = mrb_ary_new_capa(mrb, size); + sg_foreach(mrb, sg, hash_vals_i, (void*)&ary); return ary; } @@ -898,13 +1059,11 @@ mrb_hash_values(mrb_state *mrb, mrb_value hash) MRB_API mrb_bool mrb_hash_key_p(mrb_state *mrb, mrb_value hash, mrb_value key) { - khash_t(ht) *h; - khiter_t k; + seglist *sg; - h = RHASH_TBL(hash); - if (h) { - k = kh_get(ht, mrb, h, key); - return k != kh_end(h); + sg = RHASH_TBL(hash); + if (sg_get(mrb, sg, key, NULL)) { + return TRUE; } return FALSE; } @@ -920,6 +1079,23 @@ mrb_hash_has_key(mrb_state *mrb, mrb_value hash) return mrb_bool_value(key_p); } +struct has_v_arg { + mrb_bool found; + mrb_value val; +}; + +static int +hash_has_value_i(mrb_state *mrb, mrb_value key, mrb_value val, void *p) +{ + struct has_v_arg *arg = (struct has_v_arg*)p; + + if (mrb_equal(mrb, arg->val, val)) { + arg->found = TRUE; + return 1; + } + return 0; +} + /* 15.2.13.4.14 */ /* 15.2.13.4.27 */ /* @@ -939,30 +1115,28 @@ static mrb_value mrb_hash_has_value(mrb_state *mrb, mrb_value hash) { mrb_value val; - khash_t(ht) *h; - khiter_t k; - + struct has_v_arg arg; + mrb_get_args(mrb, "o", &val); - h = RHASH_TBL(hash); + arg.found = FALSE; + arg.val = val; + sg_foreach(mrb, RHASH_TBL(hash), hash_has_value_i, &arg); + return mrb_bool_value(arg.found); +} - if (h) { - for (k = kh_begin(h); k != kh_end(h); k++) { - if (!kh_exist(h, k)) continue; +static int +merge_i(mrb_state *mrb, mrb_value key, mrb_value val, void *data) +{ + seglist *h1 = (seglist*)data; - if (mrb_equal(mrb, kh_value(h, k).v, val)) { - return mrb_true_value(); - } - } - } - return mrb_false_value(); + sg_put(mrb, h1, key, val); + return 0; } MRB_API void mrb_hash_merge(mrb_state *mrb, mrb_value hash1, mrb_value hash2) { - khash_t(ht) *h1; - khash_t(ht) *h2; - khiter_t k; + seglist *h1, *h2; mrb_hash_modify(mrb, hash1); hash2 = mrb_ensure_hash_type(mrb, hash2); @@ -971,22 +1145,10 @@ mrb_hash_merge(mrb_state *mrb, mrb_value hash1, mrb_value hash2) if (!h2) return; if (!h1) { - RHASH_TBL(hash1) = kh_copy(ht, mrb, h2); + RHASH_TBL(hash1) = sg_copy(mrb, h2); return; } - for (k = kh_begin(h2); k != kh_end(h2); k++) { - khiter_t k1; - int r; - - if (!kh_exist(h2, k)) continue; - k1 = kh_put2(ht, mrb, h1, kh_key(h2, k), &r); - kh_value(h1, k1).v = kh_value(h2,k).v; - if (r != 0) { - /* expand */ - kh_key(h1, k1) = kh_key(h2, k); - kh_value(h1, k1).n = kh_size(h1)-1; - } - } + sg_foreach(mrb, h2, merge_i, h1); mrb_write_barrier(mrb, (struct RBasic*)RHASH(hash1)); return; } -- cgit v1.2.3 From 8ffd4e47fb1c18088e554d31e8af88881517a201 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Sat, 22 Sep 2018 23:05:52 +0900 Subject: Use `mrb_undef_value` for delete mark instead of shifting Hash entry table. That means entry table should be compacted periodically by `sg_compact()`. --- mrbgems/mruby-hash-ext/mrblib/hash.rb | 4 +- mrblib/hash.rb | 12 +-- src/hash.c | 176 ++++++++++++++++++---------------- 3 files changed, 97 insertions(+), 95 deletions(-) diff --git a/mrbgems/mruby-hash-ext/mrblib/hash.rb b/mrbgems/mruby-hash-ext/mrblib/hash.rb index 61e4c890c..5bbbdf559 100644 --- a/mrbgems/mruby-hash-ext/mrblib/hash.rb +++ b/mrbgems/mruby-hash-ext/mrblib/hash.rb @@ -461,9 +461,9 @@ class Hash return to_enum :transform_keys! unless block self.keys.each do |k| value = self[k] - new_key = block.call(k) self.__delete(k) - self[new_key] = value + k = block.call(k) if block + self[k] = value end self end diff --git a/mrblib/hash.rb b/mrblib/hash.rb index 96029a230..eba92ba4a 100644 --- a/mrblib/hash.rb +++ b/mrblib/hash.rb @@ -55,10 +55,9 @@ class Hash # ISO 15.2.13.4.8 def delete(key, &block) if block && !self.has_key?(key) - block.call(key) - else - self.__delete(key) + return block.call(key) end + self.__delete(key) end ## @@ -335,11 +334,8 @@ class Hash # h["AA"] #=> "b" # def rehash - h = {} - self.each{|k,v| - h[k] = v - } - self.replace(h) + self.size + self end end diff --git a/src/hash.c b/src/hash.c index 16d49af24..820ee5a71 100644 --- a/src/hash.c +++ b/src/hash.c @@ -96,16 +96,18 @@ typedef int (sg_foreach_func)(mrb_state *mrb,mrb_value key,mrb_value val, void * #endif typedef struct segment { - mrb_value key[MRB_SG_SEGMENT_SIZE]; - mrb_value val[MRB_SG_SEGMENT_SIZE]; struct segment *next; + struct { + mrb_value key; + mrb_value val; + } e[MRB_SG_SEGMENT_SIZE]; } segment; /* Instance variable table structure */ typedef struct seglist { segment *rootseg; - size_t size; - size_t last_len; + mrb_int size; + mrb_int last_len; } seglist; /* Creates the instance variable table. */ @@ -128,23 +130,24 @@ sg_put(mrb_state *mrb, seglist *t, mrb_value key, mrb_value val) { segment *seg; segment *prev = NULL; - size_t i; + mrb_int i; if (t == NULL) return; seg = t->rootseg; while (seg) { for (i=0; ikey[i]; + mrb_value k = seg->e[i].key; /* Found room in last segment after last_len */ if (!seg->next && i >= t->last_len) { - seg->key[i] = key; - seg->val[i] = val; + seg->e[i].key = key; + seg->e[i].val = val; t->last_len = i+1; - t->size++; + if (t->size >= 0) t->size++; return; } + if (mrb_undef_p(k)) continue; if (mrb_hash_ht_hash_equal(mrb, k, key)) { - seg->val[i] = val; + seg->e[i].val = val; return; } } @@ -153,13 +156,13 @@ sg_put(mrb_state *mrb, seglist *t, mrb_value key, mrb_value val) } /* Not found */ - t->size++; + if (t->size >= 0) t->size++; seg = (segment*)mrb_malloc(mrb, sizeof(segment)); if (!seg) return; seg->next = NULL; - seg->key[0] = key; - seg->val[0] = val; + seg->e[0].key = key; + seg->e[0].val = val; t->last_len = 1; if (prev) { prev->next = seg; @@ -174,19 +177,20 @@ static mrb_bool sg_get(mrb_state *mrb, seglist *t, mrb_value key, mrb_value *vp) { segment *seg; - size_t i; + mrb_int i; if (t == NULL) return FALSE; seg = t->rootseg; while (seg) { for (i=0; ikey[i]; + mrb_value k = seg->e[i].key; if (!seg->next && i >= t->last_len) { return FALSE; } + if (mrb_undef_p(k)) continue; if (mrb_hash_ht_hash_equal(mrb, k, key)) { - if (vp) *vp = seg->val[i]; + if (vp) *vp = seg->e[i].val; return TRUE; } } @@ -195,50 +199,81 @@ sg_get(mrb_state *mrb, seglist *t, mrb_value key, mrb_value *vp) return FALSE; } +/* Compacts the hash removing delete entries. */ +static void +sg_compact(mrb_state *mrb, seglist *t) +{ + segment *seg = t->rootseg; + mrb_int i; + segment *seg2 = NULL; + mrb_int i2; + mrb_int size = 0; + + while (seg) { + for (i=0; ie[i].key; + + if (!seg->next && i >= t->last_len) { + goto exit; + } + if (mrb_undef_p(k)) { /* found delete key */ + if (seg2 == NULL) { + seg2 = seg; + i2 = i; + } + } + else { + size++; + if (seg2 != NULL) { + seg2->e[i2++] = seg->e[i]; + if (i2 >= MRB_SG_SEGMENT_SIZE) { + seg2 = seg2->next; + i2 = 0; + } + } + } + } + seg = seg->next; + } + exit: + /* reached at end */ + t->size = size; + t->last_len = i2; + if (seg != seg2) { + seg = seg2->next; + seg2->next = NULL; + while (seg) { + seg2 = seg->next; + mrb_free(mrb, seg); + seg = seg2; + } + } +} + /* Deletes the value for the symbol from the instance variable table. */ +/* Deletion is done by overwriting keys by `undef`. */ static mrb_bool sg_del(mrb_state *mrb, seglist *t, mrb_value key, mrb_value *vp) { segment *seg; - size_t i; + mrb_int i; if (t == NULL) return FALSE; seg = t->rootseg; while (seg) { for (i=0; ikey[i]; + mrb_value k = seg->e[i].key; if (!seg->next && i >= t->last_len) { /* not found */ return FALSE; } + if (mrb_undef_p(k)) continue; if (mrb_hash_ht_hash_equal(mrb, k, key)) { - segment *sg0; - size_t i0; - - t->size--; - if (vp) *vp = seg->val[i]; - sg0 = seg; - i0 = i; - while (seg) { - for (i++; inext && i >= t->last_len) { - t->last_len--; - if (t->last_len == 0 && sg0 != seg) { - sg0->next = NULL; - t->last_len = MRB_SG_SEGMENT_SIZE; - mrb_free(mrb, seg); - } - return TRUE; - } - sg0->key[i0] = seg->key[i]; - sg0->val[i0] = seg->val[i]; - i0 = i; - } - sg0 = seg; - seg = seg->next; - } - t->last_len--; + if (vp) *vp = k; + seg->e[i].key = mrb_undef_value(); + if (t->size > 0) t->size = -1; + else t->size--; /* count number of deleted */ return TRUE; } } @@ -252,7 +287,7 @@ static void sg_foreach(mrb_state *mrb, seglist *t, sg_foreach_func *func, void *p) { segment *seg; - size_t i; + mrb_int i; if (t == NULL) return; seg = t->rootseg; @@ -262,7 +297,8 @@ sg_foreach(mrb_state *mrb, seglist *t, sg_foreach_func *func, void *p) if (!seg->next && i >= t->last_len) { return; } - if ((*func)(mrb, seg->key[i], seg->val[i], p) != 0) + if (mrb_undef_p(seg->e[i].key)) continue; + if ((*func)(mrb, seg->e[i].key, seg->e[i].val, p) != 0) return; } seg = seg->next; @@ -270,25 +306,14 @@ sg_foreach(mrb_state *mrb, seglist *t, sg_foreach_func *func, void *p) } /* Get the size of the instance variable table. */ -static size_t +static mrb_int sg_size(mrb_state *mrb, seglist *t) { - segment *seg; - size_t size = 0; - if (t == NULL) return 0; - if (t->size > 0) return t->size; - seg = t->rootseg; - while (seg) { - if (seg->next == NULL) { - size += t->last_len; - return size; - } - seg = seg->next; - size += MRB_SG_SEGMENT_SIZE; + if (t->size < 0) { + sg_compact(mrb, t); } - /* empty seglist */ - return 0; + return t->size; } /* Copy the instance variable table. */ @@ -297,16 +322,15 @@ sg_copy(mrb_state *mrb, seglist *t) { segment *seg; seglist *t2; - - size_t i; + mrb_int i; seg = t->rootseg; t2 = sg_new(mrb); while (seg != NULL) { for (i=0; ikey[i]; - mrb_value val = seg->val[i]; + mrb_value key = seg->e[i].key; + mrb_value val = seg->e[i].val; if ((seg->next == NULL) && (i >= t->last_len)) { return t2; @@ -787,24 +811,6 @@ mrb_hash_delete_key(mrb_state *mrb, mrb_value hash, mrb_value key) return mrb_nil_value(); } -/* 15.2.13.4.8 */ -/* - * call-seq: - * hsh.delete(key) -> value - * hsh.delete(key) {| key | block } -> value - * - * Deletes and returns a key-value pair from hsh whose key is - * equal to key. If the key is not found, returns the - * default value. If the optional code block is given and the - * key is not found, pass in the key and return the result of - * block. - * - * h = { "a" => 100, "b" => 200 } - * h.delete("a") #=> 100 - * h.delete("z") #=> nil - * h.delete("z") { |el| "#{el} not found" } #=> "z not found" - * - */ static mrb_value mrb_hash_delete(mrb_state *mrb, mrb_value self) { @@ -836,8 +842,8 @@ mrb_hash_shift(mrb_state *mrb, mrb_value hash) mrb_hash_modify(mrb, hash); if (sg && sg_size(mrb, sg) > 0) { - mrb_value del_key = sg->rootseg->key[0]; - mrb_value del_val = sg->rootseg->val[0]; + mrb_value del_key = sg->rootseg->e[0].key; + mrb_value del_val = sg->rootseg->e[0].val; sg_del(mrb, sg, del_key, NULL); return mrb_assoc_new(mrb, del_key, del_val); } -- cgit v1.2.3 From d78acc7afed35813f25e3091150dab668c373f05 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Wed, 26 Sep 2018 11:14:36 +0900 Subject: Add index to larger segment lists for performance --- mrbgems/mruby-array-ext/mrblib/array.rb | 14 +- mrblib/hash.rb | 2 +- src/hash.c | 440 +++++++++++++++++++++++--------- 3 files changed, 329 insertions(+), 127 deletions(-) diff --git a/mrbgems/mruby-array-ext/mrblib/array.rb b/mrbgems/mruby-array-ext/mrblib/array.rb index 8c2acc7ac..eac8d4718 100644 --- a/mrbgems/mruby-array-ext/mrblib/array.rb +++ b/mrbgems/mruby-array-ext/mrblib/array.rb @@ -1,3 +1,4 @@ +# coding: cp932 class Array ## # call-seq: @@ -41,26 +42,19 @@ class Array # c.uniq! { |s| s.first } # => [["student", "sam"], ["teacher", "matz"]] # def uniq!(&block) + hash = {} if block - hash = {} self.each do |val| key = block.call(val) hash[key] = val unless hash.key?(key) end result = hash.values - elsif self.size > 20 + else hash = {} self.each do |val| hash[val] = val end - result = hash.values - else - ary = self.dup - result = [] - while ary.size > 0 - result << ary.shift - ary.delete(result.last) - end + result = hash.keys end if result.size == self.size nil diff --git a/mrblib/hash.rb b/mrblib/hash.rb index eba92ba4a..245b76ee0 100644 --- a/mrblib/hash.rb +++ b/mrblib/hash.rb @@ -334,7 +334,7 @@ class Hash # h["AA"] #=> "b" # def rehash - self.size + # do nothing (for now) self end end diff --git a/src/hash.c b/src/hash.c index 820ee5a71..07a12be68 100644 --- a/src/hash.c +++ b/src/hash.c @@ -16,14 +16,48 @@ mrb_int mrb_float_id(mrb_float f); #endif -static inline khint_t -mrb_hash_ht_hash_func(mrb_state *mrb, mrb_value key) +/* return non zero to break the loop */ +typedef int (sg_foreach_func)(mrb_state *mrb,mrb_value key, mrb_value val, void *data); + +#ifndef MRB_SG_SEGMENT_SIZE +#define MRB_SG_SEGMENT_SIZE 5 +#endif + +struct segkv { + mrb_value key; + mrb_value val; +}; + +typedef struct segment { + struct segment *next; + struct segkv e[MRB_SG_SEGMENT_SIZE]; +} segment; + +typedef struct segindex { + size_t size; + size_t capa; + struct segkv *table[]; +} segindex; + +/* Instance variable table structure */ +typedef struct seglist { + segment *rootseg; + segment *lastseg; + mrb_int size; + mrb_int last_len; + segindex *index; +} seglist; + +static /* inline */ size_t +sg_hash_func(mrb_state *mrb, seglist *t, mrb_value key) { - enum mrb_vtype t = mrb_type(key); + enum mrb_vtype tt = mrb_type(key); mrb_value hv; - khint_t h; + size_t h; + segindex *index = t->index; + size_t capa = index ? index->capa : 0; - switch (t) { + switch (tt) { case MRB_TT_STRING: h = mrb_str_hash(mrb, key); break; @@ -35,23 +69,26 @@ mrb_hash_ht_hash_func(mrb_state *mrb, mrb_value key) #ifndef MRB_WITHOUT_FLOAT case MRB_TT_FLOAT: #endif - h = (khint_t)mrb_obj_id(key); + h = (size_t)mrb_obj_id(key); break; default: hv = mrb_funcall(mrb, key, "hash", 0); - h = (khint_t)t ^ (khint_t)mrb_fixnum(hv); + h = (size_t)t ^ (size_t)mrb_fixnum(hv); break; } - return kh_int_hash_func(mrb, h); + if (index && (index != t->index || capa != index->capa)) { + mrb_raise(mrb, E_RUNTIME_ERROR, "hash modified"); + } + return ((h)^((h)<<2)^((h)>>2)); } static inline mrb_bool -mrb_hash_ht_hash_equal(mrb_state *mrb, mrb_value a, mrb_value b) +sg_hash_equal(mrb_state *mrb, seglist *t, mrb_value a, mrb_value b) { - enum mrb_vtype t = mrb_type(a); + enum mrb_vtype tt = mrb_type(a); - switch (t) { + switch (tt) { case MRB_TT_STRING: return mrb_str_equal(mrb, a, b); @@ -84,32 +121,18 @@ mrb_hash_ht_hash_equal(mrb_state *mrb, mrb_value a, mrb_value b) #endif default: - return mrb_eql(mrb, a, b); - } + { + segindex *index = t->index; + size_t capa = index ? index->capa : 0; + mrb_bool eql = mrb_eql(mrb, a, b); + if (index && (index != t->index || capa != index->capa)) { + mrb_raise(mrb, E_RUNTIME_ERROR, "hash modified"); + } + return eql; + } + } } -/* return non zero to break the loop */ -typedef int (sg_foreach_func)(mrb_state *mrb,mrb_value key,mrb_value val, void *data); - -#ifndef MRB_SG_SEGMENT_SIZE -#define MRB_SG_SEGMENT_SIZE 5 -#endif - -typedef struct segment { - struct segment *next; - struct { - mrb_value key; - mrb_value val; - } e[MRB_SG_SEGMENT_SIZE]; -} segment; - -/* Instance variable table structure */ -typedef struct seglist { - segment *rootseg; - mrb_int size; - mrb_int last_len; -} seglist; - /* Creates the instance variable table. */ static seglist* sg_new(mrb_state *mrb) @@ -119,87 +142,87 @@ sg_new(mrb_state *mrb) t = (seglist*)mrb_malloc(mrb, sizeof(seglist)); t->size = 0; t->rootseg = NULL; + t->lastseg = NULL; t->last_len = 0; + t->index = NULL; return t; } -/* Set the value for the symbol in the instance variable table. */ +#define power2(v) do { \ + v--;\ + v |= v >> 1;\ + v |= v >> 2;\ + v |= v >> 4;\ + v |= v >> 8;\ + v |= v >> 16;\ + v++;\ +} while (0) + +#ifndef UPPER_BOUND +#define UPPER_BOUND(x) ((x)>>2|(x)>>1) +#endif + +#define SG_MASK(index) ((index->capa)-1) + +/* Build index for the segment list */ static void -sg_put(mrb_state *mrb, seglist *t, mrb_value key, mrb_value val) +sg_index(mrb_state *mrb, seglist *t) { + size_t size = (size_t)t->size; + size_t mask; + segindex *index = t->index; segment *seg; - segment *prev = NULL; - mrb_int i; + size_t i; - if (t == NULL) return; - seg = t->rootseg; - while (seg) { - for (i=0; ie[i].key; - /* Found room in last segment after last_len */ - if (!seg->next && i >= t->last_len) { - seg->e[i].key = key; - seg->e[i].val = val; - t->last_len = i+1; - if (t->size >= 0) t->size++; - return; - } - if (mrb_undef_p(k)) continue; - if (mrb_hash_ht_hash_equal(mrb, k, key)) { - seg->e[i].val = val; - return; - } + if (size < MRB_SG_SEGMENT_SIZE) { + if (index) { + failed: + mrb_free(mrb, index); + t->index = NULL; } - prev = seg; - seg = seg->next; + return; } - - /* Not found */ - if (t->size >= 0) t->size++; - - seg = (segment*)mrb_malloc(mrb, sizeof(segment)); - if (!seg) return; - seg->next = NULL; - seg->e[0].key = key; - seg->e[0].val = val; - t->last_len = 1; - if (prev) { - prev->next = seg; + /* allocate index table */ + if (index && index->size >= UPPER_BOUND(index->capa)) { + size = index->capa+1; } - else { - t->rootseg = seg; + power2(size); + if (!index || index->capa < size) { + index = (segindex*)mrb_realloc_simple(mrb, index, sizeof(segindex)+sizeof(struct segkv*)*size); + if (index == NULL) goto failed; + t->index = index; + } + index->size = t->size; + index->capa = size; + for (i=0; itable[i] = NULL; } -} - -/* Get a value for a symbol from the instance variable table. */ -static mrb_bool -sg_get(mrb_state *mrb, seglist *t, mrb_value key, mrb_value *vp) -{ - segment *seg; - mrb_int i; - if (t == NULL) return FALSE; + /* rebuld index */ + mask = SG_MASK(index); seg = t->rootseg; while (seg) { for (i=0; ie[i].key; + mrb_value key; + size_t k, step = 0; - if (!seg->next && i >= t->last_len) { - return FALSE; + if (!seg->next && i >= (size_t)t->last_len) { + return; } - if (mrb_undef_p(k)) continue; - if (mrb_hash_ht_hash_equal(mrb, k, key)) { - if (vp) *vp = seg->e[i].val; - return TRUE; + key = seg->e[i].key; + if (mrb_undef_p(key)) continue; + k = sg_hash_func(mrb, t, key) & mask; + while (index->table[k]) { + k = (k+(++step)) & mask; } + index->table[k] = &seg->e[i]; } seg = seg->next; } - return FALSE; } -/* Compacts the hash removing delete entries. */ +/* Compacts the segment list removing deleted entries. */ static void sg_compact(mrb_state *mrb, seglist *t) { @@ -209,6 +232,10 @@ sg_compact(mrb_state *mrb, seglist *t) mrb_int i2; mrb_int size = 0; + if (t->index && (size_t)t->size == t->index->size) { + sg_index(mrb, t); + return; + } while (seg) { for (i=0; ie[i].key; @@ -238,16 +265,179 @@ sg_compact(mrb_state *mrb, seglist *t) exit: /* reached at end */ t->size = size; - t->last_len = i2; - if (seg != seg2) { + if (seg2) { seg = seg2->next; seg2->next = NULL; + t->last_len = i2; + t->lastseg = seg2; while (seg) { seg2 = seg->next; mrb_free(mrb, seg); seg = seg2; } } + if (t->index) { + sg_index(mrb, t); + } +} + +/* Set the value for the key in the indexed segment list. */ +static void +sg_index_put(mrb_state *mrb, seglist *t, mrb_value key, mrb_value val) +{ + segindex *index = t->index; + size_t k, sp, step = 0, mask; + segment *seg; + + if (index->size >= UPPER_BOUND(index->capa)) { + /* need to expand table */ + sg_compact(mrb, t); + index = t->index; + } + mask = SG_MASK(index); + sp = index->capa; + k = sg_hash_func(mrb, t, key) & mask; + while (index->table[k]) { + mrb_value key2 = index->table[k]->key; + if (mrb_undef_p(key2)) { + if (sp == index->capa) sp = k; + } + else if (sg_hash_equal(mrb, t, key, key2)) { + index->table[k]->val = val; + return; + } + k = (k+(++step)) & mask; + } + if (sp < index->capa) { + k = sp; + } + + /* put the value at the last */ + seg = t->lastseg; + if (t->last_len < MRB_SG_SEGMENT_SIZE) { + index->table[k] = &seg->e[t->last_len++]; + } + else { /* append a new segment */ + seg->next = (segment*)mrb_malloc(mrb, sizeof(segment)); + seg = seg->next; + seg->next = NULL; + t->lastseg = seg; + t->last_len = 1; + index->table[k] = &seg->e[0]; + } + index->table[k]->key = key; + index->table[k]->val = val; + index->size++; + t->size++; +} + +/* Set the value for the key in the segment list. */ +static void +sg_put(mrb_state *mrb, seglist *t, mrb_value key, mrb_value val) +{ + segment *seg; + mrb_int i, deleted = 0; + + if (t == NULL) return; + if (t->index) { + sg_index_put(mrb, t, key, val); + return; + } + seg = t->rootseg; + while (seg) { + for (i=0; ie[i].key; + /* Found room in last segment after last_len */ + if (!seg->next && i >= t->last_len) { + seg->e[i].key = key; + seg->e[i].val = val; + t->last_len = i+1; + t->size++; + return; + } + if (mrb_undef_p(k)) { + deleted++; + continue; + } + if (sg_hash_equal(mrb, t, k, key)) { + seg->e[i].val = val; + return; + } + } + seg = seg->next; + } + + /* Not found */ + if (deleted > MRB_SG_SEGMENT_SIZE) { + sg_compact(mrb, t); + } + t->size++; + + seg = (segment*)mrb_malloc(mrb, sizeof(segment)); + seg->next = NULL; + seg->e[0].key = key; + seg->e[0].val = val; + t->last_len = 1; + if (t->rootseg == NULL) { + t->rootseg = seg; + } + else { + t->lastseg->next = seg; + } + t->lastseg = seg; + if (t->index == NULL && t->size > MRB_SG_SEGMENT_SIZE*4) { + sg_index(mrb, t); + } +} + +/* Get a value for a key from the indexed segment list. */ +static mrb_bool +sg_index_get(mrb_state *mrb, seglist *t, mrb_value key, mrb_value *vp) +{ + segindex *index = t->index; + size_t mask = SG_MASK(index); + size_t k = sg_hash_func(mrb, t, key) & mask; + size_t step = 0; + + while (index->table[k]) { + if (sg_hash_equal(mrb, t, key, index->table[k]->key)) { + if (vp) *vp = index->table[k]->val; + return TRUE; + } + k = (k+(++step)) & mask; + } + return FALSE; +} + +/* Get a value for a key from the segment list. */ +static mrb_bool +sg_get(mrb_state *mrb, seglist *t, mrb_value key, mrb_value *vp) +{ + segment *seg; + mrb_int i; + + if (t == NULL) return FALSE; + if (t->index) { + return sg_index_get(mrb, t, key, vp); + } + + seg = t->rootseg; + while (seg) { + for (i=0; ie[i].key; + + if (!seg->next && i >= t->last_len) { + return FALSE; + } + if (mrb_undef_p(k)) continue; + if (sg_hash_equal(mrb, t, k, key)) { + if (vp) *vp = seg->e[i].val; + return TRUE; + } + } + seg = seg->next; + } + return FALSE; } /* Deletes the value for the symbol from the instance variable table. */ @@ -262,18 +452,17 @@ sg_del(mrb_state *mrb, seglist *t, mrb_value key, mrb_value *vp) seg = t->rootseg; while (seg) { for (i=0; ie[i].key; + mrb_value key2; if (!seg->next && i >= t->last_len) { /* not found */ return FALSE; } - if (mrb_undef_p(k)) continue; - if (mrb_hash_ht_hash_equal(mrb, k, key)) { - if (vp) *vp = k; + key2 = seg->e[i].key; + if (!mrb_undef_p(key2) && sg_hash_equal(mrb, t, key, key2)) { + if (vp) *vp = key2; seg->e[i].key = mrb_undef_value(); - if (t->size > 0) t->size = -1; - else t->size--; /* count number of deleted */ + t->size--; return TRUE; } } @@ -290,6 +479,9 @@ sg_foreach(mrb_state *mrb, seglist *t, sg_foreach_func *func, void *p) mrb_int i; if (t == NULL) return; + if (t->index && t->index->size-(size_t)t->size > MRB_SG_SEGMENT_SIZE) { + sg_compact(mrb, t); + } seg = t->rootseg; while (seg) { for (i=0; isize < 0) { - sg_compact(mrb, t); - } return t->size; } @@ -355,13 +544,14 @@ sg_free(mrb_state *mrb, seglist *t) seg = seg->next; mrb_free(mrb, p); } + if (t->index) mrb_free(mrb, t->index); mrb_free(mrb, t); } static void mrb_hash_modify(mrb_state *mrb, mrb_value hash); static inline mrb_value -mrb_hash_ht_key(mrb_state *mrb, mrb_value key) +ht_key(mrb_state *mrb, mrb_value key) { if (mrb_string_p(key) && !MRB_FROZEN_P(mrb_str_ptr(key))) { key = mrb_str_dup(mrb, key); @@ -370,7 +560,7 @@ mrb_hash_ht_key(mrb_state *mrb, mrb_value key) return key; } -#define KEY(key) mrb_hash_ht_key(mrb, key) +#define KEY(key) ht_key(mrb, key) static int hash_mark_i(mrb_state *mrb, mrb_value key, mrb_value val, void *p) @@ -489,15 +679,6 @@ mrb_hash_dup(mrb_state *mrb, mrb_value self) return mrb_obj_value(copy); } -MRB_API mrb_bool -mrb_hash_has_key_p(mrb_state *mrb, mrb_value hash, mrb_value key) -{ - if (sg_get(mrb, RHASH_TBL(hash), key, NULL)) { - return TRUE; - } - return FALSE; -} - MRB_API mrb_value mrb_hash_get(mrb_state *mrb, mrb_value hash, mrb_value key) { @@ -821,6 +1002,33 @@ mrb_hash_delete(mrb_state *mrb, mrb_value self) return mrb_hash_delete_key(mrb, self, key); } +/* find first element in segment list, and remove it. */ +static void +sg_shift(mrb_state *mrb, seglist *t, mrb_value *kp, mrb_value *vp) +{ + segment *seg = t->rootseg; + mrb_int i; + + while (seg) { + for (i=0; inext && i >= t->last_len) { + return; + } + key = seg->e[i].key; + if (mrb_undef_p(key)) continue; + *kp = key; + *vp = seg->e[i].val; + /* delete element */ + seg->e[i].key = mrb_undef_value(); + t->size--; + return; + } + seg = seg->next; + } +} + /* 15.2.13.4.24 */ /* * call-seq: @@ -842,9 +1050,9 @@ mrb_hash_shift(mrb_state *mrb, mrb_value hash) mrb_hash_modify(mrb, hash); if (sg && sg_size(mrb, sg) > 0) { - mrb_value del_key = sg->rootseg->e[0].key; - mrb_value del_val = sg->rootseg->e[0].val; - sg_del(mrb, sg, del_key, NULL); + mrb_value del_key, del_val; + + sg_shift(mrb, sg, &del_key, &del_val); return mrb_assoc_new(mrb, del_key, del_val); } -- cgit v1.2.3 From 54ec08c7f19e7c46de3dcb63e4f30cd65e4a56e7 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Wed, 26 Sep 2018 13:04:13 +0900 Subject: Implement `Hash#rehash` in C using `sg_compact()`. --- mrblib/hash.rb | 20 -------------------- src/hash.c | 21 +++++++++++++++++++++ 2 files changed, 21 insertions(+), 20 deletions(-) diff --git a/mrblib/hash.rb b/mrblib/hash.rb index 245b76ee0..582cfbc6c 100644 --- a/mrblib/hash.rb +++ b/mrblib/hash.rb @@ -317,26 +317,6 @@ class Hash } h end - - ## - # call-seq: - # hsh.rehash -> hsh - # - # Rebuilds the hash based on the current hash values for each key. If - # values of key objects have changed since they were inserted, this - # method will reindex hsh. - # - # h = {"AAA" => "b"} - # h.keys[0].chop! - # h #=> {"AA"=>"b"} - # h["AA"] #=> nil - # h.rehash #=> {"AA"=>"b"} - # h["AA"] #=> "b" - # - def rehash - # do nothing (for now) - self - end end ## diff --git a/src/hash.c b/src/hash.c index 07a12be68..21dc846af 100644 --- a/src/hash.c +++ b/src/hash.c @@ -1367,6 +1367,26 @@ mrb_hash_merge(mrb_state *mrb, mrb_value hash1, mrb_value hash2) return; } +/* + * call-seq: + * hsh.rehash -> hsh + * + * Rebuilds the hash based on the current hash values for each key. If + * values of key objects have changed since they were inserted, this + * method will reindex hsh. + * + * h = {"AAA" => "b"} + * h.keys[0].chop! + * h.rehash #=> {"AA"=>"b"} + * h["AA"] #=> "b" + */ +static mrb_value +mrb_hash_rehash(mrb_state *mrb, mrb_value self) +{ + sg_compact(mrb, RHASH_TBL(self)); + return self; +} + void mrb_init_hash(mrb_state *mrb) { @@ -1398,6 +1418,7 @@ mrb_init_hash(mrb_state *mrb) mrb_define_method(mrb, h, "store", mrb_hash_aset, MRB_ARGS_REQ(2)); /* 15.2.13.4.26 */ mrb_define_method(mrb, h, "value?", mrb_hash_has_value, MRB_ARGS_REQ(1)); /* 15.2.13.4.27 */ mrb_define_method(mrb, h, "values", mrb_hash_values, MRB_ARGS_NONE()); /* 15.2.13.4.28 */ + mrb_define_method(mrb, h, "rehash", mrb_hash_rehash, MRB_ARGS_NONE()); mrb_define_method(mrb, h, "to_hash", mrb_hash_to_hash, MRB_ARGS_NONE()); /* 15.2.13.4.29 (x)*/ } -- cgit v1.2.3 From e6841abad69df4d20e359e0b1c2eb190696ec0c4 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Thu, 27 Sep 2018 21:43:35 +0900 Subject: Fixed a `String#squeeze` bug in handling `iso-8859-1` strings; ref #4127 --- mrbgems/mruby-string-ext/src/string.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mrbgems/mruby-string-ext/src/string.c b/mrbgems/mruby-string-ext/src/string.c index ea8d77249..9e35b18a9 100644 --- a/mrbgems/mruby-string-ext/src/string.c +++ b/mrbgems/mruby-string-ext/src/string.c @@ -573,7 +573,7 @@ str_squeeze(mrb_state *mrb, mrb_value str, mrb_value v_pat) else { for (i=j=0; ij) s[j] = s[i]; - if (s[i] == lastch) { + if (s[i] >= 0 && s[i] == lastch) { flag_changed = TRUE; j--; } -- cgit v1.2.3 From 8392578216548c01713319df199c7344e056ba24 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Tue, 2 Oct 2018 17:26:43 +0900 Subject: Fixed SEGV from `eval` called form top-level `mrb_funcall()`; fix #4028 --- mrbgems/mruby-eval/src/eval.c | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/mrbgems/mruby-eval/src/eval.c b/mrbgems/mruby-eval/src/eval.c index b9c87f6d1..e6a82723d 100644 --- a/mrbgems/mruby-eval/src/eval.c +++ b/mrbgems/mruby-eval/src/eval.c @@ -226,7 +226,7 @@ create_proc_from_string(mrb_state *mrb, char *s, mrb_int len, mrb_value binding, struct mrb_parser_state *p; struct RProc *proc; struct REnv *e; - mrb_callinfo *ci = &mrb->c->ci[-1]; /* callinfo of eval caller */ + mrb_callinfo *ci; /* callinfo of eval caller */ struct RClass *target_class = NULL; int bidx; @@ -276,8 +276,16 @@ create_proc_from_string(mrb_state *mrb, char *s, mrb_int len, mrb_value binding, mrbc_context_free(mrb, cxt); mrb_raise(mrb, E_SCRIPT_ERROR, "codegen error"); } - target_class = MRB_PROC_TARGET_CLASS(ci->proc); - if (!MRB_PROC_CFUNC_P(ci->proc)) { + if (mrb->c->ci > mrb->c->cibase) { + ci = &mrb->c->ci[-1]; + } + else { + ci = mrb->c->cibase; + } + if (ci->proc) { + target_class = MRB_PROC_TARGET_CLASS(ci->proc); + } + if (ci->proc && !MRB_PROC_CFUNC_P(ci->proc)) { if (ci->env) { e = ci->env; } @@ -315,10 +323,12 @@ exec_irep(mrb_state *mrb, mrb_value self, struct RProc *proc) /* no argument passed from eval() */ mrb->c->ci->argc = 0; if (mrb->c->ci->acc < 0) { + ptrdiff_t cioff = mrb->c->ci - mrb->c->cibase; mrb_value ret = mrb_top_run(mrb, proc, self, 0); if (mrb->exc) { mrb_exc_raise(mrb, mrb_obj_value(mrb->exc)); } + mrb->c->ci = mrb->c->cibase + cioff; return ret; } /* clear block */ -- cgit v1.2.3 From f38e6c63e9bed2aea5dffcf058fca13f7917365b Mon Sep 17 00:00:00 2001 From: Jun Aruga Date: Fri, 5 Oct 2018 14:15:33 +0200 Subject: Refactor .travis.yml to remove duplicated env: MRUBY_CONFIG. --- .travis.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index d8c22c046..9ef7009a6 100644 --- a/.travis.yml +++ b/.travis.yml @@ -15,6 +15,5 @@ addons: - gperf env: - MRUBY_CONFIG=travis_config.rb -env: MRUBY_CONFIG=travis_config.rb + - MRUBY_CONFIG=travis_config.rb script: "./minirake -j4 all test" -- cgit v1.2.3 From 82e00ce60f358489ae2c3a7fdbe4da9bf264b286 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Fri, 12 Oct 2018 08:25:54 +0900 Subject: `Hash#delete` should return the deleted value; fix #4133 --- src/hash.c | 2 +- test/t/hash.rb | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/hash.c b/src/hash.c index 21dc846af..5bccb3091 100644 --- a/src/hash.c +++ b/src/hash.c @@ -460,7 +460,7 @@ sg_del(mrb_state *mrb, seglist *t, mrb_value key, mrb_value *vp) } key2 = seg->e[i].key; if (!mrb_undef_p(key2) && sg_hash_equal(mrb, t, key, key2)) { - if (vp) *vp = key2; + if (vp) *vp = seg->e[i].val; seg->e[i].key = mrb_undef_value(); t->size--; return TRUE; diff --git a/test/t/hash.rb b/test/t/hash.rb index 5403a5901..8088bfa21 100644 --- a/test/t/hash.rb +++ b/test/t/hash.rb @@ -82,12 +82,12 @@ assert('Hash#default_proc', '15.2.13.4.7') do end assert('Hash#delete', '15.2.13.4.8') do - a = { 'abc' => 'abc' } - b = { 'abc' => 'abc' } + a = { 'abc' => 'ABC' } + b = { 'abc' => 'ABC' } b_tmp_1 = false b_tmp_2 = false - a.delete('abc') + assert_equal 'ABC', a.delete('abc') b.delete('abc') do |k| b_tmp_1 = true end -- cgit v1.2.3 From 249fef7dc49ee5c22256aa7e9c36cd788e0ba323 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Fri, 12 Oct 2018 08:30:57 +0900 Subject: Add `NULL` check in `sg_compact()`; fix #4139 --- src/hash.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/hash.c b/src/hash.c index 5bccb3091..325c7e66f 100644 --- a/src/hash.c +++ b/src/hash.c @@ -226,12 +226,14 @@ sg_index(mrb_state *mrb, seglist *t) static void sg_compact(mrb_state *mrb, seglist *t) { - segment *seg = t->rootseg; + segment *seg; mrb_int i; segment *seg2 = NULL; mrb_int i2; mrb_int size = 0; + if (t == NULL) return; + seg = t->rootseg; if (t->index && (size_t)t->size == t->index->size) { sg_index(mrb, t); return; -- cgit v1.2.3 From ab0f4db688248a27faba904a0b2bdc55ba9e5ac9 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Fri, 12 Oct 2018 19:00:14 +0900 Subject: Call `uniq!` for each union processing in `Array#union`. --- mrbgems/mruby-array-ext/mrblib/array.rb | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/mrbgems/mruby-array-ext/mrblib/array.rb b/mrbgems/mruby-array-ext/mrblib/array.rb index eac8d4718..ed3f591fe 100644 --- a/mrbgems/mruby-array-ext/mrblib/array.rb +++ b/mrbgems/mruby-array-ext/mrblib/array.rb @@ -143,11 +143,11 @@ class Array # def union(*args) ary = self.dup - args.each_with_index do |x,i| + args.each do |x| ary.concat(x) - ary.uniq! if i % 20 == 0 + ary.uniq! end - ary.uniq! or ary + ary end ## -- cgit v1.2.3 From e5f160dc7ec4f5ae596a7129f368ccc06186c3ee Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Fri, 12 Oct 2018 19:00:45 +0900 Subject: Should not compare `undef` (deleted) key in hashes; fix #4136 --- src/hash.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/hash.c b/src/hash.c index 325c7e66f..e1ceec489 100644 --- a/src/hash.c +++ b/src/hash.c @@ -402,7 +402,8 @@ sg_index_get(mrb_state *mrb, seglist *t, mrb_value key, mrb_value *vp) size_t step = 0; while (index->table[k]) { - if (sg_hash_equal(mrb, t, key, index->table[k]->key)) { + mrb_value key2 = index->table[k]->key; + if (!mrb_undef_p(key2) && sg_hash_equal(mrb, t, key, key2)) { if (vp) *vp = index->table[k]->val; return TRUE; } -- cgit v1.2.3 From d2313aebd6940df8d3fec53c6397bc8c0cde9cff Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Fri, 12 Oct 2018 23:26:14 +0900 Subject: Fixed broken stack consistency; fix #4135 --- mrbgems/mruby-compiler/core/codegen.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mrbgems/mruby-compiler/core/codegen.c b/mrbgems/mruby-compiler/core/codegen.c index 74504ffd1..4ebd4cd93 100644 --- a/mrbgems/mruby-compiler/core/codegen.c +++ b/mrbgems/mruby-compiler/core/codegen.c @@ -1795,8 +1795,8 @@ codegen(codegen_scope *s, node *tree, int val) len = 0; } else { - codegen(s, tree->car->car, VAL); - codegen(s, tree->car->cdr, VAL); + codegen(s, tree->car->car, val); + codegen(s, tree->car->cdr, val); len++; } tree = tree->cdr; -- cgit v1.2.3 From fdd5ce8fac8f306f71f336f07f0a537b8626e6d6 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Sat, 13 Oct 2018 00:31:13 +0900 Subject: Fixed a bug caused by too much optimization; fix #4137 --- mrbgems/mruby-compiler/core/codegen.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/mrbgems/mruby-compiler/core/codegen.c b/mrbgems/mruby-compiler/core/codegen.c index 4ebd4cd93..8ab1b9bc3 100644 --- a/mrbgems/mruby-compiler/core/codegen.c +++ b/mrbgems/mruby-compiler/core/codegen.c @@ -1969,9 +1969,9 @@ codegen(codegen_scope *s, node *tree, int val) } } /* copy receiver and arguments */ - gen_move(s, cursp(), base, 0); + gen_move(s, cursp(), base, 1); for (i=0; i= 0) { - gen_move(s, vsp, cursp(), 0); + gen_move(s, vsp, cursp(), 1); } pos = genjmp2(s, name[0]=='|'?OP_JMPIF:OP_JMPNOT, cursp(), 0, val); } @@ -1998,7 +1998,7 @@ codegen(codegen_scope *s, node *tree, int val) codegen(s, tree->cdr->cdr->car, VAL); pop(); if (val && vsp >= 0) { - gen_move(s, vsp, cursp(), 0); + gen_move(s, vsp, cursp(), 1); } if (nint(tree->car->car) == NODE_CALL) { if (callargs == CALL_MAXARGS) { -- cgit v1.2.3 From 91444c47476f8f62723d0bee2684a0817b99e448 Mon Sep 17 00:00:00 2001 From: Tomoyuki Sahara Date: Thu, 18 Oct 2018 13:07:47 +0900 Subject: replace quicksort with mergesort. --- mrbgems/mruby-enum-ext/mrblib/enum.rb | 4 +- mrblib/array.rb | 84 +++++++++++++++++++++-------------- test/t/array.rb | 6 +++ 3 files changed, 58 insertions(+), 36 deletions(-) diff --git a/mrbgems/mruby-enum-ext/mrblib/enum.rb b/mrbgems/mruby-enum-ext/mrblib/enum.rb index 6cbacdf9e..ba92decee 100644 --- a/mrbgems/mruby-enum-ext/mrblib/enum.rb +++ b/mrbgems/mruby-enum-ext/mrblib/enum.rb @@ -201,9 +201,7 @@ module Enumerable ary.push([block.call(e), i]) } if ary.size > 1 - ary.__sort_sub__(0, ary.size - 1) do |a,b| - a <=> b - end + ary.sort! end ary.collect{|e,i| orig[i]} end diff --git a/mrblib/array.rb b/mrblib/array.rb index 13c5d646c..ae0868410 100644 --- a/mrblib/array.rb +++ b/mrblib/array.rb @@ -193,43 +193,61 @@ class Array include Enumerable ## - # Quick sort - # left : the beginning of sort region - # right : the end of sort region - def __sort_sub__(left, right, &block) - stack = [ [left, right] ] + # Sort all elements and replace +self+ with these + # elements. + def sort!(&block) + stack = [ [ 0, self.size - 1 ] ] until stack.empty? - left, right = stack.pop - if left < right - i = left - j = right - pivot = self[i + (j - i) / 2] - while true - while ((block)? block.call(self[i], pivot): (self[i] <=> pivot)) < 0 - i += 1 - end - while ((block)? block.call(pivot, self[j]): (pivot <=> self[j])) < 0 - j -= 1 + left, mid, right = stack.pop + if right == nil + right = mid + # sort self[left..right] + if left < right + if left + 1 == right + lval = self[left] + rval = self[right] + if (block&.call(lval, rval) || (lval <=> rval)) > 0 + self[left] = rval + self[right] = lval + end + else + mid = ((left + right + 1) / 2).floor + stack.push [ left, mid, right ] + stack.push [ mid, right ] + stack.push [ left, (mid - 1) ] if left < mid - 1 end - break if (i >= j) - tmp = self[i]; self[i] = self[j]; self[j] = tmp; - i += 1 - j -= 1 end - stack.push [left, i-1] - stack.push [j+1, right] - end - end - end - # private :__sort_sub__ + else + lary = self[left, mid - left] + lsize = lary.size - ## - # Sort all elements and replace +self+ with these - # elements. - def sort!(&block) - size = self.size - if size > 1 - __sort_sub__(0, size - 1, &block) + # The entity sharing between lary and self may cause a large memory + # copy operation in the merge loop below. This harmless operation + # cancels the sharing and provides a huge performance gain. + lary[0] = lary[0] + + # merge + lidx = 0 + ridx = mid + (left..right).each { |i| + if lidx >= lsize + break + elsif ridx > right + self[i, lsize - lidx] = lary[lidx, lsize - lidx] + break + else + lval = lary[lidx] + rval = self[ridx] + if (block&.call(lval, rval) || (lval <=> rval)) <= 0 + self[i] = lval + lidx += 1 + else + self[i] = rval + ridx += 1 + end + end + } + end end self end diff --git a/test/t/array.rb b/test/t/array.rb index ecec39363..53fbdcf1a 100644 --- a/test/t/array.rb +++ b/test/t/array.rb @@ -386,6 +386,12 @@ assert("Array#rindex") do assert_equal 0, $a.rindex(1) end +assert('Array#sort!') do + a = [3, 2, 1] + assert_equal a, a.sort! # sort! returns self. + assert_equal [1, 2, 3], a # it is sorted. +end + assert('Array#freeze') do a = [].freeze assert_raise(RuntimeError) do -- cgit v1.2.3 From 80b5a56f5139c9bcc6f064ac77c7a69b7489137c Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Sat, 20 Oct 2018 19:02:12 +0900 Subject: Need to freeze string keys. --- src/hash.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/hash.c b/src/hash.c index e1ceec489..03a95dbd8 100644 --- a/src/hash.c +++ b/src/hash.c @@ -717,6 +717,7 @@ mrb_hash_set(mrb_state *mrb, mrb_value hash, mrb_value key, mrb_value val) { mrb_hash_modify(mrb, hash); + key = KEY(key); sg_put(mrb, RHASH_TBL(hash), key, val); mrb_field_write_barrier_value(mrb, (struct RBasic*)RHASH(hash), key); mrb_field_write_barrier_value(mrb, (struct RBasic*)RHASH(hash), val); -- cgit v1.2.3 From b3a181aaa13aaa85e968fd09b780c061289aea38 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Tue, 23 Oct 2018 21:10:03 +0900 Subject: Fixed a bug in processing `OP_EXT?` instructions. fix haconiwa/haconiwa#171 --- mrbgems/mruby-eval/src/eval.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/mrbgems/mruby-eval/src/eval.c b/mrbgems/mruby-eval/src/eval.c index e6a82723d..fa687d624 100644 --- a/mrbgems/mruby-eval/src/eval.c +++ b/mrbgems/mruby-eval/src/eval.c @@ -201,16 +201,16 @@ patch_irep(mrb_state *mrb, mrb_irep *irep, int bnest, mrb_irep *top) break; case OP_EXT1: - insn = PEEK_B(irep->iseq+1); - i += mrb_insn_size1[insn]; + insn = PEEK_B(irep->iseq+i+1); + i += mrb_insn_size1[insn]+1; continue; case OP_EXT2: - insn = PEEK_B(irep->iseq+1); - i += mrb_insn_size2[insn]; + insn = PEEK_B(irep->iseq+i+1); + i += mrb_insn_size2[insn]+1; continue; case OP_EXT3: - insn = PEEK_B(irep->iseq+1); - i += mrb_insn_size3[insn]; + insn = PEEK_B(irep->iseq+i+1); + i += mrb_insn_size3[insn]+1; continue; } i+=mrb_insn_size[insn]; -- cgit v1.2.3 From 7ff84789c3f77f0d61441f9afb22a1039ea7cc4a Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Mon, 29 Oct 2018 10:12:10 +0900 Subject: Add argument check to `Array#clear`; fix #4144 --- src/array.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/array.c b/src/array.c index 0b039a6ec..eddd9b2ac 100644 --- a/src/array.c +++ b/src/array.c @@ -1100,6 +1100,7 @@ mrb_ary_clear(mrb_state *mrb, mrb_value self) { struct RArray *a = mrb_ary_ptr(self); + mrb_get_args(mrb, ""); ary_modify(mrb, a); if (ARY_SHARED_P(a)) { mrb_ary_decref(mrb, a->as.heap.aux.shared); -- cgit v1.2.3 From dffa203d07aaeec4ea65669542a8ec2033559bdd Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Mon, 29 Oct 2018 11:51:04 +0900 Subject: Need to mark shared env objects as `MRB_TT_FREE`; fix #4143 The following code mistakenly exits from the function without marking the env object as `MRB_TT_FREE`. ``` ruby if (MRB_ENV_STACK_SHARED_P(e)) { /* cannot be freed */ return; // <- should be `break` } ``` --- src/gc.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/gc.c b/src/gc.c index e429603dd..9b11b7a83 100644 --- a/src/gc.c +++ b/src/gc.c @@ -788,7 +788,8 @@ obj_free(mrb_state *mrb, struct RBasic *obj, int end) if (MRB_ENV_STACK_SHARED_P(e)) { /* cannot be freed */ - return; + e->stack = NULL; + break; } mrb_free(mrb, e->stack); e->stack = NULL; -- cgit v1.2.3 From 34872e90d44bdde64e18b7774cf09495ec043e24 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Mon, 29 Oct 2018 11:55:49 +0900 Subject: Re-implement `Array#_inspect` and `Hash#_inspect` without blocks. To reduce the env object allocation; ref #4143 --- mrblib/array.rb | 11 +++++++++-- mrblib/hash.rb | 13 ++++++++++--- 2 files changed, 19 insertions(+), 5 deletions(-) diff --git a/mrblib/array.rb b/mrblib/array.rb index ae0868410..53d880660 100644 --- a/mrblib/array.rb +++ b/mrblib/array.rb @@ -84,8 +84,15 @@ class Array end def _inspect - return "[]" if self.size == 0 - "["+self.map{|x|x.inspect}.join(", ")+"]" + size = self.size + return "[]" if size == 0 + ary=[] + i=0 + while i" + v._inspect - }.join(", ")+"}" + ary=[] + keys=self.keys + size=keys.size + i=0 + while i" + self[k]._inspect) + i+=1 + end + "{"+ary.join(", ")+"}" end ## # Return the contents of this hash as a string. -- cgit v1.2.3 From 3dc3643e34e1e9f119594ebd550f19e876d60e26 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Mon, 29 Oct 2018 11:58:10 +0900 Subject: Marking from terminated fibers are not needed; ref #4143 The old condition marks the top-level callinfo even after the fiber is terminated. --- src/gc.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/gc.c b/src/gc.c index 9b11b7a83..bacc322e8 100644 --- a/src/gc.c +++ b/src/gc.c @@ -801,10 +801,10 @@ obj_free(mrb_state *mrb, struct RBasic *obj, int end) struct mrb_context *c = ((struct RFiber*)obj)->cxt; if (c && c != mrb->root_c) { - mrb_callinfo *ci = c->ci; - mrb_callinfo *ce = c->cibase; + if (!end && c->status != MRB_FIBER_TERMINATED) { + mrb_callinfo *ci = c->ci; + mrb_callinfo *ce = c->cibase; - if (!end) { while (ce <= ci) { struct REnv *e = ci->env; if (e && !is_dead(&mrb->gc, e) && -- cgit v1.2.3 From fa33a4d75a33c303a78b5bbd7743e207e3e89d61 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Mon, 29 Oct 2018 12:01:27 +0900 Subject: We need no write barrier here; ref #4143 --- src/vm.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/vm.c b/src/vm.c index 9eeb388fc..067dd90f7 100644 --- a/src/vm.c +++ b/src/vm.c @@ -1984,10 +1984,7 @@ RETRY_TRY_BLOCK: while (c->eidx > ci->epos) { ecall_adjust(); } - if (c->fib) { - mrb_write_barrier(mrb, (struct RBasic*)c->fib); - } - mrb->c->status = MRB_FIBER_TERMINATED; + c->status = MRB_FIBER_TERMINATED; mrb->c = c->prev; c->prev = NULL; goto L_RAISE; -- cgit v1.2.3 From 52d55e6069a513f664f94947778011120e4974c3 Mon Sep 17 00:00:00 2001 From: take-cheeze Date: Mon, 29 Oct 2018 13:21:36 +0900 Subject: Keep tr_pattern static --- mrbgems/mruby-string-ext/src/string.c | 107 +++++++++++++++++++++------------- 1 file changed, 65 insertions(+), 42 deletions(-) diff --git a/mrbgems/mruby-string-ext/src/string.c b/mrbgems/mruby-string-ext/src/string.c index 9e35b18a9..9b317386e 100644 --- a/mrbgems/mruby-string-ext/src/string.c +++ b/mrbgems/mruby-string-ext/src/string.c @@ -235,6 +235,12 @@ mrb_str_end_with(mrb_state *mrb, mrb_value self) return mrb_false_value(); } +enum tr_pattern_type { + TR_UNINITIALIZED = 0, + TR_IN_ORDER = 1, + TR_RANGE = 2, +}; + /* #tr Pattern syntax @@ -245,18 +251,26 @@ mrb_str_end_with(mrb_state *mrb, mrb_value self) */ struct tr_pattern { uint8_t type; // 1:in-order, 2:range - mrb_bool flag_reverse; - int16_t n; + mrb_bool flag_reverse : 1; + mrb_bool flag_on_stack : 1; + uint16_t n; + union { + uint16_t start_pos; + char ch[2]; + } val; struct tr_pattern *next; - char ch[]; }; -static void +#define STATIC_TR_PATTERN { TR_UNINITIALIZED, FALSE, TRUE, 0, {}, NULL } + +static inline void tr_free_pattern(mrb_state *mrb, struct tr_pattern *pat) { while (pat) { struct tr_pattern *p = pat->next; - mrb_free(mrb, pat); + if (!pat->flag_on_stack) { + mrb_free(mrb, pat); + } pat = p; } } @@ -277,20 +291,24 @@ tr_parse_pattern(mrb_state *mrb, struct tr_pattern *ret, const mrb_value v_patte while (i < pattern_length) { /* is range pattern ? */ + mrb_bool const ret_uninit = (ret->type == TR_UNINITIALIZED); + pat1 = ret_uninit + ? ret + : (struct tr_pattern*)mrb_malloc_simple(mrb, sizeof(struct tr_pattern)); if ((i+2) < pattern_length && pattern[i] != '\\' && pattern[i+1] == '-') { - pat1 = (struct tr_pattern*)mrb_malloc_simple(mrb, sizeof(struct tr_pattern) + 2); if (pat1 == NULL && ret) { nomem: tr_free_pattern(mrb, ret); mrb_exc_raise(mrb, mrb_obj_value(mrb->nomem_err)); return NULL; /* not reached */ } - pat1->type = 2; + pat1->type = TR_RANGE; pat1->flag_reverse = flag_reverse; + pat1->flag_on_stack = ret_uninit; pat1->n = pattern[i+2] - pattern[i] + 1; pat1->next = NULL; - pat1->ch[0] = pattern[i]; - pat1->ch[1] = pattern[i+2]; + pat1->val.ch[0] = pattern[i]; + pat1->val.ch[1] = pattern[i+2]; i += 3; } else { @@ -305,18 +323,18 @@ tr_parse_pattern(mrb_state *mrb, struct tr_pattern *ret, const mrb_value v_patte } len = i - start_pos; - pat1 = (struct tr_pattern*)mrb_malloc_simple(mrb, sizeof(struct tr_pattern) + len); if (pat1 == NULL && ret) { goto nomem; } - pat1->type = 1; + pat1->type = TR_IN_ORDER; pat1->flag_reverse = flag_reverse; + pat1->flag_on_stack = ret_uninit; pat1->n = len; pat1->next = NULL; - memcpy(pat1->ch, &pattern[start_pos], len); + pat1->val.start_pos = start_pos; } - if (ret == NULL) { + if (ret == NULL || ret_uninit) { ret = pat1; } else { @@ -331,23 +349,26 @@ tr_parse_pattern(mrb_state *mrb, struct tr_pattern *ret, const mrb_value v_patte return ret; } -static mrb_int -tr_find_character(const struct tr_pattern *pat, int ch) +static inline mrb_int +tr_find_character(const struct tr_pattern *pat, const char *pat_str, int ch) { mrb_int ret = -1; mrb_int n_sum = 0; mrb_int flag_reverse = pat ? pat->flag_reverse : 0; while (pat != NULL) { - if (pat->type == 1) { /* pat->type == 1 in-order */ + if (pat->type == TR_IN_ORDER) { int i; for (i = 0; i < pat->n; i++) { - if (pat->ch[i] == ch) ret = n_sum + i; + if (pat_str[pat->val.start_pos + i] == ch) ret = n_sum + i; } } - else { /* pat->type == 2 range */ - if (pat->ch[0] <= ch && ch <= pat->ch[1]) - ret = n_sum + ch - pat->ch[0]; + else if (pat->type == TR_RANGE) { + if (pat->val.ch[0] <= ch && ch <= pat->val.ch[1]) + ret = n_sum + ch - pat->val.ch[0]; + } + else { + mrb_assert(FALSE); // should not reach } n_sum += pat->n; pat = pat->next; @@ -359,17 +380,17 @@ tr_find_character(const struct tr_pattern *pat, int ch) return ret; } -static mrb_int -tr_get_character(const struct tr_pattern *pat, mrb_int n_th) +static inline mrb_int +tr_get_character(const struct tr_pattern *pat, const char *pat_str, mrb_int n_th) { mrb_int n_sum = 0; while (pat != NULL) { if (n_th < (n_sum + pat->n)) { mrb_int i = (n_th - n_sum); - return (pat->type == 1) ? pat->ch[i] :pat->ch[0] + i; + return (pat->type == TR_IN_ORDER) ? pat_str[pat->val.start_pos + i] :pat->val.ch[0] + i; } if (pat->next == NULL) { - return (pat->type == 1) ? pat->ch[pat->n - 1] : pat->ch[1]; + return (pat->type == TR_IN_ORDER) ? pat_str[pat->val.start_pos + pat->n - 1] : pat->val.ch[1]; } n_sum += pat->n; pat = pat->next; @@ -381,23 +402,24 @@ tr_get_character(const struct tr_pattern *pat, mrb_int n_th) static mrb_bool str_tr(mrb_state *mrb, mrb_value str, mrb_value p1, mrb_value p2, mrb_bool squeeze) { - struct tr_pattern *pat; - struct tr_pattern *rep; + struct tr_pattern pat = STATIC_TR_PATTERN; + struct tr_pattern rep_storage = STATIC_TR_PATTERN; char *s; mrb_int len; mrb_int i; mrb_int j; mrb_bool flag_changed = FALSE; mrb_int lastch = -1; + struct tr_pattern *rep; mrb_str_modify(mrb, mrb_str_ptr(str)); - pat = tr_parse_pattern(mrb, NULL, p1, TRUE); - rep = tr_parse_pattern(mrb, NULL, p2, FALSE); + tr_parse_pattern(mrb, &pat, p1, TRUE); + rep = tr_parse_pattern(mrb, &rep_storage, p2, FALSE); s = RSTRING_PTR(str); len = RSTRING_LEN(str); for (i=j=0; ij) s[j] = s[i]; if (n >= 0) { @@ -406,7 +428,7 @@ str_tr(mrb_state *mrb, mrb_value str, mrb_value p1, mrb_value p2, mrb_bool squee j--; } else { - mrb_int c = tr_get_character(rep, n); + mrb_int c = tr_get_character(rep, RSTRING_PTR(p2), n); if (squeeze && c == lastch) { j--; @@ -421,8 +443,8 @@ str_tr(mrb_state *mrb, mrb_value str, mrb_value p1, mrb_value p2, mrb_bool squee } } - tr_free_pattern(mrb, pat); - if (rep) tr_free_pattern(mrb, rep); + tr_free_pattern(mrb, &pat); + tr_free_pattern(mrb, rep); if (flag_changed) { RSTR_SET_LEN(RSTRING(str), j); @@ -544,6 +566,7 @@ mrb_str_tr_s_bang(mrb_state *mrb, mrb_value str) static mrb_bool str_squeeze(mrb_state *mrb, mrb_value str, mrb_value v_pat) { + struct tr_pattern pat_storage = STATIC_TR_PATTERN; struct tr_pattern *pat = NULL; mrb_int i, j; char *s; @@ -553,14 +576,14 @@ str_squeeze(mrb_state *mrb, mrb_value str, mrb_value v_pat) mrb_str_modify(mrb, mrb_str_ptr(str)); if (!mrb_nil_p(v_pat)) { - pat = tr_parse_pattern(mrb, pat, v_pat, TRUE); + pat = tr_parse_pattern(mrb, &pat_storage, v_pat, TRUE); } s = RSTRING_PTR(str); len = RSTRING_LEN(str); if (pat) { for (i=j=0; ij) s[j] = s[i]; if (n >= 0 && s[i] == lastch) { @@ -637,19 +660,19 @@ mrb_str_squeeze_bang(mrb_state *mrb, mrb_value str) static mrb_bool str_delete(mrb_state *mrb, mrb_value str, mrb_value v_pat) { - struct tr_pattern *pat = NULL; + struct tr_pattern pat = STATIC_TR_PATTERN; mrb_int i, j; char *s; mrb_int len; mrb_bool flag_changed = FALSE; mrb_str_modify(mrb, mrb_str_ptr(str)); - pat = tr_parse_pattern(mrb, pat, v_pat, TRUE); + tr_parse_pattern(mrb, &pat, v_pat, TRUE); s = RSTRING_PTR(str); len = RSTRING_LEN(str); for (i=j=0; ij) s[j] = s[i]; if (n >= 0) { @@ -657,7 +680,7 @@ str_delete(mrb_state *mrb, mrb_value str, mrb_value v_pat) j--; } } - tr_free_pattern(mrb, pat); + tr_free_pattern(mrb, &pat); if (flag_changed) { RSTR_SET_LEN(RSTRING(str), j); RSTRING_PTR(str)[j] = 0; @@ -704,22 +727,22 @@ static mrb_value mrb_str_count(mrb_state *mrb, mrb_value str) { mrb_value v_pat = mrb_nil_value(); - struct tr_pattern *pat = NULL; mrb_int i; char *s; mrb_int len; mrb_int count = 0; + struct tr_pattern pat = STATIC_TR_PATTERN; mrb_get_args(mrb, "S", &v_pat); - pat = tr_parse_pattern(mrb, pat, v_pat, TRUE); + tr_parse_pattern(mrb, &pat, v_pat, TRUE); s = RSTRING_PTR(str); len = RSTRING_LEN(str); for (i = 0; i < len; i++) { - mrb_int n = tr_find_character(pat, s[i]); + mrb_int n = tr_find_character(&pat, RSTRING_PTR(v_pat), s[i]); if (n >= 0) count++; } - tr_free_pattern(mrb, pat); + tr_free_pattern(mrb, &pat); return mrb_fixnum_value(count); } -- cgit v1.2.3 From ac512e9d9f4cc16ab57c1faf5ddd71dc2b96cfc6 Mon Sep 17 00:00:00 2001 From: take-cheeze Date: Mon, 29 Oct 2018 13:57:41 +0900 Subject: Sort test script list too --- lib/mruby/gem.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/mruby/gem.rb b/lib/mruby/gem.rb index 7e97c34f3..3ecc2e3ab 100644 --- a/lib/mruby/gem.rb +++ b/lib/mruby/gem.rb @@ -63,7 +63,7 @@ module MRuby objfile(f.relative_path_from(@dir).to_s.pathmap("#{build_dir}/%X")) end - @test_rbfiles = Dir.glob("#{dir}/test/**/*.rb") + @test_rbfiles = Dir.glob("#{dir}/test/**/*.rb").sort @test_objs = Dir.glob("#{dir}/test/*.{c,cpp,cxx,cc,m,asm,s,S}").map do |f| objfile(f.relative_path_from(dir).to_s.pathmap("#{build_dir}/%X")) end -- cgit v1.2.3 From 1b185f08e771ecbe6a0baec67499f41bfcea5698 Mon Sep 17 00:00:00 2001 From: take-cheeze Date: Mon, 29 Oct 2018 13:58:25 +0900 Subject: Suppress sleep test script warning --- mrbgems/mruby-sleep/test/sleep_test.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mrbgems/mruby-sleep/test/sleep_test.rb b/mrbgems/mruby-sleep/test/sleep_test.rb index 74030c0d3..349f169b3 100644 --- a/mrbgems/mruby-sleep/test/sleep_test.rb +++ b/mrbgems/mruby-sleep/test/sleep_test.rb @@ -16,7 +16,7 @@ assert("sleep works") do end assert("sleep would not accept negative value") do - e = run_with_catching_error{ sleep -1 } + e = run_with_catching_error{ sleep(-1) } assert_not_equal e, nil assert_equal e.class, ArgumentError @@ -29,7 +29,7 @@ assert("usleep works") do end assert("usleep would not accept negative value") do - e = run_with_catching_error{ usleep -100 } + e = run_with_catching_error{ usleep(-100) } assert_not_equal e, nil assert_equal e.class, ArgumentError -- cgit v1.2.3 From c240aeada99a410e41afcfa5f36f1a0d370f7aa3 Mon Sep 17 00:00:00 2001 From: take-cheeze Date: Mon, 29 Oct 2018 13:58:57 +0900 Subject: Add missing dependency of source code generator --- mrbgems/mruby-test/mrbgem.rake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mrbgems/mruby-test/mrbgem.rake b/mrbgems/mruby-test/mrbgem.rake index 589fc688a..ee70d906f 100644 --- a/mrbgems/mruby-test/mrbgem.rake +++ b/mrbgems/mruby-test/mrbgem.rake @@ -171,7 +171,7 @@ MRuby::Gem::Specification.new('mruby-test') do |spec| file clib => active_gems_path if active_gem_list != current_gem_list file mlib => clib - file clib => [init, build.mrbcfile] do |_t| + file clib => [init, build.mrbcfile, __FILE__] do |_t| _pp "GEN", "*.rb", "#{clib.relative_path}" FileUtils.mkdir_p File.dirname(clib) open(clib, 'w') do |f| -- cgit v1.2.3 From b37b31208152fdee0cb99e00cffec0b9e57040c6 Mon Sep 17 00:00:00 2001 From: take-cheeze Date: Mon, 29 Oct 2018 13:56:20 +0900 Subject: Rename libmruby stuff to avoid confusion --- Rakefile | 4 ++-- lib/mruby/build.rb | 18 ++++++++++++++++-- lib/mruby/gem.rb | 2 +- mrbgems/mruby-bin-mrbc/mrbgem.rake | 2 +- mrbgems/mruby-bin-mruby-config/mrbgem.rake | 2 +- mrbgems/mruby-compiler/mrbgem.rake | 2 +- mrbgems/mruby-test/mrbgem.rake | 5 +---- mrblib/mrblib.rake | 2 +- src/mruby_core.rake | 4 ++-- tasks/libmruby.rake | 6 +++--- tasks/mrbgems.rake | 2 +- 11 files changed, 30 insertions(+), 19 deletions(-) diff --git a/Rakefile b/Rakefile index d2ad9044c..20b6096f5 100644 --- a/Rakefile +++ b/Rakefile @@ -65,7 +65,7 @@ MRuby.each_target do |target| exec = exefile("#{build_dir}/bin/#{bin}") objs = Dir.glob("#{current_dir}/tools/#{bin}/*.{c,cpp,cxx,cc}").map { |f| objfile(f.pathmap("#{current_build_dir}/tools/#{bin}/%n")) } - file exec => objs + [libfile("#{build_dir}/lib/libmruby")] do |t| + file exec => objs + target.libraries do |t| gem_flags = gems.map { |g| g.linker.flags } gem_flags_before_libraries = gems.map { |g| g.linker.flags_before_libraries } gem_flags_after_libraries = gems.map { |g| g.linker.flags_after_libraries } @@ -100,7 +100,7 @@ MRuby.each_target do |target| end depfiles += MRuby.targets.map { |n, t| - [t.libfile("#{t.build_dir}/lib/libmruby")] + t.libraries }.flatten depfiles += MRuby.targets.reject { |n, t| n == 'host' }.map { |n, t| diff --git a/lib/mruby/build.rb b/lib/mruby/build.rb index 047ae13dc..7a0f7a759 100644 --- a/lib/mruby/build.rb +++ b/lib/mruby/build.rb @@ -45,9 +45,11 @@ module MRuby include Rake::DSL include LoadGems attr_accessor :name, :bins, :exts, :file_separator, :build_dir, :gem_clone_dir - attr_reader :libmruby, :gems, :toolchains + attr_reader :libmruby_objs, :gems, :toolchains attr_writer :enable_bintest, :enable_test + alias libmruby libmruby_objs + COMPILERS = %w(cc cxx objc asm) COMMANDS = COMPILERS + %w(linker archiver yacc gperf git exts mrbc) attr_block MRuby::Build::COMMANDS @@ -81,7 +83,7 @@ module MRuby @mrbc = Command::Mrbc.new(self) @bins = [] - @gems, @libmruby = MRuby::Gem::List.new, [] + @gems, @libmruby_objs = MRuby::Gem::List.new, [] @build_mrbtest_lib_only = false @cxx_exception_enabled = false @cxx_exception_disabled = false @@ -327,6 +329,18 @@ EOS puts "================================================" puts end + + def libmruby_static + libfile("#{build_dir}/lib/libmruby") + end + + def libmruby_core_static + libfile("#{build_dir}/lib/libmruby_core") + end + + def libraries + [libmruby_static] + end end # Build class CrossBuild < Build diff --git a/lib/mruby/gem.rb b/lib/mruby/gem.rb index 7e97c34f3..ba4d5d17a 100644 --- a/lib/mruby/gem.rb +++ b/lib/mruby/gem.rb @@ -87,7 +87,7 @@ module MRuby fail "#{name || dir} required to set name, license(s) and author(s)" end - build.libmruby << @objs + build.libmruby_objs << @objs instance_eval(&@build_config_initializer) if @build_config_initializer end diff --git a/mrbgems/mruby-bin-mrbc/mrbgem.rake b/mrbgems/mruby-bin-mrbc/mrbgem.rake index e710b5a49..48b67aedb 100644 --- a/mrbgems/mruby-bin-mrbc/mrbgem.rake +++ b/mrbgems/mruby-bin-mrbc/mrbgem.rake @@ -8,7 +8,7 @@ MRuby::Gem::Specification.new 'mruby-bin-mrbc' do |spec| exec = exefile("#{build.build_dir}/bin/mrbc") mrbc_objs = Dir.glob("#{spec.dir}/tools/mrbc/*.c").map { |f| objfile(f.pathmap("#{spec.build_dir}/tools/mrbc/%n")) }.flatten - file exec => mrbc_objs + [libfile("#{build.build_dir}/lib/libmruby_core")] do |t| + file exec => mrbc_objs + [build.libmruby_core_static] do |t| build.linker.run t.name, t.prerequisites end diff --git a/mrbgems/mruby-bin-mruby-config/mrbgem.rake b/mrbgems/mruby-bin-mruby-config/mrbgem.rake index 32ae2164b..cca7423ac 100644 --- a/mrbgems/mruby-bin-mruby-config/mrbgem.rake +++ b/mrbgems/mruby-bin-mruby-config/mrbgem.rake @@ -20,7 +20,7 @@ MRuby.each_target do @bins << mruby_config make_cfg = "#{build_dir}/lib/libmruby.flags.mak" - file mruby_config_path => [libfile("#{build_dir}/lib/libmruby"), make_cfg] do |t| + file mruby_config_path => [libmruby_static, make_cfg] do |t| FileUtils.copy "#{File.dirname(__FILE__)}/#{mruby_config}", t.name config = Hash[open(make_cfg).read.split("\n").map {|x| a = x.split(/\s*=\s*/, 2); [a[0], a[1].gsub('\\"', '"') ]}] IO.write(t.name, File.open(t.name) {|f| diff --git a/mrbgems/mruby-compiler/mrbgem.rake b/mrbgems/mruby-compiler/mrbgem.rake index e9e0cc2c7..fa191e69b 100644 --- a/mrbgems/mruby-compiler/mrbgem.rake +++ b/mrbgems/mruby-compiler/mrbgem.rake @@ -35,6 +35,6 @@ MRuby::Gem::Specification.new 'mruby-compiler' do |spec| gperf.run t.name, t.prerequisites.first end - file libfile("#{build.build_dir}/lib/libmruby_core") => core_objs + file build.libmruby_core_static => core_objs build.libmruby << core_objs end diff --git a/mrbgems/mruby-test/mrbgem.rake b/mrbgems/mruby-test/mrbgem.rake index 589fc688a..c9d254bfe 100644 --- a/mrbgems/mruby-test/mrbgem.rake +++ b/mrbgems/mruby-test/mrbgem.rake @@ -16,9 +16,6 @@ MRuby::Gem::Specification.new('mruby-test') do |spec| mlib = clib.ext(exts.object) exec = exefile("#{build.build_dir}/bin/mrbtest") - libmruby = libfile("#{build.build_dir}/lib/libmruby") - libmruby_core = libfile("#{build.build_dir}/lib/libmruby_core") - mrbtest_lib = libfile("#{build_dir}/mrbtest") mrbtest_objs = [] @@ -140,7 +137,7 @@ MRuby::Gem::Specification.new('mruby-test') do |spec| end unless build.build_mrbtest_lib_only? - file exec => [driver_obj, mlib, mrbtest_lib, libmruby_core, libmruby] do |t| + file exec => [driver_obj, mlib, mrbtest_lib, build.libmruby_static] do |t| gem_flags = build.gems.map { |g| g.linker.flags } gem_flags_before_libraries = build.gems.map { |g| g.linker.flags_before_libraries } gem_flags_after_libraries = build.gems.map { |g| g.linker.flags_after_libraries } diff --git a/mrblib/mrblib.rake b/mrblib/mrblib.rake index fe4aae1f7..6895d4252 100644 --- a/mrblib/mrblib.rake +++ b/mrblib/mrblib.rake @@ -3,7 +3,7 @@ MRuby.each_target do relative_from_root = File.dirname(__FILE__).relative_path_from(MRUBY_ROOT) current_build_dir = "#{build_dir}/#{relative_from_root}" - self.libmruby << objfile("#{current_build_dir}/mrblib") + self.libmruby_objs << objfile("#{current_build_dir}/mrblib") file objfile("#{current_build_dir}/mrblib") => "#{current_build_dir}/mrblib.c" file "#{current_build_dir}/mrblib.c" => [mrbcfile, __FILE__] + Dir.glob("#{current_dir}/*.rb").sort do |t| diff --git a/src/mruby_core.rake b/src/mruby_core.rake index bb3d7b633..3024c8544 100644 --- a/src/mruby_core.rake +++ b/src/mruby_core.rake @@ -12,9 +12,9 @@ MRuby.each_target do if cxx_exception_enabled? objs += %w(vm error).map { |v| compile_as_cxx "#{current_dir}/#{v}.c", "#{current_build_dir}/#{v}.cxx" } end - self.libmruby << objs + self.libmruby_objs << objs - file libfile("#{build_dir}/lib/libmruby_core") => objs do |t| + file libmruby_core_static => objs do |t| archiver.run t.name, t.prerequisites end end diff --git a/tasks/libmruby.rake b/tasks/libmruby.rake index b6ef29986..ab5a15b4a 100644 --- a/tasks/libmruby.rake +++ b/tasks/libmruby.rake @@ -1,9 +1,9 @@ MRuby.each_target do - file libfile("#{build_dir}/lib/libmruby") => libmruby.flatten do |t| + file libmruby_static => libmruby_objs.flatten do |t| archiver.run t.name, t.prerequisites end - file "#{build_dir}/lib/libmruby.flags.mak" => [__FILE__, libfile("#{build_dir}/lib/libmruby")] do |t| + file "#{build_dir}/lib/libmruby.flags.mak" => [__FILE__, libmruby_static] do |t| FileUtils.mkdir_p File.dirname t.name open(t.name, 'w') do |f| f.puts "MRUBY_CFLAGS = #{cc.all_flags}" @@ -18,7 +18,7 @@ MRuby.each_target do gem_libraries = gems.map { |g| g.linker.libraries } f.puts "MRUBY_LIBS = #{linker.option_library % 'mruby'} #{linker.library_flags(gem_libraries)}" - f.puts "MRUBY_LIBMRUBY_PATH = #{libfile("#{build_dir}/lib/libmruby")}" + f.puts "MRUBY_LIBMRUBY_PATH = #{libmruby_static}" end end task :all => "#{build_dir}/lib/libmruby.flags.mak" diff --git a/tasks/mrbgems.rake b/tasks/mrbgems.rake index e2aeb1514..fb76856e5 100644 --- a/tasks/mrbgems.rake +++ b/tasks/mrbgems.rake @@ -5,7 +5,7 @@ MRuby.each_target do gems.check self # loader all gems - self.libmruby << objfile("#{build_dir}/mrbgems/gem_init") + self.libmruby_objs << objfile("#{build_dir}/mrbgems/gem_init") file objfile("#{build_dir}/mrbgems/gem_init") => ["#{build_dir}/mrbgems/gem_init.c", "#{build_dir}/LEGAL"] file "#{build_dir}/mrbgems/gem_init.c" => [MRUBY_CONFIG, __FILE__] do |t| FileUtils.mkdir_p "#{build_dir}/mrbgems" -- cgit v1.2.3 From 3248de83b6754eecc99d9ab6fdef8bb3575fcd04 Mon Sep 17 00:00:00 2001 From: take-cheeze Date: Mon, 29 Oct 2018 19:17:05 +0900 Subject: Reduce instruction size --- include/mruby/ops.h | 22 ++++++------- include/mruby/symbol.h | 32 ++++++++++++++++++ mrbgems/mruby-compiler/core/codegen.c | 43 ++++++++++++------------ src/symbol.c | 26 +++++++++++++++ src/vm.c | 62 ++++++++++++++++++++++------------- 5 files changed, 130 insertions(+), 55 deletions(-) create mode 100644 include/mruby/symbol.h diff --git a/include/mruby/ops.h b/include/mruby/ops.h index f23bb1b0b..7531a5ee2 100644 --- a/include/mruby/ops.h +++ b/include/mruby/ops.h @@ -70,17 +70,17 @@ OPCODE(RETURN, B) /* return R(a) (normal) */ OPCODE(RETURN_BLK, B) /* return R(a) (in-block return) */ OPCODE(BREAK, B) /* break R(a) */ OPCODE(BLKPUSH, BS) /* R(a) = block (16=m5:r1:m5:d1:lv4) */ -OPCODE(ADD, BB) /* R(a) = R(a)+R(a+1) (Syms[b]=:+) */ -OPCODE(ADDI, BBB) /* R(a) = R(a)+mrb_int(c) (Syms[b]=:+) */ -OPCODE(SUB, BB) /* R(a) = R(a)-R(a+1) (Syms[b]=:-) */ -OPCODE(SUBI, BBB) /* R(a) = R(a)-C (Syms[b]=:-) */ -OPCODE(MUL, BB) /* R(a) = R(a)*R(a+1) (Syms[b]=:*) */ -OPCODE(DIV, BB) /* R(a) = R(a)/R(a+1) (Syms[b]=:/) */ -OPCODE(EQ, BB) /* R(a) = R(a)==R(a+1) (Syms[b]=:==) */ -OPCODE(LT, BB) /* R(a) = R(a)R(a+1) (Syms[b]=:>) */ -OPCODE(GE, BB) /* R(a) = R(a)>=R(a+1) (Syms[b]=:>=) */ +OPCODE(ADD, B) /* R(a) = R(a)+R(a+1) */ +OPCODE(ADDI, BB) /* R(a) = R(a)+mrb_int(c) */ +OPCODE(SUB, B) /* R(a) = R(a)-R(a+1) */ +OPCODE(SUBI, BB) /* R(a) = R(a)-C */ +OPCODE(MUL, B) /* R(a) = R(a)*R(a+1) */ +OPCODE(DIV, B) /* R(a) = R(a)/R(a+1) */ +OPCODE(EQ, B) /* R(a) = R(a)==R(a+1) */ +OPCODE(LT, B) /* R(a) = R(a)R(a+1) */ +OPCODE(GE, B) /* R(a) = R(a)>=R(a+1) */ OPCODE(ARRAY, BB) /* R(a) = ary_new(R(a),R(a+1)..R(a+b)) */ OPCODE(ARRAY2, BBB) /* R(a) = ary_new(R(b),R(b+1)..R(b+c)) */ OPCODE(ARYCAT, B) /* ary_cat(R(a),R(a+1)) */ diff --git a/include/mruby/symbol.h b/include/mruby/symbol.h new file mode 100644 index 000000000..595caeefd --- /dev/null +++ b/include/mruby/symbol.h @@ -0,0 +1,32 @@ +/* +** mruby/symbol.h - symbol utilities +** +** See Copyright Notice in mruby.h +*/ + +#ifndef MRUBY_SYMBOL_H +#define MRUBY_SYMBOL_H + +#include "common.h" + +/** + * Symbol utilities + */ +MRB_BEGIN_DECL + +typedef enum mrb_reserved_symbol { + mrb_sym_add = 1, // + + mrb_sym_sub = 2, // - + mrb_sym_mul = 3, // * + mrb_sym_div = 4, // / + mrb_sym_eq = 5, // == + mrb_sym_lt = 6, // < + mrb_sym_le = 7, // <= + mrb_sym_gt = 8, // > + mrb_sym_ge = 9, // >= + mrb_sym_method_missing = 10, // method_missing +} mrb_reserved_symbol; + +MRB_END_DECL + +#endif /* MRUBY_SYMBOL_H */ diff --git a/mrbgems/mruby-compiler/core/codegen.c b/mrbgems/mruby-compiler/core/codegen.c index 8ab1b9bc3..759e7267e 100644 --- a/mrbgems/mruby-compiler/core/codegen.c +++ b/mrbgems/mruby-compiler/core/codegen.c @@ -468,11 +468,11 @@ gen_return(codegen_scope *s, uint8_t op, uint16_t src) } static void -gen_addsub(codegen_scope *s, uint8_t op, uint16_t dst, uint16_t idx) +gen_addsub(codegen_scope *s, uint8_t op, uint16_t dst) { if (no_peephole(s)) { normal: - genop_2(s, op, dst, idx); + genop_1(s, op, dst); return; } else { @@ -493,10 +493,10 @@ gen_addsub(codegen_scope *s, uint8_t op, uint16_t dst, uint16_t idx) if (data.b >= 128) goto normal; s->pc = s->lastpc; if (op == OP_ADD) { - genop_3(s, OP_ADDI, dst, idx, (uint8_t)data.b); + genop_2(s, OP_ADDI, dst, (uint8_t)data.b); } else { - genop_3(s, OP_SUBI, dst, idx, (uint8_t)data.b); + genop_2(s, OP_SUBI, dst, (uint8_t)data.b); } break; default: @@ -982,6 +982,7 @@ gen_call(codegen_scope *s, node *tree, mrb_sym name, int sp, int val, int safe) gen_move(s, cursp(), recv, 1); skip = genjmp2(s, OP_JMPNIL, cursp(), 0, val); } + // TODO: don't new when unused idx = new_sym(s, sym); tree = tree->cdr->cdr->car; if (tree) { @@ -1017,31 +1018,31 @@ gen_call(codegen_scope *s, node *tree, mrb_sym name, int sp, int val, int safe) const char *symname = mrb_sym2name_len(s->mrb, sym, &symlen); if (!noop && symlen == 1 && symname[0] == '+' && n == 1) { - gen_addsub(s, OP_ADD, cursp(), idx); + gen_addsub(s, OP_ADD, cursp()); } else if (!noop && symlen == 1 && symname[0] == '-' && n == 1) { - gen_addsub(s, OP_SUB, cursp(), idx); + gen_addsub(s, OP_SUB, cursp()); } else if (!noop && symlen == 1 && symname[0] == '*' && n == 1) { - genop_2(s, OP_MUL, cursp(), idx); + genop_1(s, OP_MUL, cursp()); } else if (!noop && symlen == 1 && symname[0] == '/' && n == 1) { - genop_2(s, OP_DIV, cursp(), idx); + genop_1(s, OP_DIV, cursp()); } else if (!noop && symlen == 1 && symname[0] == '<' && n == 1) { - genop_2(s, OP_LT, cursp(), idx); + genop_1(s, OP_LT, cursp()); } else if (!noop && symlen == 2 && symname[0] == '<' && symname[1] == '=' && n == 1) { - genop_2(s, OP_LE, cursp(), idx); + genop_1(s, OP_LE, cursp()); } else if (!noop && symlen == 1 && symname[0] == '>' && n == 1) { - genop_2(s, OP_GT, cursp(), idx); + genop_1(s, OP_GT, cursp()); } else if (!noop && symlen == 2 && symname[0] == '>' && symname[1] == '=' && n == 1) { - genop_2(s, OP_GE, cursp(), idx); + genop_1(s, OP_GE, cursp()); } else if (!noop && symlen == 2 && symname[0] == '=' && symname[1] == '=' && n == 1) { - genop_2(s, OP_EQ, cursp(), idx); + genop_1(s, OP_EQ, cursp()); } else { if (sendv) { @@ -2025,28 +2026,28 @@ codegen(codegen_scope *s, node *tree, int val) idx = new_sym(s, sym); if (len == 1 && name[0] == '+') { - gen_addsub(s, OP_ADD, cursp(), idx); + gen_addsub(s, OP_ADD, cursp()); } else if (len == 1 && name[0] == '-') { - gen_addsub(s, OP_SUB, cursp(), idx); + gen_addsub(s, OP_SUB, cursp()); } else if (len == 1 && name[0] == '*') { - genop_2(s, OP_MUL, cursp(), idx); + genop_1(s, OP_MUL, cursp()); } else if (len == 1 && name[0] == '/') { - genop_2(s, OP_DIV, cursp(), idx); + genop_1(s, OP_DIV, cursp()); } else if (len == 1 && name[0] == '<') { - genop_2(s, OP_LT, cursp(), idx); + genop_1(s, OP_LT, cursp()); } else if (len == 2 && name[0] == '<' && name[1] == '=') { - genop_2(s, OP_LE, cursp(), idx); + genop_1(s, OP_LE, cursp()); } else if (len == 1 && name[0] == '>') { - genop_2(s, OP_GT, cursp(), idx); + genop_1(s, OP_GT, cursp()); } else if (len == 2 && name[0] == '>' && name[1] == '=') { - genop_2(s, OP_GE, cursp(), idx); + genop_1(s, OP_GE, cursp()); } else { genop_3(s, OP_SEND, cursp(), idx, 1); diff --git a/src/symbol.c b/src/symbol.c index 6b4c7200c..f7dbc1be1 100644 --- a/src/symbol.c +++ b/src/symbol.c @@ -11,6 +11,7 @@ #include #include #include +#include /* ------------------------------------------------------ */ typedef struct symbol_name { @@ -170,10 +171,35 @@ mrb_free_symtbl(mrb_state *mrb) kh_destroy(n2s, mrb, mrb->name2sym); } +struct reserved_symbol_t { + mrb_reserved_symbol sym; + char const *str; +}; + +static struct reserved_symbol_t reserved_symbols[] = { + { mrb_sym_add, "+" }, + { mrb_sym_sub, "-" }, + { mrb_sym_mul, "*" }, + { mrb_sym_div, "/" }, + { mrb_sym_eq, "==" }, + { mrb_sym_lt, "<" }, + { mrb_sym_le, "<=" }, + { mrb_sym_gt, ">" }, + { mrb_sym_ge, ">=" }, + { mrb_sym_method_missing, "method_missing" }, + { 0, NULL }, +}; + void mrb_init_symtbl(mrb_state *mrb) { + int i; mrb->name2sym = kh_init(n2s, mrb); + + for (i = 0; reserved_symbols[i].sym != 0; ++i) { + mrb_sym s = mrb_intern_static(mrb, reserved_symbols[i].str, strlen(reserved_symbols[i].str)); + mrb_assert(s == reserved_symbols[i].sym); + } } /********************************************************************** diff --git a/src/vm.c b/src/vm.c index 067dd90f7..9792c3fbd 100644 --- a/src/vm.c +++ b/src/vm.c @@ -21,6 +21,7 @@ #include #include "value_array.h" #include +#include #ifdef MRB_DISABLE_STDIO #if defined(__cplusplus) @@ -1009,6 +1010,7 @@ mrb_vm_exec(mrb_state *mrb, struct RProc *proc, mrb_code *pc) uint32_t a; uint16_t b; uint8_t c; + mrb_sym mid; #ifdef DIRECT_THREADED static void *optable[] = { @@ -1386,9 +1388,18 @@ RETRY_TRY_BLOCK: SET_NIL_VALUE(regs[bidx]); goto L_SENDB; }; + L_SEND_CONSTSYM: + { + /* push nil after arguments */ + int bidx = (c == CALL_MAXARGS) ? a+2 : a+c+1; + SET_NIL_VALUE(regs[bidx]); + goto L_SENDB_CONSTSYM; + }; CASE(OP_SENDB, BBB) L_SENDB: + mid = syms[b]; + L_SENDB_CONSTSYM: { int argc = (c == CALL_MAXARGS) ? -1 : c; int bidx = (argc < 0) ? a+2 : a+c+1; @@ -1396,7 +1407,6 @@ RETRY_TRY_BLOCK: struct RClass *cls; mrb_callinfo *ci = mrb->c->ci; mrb_value recv, blk; - mrb_sym mid = syms[b]; mrb_assert(bidx < irep->nregs); @@ -2204,7 +2214,7 @@ RETRY_TRY_BLOCK: v1(regs[a]) = v1(regs[a]) op v2(regs[a+1]);\ } while(0) - CASE(OP_ADD, BB) { + CASE(OP_ADD, B) { /* need to check if op is overridden */ switch (TYPES2(mrb_type(regs[a]),mrb_type(regs[a+1]))) { case TYPES2(MRB_TT_FIXNUM,MRB_TT_FIXNUM): @@ -2259,13 +2269,14 @@ RETRY_TRY_BLOCK: break; default: c = 1; - goto L_SEND; + mid = mrb_sym_add; + goto L_SEND_CONSTSYM; } mrb_gc_arena_restore(mrb, ai); NEXT; } - CASE(OP_SUB, BB) { + CASE(OP_SUB, B) { /* need to check if op is overridden */ switch (TYPES2(mrb_type(regs[a]),mrb_type(regs[a+1]))) { case TYPES2(MRB_TT_FIXNUM,MRB_TT_FIXNUM): @@ -2316,12 +2327,13 @@ RETRY_TRY_BLOCK: #endif default: c = 1; - goto L_SEND; + mid = mrb_sym_sub; + goto L_SEND_CONSTSYM; } NEXT; } - CASE(OP_MUL, BB) { + CASE(OP_MUL, B) { /* need to check if op is overridden */ switch (TYPES2(mrb_type(regs[a]),mrb_type(regs[a+1]))) { case TYPES2(MRB_TT_FIXNUM,MRB_TT_FIXNUM): @@ -2372,12 +2384,13 @@ RETRY_TRY_BLOCK: #endif default: c = 1; - goto L_SEND; + mid = mrb_sym_mul; + goto L_SEND_CONSTSYM; } NEXT; } - CASE(OP_DIV, BB) { + CASE(OP_DIV, B) { #ifndef MRB_WITHOUT_FLOAT double x, y, f; #endif @@ -2411,7 +2424,8 @@ RETRY_TRY_BLOCK: #endif default: c = 1; - goto L_SEND; + mid = mrb_sym_div; + goto L_SEND_CONSTSYM; } #ifndef MRB_WITHOUT_FLOAT @@ -2509,7 +2523,7 @@ RETRY_TRY_BLOCK: #define OP_CMP_BODY(op,v1,v2) (v1(regs[a]) op v2(regs[a+1])) #ifdef MRB_WITHOUT_FLOAT -#define OP_CMP(op) do {\ +#define OP_CMP(op, sym) do {\ int result;\ /* need to check if - is overridden */\ switch (TYPES2(mrb_type(regs[a]),mrb_type(regs[a+1]))) {\ @@ -2518,7 +2532,8 @@ RETRY_TRY_BLOCK: break;\ default:\ c = 1;\ - goto L_SEND;\ + mid = mrb_sym_ ## sym;\ + goto L_SEND_CONSTSYM;\ }\ if (result) {\ SET_TRUE_VALUE(regs[a]);\ @@ -2528,7 +2543,7 @@ RETRY_TRY_BLOCK: }\ } while(0) #else -#define OP_CMP(op) do {\ +#define OP_CMP(op, sym) do {\ int result;\ /* need to check if - is overridden */\ switch (TYPES2(mrb_type(regs[a]),mrb_type(regs[a+1]))) {\ @@ -2546,7 +2561,8 @@ RETRY_TRY_BLOCK: break;\ default:\ c = 1;\ - goto L_SEND;\ + mid = mrb_sym_ ## sym;\ + goto L_SEND_CONSTSYM;\ }\ if (result) {\ SET_TRUE_VALUE(regs[a]);\ @@ -2557,33 +2573,33 @@ RETRY_TRY_BLOCK: } while(0) #endif - CASE(OP_EQ, BB) { + CASE(OP_EQ, B) { if (mrb_obj_eq(mrb, regs[a], regs[a+1])) { SET_TRUE_VALUE(regs[a]); } else { - OP_CMP(==); + OP_CMP(==, eq); } NEXT; } - CASE(OP_LT, BB) { - OP_CMP(<); + CASE(OP_LT, B) { + OP_CMP(<, gt); NEXT; } - CASE(OP_LE, BB) { - OP_CMP(<=); + CASE(OP_LE, B) { + OP_CMP(<=, ge); NEXT; } - CASE(OP_GT, BB) { - OP_CMP(>); + CASE(OP_GT, B) { + OP_CMP(>, lt); NEXT; } - CASE(OP_GE, BB) { - OP_CMP(>=); + CASE(OP_GE, B) { + OP_CMP(>=, le); NEXT; } -- cgit v1.2.3 From e022080390107e6d746bc24a3651eb6b65daa509 Mon Sep 17 00:00:00 2001 From: take-cheeze Date: Mon, 29 Oct 2018 19:22:43 +0900 Subject: Define null symbol --- include/mruby/symbol.h | 1 + src/symbol.c | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/include/mruby/symbol.h b/include/mruby/symbol.h index 595caeefd..f11346830 100644 --- a/include/mruby/symbol.h +++ b/include/mruby/symbol.h @@ -15,6 +15,7 @@ MRB_BEGIN_DECL typedef enum mrb_reserved_symbol { + mrb_sym_null = 0, // NULL symbol mrb_sym_add = 1, // + mrb_sym_sub = 2, // - mrb_sym_mul = 3, // * diff --git a/src/symbol.c b/src/symbol.c index f7dbc1be1..8ec300e20 100644 --- a/src/symbol.c +++ b/src/symbol.c @@ -187,7 +187,7 @@ static struct reserved_symbol_t reserved_symbols[] = { { mrb_sym_gt, ">" }, { mrb_sym_ge, ">=" }, { mrb_sym_method_missing, "method_missing" }, - { 0, NULL }, + { mrb_sym_null, NULL }, }; void @@ -196,7 +196,7 @@ mrb_init_symtbl(mrb_state *mrb) int i; mrb->name2sym = kh_init(n2s, mrb); - for (i = 0; reserved_symbols[i].sym != 0; ++i) { + for (i = 0; reserved_symbols[i].sym != mrb_sym_null; ++i) { mrb_sym s = mrb_intern_static(mrb, reserved_symbols[i].str, strlen(reserved_symbols[i].str)); mrb_assert(s == reserved_symbols[i].sym); } -- cgit v1.2.3 From 68714ab648356695bc235aaeb29fc43e8bad31d1 Mon Sep 17 00:00:00 2001 From: take-cheeze Date: Mon, 29 Oct 2018 19:26:00 +0900 Subject: Fix SEGV --- src/vm.c | 26 ++++++++++++++------------ 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/src/vm.c b/src/vm.c index 9792c3fbd..85e2f6c59 100644 --- a/src/vm.c +++ b/src/vm.c @@ -2442,13 +2442,13 @@ RETRY_TRY_BLOCK: NEXT; } - CASE(OP_ADDI, BBB) { + CASE(OP_ADDI, BB) { /* need to check if + is overridden */ switch (mrb_type(regs[a])) { case MRB_TT_FIXNUM: { mrb_int x = mrb_fixnum(regs[a]); - mrb_int y = (mrb_int)c; + mrb_int y = (mrb_int)b; mrb_int z; if (mrb_int_add_overflow(x, y, &z)) { @@ -2465,22 +2465,23 @@ RETRY_TRY_BLOCK: #ifdef MRB_WORD_BOXING { mrb_float x = mrb_float(regs[a]); - SET_FLOAT_VALUE(mrb, regs[a], x + c); + SET_FLOAT_VALUE(mrb, regs[a], x + b); } #else - mrb_float(regs[a]) += c; + mrb_float(regs[a]) += b; #endif break; #endif default: - SET_INT_VALUE(regs[a+1], c); + SET_INT_VALUE(regs[a+1], b); c = 1; - goto L_SEND; + mid = mrb_sym_add; + goto L_SEND_CONSTSYM; } NEXT; } - CASE(OP_SUBI, BBB) { + CASE(OP_SUBI, BB) { mrb_value *regs_a = regs + a; /* need to check if + is overridden */ @@ -2488,7 +2489,7 @@ RETRY_TRY_BLOCK: case MRB_TT_FIXNUM: { mrb_int x = mrb_fixnum(regs_a[0]); - mrb_int y = (mrb_int)c; + mrb_int y = (mrb_int)b; mrb_int z; if (mrb_int_sub_overflow(x, y, &z)) { @@ -2505,17 +2506,18 @@ RETRY_TRY_BLOCK: #ifdef MRB_WORD_BOXING { mrb_float x = mrb_float(regs[a]); - SET_FLOAT_VALUE(mrb, regs[a], (mrb_float)x - (mrb_float)c); + SET_FLOAT_VALUE(mrb, regs[a], (mrb_float)x - (mrb_float)b); } #else - mrb_float(regs_a[0]) -= c; + mrb_float(regs_a[0]) -= b; #endif break; #endif default: - SET_INT_VALUE(regs_a[1], c); + SET_INT_VALUE(regs_a[1], b); c = 1; - goto L_SEND; + mid = mrb_sym_sub; + goto L_SEND_CONSTSYM; } NEXT; } -- cgit v1.2.3 From 557805da071e2dc685a7893107ca06a8e3787af0 Mon Sep 17 00:00:00 2001 From: take-cheeze Date: Mon, 29 Oct 2018 19:29:43 +0900 Subject: Fix operator --- src/vm.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/vm.c b/src/vm.c index 85e2f6c59..005396816 100644 --- a/src/vm.c +++ b/src/vm.c @@ -2586,22 +2586,22 @@ RETRY_TRY_BLOCK: } CASE(OP_LT, B) { - OP_CMP(<, gt); + OP_CMP(<, lt); NEXT; } CASE(OP_LE, B) { - OP_CMP(<=, ge); + OP_CMP(<=, le); NEXT; } CASE(OP_GT, B) { - OP_CMP(>, lt); + OP_CMP(>, gt); NEXT; } CASE(OP_GE, B) { - OP_CMP(>=, le); + OP_CMP(>=, ge); NEXT; } -- cgit v1.2.3 From 7d51a7bbf5439f294dd5b7281ebd960211dc4baa Mon Sep 17 00:00:00 2001 From: take-cheeze Date: Mon, 29 Oct 2018 19:34:56 +0900 Subject: Fix document --- doc/opcode.md | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/doc/opcode.md b/doc/opcode.md index fea0afafd..eab82a26f 100644 --- a/doc/opcode.md +++ b/doc/opcode.md @@ -84,17 +84,17 @@ with `"`, either `OP_EXT1` or `OP_EXT2` or `OP_EXT2` can be prefixed. |OP_RETURN_BLK' |B |return R(a) (in-block return) |OP_BREAK' |B |break R(a) |OP_BLKPUSH' |BS |R(a) = block (16=5:1:5:1:4) -|OP_ADD" |BB |R(a) = R(a)+R(a+1) (Syms[b]=:+) -|OP_ADDI" |BBB |R(a) = R(a)+mrb_int(c) (Syms[b]=:+) -|OP_SUB" |BB |R(a) = R(a)-R(a+1) (Syms[b]=:-) -|OP_SUBI" |BB |R(a) = R(a)-C (Syms[b]=:-) -|OP_MUL" |BB |R(a) = R(a)*R(a+1) (Syms[b]=:*) -|OP_DIV" |BB |R(a) = R(a)/R(a+1) (Syms[b]=:/) -|OP_EQ" |BB |R(a) = R(a)==R(a+1) (Syms[b]=:==) -|OP_LT" |BB |R(a) = R(a)R(a+1) (Syms[b]=:>) -|OP_GE" |BB |R(a) = R(a)>=R(a+1) (Syms[b]=:>=) +|OP_ADD" |BB |R(a) = R(a)+R(a+1) +|OP_ADDI" |BBB |R(a) = R(a)+mrb_int(c) +|OP_SUB" |BB |R(a) = R(a)-R(a+1) +|OP_SUBI" |BB |R(a) = R(a)-C +|OP_MUL" |BB |R(a) = R(a)*R(a+1) +|OP_DIV" |BB |R(a) = R(a)/R(a+1) +|OP_EQ" |BB |R(a) = R(a)==R(a+1) +|OP_LT" |BB |R(a) = R(a)R(a+1) +|OP_GE" |BB |R(a) = R(a)>=R(a+1) |OP_ARRAY' |BB |R(a) = ary_new(R(a),R(a+1)..R(a+b)) |OP_ARRAY2" |BB |R(a) = ary_new(R(b),R(b+1)..R(b+c)) |OP_ARYCAT' |B |ary_cat(R(a),R(a+1)) -- cgit v1.2.3 From 486c9d902dfc525f5843dbd3d166e5ccf58e1c81 Mon Sep 17 00:00:00 2001 From: take-cheeze Date: Mon, 29 Oct 2018 19:35:31 +0900 Subject: Fix codedumper --- src/codedump.c | 44 ++++++++++++++++++++++---------------------- 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/src/codedump.c b/src/codedump.c index 30a14f937..7d1950f75 100644 --- a/src/codedump.c +++ b/src/codedump.c @@ -328,38 +328,38 @@ codedump(mrb_state *mrb, mrb_irep *irep) CASE(OP_ALIAS, BB): printf("OP_ALIAS\t:%s\t%s\n", mrb_sym2name(mrb, irep->syms[a]), mrb_sym2name(mrb, irep->syms[b])); break; - CASE(OP_ADD, BB): - printf("OP_ADD\tR%d\t:%s\t\n", a, mrb_sym2name(mrb, irep->syms[b])); + CASE(OP_ADD, B): + printf("OP_ADD\tR%d\t\n", a); break; - CASE(OP_ADDI, BBB): - printf("OP_ADDI\tR%d\t:%s\t%d\n", a, mrb_sym2name(mrb, irep->syms[b]), c); + CASE(OP_ADDI, BB): + printf("OP_ADDI\tR%d\t%d\n", a, b); break; - CASE(OP_SUB, BB): - printf("OP_SUB\tR%d\t:%s\t\n", a, mrb_sym2name(mrb, irep->syms[b])); + CASE(OP_SUB, B): + printf("OP_SUB\tR%d\t\n", a); break; - CASE(OP_SUBI, BBB): - printf("OP_SUBI\tR%d\t:%s\t%d\n", a, mrb_sym2name(mrb, irep->syms[b]), c); + CASE(OP_SUBI, BB): + printf("OP_SUBI\tR%d\t%d\n", a, b); break; - CASE(OP_MUL, BB): - printf("OP_MUL\tR%d\t:%s\t\n", a, mrb_sym2name(mrb, irep->syms[b])); + CASE(OP_MUL, B): + printf("OP_MUL\tR%d\t\n", a); break; - CASE(OP_DIV, BB): - printf("OP_DIV\tR%d\t:%s\t\n", a, mrb_sym2name(mrb, irep->syms[b])); + CASE(OP_DIV, B): + printf("OP_DIV\tR%d\t\n", a); break; - CASE(OP_LT, BB): - printf("OP_LT\t\tR%d\t:%s\t\n", a, mrb_sym2name(mrb, irep->syms[b])); + CASE(OP_LT, B): + printf("OP_LT\t\tR%d\t\n", a); break; - CASE(OP_LE, BB): - printf("OP_LE\t\tR%d\t:%s\t\n", a, mrb_sym2name(mrb, irep->syms[b])); + CASE(OP_LE, B): + printf("OP_LE\t\tR%d\t\n", a); break; - CASE(OP_GT, BB): - printf("OP_GT\t\tR%d\t:%s\t\n", a, mrb_sym2name(mrb, irep->syms[b])); + CASE(OP_GT, B): + printf("OP_GT\t\tR%d\t\n", a); break; - CASE(OP_GE, BB): - printf("OP_GE\t\tR%d\t:%s\t\n", a, mrb_sym2name(mrb, irep->syms[b])); + CASE(OP_GE, B): + printf("OP_GE\t\tR%d\t\n", a); break; - CASE(OP_EQ, BB): - printf("OP_EQ\t\tR%d\t:%s\t\n", a, mrb_sym2name(mrb, irep->syms[b])); + CASE(OP_EQ, B): + printf("OP_EQ\t\tR%d\t\n", a); break; CASE(OP_ARRAY, BB): printf("OP_ARRAY\tR%d\t%d\t", a, b); -- cgit v1.2.3 From 6a6586ca84c6a9a691c9968320eed5e60e824b3c Mon Sep 17 00:00:00 2001 From: take-cheeze Date: Mon, 29 Oct 2018 19:40:33 +0900 Subject: Reduce unnecessary symbol table entry --- include/mruby/symbol.h | 7 +++++++ mrbgems/mruby-compiler/core/codegen.c | 10 +++++++--- 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/include/mruby/symbol.h b/include/mruby/symbol.h index f11346830..b0feccc51 100644 --- a/include/mruby/symbol.h +++ b/include/mruby/symbol.h @@ -16,6 +16,7 @@ MRB_BEGIN_DECL typedef enum mrb_reserved_symbol { mrb_sym_null = 0, // NULL symbol + mrb_sym_add = 1, // + mrb_sym_sub = 2, // - mrb_sym_mul = 3, // * @@ -25,9 +26,15 @@ typedef enum mrb_reserved_symbol { mrb_sym_le = 7, // <= mrb_sym_gt = 8, // > mrb_sym_ge = 9, // >= + mrb_sym_method_missing = 10, // method_missing } mrb_reserved_symbol; +static inline mrb_bool +mrb_symbol_constsym_send_p(mrb_sym sym) { + return mrb_sym_add <= sym && sym <= mrb_sym_ge; +} + MRB_END_DECL #endif /* MRUBY_SYMBOL_H */ diff --git a/mrbgems/mruby-compiler/core/codegen.c b/mrbgems/mruby-compiler/core/codegen.c index 759e7267e..22ac51239 100644 --- a/mrbgems/mruby-compiler/core/codegen.c +++ b/mrbgems/mruby-compiler/core/codegen.c @@ -18,6 +18,7 @@ #include #include #include +#include #ifndef MRB_CODEGEN_LEVEL_MAX #define MRB_CODEGEN_LEVEL_MAX 1024 @@ -982,8 +983,9 @@ gen_call(codegen_scope *s, node *tree, mrb_sym name, int sp, int val, int safe) gen_move(s, cursp(), recv, 1); skip = genjmp2(s, OP_JMPNIL, cursp(), 0, val); } - // TODO: don't new when unused - idx = new_sym(s, sym); + if (!mrb_symbol_constsym_send_p(sym)) { + idx = new_sym(s, sym); + } tree = tree->cdr->cdr->car; if (tree) { n = gen_values(s, tree->car, VAL, sp?1:0); @@ -2024,7 +2026,9 @@ codegen(codegen_scope *s, node *tree, int val) push(); pop(); pop(); pop(); - idx = new_sym(s, sym); + if (!mrb_symbol_constsym_send_p(sym)) { + idx = new_sym(s, sym); + } if (len == 1 && name[0] == '+') { gen_addsub(s, OP_ADD, cursp()); } -- cgit v1.2.3 From 08bd095446052f492d6a5eb6daf240a7ff646b4b Mon Sep 17 00:00:00 2001 From: take-cheeze Date: Mon, 29 Oct 2018 20:10:03 +0900 Subject: Add debug flag to `MRuby::Build` --- lib/mruby/build.rb | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/lib/mruby/build.rb b/lib/mruby/build.rb index 7a0f7a759..e2d9fc41e 100644 --- a/lib/mruby/build.rb +++ b/lib/mruby/build.rb @@ -102,6 +102,10 @@ module MRuby build_mrbtest if test_enabled? end + def debug_enabled? + @enable_debug + end + def enable_debug compilers.each do |c| c.defines += %w(MRB_DEBUG) @@ -110,6 +114,8 @@ module MRuby end end @mrbc.compile_options += ' -g' + + @enable_debug = true end def disable_cxx_exception -- cgit v1.2.3 From cca5e0977ca4ac54d109e68e256e89b041833c7a Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Tue, 30 Oct 2018 09:01:12 +0900 Subject: VS 2017 C does not understand inline struct initialization; ref #4153 --- mrbgems/mruby-string-ext/src/string.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/mrbgems/mruby-string-ext/src/string.c b/mrbgems/mruby-string-ext/src/string.c index 9b317386e..9fd84af7b 100644 --- a/mrbgems/mruby-string-ext/src/string.c +++ b/mrbgems/mruby-string-ext/src/string.c @@ -252,7 +252,7 @@ enum tr_pattern_type { struct tr_pattern { uint8_t type; // 1:in-order, 2:range mrb_bool flag_reverse : 1; - mrb_bool flag_on_stack : 1; + mrb_bool flag_on_heap : 1; uint16_t n; union { uint16_t start_pos; @@ -261,14 +261,14 @@ struct tr_pattern { struct tr_pattern *next; }; -#define STATIC_TR_PATTERN { TR_UNINITIALIZED, FALSE, TRUE, 0, {}, NULL } +#define STATIC_TR_PATTERN { 0 } static inline void tr_free_pattern(mrb_state *mrb, struct tr_pattern *pat) { while (pat) { struct tr_pattern *p = pat->next; - if (!pat->flag_on_stack) { + if (pat->flag_on_heap) { mrb_free(mrb, pat); } pat = p; @@ -304,7 +304,7 @@ tr_parse_pattern(mrb_state *mrb, struct tr_pattern *ret, const mrb_value v_patte } pat1->type = TR_RANGE; pat1->flag_reverse = flag_reverse; - pat1->flag_on_stack = ret_uninit; + pat1->flag_on_heap = !ret_uninit; pat1->n = pattern[i+2] - pattern[i] + 1; pat1->next = NULL; pat1->val.ch[0] = pattern[i]; @@ -328,7 +328,7 @@ tr_parse_pattern(mrb_state *mrb, struct tr_pattern *ret, const mrb_value v_patte } pat1->type = TR_IN_ORDER; pat1->flag_reverse = flag_reverse; - pat1->flag_on_stack = ret_uninit; + pat1->flag_on_heap = !ret_uninit; pat1->n = len; pat1->next = NULL; pat1->val.start_pos = start_pos; -- cgit v1.2.3 From 73727aeb50028830e9c70dcdbdc05b8bbbe6a688 Mon Sep 17 00:00:00 2001 From: Hiroshi Mimaki Date: Thu, 1 Nov 2018 11:10:47 +0900 Subject: Fixed a bug in INIT_DISPATCH for non direct threading; fix #4153 --- src/vm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vm.c b/src/vm.c index 067dd90f7..28b375c68 100644 --- a/src/vm.c +++ b/src/vm.c @@ -935,7 +935,7 @@ argnum_error(mrb_state *mrb, mrb_int num) #ifndef DIRECT_THREADED -#define INIT_DISPATCH for (;;) { insn = BYTECODE_DECODER(*pc); pc++; CODE_FETCH_HOOK(mrb, irep, pc, regs); switch (insn) { +#define INIT_DISPATCH for (;;) { insn = BYTECODE_DECODER(*pc); CODE_FETCH_HOOK(mrb, irep, pc, regs); switch (insn) { #define CASE(insn,ops) case insn: pc++; FETCH_ ## ops ();; L_ ## insn ## _BODY: #define NEXT break #define JUMP NEXT -- cgit v1.2.3 From d68da042b3666c1e46e4d3cf1a14e708df89f440 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Thu, 1 Nov 2018 22:33:15 +0900 Subject: The `env` object referenced from fibers may be freed; fix #4154 By dffa203 that reclaim `env` objects from heaps, there's more chance for `env` objects referenced from fibers may be freed from heap pages. --- src/gc.c | 24 ++++++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/src/gc.c b/src/gc.c index bacc322e8..a52c64bfa 100644 --- a/src/gc.c +++ b/src/gc.c @@ -274,9 +274,29 @@ mrb_free(mrb_state *mrb, void *p) (mrb->allocf)(mrb, p, 0, mrb->allocf_ud); } +static mrb_bool +heap_p(mrb_gc *gc, struct RBasic *object) +{ + mrb_heap_page* page; + + page = gc->heaps; + while (page) { + RVALUE *p; + + p = objects(page); + if (&p[0].as.basic <= object && object <= &p[MRB_HEAP_PAGE_SIZE].as.basic) { + return TRUE; + } + page = page->next; + } + return FALSE; +} + MRB_API mrb_bool mrb_object_dead_p(mrb_state *mrb, struct RBasic *object) { - return is_dead(&mrb->gc, object); + mrb_gc *gc = &mrb->gc; + if (!heap_p(gc, object)) return TRUE; + return is_dead(gc, object); } static void @@ -807,7 +827,7 @@ obj_free(mrb_state *mrb, struct RBasic *obj, int end) while (ce <= ci) { struct REnv *e = ci->env; - if (e && !is_dead(&mrb->gc, e) && + if (e && !mrb_object_dead_p(mrb, (struct RBasic*)e) && e->tt == MRB_TT_ENV && MRB_ENV_STACK_SHARED_P(e)) { mrb_env_unshare(mrb, e); } -- cgit v1.2.3 From 7ad53273a2c5346557a233d040ad233019c03277 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Thu, 1 Nov 2018 22:52:12 +0900 Subject: Silence Appveyor's VC compilation warnings. --- mrbgems/mruby-pack/src/pack.c | 2 +- mrbgems/mruby-sleep/src/mrb_sleep.c | 2 +- mrbgems/mruby-string-ext/src/string.c | 5 +++-- src/vm.c | 2 +- 4 files changed, 6 insertions(+), 5 deletions(-) diff --git a/mrbgems/mruby-pack/src/pack.c b/mrbgems/mruby-pack/src/pack.c index f970d9339..796ba4d34 100644 --- a/mrbgems/mruby-pack/src/pack.c +++ b/mrbgems/mruby-pack/src/pack.c @@ -64,7 +64,7 @@ static int littleendian = 0; const static unsigned char base64chars[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; -static signed char base64_dec_tab[128]; +static unsigned char base64_dec_tab[128]; static int diff --git a/mrbgems/mruby-sleep/src/mrb_sleep.c b/mrbgems/mruby-sleep/src/mrb_sleep.c index ce643cf12..0428f29eb 100644 --- a/mrbgems/mruby-sleep/src/mrb_sleep.c +++ b/mrbgems/mruby-sleep/src/mrb_sleep.c @@ -29,7 +29,7 @@ #ifdef _WIN32 #include #define sleep(x) Sleep(x * 1000) - #define usleep(x) Sleep(((x)<1000) ? 1 : ((x)/1000)) + #define usleep(x) Sleep((DWORD)((x)<1000) ? 1 : ((x)/1000)) #else #include #include diff --git a/mrbgems/mruby-string-ext/src/string.c b/mrbgems/mruby-string-ext/src/string.c index 9fd84af7b..c0105fbd9 100644 --- a/mrbgems/mruby-string-ext/src/string.c +++ b/mrbgems/mruby-string-ext/src/string.c @@ -279,7 +279,7 @@ static struct tr_pattern* tr_parse_pattern(mrb_state *mrb, struct tr_pattern *ret, const mrb_value v_pattern, mrb_bool flag_reverse_enable) { const char *pattern = RSTRING_PTR(v_pattern); - int pattern_length = RSTRING_LEN(v_pattern); + mrb_int pattern_length = RSTRING_LEN(v_pattern); mrb_bool flag_reverse = FALSE; struct tr_pattern *pat1; int i = 0; @@ -438,7 +438,8 @@ str_tr(mrb_state *mrb, mrb_value str, mrb_value p1, mrb_value p2, mrb_bool squee mrb_raisef(mrb, E_ARGUMENT_ERROR, "character (%S) out of range", mrb_fixnum_value((mrb_int)c)); } - lastch = s[i] = c; + lastch = c; + s[i] = (char)c; } } } diff --git a/src/vm.c b/src/vm.c index 28b375c68..8157f6ca0 100644 --- a/src/vm.c +++ b/src/vm.c @@ -186,7 +186,7 @@ stack_extend_alloc(mrb_state *mrb, mrb_int room) if (off > size) size = off; #ifdef MRB_STACK_EXTEND_DOUBLING - if (room <= (size_t)size) + if ((size_t)room <= size) size *= 2; else size += room; -- cgit v1.2.3 From 65b04066a25812fe51e25d028d7cc2ef0b53fbc2 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Fri, 2 Nov 2018 08:54:24 +0900 Subject: Empty pattern string can generate `TR_UNINITIALIZED` pattern; fix #4156 --- mrbgems/mruby-string-ext/src/string.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mrbgems/mruby-string-ext/src/string.c b/mrbgems/mruby-string-ext/src/string.c index c0105fbd9..6f574b9db 100644 --- a/mrbgems/mruby-string-ext/src/string.c +++ b/mrbgems/mruby-string-ext/src/string.c @@ -368,7 +368,7 @@ tr_find_character(const struct tr_pattern *pat, const char *pat_str, int ch) ret = n_sum + ch - pat->val.ch[0]; } else { - mrb_assert(FALSE); // should not reach + mrb_assert(pat->type == TR_UNINITIALIZED); } n_sum += pat->n; pat = pat->next; -- cgit v1.2.3 From 8e596956259353ddf3ff0370028a758d9ce435d8 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Fri, 2 Nov 2018 08:55:17 +0900 Subject: Empty pattern string for `String#tr` should remove characters; fix #4157 --- mrbgems/mruby-string-ext/src/string.c | 24 ++++++++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/mrbgems/mruby-string-ext/src/string.c b/mrbgems/mruby-string-ext/src/string.c index 6f574b9db..460c8509e 100644 --- a/mrbgems/mruby-string-ext/src/string.c +++ b/mrbgems/mruby-string-ext/src/string.c @@ -384,13 +384,29 @@ static inline mrb_int tr_get_character(const struct tr_pattern *pat, const char *pat_str, mrb_int n_th) { mrb_int n_sum = 0; + while (pat != NULL) { if (n_th < (n_sum + pat->n)) { mrb_int i = (n_th - n_sum); - return (pat->type == TR_IN_ORDER) ? pat_str[pat->val.start_pos + i] :pat->val.ch[0] + i; + + switch (pat->type) { + case TR_IN_ORDER: + return pat_str[pat->val.start_pos + i]; + case TR_RANGE: + return pat->val.ch[0]+i; + case TR_UNINITIALIZED: + return -1; + } } if (pat->next == NULL) { - return (pat->type == TR_IN_ORDER) ? pat_str[pat->val.start_pos + pat->n - 1] : pat->val.ch[1]; + switch (pat->type) { + case TR_IN_ORDER: + return pat_str[pat->val.start_pos + pat->n - 1]; + case TR_RANGE: + return pat->val.ch[1]; + case TR_UNINITIALIZED: + return -1; + } } n_sum += pat->n; pat = pat->next; @@ -430,11 +446,11 @@ str_tr(mrb_state *mrb, mrb_value str, mrb_value p1, mrb_value p2, mrb_bool squee else { mrb_int c = tr_get_character(rep, RSTRING_PTR(p2), n); - if (squeeze && c == lastch) { + if (c < 0 || (squeeze && c == lastch)) { j--; continue; } - if (c < 0 || c > 0x80) { + if (c > 0x80) { mrb_raisef(mrb, E_ARGUMENT_ERROR, "character (%S) out of range", mrb_fixnum_value((mrb_int)c)); } -- cgit v1.2.3 From f2084f300ba87ff6e42437a52aebb5e7a6c19355 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Fri, 2 Nov 2018 08:58:21 +0900 Subject: Add tests for empty patterns for `tr` and `count`; #4156 #4157 --- mrbgems/mruby-string-ext/test/string.rb | 2 ++ 1 file changed, 2 insertions(+) diff --git a/mrbgems/mruby-string-ext/test/string.rb b/mrbgems/mruby-string-ext/test/string.rb index 36a253989..f0f8be6b3 100644 --- a/mrbgems/mruby-string-ext/test/string.rb +++ b/mrbgems/mruby-string-ext/test/string.rb @@ -149,6 +149,7 @@ end assert('String#count') do s = "abccdeff123" + assert_equal 0, s.count("") assert_equal 1, s.count("a") assert_equal 2, s.count("ab") assert_equal 9, s.count("^c") @@ -161,6 +162,7 @@ assert('String#tr') do assert_equal "hippo", "hello".tr('el', 'ip') assert_equal "Ruby", "Lisp".tr("Lisp", "Ruby") assert_equal "*e**o", "hello".tr('^aeiou', '*') + assert_equal "heo", "hello".tr('l', '') end assert('String#tr!') do -- cgit v1.2.3 From 0419f07915603f74bbd3f6435ffee42cde5eaa5f Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Fri, 2 Nov 2018 14:57:03 +0900 Subject: Add `NULL` checks for `mrb->ci` and `proc->upeer`; #4024 --- src/proc.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/src/proc.c b/src/proc.c index 05b897480..dcbeb4f62 100644 --- a/src/proc.c +++ b/src/proc.c @@ -63,12 +63,12 @@ closure_setup(mrb_state *mrb, struct RProc *p) { mrb_callinfo *ci = mrb->c->ci; struct RProc *up = p->upper; - struct REnv *e; + struct REnv *e = NULL; - if (ci->env) { + if (ci && ci->env) { e = ci->env; } - else { + else if (up) { struct RClass *tc = MRB_PROC_TARGET_CLASS(p); e = env_new(mrb, up->body.irep->nlocals); @@ -78,9 +78,11 @@ closure_setup(mrb_state *mrb, struct RProc *p) mrb_field_write_barrier(mrb, (struct RBasic*)e, (struct RBasic*)tc); } } - p->e.env = e; - p->flags |= MRB_PROC_ENVSET; - mrb_field_write_barrier(mrb, (struct RBasic*)p, (struct RBasic*)e); + if (e) { + p->e.env = e; + p->flags |= MRB_PROC_ENVSET; + mrb_field_write_barrier(mrb, (struct RBasic*)p, (struct RBasic*)e); + } } struct RProc* -- cgit v1.2.3 From 659c680a5bbc04c736544741e2e16c27a3a3f374 Mon Sep 17 00:00:00 2001 From: take-cheeze Date: Fri, 2 Nov 2018 15:34:35 +0900 Subject: Fix dump and load with endianess --- src/dump.c | 22 ++-------------------- src/load.c | 21 ++++----------------- 2 files changed, 6 insertions(+), 37 deletions(-) diff --git a/src/dump.c b/src/dump.c index df1e171e4..0b1344594 100644 --- a/src/dump.c +++ b/src/dump.c @@ -85,26 +85,8 @@ write_iseq_block(mrb_state *mrb, mrb_irep *irep, uint8_t *buf, uint8_t flags) cur += uint32_to_bin(irep->ilen, cur); /* number of opcode */ cur += write_padding(cur); - switch (flags & DUMP_ENDIAN_NAT) { - case DUMP_ENDIAN_BIG: - if (bigendian_p()) goto native; - for (iseq_no = 0; iseq_no < irep->ilen; iseq_no++) { - cur += uint32_to_bin(irep->iseq[iseq_no], cur); /* opcode */ - } - break; - case DUMP_ENDIAN_LIL: - if (!bigendian_p()) goto native; - for (iseq_no = 0; iseq_no < irep->ilen; iseq_no++) { - cur += uint32l_to_bin(irep->iseq[iseq_no], cur); /* opcode */ - } - break; - - native: - case DUMP_ENDIAN_NAT: - memcpy(cur, irep->iseq, irep->ilen * sizeof(mrb_code)); - cur += irep->ilen * sizeof(mrb_code); - break; - } + memcpy(cur, irep->iseq, irep->ilen * sizeof(mrb_code)); + cur += irep->ilen * sizeof(mrb_code); return cur - buf; } diff --git a/src/load.c b/src/load.c index 54b50b14d..70f5406eb 100644 --- a/src/load.c +++ b/src/load.c @@ -83,23 +83,10 @@ read_irep_record_1(mrb_state *mrb, const uint8_t *bin, size_t *len, uint8_t flag irep->flags |= MRB_ISEQ_NO_FREE; } else { - irep->iseq = (mrb_code *)mrb_malloc(mrb, sizeof(mrb_code) * irep->ilen); - if (flags & FLAG_BYTEORDER_NATIVE) { - memcpy(irep->iseq, src, sizeof(uint32_t) * irep->ilen); - src += sizeof(uint32_t) * irep->ilen; - } - else if (flags & FLAG_BYTEORDER_BIG) { - for (i = 0; i < irep->ilen; i++) { - irep->iseq[i] = (mrb_code)bin_to_uint32(src); /* iseq */ - src += sizeof(uint32_t); - } - } - else { - for (i = 0; i < irep->ilen; i++) { - irep->iseq[i] = (mrb_code)bin_to_uint32l(src); /* iseq */ - src += sizeof(uint32_t); - } - } + size_t data_len = sizeof(mrb_code) * irep->ilen; + irep->iseq = (mrb_code *)mrb_malloc(mrb, data_len); + memcpy(irep->iseq, src, data_len); + src += data_len; } } -- cgit v1.2.3 From 57a435aa1d26c7d64c9d38c6865255a98e32d4cb Mon Sep 17 00:00:00 2001 From: take-cheeze Date: Fri, 2 Nov 2018 15:49:34 +0900 Subject: Suppress warning --- src/dump.c | 1 - 1 file changed, 1 deletion(-) diff --git a/src/dump.c b/src/dump.c index 0b1344594..c2c334c9a 100644 --- a/src/dump.c +++ b/src/dump.c @@ -81,7 +81,6 @@ static ptrdiff_t write_iseq_block(mrb_state *mrb, mrb_irep *irep, uint8_t *buf, uint8_t flags) { uint8_t *cur = buf; - int iseq_no; cur += uint32_to_bin(irep->ilen, cur); /* number of opcode */ cur += write_padding(cur); -- cgit v1.2.3 From d9e253255218b04fd54a55980c4d8b6d61b1697c Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Fri, 2 Nov 2018 22:58:12 +0900 Subject: Remove reserved symbols for now. It should be done by planned embedded symbols. --- include/mruby/symbol.h | 40 -------------------------- mrbgems/mruby-compiler/core/codegen.c | 12 +++----- src/symbol.c | 26 ----------------- src/vm.c | 53 +++++++++++++++++------------------ 4 files changed, 30 insertions(+), 101 deletions(-) delete mode 100644 include/mruby/symbol.h diff --git a/include/mruby/symbol.h b/include/mruby/symbol.h deleted file mode 100644 index b0feccc51..000000000 --- a/include/mruby/symbol.h +++ /dev/null @@ -1,40 +0,0 @@ -/* -** mruby/symbol.h - symbol utilities -** -** See Copyright Notice in mruby.h -*/ - -#ifndef MRUBY_SYMBOL_H -#define MRUBY_SYMBOL_H - -#include "common.h" - -/** - * Symbol utilities - */ -MRB_BEGIN_DECL - -typedef enum mrb_reserved_symbol { - mrb_sym_null = 0, // NULL symbol - - mrb_sym_add = 1, // + - mrb_sym_sub = 2, // - - mrb_sym_mul = 3, // * - mrb_sym_div = 4, // / - mrb_sym_eq = 5, // == - mrb_sym_lt = 6, // < - mrb_sym_le = 7, // <= - mrb_sym_gt = 8, // > - mrb_sym_ge = 9, // >= - - mrb_sym_method_missing = 10, // method_missing -} mrb_reserved_symbol; - -static inline mrb_bool -mrb_symbol_constsym_send_p(mrb_sym sym) { - return mrb_sym_add <= sym && sym <= mrb_sym_ge; -} - -MRB_END_DECL - -#endif /* MRUBY_SYMBOL_H */ diff --git a/mrbgems/mruby-compiler/core/codegen.c b/mrbgems/mruby-compiler/core/codegen.c index 22ac51239..22ad3253b 100644 --- a/mrbgems/mruby-compiler/core/codegen.c +++ b/mrbgems/mruby-compiler/core/codegen.c @@ -18,7 +18,6 @@ #include #include #include -#include #ifndef MRB_CODEGEN_LEVEL_MAX #define MRB_CODEGEN_LEVEL_MAX 1024 @@ -974,7 +973,7 @@ static void gen_call(codegen_scope *s, node *tree, mrb_sym name, int sp, int val, int safe) { mrb_sym sym = name ? name : nsym(tree->cdr->car); - int idx, skip = 0; + int skip = 0; int n = 0, noop = 0, sendv = 0, blk = 0; codegen(s, tree->car, VAL); /* receiver */ @@ -983,9 +982,6 @@ gen_call(codegen_scope *s, node *tree, mrb_sym name, int sp, int val, int safe) gen_move(s, cursp(), recv, 1); skip = genjmp2(s, OP_JMPNIL, cursp(), 0, val); } - if (!mrb_symbol_constsym_send_p(sym)) { - idx = new_sym(s, sym); - } tree = tree->cdr->cdr->car; if (tree) { n = gen_values(s, tree->car, VAL, sp?1:0); @@ -1047,6 +1043,8 @@ gen_call(codegen_scope *s, node *tree, mrb_sym name, int sp, int val, int safe) genop_1(s, OP_EQ, cursp()); } else { + int idx = new_sym(s, sym); + if (sendv) { genop_2(s, blk ? OP_SENDVB : OP_SENDV, cursp(), idx); } @@ -2026,9 +2024,6 @@ codegen(codegen_scope *s, node *tree, int val) push(); pop(); pop(); pop(); - if (!mrb_symbol_constsym_send_p(sym)) { - idx = new_sym(s, sym); - } if (len == 1 && name[0] == '+') { gen_addsub(s, OP_ADD, cursp()); } @@ -2054,6 +2049,7 @@ codegen(codegen_scope *s, node *tree, int val) genop_1(s, OP_GE, cursp()); } else { + idx = new_sym(s, sym); genop_3(s, OP_SEND, cursp(), idx, 1); } if (callargs < 0) { diff --git a/src/symbol.c b/src/symbol.c index 8ec300e20..6b4c7200c 100644 --- a/src/symbol.c +++ b/src/symbol.c @@ -11,7 +11,6 @@ #include #include #include -#include /* ------------------------------------------------------ */ typedef struct symbol_name { @@ -171,35 +170,10 @@ mrb_free_symtbl(mrb_state *mrb) kh_destroy(n2s, mrb, mrb->name2sym); } -struct reserved_symbol_t { - mrb_reserved_symbol sym; - char const *str; -}; - -static struct reserved_symbol_t reserved_symbols[] = { - { mrb_sym_add, "+" }, - { mrb_sym_sub, "-" }, - { mrb_sym_mul, "*" }, - { mrb_sym_div, "/" }, - { mrb_sym_eq, "==" }, - { mrb_sym_lt, "<" }, - { mrb_sym_le, "<=" }, - { mrb_sym_gt, ">" }, - { mrb_sym_ge, ">=" }, - { mrb_sym_method_missing, "method_missing" }, - { mrb_sym_null, NULL }, -}; - void mrb_init_symtbl(mrb_state *mrb) { - int i; mrb->name2sym = kh_init(n2s, mrb); - - for (i = 0; reserved_symbols[i].sym != mrb_sym_null; ++i) { - mrb_sym s = mrb_intern_static(mrb, reserved_symbols[i].str, strlen(reserved_symbols[i].str)); - mrb_assert(s == reserved_symbols[i].sym); - } } /********************************************************************** diff --git a/src/vm.c b/src/vm.c index 627eb9325..9844d3e60 100644 --- a/src/vm.c +++ b/src/vm.c @@ -21,7 +21,6 @@ #include #include "value_array.h" #include -#include #ifdef MRB_DISABLE_STDIO #if defined(__cplusplus) @@ -1388,18 +1387,18 @@ RETRY_TRY_BLOCK: SET_NIL_VALUE(regs[bidx]); goto L_SENDB; }; - L_SEND_CONSTSYM: + L_SEND_SYM: { /* push nil after arguments */ int bidx = (c == CALL_MAXARGS) ? a+2 : a+c+1; SET_NIL_VALUE(regs[bidx]); - goto L_SENDB_CONSTSYM; + goto L_SENDB_SYM; }; CASE(OP_SENDB, BBB) L_SENDB: mid = syms[b]; - L_SENDB_CONSTSYM: + L_SENDB_SYM: { int argc = (c == CALL_MAXARGS) ? -1 : c; int bidx = (argc < 0) ? a+2 : a+c+1; @@ -2269,8 +2268,8 @@ RETRY_TRY_BLOCK: break; default: c = 1; - mid = mrb_sym_add; - goto L_SEND_CONSTSYM; + mid = mrb_intern_lit(mrb, "+"); + goto L_SEND_SYM; } mrb_gc_arena_restore(mrb, ai); NEXT; @@ -2327,8 +2326,8 @@ RETRY_TRY_BLOCK: #endif default: c = 1; - mid = mrb_sym_sub; - goto L_SEND_CONSTSYM; + mid = mrb_intern_lit(mrb, "-"); + goto L_SEND_SYM; } NEXT; } @@ -2384,8 +2383,8 @@ RETRY_TRY_BLOCK: #endif default: c = 1; - mid = mrb_sym_mul; - goto L_SEND_CONSTSYM; + mid = mrb_intern_lit(mrb, "*"); + goto L_SEND_SYM; } NEXT; } @@ -2424,8 +2423,8 @@ RETRY_TRY_BLOCK: #endif default: c = 1; - mid = mrb_sym_div; - goto L_SEND_CONSTSYM; + mid = mrb_intern_lit(mrb, "/"); + goto L_SEND_SYM; } #ifndef MRB_WITHOUT_FLOAT @@ -2475,8 +2474,8 @@ RETRY_TRY_BLOCK: default: SET_INT_VALUE(regs[a+1], b); c = 1; - mid = mrb_sym_add; - goto L_SEND_CONSTSYM; + mid = mrb_intern_lit(mrb, "+"); + goto L_SEND_SYM; } NEXT; } @@ -2516,8 +2515,8 @@ RETRY_TRY_BLOCK: default: SET_INT_VALUE(regs_a[1], b); c = 1; - mid = mrb_sym_sub; - goto L_SEND_CONSTSYM; + mid = mrb_intern_lit(mrb, "-"); + goto L_SEND_SYM; } NEXT; } @@ -2525,7 +2524,7 @@ RETRY_TRY_BLOCK: #define OP_CMP_BODY(op,v1,v2) (v1(regs[a]) op v2(regs[a+1])) #ifdef MRB_WITHOUT_FLOAT -#define OP_CMP(op, sym) do {\ +#define OP_CMP(op) do {\ int result;\ /* need to check if - is overridden */\ switch (TYPES2(mrb_type(regs[a]),mrb_type(regs[a+1]))) {\ @@ -2534,8 +2533,8 @@ RETRY_TRY_BLOCK: break;\ default:\ c = 1;\ - mid = mrb_sym_ ## sym;\ - goto L_SEND_CONSTSYM;\ + mid = mrb_intern_lit(mrb, # op);\ + goto L_SEND_SYM;\ }\ if (result) {\ SET_TRUE_VALUE(regs[a]);\ @@ -2545,7 +2544,7 @@ RETRY_TRY_BLOCK: }\ } while(0) #else -#define OP_CMP(op, sym) do {\ +#define OP_CMP(op) do {\ int result;\ /* need to check if - is overridden */\ switch (TYPES2(mrb_type(regs[a]),mrb_type(regs[a+1]))) {\ @@ -2563,8 +2562,8 @@ RETRY_TRY_BLOCK: break;\ default:\ c = 1;\ - mid = mrb_sym_ ## sym;\ - goto L_SEND_CONSTSYM;\ + mid = mrb_intern_lit(mrb, # op);\ + goto L_SEND_SYM;\ }\ if (result) {\ SET_TRUE_VALUE(regs[a]);\ @@ -2580,28 +2579,28 @@ RETRY_TRY_BLOCK: SET_TRUE_VALUE(regs[a]); } else { - OP_CMP(==, eq); + OP_CMP(==); } NEXT; } CASE(OP_LT, B) { - OP_CMP(<, lt); + OP_CMP(<); NEXT; } CASE(OP_LE, B) { - OP_CMP(<=, le); + OP_CMP(<=); NEXT; } CASE(OP_GT, B) { - OP_CMP(>, gt); + OP_CMP(>); NEXT; } CASE(OP_GE, B) { - OP_CMP(>=, ge); + OP_CMP(>=); NEXT; } -- cgit v1.2.3 From d47003aea406e1e48ef79efd61b17d5121c4c6b9 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Mon, 5 Nov 2018 07:44:25 +0900 Subject: Fixed a bug in argument number check with kwargs; fix #4159 --- src/vm.c | 11 ++++------- test/t/syntax.rb | 4 ++++ 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/src/vm.c b/src/vm.c index 9844d3e60..19288245c 100644 --- a/src/vm.c +++ b/src/vm.c @@ -1780,11 +1780,9 @@ RETRY_TRY_BLOCK: /* strict argument check */ if (mrb->c->ci->proc && MRB_PROC_STRICT_P(mrb->c->ci->proc)) { - if (argc >= 0 && !(argc <= 1 && kd)) { - if (argc < m1 + m2 + kd || (r == 0 && argc > len + kd)) { - argnum_error(mrb, m1+m2); - goto L_RAISE; - } + if (argc < m1 + m2 || (r == 0 && argc > len + kd)) { + argnum_error(mrb, m1+m2); + goto L_RAISE; } } /* extract first argument array to arguments */ @@ -1810,8 +1808,7 @@ RETRY_TRY_BLOCK: kargs = 0; } else { - mrb_value str = mrb_str_new_lit(mrb, "Excepcted `Hash` as last argument for keyword arguments"); - mrb_exc_set(mrb, mrb_exc_new_str(mrb, E_ARGUMENT_ERROR, str)); + argnum_error(mrb, m1+m2); goto L_RAISE; } if (MRB_ASPEC_KEY(a) > 0) { diff --git a/test/t/syntax.rb b/test/t/syntax.rb index 883cbd1ba..603547c7c 100644 --- a/test/t/syntax.rb +++ b/test/t/syntax.rb @@ -471,6 +471,10 @@ this is a comment that has extra after =begin and =end with tabs after it end assert 'keyword arguments' do + def m(a, b:1) [a, b] end + assert_equal [1, 1], m(1) + assert_equal [1, 2], m(1, b: 2) + def m(a, b:) [a, b] end assert_equal [1, 2], m(1, b: 2) assert_raise(ArgumentError) { m b: 1 } -- cgit v1.2.3 From d25ebec988f61f60d181f38dad9057243034eb10 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Mon, 5 Nov 2018 21:52:17 +0900 Subject: Fixed wrong `ArgumentError` with keyword arguments; fix #4159 --- src/vm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vm.c b/src/vm.c index 19288245c..5779791bc 100644 --- a/src/vm.c +++ b/src/vm.c @@ -1803,7 +1803,7 @@ RETRY_TRY_BLOCK: kdict = argv[argc-1]; mrb_hash_check_kdict(mrb, kdict); } - else if (r) { + else if (r || argc <= m1+m2+o) { kdict = mrb_hash_new(mrb); kargs = 0; } -- cgit v1.2.3 From 7d7f9feee7302ffabb04fa6ea9fb4e46db5682a2 Mon Sep 17 00:00:00 2001 From: Hiroshi Mimaki Date: Wed, 7 Nov 2018 17:20:18 +0900 Subject: Wrong pool data length for negative floating value in a mrb file. --- src/fmt_fp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/fmt_fp.c b/src/fmt_fp.c index 783cc6c02..7028d3aac 100644 --- a/src/fmt_fp.c +++ b/src/fmt_fp.c @@ -379,7 +379,7 @@ mrb_float_to_str(mrb_state *mrb, mrb_value flo, const char *fmt) mrb_value mrb_float_to_str(mrb_state *mrb, mrb_value flo, const char *fmt) { - char buf[24]; + char buf[25]; snprintf(buf, sizeof(buf), fmt, mrb_float(flo)); return mrb_str_new_cstr(mrb, buf); -- cgit v1.2.3 From 4550f4e38153c623537e6df53a4fe7c1c063adc0 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Thu, 15 Nov 2018 02:03:54 +0900 Subject: Pattern length may overflow `uint16_t`; fixed #4163 The issue is reported by `https://hackerone.com/dgaletic`. --- mrbgems/mruby-string-ext/src/string.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/mrbgems/mruby-string-ext/src/string.c b/mrbgems/mruby-string-ext/src/string.c index 460c8509e..cfc194906 100644 --- a/mrbgems/mruby-string-ext/src/string.c +++ b/mrbgems/mruby-string-ext/src/string.c @@ -282,7 +282,7 @@ tr_parse_pattern(mrb_state *mrb, struct tr_pattern *ret, const mrb_value v_patte mrb_int pattern_length = RSTRING_LEN(v_pattern); mrb_bool flag_reverse = FALSE; struct tr_pattern *pat1; - int i = 0; + mrb_int i = 0; if(flag_reverse_enable && pattern_length >= 2 && pattern[0] == '^') { flag_reverse = TRUE; @@ -313,8 +313,8 @@ tr_parse_pattern(mrb_state *mrb, struct tr_pattern *ret, const mrb_value v_patte } else { /* in order pattern. */ - int start_pos = i++; - int len; + mrb_int start_pos = i++; + mrb_int len; while (i < pattern_length) { if ((i+2) < pattern_length && pattern[i] != '\\' && pattern[i+1] == '-') @@ -323,6 +323,9 @@ tr_parse_pattern(mrb_state *mrb, struct tr_pattern *ret, const mrb_value v_patte } len = i - start_pos; + if (len > UINT16_MAX) { + mrb_raise(mrb, E_ARGUMENT_ERROR, "tr pattern too long (max 65536)"); + } if (pat1 == NULL && ret) { goto nomem; } -- cgit v1.2.3 From 485955eccc4993df89bdd227cdf9b0e2f6c95c9c Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Thu, 15 Nov 2018 04:44:27 +0900 Subject: `String#{squeeze,delete,count}` to use bitmap for matching; ref #4163 --- mrbgems/mruby-string-ext/src/string.c | 79 +++++++++++++++++++++++++++++------ 1 file changed, 67 insertions(+), 12 deletions(-) diff --git a/mrbgems/mruby-string-ext/src/string.c b/mrbgems/mruby-string-ext/src/string.c index cfc194906..6d661c352 100644 --- a/mrbgems/mruby-string-ext/src/string.c +++ b/mrbgems/mruby-string-ext/src/string.c @@ -418,6 +418,59 @@ tr_get_character(const struct tr_pattern *pat, const char *pat_str, mrb_int n_th return -1; } +static inline void +tr_bitmap_set(uint8_t bitmap[32], uint8_t ch) +{ + uint8_t idx1 = ch / 8; + uint8_t idx2 = ch % 8; + bitmap[idx1] |= (1<flag_reverse : 0; + int i; + + for (i=0; i<32; i++) { + bitmap[i] = 0; + } + while (pat != NULL) { + if (pat->type == TR_IN_ORDER) { + for (i = 0; i < pat->n; i++) { + tr_bitmap_set(bitmap, pattern[pat->val.start_pos + i]); + } + } + else if (pat->type == TR_RANGE) { + for (i = pat->val.ch[0]; i < pat->val.ch[1]; i++) { + tr_bitmap_set(bitmap, i); + } + } + else { + mrb_assert(pat->type == TR_UNINITIALIZED); + } + pat = pat->next; + } + + if (flag_reverse) { + for (i=0; i<32; i++) { + bitmap[i] ^= 0xff; + } + } +} + static mrb_bool str_tr(mrb_state *mrb, mrb_value str, mrb_value p1, mrb_value p2, mrb_bool squeeze) { @@ -593,20 +646,21 @@ str_squeeze(mrb_state *mrb, mrb_value str, mrb_value v_pat) mrb_int len; mrb_bool flag_changed = FALSE; mrb_int lastch = -1; + uint8_t bitmap[32]; mrb_str_modify(mrb, mrb_str_ptr(str)); if (!mrb_nil_p(v_pat)) { pat = tr_parse_pattern(mrb, &pat_storage, v_pat, TRUE); + tr_compile_pattern(pat, v_pat, bitmap); + tr_free_pattern(mrb, pat); } s = RSTRING_PTR(str); len = RSTRING_LEN(str); if (pat) { for (i=j=0; ij) s[j] = s[i]; - if (n >= 0 && s[i] == lastch) { + if (tr_bitmap_detect(bitmap, s[i]) && s[i] == lastch) { flag_changed = TRUE; j--; } @@ -623,7 +677,6 @@ str_squeeze(mrb_state *mrb, mrb_value str, mrb_value v_pat) lastch = s[i]; } } - tr_free_pattern(mrb, pat); if (flag_changed) { RSTR_SET_LEN(RSTRING(str), j); @@ -685,22 +738,23 @@ str_delete(mrb_state *mrb, mrb_value str, mrb_value v_pat) char *s; mrb_int len; mrb_bool flag_changed = FALSE; + uint8_t bitmap[32]; mrb_str_modify(mrb, mrb_str_ptr(str)); tr_parse_pattern(mrb, &pat, v_pat, TRUE); + tr_compile_pattern(&pat, v_pat, bitmap); + tr_free_pattern(mrb, &pat); + s = RSTRING_PTR(str); len = RSTRING_LEN(str); for (i=j=0; ij) s[j] = s[i]; - if (n >= 0) { + if (tr_bitmap_detect(bitmap, s[i])) { flag_changed = TRUE; j--; } } - tr_free_pattern(mrb, &pat); if (flag_changed) { RSTR_SET_LEN(RSTRING(str), j); RSTRING_PTR(str)[j] = 0; @@ -752,17 +806,18 @@ mrb_str_count(mrb_state *mrb, mrb_value str) mrb_int len; mrb_int count = 0; struct tr_pattern pat = STATIC_TR_PATTERN; + uint8_t bitmap[32]; mrb_get_args(mrb, "S", &v_pat); tr_parse_pattern(mrb, &pat, v_pat, TRUE); + tr_compile_pattern(&pat, v_pat, bitmap); + tr_free_pattern(mrb, &pat); + s = RSTRING_PTR(str); len = RSTRING_LEN(str); for (i = 0; i < len; i++) { - mrb_int n = tr_find_character(&pat, RSTRING_PTR(v_pat), s[i]); - - if (n >= 0) count++; + if (tr_bitmap_detect(bitmap, s[i])) count++; } - tr_free_pattern(mrb, &pat); return mrb_fixnum_value(count); } -- cgit v1.2.3 From 1bea1e2050ee4c1b3e558a307c7d2731f6b52823 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Thu, 15 Nov 2018 19:24:45 +0900 Subject: Small renaming refactor in `dump.c` --- src/dump.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/dump.c b/src/dump.c index c2c334c9a..e41dd83ed 100644 --- a/src/dump.c +++ b/src/dump.c @@ -838,26 +838,26 @@ write_rite_binary_header(mrb_state *mrb, size_t binary_size, uint8_t *bin, uint8 } static mrb_bool -is_debug_info_defined(mrb_irep *irep) +debug_info_defined_p(mrb_irep *irep) { int i; if (!irep->debug_info) return FALSE; for (i=0; irlen; i++) { - if (!is_debug_info_defined(irep->reps[i])) return FALSE; + if (!debug_info_defined_p(irep->reps[i])) return FALSE; } return TRUE; } static mrb_bool -is_lv_defined(mrb_irep *irep) +lv_defined_p(mrb_irep *irep) { int i; if (irep->lv) { return TRUE; } for (i = 0; i < irep->rlen; ++i) { - if (is_lv_defined(irep->reps[i])) { return TRUE; } + if (lv_defined_p(irep->reps[i])) { return TRUE; } } return FALSE; @@ -886,7 +886,7 @@ dump_irep(mrb_state *mrb, mrb_irep *irep, uint8_t flags, uint8_t **bin, size_t * size_t section_irep_size; size_t section_lineno_size = 0, section_lv_size = 0; uint8_t *cur = NULL; - mrb_bool const debug_info_defined = is_debug_info_defined(irep), lv_defined = is_lv_defined(irep); + mrb_bool const debug_info_defined = debug_info_defined_p(irep), lv_defined = lv_defined_p(irep); mrb_sym *lv_syms = NULL; uint32_t lv_syms_len = 0; mrb_sym *filenames = NULL; uint16_t filenames_len = 0; -- cgit v1.2.3 From 61f49690e43cea3df6ebbdf424cf6777826056b0 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Thu, 15 Nov 2018 20:15:10 +0900 Subject: Remove `filename`&`lines` from `mrb_irep` struct. This patch slightly reduce memory consumption (2% for my test). --- include/mruby/debug.h | 5 +- include/mruby/irep.h | 3 - mrbgems/mruby-compiler/core/codegen.c | 38 +++-------- src/debug.c | 32 ++++----- src/dump.c | 125 +--------------------------------- src/load.c | 10 +-- src/state.c | 5 -- 7 files changed, 30 insertions(+), 188 deletions(-) diff --git a/include/mruby/debug.h b/include/mruby/debug.h index d1de34882..f0a40dfcf 100644 --- a/include/mruby/debug.h +++ b/include/mruby/debug.h @@ -55,10 +55,11 @@ MRB_API const char *mrb_debug_get_filename(mrb_irep *irep, ptrdiff_t pc); */ MRB_API int32_t mrb_debug_get_line(mrb_irep *irep, ptrdiff_t pc); +MRB_API mrb_irep_debug_info *mrb_debug_info_alloc(mrb_state *mrb, mrb_irep *irep); MRB_API mrb_irep_debug_info_file *mrb_debug_info_append_file( - mrb_state *mrb, mrb_irep *irep, + mrb_state *mrb, mrb_irep_debug_info *info, + const char *filename, uint16_t *lines, uint32_t start_pos, uint32_t end_pos); -MRB_API mrb_irep_debug_info *mrb_debug_info_alloc(mrb_state *mrb, mrb_irep *irep); MRB_API void mrb_debug_info_free(mrb_state *mrb, mrb_irep_debug_info *d); MRB_END_DECL diff --git a/include/mruby/irep.h b/include/mruby/irep.h index 76bafb25c..78cbc2b74 100644 --- a/include/mruby/irep.h +++ b/include/mruby/irep.h @@ -39,9 +39,6 @@ typedef struct mrb_irep { struct mrb_locals *lv; /* debug info */ - mrb_bool own_filename; - const char *filename; - uint16_t *lines; struct mrb_irep_debug_info* debug_info; uint16_t ilen, plen, slen, rlen; diff --git a/mrbgems/mruby-compiler/core/codegen.c b/mrbgems/mruby-compiler/core/codegen.c index 22ad3253b..dbd3b8ecf 100644 --- a/mrbgems/mruby-compiler/core/codegen.c +++ b/mrbgems/mruby-compiler/core/codegen.c @@ -124,15 +124,6 @@ codegen_palloc(codegen_scope *s, size_t len) return p; } -static void* -codegen_malloc(codegen_scope *s, size_t len) -{ - void *p = mrb_malloc_simple(s->mrb, len); - - if (!p) codegen_error(s, "mrb_malloc"); - return p; -} - static void* codegen_realloc(codegen_scope *s, void *p, size_t len) { @@ -162,7 +153,6 @@ emit_B(codegen_scope *s, uint32_t pc, uint8_t i) s->iseq = (mrb_code *)codegen_realloc(s, s->iseq, sizeof(mrb_code)*s->icapa); if (s->lines) { s->lines = (uint16_t*)codegen_realloc(s, s->lines, sizeof(uint16_t)*s->icapa); - s->irep->lines = s->lines; } } if (s->lines) { @@ -1371,8 +1361,10 @@ codegen(codegen_scope *s, node *tree, int val) codegen_error(s, "too complex expression"); } if (s->irep && s->filename_index != tree->filename_index) { - s->irep->filename = mrb_parser_get_filename(s->parser, s->filename_index); - mrb_debug_info_append_file(s->mrb, s->irep, s->debug_start_pos, s->pc); + const char *filename = mrb_parser_get_filename(s->parser, s->filename_index); + + mrb_debug_info_append_file(s->mrb, s->irep->debug_info, + filename, s->lines, s->debug_start_pos, s->pc); s->debug_start_pos = s->pc; s->filename_index = tree->filename_index; s->filename = mrb_parser_get_filename(s->parser, tree->filename_index); @@ -2965,8 +2957,6 @@ scope_new(mrb_state *mrb, codegen_scope *prev, node *lv) p->debug_start_pos = 0; if (p->filename) { mrb_debug_info_alloc(mrb, p->irep); - p->irep->filename = p->filename; - p->irep->lines = p->lines; } else { p->irep->debug_info = NULL; @@ -2984,34 +2974,22 @@ scope_finish(codegen_scope *s) { mrb_state *mrb = s->mrb; mrb_irep *irep = s->irep; - size_t fname_len; - char *fname; irep->flags = 0; if (s->iseq) { irep->iseq = (mrb_code *)codegen_realloc(s, s->iseq, sizeof(mrb_code)*s->pc); irep->ilen = s->pc; - if (s->lines) { - irep->lines = (uint16_t *)codegen_realloc(s, s->lines, sizeof(uint16_t)*s->pc); - } - else { - irep->lines = 0; - } } irep->pool = (mrb_value*)codegen_realloc(s, irep->pool, sizeof(mrb_value)*irep->plen); irep->syms = (mrb_sym*)codegen_realloc(s, irep->syms, sizeof(mrb_sym)*irep->slen); irep->reps = (mrb_irep**)codegen_realloc(s, irep->reps, sizeof(mrb_irep*)*irep->rlen); if (s->filename) { - irep->filename = mrb_parser_get_filename(s->parser, s->filename_index); - mrb_debug_info_append_file(mrb, irep, s->debug_start_pos, s->pc); + const char *filename = mrb_parser_get_filename(s->parser, s->filename_index); - fname_len = strlen(s->filename); - fname = (char*)codegen_malloc(s, fname_len + 1); - memcpy(fname, s->filename, fname_len); - fname[fname_len] = '\0'; - irep->filename = fname; - irep->own_filename = TRUE; + mrb_debug_info_append_file(s->mrb, s->irep->debug_info, + filename, s->lines, s->debug_start_pos, s->pc); } + mrb_free(s->mrb, s->lines); irep->nlocals = s->nlocals; irep->nregs = s->nregs; diff --git a/src/debug.c b/src/debug.c index e55f11d4f..207065d9e 100644 --- a/src/debug.c +++ b/src/debug.c @@ -55,7 +55,7 @@ mrb_debug_get_filename(mrb_irep *irep, ptrdiff_t pc) { if (irep && pc >= 0 && pc < irep->ilen) { mrb_irep_debug_info_file* f = NULL; - if (!irep->debug_info) { return irep->filename; } + if (!irep->debug_info) return NULL; else if ((f = get_file(irep->debug_info, (uint32_t)pc))) { return f->filename; } @@ -69,7 +69,7 @@ mrb_debug_get_line(mrb_irep *irep, ptrdiff_t pc) if (irep && pc >= 0 && pc < irep->ilen) { mrb_irep_debug_info_file* f = NULL; if (!irep->debug_info) { - return irep->lines? irep->lines[pc] : -1; + return -1; } else if ((f = get_file(irep->debug_info, (uint32_t)pc))) { switch (f->line_type) { @@ -122,24 +122,22 @@ mrb_debug_info_alloc(mrb_state *mrb, mrb_irep *irep) } MRB_API mrb_irep_debug_info_file* -mrb_debug_info_append_file(mrb_state *mrb, mrb_irep *irep, +mrb_debug_info_append_file(mrb_state *mrb, mrb_irep_debug_info *info, + const char *filename, uint16_t *lines, uint32_t start_pos, uint32_t end_pos) { - mrb_irep_debug_info *info; mrb_irep_debug_info_file *ret; uint32_t file_pc_count; size_t fn_len; mrb_int len; uint32_t i; - if (!irep->debug_info) { return NULL; } + if (!info) { return NULL; } - mrb_assert(irep->filename); - mrb_assert(irep->lines); + mrb_assert(filename); + mrb_assert(lines); - info = irep->debug_info; - - if (info->flen > 0 && strcmp(irep->filename, info->files[info->flen - 1]->filename) == 0) { + if (info->flen > 0 && strcmp(filename, info->files[info->flen - 1]->filename) == 0) { return NULL; } @@ -156,12 +154,12 @@ mrb_debug_info_append_file(mrb_state *mrb, mrb_irep *irep, ret->start_pos = start_pos; info->pc_count = end_pos; - fn_len = strlen(irep->filename); - ret->filename_sym = mrb_intern(mrb, irep->filename, fn_len); + fn_len = strlen(filename); + ret->filename_sym = mrb_intern(mrb, filename, fn_len); len = 0; ret->filename = mrb_sym2name_len(mrb, ret->filename_sym, &len); - ret->line_type = select_line_type(irep->lines + start_pos, end_pos - start_pos); + ret->line_type = select_line_type(lines + start_pos, end_pos - start_pos); ret->lines.ptr = NULL; switch (ret->line_type) { @@ -169,7 +167,7 @@ mrb_debug_info_append_file(mrb_state *mrb, mrb_irep *irep, ret->line_entry_count = file_pc_count; ret->lines.ary = (uint16_t*)mrb_malloc(mrb, sizeof(uint16_t) * file_pc_count); for (i = 0; i < file_pc_count; ++i) { - ret->lines.ary[i] = irep->lines[start_pos + i]; + ret->lines.ary[i] = lines[start_pos + i]; } break; @@ -179,18 +177,18 @@ mrb_debug_info_append_file(mrb_state *mrb, mrb_irep *irep, ret->lines.flat_map = (mrb_irep_debug_info_line*)mrb_malloc(mrb, sizeof(mrb_irep_debug_info_line) * 1); ret->line_entry_count = 0; for (i = 0; i < file_pc_count; ++i) { - if (irep->lines[start_pos + i] == prev_line) { continue; } + if (lines[start_pos + i] == prev_line) { continue; } ret->lines.flat_map = (mrb_irep_debug_info_line*)mrb_realloc( mrb, ret->lines.flat_map, sizeof(mrb_irep_debug_info_line) * (ret->line_entry_count + 1)); m.start_pos = start_pos + i; - m.line = irep->lines[start_pos + i]; + m.line = lines[start_pos + i]; ret->lines.flat_map[ret->line_entry_count] = m; /* update */ ++ret->line_entry_count; - prev_line = irep->lines[start_pos + i]; + prev_line = lines[start_pos + i]; } } break; diff --git a/src/dump.c b/src/dump.c index e41dd83ed..6ce9c4eb9 100644 --- a/src/dump.c +++ b/src/dump.c @@ -353,118 +353,6 @@ write_section_irep(mrb_state *mrb, mrb_irep *irep, uint8_t *bin, size_t *len_p, return MRB_DUMP_OK; } -static int -write_section_lineno_header(mrb_state *mrb, size_t section_size, uint8_t *bin) -{ - struct rite_section_lineno_header *header = (struct rite_section_lineno_header*)bin; - - memcpy(header->section_ident, RITE_SECTION_LINENO_IDENT, sizeof(header->section_ident)); - uint32_to_bin((uint32_t)section_size, header->section_size); - - return MRB_DUMP_OK; -} - -static size_t -get_lineno_record_size(mrb_state *mrb, mrb_irep *irep) -{ - size_t size = 0; - - size += sizeof(uint32_t); /* record size */ - size += sizeof(uint16_t); /* filename size */ - if (irep->filename) { - size += strlen(irep->filename); /* filename */ - } - size += sizeof(uint32_t); /* niseq */ - if (irep->lines) { - size += sizeof(uint16_t) * irep->ilen; /* lineno */ - } - - return size; -} - -static size_t -write_lineno_record_1(mrb_state *mrb, mrb_irep *irep, uint8_t* bin) -{ - uint8_t *cur = bin; - int iseq_no; - size_t filename_len; - ptrdiff_t diff; - - cur += sizeof(uint32_t); /* record size */ - - if (irep->filename) { - filename_len = strlen(irep->filename); - } - else { - filename_len = 0; - } - mrb_assert_int_fit(size_t, filename_len, uint16_t, UINT16_MAX); - cur += uint16_to_bin((uint16_t)filename_len, cur); /* filename size */ - - if (filename_len) { - memcpy(cur, irep->filename, filename_len); - cur += filename_len; /* filename */ - } - - if (irep->lines) { - mrb_assert_int_fit(size_t, irep->ilen, uint32_t, UINT32_MAX); - cur += uint32_to_bin((uint32_t)(irep->ilen), cur); /* niseq */ - for (iseq_no = 0; iseq_no < irep->ilen; iseq_no++) { - cur += uint16_to_bin(irep->lines[iseq_no], cur); /* opcode */ - } - } - else { - cur += uint32_to_bin(0, cur); /* niseq */ - } - - diff = cur - bin; - mrb_assert_int_fit(ptrdiff_t, diff, uint32_t, UINT32_MAX); - - uint32_to_bin((uint32_t)diff, bin); /* record size */ - - mrb_assert_int_fit(ptrdiff_t, diff, size_t, SIZE_MAX); - return (size_t)diff; -} - -static size_t -write_lineno_record(mrb_state *mrb, mrb_irep *irep, uint8_t* bin) -{ - size_t rlen, size = 0; - int i; - - rlen = write_lineno_record_1(mrb, irep, bin); - bin += rlen; - size += rlen; - for (i=0; irlen; i++) { - rlen = write_lineno_record(mrb, irep, bin); - bin += rlen; - size += rlen; - } - return size; -} - -static int -write_section_lineno(mrb_state *mrb, mrb_irep *irep, uint8_t *bin) -{ - size_t section_size = 0; - size_t rlen = 0; /* size of irep record */ - uint8_t *cur = bin; - - if (mrb == NULL || bin == NULL) { - return MRB_DUMP_INVALID_ARGUMENT; - } - - cur += sizeof(struct rite_section_lineno_header); - section_size += sizeof(struct rite_section_lineno_header); - - rlen = write_lineno_record(mrb, irep, cur); - section_size += rlen; - - write_section_lineno_header(mrb, section_size, bin); - - return MRB_DUMP_OK; -} - static size_t get_debug_record_size(mrb_state *mrb, mrb_irep *irep) { @@ -911,10 +799,6 @@ dump_irep(mrb_state *mrb, mrb_irep *irep, uint8_t flags, uint8_t **bin, size_t * section_lineno_size += get_debug_record_size(mrb, irep); } - else { - section_lineno_size += sizeof(struct rite_section_lineno_header); - section_lineno_size += get_lineno_record_size(mrb, irep); - } } if (lv_defined) { @@ -942,12 +826,9 @@ dump_irep(mrb_state *mrb, mrb_irep *irep, uint8_t flags, uint8_t **bin, size_t * if (flags & DUMP_DEBUG_INFO) { if (debug_info_defined) { result = write_section_debug(mrb, irep, cur, filenames, filenames_len); - } - else { - result = write_section_lineno(mrb, irep, cur); - } - if (result != MRB_DUMP_OK) { - goto error_exit; + if (result != MRB_DUMP_OK) { + goto error_exit; + } } cur += section_lineno_size; } diff --git a/src/load.c b/src/load.c index 70f5406eb..559fff1d4 100644 --- a/src/load.c +++ b/src/load.c @@ -215,12 +215,11 @@ read_section_irep(mrb_state *mrb, const uint8_t *bin, uint8_t flags) return read_irep_record(mrb, bin, &len, flags); } +/* ignore lineno record */ static int read_lineno_record_1(mrb_state *mrb, const uint8_t *bin, mrb_irep *irep, size_t *len) { size_t i, fname_len, niseq; - char *fname; - uint16_t *lines; *len = 0; bin += sizeof(uint32_t); /* record size */ @@ -228,9 +227,6 @@ read_lineno_record_1(mrb_state *mrb, const uint8_t *bin, mrb_irep *irep, size_t fname_len = bin_to_uint16(bin); bin += sizeof(uint16_t); *len += sizeof(uint16_t); - fname = (char *)mrb_malloc(mrb, fname_len + 1); - memcpy(fname, bin, fname_len); - fname[fname_len] = '\0'; bin += fname_len; *len += fname_len; @@ -241,15 +237,11 @@ read_lineno_record_1(mrb_state *mrb, const uint8_t *bin, mrb_irep *irep, size_t if (SIZE_ERROR_MUL(niseq, sizeof(uint16_t))) { return MRB_DUMP_GENERAL_FAILURE; } - lines = (uint16_t *)mrb_malloc(mrb, niseq * sizeof(uint16_t)); for (i = 0; i < niseq; i++) { - lines[i] = bin_to_uint16(bin); bin += sizeof(uint16_t); /* niseq */ *len += sizeof(uint16_t); } - irep->filename = fname; - irep->lines = lines; return MRB_DUMP_OK; } diff --git a/src/state.c b/src/state.c index 18d104555..5583a77e5 100644 --- a/src/state.c +++ b/src/state.c @@ -168,10 +168,6 @@ mrb_irep_free(mrb_state *mrb, mrb_irep *irep) } mrb_free(mrb, irep->reps); mrb_free(mrb, irep->lv); - if (irep->own_filename) { - mrb_free(mrb, (void *)irep->filename); - } - mrb_free(mrb, irep->lines); mrb_debug_info_free(mrb, irep->debug_info); mrb_free(mrb, irep); } @@ -273,7 +269,6 @@ mrb_add_irep(mrb_state *mrb) irep = (mrb_irep *)mrb_malloc(mrb, sizeof(mrb_irep)); *irep = mrb_irep_zero; irep->refcnt = 1; - irep->own_filename = FALSE; return irep; } -- cgit v1.2.3 From f39f428ed4cce826e3cc1e59a323369a2932ed75 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Thu, 15 Nov 2018 20:58:36 +0900 Subject: Silence `-fsanitize=undefined` warning in `src/enum.c`; fix #4161 --- src/enum.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/enum.c b/src/enum.c index 03508953e..38f004f51 100644 --- a/src/enum.c +++ b/src/enum.c @@ -30,7 +30,7 @@ enum_update_hash(mrb_state *mrb, mrb_value self) /* not reached */ hv = 0; } - hash ^= (hv << (index % 16)); + hash ^= ((uint32_t)hv << (index % 16)); return mrb_fixnum_value(hash); } -- cgit v1.2.3 From 56db3cf3eb35e430f73d31468b8cad37e21538c7 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Thu, 15 Nov 2018 21:01:25 +0900 Subject: Simplify argument parsing; ref #4161 --- src/enum.c | 16 +--------------- 1 file changed, 1 insertion(+), 15 deletions(-) diff --git a/src/enum.c b/src/enum.c index 38f004f51..1e9445176 100644 --- a/src/enum.c +++ b/src/enum.c @@ -14,22 +14,8 @@ enum_update_hash(mrb_state *mrb, mrb_value self) mrb_int hash; mrb_int index; mrb_int hv; - mrb_value item_hash; - mrb_get_args(mrb, "iio", &hash, &index, &item_hash); - if (mrb_fixnum_p(item_hash)) { - hv = mrb_fixnum(item_hash); - } -#ifndef MRB_WITHOUT_FLOAT - else if (mrb_float_p(item_hash)) { - hv = (mrb_int)mrb_float(item_hash); - } -#endif - else { - mrb_raise(mrb, E_TYPE_ERROR, "can't calculate hash"); - /* not reached */ - hv = 0; - } + mrb_get_args(mrb, "iii", &hash, &index, &hv); hash ^= ((uint32_t)hv << (index % 16)); return mrb_fixnum_value(hash); -- cgit v1.2.3 From faf51f82c7265f2cbdda8291429d7f2016d2bc3f Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Thu, 15 Nov 2018 23:28:34 +0900 Subject: Rename local variables in `mrb_debug_info_append_file` --- src/debug.c | 56 ++++++++++++++++++++++++++++---------------------------- 1 file changed, 28 insertions(+), 28 deletions(-) diff --git a/src/debug.c b/src/debug.c index 207065d9e..2949131e4 100644 --- a/src/debug.c +++ b/src/debug.c @@ -122,72 +122,72 @@ mrb_debug_info_alloc(mrb_state *mrb, mrb_irep *irep) } MRB_API mrb_irep_debug_info_file* -mrb_debug_info_append_file(mrb_state *mrb, mrb_irep_debug_info *info, +mrb_debug_info_append_file(mrb_state *mrb, mrb_irep_debug_info *d, const char *filename, uint16_t *lines, uint32_t start_pos, uint32_t end_pos) { - mrb_irep_debug_info_file *ret; + mrb_irep_debug_info_file *f; uint32_t file_pc_count; size_t fn_len; mrb_int len; uint32_t i; - if (!info) { return NULL; } + if (!d) return NULL; + if (start_pos == end_pos) return NULL; mrb_assert(filename); mrb_assert(lines); - if (info->flen > 0 && strcmp(filename, info->files[info->flen - 1]->filename) == 0) { + if (d->flen > 0 && strcmp(filename, d->files[d->flen - 1]->filename) == 0) { return NULL; } - ret = (mrb_irep_debug_info_file *)mrb_malloc(mrb, sizeof(*ret)); - info->files = - (mrb_irep_debug_info_file**)( - info->files - ? mrb_realloc(mrb, info->files, sizeof(mrb_irep_debug_info_file*) * (info->flen + 1)) + f = (mrb_irep_debug_info_file*)mrb_malloc(mrb, sizeof(*f)); + d->files = (mrb_irep_debug_info_file**)( + d->files + ? mrb_realloc(mrb, d->files, sizeof(mrb_irep_debug_info_file*) * (d->flen + 1)) : mrb_malloc(mrb, sizeof(mrb_irep_debug_info_file*))); - info->files[info->flen++] = ret; + d->files[d->flen++] = f; file_pc_count = end_pos - start_pos; - ret->start_pos = start_pos; - info->pc_count = end_pos; + f->start_pos = start_pos; + d->pc_count = end_pos; fn_len = strlen(filename); - ret->filename_sym = mrb_intern(mrb, filename, fn_len); + f->filename_sym = mrb_intern(mrb, filename, fn_len); len = 0; - ret->filename = mrb_sym2name_len(mrb, ret->filename_sym, &len); + f->filename = mrb_sym2name_len(mrb, f->filename_sym, &len); - ret->line_type = select_line_type(lines + start_pos, end_pos - start_pos); - ret->lines.ptr = NULL; + f->line_type = select_line_type(lines + start_pos, end_pos - start_pos); + f->lines.ptr = NULL; - switch (ret->line_type) { + switch (f->line_type) { case mrb_debug_line_ary: - ret->line_entry_count = file_pc_count; - ret->lines.ary = (uint16_t*)mrb_malloc(mrb, sizeof(uint16_t) * file_pc_count); + f->line_entry_count = file_pc_count; + f->lines.ary = (uint16_t*)mrb_malloc(mrb, sizeof(uint16_t) * file_pc_count); for (i = 0; i < file_pc_count; ++i) { - ret->lines.ary[i] = lines[start_pos + i]; + f->lines.ary[i] = lines[start_pos + i]; } break; case mrb_debug_line_flat_map: { uint16_t prev_line = 0; mrb_irep_debug_info_line m; - ret->lines.flat_map = (mrb_irep_debug_info_line*)mrb_malloc(mrb, sizeof(mrb_irep_debug_info_line) * 1); - ret->line_entry_count = 0; + f->lines.flat_map = (mrb_irep_debug_info_line*)mrb_malloc(mrb, sizeof(mrb_irep_debug_info_line) * 1); + f->line_entry_count = 0; for (i = 0; i < file_pc_count; ++i) { if (lines[start_pos + i] == prev_line) { continue; } - ret->lines.flat_map = (mrb_irep_debug_info_line*)mrb_realloc( - mrb, ret->lines.flat_map, - sizeof(mrb_irep_debug_info_line) * (ret->line_entry_count + 1)); + f->lines.flat_map = (mrb_irep_debug_info_line*)mrb_realloc( + mrb, f->lines.flat_map, + sizeof(mrb_irep_debug_info_line) * (f->line_entry_count + 1)); m.start_pos = start_pos + i; m.line = lines[start_pos + i]; - ret->lines.flat_map[ret->line_entry_count] = m; + f->lines.flat_map[f->line_entry_count] = m; /* update */ - ++ret->line_entry_count; + ++f->line_entry_count; prev_line = lines[start_pos + i]; } } break; @@ -195,7 +195,7 @@ mrb_debug_info_append_file(mrb_state *mrb, mrb_irep_debug_info *info, default: mrb_assert(0); break; } - return ret; + return f; } MRB_API void -- cgit v1.2.3 From 7e3e8d8ed5d9d12e7d3b0d616bf9b770f07e0d4f Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Thu, 15 Nov 2018 23:26:37 +0900 Subject: Shrink file name table size to `uint16_t`; ref #4138 --- include/mruby/compile.h | 4 ++-- mrbgems/mruby-compiler/core/parse.y | 8 ++++++-- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/include/mruby/compile.h b/include/mruby/compile.h index a85460415..63ec8aca1 100644 --- a/include/mruby/compile.h +++ b/include/mruby/compile.h @@ -158,8 +158,8 @@ struct mrb_parser_state { struct mrb_parser_message warn_buffer[10]; mrb_sym* filename_table; - size_t filename_table_length; - int current_filename_index; + uint16_t filename_table_length; + uint16_t current_filename_index; struct mrb_jmpbuf* jmp; }; diff --git a/mrbgems/mruby-compiler/core/parse.y b/mrbgems/mruby-compiler/core/parse.y index 5e6cda236..1c06be839 100644 --- a/mrbgems/mruby-compiler/core/parse.y +++ b/mrbgems/mruby-compiler/core/parse.y @@ -5900,7 +5900,11 @@ mrb_parser_set_filename(struct mrb_parser_state *p, const char *f) } } - p->current_filename_index = (int)p->filename_table_length++; + if (p->filename_table_length == UINT16_MAX) { + yyerror(p, "too many files to compile"); + return; + } + p->current_filename_index = p->filename_table_length++; new_table = (mrb_sym*)parser_palloc(p, sizeof(mrb_sym) * p->filename_table_length); if (p->filename_table) { @@ -5912,7 +5916,7 @@ mrb_parser_set_filename(struct mrb_parser_state *p, const char *f) MRB_API char const* mrb_parser_get_filename(struct mrb_parser_state* p, uint16_t idx) { - if (idx >= p->filename_table_length) { return NULL; } + if (idx >= p->filename_table_length) return NULL; else { return mrb_sym2name_len(p->mrb, p->filename_table[idx], NULL); } -- cgit v1.2.3 From 418ad65db40200058a023b57682f4a3853fd63bc Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Thu, 15 Nov 2018 23:29:55 +0900 Subject: Fixed a bug in continuous read of target files; ref #4138 Line number information in a compiled file was wrong. --- mrbgems/mruby-compiler/core/codegen.c | 5 ++++- mrbgems/mruby-compiler/core/parse.y | 4 ++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/mrbgems/mruby-compiler/core/codegen.c b/mrbgems/mruby-compiler/core/codegen.c index dbd3b8ecf..ba7d8cf63 100644 --- a/mrbgems/mruby-compiler/core/codegen.c +++ b/mrbgems/mruby-compiler/core/codegen.c @@ -156,7 +156,10 @@ emit_B(codegen_scope *s, uint32_t pc, uint8_t i) } } if (s->lines) { - s->lines[pc] = s->lineno; + if (s->lineno > 0 || pc == 0) + s->lines[pc] = s->lineno; + else + s->lines[pc] = s->lines[pc-1]; } s->iseq[pc] = i; } diff --git a/mrbgems/mruby-compiler/core/parse.y b/mrbgems/mruby-compiler/core/parse.y index 1c06be839..ac8724377 100644 --- a/mrbgems/mruby-compiler/core/parse.y +++ b/mrbgems/mruby-compiler/core/parse.y @@ -133,6 +133,10 @@ cons_gen(parser_state *p, node *car, node *cdr) c->cdr = cdr; c->lineno = p->lineno; c->filename_index = p->current_filename_index; + /* beginning of next partial file; need to point the previous file */ + if (p->lineno == 0 && p->current_filename_index > 0) { + c->filename_index-- ; + } return c; } #define cons(a,b) cons_gen(p,(a),(b)) -- cgit v1.2.3 From 0a022f7b8d3e6abc0320001430de9e7d63ba9212 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Thu, 15 Nov 2018 23:31:29 +0900 Subject: The saved `pc` from `ERR_PC_SET` was wrong; fix #4138 The saving `pc` position should be beginning of the instruction. But after `mruby 2.0` byte code modification, the `pc` variable points the beginning of the next instruction. We save the previous position in a local variable `pc0`. --- src/vm.c | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/src/vm.c b/src/vm.c index 5779791bc..2b88b0761 100644 --- a/src/vm.c +++ b/src/vm.c @@ -913,8 +913,8 @@ argnum_error(mrb_state *mrb, mrb_int num) mrb_exc_set(mrb, exc); } -#define ERR_PC_SET(mrb, pc) mrb->c->ci->err = pc; -#define ERR_PC_CLR(mrb) mrb->c->ci->err = 0; +#define ERR_PC_SET(mrb) mrb->c->ci->err = pc0; +#define ERR_PC_CLR(mrb) mrb->c->ci->err = 0; #ifdef MRB_ENABLE_DEBUG_HOOK #define CODE_FETCH_HOOK(mrb, irep, pc, regs) if ((mrb)->code_fetch_hook) (mrb)->code_fetch_hook((mrb), (irep), (pc), (regs)); #else @@ -936,7 +936,7 @@ argnum_error(mrb_state *mrb, mrb_int num) #ifndef DIRECT_THREADED #define INIT_DISPATCH for (;;) { insn = BYTECODE_DECODER(*pc); CODE_FETCH_HOOK(mrb, irep, pc, regs); switch (insn) { -#define CASE(insn,ops) case insn: pc++; FETCH_ ## ops ();; L_ ## insn ## _BODY: +#define CASE(insn,ops) case insn: pc0=pc++; FETCH_ ## ops ();; L_ ## insn ## _BODY: #define NEXT break #define JUMP NEXT #define END_DISPATCH }} @@ -944,7 +944,7 @@ argnum_error(mrb_state *mrb, mrb_int num) #else #define INIT_DISPATCH JUMP; return mrb_nil_value(); -#define CASE(insn,ops) L_ ## insn: pc++; FETCH_ ## ops (); L_ ## insn ## _BODY: +#define CASE(insn,ops) L_ ## insn: pc0=pc++; FETCH_ ## ops (); L_ ## insn ## _BODY: #define NEXT insn=BYTECODE_DECODER(*pc); CODE_FETCH_HOOK(mrb, irep, pc, regs); goto *optable[insn] #define JUMP NEXT @@ -999,6 +999,7 @@ MRB_API mrb_value mrb_vm_exec(mrb_state *mrb, struct RProc *proc, mrb_code *pc) { /* mrb_assert(mrb_proc_cfunc_p(proc)) */ + mrb_code *pc0 = pc; mrb_irep *irep = proc->body.irep; mrb_value *pool = irep->pool; mrb_sym *syms = irep->syms; @@ -1144,7 +1145,7 @@ RETRY_TRY_BLOCK: CASE(OP_GETCV, BB) { mrb_value val; - ERR_PC_SET(mrb, pc); + ERR_PC_SET(mrb); val = mrb_vm_cv_get(mrb, syms[b]); ERR_PC_CLR(mrb); regs[a] = val; @@ -1160,7 +1161,7 @@ RETRY_TRY_BLOCK: mrb_value val; mrb_sym sym = syms[b]; - ERR_PC_SET(mrb, pc); + ERR_PC_SET(mrb); val = mrb_vm_const_get(mrb, sym); ERR_PC_CLR(mrb); regs[a] = val; @@ -1175,7 +1176,7 @@ RETRY_TRY_BLOCK: CASE(OP_GETMCNST, BB) { mrb_value val; - ERR_PC_SET(mrb, pc); + ERR_PC_SET(mrb); val = mrb_const_get(mrb, regs[a], syms[b]); ERR_PC_CLR(mrb); regs[a] = val; @@ -1424,7 +1425,7 @@ RETRY_TRY_BLOCK: m = mrb_method_search_vm(mrb, &cls, missing); if (MRB_METHOD_UNDEF_P(m) || (missing == mrb->c->ci->mid && mrb_obj_eq(mrb, regs[0], recv))) { mrb_value args = (argc < 0) ? regs[a+1] : mrb_ary_new_from_values(mrb, c, regs+a+1); - ERR_PC_SET(mrb, pc); + ERR_PC_SET(mrb); mrb_method_missing(mrb, mid, recv, args); } if (argc >= 0) { @@ -1621,7 +1622,7 @@ RETRY_TRY_BLOCK: m = mrb_method_search_vm(mrb, &cls, missing); if (MRB_METHOD_UNDEF_P(m)) { mrb_value args = (argc < 0) ? regs[a+1] : mrb_ary_new_from_values(mrb, b, regs+a+1); - ERR_PC_SET(mrb, pc); + ERR_PC_SET(mrb); mrb_method_missing(mrb, mid, recv, args); } mid = missing; @@ -2925,7 +2926,7 @@ RETRY_TRY_BLOCK: mrb_value exc; exc = mrb_exc_new_str(mrb, E_LOCALJUMP_ERROR, msg); - ERR_PC_SET(mrb, pc); + ERR_PC_SET(mrb); mrb_exc_set(mrb, exc); goto L_RAISE; } -- cgit v1.2.3 From 180b73fec437e21e2e862fc47bff9ad07f581d2c Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Fri, 16 Nov 2018 01:04:57 +0900 Subject: The key or value object could be reclaimed by GC; fix #4164 The GC may occur between `sg_shift` and `mrb_assoc_new`, in which case `key` and `value` could be freed even tough they are still alive. The issue is found and fixed by https://hackerone.com/hexodus --- src/hash.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/hash.c b/src/hash.c index 03a95dbd8..376c054cb 100644 --- a/src/hash.c +++ b/src/hash.c @@ -1057,6 +1057,8 @@ mrb_hash_shift(mrb_state *mrb, mrb_value hash) mrb_value del_key, del_val; sg_shift(mrb, sg, &del_key, &del_val); + mrb_gc_protect(mrb, del_key); + mrb_gc_protect(mrb, del_val); return mrb_assoc_new(mrb, del_key, del_val); } -- cgit v1.2.3 From 25d390d6ccf3da7a853ddd8272dd318ecadca316 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Mon, 19 Nov 2018 09:30:15 +0900 Subject: Improve Hash table using variable sized segments. --- include/mruby/hash.h | 2 +- src/hash.c | 308 +++++++++++++++++++++++++++------------------------ 2 files changed, 162 insertions(+), 148 deletions(-) diff --git a/include/mruby/hash.h b/include/mruby/hash.h index dacdd9376..7811894ae 100644 --- a/include/mruby/hash.h +++ b/include/mruby/hash.h @@ -18,7 +18,7 @@ MRB_BEGIN_DECL struct RHash { MRB_OBJECT_HEADER; struct iv_tbl *iv; - struct seglist *ht; + struct htable *ht; }; #define mrb_hash_ptr(v) ((struct RHash*)(mrb_ptr(v))) diff --git a/src/hash.c b/src/hash.c index 376c054cb..f43fd901c 100644 --- a/src/hash.c +++ b/src/hash.c @@ -17,11 +17,12 @@ mrb_int mrb_float_id(mrb_float f); #endif /* return non zero to break the loop */ -typedef int (sg_foreach_func)(mrb_state *mrb,mrb_value key, mrb_value val, void *data); +typedef int (ht_foreach_func)(mrb_state *mrb,mrb_value key, mrb_value val, void *data); -#ifndef MRB_SG_SEGMENT_SIZE -#define MRB_SG_SEGMENT_SIZE 5 +#ifndef MRB_HT_INIT_SIZE +#define MRB_HT_INIT_SIZE 4 #endif +#define HT_SEG_INCREASE_RATIO 1.2 struct segkv { mrb_value key; @@ -29,8 +30,9 @@ struct segkv { }; typedef struct segment { + uint16_t size; struct segment *next; - struct segkv e[MRB_SG_SEGMENT_SIZE]; + struct segkv e[]; } segment; typedef struct segindex { @@ -40,16 +42,16 @@ typedef struct segindex { } segindex; /* Instance variable table structure */ -typedef struct seglist { +typedef struct htable { segment *rootseg; segment *lastseg; mrb_int size; - mrb_int last_len; + uint16_t last_len; segindex *index; -} seglist; +} htable; static /* inline */ size_t -sg_hash_func(mrb_state *mrb, seglist *t, mrb_value key) +ht_hash_func(mrb_state *mrb, htable *t, mrb_value key) { enum mrb_vtype tt = mrb_type(key); mrb_value hv; @@ -84,7 +86,7 @@ sg_hash_func(mrb_state *mrb, seglist *t, mrb_value key) } static inline mrb_bool -sg_hash_equal(mrb_state *mrb, seglist *t, mrb_value a, mrb_value b) +ht_hash_equal(mrb_state *mrb, htable *t, mrb_value a, mrb_value b) { enum mrb_vtype tt = mrb_type(a); @@ -134,12 +136,12 @@ sg_hash_equal(mrb_state *mrb, seglist *t, mrb_value a, mrb_value b) } /* Creates the instance variable table. */ -static seglist* -sg_new(mrb_state *mrb) +static htable* +ht_new(mrb_state *mrb) { - seglist *t; + htable *t; - t = (seglist*)mrb_malloc(mrb, sizeof(seglist)); + t = (htable*)mrb_malloc(mrb, sizeof(htable)); t->size = 0; t->rootseg = NULL; t->lastseg = NULL; @@ -163,11 +165,11 @@ sg_new(mrb_state *mrb) #define UPPER_BOUND(x) ((x)>>2|(x)>>1) #endif -#define SG_MASK(index) ((index->capa)-1) +#define HT_MASK(index) ((index->capa)-1) -/* Build index for the segment list */ +/* Build index for the hash table */ static void -sg_index(mrb_state *mrb, seglist *t) +ht_index(mrb_state *mrb, htable *t) { size_t size = (size_t)t->size; size_t mask; @@ -175,14 +177,6 @@ sg_index(mrb_state *mrb, seglist *t) segment *seg; size_t i; - if (size < MRB_SG_SEGMENT_SIZE) { - if (index) { - failed: - mrb_free(mrb, index); - t->index = NULL; - } - return; - } /* allocate index table */ if (index && index->size >= UPPER_BOUND(index->capa)) { size = index->capa+1; @@ -190,7 +184,11 @@ sg_index(mrb_state *mrb, seglist *t) power2(size); if (!index || index->capa < size) { index = (segindex*)mrb_realloc_simple(mrb, index, sizeof(segindex)+sizeof(struct segkv*)*size); - if (index == NULL) goto failed; + if (index == NULL) { + mrb_free(mrb, index); + t->index = NULL; + return; + } t->index = index; } index->size = t->size; @@ -200,10 +198,10 @@ sg_index(mrb_state *mrb, seglist *t) } /* rebuld index */ - mask = SG_MASK(index); + mask = HT_MASK(index); seg = t->rootseg; while (seg) { - for (i=0; isize; i++) { mrb_value key; size_t k, step = 0; @@ -212,7 +210,7 @@ sg_index(mrb_state *mrb, seglist *t) } key = seg->e[i].key; if (mrb_undef_p(key)) continue; - k = sg_hash_func(mrb, t, key) & mask; + k = ht_hash_func(mrb, t, key) & mask; while (index->table[k]) { k = (k+(++step)) & mask; } @@ -222,9 +220,9 @@ sg_index(mrb_state *mrb, seglist *t) } } -/* Compacts the segment list removing deleted entries. */ +/* Compacts the hash table removing deleted entries. */ static void -sg_compact(mrb_state *mrb, seglist *t) +ht_compact(mrb_state *mrb, htable *t) { segment *seg; mrb_int i; @@ -235,11 +233,11 @@ sg_compact(mrb_state *mrb, seglist *t) if (t == NULL) return; seg = t->rootseg; if (t->index && (size_t)t->size == t->index->size) { - sg_index(mrb, t); + ht_index(mrb, t); return; } while (seg) { - for (i=0; isize; i++) { mrb_value k = seg->e[i].key; if (!seg->next && i >= t->last_len) { @@ -255,7 +253,7 @@ sg_compact(mrb_state *mrb, seglist *t) size++; if (seg2 != NULL) { seg2->e[i2++] = seg->e[i]; - if (i2 >= MRB_SG_SEGMENT_SIZE) { + if (i2 >= seg2->size) { seg2 = seg2->next; i2 = 0; } @@ -279,13 +277,31 @@ sg_compact(mrb_state *mrb, seglist *t) } } if (t->index) { - sg_index(mrb, t); + ht_index(mrb, t); } } -/* Set the value for the key in the indexed segment list. */ +static segment* +segment_alloc(mrb_state *mrb, segment *seg) +{ + uint32_t size; + + if (!seg) size = MRB_HT_INIT_SIZE; + else { + size = seg->size*HT_SEG_INCREASE_RATIO + 1; + if (size > UINT16_MAX) size = UINT16_MAX; + } + + seg = (segment*)mrb_malloc(mrb, sizeof(segment)+sizeof(struct segkv)*size); + seg->size = size; + seg->next = NULL; + + return seg; +} + +/* Set the value for the key in the indexed table. */ static void -sg_index_put(mrb_state *mrb, seglist *t, mrb_value key, mrb_value val) +ht_index_put(mrb_state *mrb, htable *t, mrb_value key, mrb_value val) { segindex *index = t->index; size_t k, sp, step = 0, mask; @@ -293,18 +309,18 @@ sg_index_put(mrb_state *mrb, seglist *t, mrb_value key, mrb_value val) if (index->size >= UPPER_BOUND(index->capa)) { /* need to expand table */ - sg_compact(mrb, t); + ht_compact(mrb, t); index = t->index; } - mask = SG_MASK(index); + mask = HT_MASK(index); sp = index->capa; - k = sg_hash_func(mrb, t, key) & mask; + k = ht_hash_func(mrb, t, key) & mask; while (index->table[k]) { mrb_value key2 = index->table[k]->key; if (mrb_undef_p(key2)) { if (sp == index->capa) sp = k; } - else if (sg_hash_equal(mrb, t, key, key2)) { + else if (ht_hash_equal(mrb, t, key, key2)) { index->table[k]->val = val; return; } @@ -316,11 +332,11 @@ sg_index_put(mrb_state *mrb, seglist *t, mrb_value key, mrb_value val) /* put the value at the last */ seg = t->lastseg; - if (t->last_len < MRB_SG_SEGMENT_SIZE) { + if (t->last_len < seg->size) { index->table[k] = &seg->e[t->last_len++]; } else { /* append a new segment */ - seg->next = (segment*)mrb_malloc(mrb, sizeof(segment)); + seg->next = segment_alloc(mrb, seg); seg = seg->next; seg->next = NULL; t->lastseg = seg; @@ -333,21 +349,21 @@ sg_index_put(mrb_state *mrb, seglist *t, mrb_value key, mrb_value val) t->size++; } -/* Set the value for the key in the segment list. */ +/* Set the value for the key in the table. */ static void -sg_put(mrb_state *mrb, seglist *t, mrb_value key, mrb_value val) +ht_put(mrb_state *mrb, htable *t, mrb_value key, mrb_value val) { segment *seg; mrb_int i, deleted = 0; if (t == NULL) return; if (t->index) { - sg_index_put(mrb, t, key, val); + ht_index_put(mrb, t, key, val); return; } seg = t->rootseg; while (seg) { - for (i=0; isize; i++) { mrb_value k = seg->e[i].key; /* Found room in last segment after last_len */ if (!seg->next && i >= t->last_len) { @@ -361,49 +377,58 @@ sg_put(mrb_state *mrb, seglist *t, mrb_value key, mrb_value val) deleted++; continue; } - if (sg_hash_equal(mrb, t, k, key)) { + if (ht_hash_equal(mrb, t, k, key)) { seg->e[i].val = val; return; } } seg = seg->next; } - /* Not found */ - if (deleted > MRB_SG_SEGMENT_SIZE) { - sg_compact(mrb, t); + + /* Compact if last segment has room */ + if (deleted > 0 && deleted > MRB_HT_INIT_SIZE) { + ht_compact(mrb, t); } t->size++; - seg = (segment*)mrb_malloc(mrb, sizeof(segment)); - seg->next = NULL; - seg->e[0].key = key; - seg->e[0].val = val; - t->last_len = 1; - if (t->rootseg == NULL) { - t->rootseg = seg; + /* check if thre's room after compaction */ + if (t->lastseg && t->last_len < t->lastseg->size) { + seg = t->lastseg; + i = t->last_len; } else { - t->lastseg->next = seg; + /* append new segment */ + seg = segment_alloc(mrb, t->lastseg); + i = 0; + if (t->rootseg == NULL) { + t->rootseg = seg; + } + else { + t->lastseg->next = seg; + } + t->lastseg = seg; } - t->lastseg = seg; - if (t->index == NULL && t->size > MRB_SG_SEGMENT_SIZE*4) { - sg_index(mrb, t); + seg->e[i].key = key; + seg->e[i].val = val; + t->last_len = i+1; + if (t->index == NULL && t->size > MRB_HT_INIT_SIZE*4) { + ht_index(mrb, t); } } -/* Get a value for a key from the indexed segment list. */ +/* Get a value for a key from the indexed table. */ static mrb_bool -sg_index_get(mrb_state *mrb, seglist *t, mrb_value key, mrb_value *vp) +ht_index_get(mrb_state *mrb, htable *t, mrb_value key, mrb_value *vp) { segindex *index = t->index; - size_t mask = SG_MASK(index); - size_t k = sg_hash_func(mrb, t, key) & mask; + size_t mask = HT_MASK(index); + size_t k = ht_hash_func(mrb, t, key) & mask; size_t step = 0; while (index->table[k]) { mrb_value key2 = index->table[k]->key; - if (!mrb_undef_p(key2) && sg_hash_equal(mrb, t, key, key2)) { + if (!mrb_undef_p(key2) && ht_hash_equal(mrb, t, key, key2)) { if (vp) *vp = index->table[k]->val; return TRUE; } @@ -412,28 +437,28 @@ sg_index_get(mrb_state *mrb, seglist *t, mrb_value key, mrb_value *vp) return FALSE; } -/* Get a value for a key from the segment list. */ +/* Get a value for a key from the hash table. */ static mrb_bool -sg_get(mrb_state *mrb, seglist *t, mrb_value key, mrb_value *vp) +ht_get(mrb_state *mrb, htable *t, mrb_value key, mrb_value *vp) { segment *seg; mrb_int i; if (t == NULL) return FALSE; if (t->index) { - return sg_index_get(mrb, t, key, vp); + return ht_index_get(mrb, t, key, vp); } seg = t->rootseg; while (seg) { - for (i=0; isize; i++) { mrb_value k = seg->e[i].key; if (!seg->next && i >= t->last_len) { return FALSE; } if (mrb_undef_p(k)) continue; - if (sg_hash_equal(mrb, t, k, key)) { + if (ht_hash_equal(mrb, t, k, key)) { if (vp) *vp = seg->e[i].val; return TRUE; } @@ -446,7 +471,7 @@ sg_get(mrb_state *mrb, seglist *t, mrb_value key, mrb_value *vp) /* Deletes the value for the symbol from the instance variable table. */ /* Deletion is done by overwriting keys by `undef`. */ static mrb_bool -sg_del(mrb_state *mrb, seglist *t, mrb_value key, mrb_value *vp) +ht_del(mrb_state *mrb, htable *t, mrb_value key, mrb_value *vp) { segment *seg; mrb_int i; @@ -454,7 +479,7 @@ sg_del(mrb_state *mrb, seglist *t, mrb_value key, mrb_value *vp) if (t == NULL) return FALSE; seg = t->rootseg; while (seg) { - for (i=0; isize; i++) { mrb_value key2; if (!seg->next && i >= t->last_len) { @@ -462,7 +487,7 @@ sg_del(mrb_state *mrb, seglist *t, mrb_value key, mrb_value *vp) return FALSE; } key2 = seg->e[i].key; - if (!mrb_undef_p(key2) && sg_hash_equal(mrb, t, key, key2)) { + if (!mrb_undef_p(key2) && ht_hash_equal(mrb, t, key, key2)) { if (vp) *vp = seg->e[i].val; seg->e[i].key = mrb_undef_value(); t->size--; @@ -476,18 +501,15 @@ sg_del(mrb_state *mrb, seglist *t, mrb_value key, mrb_value *vp) /* Iterates over the instance variable table. */ static void -sg_foreach(mrb_state *mrb, seglist *t, sg_foreach_func *func, void *p) +ht_foreach(mrb_state *mrb, htable *t, ht_foreach_func *func, void *p) { segment *seg; mrb_int i; if (t == NULL) return; - if (t->index && t->index->size-(size_t)t->size > MRB_SG_SEGMENT_SIZE) { - sg_compact(mrb, t); - } seg = t->rootseg; while (seg) { - for (i=0; isize; i++) { /* no value in last segment after last_len */ if (!seg->next && i >= t->last_len) { return; @@ -500,34 +522,26 @@ sg_foreach(mrb_state *mrb, seglist *t, sg_foreach_func *func, void *p) } } -/* Get the size of the instance variable table. */ -static mrb_int -sg_size(mrb_state *mrb, seglist *t) -{ - if (t == NULL) return 0; - return t->size; -} - /* Copy the instance variable table. */ -static seglist* -sg_copy(mrb_state *mrb, seglist *t) +static htable* +ht_copy(mrb_state *mrb, htable *t) { segment *seg; - seglist *t2; + htable *t2; mrb_int i; seg = t->rootseg; - t2 = sg_new(mrb); + t2 = ht_new(mrb); - while (seg != NULL) { - for (i=0; isize; i++) { mrb_value key = seg->e[i].key; mrb_value val = seg->e[i].val; if ((seg->next == NULL) && (i >= t->last_len)) { return t2; } - sg_put(mrb, t2, key, val); + ht_put(mrb, t2, key, val); } seg = seg->next; } @@ -536,7 +550,7 @@ sg_copy(mrb_state *mrb, seglist *t) /* Free memory of the instance variable table. */ static void -sg_free(mrb_state *mrb, seglist *t) +ht_free(mrb_state *mrb, htable *t) { segment *seg; @@ -576,20 +590,20 @@ hash_mark_i(mrb_state *mrb, mrb_value key, mrb_value val, void *p) void mrb_gc_mark_hash(mrb_state *mrb, struct RHash *hash) { - sg_foreach(mrb, hash->ht, hash_mark_i, NULL); + ht_foreach(mrb, hash->ht, hash_mark_i, NULL); } size_t mrb_gc_mark_hash_size(mrb_state *mrb, struct RHash *hash) { if (!hash->ht) return 0; - return sg_size(mrb, hash->ht)*2; + return hash->ht->size*2; } void mrb_gc_free_hash(mrb_state *mrb, struct RHash *hash) { - sg_free(mrb, hash->ht); + ht_free(mrb, hash->ht); } MRB_API mrb_value @@ -609,8 +623,8 @@ mrb_hash_new_capa(mrb_state *mrb, mrb_int capa) struct RHash *h; h = (struct RHash*)mrb_obj_alloc(mrb, MRB_TT_HASH, mrb->hash_class); - /* preallocate segment list */ - h->ht = sg_new(mrb); + /* preallocate hash table */ + h->ht = ht_new(mrb); /* capacity ignored */ h->iv = 0; return mrb_obj_value(h); @@ -624,7 +638,7 @@ mrb_hash_init_copy(mrb_state *mrb, mrb_value self) { mrb_value orig; struct RHash* copy; - seglist *orig_h; + htable *orig_h; mrb_value ifnone, vret; mrb_get_args(mrb, "o", &orig); @@ -635,7 +649,7 @@ mrb_hash_init_copy(mrb_state *mrb, mrb_value self) orig_h = RHASH_TBL(self); copy = (struct RHash*)mrb_obj_alloc(mrb, MRB_TT_HASH, mrb->hash_class); - copy->ht = sg_copy(mrb, orig_h); + copy->ht = ht_copy(mrb, orig_h); if (MRB_RHASH_DEFAULT_P(self)) { copy->flags |= MRB_HASH_DEFAULT; @@ -663,22 +677,22 @@ check_kdict_i(mrb_state *mrb, mrb_value key, mrb_value val, void *data) void mrb_hash_check_kdict(mrb_state *mrb, mrb_value self) { - seglist *sg; + htable *t; - sg = RHASH_TBL(self); - if (!sg || sg_size(mrb, sg) == 0) return; - sg_foreach(mrb, sg, check_kdict_i, NULL); + t = RHASH_TBL(self); + if (!t || t->size == 0) return; + ht_foreach(mrb, t, check_kdict_i, NULL); } MRB_API mrb_value mrb_hash_dup(mrb_state *mrb, mrb_value self) { struct RHash* copy; - seglist *orig_h; + htable *orig_h; orig_h = RHASH_TBL(self); copy = (struct RHash*)mrb_obj_alloc(mrb, MRB_TT_HASH, mrb->hash_class); - copy->ht = orig_h ? sg_copy(mrb, orig_h) : NULL; + copy->ht = orig_h ? ht_copy(mrb, orig_h) : NULL; return mrb_obj_value(copy); } @@ -688,7 +702,7 @@ mrb_hash_get(mrb_state *mrb, mrb_value hash, mrb_value key) mrb_value val; mrb_sym mid; - if (sg_get(mrb, RHASH_TBL(hash), key, &val)) { + if (ht_get(mrb, RHASH_TBL(hash), key, &val)) { return val; } @@ -705,7 +719,7 @@ mrb_hash_fetch(mrb_state *mrb, mrb_value hash, mrb_value key, mrb_value def) { mrb_value val; - if (sg_get(mrb, RHASH_TBL(hash), key, &val)) { + if (ht_get(mrb, RHASH_TBL(hash), key, &val)) { return val; } /* not found */ @@ -718,7 +732,7 @@ mrb_hash_set(mrb_state *mrb, mrb_value hash, mrb_value key, mrb_value val) mrb_hash_modify(mrb, hash); key = KEY(key); - sg_put(mrb, RHASH_TBL(hash), key, val); + ht_put(mrb, RHASH_TBL(hash), key, val); mrb_field_write_barrier_value(mrb, (struct RBasic*)RHASH(hash), key); mrb_field_write_barrier_value(mrb, (struct RBasic*)RHASH(hash), val); return; @@ -744,7 +758,7 @@ mrb_hash_modify(mrb_state *mrb, mrb_value hash) } if (!RHASH_TBL(hash)) { - RHASH_TBL(hash) = sg_new(mrb); + RHASH_TBL(hash) = ht_new(mrb); } } @@ -985,10 +999,10 @@ mrb_hash_set_default_proc(mrb_state *mrb, mrb_value hash) MRB_API mrb_value mrb_hash_delete_key(mrb_state *mrb, mrb_value hash, mrb_value key) { - seglist *sg = RHASH_TBL(hash); + htable *t = RHASH_TBL(hash); mrb_value del_val; - if (sg_del(mrb, sg, key, &del_val)) { + if (ht_del(mrb, t, key, &del_val)) { return del_val; } @@ -1006,15 +1020,15 @@ mrb_hash_delete(mrb_state *mrb, mrb_value self) return mrb_hash_delete_key(mrb, self, key); } -/* find first element in segment list, and remove it. */ +/* find first element in a hash table, and remove it. */ static void -sg_shift(mrb_state *mrb, seglist *t, mrb_value *kp, mrb_value *vp) +ht_shift(mrb_state *mrb, htable *t, mrb_value *kp, mrb_value *vp) { segment *seg = t->rootseg; mrb_int i; while (seg) { - for (i=0; isize; i++) { mrb_value key; if (!seg->next && i >= t->last_len) { @@ -1050,13 +1064,13 @@ sg_shift(mrb_state *mrb, seglist *t, mrb_value *kp, mrb_value *vp) static mrb_value mrb_hash_shift(mrb_state *mrb, mrb_value hash) { - seglist *sg = RHASH_TBL(hash); + htable *t = RHASH_TBL(hash); mrb_hash_modify(mrb, hash); - if (sg && sg_size(mrb, sg) > 0) { + if (t && t->size > 0) { mrb_value del_key, del_val; - sg_shift(mrb, sg, &del_key, &del_val); + ht_shift(mrb, t, &del_key, &del_val); mrb_gc_protect(mrb, del_key); mrb_gc_protect(mrb, del_val); return mrb_assoc_new(mrb, del_key, del_val); @@ -1088,11 +1102,11 @@ mrb_hash_shift(mrb_state *mrb, mrb_value hash) MRB_API mrb_value mrb_hash_clear(mrb_state *mrb, mrb_value hash) { - seglist *sg = RHASH_TBL(hash); + htable *t = RHASH_TBL(hash); mrb_hash_modify(mrb, hash); - if (sg) { - sg_free(mrb, sg); + if (t) { + ht_free(mrb, t); RHASH_TBL(hash) = NULL; } return hash; @@ -1144,19 +1158,19 @@ mrb_hash_aset(mrb_state *mrb, mrb_value self) static mrb_value mrb_hash_size_m(mrb_state *mrb, mrb_value self) { - seglist *sg = RHASH_TBL(self); + htable *t = RHASH_TBL(self); - if (!sg) return mrb_fixnum_value(0); - return mrb_fixnum_value(sg_size(mrb, sg)); + if (!t) return mrb_fixnum_value(0); + return mrb_fixnum_value(t->size); } MRB_API mrb_bool mrb_hash_empty_p(mrb_state *mrb, mrb_value self) { - seglist *sg = RHASH_TBL(self); + htable *t = RHASH_TBL(self); - if (!sg) return TRUE; - return sg_size(mrb, sg) == 0; + if (!t) return TRUE; + return t->size == 0; } /* 15.2.13.4.12 */ @@ -1212,14 +1226,14 @@ hash_keys_i(mrb_state *mrb, mrb_value key, mrb_value val, void *p) MRB_API mrb_value mrb_hash_keys(mrb_state *mrb, mrb_value hash) { - seglist *sg = RHASH_TBL(hash); - size_t size; + htable *t = RHASH_TBL(hash); + mrb_int size; mrb_value ary; - if (!sg || (size = sg_size(mrb, sg)) == 0) + if (!t || (size = t->size) == 0) return mrb_ary_new(mrb); ary = mrb_ary_new_capa(mrb, size); - sg_foreach(mrb, sg, hash_keys_i, (void*)&ary); + ht_foreach(mrb, t, hash_keys_i, (void*)&ary); return ary; } @@ -1246,14 +1260,14 @@ hash_vals_i(mrb_state *mrb, mrb_value key, mrb_value val, void *p) MRB_API mrb_value mrb_hash_values(mrb_state *mrb, mrb_value hash) { - seglist *sg = RHASH_TBL(hash); - size_t size; + htable *t = RHASH_TBL(hash); + mrb_int size; mrb_value ary; - if (!sg || (size = sg_size(mrb, sg)) == 0) + if (!t || (size = t->size) == 0) return mrb_ary_new(mrb); ary = mrb_ary_new_capa(mrb, size); - sg_foreach(mrb, sg, hash_vals_i, (void*)&ary); + ht_foreach(mrb, t, hash_vals_i, (void*)&ary); return ary; } @@ -1279,10 +1293,10 @@ mrb_hash_values(mrb_state *mrb, mrb_value hash) MRB_API mrb_bool mrb_hash_key_p(mrb_state *mrb, mrb_value hash, mrb_value key) { - seglist *sg; + htable *t; - sg = RHASH_TBL(hash); - if (sg_get(mrb, sg, key, NULL)) { + t = RHASH_TBL(hash); + if (ht_get(mrb, t, key, NULL)) { return TRUE; } return FALSE; @@ -1340,23 +1354,23 @@ mrb_hash_has_value(mrb_state *mrb, mrb_value hash) mrb_get_args(mrb, "o", &val); arg.found = FALSE; arg.val = val; - sg_foreach(mrb, RHASH_TBL(hash), hash_has_value_i, &arg); + ht_foreach(mrb, RHASH_TBL(hash), hash_has_value_i, &arg); return mrb_bool_value(arg.found); } static int merge_i(mrb_state *mrb, mrb_value key, mrb_value val, void *data) { - seglist *h1 = (seglist*)data; + htable *h1 = (htable*)data; - sg_put(mrb, h1, key, val); + ht_put(mrb, h1, key, val); return 0; } MRB_API void mrb_hash_merge(mrb_state *mrb, mrb_value hash1, mrb_value hash2) { - seglist *h1, *h2; + htable *h1, *h2; mrb_hash_modify(mrb, hash1); hash2 = mrb_ensure_hash_type(mrb, hash2); @@ -1365,10 +1379,10 @@ mrb_hash_merge(mrb_state *mrb, mrb_value hash1, mrb_value hash2) if (!h2) return; if (!h1) { - RHASH_TBL(hash1) = sg_copy(mrb, h2); + RHASH_TBL(hash1) = ht_copy(mrb, h2); return; } - sg_foreach(mrb, h2, merge_i, h1); + ht_foreach(mrb, h2, merge_i, h1); mrb_write_barrier(mrb, (struct RBasic*)RHASH(hash1)); return; } @@ -1389,7 +1403,7 @@ mrb_hash_merge(mrb_state *mrb, mrb_value hash1, mrb_value hash2) static mrb_value mrb_hash_rehash(mrb_state *mrb, mrb_value self) { - sg_compact(mrb, RHASH_TBL(self)); + ht_compact(mrb, RHASH_TBL(self)); return self; } -- cgit v1.2.3 From cab6b0f39b77098425b1c3c80e8e1d193d5882c8 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Mon, 19 Nov 2018 09:49:20 +0900 Subject: Protect Fiber from GC in `ecall()`; fix #4104 --- src/vm.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/vm.c b/src/vm.c index 2b88b0761..b899a2d70 100644 --- a/src/vm.c +++ b/src/vm.c @@ -364,6 +364,9 @@ ecall(mrb_state *mrb) if (exc) { mrb_gc_protect(mrb, mrb_obj_value(exc)); } + if (mrb->c->fib) { + mrb_gc_protect(mrb, mrb_obj_value(mrb->c->fib)); + } mrb_run(mrb, p, env->stack[0]); mrb->c = c; c->ci = c->cibase + cioff; -- cgit v1.2.3 From 31a961acf16b7a9454ccb0f0ece91b79e95f7078 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Mon, 19 Nov 2018 09:50:31 +0900 Subject: The current context may be changed in `mrb_vm_exec`; ref #3668 #4104 --- src/vm.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/vm.c b/src/vm.c index b899a2d70..2d12df4ba 100644 --- a/src/vm.c +++ b/src/vm.c @@ -973,15 +973,15 @@ mrb_vm_run(mrb_state *mrb, struct RProc *proc, mrb_value self, unsigned int stac stack_clear(c->stack + stack_keep, nregs - stack_keep); c->stack[0] = self; result = mrb_vm_exec(mrb, proc, irep->iseq); - if (c->ci - c->cibase > cioff) { - c->ci = c->cibase + cioff; - } if (mrb->c != c) { if (mrb->c->fib) { mrb_write_barrier(mrb, (struct RBasic*)mrb->c->fib); } mrb->c = c; } + else if (c->ci - c->cibase > cioff) { + c->ci = c->cibase + cioff; + } return result; } -- cgit v1.2.3 From 0a0cc5a217b577dfadddfb250d5a91ca69978887 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Mon, 19 Nov 2018 10:40:07 +0900 Subject: Check method existence for Enumerators; fix #3920 The issue #3920 was fixed but the fundamental flaw of lack of stack depth check along with fibers still remains, even though it's not easy to cause the issue. Use `MRB_GC_FIXED_ARENA` to avoid the issue for workaround. After this patch, `obj.to_enum` raises `ArgumentError` if the object does not respond to the enumerating method. This is incompatible to CRuby but I think this behavior is better and CRuby should be updated to behave like this. --- mrbgems/mruby-enum-lazy/mrblib/lazy.rb | 2 +- mrbgems/mruby-enumerator/mrblib/enumerator.rb | 3 +++ mrbgems/mruby-enumerator/test/enumerator.rb | 3 +-- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/mrbgems/mruby-enum-lazy/mrblib/lazy.rb b/mrbgems/mruby-enum-lazy/mrblib/lazy.rb index 9227abe8a..e4f116a93 100644 --- a/mrbgems/mruby-enum-lazy/mrblib/lazy.rb +++ b/mrbgems/mruby-enum-lazy/mrblib/lazy.rb @@ -44,7 +44,7 @@ class Enumerator def to_enum(meth=:each, *args, &block) unless self.respond_to?(meth) - raise NoMethodError, "undefined method #{meth}" + raise ArgumentError, "undefined method #{meth}" end lz = Lazy.new(self, &block) lz.obj = self diff --git a/mrbgems/mruby-enumerator/mrblib/enumerator.rb b/mrbgems/mruby-enumerator/mrblib/enumerator.rb index 7ca1d5eb6..dbc7d3004 100644 --- a/mrbgems/mruby-enumerator/mrblib/enumerator.rb +++ b/mrbgems/mruby-enumerator/mrblib/enumerator.rb @@ -614,6 +614,9 @@ module Kernel # enum.first(4) # => [1, 1, 1, 2] # def to_enum(meth=:each, *args) + unless self.respond_to?(meth) + raise ArgumentError, "undefined method #{meth}" + end Enumerator.new self, meth, *args end alias enum_for to_enum diff --git a/mrbgems/mruby-enumerator/test/enumerator.rb b/mrbgems/mruby-enumerator/test/enumerator.rb index 428ea0307..ef4970883 100644 --- a/mrbgems/mruby-enumerator/test/enumerator.rb +++ b/mrbgems/mruby-enumerator/test/enumerator.rb @@ -22,8 +22,7 @@ assert 'Enumerator.new' do assert_equal [1,2,3], Enumerator.new(@obj, :foo, 1,2,3).to_a assert_equal [1,2,3], Enumerator.new { |y| i = 0; loop { y << (i += 1) } }.take(3) assert_raise(ArgumentError) { Enumerator.new } - enum = @obj.to_enum - assert_raise(NoMethodError) { enum.each {} } + assert_raise(ArgumentError) { @obj.to_enum } # examples fib = Enumerator.new do |y| -- cgit v1.2.3 From 426c1f9e0b77a27d5384ccdee7f7a49eef0e2ed0 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Mon, 19 Nov 2018 11:28:03 +0900 Subject: fix non-ASCII comment. --- mrbgems/mruby-array-ext/mrblib/array.rb | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/mrbgems/mruby-array-ext/mrblib/array.rb b/mrbgems/mruby-array-ext/mrblib/array.rb index ed3f591fe..42da0207e 100644 --- a/mrbgems/mruby-array-ext/mrblib/array.rb +++ b/mrbgems/mruby-array-ext/mrblib/array.rb @@ -1,4 +1,3 @@ -# coding: cp932 class Array ## # call-seq: @@ -927,7 +926,7 @@ class Array # # Assumes that self is an array of arrays and transposes the rows and columns. # - # If the length of the subarrays don’t match, an IndexError is raised. + # If the length of the subarrays don't match, an IndexError is raised. # # Examples: # -- cgit v1.2.3 From afca99a40b8a3415b3a9a0e8fc41c93ddcbb11d8 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Wed, 19 Sep 2018 20:53:32 +0900 Subject: Remove implicit conversion using `to_int` method. The ISO standard does not include implicit type conversion using `to_int`. This implicit conversion often causes vulnerability. There will be no more attacks like #4120. In addition, we have added internal convenience method `__to_int` which does type check and conversion (from floats). --- include/mruby.h | 1 - mrbgems/mruby-enum-ext/mrblib/enum.rb | 27 +++++-------- mrbgems/mruby-enumerator/mrblib/enumerator.rb | 8 ++-- mrbgems/mruby-enumerator/test/enumerator.rb | 6 --- mrbgems/mruby-kernel-ext/src/kernel.c | 5 +-- mrbgems/mruby-numeric-ext/src/numeric_ext.c | 17 ++++---- mrbgems/mruby-pack/src/pack.c | 6 ++- mrbgems/mruby-random/src/random.c | 12 +++--- mrbgems/mruby-random/test/random.rb | 12 ------ mrbgems/mruby-range-ext/mrblib/range.rb | 5 +-- mrbgems/mruby-string-ext/test/string.rb | 12 ------ mrblib/array.rb | 2 +- src/kernel.c | 2 + src/numeric.c | 4 -- src/object.c | 57 ++++++++------------------- 15 files changed, 51 insertions(+), 125 deletions(-) diff --git a/include/mruby.h b/include/mruby.h index 8eff31746..33597101a 100644 --- a/include/mruby.h +++ b/include/mruby.h @@ -716,7 +716,6 @@ MRB_API mrb_value mrb_notimplement_m(mrb_state*, mrb_value); * @return [mrb_value] The newly duplicated object. */ MRB_API mrb_value mrb_obj_dup(mrb_state *mrb, mrb_value obj); -MRB_API mrb_value mrb_check_to_integer(mrb_state *mrb, mrb_value val, const char *method); /** * Returns true if obj responds to the given method. If the method was defined for that diff --git a/mrbgems/mruby-enum-ext/mrblib/enum.rb b/mrbgems/mruby-enum-ext/mrblib/enum.rb index ba92decee..fedf8b1ae 100644 --- a/mrbgems/mruby-enum-ext/mrblib/enum.rb +++ b/mrbgems/mruby-enum-ext/mrblib/enum.rb @@ -13,10 +13,9 @@ module Enumerable # a.drop(3) #=> [4, 5, 0] def drop(n) - raise TypeError, "no implicit conversion of #{n.class} into Integer" unless n.respond_to?(:to_int) + n = n.__to_int raise ArgumentError, "attempt to drop negative size" if n < 0 - n = n.to_int ary = [] self.each {|*val| n == 0 ? ary << val.__svalue : n -= 1 } ary @@ -57,8 +56,8 @@ module Enumerable # a.take(3) #=> [1, 2, 3] def take(n) - raise TypeError, "no implicit conversion of #{n.class} into Integer" unless n.respond_to?(:to_int) - i = n.to_int + n = n.__to_int + i = n.to_i raise ArgumentError, "attempt to take negative size" if i < 0 ary = [] return ary if i == 0 @@ -113,12 +112,12 @@ module Enumerable # [8, 9, 10] def each_cons(n, &block) - raise TypeError, "no implicit conversion of #{n.class} into Integer" unless n.respond_to?(:to_int) + n = n.__to_int raise ArgumentError, "invalid size" if n <= 0 return to_enum(:each_cons,n) unless block ary = [] - n = n.to_int + n = n.to_i self.each do |*val| ary.shift if ary.size == n ary << val.__svalue @@ -141,12 +140,12 @@ module Enumerable # [10] def each_slice(n, &block) - raise TypeError, "no implicit conversion of #{n.class} into Integer" unless n.respond_to?(:to_int) + n = n.__to_int raise ArgumentError, "invalid slice size" if n <= 0 return to_enum(:each_slice,n) unless block ary = [] - n = n.to_int + n = n.to_i self.each do |*val| ary << val.__svalue if ary.size == n @@ -223,9 +222,7 @@ module Enumerable end return nil when 1 - n = args[0] - raise TypeError, "no implicit conversion of #{n.class} into Integer" unless n.respond_to?(:to_int) - i = n.to_int + i = args[0].__to_int raise ArgumentError, "attempt to take negative size" if i < 0 ary = [] return ary if i == 0 @@ -673,13 +670,7 @@ module Enumerable if nv.nil? n = -1 else - unless nv.respond_to?(:to_int) - raise TypeError, "no implicit conversion of #{nv.class} into Integer" - end - n = nv.to_int - unless n.kind_of?(Integer) - raise TypeError, "no implicit conversion of #{nv.class} into Integer" - end + n = nv.__to_int return nil if n <= 0 end diff --git a/mrbgems/mruby-enumerator/mrblib/enumerator.rb b/mrbgems/mruby-enumerator/mrblib/enumerator.rb index dbc7d3004..6dd971f3a 100644 --- a/mrbgems/mruby-enumerator/mrblib/enumerator.rb +++ b/mrbgems/mruby-enumerator/mrblib/enumerator.rb @@ -157,12 +157,10 @@ class Enumerator def with_index(offset=0, &block) return to_enum :with_index, offset unless block - offset = if offset.nil? - 0 - elsif offset.respond_to?(:to_int) - offset.to_int + if offset.nil? + offset = 0 else - raise TypeError, "no implicit conversion of #{offset.class} into Integer" + offset = offset.__to_int end n = offset - 1 diff --git a/mrbgems/mruby-enumerator/test/enumerator.rb b/mrbgems/mruby-enumerator/test/enumerator.rb index ef4970883..f3bd1bdba 100644 --- a/mrbgems/mruby-enumerator/test/enumerator.rb +++ b/mrbgems/mruby-enumerator/test/enumerator.rb @@ -54,12 +54,6 @@ assert 'Enumerator#with_index' do assert_equal [[[1, 10], 20], [[2, 11], 21], [[3, 12], 22]], a end -assert 'Enumerator#with_index nonnum offset' do - s = Object.new - def s.to_int; 1 end - assert_equal([[1,1],[2,2],[3,3]], @obj.to_enum(:foo, 1, 2, 3).with_index(s).to_a) -end - assert 'Enumerator#with_index string offset' do assert_raise(TypeError){ @obj.to_enum(:foo, 1, 2, 3).with_index('1').to_a } end diff --git a/mrbgems/mruby-kernel-ext/src/kernel.c b/mrbgems/mruby-kernel-ext/src/kernel.c index 32d86376a..a60e9a210 100644 --- a/mrbgems/mruby-kernel-ext/src/kernel.c +++ b/mrbgems/mruby-kernel-ext/src/kernel.c @@ -93,9 +93,8 @@ mrb_f_method(mrb_state *mrb, mrb_value self) * (0, 0b, and 0x) are honored. * In any case, strings should be strictly conformed to numeric * representation. This behavior is different from that of - * String#to_i. Non string values will be converted using - * to_int, and to_i. Passing nil - * raises a TypeError. + * String#to_i. Non string values will be treated as integers. + * Passing nil raises a TypeError. * * Integer(123.999) #=> 123 * Integer("0x1a") #=> 26 diff --git a/mrbgems/mruby-numeric-ext/src/numeric_ext.c b/mrbgems/mruby-numeric-ext/src/numeric_ext.c index 1d6a07769..cd8bbf187 100644 --- a/mrbgems/mruby-numeric-ext/src/numeric_ext.c +++ b/mrbgems/mruby-numeric-ext/src/numeric_ext.c @@ -2,13 +2,10 @@ #include static inline mrb_int -to_int(mrb_value x) +to_int(mrb_state *mrb, mrb_value x) { - double f; - - if (mrb_fixnum_p(x)) return mrb_fixnum(x); - f = mrb_float(x); - return (mrb_int)f; + x = mrb_to_int(mrb, x); + return mrb_fixnum(x); } /* @@ -28,7 +25,7 @@ mrb_int_chr(mrb_state *mrb, mrb_value x) mrb_int chr; char c; - chr = to_int(x); + chr = to_int(mrb, x); if (chr >= (1 << CHAR_BIT)) { mrb_raisef(mrb, E_RANGE_ERROR, "%S out of char range", x); } @@ -48,8 +45,8 @@ mrb_int_allbits(mrb_state *mrb, mrb_value self) { mrb_int n, m; - n = to_int(self); mrb_get_args(mrb, "i", &m); + n = to_int(mrb, self); return mrb_bool_value((n & m) == m); } @@ -64,8 +61,8 @@ mrb_int_anybits(mrb_state *mrb, mrb_value self) { mrb_int n, m; - n = to_int(self); mrb_get_args(mrb, "i", &m); + n = to_int(mrb, self); return mrb_bool_value((n & m) != 0); } @@ -80,8 +77,8 @@ mrb_int_nobits(mrb_state *mrb, mrb_value self) { mrb_int n, m; - n = to_int(self); mrb_get_args(mrb, "i", &m); + n = to_int(mrb, self); return mrb_bool_value((n & m) == 0); } diff --git a/mrbgems/mruby-pack/src/pack.c b/mrbgems/mruby-pack/src/pack.c index 796ba4d34..5caf7b62b 100644 --- a/mrbgems/mruby-pack/src/pack.c +++ b/mrbgems/mruby-pack/src/pack.c @@ -1124,14 +1124,16 @@ mrb_pack_pack(mrb_state *mrb, mrb_value ary) o = mrb_ary_ref(mrb, ary, aidx); if (type == PACK_TYPE_INTEGER) { o = mrb_to_int(mrb, o); + } #ifndef MRB_WITHOUT_FLOAT - } else if (type == PACK_TYPE_FLOAT) { + else if (type == PACK_TYPE_FLOAT) { if (!mrb_float_p(o)) { mrb_float f = mrb_to_flo(mrb, o); o = mrb_float_value(mrb, f); } + } #endif - } else if (type == PACK_TYPE_STRING) { + else if (type == PACK_TYPE_STRING) { if (!mrb_string_p(o)) { mrb_raisef(mrb, E_TYPE_ERROR, "can't convert %S into String", mrb_class_path(mrb, mrb_obj_class(mrb, o))); } diff --git a/mrbgems/mruby-random/src/random.c b/mrbgems/mruby-random/src/random.c index 5b926a228..68209840a 100644 --- a/mrbgems/mruby-random/src/random.c +++ b/mrbgems/mruby-random/src/random.c @@ -79,12 +79,12 @@ get_opt(mrb_state* mrb) mrb_get_args(mrb, "|o", &arg); if (!mrb_nil_p(arg)) { - arg = mrb_check_convert_type(mrb, arg, MRB_TT_FIXNUM, "Fixnum", "to_int"); - if (mrb_nil_p(arg)) { - mrb_raise(mrb, E_ARGUMENT_ERROR, "invalid argument type"); - } - if (mrb_fixnum(arg) < 0) { - arg = mrb_fixnum_value(0 - mrb_fixnum(arg)); + mrb_int i; + + arg = mrb_to_int(mrb, arg); + i = mrb_fixnum(arg); + if (i < 0) { + arg = mrb_fixnum_value(0 - i); } } return arg; diff --git a/mrbgems/mruby-random/test/random.rb b/mrbgems/mruby-random/test/random.rb index 1c59be3a6..1653ae4a6 100644 --- a/mrbgems/mruby-random/test/random.rb +++ b/mrbgems/mruby-random/test/random.rb @@ -74,15 +74,3 @@ assert('Array#shuffle!(random)') do ary1 != [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] and 10.times { |x| ary1.include? x } and ary1 == ary2 end - -assert('Array#sample checks input length after reading arguments') do - $ary = [1, 2, 3] - class ArrayChange - def to_i - $ary << 4 - 4 - end - end - - assert_equal [1, 2, 3, 4], $ary.sample(ArrayChange.new).sort -end diff --git a/mrbgems/mruby-range-ext/mrblib/range.rb b/mrbgems/mruby-range-ext/mrblib/range.rb index e5d1fb079..de7925ba7 100644 --- a/mrbgems/mruby-range-ext/mrblib/range.rb +++ b/mrbgems/mruby-range-ext/mrblib/range.rb @@ -15,10 +15,7 @@ class Range raise ArgumentError, "wrong number of arguments (given #{args.length}, expected 1)" unless args.length == 1 nv = args[0] - raise TypeError, "no implicit conversion from nil to integer" if nv.nil? - raise TypeError, "no implicit conversion of #{nv.class} into Integer" unless nv.respond_to?(:to_int) - n = nv.to_int - raise TypeError, "no implicit conversion of #{nv.class} into Integer" unless n.kind_of?(Integer) + n = nv.__to_int raise ArgumentError, "negative array size (or size too big)" unless 0 <= n ary = [] each do |i| diff --git a/mrbgems/mruby-string-ext/test/string.rb b/mrbgems/mruby-string-ext/test/string.rb index f0f8be6b3..781506949 100644 --- a/mrbgems/mruby-string-ext/test/string.rb +++ b/mrbgems/mruby-string-ext/test/string.rb @@ -31,18 +31,6 @@ assert('String#setbyte') do assert_equal("Hello", str1) end -assert("String#setbyte raises IndexError if arg conversion resizes String") do - $s = "01234\n" - class Tmp - def to_i - $s.chomp! '' - 95 - end - end - tmp = Tmp.new - assert_raise(IndexError) { $s.setbyte(5, tmp) } -end - assert('String#byteslice') do str1 = "hello" assert_equal("e", str1.byteslice(1)) diff --git a/mrblib/array.rb b/mrblib/array.rb index 53d880660..a677b2a1f 100644 --- a/mrblib/array.rb +++ b/mrblib/array.rb @@ -66,7 +66,7 @@ class Array # # ISO 15.2.12.5.15 def initialize(size=0, obj=nil, &block) - raise TypeError, "expected Integer for 1st argument" unless size.kind_of? Integral + size = size.__to_int raise ArgumentError, "negative array size" if size < 0 self.clear diff --git a/src/kernel.c b/src/kernel.c index db681d510..195594d6b 100644 --- a/src/kernel.c +++ b/src/kernel.c @@ -830,6 +830,7 @@ mrb_obj_ceqq(mrb_state *mrb, mrb_value self) } mrb_value mrb_obj_equal_m(mrb_state *mrb, mrb_value); + void mrb_init_kernel(mrb_state *mrb) { @@ -871,6 +872,7 @@ mrb_init_kernel(mrb_state *mrb) mrb_define_method(mrb, krn, "respond_to?", obj_respond_to, MRB_ARGS_ANY()); /* 15.3.1.3.43 */ mrb_define_method(mrb, krn, "to_s", mrb_any_to_s, MRB_ARGS_NONE()); /* 15.3.1.3.46 */ mrb_define_method(mrb, krn, "__case_eqq", mrb_obj_ceqq, MRB_ARGS_REQ(1)); /* internal */ + mrb_define_method(mrb, krn, "__to_int", mrb_to_int, MRB_ARGS_NONE()); /* internal */ mrb_define_method(mrb, krn, "class_defined?", mrb_krn_class_defined, MRB_ARGS_REQ(1)); diff --git a/src/numeric.c b/src/numeric.c index f7f0318e8..3624831cc 100644 --- a/src/numeric.c +++ b/src/numeric.c @@ -674,7 +674,6 @@ flo_round(mrb_state *mrb, mrb_value num) /* * call-seq: * flt.to_i -> integer - * flt.to_int -> integer * flt.truncate -> integer * * Returns flt truncated to an Integer. @@ -714,7 +713,6 @@ flo_nan_p(mrb_state *mrb, mrb_value num) /* * call-seq: * int.to_i -> integer - * int.to_int -> integer * * As int is already an Integer, all these * methods simply return the receiver. @@ -1513,7 +1511,6 @@ mrb_init_numeric(mrb_state *mrb) MRB_SET_INSTANCE_TT(integer, MRB_TT_FIXNUM); mrb_undef_class_method(mrb, integer, "new"); mrb_define_method(mrb, integer, "to_i", int_to_i, MRB_ARGS_NONE()); /* 15.2.8.3.24 */ - mrb_define_method(mrb, integer, "to_int", int_to_i, MRB_ARGS_NONE()); #ifndef MRB_WITHOUT_FLOAT mrb_define_method(mrb, integer, "ceil", int_to_i, MRB_ARGS_REQ(1)); /* 15.2.8.3.8 (x) */ mrb_define_method(mrb, integer, "floor", int_to_i, MRB_ARGS_REQ(1)); /* 15.2.8.3.10 (x) */ @@ -1565,7 +1562,6 @@ mrb_init_numeric(mrb_state *mrb) mrb_define_method(mrb, fl, "round", flo_round, MRB_ARGS_OPT(1)); /* 15.2.9.3.12 */ mrb_define_method(mrb, fl, "to_f", flo_to_f, MRB_ARGS_NONE()); /* 15.2.9.3.13 */ mrb_define_method(mrb, fl, "to_i", flo_truncate, MRB_ARGS_NONE()); /* 15.2.9.3.14 */ - mrb_define_method(mrb, fl, "to_int", flo_truncate, MRB_ARGS_NONE()); mrb_define_method(mrb, fl, "truncate", flo_truncate, MRB_ARGS_NONE()); /* 15.2.9.3.15 */ mrb_define_method(mrb, fl, "divmod", flo_divmod, MRB_ARGS_REQ(1)); mrb_define_method(mrb, fl, "eql?", flo_eql, MRB_ARGS_REQ(1)); /* 15.2.8.3.16 */ diff --git a/src/object.c b/src/object.c index 8724c5416..ba6fa3947 100644 --- a/src/object.c +++ b/src/object.c @@ -322,19 +322,6 @@ convert_type(mrb_state *mrb, mrb_value val, const char *tname, const char *metho return mrb_funcall_argv(mrb, val, m, 0, 0); } -MRB_API mrb_value -mrb_check_to_integer(mrb_state *mrb, mrb_value val, const char *method) -{ - mrb_value v; - - if (mrb_fixnum_p(val)) return val; - v = convert_type(mrb, val, "Integer", method, FALSE); - if (mrb_nil_p(v) || !mrb_fixnum_p(v)) { - return mrb_nil_value(); - } - return v; -} - MRB_API mrb_value mrb_convert_type(mrb_state *mrb, mrb_value val, enum mrb_vtype type, const char *tname, const char *method) { @@ -505,25 +492,22 @@ mrb_obj_is_kind_of(mrb_state *mrb, mrb_value obj, struct RClass *c) return FALSE; } -static mrb_value -mrb_to_integer(mrb_state *mrb, mrb_value val, const char *method) -{ - mrb_value v; - - if (mrb_fixnum_p(val)) return val; - v = convert_type(mrb, val, "Integer", method, TRUE); - if (!mrb_obj_is_kind_of(mrb, v, mrb->fixnum_class)) { - mrb_value type = inspect_type(mrb, val); - mrb_raisef(mrb, E_TYPE_ERROR, "can't convert %S to Integer (%S#%S gives %S)", - type, type, mrb_str_new_cstr(mrb, method), inspect_type(mrb, v)); - } - return v; -} - MRB_API mrb_value mrb_to_int(mrb_state *mrb, mrb_value val) { - return mrb_to_integer(mrb, val, "to_int"); + + if (!mrb_fixnum_p(val)) { + mrb_value type; + +#ifndef MRB_WITHOUT_FLOAT + if (mrb_float_p(val)) { + return mrb_flo_to_fixnum(mrb, val); + } +#endif + type = inspect_type(mrb, val); + mrb_raisef(mrb, E_TYPE_ERROR, "can't convert %S to Integer", type); + } + return val; } MRB_API mrb_value @@ -533,18 +517,12 @@ mrb_convert_to_integer(mrb_state *mrb, mrb_value val, mrb_int base) if (mrb_nil_p(val)) { if (base != 0) goto arg_error; - mrb_raise(mrb, E_TYPE_ERROR, "can't convert nil into Integer"); + mrb_raise(mrb, E_TYPE_ERROR, "can't convert nil into Integer"); } switch (mrb_type(val)) { #ifndef MRB_WITHOUT_FLOAT case MRB_TT_FLOAT: if (base != 0) goto arg_error; - else { - mrb_float f = mrb_float(val); - if (FIXABLE_FLOAT(f)) { - break; - } - } return mrb_flo_to_fixnum(mrb, val); #endif @@ -568,11 +546,8 @@ mrb_convert_to_integer(mrb_state *mrb, mrb_value val, mrb_int base) arg_error: mrb_raise(mrb, E_ARGUMENT_ERROR, "base specified for non string value"); } - tmp = convert_type(mrb, val, "Integer", "to_int", FALSE); - if (mrb_nil_p(tmp) || !mrb_fixnum_p(tmp)) { - tmp = mrb_to_integer(mrb, val, "to_i"); - } - return tmp; + /* to raise TypeError */ + return mrb_to_int(mrb, val); } MRB_API mrb_value -- cgit v1.2.3 From ff08856fe314faa4d16b4502c0960a3475387846 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Wed, 19 Sep 2018 21:51:53 +0900 Subject: Remove implicit conversion using `to_str` method; fix #3854 We have added internal convenience method `__to_str` which does string type check. The issue #3854 was fixed but fundamental flaw of lack of stack depth check along with fibers still remains. Use `MRB_GC_FIXED_ARENA` for workaround. --- include/mruby.h | 5 +--- include/mruby/string.h | 3 +-- mrbgems/mruby-io/src/file.c | 2 +- mrbgems/mruby-kernel-ext/src/kernel.c | 8 ++----- mrbgems/mruby-string-ext/mrblib/string.rb | 6 ++--- mrbgems/mruby-string-ext/src/string.c | 6 ++--- mrbgems/mruby-string-ext/test/string.rb | 11 --------- mrblib/string.rb | 11 ++++----- src/class.c | 11 +++++++-- src/kernel.c | 39 +++++-------------------------- src/object.c | 27 +++++++++++++++++++++ src/string.c | 32 ++----------------------- test/t/string.rb | 13 ----------- 13 files changed, 60 insertions(+), 114 deletions(-) diff --git a/include/mruby.h b/include/mruby.h index 33597101a..12df9cd5a 100644 --- a/include/mruby.h +++ b/include/mruby.h @@ -854,10 +854,6 @@ typedef const char *mrb_args_format; /** * Retrieve arguments from mrb_state. * - * When applicable, implicit conversions (such as `to_str`, `to_ary`, `to_hash`) are - * applied to received arguments. - * Used inside a function of mrb_func_t type. - * * @param mrb The current MRuby state. * @param format [mrb_args_format] is a list of format specifiers * @param ... The passing variadic arguments must be a pointer of retrieving type. @@ -1187,6 +1183,7 @@ MRB_API void mrb_gc_unregister(mrb_state *mrb, mrb_value obj); MRB_API mrb_value mrb_to_int(mrb_state *mrb, mrb_value val); #define mrb_int(mrb, val) mrb_fixnum(mrb_to_int(mrb, val)) +MRB_API mrb_value mrb_to_str(mrb_state *mrb, mrb_value val); MRB_API void mrb_check_type(mrb_state *mrb, mrb_value x, enum mrb_vtype t); typedef enum call_type { diff --git a/include/mruby/string.h b/include/mruby/string.h index 481b2fb38..fa1955f48 100644 --- a/include/mruby/string.h +++ b/include/mruby/string.h @@ -311,8 +311,7 @@ MRB_API mrb_value mrb_str_substr(mrb_state *mrb, mrb_value str, mrb_int beg, mrb * @param [mrb_value] str Ruby string. * @return [mrb_value] A Ruby string. */ -MRB_API mrb_value mrb_string_type(mrb_state *mrb, mrb_value str); - +MRB_API mrb_value mrb_ensure_string_type(mrb_state *mrb, mrb_value str); MRB_API mrb_value mrb_check_string_type(mrb_state *mrb, mrb_value str); MRB_API mrb_value mrb_str_new_capa(mrb_state *mrb, size_t capa); MRB_API mrb_value mrb_str_buf_new(mrb_state *mrb, size_t capa); diff --git a/mrbgems/mruby-io/src/file.c b/mrbgems/mruby-io/src/file.c index e65741061..c00663481 100644 --- a/mrbgems/mruby-io/src/file.c +++ b/mrbgems/mruby-io/src/file.c @@ -115,7 +115,7 @@ mrb_file_s_unlink(mrb_state *mrb, mrb_value obj) mrb_get_args(mrb, "*", &argv, &argc); for (i = 0; i < argc; i++) { const char *utf8_path; - pathv = mrb_convert_type(mrb, argv[i], MRB_TT_STRING, "String", "to_str"); + pathv = mrb_ensure_string_type(mrb, argv[i]); utf8_path = mrb_string_value_cstr(mrb, &pathv); path = mrb_locale_from_utf8(utf8_path, -1); if (UNLINK(path) < 0) { diff --git a/mrbgems/mruby-kernel-ext/src/kernel.c b/mrbgems/mruby-kernel-ext/src/kernel.c index a60e9a210..bc2656399 100644 --- a/mrbgems/mruby-kernel-ext/src/kernel.c +++ b/mrbgems/mruby-kernel-ext/src/kernel.c @@ -141,8 +141,7 @@ mrb_f_float(mrb_state *mrb, mrb_value self) * String(arg) -> string * * Returns arg as an String. - * - * First tries to call its to_str method, then its to_s method. + * converted using to_s method. * * String(self) #=> "main" * String(self.class) #=> "Object" @@ -154,10 +153,7 @@ mrb_f_string(mrb_state *mrb, mrb_value self) mrb_value arg, tmp; mrb_get_args(mrb, "o", &arg); - tmp = mrb_check_convert_type(mrb, arg, MRB_TT_STRING, "String", "to_str"); - if (mrb_nil_p(tmp)) { - tmp = mrb_check_convert_type(mrb, arg, MRB_TT_STRING, "String", "to_s"); - } + tmp = mrb_convert_type(mrb, arg, MRB_TT_STRING, "String", "to_s"); return tmp; } diff --git a/mrbgems/mruby-string-ext/mrblib/string.rb b/mrbgems/mruby-string-ext/mrblib/string.rb index 27ca30610..9212d83a5 100644 --- a/mrbgems/mruby-string-ext/mrblib/string.rb +++ b/mrbgems/mruby-string-ext/mrblib/string.rb @@ -12,8 +12,8 @@ class String # String.try_convert(/re/) #=> nil # def self.try_convert(obj) - if obj.respond_to?(:to_str) - obj.to_str + if self === obj + obj else nil end @@ -142,7 +142,7 @@ class String # "abcdef".casecmp("ABCDEF") #=> 0 # def casecmp(str) - self.downcase <=> str.to_str.downcase + self.downcase <=> str.__to_str.downcase rescue NoMethodError nil end diff --git a/mrbgems/mruby-string-ext/src/string.c b/mrbgems/mruby-string-ext/src/string.c index 6d661c352..ba7e3c610 100644 --- a/mrbgems/mruby-string-ext/src/string.c +++ b/mrbgems/mruby-string-ext/src/string.c @@ -163,7 +163,7 @@ mrb_str_concat_m(mrb_state *mrb, mrb_value self) if (mrb_fixnum_p(str)) str = mrb_fixnum_chr(mrb, str); else - str = mrb_string_type(mrb, str); + str = mrb_ensure_string_type(mrb, str); mrb_str_concat(mrb, self, str); return self; } @@ -191,7 +191,7 @@ mrb_str_start_with(mrb_state *mrb, mrb_value self) for (i = 0; i < argc; i++) { size_t len_l, len_r; int ai = mrb_gc_arena_save(mrb); - sub = mrb_string_type(mrb, argv[i]); + sub = mrb_ensure_string_type(mrb, argv[i]); mrb_gc_arena_restore(mrb, ai); len_l = RSTRING_LEN(self); len_r = RSTRING_LEN(sub); @@ -220,7 +220,7 @@ mrb_str_end_with(mrb_state *mrb, mrb_value self) for (i = 0; i < argc; i++) { size_t len_l, len_r; int ai = mrb_gc_arena_save(mrb); - sub = mrb_string_type(mrb, argv[i]); + sub = mrb_ensure_string_type(mrb, argv[i]); mrb_gc_arena_restore(mrb, ai); len_l = RSTRING_LEN(self); len_r = RSTRING_LEN(sub); diff --git a/mrbgems/mruby-string-ext/test/string.rb b/mrbgems/mruby-string-ext/test/string.rb index 781506949..4ccdfd6c3 100644 --- a/mrbgems/mruby-string-ext/test/string.rb +++ b/mrbgems/mruby-string-ext/test/string.rb @@ -114,12 +114,6 @@ assert('String#concat') do assert_equal "Hello World!", "Hello " << "World" << 33 assert_equal "Hello World!", "Hello ".concat("World").concat(33) - o = Object.new - def o.to_str - "to_str" - end - assert_equal "hi to_str", "hi " << o - assert_raise(TypeError) { "".concat(Object.new) } end @@ -128,11 +122,6 @@ assert('String#casecmp') do assert_equal 0, "aBcDeF".casecmp("abcdef") assert_equal(-1, "abcdef".casecmp("abcdefg")) assert_equal 0, "abcdef".casecmp("ABCDEF") - o = Object.new - def o.to_str - "ABCDEF" - end - assert_equal 0, "abcdef".casecmp(o) end assert('String#count') do diff --git a/mrblib/string.rb b/mrblib/string.rb index 07b80b340..397603e9d 100644 --- a/mrblib/string.rb +++ b/mrblib/string.rb @@ -12,7 +12,7 @@ class String def each_line(rs = "\n", &block) return to_enum(:each_line, rs, &block) unless block return block.call(self) if rs.nil? - rs = rs.to_str + rs = rs.__to_str offset = 0 rs_len = rs.length this = dup @@ -67,7 +67,7 @@ class String block = nil end if !replace.nil? || !block - replace = replace.to_str + replace = replace.__to_str end offset = 0 result = [] @@ -129,12 +129,12 @@ class String end pattern, replace = *args - pattern = pattern.to_str + pattern = pattern.__to_str if args.length == 2 && block block = nil end unless block - replace = replace.to_str + replace = replace.__to_str end result = [] this = dup @@ -245,14 +245,13 @@ class String ## # ISO 15.2.10.5.3 def =~(re) - raise TypeError, "type mismatch: String given" if re.respond_to? :to_str re =~ self end ## # ISO 15.2.10.5.27 def match(re, &block) - if re.respond_to? :to_str + if String === re if Object.const_defined?(:Regexp) r = Regexp.new(re) r.match(self, &block) diff --git a/src/class.c b/src/class.c index 50ab0ea59..90c73104e 100644 --- a/src/class.c +++ b/src/class.c @@ -504,10 +504,17 @@ check_type(mrb_state *mrb, mrb_value val, enum mrb_vtype t, const char *c, const return tmp; } +#define CHECK_TYPE(mrb, val, t, c) do { \ + if (mrb_type(val) != (t)) {\ + mrb_raisef(mrb, E_TYPE_ERROR, "expected %S", mrb_str_new_lit(mrb, c));\ + }\ +} while (0) + static mrb_value to_str(mrb_state *mrb, mrb_value val) { - return check_type(mrb, val, MRB_TT_STRING, "String", "to_str"); + CHECK_TYPE(mrb, val, MRB_TT_STRING, "String"); + return val; } static mrb_value @@ -1972,7 +1979,7 @@ mrb_mod_const_get(mrb_state *mrb, mrb_value mod) } /* const get with class path string */ - path = mrb_string_type(mrb, path); + path = mrb_ensure_string_type(mrb, path); ptr = RSTRING_PTR(path); len = RSTRING_LEN(path); off = 0; diff --git a/src/kernel.c b/src/kernel.c index 195594d6b..ce9cd1d44 100644 --- a/src/kernel.c +++ b/src/kernel.c @@ -746,6 +746,7 @@ basic_obj_respond_to(mrb_state *mrb, mrb_value obj, mrb_sym id, int pub) { return mrb_respond_to(mrb, obj, id); } + /* 15.3.1.3.43 */ /* * call-seq: @@ -765,45 +766,16 @@ basic_obj_respond_to(mrb_state *mrb, mrb_value obj, mrb_sym id, int pub) static mrb_value obj_respond_to(mrb_state *mrb, mrb_value self) { - mrb_value mid; mrb_sym id, rtm_id; - mrb_bool priv = FALSE, respond_to_p = TRUE; - - mrb_get_args(mrb, "o|b", &mid, &priv); - - if (mrb_symbol_p(mid)) { - id = mrb_symbol(mid); - } - else { - mrb_value tmp; - if (mrb_string_p(mid)) { - tmp = mrb_check_intern_str(mrb, mid); - } - else { - tmp = mrb_check_string_type(mrb, mid); - if (mrb_nil_p(tmp)) { - tmp = mrb_inspect(mrb, mid); - mrb_raisef(mrb, E_TYPE_ERROR, "%S is not a symbol", tmp); - } - tmp = mrb_check_intern_str(mrb, tmp); - } - if (mrb_nil_p(tmp)) { - respond_to_p = FALSE; - } - else { - id = mrb_symbol(tmp); - } - } - - if (respond_to_p) { - respond_to_p = basic_obj_respond_to(mrb, self, id, !priv); - } + mrb_bool priv = FALSE, respond_to_p; + mrb_get_args(mrb, "n|b", &id, &priv); + respond_to_p = basic_obj_respond_to(mrb, self, id, !priv); if (!respond_to_p) { rtm_id = mrb_intern_lit(mrb, "respond_to_missing?"); if (basic_obj_respond_to(mrb, self, rtm_id, !priv)) { mrb_value args[2], v; - args[0] = mid; + args[0] = mrb_symbol_value(id); args[1] = mrb_bool_value(priv); v = mrb_funcall_argv(mrb, self, rtm_id, 2, args); return mrb_bool_value(mrb_bool(v)); @@ -873,6 +845,7 @@ mrb_init_kernel(mrb_state *mrb) mrb_define_method(mrb, krn, "to_s", mrb_any_to_s, MRB_ARGS_NONE()); /* 15.3.1.3.46 */ mrb_define_method(mrb, krn, "__case_eqq", mrb_obj_ceqq, MRB_ARGS_REQ(1)); /* internal */ mrb_define_method(mrb, krn, "__to_int", mrb_to_int, MRB_ARGS_NONE()); /* internal */ + mrb_define_method(mrb, krn, "__to_str", mrb_to_str, MRB_ARGS_NONE()); /* internal */ mrb_define_method(mrb, krn, "class_defined?", mrb_krn_class_defined, MRB_ARGS_REQ(1)); diff --git a/src/object.c b/src/object.c index ba6fa3947..18ccacfb9 100644 --- a/src/object.c +++ b/src/object.c @@ -579,6 +579,33 @@ mrb_Float(mrb_state *mrb, mrb_value val) } #endif +MRB_API mrb_value +mrb_to_str(mrb_state *mrb, mrb_value val) +{ + if (!mrb_string_p(val)) { + mrb_value type = inspect_type(mrb, val); + mrb_raisef(mrb, E_TYPE_ERROR, "can't convert %S to String", type); + } + return val; +} + +MRB_API mrb_value +mrb_ensure_string_type(mrb_state *mrb, mrb_value str) +{ + if (!mrb_string_p(str)) { + mrb_raisef(mrb, E_TYPE_ERROR, "%S cannot be converted to String", + inspect_type(mrb, str)); + } + return str; +} + +MRB_API mrb_value +mrb_check_string_type(mrb_state *mrb, mrb_value str) +{ + if (!mrb_string_p(str)) return mrb_nil_value(); + return str; +} + MRB_API mrb_value mrb_inspect(mrb_state *mrb, mrb_value obj) { diff --git a/src/string.c b/src/string.c index b7abfb762..b6d4ecef0 100644 --- a/src/string.c +++ b/src/string.c @@ -956,15 +956,7 @@ str_eql(mrb_state *mrb, const mrb_value str1, const mrb_value str2) MRB_API mrb_bool mrb_str_equal(mrb_state *mrb, mrb_value str1, mrb_value str2) { - if (mrb_immediate_p(str2)) return FALSE; - if (!mrb_string_p(str2)) { - if (mrb_nil_p(str2)) return FALSE; - if (!mrb_respond_to(mrb, str2, mrb_intern_lit(mrb, "to_str"))) { - return FALSE; - } - str2 = mrb_funcall(mrb, str2, "to_str", 0); - return mrb_equal(mrb, str2, str1); - } + if (!mrb_string_p(str2)) return FALSE; return str_eql(mrb, str1, str2); } @@ -992,14 +984,8 @@ mrb_str_equal_m(mrb_state *mrb, mrb_value str1) MRB_API mrb_value mrb_str_to_str(mrb_state *mrb, mrb_value str) { - mrb_value s; - if (!mrb_string_p(str)) { - s = mrb_check_convert_type(mrb, str, MRB_TT_STRING, "String", "to_str"); - if (mrb_nil_p(s)) { - s = mrb_convert_type(mrb, str, MRB_TT_STRING, "String", "to_s"); - } - return s; + return mrb_convert_type(mrb, str, MRB_TT_STRING, "String", "to_s"); } return str; } @@ -1714,18 +1700,6 @@ mrb_ptr_to_str(mrb_state *mrb, void *p) return mrb_obj_value(p_str); } -MRB_API mrb_value -mrb_string_type(mrb_state *mrb, mrb_value str) -{ - return mrb_convert_type(mrb, str, MRB_TT_STRING, "String", "to_str"); -} - -MRB_API mrb_value -mrb_check_string_type(mrb_state *mrb, mrb_value str) -{ - return mrb_check_convert_type(mrb, str, MRB_TT_STRING, "String", "to_str"); -} - /* 15.2.10.5.30 */ /* * call-seq: @@ -2379,7 +2353,6 @@ mrb_str_to_f(mrb_state *mrb, mrb_value self) /* * call-seq: * str.to_s => str - * str.to_str => str * * Returns the receiver. */ @@ -2783,7 +2756,6 @@ mrb_init_string(mrb_state *mrb) #endif mrb_define_method(mrb, s, "to_i", mrb_str_to_i, MRB_ARGS_ANY()); /* 15.2.10.5.39 */ mrb_define_method(mrb, s, "to_s", mrb_str_to_s, MRB_ARGS_NONE()); /* 15.2.10.5.40 */ - mrb_define_method(mrb, s, "to_str", mrb_str_to_s, MRB_ARGS_NONE()); mrb_define_method(mrb, s, "to_sym", mrb_str_intern, MRB_ARGS_NONE()); /* 15.2.10.5.41 */ mrb_define_method(mrb, s, "upcase", mrb_str_upcase, MRB_ARGS_NONE()); /* 15.2.10.5.42 */ mrb_define_method(mrb, s, "upcase!", mrb_str_upcase_bang, MRB_ARGS_NONE()); /* 15.2.10.5.43 */ diff --git a/test/t/string.rb b/test/t/string.rb index e91b915fe..3a1eced16 100644 --- a/test/t/string.rb +++ b/test/t/string.rb @@ -253,19 +253,6 @@ assert('String#chomp!', '15.2.10.5.10') do assert_equal 'abc', e end -assert('String#chomp! uses the correct length') do - class A - def to_str - $s.replace("AA") - "A" - end - end - - $s = "AAA" - $s.chomp!(A.new) - assert_equal $s, "A" -end - assert('String#chop', '15.2.10.5.11') do a = ''.chop b = 'abc'.chop -- cgit v1.2.3 From b5d43a16a38d522aa1d1d1a889585749a6b8086d Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Wed, 19 Sep 2018 21:54:32 +0900 Subject: Removed `String#try_convert` method from `mruby-string-ext` gem. Because `try_convert` method rarely used in production. For mruby users, we have `__to_str` utility method to check string type. --- mrbgems/mruby-string-ext/mrblib/string.rb | 19 ------------------- mrbgems/mruby-string-ext/test/string.rb | 7 ------- 2 files changed, 26 deletions(-) diff --git a/mrbgems/mruby-string-ext/mrblib/string.rb b/mrbgems/mruby-string-ext/mrblib/string.rb index 9212d83a5..2a323c858 100644 --- a/mrbgems/mruby-string-ext/mrblib/string.rb +++ b/mrbgems/mruby-string-ext/mrblib/string.rb @@ -1,24 +1,5 @@ class String - ## - # call-seq: - # String.try_convert(obj) -> string or nil - # - # Try to convert obj into a String, using to_str method. - # Returns converted string or nil if obj cannot be converted - # for any reason. - # - # String.try_convert("str") #=> "str" - # String.try_convert(/re/) #=> nil - # - def self.try_convert(obj) - if self === obj - obj - else - nil - end - end - ## # call-seq: # string.clear -> string diff --git a/mrbgems/mruby-string-ext/test/string.rb b/mrbgems/mruby-string-ext/test/string.rb index 4ccdfd6c3..7c96ab694 100644 --- a/mrbgems/mruby-string-ext/test/string.rb +++ b/mrbgems/mruby-string-ext/test/string.rb @@ -4,13 +4,6 @@ UTF8STRING = ("\343\201\202".size == 1) -assert('String.try_convert') do - assert_nil String.try_convert(nil) - assert_nil String.try_convert(:foo) - assert_equal "", String.try_convert("") - assert_equal "1,2,3", String.try_convert("1,2,3") -end - assert('String#getbyte') do str1 = "hello" bytes1 = [104, 101, 108, 108, 111] -- cgit v1.2.3 From 5bbcea9b3bdb0e7dc048f92cebefb54858196935 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Wed, 19 Sep 2018 22:01:28 +0900 Subject: Removed `try_convert` method from Array and Hash. --- mrbgems/mruby-array-ext/mrblib/array.rb | 25 ------------------------- mrbgems/mruby-array-ext/test/array.rb | 7 ------- mrbgems/mruby-hash-ext/mrblib/hash.rb | 19 ------------------- mrbgems/mruby-hash-ext/test/hash.rb | 6 ------ 4 files changed, 57 deletions(-) diff --git a/mrbgems/mruby-array-ext/mrblib/array.rb b/mrbgems/mruby-array-ext/mrblib/array.rb index 42da0207e..54d62e3fd 100644 --- a/mrbgems/mruby-array-ext/mrblib/array.rb +++ b/mrbgems/mruby-array-ext/mrblib/array.rb @@ -1,29 +1,4 @@ class Array - ## - # call-seq: - # Array.try_convert(obj) -> array or nil - # - # Tries to convert +obj+ into an array, using +to_ary+ method. - # converted array or +nil+ if +obj+ cannot be converted for any reason. - # This method can be used to check if an argument is an array. - # - # Array.try_convert([1]) #=> [1] - # Array.try_convert("1") #=> nil - # - # if tmp = Array.try_convert(arg) - # # the argument is an array - # elsif tmp = String.try_convert(arg) - # # the argument is a string - # end - # - def self.try_convert(obj) - if obj.respond_to?(:to_ary) - obj.to_ary - else - nil - end - end - ## # call-seq: # ary.uniq! -> ary or nil diff --git a/mrbgems/mruby-array-ext/test/array.rb b/mrbgems/mruby-array-ext/test/array.rb index 84f9cfeaf..b7467724c 100644 --- a/mrbgems/mruby-array-ext/test/array.rb +++ b/mrbgems/mruby-array-ext/test/array.rb @@ -1,13 +1,6 @@ ## # Array(Ext) Test -assert("Array.try_convert") do - assert_nil Array.try_convert(0) - assert_nil Array.try_convert(nil) - assert_equal [], Array.try_convert([]) - assert_equal [1,2,3], Array.try_convert([1,2,3]) -end - assert("Array#assoc") do s1 = [ "colors", "red", "blue", "green" ] s2 = [ "letters", "a", "b", "c" ] diff --git a/mrbgems/mruby-hash-ext/mrblib/hash.rb b/mrbgems/mruby-hash-ext/mrblib/hash.rb index 5bbbdf559..f1143e25b 100644 --- a/mrbgems/mruby-hash-ext/mrblib/hash.rb +++ b/mrbgems/mruby-hash-ext/mrblib/hash.rb @@ -60,25 +60,6 @@ class Hash h end - ## - # call-seq: - # Hash.try_convert(obj) -> hash or nil - # - # Try to convert obj into a hash, using to_hash method. - # Returns converted hash or nil if obj cannot be converted - # for any reason. - # - # Hash.try_convert({1=>2}) # => {1=>2} - # Hash.try_convert("1=>2") # => nil - # - def self.try_convert(obj) - if obj.respond_to?(:to_hash) - obj.to_hash - else - nil - end - end - ## # call-seq: # hsh.merge!(other_hash) -> hsh diff --git a/mrbgems/mruby-hash-ext/test/hash.rb b/mrbgems/mruby-hash-ext/test/hash.rb index 269da800d..b5d0aaaf8 100644 --- a/mrbgems/mruby-hash-ext/test/hash.rb +++ b/mrbgems/mruby-hash-ext/test/hash.rb @@ -45,12 +45,6 @@ assert('Hash.[] for sub class') do assert_equal(sub_hash_class, sub_hash.class) end -assert('Hash.try_convert') do - assert_nil Hash.try_convert(nil) - assert_nil Hash.try_convert("{1=>2}") - assert_equal({1=>2}, Hash.try_convert({1=>2})) -end - assert('Hash#merge!') do a = { 'abc_key' => 'abc_value', 'cba_key' => 'cba_value' } b = { 'cba_key' => 'XXX', 'xyz_key' => 'xyz_value' } -- cgit v1.2.3 From 698f5f707c2db334a15c605bf1b0d0cff42b1224 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Wed, 19 Sep 2018 22:19:55 +0900 Subject: Removed `to_ary` conversion method. --- include/mruby/array.h | 1 + mrbgems/mruby-array-ext/mrblib/array.rb | 10 ---------- mrbgems/mruby-array-ext/test/array.rb | 16 ---------------- mrbgems/mruby-enumerator/mrblib/enumerator.rb | 4 +--- mrbgems/mruby-kernel-ext/src/kernel.c | 9 ++------- src/array.c | 27 +++++---------------------- src/class.c | 3 ++- src/object.c | 17 +++++++++++++++++ 8 files changed, 28 insertions(+), 59 deletions(-) diff --git a/include/mruby/array.h b/include/mruby/array.h index 6fffe4512..2457f68f2 100644 --- a/include/mruby/array.h +++ b/include/mruby/array.h @@ -199,6 +199,7 @@ MRB_API void mrb_ary_set(mrb_state *mrb, mrb_value ary, mrb_int n, mrb_value val * @param other The array to replace it with. */ MRB_API void mrb_ary_replace(mrb_state *mrb, mrb_value self, mrb_value other); +MRB_API mrb_value mrb_ensure_array_type(mrb_state *mrb, mrb_value self); MRB_API mrb_value mrb_check_array_type(mrb_state *mrb, mrb_value self); /* diff --git a/mrbgems/mruby-array-ext/mrblib/array.rb b/mrbgems/mruby-array-ext/mrblib/array.rb index 54d62e3fd..bb95d70c5 100644 --- a/mrbgems/mruby-array-ext/mrblib/array.rb +++ b/mrbgems/mruby-array-ext/mrblib/array.rb @@ -772,16 +772,6 @@ class Array nil end - ## - # call-seq: - # ary.to_ary -> ary - # - # Returns +self+. - # - def to_ary - self - end - ## # call-seq: # ary.dig(idx, ...) -> object diff --git a/mrbgems/mruby-array-ext/test/array.rb b/mrbgems/mruby-array-ext/test/array.rb index b7467724c..853554bcc 100644 --- a/mrbgems/mruby-array-ext/test/array.rb +++ b/mrbgems/mruby-array-ext/test/array.rb @@ -331,27 +331,11 @@ assert('Array#to_h') do assert_raise(ArgumentError) { [[1]].to_h } end -assert('Array#to_h (Modified)') do - class A - def to_ary - $a.clear - nil - end - end - $a = [A.new] - assert_raise(TypeError) { $a.to_h } -end - assert("Array#index (block)") do assert_nil (1..10).to_a.index { |i| i % 5 == 0 and i % 7 == 0 } assert_equal 34, (1..100).to_a.index { |i| i % 5 == 0 and i % 7 == 0 } end -assert("Array#to_ary") do - assert_equal [], [].to_ary - assert_equal [1,2,3], [1,2,3].to_ary -end - assert("Array#dig") do h = [[[1]], 0] assert_equal(1, h.dig(0, 0, 0)) diff --git a/mrbgems/mruby-enumerator/mrblib/enumerator.rb b/mrbgems/mruby-enumerator/mrblib/enumerator.rb index 6dd971f3a..9d80bc552 100644 --- a/mrbgems/mruby-enumerator/mrblib/enumerator.rb +++ b/mrbgems/mruby-enumerator/mrblib/enumerator.rb @@ -624,9 +624,7 @@ module Enumerable # use Enumerator to use infinite sequence def zip(*args, &block) args = args.map do |a| - if a.respond_to?(:to_ary) - a.to_ary.to_enum(:each) - elsif a.respond_to?(:each) + if a.respond_to?(:each) a.to_enum(:each) else raise TypeError, "wrong argument type #{a.class} (must respond to :each)" diff --git a/mrbgems/mruby-kernel-ext/src/kernel.c b/mrbgems/mruby-kernel-ext/src/kernel.c index bc2656399..324753f6e 100644 --- a/mrbgems/mruby-kernel-ext/src/kernel.c +++ b/mrbgems/mruby-kernel-ext/src/kernel.c @@ -161,9 +161,7 @@ mrb_f_string(mrb_state *mrb, mrb_value self) * call-seq: * Array(arg) -> array * - * Returns +arg+ as an Array. - * - * First tries to call Array#to_ary on +arg+, then Array#to_a. + * Returns +arg+ as an Array using to_a method. * * Array(1..5) #=> [1, 2, 3, 4, 5] * @@ -174,10 +172,7 @@ mrb_f_array(mrb_state *mrb, mrb_value self) mrb_value arg, tmp; mrb_get_args(mrb, "o", &arg); - tmp = mrb_check_convert_type(mrb, arg, MRB_TT_ARRAY, "Array", "to_ary"); - if (mrb_nil_p(tmp)) { - tmp = mrb_check_convert_type(mrb, arg, MRB_TT_ARRAY, "Array", "to_a"); - } + tmp = mrb_check_convert_type(mrb, arg, MRB_TT_ARRAY, "Array", "to_a"); if (mrb_nil_p(tmp)) { return mrb_ary_new_from_values(mrb, 1, &arg); } diff --git a/src/array.c b/src/array.c index eddd9b2ac..084b48dc0 100644 --- a/src/array.c +++ b/src/array.c @@ -1058,7 +1058,7 @@ mrb_ary_rindex_m(mrb_state *mrb, mrb_value self) MRB_API mrb_value mrb_ary_splat(mrb_state *mrb, mrb_value v) { - mrb_value a, recv_class; + mrb_value a; if (mrb_array_p(v)) { return v; @@ -1069,22 +1069,11 @@ mrb_ary_splat(mrb_state *mrb, mrb_value v) } a = mrb_funcall(mrb, v, "to_a", 0); - if (mrb_array_p(a)) { - return a; - } - else if (mrb_nil_p(a)) { + if (mrb_nil_p(a)) { return mrb_ary_new_from_values(mrb, 1, &v); } - else { - recv_class = mrb_obj_value(mrb_obj_class(mrb, v)); - mrb_raisef(mrb, E_TYPE_ERROR, "can't convert %S to Array (%S#to_a gives %S)", - recv_class, - recv_class, - mrb_obj_value(mrb_obj_class(mrb, a)) - ); - /* not reached */ - return mrb_undef_value(); - } + mrb_ensure_array_type(mrb, a); + return a; } static mrb_value @@ -1122,12 +1111,6 @@ mrb_ary_empty_p(mrb_state *mrb, mrb_value self) return mrb_bool_value(ARY_LEN(a) == 0); } -MRB_API mrb_value -mrb_check_array_type(mrb_state *mrb, mrb_value ary) -{ - return mrb_check_convert_type(mrb, ary, MRB_TT_ARRAY, "Array", "to_ary"); -} - MRB_API mrb_value mrb_ary_entry(mrb_value ary, mrb_int offset) { @@ -1181,7 +1164,7 @@ join_ary(mrb_state *mrb, mrb_value ary, mrb_value sep, mrb_value list) val = tmp; goto str_join; } - tmp = mrb_check_convert_type(mrb, val, MRB_TT_ARRAY, "Array", "to_ary"); + tmp = mrb_check_array_type(mrb, val); if (!mrb_nil_p(tmp)) { val = tmp; goto ary_join; diff --git a/src/class.c b/src/class.c index 90c73104e..5d6ff4b39 100644 --- a/src/class.c +++ b/src/class.c @@ -520,7 +520,8 @@ to_str(mrb_state *mrb, mrb_value val) static mrb_value to_ary(mrb_state *mrb, mrb_value val) { - return check_type(mrb, val, MRB_TT_ARRAY, "Array", "to_ary"); + CHECK_TYPE(mrb, val, MRB_TT_ARRAY, "Array"); + return val; } static mrb_value diff --git a/src/object.c b/src/object.c index 18ccacfb9..a105c62f0 100644 --- a/src/object.c +++ b/src/object.c @@ -606,6 +606,23 @@ mrb_check_string_type(mrb_state *mrb, mrb_value str) return str; } +MRB_API mrb_value +mrb_ensure_array_type(mrb_state *mrb, mrb_value ary) +{ + if (!mrb_array_p(ary)) { + mrb_raisef(mrb, E_TYPE_ERROR, "%S cannot be converted to Array", + inspect_type(mrb, ary)); + } + return ary; +} + +MRB_API mrb_value +mrb_check_array_type(mrb_state *mrb, mrb_value ary) +{ + if (!mrb_array_p(ary)) return mrb_nil_value(); + return ary; +} + MRB_API mrb_value mrb_inspect(mrb_state *mrb, mrb_value obj) { -- cgit v1.2.3 From 610bcc88c2b4f3ca9bbfebb57279c25806fa0461 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Wed, 19 Sep 2018 22:53:48 +0900 Subject: Removed `to_hash` conversion method. --- mrbgems/mruby-hash-ext/mrblib/hash.rb | 30 +++++++----------------------- mrbgems/mruby-kernel-ext/src/kernel.c | 20 ++++++-------------- mrbgems/mruby-sprintf/src/sprintf.c | 2 +- mrblib/hash.rb | 14 ++++---------- src/class.c | 15 ++------------- src/hash.c | 28 ---------------------------- src/object.c | 17 +++++++++++++++++ 7 files changed, 37 insertions(+), 89 deletions(-) diff --git a/mrbgems/mruby-hash-ext/mrblib/hash.rb b/mrbgems/mruby-hash-ext/mrblib/hash.rb index f1143e25b..547f3404a 100644 --- a/mrbgems/mruby-hash-ext/mrblib/hash.rb +++ b/mrbgems/mruby-hash-ext/mrblib/hash.rb @@ -27,9 +27,9 @@ class Hash length = object.length if length == 1 o = object[0] - if o.respond_to?(:to_hash) + if Hash === o h = self.new - object[0].to_hash.each { |k, v| h[k] = v } + o.each { |k, v| h[k] = v } return h elsif o.respond_to?(:to_a) h = self.new @@ -82,7 +82,7 @@ class Hash # def merge!(other, &block) - raise TypeError, "can't convert argument into Hash" unless other.respond_to?(:to_hash) + raise TypeError, "Hash required (#{other.class} given)" unless Hash === other if block other.each_key{|k| self[k] = (self.has_key?(k))? block.call(k, self[k], other[k]): other[k] @@ -310,11 +310,7 @@ class Hash # h1 < h1 #=> false # def <(hash) - begin - hash = hash.to_hash - rescue NoMethodError - raise TypeError, "can't convert #{hash.class} to Hash" - end + raise TypeError, "can't convert #{hash.class} to Hash" unless Hash === hash size < hash.size and all? {|key, val| hash.key?(key) and hash[key] == val } @@ -334,11 +330,7 @@ class Hash # h1 <= h1 #=> true # def <=(hash) - begin - hash = hash.to_hash - rescue NoMethodError - raise TypeError, "can't convert #{hash.class} to Hash" - end + raise TypeError, "can't convert #{hash.class} to Hash" unless Hash === hash size <= hash.size and all? {|key, val| hash.key?(key) and hash[key] == val } @@ -358,11 +350,7 @@ class Hash # h1 > h1 #=> false # def >(hash) - begin - hash = hash.to_hash - rescue NoMethodError - raise TypeError, "can't convert #{hash.class} to Hash" - end + raise TypeError, "can't convert #{hash.class} to Hash" unless Hash === hash size > hash.size and hash.all? {|key, val| key?(key) and self[key] == val } @@ -382,11 +370,7 @@ class Hash # h1 >= h1 #=> true # def >=(hash) - begin - hash = hash.to_hash - rescue NoMethodError - raise TypeError, "can't convert #{hash.class} to Hash" - end + raise TypeError, "can't convert #{hash.class} to Hash" unless Hash === hash size >= hash.size and hash.all? {|key, val| key?(key) and self[key] == val } diff --git a/mrbgems/mruby-kernel-ext/src/kernel.c b/mrbgems/mruby-kernel-ext/src/kernel.c index 324753f6e..99affbfa4 100644 --- a/mrbgems/mruby-kernel-ext/src/kernel.c +++ b/mrbgems/mruby-kernel-ext/src/kernel.c @@ -184,9 +184,9 @@ mrb_f_array(mrb_state *mrb, mrb_value self) * call-seq: * Hash(arg) -> hash * - * Converts arg to a Hash by calling - * arg.to_hash. Returns an empty Hash when - * arg is nil or []. + * Returns a Hash if arg is a Hash. + * Returns an empty Hash when arg is nil + * or []. * * Hash([]) #=> {} * Hash(nil) #=> {} @@ -197,21 +197,13 @@ mrb_f_array(mrb_state *mrb, mrb_value self) static mrb_value mrb_f_hash(mrb_state *mrb, mrb_value self) { - mrb_value arg, tmp; + mrb_value arg; mrb_get_args(mrb, "o", &arg); - if (mrb_nil_p(arg)) { + if (mrb_nil_p(arg) || (mrb_array_p(arg) && RARRAY_LEN(arg) == 0)) { return mrb_hash_new(mrb); } - tmp = mrb_check_convert_type(mrb, arg, MRB_TT_HASH, "Hash", "to_hash"); - if (mrb_nil_p(tmp)) { - if (mrb_array_p(arg) && RARRAY_LEN(arg) == 0) { - return mrb_hash_new(mrb); - } - mrb_raisef(mrb, E_TYPE_ERROR, "can't convert %S into Hash", - mrb_str_new_cstr(mrb, mrb_obj_classname(mrb, arg))); - } - return tmp; + return mrb_ensure_hash_type(mrb, arg); } /* diff --git a/mrbgems/mruby-sprintf/src/sprintf.c b/mrbgems/mruby-sprintf/src/sprintf.c index 15d7b5464..5a4a7899e 100644 --- a/mrbgems/mruby-sprintf/src/sprintf.c +++ b/mrbgems/mruby-sprintf/src/sprintf.c @@ -233,7 +233,7 @@ get_hash(mrb_state *mrb, mrb_value *hash, mrb_int argc, const mrb_value *argv) if (argc != 2) { mrb_raise(mrb, E_ARGUMENT_ERROR, "one hash required"); } - tmp = mrb_check_convert_type(mrb, argv[1], MRB_TT_HASH, "Hash", "to_hash"); + tmp = mrb_check_hash_type(mrb, argv[1]); if (mrb_nil_p(tmp)) { mrb_raise(mrb, E_ARGUMENT_ERROR, "one hash required"); } diff --git a/mrblib/hash.rb b/mrblib/hash.rb index 6b61218ff..609883ecb 100644 --- a/mrblib/hash.rb +++ b/mrblib/hash.rb @@ -12,9 +12,7 @@ class Hash # ISO 15.2.13.4.1 def ==(hash) return true if self.equal?(hash) - begin - hash = hash.to_hash - rescue NoMethodError + unless Hash === hash return false end return false if self.size != hash.size @@ -32,9 +30,7 @@ class Hash # ISO 15.2.13.4.32 (x) def eql?(hash) return true if self.equal?(hash) - begin - hash = hash.to_hash - rescue NoMethodError + unless Hash === hash return false end return false if self.size != hash.size @@ -153,9 +149,8 @@ class Hash # # ISO 15.2.13.4.23 def replace(hash) - raise TypeError, "can't convert argument into Hash" unless hash.respond_to?(:to_hash) + raise TypeError, "Hash required (#{hash.class} given)" unless Hash === hash self.clear - hash = hash.to_hash hash.each_key{|k| self[k] = hash[k] } @@ -178,8 +173,7 @@ class Hash # # ISO 15.2.13.4.22 def merge(other, &block) - raise TypeError, "can't convert argument into Hash" unless other.respond_to?(:to_hash) - other = other.to_hash + raise TypeError, "Hash required (#{other.class} given)" unless Hash === other h = self.dup if block other.each_key{|k| diff --git a/src/class.c b/src/class.c index 5d6ff4b39..dd5b65cc3 100644 --- a/src/class.c +++ b/src/class.c @@ -492,18 +492,6 @@ mrb_notimplement_m(mrb_state *mrb, mrb_value self) return mrb_nil_value(); } -static mrb_value -check_type(mrb_state *mrb, mrb_value val, enum mrb_vtype t, const char *c, const char *m) -{ - mrb_value tmp; - - tmp = mrb_check_convert_type(mrb, val, t, c, m); - if (mrb_nil_p(tmp)) { - mrb_raisef(mrb, E_TYPE_ERROR, "expected %S", mrb_str_new_cstr(mrb, c)); - } - return tmp; -} - #define CHECK_TYPE(mrb, val, t, c) do { \ if (mrb_type(val) != (t)) {\ mrb_raisef(mrb, E_TYPE_ERROR, "expected %S", mrb_str_new_lit(mrb, c));\ @@ -527,7 +515,8 @@ to_ary(mrb_state *mrb, mrb_value val) static mrb_value to_hash(mrb_state *mrb, mrb_value val) { - return check_type(mrb, val, MRB_TT_HASH, "Hash", "to_hash"); + CHECK_TYPE(mrb, val, MRB_TT_HASH, "Hash"); + return val; } #define to_sym(mrb, ss) mrb_obj_to_sym(mrb, ss) diff --git a/src/hash.c b/src/hash.c index f43fd901c..467b20a51 100644 --- a/src/hash.c +++ b/src/hash.c @@ -738,18 +738,6 @@ mrb_hash_set(mrb_state *mrb, mrb_value hash, mrb_value key, mrb_value val) return; } -MRB_API mrb_value -mrb_ensure_hash_type(mrb_state *mrb, mrb_value hash) -{ - return mrb_convert_type(mrb, hash, MRB_TT_HASH, "Hash", "to_hash"); -} - -MRB_API mrb_value -mrb_check_hash_type(mrb_state *mrb, mrb_value hash) -{ - return mrb_check_convert_type(mrb, hash, MRB_TT_HASH, "Hash", "to_hash"); -} - static void mrb_hash_modify(mrb_state *mrb, mrb_value hash) { @@ -1189,20 +1177,6 @@ mrb_hash_empty_m(mrb_state *mrb, mrb_value self) return mrb_bool_value(mrb_hash_empty_p(mrb, self)); } -/* 15.2.13.4.29 (x)*/ -/* - * call-seq: - * hsh.to_hash => hsh - * - * Returns +self+. - */ - -static mrb_value -mrb_hash_to_hash(mrb_state *mrb, mrb_value hash) -{ - return hash; -} - static int hash_keys_i(mrb_state *mrb, mrb_value key, mrb_value val, void *p) { @@ -1439,6 +1413,4 @@ mrb_init_hash(mrb_state *mrb) mrb_define_method(mrb, h, "value?", mrb_hash_has_value, MRB_ARGS_REQ(1)); /* 15.2.13.4.27 */ mrb_define_method(mrb, h, "values", mrb_hash_values, MRB_ARGS_NONE()); /* 15.2.13.4.28 */ mrb_define_method(mrb, h, "rehash", mrb_hash_rehash, MRB_ARGS_NONE()); - - mrb_define_method(mrb, h, "to_hash", mrb_hash_to_hash, MRB_ARGS_NONE()); /* 15.2.13.4.29 (x)*/ } diff --git a/src/object.c b/src/object.c index a105c62f0..66dfa0f97 100644 --- a/src/object.c +++ b/src/object.c @@ -623,6 +623,23 @@ mrb_check_array_type(mrb_state *mrb, mrb_value ary) return ary; } +MRB_API mrb_value +mrb_ensure_hash_type(mrb_state *mrb, mrb_value hash) +{ + if (!mrb_hash_p(hash)) { + mrb_raisef(mrb, E_TYPE_ERROR, "%S cannot be converted to Hash", + inspect_type(mrb, hash)); + } + return hash; +} + +MRB_API mrb_value +mrb_check_hash_type(mrb_state *mrb, mrb_value hash) +{ + if (!mrb_hash_p(hash)) return mrb_nil_value(); + return hash; +} + MRB_API mrb_value mrb_inspect(mrb_state *mrb, mrb_value obj) { -- cgit v1.2.3 From c022e4643f2b6c84cb3f1ca716c0e7da3f14c8ca Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Mon, 19 Nov 2018 12:01:34 +0900 Subject: Avoid assignments from type checking `String#__to_str`. --- mrblib/string.rb | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/mrblib/string.rb b/mrblib/string.rb index 397603e9d..64e85c5b6 100644 --- a/mrblib/string.rb +++ b/mrblib/string.rb @@ -12,7 +12,7 @@ class String def each_line(rs = "\n", &block) return to_enum(:each_line, rs, &block) unless block return block.call(self) if rs.nil? - rs = rs.__to_str + rs.__to_str offset = 0 rs_len = rs.length this = dup @@ -67,7 +67,7 @@ class String block = nil end if !replace.nil? || !block - replace = replace.__to_str + replace.__to_str end offset = 0 result = [] @@ -129,12 +129,12 @@ class String end pattern, replace = *args - pattern = pattern.__to_str + pattern.__to_str if args.length == 2 && block block = nil end unless block - replace = replace.__to_str + replace.__to_str end result = [] this = dup -- cgit v1.2.3 From 9516731329a9d43b4aab57a19fb9cfc1b62f11e8 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Mon, 19 Nov 2018 12:01:58 +0900 Subject: Use type checking `mrb_to_str` instead of converting `mrb_str_to_str`. --- include/mruby/string.h | 1 + mrbgems/mruby-sprintf/src/sprintf.c | 2 +- mrbgems/mruby-struct/src/struct.c | 2 +- src/error.c | 2 +- src/string.c | 18 ++++++++---------- 5 files changed, 12 insertions(+), 13 deletions(-) diff --git a/include/mruby/string.h b/include/mruby/string.h index fa1955f48..60db35c99 100644 --- a/include/mruby/string.h +++ b/include/mruby/string.h @@ -352,6 +352,7 @@ MRB_API double mrb_str_to_dbl(mrb_state *mrb, mrb_value str, mrb_bool badcheck); /* * Returns a converted string type. + * For type checking, non converting `mrb_to_str` is recommended. */ MRB_API mrb_value mrb_str_to_str(mrb_state *mrb, mrb_value str); diff --git a/mrbgems/mruby-sprintf/src/sprintf.c b/mrbgems/mruby-sprintf/src/sprintf.c index 5a4a7899e..985ffe276 100644 --- a/mrbgems/mruby-sprintf/src/sprintf.c +++ b/mrbgems/mruby-sprintf/src/sprintf.c @@ -552,7 +552,7 @@ mrb_str_format(mrb_state *mrb, mrb_int argc, const mrb_value *argv, mrb_value fm ++argc; --argv; - fmt = mrb_str_to_str(mrb, fmt); + mrb_to_str(mrb, fmt); p = RSTRING_PTR(fmt); end = p + RSTRING_LEN(fmt); blen = 0; diff --git a/mrbgems/mruby-struct/src/struct.c b/mrbgems/mruby-struct/src/struct.c index b567a00d5..832583f35 100644 --- a/mrbgems/mruby-struct/src/struct.c +++ b/mrbgems/mruby-struct/src/struct.c @@ -213,7 +213,7 @@ make_struct(mrb_state *mrb, mrb_value name, mrb_value members, struct RClass *kl } else { /* old style: should we warn? */ - name = mrb_str_to_str(mrb, name); + mrb_to_str(mrb, name); id = mrb_obj_to_sym(mrb, name); if (!is_const_id(mrb, mrb_sym2name_len(mrb, id, NULL))) { mrb_name_error(mrb, id, "identifier %S needs to be constant", name); diff --git a/src/error.c b/src/error.c index 599612b97..57cdfcfe1 100644 --- a/src/error.c +++ b/src/error.c @@ -28,7 +28,7 @@ mrb_exc_new(mrb_state *mrb, struct RClass *c, const char *ptr, size_t len) MRB_API mrb_value mrb_exc_new_str(mrb_state *mrb, struct RClass* c, mrb_value str) { - str = mrb_str_to_str(mrb, str); + mrb_to_str(mrb, str); return mrb_obj_new(mrb, c, 1, &str); } diff --git a/src/string.c b/src/string.c index b6d4ecef0..287b4dcbb 100644 --- a/src/string.c +++ b/src/string.c @@ -748,9 +748,7 @@ mrb_str_to_cstr(mrb_state *mrb, mrb_value str0) MRB_API void mrb_str_concat(mrb_state *mrb, mrb_value self, mrb_value other) { - if (!mrb_string_p(other)) { - other = mrb_str_to_str(mrb, other); - } + other = mrb_str_to_str(mrb, other); mrb_str_cat_str(mrb, self, other); } @@ -993,15 +991,15 @@ mrb_str_to_str(mrb_state *mrb, mrb_value str) MRB_API const char* mrb_string_value_ptr(mrb_state *mrb, mrb_value ptr) { - mrb_value str = mrb_str_to_str(mrb, ptr); - return RSTRING_PTR(str); + mrb_to_str(mrb, ptr); + return RSTRING_PTR(ptr); } MRB_API mrb_int mrb_string_value_len(mrb_state *mrb, mrb_value ptr) { - mrb_value str = mrb_str_to_str(mrb, ptr); - return RSTRING_LEN(str); + mrb_to_str(mrb, ptr); + return RSTRING_LEN(ptr); } void @@ -2183,7 +2181,7 @@ mrb_cstr_to_inum(mrb_state *mrb, const char *str, int base, int badcheck) MRB_API const char* mrb_string_value_cstr(mrb_state *mrb, mrb_value *ptr) { - mrb_value str = mrb_str_to_str(mrb, *ptr); + mrb_value str = mrb_to_str(mrb, *ptr); struct RString *ps = mrb_str_ptr(str); mrb_int len = mrb_str_strlen(mrb, ps); char *p = RSTR_PTR(ps); @@ -2313,7 +2311,7 @@ mrb_str_to_dbl(mrb_state *mrb, mrb_value str, mrb_bool badcheck) char *s; mrb_int len; - str = mrb_str_to_str(mrb, str); + mrb_to_str(mrb, str); s = RSTRING_PTR(str); len = RSTRING_LEN(str); if (s) { @@ -2600,7 +2598,7 @@ mrb_str_cat_str(mrb_state *mrb, mrb_value str, mrb_value str2) MRB_API mrb_value mrb_str_append(mrb_state *mrb, mrb_value str1, mrb_value str2) { - str2 = mrb_str_to_str(mrb, str2); + mrb_to_str(mrb, str2); return mrb_str_cat_str(mrb, str1, str2); } -- cgit v1.2.3 From 87ffab5713a49cef7133eeff7085b9c6a6a427fb Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Mon, 19 Nov 2018 15:25:42 +0900 Subject: Adjust codedump output format; ref #4166 --- src/codedump.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/codedump.c b/src/codedump.c index 7d1950f75..4d56fd427 100644 --- a/src/codedump.c +++ b/src/codedump.c @@ -17,6 +17,7 @@ print_r(mrb_state *mrb, mrb_irep *irep, size_t n) if (irep->lv[i].r == n) { mrb_sym sym = irep->lv[i].name; printf(" R%d:%s", (int)n, mrb_sym2name(mrb, sym)); + break; } } } @@ -81,8 +82,9 @@ codedump(mrb_state *mrb, mrb_irep *irep) printf("local variable names:\n"); for (i = 1; i < irep->nlocals; ++i) { - char const *n = mrb_sym2name(mrb, irep->lv[i - 1].name); - printf(" R%d:%s\n", irep->lv[i - 1].r, n? n : ""); + char const *s = mrb_sym2name(mrb, irep->lv[i - 1].name); + int n = irep->lv[i - 1].r ? irep->lv[i - 1].r : i; + printf(" R%d:%s\n", n, s ? s : ""); } } -- cgit v1.2.3 From 423f872c846d63056ba75f067201ba9c221231d1 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Mon, 19 Nov 2018 15:26:19 +0900 Subject: Need to keep rooms for empty splat; fix #4166 --- mrbgems/mruby-compiler/core/parse.y | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/mrbgems/mruby-compiler/core/parse.y b/mrbgems/mruby-compiler/core/parse.y index ac8724377..3a9da3d36 100644 --- a/mrbgems/mruby-compiler/core/parse.y +++ b/mrbgems/mruby-compiler/core/parse.y @@ -2482,6 +2482,7 @@ f_margs : f_marg_list } | f_marg_list ',' tSTAR { + local_add_f(p, 0); $$ = list3($1, (node*)-1, 0); } | f_marg_list ',' tSTAR ',' f_marg_list @@ -2498,11 +2499,16 @@ f_margs : f_marg_list } | tSTAR { + local_add_f(p, 0); $$ = list3(0, (node*)-1, 0); } - | tSTAR ',' f_marg_list + | tSTAR ',' { - $$ = list3(0, (node*)-1, $3); + local_add_f(p, 0); + } + f_marg_list + { + $$ = list3(0, (node*)-1, $4); } ; -- cgit v1.2.3 From c308a149f0eaa529d5b3236e696aed13a19733ae Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Mon, 19 Nov 2018 15:35:59 +0900 Subject: Add Hash type check for `OP_KARG` and `OP_KEY_P`; ref #4166 --- src/vm.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/vm.c b/src/vm.c index 2d12df4ba..6bb9a48a5 100644 --- a/src/vm.c +++ b/src/vm.c @@ -1892,7 +1892,7 @@ RETRY_TRY_BLOCK: mrb_value k = mrb_symbol_value(syms[b]); mrb_value kdict = regs[mrb->c->ci->argc]; - if (!mrb_hash_key_p(mrb, kdict, k)) { + if (!mrb_hash_p(kdict) || !mrb_hash_key_p(mrb, kdict, k)) { mrb_value str = mrb_format(mrb, "missing keyword: %S", k); mrb_exc_set(mrb, mrb_exc_new_str(mrb, E_ARGUMENT_ERROR, str)); goto L_RAISE; @@ -1905,8 +1905,11 @@ RETRY_TRY_BLOCK: CASE(OP_KEY_P, BB) { mrb_value k = mrb_symbol_value(syms[b]); mrb_value kdict = regs[mrb->c->ci->argc]; - mrb_bool key_p = mrb_hash_key_p(mrb, kdict, k); + mrb_bool key_p = FALSE; + if (mrb_hash_p(kdict)) { + key_p = mrb_hash_key_p(mrb, kdict, k); + } regs[a] = mrb_bool_value(key_p); NEXT; } -- cgit v1.2.3 From 53e2df3e93eea99f70950eebae766ce042769adb Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Mon, 19 Nov 2018 16:13:26 +0900 Subject: Restore `mrb_string_type` function for compatibility. --- include/mruby/string.h | 4 ++++ src/object.c | 7 +++++++ 2 files changed, 11 insertions(+) diff --git a/include/mruby/string.h b/include/mruby/string.h index 60db35c99..1a20cb1de 100644 --- a/include/mruby/string.h +++ b/include/mruby/string.h @@ -313,6 +313,10 @@ MRB_API mrb_value mrb_str_substr(mrb_state *mrb, mrb_value str, mrb_int beg, mrb */ MRB_API mrb_value mrb_ensure_string_type(mrb_state *mrb, mrb_value str); MRB_API mrb_value mrb_check_string_type(mrb_state *mrb, mrb_value str); +/* obsolete: use mrb_ensure_string_type() instead */ +MRB_API mrb_value mrb_string_type(mrb_state *mrb, mrb_value str); + + MRB_API mrb_value mrb_str_new_capa(mrb_state *mrb, size_t capa); MRB_API mrb_value mrb_str_buf_new(mrb_state *mrb, size_t capa); diff --git a/src/object.c b/src/object.c index 66dfa0f97..b764fc8ef 100644 --- a/src/object.c +++ b/src/object.c @@ -589,6 +589,13 @@ mrb_to_str(mrb_state *mrb, mrb_value val) return val; } +/* obsolete: use mrb_ensure_string_type() instead */ +MRB_API mrb_value +mrb_string_type(mrb_state *mrb, mrb_value str) +{ + return mrb_ensure_string_type(mrb, str); +} + MRB_API mrb_value mrb_ensure_string_type(mrb_state *mrb, mrb_value str) { -- cgit v1.2.3 From 65a2c2082d97ea5fe2b7551bf73fbcefb5ca498e Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Mon, 19 Nov 2018 17:11:19 +0900 Subject: Call `mrb_str_to_str` from `mrb_string_value_ptr` for compatibility. --- src/string.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/string.c b/src/string.c index 287b4dcbb..2668a2c85 100644 --- a/src/string.c +++ b/src/string.c @@ -989,10 +989,10 @@ mrb_str_to_str(mrb_state *mrb, mrb_value str) } MRB_API const char* -mrb_string_value_ptr(mrb_state *mrb, mrb_value ptr) +mrb_string_value_ptr(mrb_state *mrb, mrb_value str) { - mrb_to_str(mrb, ptr); - return RSTRING_PTR(ptr); + str = mrb_str_to_str(mrb, str); + return RSTRING_PTR(str); } MRB_API mrb_int -- cgit v1.2.3 From afd46eccd14e20a3898c81a3168ec764f1010bdf Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Mon, 19 Nov 2018 17:11:59 +0900 Subject: Add `-fpermissive` to C++ compiler flags. --- travis_config.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/travis_config.rb b/travis_config.rb index 5904d6880..e12bae648 100644 --- a/travis_config.rb +++ b/travis_config.rb @@ -40,7 +40,7 @@ MRuby::Build.new('cxx_abi') do |conf| toolchain :gcc conf.gembox 'full-core' - conf.cc.flags += %w(-Werror=declaration-after-statement) + conf.cc.flags += %w(-Werror=declaration-after-statement -fpermissive) conf.compilers.each do |c| c.defines += %w(MRB_GC_FIXED_ARENA) end -- cgit v1.2.3 From 86d102350b4e68ae7ad4c1fef684f53a275790dc Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Tue, 20 Nov 2018 09:14:34 +0900 Subject: Restrict total recursion number of `ecall()`; fix #3789 --- include/mruby.h | 3 ++- src/vm.c | 6 ++++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/include/mruby.h b/include/mruby.h index 12df9cd5a..5ff7a1d7b 100644 --- a/include/mruby.h +++ b/include/mruby.h @@ -267,7 +267,8 @@ typedef struct mrb_state { #else mrb_atexit_func *atexit_stack; #endif - mrb_int atexit_stack_len; + uint16_t atexit_stack_len; + uint16_t ecall_nest; /* prevent infinite recursive ecall() */ } mrb_state; /** diff --git a/src/vm.c b/src/vm.c index 6bb9a48a5..84e076ee8 100644 --- a/src/vm.c +++ b/src/vm.c @@ -55,7 +55,7 @@ void abort(void); /* Maximum depth of ecall() recursion. */ #ifndef MRB_ECALL_DEPTH_MAX -#define MRB_ECALL_DEPTH_MAX 32 +#define MRB_ECALL_DEPTH_MAX 512 #endif /* Maximum stack depth. Should be set lower on memory constrained systems. @@ -337,7 +337,8 @@ ecall(mrb_state *mrb) int nregs; if (i<0) return; - if (ci - c->cibase > MRB_ECALL_DEPTH_MAX) { + /* restrict total call depth of ecall() */ + if (++mrb->ecall_nest > MRB_ECALL_DEPTH_MAX) { mrb_exc_raise(mrb, mrb_obj_value(mrb->stack_err)); } p = c->ensure[i]; @@ -372,6 +373,7 @@ ecall(mrb_state *mrb) c->ci = c->cibase + cioff; if (!mrb->exc) mrb->exc = exc; mrb_gc_arena_restore(mrb, ai); + mrb->ecall_nest--; } #ifndef MRB_FUNCALL_ARGC_MAX -- cgit v1.2.3 From f1eeaad84a1b1183c6e5128be0a4efeec6da5e8e Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Tue, 20 Nov 2018 09:35:38 +0900 Subject: Stop special treating of `\r` in the lexer; fix #4132 --- mrbgems/mruby-compiler/core/parse.y | 8 -------- 1 file changed, 8 deletions(-) diff --git a/mrbgems/mruby-compiler/core/parse.y b/mrbgems/mruby-compiler/core/parse.y index 3a9da3d36..e489dd934 100644 --- a/mrbgems/mruby-compiler/core/parse.y +++ b/mrbgems/mruby-compiler/core/parse.y @@ -3710,14 +3710,6 @@ nextc(parser_state *p) if (c >= 0) { p->column++; } - if (c == '\r') { - c = nextc(p); - if (c != '\n') { - pushback(p, c); - return '\r'; - } - return c; - } return c; eof: -- cgit v1.2.3 From ec19c34a209e05156cdce8d317234bc62489148f Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Tue, 20 Nov 2018 10:39:34 +0900 Subject: Fixed a bug in `mirb` heredoc handling; fix #3989 --- include/mruby/compile.h | 1 - mrbgems/mruby-bin-mirb/tools/mirb/mirb.c | 4 ---- mrbgems/mruby-compiler/core/parse.y | 1 - 3 files changed, 6 deletions(-) diff --git a/include/mruby/compile.h b/include/mruby/compile.h index 63ec8aca1..fd735be88 100644 --- a/include/mruby/compile.h +++ b/include/mruby/compile.h @@ -143,7 +143,6 @@ struct mrb_parser_state { mrb_ast_node *heredocs_from_nextline; mrb_ast_node *parsing_heredoc; mrb_ast_node *lex_strterm_before_heredoc; - mrb_bool heredoc_end_now:1; /* for mirb */ void *ylval; diff --git a/mrbgems/mruby-bin-mirb/tools/mirb/mirb.c b/mrbgems/mruby-bin-mirb/tools/mirb/mirb.c index 1880f22f7..19f533acd 100644 --- a/mrbgems/mruby-bin-mirb/tools/mirb/mirb.c +++ b/mrbgems/mruby-bin-mirb/tools/mirb/mirb.c @@ -126,10 +126,6 @@ is_code_block_open(struct mrb_parser_state *parser) /* check for heredoc */ if (parser->parsing_heredoc != NULL) return TRUE; - if (parser->heredoc_end_now) { - parser->heredoc_end_now = FALSE; - return FALSE; - } /* check for unterminated string */ if (parser->lex_strterm) return TRUE; diff --git a/mrbgems/mruby-compiler/core/parse.y b/mrbgems/mruby-compiler/core/parse.y index e489dd934..70b9d0fc4 100644 --- a/mrbgems/mruby-compiler/core/parse.y +++ b/mrbgems/mruby-compiler/core/parse.y @@ -1078,7 +1078,6 @@ heredoc_end(parser_state *p) end_strterm(p); p->lex_strterm = p->lex_strterm_before_heredoc; p->lex_strterm_before_heredoc = NULL; - p->heredoc_end_now = TRUE; } else { /* next heredoc */ -- cgit v1.2.3 From 68c53848301fec856c7c3549f3cd514ee7756999 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Tue, 20 Nov 2018 10:43:34 +0900 Subject: Update version number; fix #4165 --- include/mruby/version.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/include/mruby/version.h b/include/mruby/version.h index 43d6461ea..daeca4b75 100644 --- a/include/mruby/version.h +++ b/include/mruby/version.h @@ -27,7 +27,7 @@ MRB_BEGIN_DECL /* * The version of Ruby used by mruby. */ -#define MRUBY_RUBY_VERSION "1.9" +#define MRUBY_RUBY_VERSION "2.0" /* * Ruby engine. @@ -37,17 +37,17 @@ MRB_BEGIN_DECL /* * Major release version number. */ -#define MRUBY_RELEASE_MAJOR 1 +#define MRUBY_RELEASE_MAJOR 2 /* * Minor release version number. */ -#define MRUBY_RELEASE_MINOR 4 +#define MRUBY_RELEASE_MINOR 0 /* * Tiny release version number. */ -#define MRUBY_RELEASE_TEENY 1 +#define MRUBY_RELEASE_TEENY 0 /* * The mruby version. -- cgit v1.2.3 From c9a66d4c41c7d645f0fc19cd8f5660584a3a948e Mon Sep 17 00:00:00 2001 From: Rob Fors Date: Tue, 20 Nov 2018 21:27:03 -0500 Subject: Update documentation to mrb_load_irep --- include/mruby/irep.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/include/mruby/irep.h b/include/mruby/irep.h index 78cbc2b74..027a294d5 100644 --- a/include/mruby/irep.h +++ b/include/mruby/irep.h @@ -48,8 +48,13 @@ typedef struct mrb_irep { #define MRB_ISEQ_NO_FREE 1 MRB_API mrb_irep *mrb_add_irep(mrb_state *mrb); + +/* @param [const uint8_t*] irep code, expected as a literal */ MRB_API mrb_value mrb_load_irep(mrb_state*, const uint8_t*); + +/* @param [const uint8_t*] irep code, expected as a literal */ MRB_API mrb_value mrb_load_irep_cxt(mrb_state*, const uint8_t*, mrbc_context*); + void mrb_irep_free(mrb_state*, struct mrb_irep*); void mrb_irep_incref(mrb_state*, struct mrb_irep*); void mrb_irep_decref(mrb_state*, struct mrb_irep*); -- cgit v1.2.3 From 0711c861ca939c73bed9d91601f6cc38bdf474ba Mon Sep 17 00:00:00 2001 From: Hiroshi Mimaki Date: Thu, 22 Nov 2018 09:49:00 +0900 Subject: Fix mruby-socket test failure on MinGW. --- mrbgems/mruby-socket/src/socket.c | 1 + 1 file changed, 1 insertion(+) diff --git a/mrbgems/mruby-socket/src/socket.c b/mrbgems/mruby-socket/src/socket.c index b44371544..dff176778 100644 --- a/mrbgems/mruby-socket/src/socket.c +++ b/mrbgems/mruby-socket/src/socket.c @@ -10,6 +10,7 @@ #include #include #include + #include #define SHUT_RDWR SD_BOTH #ifndef _SSIZE_T_DEFINED -- cgit v1.2.3 From 91bf55bbe5c837531f5785309eb0983e7ce78633 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Wed, 21 Nov 2018 12:07:17 +0900 Subject: Remove `do { ... } while(0)` hacks from `MRB_TRY` macros. Because it can swallow `break` etc. if they are used in loops. --- include/mruby/throw.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/include/mruby/throw.h b/include/mruby/throw.h index 5d3d214e7..4a1fd8d60 100644 --- a/include/mruby/throw.h +++ b/include/mruby/throw.h @@ -15,9 +15,9 @@ #if defined(MRB_ENABLE_CXX_EXCEPTION) && defined(__cplusplus) -#define MRB_TRY(buf) do { try { +#define MRB_TRY(buf) try { #define MRB_CATCH(buf) } catch(mrb_jmpbuf_impl e) { if (e != (buf)->impl) { throw e; } -#define MRB_END_EXC(buf) } } while(0) +#define MRB_END_EXC(buf) } #define MRB_THROW(buf) throw((buf)->impl) typedef mrb_int mrb_jmpbuf_impl; @@ -34,9 +34,9 @@ typedef mrb_int mrb_jmpbuf_impl; #define MRB_LONGJMP longjmp #endif -#define MRB_TRY(buf) do { if (MRB_SETJMP((buf)->impl) == 0) { +#define MRB_TRY(buf) if (MRB_SETJMP((buf)->impl) == 0) { #define MRB_CATCH(buf) } else { -#define MRB_END_EXC(buf) } } while(0) +#define MRB_END_EXC(buf) } #define MRB_THROW(buf) MRB_LONGJMP((buf)->impl, 1); #define mrb_jmpbuf_impl jmp_buf -- cgit v1.2.3 From e2e6554b569648bca8bf26ffcb951737e07c6888 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Wed, 21 Nov 2018 12:08:51 +0900 Subject: Protect from exceptions raised outside of `mrb_vm_run()`. It can happen if signals are used (e.g. from `mruby-alarm` gem). --- mrbgems/mruby-bin-mirb/tools/mirb/mirb.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/mrbgems/mruby-bin-mirb/tools/mirb/mirb.c b/mrbgems/mruby-bin-mirb/tools/mirb/mirb.c index 19f533acd..8d7c719d8 100644 --- a/mrbgems/mruby-bin-mirb/tools/mirb/mirb.c +++ b/mrbgems/mruby-bin-mirb/tools/mirb/mirb.c @@ -56,6 +56,7 @@ #include #include #include +#include #ifdef ENABLE_READLINE @@ -491,7 +492,10 @@ main(int argc, char **argv) while (TRUE) { char *utf8; + struct mrb_jmpbuf c_jmp; + MRB_TRY(&c_jmp); + mrb->jmp = &c_jmp; if (args.rfp) { if (fgets(last_code_line, sizeof(last_code_line)-1, args.rfp) != NULL) goto done; @@ -555,8 +559,7 @@ main(int argc, char **argv) MIRB_LINE_FREE(line); #endif -done: - + done: if (code_block_open) { if (strlen(ruby_code)+strlen(last_code_line) > sizeof(ruby_code)-1) { fputs("concatenated input string too long\n", stderr); @@ -648,6 +651,11 @@ done: } mrb_parser_free(parser); cxt->lineno++; + MRB_CATCH(&c_jmp) { + p(mrb, mrb_obj_value(mrb->exc), 0); + mrb->exc = 0; + } + MRB_END_EXC(&c_jmp); } #ifdef ENABLE_READLINE -- cgit v1.2.3 From 7ed9bb3bd361030c3fbeeaf72186e61c8e6563f0 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Sun, 25 Nov 2018 06:03:30 +0900 Subject: Fix wrong number of arguments in `Array#fetch`; fix #4170 --- mrbgems/mruby-array-ext/mrblib/array.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mrbgems/mruby-array-ext/mrblib/array.rb b/mrbgems/mruby-array-ext/mrblib/array.rb index bb95d70c5..6096696cb 100644 --- a/mrbgems/mruby-array-ext/mrblib/array.rb +++ b/mrbgems/mruby-array-ext/mrblib/array.rb @@ -291,7 +291,7 @@ class Array # #=> "100 is out of bounds" # - def fetch(n=nil, ifnone=NONE, &block) + def fetch(n, ifnone=NONE, &block) warn "block supersedes default value argument" if !n.nil? && ifnone != NONE && block idx = n -- cgit v1.2.3 From e6b72b2121b981c504f902723b3c1531be001c02 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Sun, 25 Nov 2018 07:30:32 +0900 Subject: Remove redundant rules from `parse.y`. --- mrbgems/mruby-compiler/core/parse.y | 36 ++++++++---------------------------- 1 file changed, 8 insertions(+), 28 deletions(-) diff --git a/mrbgems/mruby-compiler/core/parse.y b/mrbgems/mruby-compiler/core/parse.y index 70b9d0fc4..1485fb086 100644 --- a/mrbgems/mruby-compiler/core/parse.y +++ b/mrbgems/mruby-compiler/core/parse.y @@ -1171,7 +1171,7 @@ heredoc_end(parser_state *p) %type command_args aref_args opt_block_arg block_arg var_ref var_lhs %type command_asgn command_rhs mrhs superclass block_call block_command %type f_block_optarg f_block_opt -%type f_arglist f_args f_arg f_arg_item f_optarg f_marg f_marg_list f_margs +%type f_arglist f_args f_arg f_arg_item f_optarg f_margs %type assoc_list assocs assoc undef_list backref for_var %type block_param opt_block_param block_param_def f_opt %type bv_decls opt_bv_decl bvar f_larglist lambda_body @@ -2447,44 +2447,24 @@ for_var : lhs | mlhs ; -f_marg : f_norm_arg - { - $$ = new_arg(p, $1); - } - | tLPAREN f_margs rparen - { - $$ = new_masgn(p, $2, 0); - } - ; - -f_marg_list : f_marg - { - $$ = list1($1); - } - | f_marg_list ',' f_marg - { - $$ = push($1, $3); - } - ; - -f_margs : f_marg_list +f_margs : f_arg { $$ = list3($1,0,0); } - | f_marg_list ',' tSTAR f_norm_arg + | f_arg ',' tSTAR f_norm_arg { $$ = list3($1, new_arg(p, $4), 0); } - | f_marg_list ',' tSTAR f_norm_arg ',' f_marg_list + | f_arg ',' tSTAR f_norm_arg ',' f_arg { $$ = list3($1, new_arg(p, $4), $6); } - | f_marg_list ',' tSTAR + | f_arg ',' tSTAR { local_add_f(p, 0); $$ = list3($1, (node*)-1, 0); } - | f_marg_list ',' tSTAR ',' f_marg_list + | f_arg ',' tSTAR ',' f_arg { $$ = list3($1, (node*)-1, $5); } @@ -2492,7 +2472,7 @@ f_margs : f_marg_list { $$ = list3(0, new_arg(p, $2), 0); } - | tSTAR f_norm_arg ',' f_marg_list + | tSTAR f_norm_arg ',' f_arg { $$ = list3(0, new_arg(p, $2), $4); } @@ -2505,7 +2485,7 @@ f_margs : f_marg_list { local_add_f(p, 0); } - f_marg_list + f_arg { $$ = list3(0, (node*)-1, $4); } -- cgit v1.2.3 From 762f682b80460929d9c69b1957bcb2aad108ec93 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Sun, 25 Nov 2018 09:01:14 +0900 Subject: Allow destructuring in formal arguments. e.g. ``` def m(a,(b,c),d); p [a,b,c,d]; end m(1,[2,3],4) # => [1,2,3,4] ``` mruby limitation: Destructured arguments (`b` and `c` in above example) cannot be accessed from the default expression of optional arguments and keyword arguments, since actual assignment is done after the evaluation of those default expressions. Thus: ``` def f(a,(b,c),d=b) p [a,b,c,d] end f(1,[2,3]) ``` raises `NoMethodError` for `b` in mruby. --- mrbgems/mruby-compiler/core/codegen.c | 40 +++++++++++++++++++++++++++++------ mrbgems/mruby-compiler/core/parse.y | 31 +++++++++++++++++++++++++-- 2 files changed, 63 insertions(+), 8 deletions(-) diff --git a/mrbgems/mruby-compiler/core/codegen.c b/mrbgems/mruby-compiler/core/codegen.c index ba7d8cf63..b3659863b 100644 --- a/mrbgems/mruby-compiler/core/codegen.c +++ b/mrbgems/mruby-compiler/core/codegen.c @@ -734,15 +734,13 @@ lambda_body(codegen_scope *s, node *tree, int blk) mrb_aspec a; int ma, oa, ra, pa, ka, kd, ba; int pos, i; - node *n, *opt; + node *opt; + node *margs, *pargs; node *tail; /* mandatory arguments */ ma = node_len(tree->car->car); - n = tree->car->car; - while (n) { - n = n->cdr; - } + margs = tree->car->car; tail = tree->car->cdr->cdr->cdr->cdr; /* optional arguments */ @@ -751,6 +749,7 @@ lambda_body(codegen_scope *s, node *tree, int blk) ra = tree->car->cdr->cdr->car ? 1 : 0; /* mandatory arugments after rest argument */ pa = node_len(tree->car->cdr->cdr->cdr->car); + pargs = tree->car->cdr->cdr->cdr->car; /* keyword arguments */ ka = tail? node_len(tail->cdr->car) : 0; /* keyword dictionary? */ @@ -798,6 +797,7 @@ lambda_body(codegen_scope *s, node *tree, int blk) dispatch(s, pos+i*3+1); } + /* keyword arguments */ if (tail) { node *kwds = tail->cdr->car; int kwrest = 0; @@ -836,7 +836,34 @@ lambda_body(codegen_scope *s, node *tree, int blk) genop_0(s, OP_KEYEND); } } + + /* argument destructuring */ + if (margs) { + node *n = margs; + + pos = 1; + while (n) { + if (nint(n->car->car) == NODE_MASGN) { + gen_vmassignment(s, n->car->cdr->car, pos, NOVAL); + } + pos++; + n = n->cdr; + } + } + if (pargs) { + node *n = margs; + + pos = ma+oa+ra+1; + while (n) { + if (nint(n->car->car) == NODE_MASGN) { + gen_vmassignment(s, n->car->cdr->car, pos, NOVAL); + } + pos++; + n = n->cdr; + } + } } + codegen(s, tree->cdr->car, VAL); pop(); if (s->pc > 0) { @@ -1066,6 +1093,7 @@ gen_assignment(codegen_scope *s, node *tree, int sp, int val) idx = new_sym(s, nsym(tree)); genop_2(s, OP_SETGV, sp, idx); break; + case NODE_ARG: case NODE_LVAR: idx = lv_idx(s, nsym(tree)); if (idx > 0) { @@ -1173,7 +1201,7 @@ gen_vmassignment(codegen_scope *s, node *tree, int rhs, int val) pop_n(post+1); genop_3(s, OP_APOST, cursp(), n, post); n = 1; - if (t->car) { /* rest */ + if (t->car && t->car != (node*)-1) { /* rest */ gen_assignment(s, t->car, cursp(), NOVAL); } if (t->cdr && t->cdr->car) { diff --git a/mrbgems/mruby-compiler/core/parse.y b/mrbgems/mruby-compiler/core/parse.y index 1485fb086..d143344c3 100644 --- a/mrbgems/mruby-compiler/core/parse.y +++ b/mrbgems/mruby-compiler/core/parse.y @@ -682,6 +682,25 @@ new_arg(parser_state *p, mrb_sym sym) return cons((node*)NODE_ARG, nsym(sym)); } +static void +local_add_margs(parser_state *p, node *n) +{ + while (n) { + if (n->car->car == (node*)NODE_MASGN) { + node *t = n->car->cdr->cdr; + + n->car->cdr->cdr = NULL; + while (t) { + local_add_f(p, sym(t->car)); + t = t->cdr; + } + local_add_margs(p, n->car->cdr->car->car); + local_add_margs(p, n->car->cdr->car->cdr->cdr->car); + } + n = n->cdr; + } +} + /* (m o r m2 tail) */ /* m: (a b c) */ /* o: ((a . e1) (b . e2)) */ @@ -693,6 +712,8 @@ new_args(parser_state *p, node *m, node *opt, mrb_sym rest, node *m2, node *tail { node *n; + local_add_margs(p, m); + local_add_margs(p, m2); n = cons(m2, tail); n = cons(nsym(rest), n); n = cons(opt, n); @@ -3275,9 +3296,15 @@ f_arg_item : f_norm_arg { $$ = new_arg(p, $1); } - | tLPAREN f_margs rparen + | tLPAREN + { + $$ = local_switch(p); + } + f_margs rparen { - $$ = new_masgn(p, $2, 0); + $$ = new_masgn(p, $3, p->locals->car); + local_resume(p, $2); + local_add_f(p, 0); } ; -- cgit v1.2.3 From 26475d0a7897c25f8632b776014a19c3a6f6ecc2 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Sun, 25 Nov 2018 18:03:27 +0900 Subject: Update `doc/limitations.md` for argument destructuring. --- doc/limitations.md | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/doc/limitations.md b/doc/limitations.md index 92858cb1f..825435f01 100644 --- a/doc/limitations.md +++ b/doc/limitations.md @@ -219,7 +219,7 @@ $ ruby -e 'def m(*r,**k) p [r,k] end; m("a"=>1,:b=>2)' [[{"a"=>1}], {:b=>2}] ``` -#### mruby [] +#### mruby [mruby 2.0.0] ``` $ ./bin/mruby -e 'def m(*r,**k) p [r,k] end; m("a"=>1,:b=>2)' @@ -227,3 +227,23 @@ trace (most recent call last): [0] -e:1 -e:1: keyword argument hash with non symbol keys (ArgumentError) ``` + +## Argument Destructuring + +```ruby +def m(a,(b,c),d); p [a,b,c,d]; end +m(1,[2,3],4) # => [1,2,3,4] +``` +Destructured arguments (`b` and `c` in above example) cannot be accessed +from the default expression of optional arguments and keyword arguments, +since actual assignment is done after the evaluation of those default +expressions. Thus: + +```ruby +def f(a,(b,c),d=b) + p [a,b,c,d] +end +f(1,[2,3]) +``` + +CRuby gives `[1,2,3,nil]`. mruby raises `NoMethodError` for `b`. -- cgit v1.2.3 From e300ac8e3a100aa9538560700050dc3df6cdb09d Mon Sep 17 00:00:00 2001 From: Rob Date: Sun, 2 Dec 2018 18:38:40 -0500 Subject: Adds Module#< and Module#<= --- mrbgems/mruby-class-ext/mrblib/module.rb | 39 +++++++++++++++++++++++ mrbgems/mruby-class-ext/test/module.rb | 54 ++++++++++++++++++++++++++++++++ 2 files changed, 93 insertions(+) create mode 100644 mrbgems/mruby-class-ext/mrblib/module.rb diff --git a/mrbgems/mruby-class-ext/mrblib/module.rb b/mrbgems/mruby-class-ext/mrblib/module.rb new file mode 100644 index 000000000..d35b4cbae --- /dev/null +++ b/mrbgems/mruby-class-ext/mrblib/module.rb @@ -0,0 +1,39 @@ +class Module + + ## + # call-seq: + # mod < other -> true, false, or nil + # + # Returns true if mod is a subclass of other. Returns + # nil if there's no relationship between the two. + # (Think of the relationship in terms of the class definition: + # "class A < B" implies "A < B".) + # + def <(other) + raise TypeError, 'compared with non class/module' unless other.is_a?(Module) + if self.equal?(other) + false + else + self <= other + end + end + + ## + # call-seq: + # mod <= other -> true, false, or nil + # + # Returns true if mod is a subclass of other or + # is the same as other. Returns + # nil if there's no relationship between the two. + # (Think of the relationship in terms of the class definition: + # "class A < B" implies "A < B".) + def <=(other) + raise TypeError, 'compared with non class/module' unless other.is_a?(Module) + if self.ancestors.include?(other) + return true + elsif other.ancestors.include?(self) + return false + end + end + +end diff --git a/mrbgems/mruby-class-ext/test/module.rb b/mrbgems/mruby-class-ext/test/module.rb index 71a8da451..52e04ab37 100644 --- a/mrbgems/mruby-class-ext/test/module.rb +++ b/mrbgems/mruby-class-ext/test/module.rb @@ -1,3 +1,57 @@ +assert 'Module#<' do + a = Class.new + b = Class.new(a) + c = Class.new(a) + d = Module.new + e = Class.new { include d } + f = Module.new { include d } + + # compare class to class + assert_true b < a + assert_false b < b + assert_false a < b + assert_nil c < b + + # compare class to module + assert_true e < d + assert_false d < e + assert_nil a < d + + # compare module to module + assert_true f < d + assert_false f < f + assert_false d < f + + assert_raise(TypeError) { a < Object.new } +end + +assert 'Module#<=' do + a = Class.new + b = Class.new(a) + c = Class.new(a) + d = Module.new + e = Class.new { include d } + f = Module.new { include d } + + # compare class to class + assert_true b <= a + assert_true b <= b + assert_false a <= b + assert_nil c <= b + + # compare class to module + assert_true e <= d + assert_false d <= e + assert_nil a <= d + + # compare module to module + assert_true f <= d + assert_true f <= f + assert_false d <= f + + assert_raise(TypeError) { a <= Object.new } +end + assert 'Module#name' do module Outer class Inner; end -- cgit v1.2.3 From 6ef4a5fd6b28375ec7c4f066cf8c5364256f83fd Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Tue, 4 Dec 2018 08:39:44 +0900 Subject: Replace RDoc `` to Markdown back quotes; ref #4174 --- mrbgems/mruby-class-ext/mrblib/module.rb | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/mrbgems/mruby-class-ext/mrblib/module.rb b/mrbgems/mruby-class-ext/mrblib/module.rb index d35b4cbae..484d63674 100644 --- a/mrbgems/mruby-class-ext/mrblib/module.rb +++ b/mrbgems/mruby-class-ext/mrblib/module.rb @@ -4,7 +4,7 @@ class Module # call-seq: # mod < other -> true, false, or nil # - # Returns true if mod is a subclass of other. Returns + # Returns true if `mod` is a subclass of `other`. Returns # nil if there's no relationship between the two. # (Think of the relationship in terms of the class definition: # "class A < B" implies "A < B".) @@ -22,8 +22,8 @@ class Module # call-seq: # mod <= other -> true, false, or nil # - # Returns true if mod is a subclass of other or - # is the same as other. Returns + # Returns true if `mod` is a subclass of `other` or + # is the same as `other`. Returns # nil if there's no relationship between the two. # (Think of the relationship in terms of the class definition: # "class A < B" implies "A < B".) -- cgit v1.2.3 From d5d9cc8b62bd173375046d07fc62b75c3e2d807e Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Tue, 4 Dec 2018 08:40:23 +0900 Subject: Remove unnecessary check in `Module#<`; ref #4174 --- mrbgems/mruby-class-ext/mrblib/module.rb | 1 - 1 file changed, 1 deletion(-) diff --git a/mrbgems/mruby-class-ext/mrblib/module.rb b/mrbgems/mruby-class-ext/mrblib/module.rb index 484d63674..8102b5417 100644 --- a/mrbgems/mruby-class-ext/mrblib/module.rb +++ b/mrbgems/mruby-class-ext/mrblib/module.rb @@ -10,7 +10,6 @@ class Module # "class A < B" implies "A < B".) # def <(other) - raise TypeError, 'compared with non class/module' unless other.is_a?(Module) if self.equal?(other) false else -- cgit v1.2.3 From e6bad6766a8ddc00c23b1c0204b047dfbf8e3041 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Tue, 4 Dec 2018 08:41:09 +0900 Subject: Add new methods `Module#{>,>=,<=>}`; ref #4174 --- mrbgems/mruby-class-ext/mrblib/module.rb | 51 ++++++++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) diff --git a/mrbgems/mruby-class-ext/mrblib/module.rb b/mrbgems/mruby-class-ext/mrblib/module.rb index 8102b5417..301585187 100644 --- a/mrbgems/mruby-class-ext/mrblib/module.rb +++ b/mrbgems/mruby-class-ext/mrblib/module.rb @@ -35,4 +35,55 @@ class Module end end + ## + # call-seq: + # mod > other -> true, false, or nil + # + # Returns true if `mod` is an ancestor of `other`. Returns + # nil if there's no relationship between the two. + # (Think of the relationship in terms of the class definition: + # "class A < B" implies "B > A".) + # + def >(other) + if self.equal?(other) + false + else + self >= other + end + end + + ## + # call-seq: + # mod >= other -> true, false, or nil + # + # Returns true if `mod` is an ancestor of `other`, or the + # two modules are the same. Returns + # nil if there's no relationship between the two. + # (Think of the relationship in terms of the class definition: + # "class A < B" implies "B > A".) + # + def >=(other) + raise TypeError, 'compared with non class/module' unless other.is_a?(Module) + return other < self + end + + ## + # call-seq: + # module <=> other_module -> -1, 0, +1, or nil + # + # Comparison---Returns -1, 0, +1 or nil depending on whether `module` + # includes `other_module`, they are the same, or if `module` is included by + # `other_module`. + # + # Returns `nil` if `module` has no relationship with `other_module`, if + # `other_module` is not a module, or if the two values are incomparable. + # + def <=>(other) + return 0 if self.equal?(other) + return nil unless other.is_a?(Module) + cmp = self < other + return -1 if cmp + return 1 unless cmp.nil? + return nil + end end -- cgit v1.2.3 From 1d1b47044c7ead3a629a6c8979a5ce1bf81c65b1 Mon Sep 17 00:00:00 2001 From: Bhargava Shastry Date: Wed, 5 Dec 2018 17:45:27 +0100 Subject: ossfuzz: Add simple mruby compile test harness --- oss-fuzz/mruby_fuzzer.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100644 oss-fuzz/mruby_fuzzer.c diff --git a/oss-fuzz/mruby_fuzzer.c b/oss-fuzz/mruby_fuzzer.c new file mode 100644 index 000000000..9d3d44a5b --- /dev/null +++ b/oss-fuzz/mruby_fuzzer.c @@ -0,0 +1,18 @@ +#include +#include +#include +#include + +int LLVMFuzzerTestOneInput(uint8_t *Data, size_t size) { + if (size < 1) { + return 0; + } + char *code = malloc(size+1); + memcpy(code, Data, size); + code[size] = '\0'; + mrb_state *mrb = mrb_open(); + mrb_load_string(mrb, code); + mrb_close(mrb); + free(code); + return 0; +} -- cgit v1.2.3 From bccf9e4a3fd07ed82a57dcba138f926d400758b7 Mon Sep 17 00:00:00 2001 From: Bhargava Shastry Date: Wed, 5 Dec 2018 18:00:47 +0100 Subject: ossfuzz: Add fuzzing dictionary for mruby. --- oss-fuzz/mruby.dict | 105 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 105 insertions(+) create mode 100644 oss-fuzz/mruby.dict diff --git a/oss-fuzz/mruby.dict b/oss-fuzz/mruby.dict new file mode 100644 index 000000000..a332d3505 --- /dev/null +++ b/oss-fuzz/mruby.dict @@ -0,0 +1,105 @@ +keyword___ENCODING__="__ENCODING__" +keyword___FILE__="__FILE__" +keyword___LINE__="__LINE__" +keyword_BEGIN="BEGIN" +keyword_END="END" +keyword_alias="alias" +keyword_and="and" +keyword_begin="begin" +keyword_break="break" +keyword_case="case" +keyword_class="class" +keyword_def="def" +keyword_do="do" +keyword_else="else" +keyword_elsif="elsif" +keyword_end="end" +keyword_ensure="ensure" +keyword_false="false" +keyword_for="for" +keyword_if="if" +keyword_in="in" +keyword_module="module" +keyword_next="next" +keyword_nil="nil" +keyword_not="not" +keyword_or="or" +keyword_redo="redo" +keyword_rescue="rescue" +keyword_retry="retry" +keyword_return="return" +keyword_self="self" +keyword_super="super" +keyword_then="then" +keyword_true="true" +keyword_undef="undef" +keyword_unless="unless" +keyword_until="until" +keyword_when="when" +keyword_while="while" +keyword_yield="yield" + +operator_a=" !" +operator_b=" ~" +operator_c=" +" +operator_d=" -" +operator_e=" []" +operator_f=" []=" +operator_g=" *" +operator_h=" /" +operator_i=" %" +operator_j=" +-" +operator_k=" >>" +operator_l=" <<" +operator_m=" &" +operator_n=" ^" +operator_o=" |" +operator_p=" <=" +operator_q=" <>" +operator_r=" >=" +operator_s=" <=>" +operator_t=" ==" +operator_u=" ===" +operator_v=" !=" +operator_w=" =~" +operator_x=" !~" +operator_y=" &&" +operator_z=" ||" +operator_aa=" .." +operator_ab=" ..." +operator_ac=" ?" +operator_ad=" :" +operator_ae=" =" +operator_af=" %=" +operator_ag=" /=" +operator_ah=" -=" +operator_ai=" +=" +operator_aj=" |=" +operator_ak=" &=" +operator_al=" >>=" +operator_am=" <<=" +operator_an=" *=" +operator_ao=" &&=" +operator_ap=" ||=" +operator_aq=" **=" +operator_ar=" ^=" +operator_as=" not" +operator_at=" or" +operator_au=" and" +operator_av=" if" +operator_aw=" unless" +operator_ax=" while" +operator_ay=" until" +operator_az=" begin" +operator_ba=" end" + +snippet_1eq1=" 1=1" +snippet_dollar=" $1" +snippet_at=" @a" +snippet_symbol=" :a" +snippet_array=" [1,2]" +snippet_block=" 1.times{|x| x}" +snippet_multi=" 1*1" + +string_single_q=" 'a'" +string_dbl_q=" \"a\"" -- cgit v1.2.3 From 05b4eaac4b6bbf7d6e28887b48dcead2140c7d0b Mon Sep 17 00:00:00 2001 From: Bhargava Shastry Date: Wed, 5 Dec 2018 18:06:30 +0100 Subject: ossfuzz: Moved config related files to a namesake directory under ossfuzz --- oss-fuzz/config/mruby.dict | 105 +++++++++++++++++++++++++++++++++++ oss-fuzz/config/mruby_fuzzer.options | 3 + oss-fuzz/mruby.dict | 105 ----------------------------------- 3 files changed, 108 insertions(+), 105 deletions(-) create mode 100644 oss-fuzz/config/mruby.dict create mode 100644 oss-fuzz/config/mruby_fuzzer.options delete mode 100644 oss-fuzz/mruby.dict diff --git a/oss-fuzz/config/mruby.dict b/oss-fuzz/config/mruby.dict new file mode 100644 index 000000000..a332d3505 --- /dev/null +++ b/oss-fuzz/config/mruby.dict @@ -0,0 +1,105 @@ +keyword___ENCODING__="__ENCODING__" +keyword___FILE__="__FILE__" +keyword___LINE__="__LINE__" +keyword_BEGIN="BEGIN" +keyword_END="END" +keyword_alias="alias" +keyword_and="and" +keyword_begin="begin" +keyword_break="break" +keyword_case="case" +keyword_class="class" +keyword_def="def" +keyword_do="do" +keyword_else="else" +keyword_elsif="elsif" +keyword_end="end" +keyword_ensure="ensure" +keyword_false="false" +keyword_for="for" +keyword_if="if" +keyword_in="in" +keyword_module="module" +keyword_next="next" +keyword_nil="nil" +keyword_not="not" +keyword_or="or" +keyword_redo="redo" +keyword_rescue="rescue" +keyword_retry="retry" +keyword_return="return" +keyword_self="self" +keyword_super="super" +keyword_then="then" +keyword_true="true" +keyword_undef="undef" +keyword_unless="unless" +keyword_until="until" +keyword_when="when" +keyword_while="while" +keyword_yield="yield" + +operator_a=" !" +operator_b=" ~" +operator_c=" +" +operator_d=" -" +operator_e=" []" +operator_f=" []=" +operator_g=" *" +operator_h=" /" +operator_i=" %" +operator_j=" +-" +operator_k=" >>" +operator_l=" <<" +operator_m=" &" +operator_n=" ^" +operator_o=" |" +operator_p=" <=" +operator_q=" <>" +operator_r=" >=" +operator_s=" <=>" +operator_t=" ==" +operator_u=" ===" +operator_v=" !=" +operator_w=" =~" +operator_x=" !~" +operator_y=" &&" +operator_z=" ||" +operator_aa=" .." +operator_ab=" ..." +operator_ac=" ?" +operator_ad=" :" +operator_ae=" =" +operator_af=" %=" +operator_ag=" /=" +operator_ah=" -=" +operator_ai=" +=" +operator_aj=" |=" +operator_ak=" &=" +operator_al=" >>=" +operator_am=" <<=" +operator_an=" *=" +operator_ao=" &&=" +operator_ap=" ||=" +operator_aq=" **=" +operator_ar=" ^=" +operator_as=" not" +operator_at=" or" +operator_au=" and" +operator_av=" if" +operator_aw=" unless" +operator_ax=" while" +operator_ay=" until" +operator_az=" begin" +operator_ba=" end" + +snippet_1eq1=" 1=1" +snippet_dollar=" $1" +snippet_at=" @a" +snippet_symbol=" :a" +snippet_array=" [1,2]" +snippet_block=" 1.times{|x| x}" +snippet_multi=" 1*1" + +string_single_q=" 'a'" +string_dbl_q=" \"a\"" diff --git a/oss-fuzz/config/mruby_fuzzer.options b/oss-fuzz/config/mruby_fuzzer.options new file mode 100644 index 000000000..5d1c8d2da --- /dev/null +++ b/oss-fuzz/config/mruby_fuzzer.options @@ -0,0 +1,3 @@ +[libfuzzer] +close_fd_mask=3 +dict=mruby.dict diff --git a/oss-fuzz/mruby.dict b/oss-fuzz/mruby.dict deleted file mode 100644 index a332d3505..000000000 --- a/oss-fuzz/mruby.dict +++ /dev/null @@ -1,105 +0,0 @@ -keyword___ENCODING__="__ENCODING__" -keyword___FILE__="__FILE__" -keyword___LINE__="__LINE__" -keyword_BEGIN="BEGIN" -keyword_END="END" -keyword_alias="alias" -keyword_and="and" -keyword_begin="begin" -keyword_break="break" -keyword_case="case" -keyword_class="class" -keyword_def="def" -keyword_do="do" -keyword_else="else" -keyword_elsif="elsif" -keyword_end="end" -keyword_ensure="ensure" -keyword_false="false" -keyword_for="for" -keyword_if="if" -keyword_in="in" -keyword_module="module" -keyword_next="next" -keyword_nil="nil" -keyword_not="not" -keyword_or="or" -keyword_redo="redo" -keyword_rescue="rescue" -keyword_retry="retry" -keyword_return="return" -keyword_self="self" -keyword_super="super" -keyword_then="then" -keyword_true="true" -keyword_undef="undef" -keyword_unless="unless" -keyword_until="until" -keyword_when="when" -keyword_while="while" -keyword_yield="yield" - -operator_a=" !" -operator_b=" ~" -operator_c=" +" -operator_d=" -" -operator_e=" []" -operator_f=" []=" -operator_g=" *" -operator_h=" /" -operator_i=" %" -operator_j=" +-" -operator_k=" >>" -operator_l=" <<" -operator_m=" &" -operator_n=" ^" -operator_o=" |" -operator_p=" <=" -operator_q=" <>" -operator_r=" >=" -operator_s=" <=>" -operator_t=" ==" -operator_u=" ===" -operator_v=" !=" -operator_w=" =~" -operator_x=" !~" -operator_y=" &&" -operator_z=" ||" -operator_aa=" .." -operator_ab=" ..." -operator_ac=" ?" -operator_ad=" :" -operator_ae=" =" -operator_af=" %=" -operator_ag=" /=" -operator_ah=" -=" -operator_ai=" +=" -operator_aj=" |=" -operator_ak=" &=" -operator_al=" >>=" -operator_am=" <<=" -operator_an=" *=" -operator_ao=" &&=" -operator_ap=" ||=" -operator_aq=" **=" -operator_ar=" ^=" -operator_as=" not" -operator_at=" or" -operator_au=" and" -operator_av=" if" -operator_aw=" unless" -operator_ax=" while" -operator_ay=" until" -operator_az=" begin" -operator_ba=" end" - -snippet_1eq1=" 1=1" -snippet_dollar=" $1" -snippet_at=" @a" -snippet_symbol=" :a" -snippet_array=" [1,2]" -snippet_block=" 1.times{|x| x}" -snippet_multi=" 1*1" - -string_single_q=" 'a'" -string_dbl_q=" \"a\"" -- cgit v1.2.3 From c23e68d32b8913f35e344844805d1b80f5633ecd Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Mon, 10 Dec 2018 10:23:01 +0900 Subject: Need to clear stack before invoking a block; fix #4181 --- src/vm.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/vm.c b/src/vm.c index 84e076ee8..b5249b325 100644 --- a/src/vm.c +++ b/src/vm.c @@ -667,10 +667,11 @@ eval_under(mrb_state *mrb, mrb_value self, mrb_value blk, struct RClass *c) return MRB_PROC_CFUNC(p)(mrb, self); } nregs = p->body.irep->nregs; - mrb_stack_extend(mrb, (nregs < 3) ? 3 : nregs); + if (nregs < 3) nregs = 3; + mrb_stack_extend(mrb, nregs); mrb->c->stack[0] = self; mrb->c->stack[1] = self; - mrb->c->stack[2] = mrb_nil_value(); + stack_clear(mrb->c->stack+2, nregs-2); ci = cipush(mrb); ci->target_class = 0; ci->pc = p->body.irep->iseq; -- cgit v1.2.3 From c0d91a14e78de39b3940e56d4cccdbdb17b65694 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Tue, 11 Dec 2018 09:01:05 +0900 Subject: Add API function `mrb_hash_foreach()` to iterate over items in a hash. --- include/mruby/hash.h | 4 ++++ src/hash.c | 10 +++++++--- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/include/mruby/hash.h b/include/mruby/hash.h index 7811894ae..9b20bf9e6 100644 --- a/include/mruby/hash.h +++ b/include/mruby/hash.h @@ -210,6 +210,10 @@ void mrb_gc_mark_hash(mrb_state*, struct RHash*); size_t mrb_gc_mark_hash_size(mrb_state*, struct RHash*); void mrb_gc_free_hash(mrb_state*, struct RHash*); +/* return non zero to break the loop */ +typedef int (ht_foreach_func)(mrb_state *mrb, mrb_value key, mrb_value val, void *data); +MRB_API void mrb_hash_foreach(mrb_state *mrb, struct RHash *hash, ht_foreach_func *func, void *p); + MRB_END_DECL #endif /* MRUBY_HASH_H */ diff --git a/src/hash.c b/src/hash.c index 467b20a51..00d5ad2b1 100644 --- a/src/hash.c +++ b/src/hash.c @@ -16,9 +16,6 @@ mrb_int mrb_float_id(mrb_float f); #endif -/* return non zero to break the loop */ -typedef int (ht_foreach_func)(mrb_state *mrb,mrb_value key, mrb_value val, void *data); - #ifndef MRB_HT_INIT_SIZE #define MRB_HT_INIT_SIZE 4 #endif @@ -522,6 +519,13 @@ ht_foreach(mrb_state *mrb, htable *t, ht_foreach_func *func, void *p) } } +/* Iterates over the instance variable table. */ +MRB_API void +mrb_hash_foreach(mrb_state *mrb, struct RHash *hash, ht_foreach_func *func, void *p) +{ + ht_foreach(mrb, hash->ht, func, p); +} + /* Copy the instance variable table. */ static htable* ht_copy(mrb_state *mrb, htable *t) -- cgit v1.2.3 From 378c728338c7dd828daf32468b4ce4f73fae4cb6 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Tue, 11 Dec 2018 09:04:08 +0900 Subject: Update comments. --- src/hash.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/hash.c b/src/hash.c index 00d5ad2b1..5920fe2c3 100644 --- a/src/hash.c +++ b/src/hash.c @@ -38,7 +38,7 @@ typedef struct segindex { struct segkv *table[]; } segindex; -/* Instance variable table structure */ +/* hash table structure */ typedef struct htable { segment *rootseg; segment *lastseg; @@ -132,7 +132,7 @@ ht_hash_equal(mrb_state *mrb, htable *t, mrb_value a, mrb_value b) } } -/* Creates the instance variable table. */ +/* Creates the hash table. */ static htable* ht_new(mrb_state *mrb) { @@ -346,7 +346,7 @@ ht_index_put(mrb_state *mrb, htable *t, mrb_value key, mrb_value val) t->size++; } -/* Set the value for the key in the table. */ +/* Set the value for the key in the hash table. */ static void ht_put(mrb_state *mrb, htable *t, mrb_value key, mrb_value val) { @@ -465,7 +465,7 @@ ht_get(mrb_state *mrb, htable *t, mrb_value key, mrb_value *vp) return FALSE; } -/* Deletes the value for the symbol from the instance variable table. */ +/* Deletes the value for the symbol from the hash table. */ /* Deletion is done by overwriting keys by `undef`. */ static mrb_bool ht_del(mrb_state *mrb, htable *t, mrb_value key, mrb_value *vp) @@ -496,7 +496,7 @@ ht_del(mrb_state *mrb, htable *t, mrb_value key, mrb_value *vp) return FALSE; } -/* Iterates over the instance variable table. */ +/* Iterates over the hash table. */ static void ht_foreach(mrb_state *mrb, htable *t, ht_foreach_func *func, void *p) { @@ -519,14 +519,14 @@ ht_foreach(mrb_state *mrb, htable *t, ht_foreach_func *func, void *p) } } -/* Iterates over the instance variable table. */ +/* Iterates over the hash table. */ MRB_API void mrb_hash_foreach(mrb_state *mrb, struct RHash *hash, ht_foreach_func *func, void *p) { ht_foreach(mrb, hash->ht, func, p); } -/* Copy the instance variable table. */ +/* Copy the hash table. */ static htable* ht_copy(mrb_state *mrb, htable *t) { @@ -552,7 +552,7 @@ ht_copy(mrb_state *mrb, htable *t) return t2; } -/* Free memory of the instance variable table. */ +/* Free memory of the hash table. */ static void ht_free(mrb_state *mrb, htable *t) { @@ -1012,7 +1012,7 @@ mrb_hash_delete(mrb_state *mrb, mrb_value self) return mrb_hash_delete_key(mrb, self, key); } -/* find first element in a hash table, and remove it. */ +/* find first element in the hash table, and remove it. */ static void ht_shift(mrb_state *mrb, htable *t, mrb_value *kp, mrb_value *vp) { -- cgit v1.2.3 From 716e7b815ff8bff50226ce49759493aec4ef5103 Mon Sep 17 00:00:00 2001 From: Hiroshi Mimaki Date: Tue, 11 Dec 2018 09:37:23 +0900 Subject: Fixed missing comma in mruby/mirb usage. --- mrbgems/mruby-bin-mirb/tools/mirb/mirb.c | 2 +- mrbgems/mruby-bin-mruby/tools/mruby/mruby.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/mrbgems/mruby-bin-mirb/tools/mirb/mirb.c b/mrbgems/mruby-bin-mirb/tools/mirb/mirb.c index 8d7c719d8..9519d88bb 100644 --- a/mrbgems/mruby-bin-mirb/tools/mirb/mirb.c +++ b/mrbgems/mruby-bin-mirb/tools/mirb/mirb.c @@ -230,7 +230,7 @@ usage(const char *name) { static const char *const usage_msg[] = { "switches:", - "-d set $DEBUG to true (same as `mruby -d`)" + "-d set $DEBUG to true (same as `mruby -d`)", "-r library same as `mruby -r`", "-v print version number, then run in verbose mode", "--verbose run in verbose mode", diff --git a/mrbgems/mruby-bin-mruby/tools/mruby/mruby.c b/mrbgems/mruby-bin-mruby/tools/mruby/mruby.c index caf8e78c2..498bedef2 100644 --- a/mrbgems/mruby-bin-mruby/tools/mruby/mruby.c +++ b/mrbgems/mruby-bin-mruby/tools/mruby/mruby.c @@ -41,7 +41,7 @@ usage(const char *name) "switches:", "-b load and execute RiteBinary (mrb) file", "-c check syntax only", - "-d set debugging flags (set $DEBUG to true)" + "-d set debugging flags (set $DEBUG to true)", "-e 'command' one line of script", "-r library load the library before executing your script", "-v print version number, then run in verbose mode", -- cgit v1.2.3 From f6b2e6231a1c07438915c2d32ab6002c2a2256b9 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Tue, 11 Dec 2018 09:47:06 +0900 Subject: Update `iv_foreach()` function. * return `void` instead of `mrb_bool'. * non zero return value from `func` breaks the loop. * no longer remove items on negative return value from `func`. --- src/variable.c | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/src/variable.c b/src/variable.c index 72c13aa1f..669a4f5cd 100644 --- a/src/variable.c +++ b/src/variable.c @@ -156,14 +156,13 @@ iv_del(mrb_state *mrb, iv_tbl *t, mrb_sym sym, mrb_value *vp) } /* Iterates over the instance variable table. */ -static mrb_bool +static void iv_foreach(mrb_state *mrb, iv_tbl *t, iv_foreach_func *func, void *p) { segment *seg; size_t i; - int n; - if (t == NULL) return TRUE; + if (t == NULL) return; seg = t->rootseg; while (seg) { for (i=0; inext && i >= t->last_len) { - return FALSE; + return; } if (key != 0) { - n =(*func)(mrb, key, seg->val[i], p); - if (n > 0) return FALSE; - if (n < 0) { - t->size--; - seg->key[i] = 0; + if ((*func)(mrb, key, seg->val[i], p) != 0) { + return; } } } seg = seg->next; } - return TRUE; + return; } /* Get the size of the instance variable table. */ -- cgit v1.2.3 From a0df27d8e04f5d042040c794b79b9b213e7092e0 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Tue, 11 Dec 2018 09:48:15 +0900 Subject: Add new API `mrb_iv_foreach()` to iterate over instance variables. --- include/mruby/variable.h | 4 ++++ src/variable.c | 11 +++++++++-- 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/include/mruby/variable.h b/include/mruby/variable.h index a0fbca1f9..c031567ea 100644 --- a/include/mruby/variable.h +++ b/include/mruby/variable.h @@ -131,6 +131,10 @@ void mrb_gc_mark_iv(mrb_state*, struct RObject*); size_t mrb_gc_mark_iv_size(mrb_state*, struct RObject*); void mrb_gc_free_iv(mrb_state*, struct RObject*); +/* return non zero to break the loop */ +typedef int (iv_foreach_func)(mrb_state*,mrb_sym,mrb_value,void*); +MRB_API void mrb_iv_foreach(mrb_state *mrb, mrb_value obj, iv_foreach_func *func, void *p); + MRB_END_DECL #endif /* MRUBY_VARIABLE_H */ diff --git a/src/variable.c b/src/variable.c index 669a4f5cd..fafec81bd 100644 --- a/src/variable.c +++ b/src/variable.c @@ -9,8 +9,7 @@ #include #include #include - -typedef int (iv_foreach_func)(mrb_state*,mrb_sym,mrb_value,void*); +#include #ifndef MRB_IV_SEGMENT_SIZE #define MRB_IV_SEGMENT_SIZE 4 @@ -359,6 +358,14 @@ mrb_obj_iv_set(mrb_state *mrb, struct RObject *obj, mrb_sym sym, mrb_value v) mrb_write_barrier(mrb, (struct RBasic*)obj); } +/* Iterates over the instance variable table. */ +MRB_API void +mrb_iv_foreach(mrb_state *mrb, mrb_value obj, iv_foreach_func *func, void *p) +{ + if (!obj_iv_p(obj)) return; + iv_foreach(mrb, mrb_obj_ptr(obj)->iv, func, p); +} + static inline mrb_bool namespace_p(enum mrb_vtype tt) { -- cgit v1.2.3 From e935d20ab52ddc68d4d55444d0fa3974b035c098 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Tue, 11 Dec 2018 10:39:53 +0900 Subject: Add `mrb_` prefix to `iv_foreach_func`. --- include/mruby/variable.h | 4 ++-- src/variable.c | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/include/mruby/variable.h b/include/mruby/variable.h index c031567ea..68a2a7121 100644 --- a/include/mruby/variable.h +++ b/include/mruby/variable.h @@ -132,8 +132,8 @@ size_t mrb_gc_mark_iv_size(mrb_state*, struct RObject*); void mrb_gc_free_iv(mrb_state*, struct RObject*); /* return non zero to break the loop */ -typedef int (iv_foreach_func)(mrb_state*,mrb_sym,mrb_value,void*); -MRB_API void mrb_iv_foreach(mrb_state *mrb, mrb_value obj, iv_foreach_func *func, void *p); +typedef int (mrb_iv_foreach_func)(mrb_state*,mrb_sym,mrb_value,void*); +MRB_API void mrb_iv_foreach(mrb_state *mrb, mrb_value obj, mrb_iv_foreach_func *func, void *p); MRB_END_DECL diff --git a/src/variable.c b/src/variable.c index fafec81bd..14e9da9ef 100644 --- a/src/variable.c +++ b/src/variable.c @@ -156,7 +156,7 @@ iv_del(mrb_state *mrb, iv_tbl *t, mrb_sym sym, mrb_value *vp) /* Iterates over the instance variable table. */ static void -iv_foreach(mrb_state *mrb, iv_tbl *t, iv_foreach_func *func, void *p) +iv_foreach(mrb_state *mrb, iv_tbl *t, mrb_iv_foreach_func *func, void *p) { segment *seg; size_t i; @@ -360,7 +360,7 @@ mrb_obj_iv_set(mrb_state *mrb, struct RObject *obj, mrb_sym sym, mrb_value v) /* Iterates over the instance variable table. */ MRB_API void -mrb_iv_foreach(mrb_state *mrb, mrb_value obj, iv_foreach_func *func, void *p) +mrb_iv_foreach(mrb_state *mrb, mrb_value obj, mrb_iv_foreach_func *func, void *p) { if (!obj_iv_p(obj)) return; iv_foreach(mrb, mrb_obj_ptr(obj)->iv, func, p); -- cgit v1.2.3 From 265171a28c2805ae49d0ad70d0f35220b4cb4d4b Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Tue, 11 Dec 2018 10:41:26 +0900 Subject: Rename `ht_foreach_func` to `mrb_hash_foreach_func`. --- include/mruby/hash.h | 4 ++-- src/hash.c | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/include/mruby/hash.h b/include/mruby/hash.h index 9b20bf9e6..911a96042 100644 --- a/include/mruby/hash.h +++ b/include/mruby/hash.h @@ -211,8 +211,8 @@ size_t mrb_gc_mark_hash_size(mrb_state*, struct RHash*); void mrb_gc_free_hash(mrb_state*, struct RHash*); /* return non zero to break the loop */ -typedef int (ht_foreach_func)(mrb_state *mrb, mrb_value key, mrb_value val, void *data); -MRB_API void mrb_hash_foreach(mrb_state *mrb, struct RHash *hash, ht_foreach_func *func, void *p); +typedef int (mrb_hash_foreach_func)(mrb_state *mrb, mrb_value key, mrb_value val, void *data); +MRB_API void mrb_hash_foreach(mrb_state *mrb, struct RHash *hash, mrb_hash_foreach_func *func, void *p); MRB_END_DECL diff --git a/src/hash.c b/src/hash.c index 5920fe2c3..cb4a274e8 100644 --- a/src/hash.c +++ b/src/hash.c @@ -498,7 +498,7 @@ ht_del(mrb_state *mrb, htable *t, mrb_value key, mrb_value *vp) /* Iterates over the hash table. */ static void -ht_foreach(mrb_state *mrb, htable *t, ht_foreach_func *func, void *p) +ht_foreach(mrb_state *mrb, htable *t, mrb_hash_foreach_func *func, void *p) { segment *seg; mrb_int i; @@ -521,7 +521,7 @@ ht_foreach(mrb_state *mrb, htable *t, ht_foreach_func *func, void *p) /* Iterates over the hash table. */ MRB_API void -mrb_hash_foreach(mrb_state *mrb, struct RHash *hash, ht_foreach_func *func, void *p) +mrb_hash_foreach(mrb_state *mrb, struct RHash *hash, mrb_hash_foreach_func *func, void *p) { ht_foreach(mrb, hash->ht, func, p); } -- cgit v1.2.3 From 1c09046c13fc0a763583c6da0f1d350f6c41c4ca Mon Sep 17 00:00:00 2001 From: Hiroshi Mimaki Date: Tue, 11 Dec 2018 10:52:20 +0900 Subject: Update release date. --- README.md | 2 +- doc/guides/debugger.md | 2 +- doc/limitations.md | 14 +++++++------- include/mruby/version.h | 4 ++-- 4 files changed, 11 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index 529091bdc..e43510ebe 100644 --- a/README.md +++ b/README.md @@ -17,7 +17,7 @@ of the Ministry of Economy, Trade and Industry of Japan. ## How to get mruby -The stable version 1.4.1 of mruby can be downloaded via the following URL: [https://github.com/mruby/mruby/archive/1.4.1.zip](https://github.com/mruby/mruby/archive/1.4.1.zip) +The stable version 2.0.0 of mruby can be downloaded via the following URL: [https://github.com/mruby/mruby/archive/2.0.0.zip](https://github.com/mruby/mruby/archive/2.0.0.zip) The latest development version of mruby can be downloaded via the following URL: [https://github.com/mruby/mruby/zipball/master](https://github.com/mruby/mruby/zipball/master) diff --git a/doc/guides/debugger.md b/doc/guides/debugger.md index 1cc7a9a39..b433a5ac5 100644 --- a/doc/guides/debugger.md +++ b/doc/guides/debugger.md @@ -38,7 +38,7 @@ To confirm mrdb was installed properly, run mrdb with the `--version` option: ```bash $ mrdb --version -mruby 1.4.1 (2018-4-27) +mruby 2.0.0 (2018-12-11) ``` ## 2.2 Basic Operation diff --git a/doc/limitations.md b/doc/limitations.md index 825435f01..23017ccbe 100644 --- a/doc/limitations.md +++ b/doc/limitations.md @@ -38,7 +38,7 @@ puts [1,2,3] 3 ``` -#### mruby [1.4.1 (2018-4-27)] +#### mruby [2.0.0 (2018-12-11)] ``` [1, 2, 3] @@ -61,7 +61,7 @@ end ```ZeroDivisionError``` is raised. -#### mruby [1.4.1 (2018-4-27)] +#### mruby [2.0.0 (2018-12-11)] No exception is raised. @@ -119,7 +119,7 @@ false true ``` -#### mruby [1.4.1 (2018-4-27)] +#### mruby [2.0.0 (2018-12-11)] ``` true @@ -142,7 +142,7 @@ defined?(Foo) nil ``` -#### mruby [1.4.1 (2018-4-27)] +#### mruby [2.0.0 (2018-12-11)] ```NameError``` is raised. @@ -159,7 +159,7 @@ alias $a $__a__ ``` nil ``` -#### mruby [1.4.1 (2018-4-27)] +#### mruby [2.0.0 (2018-12-11)] Syntax error @@ -181,7 +181,7 @@ end ```ArgumentError``` is raised. The re-defined ```+``` operator does not accept any arguments. -#### mruby [1.4.1 (2018-4-27)] +#### mruby [2.0.0 (2018-12-11)] ``` 'ab' ``` Behavior of the operator wasn't changed. @@ -197,7 +197,7 @@ $ ruby -e 'puts Proc.new {}.binding' # ``` -#### mruby [1.4.1 (2018-4-27)] +#### mruby [2.0.0 (2018-12-11)] ``` $ ./bin/mruby -e 'puts Proc.new {}.binding' diff --git a/include/mruby/version.h b/include/mruby/version.h index daeca4b75..680533ab4 100644 --- a/include/mruby/version.h +++ b/include/mruby/version.h @@ -67,12 +67,12 @@ MRB_BEGIN_DECL /* * Release month. */ -#define MRUBY_RELEASE_MONTH 4 +#define MRUBY_RELEASE_MONTH 12 /* * Release day. */ -#define MRUBY_RELEASE_DAY 27 +#define MRUBY_RELEASE_DAY 11 /* * Release date as a string. -- cgit v1.2.3 From 60da293d5c4f4d00798f06ad955ea12311b6fd68 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Tue, 11 Dec 2018 10:54:47 +0900 Subject: Avoid using floating point number for HT_SEG_INCREASE_RATIO; ref #4182 --- src/hash.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hash.c b/src/hash.c index cb4a274e8..3d6c2ed7d 100644 --- a/src/hash.c +++ b/src/hash.c @@ -19,7 +19,7 @@ mrb_int mrb_float_id(mrb_float f); #ifndef MRB_HT_INIT_SIZE #define MRB_HT_INIT_SIZE 4 #endif -#define HT_SEG_INCREASE_RATIO 1.2 +#define HT_SEG_INCREASE_RATIO 6 / 5 struct segkv { mrb_value key; -- cgit v1.2.3 From 74c54022118578c65a7ad97a23bb68599986be65 Mon Sep 17 00:00:00 2001 From: icm7216 Date: Wed, 12 Dec 2018 00:52:07 +0900 Subject: Sleep module is undefined. Remove module name. --- mrbgems/mruby-sleep/README.md | 4 ++-- mrbgems/mruby-sleep/example/sleep.rb | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/mrbgems/mruby-sleep/README.md b/mrbgems/mruby-sleep/README.md index 4543c49cf..a4ecba7d7 100644 --- a/mrbgems/mruby-sleep/README.md +++ b/mrbgems/mruby-sleep/README.md @@ -15,8 +15,8 @@ end ## example ```ruby -Sleep::sleep(10) -Sleep::usleep(10000) +sleep(10) +usleep(10000) ``` # License diff --git a/mrbgems/mruby-sleep/example/sleep.rb b/mrbgems/mruby-sleep/example/sleep.rb index dfe86af27..e5acea3b2 100644 --- a/mrbgems/mruby-sleep/example/sleep.rb +++ b/mrbgems/mruby-sleep/example/sleep.rb @@ -1,3 +1,3 @@ -Sleep::sleep(10) -Sleep::usleep(10000) +sleep(10) +usleep(10000) -- cgit v1.2.3 From 59651f43ad30dc48e2872b950697562d4a14e62a Mon Sep 17 00:00:00 2001 From: icm7216 Date: Wed, 12 Dec 2018 00:54:15 +0900 Subject: Specify the core library instead of the external library. --- mrbgems/mruby-sleep/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mrbgems/mruby-sleep/README.md b/mrbgems/mruby-sleep/README.md index a4ecba7d7..7707cd040 100644 --- a/mrbgems/mruby-sleep/README.md +++ b/mrbgems/mruby-sleep/README.md @@ -8,7 +8,7 @@ MRuby::Build.new do |conf| # ... (snip) ... - conf.gem :git => 'https://github.com/matsumoto-r/mruby-sleep.git' + conf.gem :core => 'mruby-sleep' end ``` -- cgit v1.2.3 From 62dd4d89fc6da2c38a9bc1913c1f25566a9e443e Mon Sep 17 00:00:00 2001 From: dearblue Date: Fri, 14 Dec 2018 21:41:07 +0900 Subject: Add `mrb_hash_size()` function. --- include/mruby/hash.h | 13 +++++++++++++ src/hash.c | 14 ++++++++++---- 2 files changed, 23 insertions(+), 4 deletions(-) diff --git a/include/mruby/hash.h b/include/mruby/hash.h index 911a96042..ce51b2016 100644 --- a/include/mruby/hash.h +++ b/include/mruby/hash.h @@ -165,6 +165,19 @@ MRB_API mrb_value mrb_hash_values(mrb_state *mrb, mrb_value hash); */ MRB_API mrb_value mrb_hash_clear(mrb_state *mrb, mrb_value hash); +/* + * Get hash size. + * + * Equivalent to: + * + * hash.size + * + * @param mrb The mruby state reference. + * @param hash The target hash. + * @return The hash size. + */ +MRB_API mrb_int mrb_hash_size(mrb_state *mrb, mrb_value hash); + /* * Copies the hash. * diff --git a/src/hash.c b/src/hash.c index 3d6c2ed7d..2f60eb74a 100644 --- a/src/hash.c +++ b/src/hash.c @@ -1133,6 +1133,15 @@ mrb_hash_aset(mrb_state *mrb, mrb_value self) return val; } +MRB_API mrb_int +mrb_hash_size(mrb_state *mrb, mrb_value hash) +{ + htable *t = RHASH_TBL(hash); + + if (!t) return 0; + return t->size; +} + /* 15.2.13.4.20 */ /* 15.2.13.4.25 */ /* @@ -1150,10 +1159,7 @@ mrb_hash_aset(mrb_state *mrb, mrb_value self) static mrb_value mrb_hash_size_m(mrb_state *mrb, mrb_value self) { - htable *t = RHASH_TBL(self); - - if (!t) return mrb_fixnum_value(0); - return mrb_fixnum_value(t->size); + return mrb_fixnum_value(mrb_hash_size(mrb, self)); } MRB_API mrb_bool -- cgit v1.2.3 From d8c70167f736dc4c3828f008658b69cd45f93363 Mon Sep 17 00:00:00 2001 From: Takashi Sawanaka Date: Sat, 15 Dec 2018 05:17:38 +0900 Subject: Make mrb_ary_clear() function callable from C again --- src/array.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/array.c b/src/array.c index 084b48dc0..707820ab9 100644 --- a/src/array.c +++ b/src/array.c @@ -1089,7 +1089,6 @@ mrb_ary_clear(mrb_state *mrb, mrb_value self) { struct RArray *a = mrb_ary_ptr(self); - mrb_get_args(mrb, ""); ary_modify(mrb, a); if (ARY_SHARED_P(a)) { mrb_ary_decref(mrb, a->as.heap.aux.shared); @@ -1103,6 +1102,13 @@ mrb_ary_clear(mrb_state *mrb, mrb_value self) return self; } +static mrb_value +mrb_ary_clear_m(mrb_state *mrb, mrb_value self) +{ + mrb_get_args(mrb, ""); + return mrb_ary_clear(mrb, self); +} + static mrb_value mrb_ary_empty_p(mrb_state *mrb, mrb_value self) { @@ -1268,7 +1274,7 @@ mrb_init_array(mrb_state *mrb) mrb_define_method(mrb, a, "<<", mrb_ary_push_m, MRB_ARGS_REQ(1)); /* 15.2.12.5.3 */ mrb_define_method(mrb, a, "[]", mrb_ary_aget, MRB_ARGS_ANY()); /* 15.2.12.5.4 */ mrb_define_method(mrb, a, "[]=", mrb_ary_aset, MRB_ARGS_ANY()); /* 15.2.12.5.5 */ - mrb_define_method(mrb, a, "clear", mrb_ary_clear, MRB_ARGS_NONE()); /* 15.2.12.5.6 */ + mrb_define_method(mrb, a, "clear", mrb_ary_clear_m, MRB_ARGS_NONE()); /* 15.2.12.5.6 */ mrb_define_method(mrb, a, "concat", mrb_ary_concat_m, MRB_ARGS_REQ(1)); /* 15.2.12.5.8 */ mrb_define_method(mrb, a, "delete_at", mrb_ary_delete_at, MRB_ARGS_REQ(1)); /* 15.2.12.5.9 */ mrb_define_method(mrb, a, "empty?", mrb_ary_empty_p, MRB_ARGS_NONE()); /* 15.2.12.5.12 */ -- cgit v1.2.3 From c03fa0e1b3acea696c8715a679915bb58b067403 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Mon, 17 Dec 2018 15:47:17 +0900 Subject: Recover `String#to_str`; ref #4177 We have removed implicit conversion to strings using `to_str`. But some people still using `to_str` as a typical string method, i.e. they do string check by code like: `obj.respond_to?(:to_str)`. So we have recovered the method. --- src/string.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/string.c b/src/string.c index 2668a2c85..52941473c 100644 --- a/src/string.c +++ b/src/string.c @@ -2754,6 +2754,7 @@ mrb_init_string(mrb_state *mrb) #endif mrb_define_method(mrb, s, "to_i", mrb_str_to_i, MRB_ARGS_ANY()); /* 15.2.10.5.39 */ mrb_define_method(mrb, s, "to_s", mrb_str_to_s, MRB_ARGS_NONE()); /* 15.2.10.5.40 */ + mrb_define_method(mrb, s, "to_str", mrb_str_to_s, MRB_ARGS_NONE()); mrb_define_method(mrb, s, "to_sym", mrb_str_intern, MRB_ARGS_NONE()); /* 15.2.10.5.41 */ mrb_define_method(mrb, s, "upcase", mrb_str_upcase, MRB_ARGS_NONE()); /* 15.2.10.5.42 */ mrb_define_method(mrb, s, "upcase!", mrb_str_upcase_bang, MRB_ARGS_NONE()); /* 15.2.10.5.43 */ -- cgit v1.2.3 From e690314525d3ebfa23eda9f2cacfff37bd53482a Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Mon, 17 Dec 2018 15:52:04 +0900 Subject: Recover `#to_int`; ref #4177 We have removed implicit conversion to strings using `to_int`. But some users still using `to_int` as a typical integer method, i.e. they do string check by code like: `obj.respond_to?(:to_int)`. So we have recovered the method. --- src/numeric.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/numeric.c b/src/numeric.c index 3624831cc..077ae30aa 100644 --- a/src/numeric.c +++ b/src/numeric.c @@ -1511,6 +1511,7 @@ mrb_init_numeric(mrb_state *mrb) MRB_SET_INSTANCE_TT(integer, MRB_TT_FIXNUM); mrb_undef_class_method(mrb, integer, "new"); mrb_define_method(mrb, integer, "to_i", int_to_i, MRB_ARGS_NONE()); /* 15.2.8.3.24 */ + mrb_define_method(mrb, integer, "to_int", int_to_i, MRB_ARGS_NONE()); #ifndef MRB_WITHOUT_FLOAT mrb_define_method(mrb, integer, "ceil", int_to_i, MRB_ARGS_REQ(1)); /* 15.2.8.3.8 (x) */ mrb_define_method(mrb, integer, "floor", int_to_i, MRB_ARGS_REQ(1)); /* 15.2.8.3.10 (x) */ @@ -1562,6 +1563,7 @@ mrb_init_numeric(mrb_state *mrb) mrb_define_method(mrb, fl, "round", flo_round, MRB_ARGS_OPT(1)); /* 15.2.9.3.12 */ mrb_define_method(mrb, fl, "to_f", flo_to_f, MRB_ARGS_NONE()); /* 15.2.9.3.13 */ mrb_define_method(mrb, fl, "to_i", flo_truncate, MRB_ARGS_NONE()); /* 15.2.9.3.14 */ + mrb_define_method(mrb, fl, "to_int", flo_truncate, MRB_ARGS_NONE()); mrb_define_method(mrb, fl, "truncate", flo_truncate, MRB_ARGS_NONE()); /* 15.2.9.3.15 */ mrb_define_method(mrb, fl, "divmod", flo_divmod, MRB_ARGS_REQ(1)); mrb_define_method(mrb, fl, "eql?", flo_eql, MRB_ARGS_REQ(1)); /* 15.2.8.3.16 */ -- cgit v1.2.3 From e65d42644afc11c15d5eaf5553c97e575020681f Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Mon, 17 Dec 2018 15:57:54 +0900 Subject: Remove `#include ` from `mruby/hash.h`. --- include/mruby/hash.h | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/include/mruby/hash.h b/include/mruby/hash.h index ce51b2016..7e2ed5596 100644 --- a/include/mruby/hash.h +++ b/include/mruby/hash.h @@ -8,7 +8,6 @@ #define MRUBY_HASH_H #include "common.h" -#include /** * Hash class @@ -198,15 +197,13 @@ MRB_API mrb_value mrb_hash_dup(mrb_state *mrb, mrb_value hash); */ MRB_API void mrb_hash_merge(mrb_state *mrb, mrb_value hash1, mrb_value hash2); -/* declaration of struct kh_ht */ +/* declaration of struct mrb_hash_value */ /* be careful when you touch the internal */ typedef struct { mrb_value v; mrb_int n; } mrb_hash_value; -KHASH_DECLARE(ht, mrb_value, mrb_hash_value, TRUE) - /* RHASH_TBL allocates st_table if not available. */ #define RHASH(obj) ((struct RHash*)(mrb_ptr(obj))) #define RHASH_TBL(h) (RHASH(h)->ht) -- cgit v1.2.3 From ccc5edc60dd8f60d4e829586ac5541cb6f4e9461 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Mon, 17 Dec 2018 16:00:22 +0900 Subject: Small refactoring of #4188 --- src/hash.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/hash.c b/src/hash.c index 2f60eb74a..6b92344c3 100644 --- a/src/hash.c +++ b/src/hash.c @@ -1159,7 +1159,8 @@ mrb_hash_size(mrb_state *mrb, mrb_value hash) static mrb_value mrb_hash_size_m(mrb_state *mrb, mrb_value self) { - return mrb_fixnum_value(mrb_hash_size(mrb, self)); + mrb_int size = mrb_hash_size(mrb, self); + return mrb_fixnum_value(size); } MRB_API mrb_bool -- cgit v1.2.3 From 14133f405772b3c1955cbb82c3883546f82683d5 Mon Sep 17 00:00:00 2001 From: dearblue Date: Tue, 18 Dec 2018 23:05:36 +0900 Subject: Fix macro arguments with paren --- include/mruby.h | 4 ++-- include/mruby/boxing_nan.h | 2 +- include/mruby/boxing_word.h | 6 +++--- include/mruby/class.h | 12 ++++++------ include/mruby/data.h | 6 +++--- include/mruby/object.h | 2 +- include/mruby/proc.h | 8 ++++---- include/mruby/string.h | 6 +++--- 8 files changed, 23 insertions(+), 23 deletions(-) diff --git a/include/mruby.h b/include/mruby.h index 5ff7a1d7b..171f47126 100644 --- a/include/mruby.h +++ b/include/mruby.h @@ -995,8 +995,8 @@ MRB_API char* mrb_locale_from_utf8(const char *p, int len); #define mrb_locale_free(p) free(p) #define mrb_utf8_free(p) free(p) #else -#define mrb_utf8_from_locale(p, l) ((char*)p) -#define mrb_locale_from_utf8(p, l) ((char*)p) +#define mrb_utf8_from_locale(p, l) ((char*)(p)) +#define mrb_locale_from_utf8(p, l) ((char*)(p)) #define mrb_locale_free(p) #define mrb_utf8_free(p) #endif diff --git a/include/mruby/boxing_nan.h b/include/mruby/boxing_nan.h index 3d9bbdc69..ff6f6082d 100644 --- a/include/mruby/boxing_nan.h +++ b/include/mruby/boxing_nan.h @@ -81,7 +81,7 @@ typedef struct mrb_value { } while (0) #define SET_FLOAT_VALUE(mrb,r,v) do { \ - if (v != v) { \ + if ((v) != (v)) { \ (r).value.ttt = 0x7ff80000; \ (r).value.i = 0; \ } \ diff --git a/include/mruby/boxing_word.h b/include/mruby/boxing_word.h index 2ff314144..8bd854ec3 100644 --- a/include/mruby/boxing_word.h +++ b/include/mruby/boxing_word.h @@ -129,13 +129,13 @@ mrb_type(mrb_value o) } while (0) #ifndef MRB_WITHOUT_FLOAT -#define SET_FLOAT_VALUE(mrb,r,v) r = mrb_word_boxing_float_value(mrb, v) +#define SET_FLOAT_VALUE(mrb,r,v) (r) = mrb_word_boxing_float_value(mrb, v) #endif -#define SET_CPTR_VALUE(mrb,r,v) r = mrb_word_boxing_cptr_value(mrb, v) +#define SET_CPTR_VALUE(mrb,r,v) (r) = mrb_word_boxing_cptr_value(mrb, v) #define SET_NIL_VALUE(r) BOXWORD_SET_VALUE(r, MRB_TT_FALSE, value.i, 0) #define SET_FALSE_VALUE(r) BOXWORD_SET_VALUE(r, MRB_TT_FALSE, value.i, 1) #define SET_TRUE_VALUE(r) BOXWORD_SET_VALUE(r, MRB_TT_TRUE, value.i, 1) -#define SET_BOOL_VALUE(r,b) BOXWORD_SET_VALUE(r, b ? MRB_TT_TRUE : MRB_TT_FALSE, value.i, 1) +#define SET_BOOL_VALUE(r,b) BOXWORD_SET_VALUE(r, (b) ? MRB_TT_TRUE : MRB_TT_FALSE, value.i, 1) #define SET_INT_VALUE(r,n) BOXWORD_SET_VALUE(r, MRB_TT_FIXNUM, value.i, (n)) #define SET_SYM_VALUE(r,v) BOXWORD_SET_VALUE(r, MRB_TT_SYMBOL, value.sym, (v)) #define SET_OBJ_VALUE(r,v) BOXWORD_SET_VALUE(r, (((struct RObject*)(v))->tt), value.p, (v)) diff --git a/include/mruby/class.h b/include/mruby/class.h index 97b1df58a..e6bac1188 100644 --- a/include/mruby/class.h +++ b/include/mruby/class.h @@ -61,17 +61,17 @@ mrb_class(mrb_state *mrb, mrb_value v) #define MRB_FL_CLASS_IS_PREPENDED (1 << 19) #define MRB_FL_CLASS_IS_ORIGIN (1 << 18) #define MRB_CLASS_ORIGIN(c) do {\ - if (c->flags & MRB_FL_CLASS_IS_PREPENDED) {\ - c = c->super;\ - while (!(c->flags & MRB_FL_CLASS_IS_ORIGIN)) {\ - c = c->super;\ + if ((c)->flags & MRB_FL_CLASS_IS_PREPENDED) {\ + (c) = (c)->super;\ + while (!((c)->flags & MRB_FL_CLASS_IS_ORIGIN)) {\ + (c) = (c)->super;\ }\ }\ } while (0) #define MRB_FL_CLASS_IS_INHERITED (1 << 17) #define MRB_INSTANCE_TT_MASK (0xFF) -#define MRB_SET_INSTANCE_TT(c, tt) c->flags = ((c->flags & ~MRB_INSTANCE_TT_MASK) | (char)tt) -#define MRB_INSTANCE_TT(c) (enum mrb_vtype)(c->flags & MRB_INSTANCE_TT_MASK) +#define MRB_SET_INSTANCE_TT(c, tt) (c)->flags = (((c)->flags & ~MRB_INSTANCE_TT_MASK) | (char)(tt)) +#define MRB_INSTANCE_TT(c) (enum mrb_vtype)((c)->flags & MRB_INSTANCE_TT_MASK) MRB_API struct RClass* mrb_define_class_id(mrb_state*, mrb_sym, struct RClass*); MRB_API struct RClass* mrb_define_module_id(mrb_state*, mrb_sym); diff --git a/include/mruby/data.h b/include/mruby/data.h index 590470528..31d6bd8fb 100644 --- a/include/mruby/data.h +++ b/include/mruby/data.h @@ -40,9 +40,9 @@ MRB_API struct RData *mrb_data_object_alloc(mrb_state *mrb, struct RClass* klass mrb_data_object_alloc(mrb,klass,ptr,type) #define Data_Make_Struct(mrb,klass,strct,type,sval,data) do { \ - sval = mrb_malloc(mrb, sizeof(strct)); \ - { static const strct zero = { 0 }; *sval = zero; };\ - data = Data_Wrap_Struct(mrb,klass,type,sval);\ + (sval) = mrb_malloc(mrb, sizeof(strct)); \ + { static const strct zero = { 0 }; *(sval) = zero; };\ + (data) = Data_Wrap_Struct(mrb,klass,type,sval);\ } while (0) #define RDATA(obj) ((struct RData *)(mrb_ptr(obj))) diff --git a/include/mruby/object.h b/include/mruby/object.h index 25584a1d4..373e3bec7 100644 --- a/include/mruby/object.h +++ b/include/mruby/object.h @@ -14,7 +14,7 @@ struct RClass *c;\ struct RBasic *gcnext -#define MRB_FLAG_TEST(obj, flag) ((obj)->flags & flag) +#define MRB_FLAG_TEST(obj, flag) ((obj)->flags & (flag)) struct RBasic { diff --git a/include/mruby/proc.h b/include/mruby/proc.h index f428e6666..431a1d985 100644 --- a/include/mruby/proc.h +++ b/include/mruby/proc.h @@ -69,11 +69,11 @@ struct RProc { #define MRB_PROC_SET_TARGET_CLASS(p,tc) do {\ if (MRB_PROC_ENV_P(p)) {\ (p)->e.env->c = (tc);\ - mrb_field_write_barrier(mrb, (struct RBasic*)(p)->e.env, (struct RBasic*)tc);\ + mrb_field_write_barrier(mrb, (struct RBasic*)(p)->e.env, (struct RBasic*)(tc));\ }\ else {\ (p)->e.target_class = (tc);\ - mrb_field_write_barrier(mrb, (struct RBasic*)p, (struct RBasic*)tc);\ + mrb_field_write_barrier(mrb, (struct RBasic*)p, (struct RBasic*)(tc));\ }\ } while (0) #define MRB_PROC_SCOPE 2048 @@ -101,8 +101,8 @@ MRB_API mrb_value mrb_proc_cfunc_env_get(mrb_state*, mrb_int); #define MRB_METHOD_FUNC_FL ((uintptr_t)1) #define MRB_METHOD_FUNC_P(m) (((uintptr_t)(m))&MRB_METHOD_FUNC_FL) #define MRB_METHOD_FUNC(m) ((mrb_func_t)((uintptr_t)(m)&(~MRB_METHOD_FUNC_FL))) -#define MRB_METHOD_FROM_FUNC(m,fn) m=(mrb_method_t)((struct RProc*)((uintptr_t)(fn)|MRB_METHOD_FUNC_FL)) -#define MRB_METHOD_FROM_PROC(m,pr) m=(mrb_method_t)(struct RProc*)(pr) +#define MRB_METHOD_FROM_FUNC(m,fn) (m)=(mrb_method_t)((struct RProc*)((uintptr_t)(fn)|MRB_METHOD_FUNC_FL)) +#define MRB_METHOD_FROM_PROC(m,pr) (m)=(mrb_method_t)(struct RProc*)(pr) #define MRB_METHOD_PROC_P(m) (!MRB_METHOD_FUNC_P(m)) #define MRB_METHOD_PROC(m) ((struct RProc*)(m)) #define MRB_METHOD_UNDEF_P(m) ((m)==0) diff --git a/include/mruby/string.h b/include/mruby/string.h index 1a20cb1de..3fe8295ff 100644 --- a/include/mruby/string.h +++ b/include/mruby/string.h @@ -39,15 +39,15 @@ struct RString { #define RSTR_UNSET_EMBED_FLAG(s) ((s)->flags &= ~(MRB_STR_EMBED|MRB_STR_EMBED_LEN_MASK)) #define RSTR_SET_EMBED_LEN(s, n) do {\ size_t tmp_n = (n);\ - s->flags &= ~MRB_STR_EMBED_LEN_MASK;\ - s->flags |= (tmp_n) << MRB_STR_EMBED_LEN_SHIFT;\ + (s)->flags &= ~MRB_STR_EMBED_LEN_MASK;\ + (s)->flags |= (tmp_n) << MRB_STR_EMBED_LEN_SHIFT;\ } while (0) #define RSTR_SET_LEN(s, n) do {\ if (RSTR_EMBED_P(s)) {\ RSTR_SET_EMBED_LEN((s),(n));\ }\ else {\ - s->as.heap.len = (mrb_int)(n);\ + (s)->as.heap.len = (mrb_int)(n);\ }\ } while (0) #define RSTR_EMBED_LEN(s)\ -- cgit v1.2.3 From e19353be25e338d414ecce3c5336a639b0baa669 Mon Sep 17 00:00:00 2001 From: dearblue Date: Tue, 18 Dec 2018 23:14:26 +0900 Subject: Fix macro expressions with paren --- include/mruby/boxing_word.h | 4 ++-- include/mruby/class.h | 2 +- include/mruby/proc.h | 10 +++++----- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/include/mruby/boxing_word.h b/include/mruby/boxing_word.h index 8bd854ec3..3b7167b28 100644 --- a/include/mruby/boxing_word.h +++ b/include/mruby/boxing_word.h @@ -129,9 +129,9 @@ mrb_type(mrb_value o) } while (0) #ifndef MRB_WITHOUT_FLOAT -#define SET_FLOAT_VALUE(mrb,r,v) (r) = mrb_word_boxing_float_value(mrb, v) +#define SET_FLOAT_VALUE(mrb,r,v) ((r) = mrb_word_boxing_float_value(mrb, v)) #endif -#define SET_CPTR_VALUE(mrb,r,v) (r) = mrb_word_boxing_cptr_value(mrb, v) +#define SET_CPTR_VALUE(mrb,r,v) ((r) = mrb_word_boxing_cptr_value(mrb, v)) #define SET_NIL_VALUE(r) BOXWORD_SET_VALUE(r, MRB_TT_FALSE, value.i, 0) #define SET_FALSE_VALUE(r) BOXWORD_SET_VALUE(r, MRB_TT_FALSE, value.i, 1) #define SET_TRUE_VALUE(r) BOXWORD_SET_VALUE(r, MRB_TT_TRUE, value.i, 1) diff --git a/include/mruby/class.h b/include/mruby/class.h index e6bac1188..b667e2051 100644 --- a/include/mruby/class.h +++ b/include/mruby/class.h @@ -70,7 +70,7 @@ mrb_class(mrb_state *mrb, mrb_value v) } while (0) #define MRB_FL_CLASS_IS_INHERITED (1 << 17) #define MRB_INSTANCE_TT_MASK (0xFF) -#define MRB_SET_INSTANCE_TT(c, tt) (c)->flags = (((c)->flags & ~MRB_INSTANCE_TT_MASK) | (char)(tt)) +#define MRB_SET_INSTANCE_TT(c, tt) ((c)->flags = (((c)->flags & ~MRB_INSTANCE_TT_MASK) | (char)(tt))) #define MRB_INSTANCE_TT(c) (enum mrb_vtype)((c)->flags & MRB_INSTANCE_TT_MASK) MRB_API struct RClass* mrb_define_class_id(mrb_state*, mrb_sym, struct RClass*); diff --git a/include/mruby/proc.h b/include/mruby/proc.h index 431a1d985..021f9c117 100644 --- a/include/mruby/proc.h +++ b/include/mruby/proc.h @@ -23,13 +23,13 @@ struct REnv { }; /* flags (21bits): 1(shared flag):10(cioff/bidx):10(stack_len) */ -#define MRB_ENV_SET_STACK_LEN(e,len) (e)->flags = (((e)->flags & ~0x3ff)|((unsigned int)(len) & 0x3ff)) +#define MRB_ENV_SET_STACK_LEN(e,len) ((e)->flags = (((e)->flags & ~0x3ff)|((unsigned int)(len) & 0x3ff))) #define MRB_ENV_STACK_LEN(e) ((mrb_int)((e)->flags & 0x3ff)) #define MRB_ENV_STACK_UNSHARED (1<<20) -#define MRB_ENV_UNSHARE_STACK(e) (e)->flags |= MRB_ENV_STACK_UNSHARED +#define MRB_ENV_UNSHARE_STACK(e) ((e)->flags |= MRB_ENV_STACK_UNSHARED) #define MRB_ENV_STACK_SHARED_P(e) (((e)->flags & MRB_ENV_STACK_UNSHARED) == 0) #define MRB_ENV_BIDX(e) (((e)->flags >> 10) & 0x3ff) -#define MRB_ENV_SET_BIDX(e,idx) (e)->flags = (((e)->flags & ~(0x3ff<<10))|((unsigned int)(idx) & 0x3ff)<<10) +#define MRB_ENV_SET_BIDX(e,idx) ((e)->flags = (((e)->flags & ~(0x3ff<<10))|((unsigned int)(idx) & 0x3ff)<<10)) void mrb_env_unshare(mrb_state*, struct REnv*); @@ -101,8 +101,8 @@ MRB_API mrb_value mrb_proc_cfunc_env_get(mrb_state*, mrb_int); #define MRB_METHOD_FUNC_FL ((uintptr_t)1) #define MRB_METHOD_FUNC_P(m) (((uintptr_t)(m))&MRB_METHOD_FUNC_FL) #define MRB_METHOD_FUNC(m) ((mrb_func_t)((uintptr_t)(m)&(~MRB_METHOD_FUNC_FL))) -#define MRB_METHOD_FROM_FUNC(m,fn) (m)=(mrb_method_t)((struct RProc*)((uintptr_t)(fn)|MRB_METHOD_FUNC_FL)) -#define MRB_METHOD_FROM_PROC(m,pr) (m)=(mrb_method_t)(struct RProc*)(pr) +#define MRB_METHOD_FROM_FUNC(m,fn) ((m)=(mrb_method_t)((struct RProc*)((uintptr_t)(fn)|MRB_METHOD_FUNC_FL))) +#define MRB_METHOD_FROM_PROC(m,pr) ((m)=(mrb_method_t)(struct RProc*)(pr)) #define MRB_METHOD_PROC_P(m) (!MRB_METHOD_FUNC_P(m)) #define MRB_METHOD_PROC(m) ((struct RProc*)(m)) #define MRB_METHOD_UNDEF_P(m) ((m)==0) -- cgit v1.2.3 From 624b126fb6b06253abff0eea7899ec876b2358e6 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Wed, 19 Dec 2018 13:12:30 +0900 Subject: Added Android Hack to `time.c`. Android bionic defines `TIME_UTC` but does not provide `timespec_get`. --- mrbgems/mruby-time/src/time.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mrbgems/mruby-time/src/time.c b/mrbgems/mruby-time/src/time.c index cfd51ac63..4217b897f 100644 --- a/mrbgems/mruby-time/src/time.c +++ b/mrbgems/mruby-time/src/time.c @@ -296,7 +296,7 @@ current_mrb_time(mrb_state *mrb) struct mrb_time *tm; tm = (struct mrb_time *)mrb_malloc(mrb, sizeof(*tm)); -#if defined(TIME_UTC) +#if defined(TIME_UTC) && !defined(__ANDROID__) { struct timespec ts; if (timespec_get(&ts, TIME_UTC) == 0) { -- cgit v1.2.3 From 7e35c659aa2516e4e59c765dea5bb0d1042453f7 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Fri, 21 Dec 2018 00:47:56 +0900 Subject: Remove things we've done in `TODO` file. --- TODO | 2 -- 1 file changed, 2 deletions(-) diff --git a/TODO b/TODO index 3e195f99b..6227b60de 100644 --- a/TODO +++ b/TODO @@ -2,8 +2,6 @@ Things to do (Things that are not done yet) * special variables ($1,$2..) * super in aliased methods -* multi-assignment decomposing -* keyword arguments in def statement Things to improve (Done but things to fix) -- cgit v1.2.3 From 2fdb309e55b6f4ee5a0438aa25b5aac27da13fd4 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Fri, 21 Dec 2018 02:21:06 +0900 Subject: `mruby-pack` should not rely on `MRB_ENDIAN_BIG` macro; fix #4190 The `MRB_ENDIAN_BIG` macro is originally used for `NaN` boxing. We cannot assume it is defined on every big endian platform (#4190 is the case). So instead of relying on untrusted `MRB_ENDIAN_BIG`, we use `BYTE_ORDER` macro with a fallback function to check endian in runtime. --- mrbgems/mruby-pack/src/pack.c | 125 ++++++++++++++++++++++++------------------ 1 file changed, 71 insertions(+), 54 deletions(-) diff --git a/mrbgems/mruby-pack/src/pack.c b/mrbgems/mruby-pack/src/pack.c index 5caf7b62b..ed9f4d77f 100644 --- a/mrbgems/mruby-pack/src/pack.c +++ b/mrbgems/mruby-pack/src/pack.c @@ -60,19 +60,28 @@ enum { #define PACK_BASE64_IGNORE 0xff #define PACK_BASE64_PADDING 0xfe -static int littleendian = 0; - const static unsigned char base64chars[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; static unsigned char base64_dec_tab[128]; - -static int +#ifdef BYTE_ORDER +# if BYTE_ORDER == BIG_ENDIAN +# define littleendian 0 +# define check_little_endian() (void)0 +# elif BYTE_ORDER == LITTLE_ENDIAN +# define littleendian 1 +# define check_little_endian() (void)0 +# else +/* can't distinguish endian in compile time */ +static int littleendian = 0; +static void check_little_endian(void) { unsigned int n = 1; - return (*(unsigned char *)&n == 1); + littleendian = (*(unsigned char *)&n == 1); } +# endif +#endif static unsigned int hex2int(unsigned char ch) @@ -313,21 +322,23 @@ pack_double(mrb_state *mrb, mrb_value o, mrb_value str, mrb_int sidx, unsigned i d = mrb_float(o); if (flags & PACK_FLAG_LITTLEENDIAN) { -#ifdef MRB_ENDIAN_BIG - for (i = 0; i < 8; ++i) { - RSTRING_PTR(str)[sidx + i] = buffer[8 - i - 1]; + if (littleendian) { + memcpy(RSTRING_PTR(str) + sidx, buffer, 8); + } + else { + for (i = 0; i < 8; ++i) { + RSTRING_PTR(str)[sidx + i] = buffer[8 - i - 1]; + } } -#else - memcpy(RSTRING_PTR(str) + sidx, buffer, 8); -#endif } else { -#ifdef MRB_ENDIAN_BIG - memcpy(RSTRING_PTR(str) + sidx, buffer, 8); -#else - for (i = 0; i < 8; ++i) { - RSTRING_PTR(str)[sidx + i] = buffer[8 - i - 1]; + if (littleendian) { + for (i = 0; i < 8; ++i) { + RSTRING_PTR(str)[sidx + i] = buffer[8 - i - 1]; + } + } + else { + memcpy(RSTRING_PTR(str) + sidx, buffer, 8); } -#endif } return 8; @@ -341,21 +352,23 @@ unpack_double(mrb_state *mrb, const unsigned char * src, int srclen, mrb_value a uint8_t *buffer = (uint8_t *)&d; if (flags & PACK_FLAG_LITTLEENDIAN) { -#ifdef MRB_ENDIAN_BIG - for (i = 0; i < 8; ++i) { - buffer[8 - i - 1] = src[i]; + if (littleendian) { + memcpy(buffer, src, 8); + } + else { + for (i = 0; i < 8; ++i) { + buffer[8 - i - 1] = src[i]; + } } -#else - memcpy(buffer, src, 8); -#endif } else { -#ifdef MRB_ENDIAN_BIG - memcpy(buffer, src, 8); -#else - for (i = 0; i < 8; ++i) { - buffer[8 - i - 1] = src[i]; + if (littleendian) { + for (i = 0; i < 8; ++i) { + buffer[8 - i - 1] = src[i]; + } + } + else { + memcpy(buffer, src, 8); } -#endif } mrb_ary_push(mrb, ary, mrb_float_value(mrb, d)); @@ -372,21 +385,23 @@ pack_float(mrb_state *mrb, mrb_value o, mrb_value str, mrb_int sidx, unsigned in f = (float)mrb_float(o); if (flags & PACK_FLAG_LITTLEENDIAN) { -#ifdef MRB_ENDIAN_BIG - for (i = 0; i < 4; ++i) { - RSTRING_PTR(str)[sidx + i] = buffer[4 - i - 1]; + if (littleendian) { + memcpy(RSTRING_PTR(str) + sidx, buffer, 4); + } + else { + for (i = 0; i < 4; ++i) { + RSTRING_PTR(str)[sidx + i] = buffer[4 - i - 1]; + } } -#else - memcpy(RSTRING_PTR(str) + sidx, buffer, 4); -#endif } else { -#ifdef MRB_ENDIAN_BIG - memcpy(RSTRING_PTR(str) + sidx, buffer, 4); -#else - for (i = 0; i < 4; ++i) { - RSTRING_PTR(str)[sidx + i] = buffer[4 - i - 1]; + if (littleendian) { + for (i = 0; i < 4; ++i) { + RSTRING_PTR(str)[sidx + i] = buffer[4 - i - 1]; + } + } + else { + memcpy(RSTRING_PTR(str) + sidx, buffer, 4); } -#endif } return 4; @@ -400,21 +415,23 @@ unpack_float(mrb_state *mrb, const unsigned char * src, int srclen, mrb_value ar uint8_t *buffer = (uint8_t *)&f; if (flags & PACK_FLAG_LITTLEENDIAN) { -#ifdef MRB_ENDIAN_BIG - for (i = 0; i < 4; ++i) { - buffer[4 - i - 1] = src[i]; + if (littleendian) { + memcpy(buffer, src, 4); + } + else { + for (i = 0; i < 4; ++i) { + buffer[4 - i - 1] = src[i]; + } } -#else - memcpy(buffer, src, 4); -#endif } else { -#ifdef MRB_ENDIAN_BIG - memcpy(buffer, src, 4); -#else - for (i = 0; i < 4; ++i) { - buffer[4 - i - 1] = src[i]; + if (littleendian) { + for (i = 0; i < 4; ++i) { + buffer[4 - i - 1] = src[i]; + } + } + else { + memcpy(buffer, src, 4); } -#endif } mrb_ary_push(mrb, ary, mrb_float_value(mrb, f)); @@ -1297,7 +1314,7 @@ mrb_pack_unpack1(mrb_state *mrb, mrb_value str) void mrb_mruby_pack_gem_init(mrb_state *mrb) { - littleendian = check_little_endian(); + check_little_endian(); make_base64_dec_tab(); mrb_define_method(mrb, mrb->array_class, "pack", mrb_pack_pack, MRB_ARGS_REQ(1)); -- cgit v1.2.3 From f5537912abed308ad6967ae52bfa8699f14dae93 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Fri, 21 Dec 2018 08:49:23 +0900 Subject: Define `MRB_ENDIAN_BIG` automatically; ref #4190 You had to define this macro on big endian platforms, but it is very error-prone. So define the macro automatically if possible. --- include/mrbconf.h | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/include/mrbconf.h b/include/mrbconf.h index cc28acfaa..553ed62cc 100644 --- a/include/mrbconf.h +++ b/include/mrbconf.h @@ -58,12 +58,16 @@ # endif #endif +/* define on big endian machines; used by MRB_NAN_BOXING, etc. */ +#ifndef MRB_ENDIAN_BIG +# if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && BYTE_ORDER == BIG_ENDIAN +# define MRB_ENDIAN_BIG +# endif +#endif + /* represent mrb_value in boxed double; conflict with MRB_USE_FLOAT and MRB_WITHOUT_FLOAT */ //#define MRB_NAN_BOXING -/* define on big endian machines; used by MRB_NAN_BOXING */ -//#define MRB_ENDIAN_BIG - /* represent mrb_value as a word (natural unit of data for the processor) */ //#define MRB_WORD_BOXING -- cgit v1.2.3 From 445c64d0ad95ec9e4918e2f2ffedcd1df1ce96bf Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Fri, 21 Dec 2018 09:26:48 +0900 Subject: Fixed a bug on platforms without `BYTE_ORDER`; ref #4190 --- mrbgems/mruby-pack/src/pack.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/mrbgems/mruby-pack/src/pack.c b/mrbgems/mruby-pack/src/pack.c index ed9f4d77f..1b1f86a88 100644 --- a/mrbgems/mruby-pack/src/pack.c +++ b/mrbgems/mruby-pack/src/pack.c @@ -71,7 +71,9 @@ static unsigned char base64_dec_tab[128]; # elif BYTE_ORDER == LITTLE_ENDIAN # define littleendian 1 # define check_little_endian() (void)0 -# else +# endif +#endif +#ifndef littleendian /* can't distinguish endian in compile time */ static int littleendian = 0; static void @@ -80,7 +82,6 @@ check_little_endian(void) unsigned int n = 1; littleendian = (*(unsigned char *)&n == 1); } -# endif #endif static unsigned int -- cgit v1.2.3 From ed2bc5d4ed363f8d8d1f4bee69555972cfbed262 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Fri, 21 Dec 2018 09:28:19 +0900 Subject: Simplify `MRB_ENDIAN_BIG` macro definition; ref #4190 `cpp` does not raise error on undefined macro access in condition. --- include/mrbconf.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/mrbconf.h b/include/mrbconf.h index 553ed62cc..9bdd11af6 100644 --- a/include/mrbconf.h +++ b/include/mrbconf.h @@ -60,7 +60,7 @@ /* define on big endian machines; used by MRB_NAN_BOXING, etc. */ #ifndef MRB_ENDIAN_BIG -# if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && BYTE_ORDER == BIG_ENDIAN +# if BYTE_ORDER == BIG_ENDIAN # define MRB_ENDIAN_BIG # endif #endif -- cgit v1.2.3 From 94b73b14402af26a844a98d22a87cce7d8f58ea0 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Fri, 21 Dec 2018 09:35:10 +0900 Subject: Add `NULL` pointer check before `void_expr_error()`; fix #4192 --- mrbgems/mruby-compiler/core/parse.y | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/mrbgems/mruby-compiler/core/parse.y b/mrbgems/mruby-compiler/core/parse.y index d143344c3..0e67e5881 100644 --- a/mrbgems/mruby-compiler/core/parse.y +++ b/mrbgems/mruby-compiler/core/parse.y @@ -3664,8 +3664,10 @@ void_expr_error(parser_state *p, node *n) break; case NODE_AND: case NODE_OR: - void_expr_error(p, n->cdr->car); - void_expr_error(p, n->cdr->cdr); + if (n->cdr) { + void_expr_error(p, n->cdr->car); + void_expr_error(p, n->cdr->cdr); + } break; case NODE_BEGIN: if (n->cdr) { -- cgit v1.2.3 From cc71bd51f1d914fd3ef1ba4b6555ca1b7c3087f4 Mon Sep 17 00:00:00 2001 From: Tatsuhiko Kubo Date: Sun, 13 Jul 2014 01:21:19 +0900 Subject: optimize Proc#parameters --- mrbgems/mruby-proc-ext/src/proc.c | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/mrbgems/mruby-proc-ext/src/proc.c b/mrbgems/mruby-proc-ext/src/proc.c index 9ce6c1831..4b85c245d 100644 --- a/mrbgems/mruby-proc-ext/src/proc.c +++ b/mrbgems/mruby-proc-ext/src/proc.c @@ -94,20 +94,21 @@ static mrb_value mrb_proc_parameters(mrb_state *mrb, mrb_value self) { struct parameters_type { - int size; + size_t len; const char *name; + int size; } *p, parameters_list [] = { - {0, "req"}, - {0, "opt"}, - {0, "rest"}, - {0, "req"}, - {0, "block"}, - {0, NULL} + {sizeof("req") - 1, "req", 0}, + {sizeof("opt") - 1, "opt", 0}, + {sizeof("rest") - 1, "rest", 0}, + {sizeof("req") - 1, "req", 0}, + {sizeof("block") - 1, "block", 0}, + {0, NULL, 0} }; const struct RProc *proc = mrb_proc_ptr(self); const struct mrb_irep *irep = proc->body.irep; mrb_aspec aspec; - mrb_value sname, parameters; + mrb_value parameters; int i, j; int max = -1; @@ -126,7 +127,9 @@ mrb_proc_parameters(mrb_state *mrb, mrb_value self) } if (!MRB_PROC_STRICT_P(proc)) { + parameters_list[0].len = sizeof("opt") - 1; parameters_list[0].name = "opt"; + parameters_list[3].len = sizeof("opt") - 1; parameters_list[3].name = "opt"; } @@ -141,8 +144,8 @@ mrb_proc_parameters(mrb_state *mrb, mrb_value self) max = irep->nlocals-1; for (i = 0, p = parameters_list; p->name; p++) { - if (p->size <= 0) continue; - sname = mrb_symbol_value(mrb_intern_cstr(mrb, p->name)); + mrb_value sname = mrb_symbol_value(mrb_intern_static(mrb, p->name, p->len)); + for (j = 0; j < p->size; i++, j++) { mrb_value a; -- cgit v1.2.3 From d2fb4752e25c2772f5410e4887d9bddc9168ccdf Mon Sep 17 00:00:00 2001 From: Tatsuhiko Kubo Date: Sun, 13 Jul 2014 01:27:28 +0900 Subject: Add test for Proc#parameters --- mrbgems/mruby-proc-ext/test/proc.rb | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/mrbgems/mruby-proc-ext/test/proc.rb b/mrbgems/mruby-proc-ext/test/proc.rb index 037d8d124..3e64bc103 100644 --- a/mrbgems/mruby-proc-ext/test/proc.rb +++ b/mrbgems/mruby-proc-ext/test/proc.rb @@ -13,6 +13,11 @@ assert('Proc#inspect') do assert_kind_of String, ins end +assert('Proc#parameters') do + parameters = Proc.new{|x,y=42,*other|}.parameters + assert_equal [[:opt, :x], [:opt, :y], [:rest, :other]], parameters +end + assert('Proc#lambda?') do assert_true lambda{}.lambda? assert_true !Proc.new{}.lambda? -- cgit v1.2.3 From 9377da977596327c6c6c271b826e60c3070405f7 Mon Sep 17 00:00:00 2001 From: dearblue Date: Fri, 21 Dec 2018 23:44:38 +0900 Subject: Fix undefined variable is using --- test/assert.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/assert.rb b/test/assert.rb index a9baae5e1..89d3a7969 100644 --- a/test/assert.rb +++ b/test/assert.rb @@ -175,7 +175,7 @@ def assert_nothing_raised(msg = nil) yield true rescue Exception => e - msg ||= "Expected not to raise #{exc.join(', ')} but it raised" + msg ||= "Expected not to raise #{e} but it raised" diff = " Class: <#{e.class}>\n" + " Message: #{e.message}" $mrbtest_assert.push [$mrbtest_assert_idx, msg, diff] -- cgit v1.2.3 From 6578fec77944898118ceae6d45d891fbeabf1770 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Sat, 22 Dec 2018 17:11:27 +0900 Subject: mirb: drop dependency on mruby-print in a test --- mrbgems/mruby-bin-mirb/bintest/mirb.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mrbgems/mruby-bin-mirb/bintest/mirb.rb b/mrbgems/mruby-bin-mirb/bintest/mirb.rb index 0515cb136..0058896f1 100644 --- a/mrbgems/mruby-bin-mirb/bintest/mirb.rb +++ b/mrbgems/mruby-bin-mirb/bintest/mirb.rb @@ -12,9 +12,9 @@ assert('regression for #1563') do end assert('mirb -d option') do - o, _ = Open3.capture2('bin/mirb', :stdin_data => "p $DEBUG\n") + o, _ = Open3.capture2('bin/mirb', :stdin_data => "$DEBUG\n") assert_true o.include?('=> false') - o, _ = Open3.capture2('bin/mirb -d', :stdin_data => "p $DEBUG\n") + o, _ = Open3.capture2('bin/mirb -d', :stdin_data => "$DEBUG\n") assert_true o.include?('=> true') end -- cgit v1.2.3 From e9ceb865b6621739c217f68bebea023069ef63ca Mon Sep 17 00:00:00 2001 From: dearblue Date: Sat, 22 Dec 2018 20:37:51 +0900 Subject: Fix MRB_ENDIAN_BIG is always defined, if byte order macro is not defined --- include/mrbconf.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/include/mrbconf.h b/include/mrbconf.h index 9bdd11af6..b1aec8334 100644 --- a/include/mrbconf.h +++ b/include/mrbconf.h @@ -60,7 +60,8 @@ /* define on big endian machines; used by MRB_NAN_BOXING, etc. */ #ifndef MRB_ENDIAN_BIG -# if BYTE_ORDER == BIG_ENDIAN +# if (defined(BYTE_ORDER) && defined(BIG_ENDIAN) && BYTE_ORDER == BIG_ENDIAN) || \ + (defined(__BYTE_ORDER__) && defined(__ORDER_BIG_ENDIAN__) && __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__) # define MRB_ENDIAN_BIG # endif #endif -- cgit v1.2.3 From b7a832bf4f20f9e0a82607fa3e313a333f9aecd8 Mon Sep 17 00:00:00 2001 From: dearblue Date: Sat, 22 Dec 2018 21:05:27 +0900 Subject: Define byte order macros, if not defined it and there are alternatives --- mrbgems/mruby-pack/src/pack.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/mrbgems/mruby-pack/src/pack.c b/mrbgems/mruby-pack/src/pack.c index 1b1f86a88..f274ff11e 100644 --- a/mrbgems/mruby-pack/src/pack.c +++ b/mrbgems/mruby-pack/src/pack.c @@ -64,6 +64,16 @@ const static unsigned char base64chars[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; static unsigned char base64_dec_tab[128]; +#if !defined(BYTE_ORDER) && defined(__BYTE_ORDER__) +# define BYTE_ORDER __BYTE_ORDER__ +#endif +#if !defined(BIG_ENDIAN) && defined(__ORDER_BIG_ENDIAN__) +# define BIG_ENDIAN __ORDER_BIG_ENDIAN__ +#endif +#if !defined(LITTLE_ENDIAN) && defined(__ORDER_LITTLE_ENDIAN__) +# define LITTLE_ENDIAN __ORDER_LITTLE_ENDIAN__ +#endif + #ifdef BYTE_ORDER # if BYTE_ORDER == BIG_ENDIAN # define littleendian 0 -- cgit v1.2.3 From 129a804136cea007a223c3860ba9e30c76a0a814 Mon Sep 17 00:00:00 2001 From: dearblue Date: Sat, 22 Dec 2018 21:58:58 +0900 Subject: Append cflags for undefined macro --- tasks/toolchains/gcc.rake | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tasks/toolchains/gcc.rake b/tasks/toolchains/gcc.rake index e0eb36f26..4929811c4 100644 --- a/tasks/toolchains/gcc.rake +++ b/tasks/toolchains/gcc.rake @@ -1,7 +1,7 @@ MRuby::Toolchain.new(:gcc) do |conf, _params| [conf.cc, conf.objc, conf.asm].each do |cc| cc.command = ENV['CC'] || 'gcc' - cc.flags = [ENV['CFLAGS'] || %w(-g -std=gnu99 -O3 -Wall -Werror-implicit-function-declaration -Wdeclaration-after-statement -Wwrite-strings)] + cc.flags = [ENV['CFLAGS'] || %w(-g -std=gnu99 -O3 -Wall -Werror-implicit-function-declaration -Wdeclaration-after-statement -Wwrite-strings -Wundef)] cc.defines = %w(DISABLE_GEMS) cc.option_include_path = '-I%s' cc.option_define = '-D%s' @@ -12,7 +12,7 @@ MRuby::Toolchain.new(:gcc) do |conf, _params| [conf.cxx].each do |cxx| cxx.command = ENV['CXX'] || 'g++' - cxx.flags = [ENV['CXXFLAGS'] || ENV['CFLAGS'] || %w(-g -O3 -Wall -Werror-implicit-function-declaration)] + cxx.flags = [ENV['CXXFLAGS'] || ENV['CFLAGS'] || %w(-g -O3 -Wall -Werror-implicit-function-declaration -Wundef)] cxx.defines = %w(DISABLE_GEMS) cxx.option_include_path = '-I%s' cxx.option_define = '-D%s' -- cgit v1.2.3 From b0dc163b5dadbdc8ef2241f3aa56a1eae428a22a Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Sun, 23 Dec 2018 14:19:09 +0900 Subject: Suppress a struct initializer warning Suppress a compiler (clang) warning bellow: src/vm.c:104:38: warning: suggest braces around initialization of subobject [-Wmissing-braces] const mrb_value mrb_value_zero = { 0 }; ^ {} --- src/vm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vm.c b/src/vm.c index b5249b325..49c2bb85c 100644 --- a/src/vm.c +++ b/src/vm.c @@ -101,7 +101,7 @@ static inline void stack_clear(mrb_value *from, size_t count) { #ifndef MRB_NAN_BOXING - const mrb_value mrb_value_zero = { 0 }; + const mrb_value mrb_value_zero = { { 0 } }; while (count-- > 0) { *from++ = mrb_value_zero; -- cgit v1.2.3 From 49cce74c1ac6b2cedc909eaefa5cbd1d44c906da Mon Sep 17 00:00:00 2001 From: dearblue Date: Sun, 23 Dec 2018 17:22:59 +0900 Subject: Suppress __STDC_VERSION__ warns for C++ --- include/mruby.h | 2 +- include/mruby/common.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/include/mruby.h b/include/mruby.h index 171f47126..8c8360784 100644 --- a/include/mruby.h +++ b/include/mruby.h @@ -57,7 +57,7 @@ #define mrb_assert_int_fit(t1,n,t2,max) ((void)0) #endif -#if __STDC_VERSION__ >= 201112L +#if defined __STDC_VERSION__ && __STDC_VERSION__ >= 201112L #define mrb_static_assert(exp, str) _Static_assert(exp, str) #else #define mrb_static_assert(exp, str) mrb_assert(exp) diff --git a/include/mruby/common.h b/include/mruby/common.h index 4c7d9384a..4eaac9af7 100644 --- a/include/mruby/common.h +++ b/include/mruby/common.h @@ -34,7 +34,7 @@ MRB_BEGIN_DECL /** Declare a function that never returns. */ -#if __STDC_VERSION__ >= 201112L +#if defined __STDC_VERSION__ && __STDC_VERSION__ >= 201112L # define mrb_noreturn _Noreturn #elif defined __GNUC__ && !defined __STRICT_ANSI__ # define mrb_noreturn __attribute__((noreturn)) -- cgit v1.2.3 From be980e9a7a39ec06bea6446e79df21cb580fdcd7 Mon Sep 17 00:00:00 2001 From: dearblue Date: Sun, 23 Dec 2018 17:23:51 +0900 Subject: Suppress __FreeBSD_version warns for FreeBSD --- mrbgems/mruby-math/src/math.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/mrbgems/mruby-math/src/math.c b/mrbgems/mruby-math/src/math.c index c182debea..c29ba6808 100644 --- a/mrbgems/mruby-math/src/math.c +++ b/mrbgems/mruby-math/src/math.c @@ -161,6 +161,10 @@ erfc(double x) #endif +#if defined __FreeBSD__ && !defined __FreeBSD_version +#include /* for __FreeBSD_version */ +#endif + #if (defined _MSC_VER && _MSC_VER < 1800) || defined __ANDROID__ || (defined __FreeBSD__ && __FreeBSD_version < 803000) double -- cgit v1.2.3 From 027f4ded34d09221ea6146aa7ccb54d001418f8c Mon Sep 17 00:00:00 2001 From: dearblue Date: Sun, 23 Dec 2018 17:24:16 +0900 Subject: Suppress TARGET_OS_IPHONE warns --- mrbgems/mruby-io/src/io.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/mrbgems/mruby-io/src/io.c b/mrbgems/mruby-io/src/io.c index 1ac15aab3..e5b83e923 100644 --- a/mrbgems/mruby-io/src/io.c +++ b/mrbgems/mruby-io/src/io.c @@ -209,7 +209,7 @@ mrb_fd_cloexec(mrb_state *mrb, int fd) #endif } -#if !defined(_WIN32) && !TARGET_OS_IPHONE +#if !defined(_WIN32) && !(defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE) static int mrb_cloexec_pipe(mrb_state *mrb, int fildes[2]) { @@ -403,7 +403,7 @@ mrb_io_s_popen(mrb_state *mrb, mrb_value klass) DATA_PTR(io) = fptr; return io; } -#elif TARGET_OS_IPHONE +#elif defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE mrb_value mrb_io_s_popen(mrb_state *mrb, mrb_value klass) { @@ -1011,7 +1011,7 @@ mrb_io_read_data_pending(mrb_state *mrb, mrb_value io) return 0; } -#if !defined(_WIN32) && !TARGET_OS_IPHONE +#if !defined(_WIN32) && !(defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE) static mrb_value mrb_io_s_pipe(mrb_state *mrb, mrb_value klass) { @@ -1313,7 +1313,7 @@ mrb_init_io(mrb_state *mrb) mrb_define_class_method(mrb, io, "for_fd", mrb_io_s_for_fd, MRB_ARGS_ANY()); mrb_define_class_method(mrb, io, "select", mrb_io_s_select, MRB_ARGS_ANY()); mrb_define_class_method(mrb, io, "sysopen", mrb_io_s_sysopen, MRB_ARGS_ANY()); -#if !defined(_WIN32) && !TARGET_OS_IPHONE +#if !defined(_WIN32) && !(defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE) mrb_define_class_method(mrb, io, "_pipe", mrb_io_s_pipe, MRB_ARGS_NONE()); #endif -- cgit v1.2.3 From 0bfeefad2ab4094ce0ff2cf38a17c8a256e121d6 Mon Sep 17 00:00:00 2001 From: dearblue Date: Sun, 23 Dec 2018 17:36:06 +0900 Subject: Suppress _MSC_VER warns for mingw32 --- mrbgems/mruby-time/src/time.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mrbgems/mruby-time/src/time.c b/mrbgems/mruby-time/src/time.c index 4217b897f..2f79617ac 100644 --- a/mrbgems/mruby-time/src/time.c +++ b/mrbgems/mruby-time/src/time.c @@ -46,7 +46,7 @@ double round(double x) { /* #define NO_GMTIME_R */ #ifdef _WIN32 -#if _MSC_VER +#ifdef _MSC_VER /* Win32 platform do not provide gmtime_r/localtime_r; emulate them using gmtime_s/localtime_s */ #define gmtime_r(tp, tm) ((gmtime_s((tm), (tp)) == 0) ? (tm) : NULL) #define localtime_r(tp, tm) ((localtime_s((tm), (tp)) == 0) ? (tm) : NULL) -- cgit v1.2.3 From 96bea076ec85a86ba715d5574eaf310e05f1a587 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Mon, 24 Dec 2018 12:12:10 +0900 Subject: Refine description for rake test tasks. Before: $ rake -T test rake test_test # run all mruby tests After: $ rake -T test rake test # run all mruby tests --- Rakefile | 1 + 1 file changed, 1 insertion(+) diff --git a/Rakefile b/Rakefile index 20b6096f5..47da28166 100644 --- a/Rakefile +++ b/Rakefile @@ -118,6 +118,7 @@ task :all => depfiles do end desc "run all mruby tests" +task :test MRuby.each_target do next unless test_enabled? -- cgit v1.2.3 From 1f914825852fc95878c6909fffb65e64102f4ea3 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Tue, 25 Dec 2018 09:47:28 +0900 Subject: mruby-bin-mruby: Add test dependency. `Kernel#p` etc are used. --- mrbgems/mruby-bin-mruby/mrbgem.rake | 1 + 1 file changed, 1 insertion(+) diff --git a/mrbgems/mruby-bin-mruby/mrbgem.rake b/mrbgems/mruby-bin-mruby/mrbgem.rake index fbec13847..280621e31 100644 --- a/mrbgems/mruby-bin-mruby/mrbgem.rake +++ b/mrbgems/mruby-bin-mruby/mrbgem.rake @@ -5,6 +5,7 @@ MRuby::Gem::Specification.new('mruby-bin-mruby') do |spec| spec.bins = %w(mruby) spec.add_dependency('mruby-compiler', :core => 'mruby-compiler') spec.add_dependency('mruby-error', :core => 'mruby-error') + spec.add_test_dependency('mruby-print', :core => 'mruby-print') if build.cxx_exception_enabled? build.compile_as_cxx("#{spec.dir}/tools/mruby/mruby.c", "#{spec.build_dir}/tools/mruby/mruby.cxx") -- cgit v1.2.3 From 5b5e54d38e241a1cf49662f4395fb5bbc26696ea Mon Sep 17 00:00:00 2001 From: Takeshi Watanabe Date: Tue, 25 Dec 2018 14:37:32 +0900 Subject: Fix `$rake_root_fiber` checking. https://github.com/mruby/mruby/pull/4101#pullrequestreview-187752352 --- minirake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/minirake b/minirake index 86c42c999..cd2d85854 100755 --- a/minirake +++ b/minirake @@ -483,7 +483,7 @@ class RakeApp def run handle_options - if $rake_root_fiber + unless $rake_root_fiber require 'fiber' $rake_root_fiber = Fiber.current end -- cgit v1.2.3 From e20d652f22dd4cda7286eedbf46d67b901d4969d Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Tue, 25 Dec 2018 15:23:05 +0900 Subject: Simplify full-core.gembox Dependencies order is auto detected. --- mrbgems/full-core.gembox | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/mrbgems/full-core.gembox b/mrbgems/full-core.gembox index 9a5b7081b..e0d008f06 100644 --- a/mrbgems/full-core.gembox +++ b/mrbgems/full-core.gembox @@ -1,9 +1,6 @@ MRuby::GemBox.new do |conf| - conf.gem :core => "mruby-sprintf" - conf.gem :core => "mruby-print" - Dir.glob("#{root}/mrbgems/mruby-*/mrbgem.rake") do |x| g = File.basename File.dirname x - conf.gem :core => g unless g =~ /^mruby-(print|sprintf|bin-debugger|test)$/ + conf.gem :core => g unless g =~ /^mruby-(?:bin-debugger|test)$/ end end -- cgit v1.2.3 From 37d795dec7b495d418dc2f9020cf980c158ba9ed Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Tue, 25 Dec 2018 23:17:10 +0900 Subject: Revert "Simplify full-core.gembox" This reverts commit e20d652f22dd4cda7286eedbf46d67b901d4969d. This change cannot handle hidden dependency between `mruby-print` and `mruby-sprintf`; ref #4202 --- mrbgems/full-core.gembox | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/mrbgems/full-core.gembox b/mrbgems/full-core.gembox index e0d008f06..9a5b7081b 100644 --- a/mrbgems/full-core.gembox +++ b/mrbgems/full-core.gembox @@ -1,6 +1,9 @@ MRuby::GemBox.new do |conf| + conf.gem :core => "mruby-sprintf" + conf.gem :core => "mruby-print" + Dir.glob("#{root}/mrbgems/mruby-*/mrbgem.rake") do |x| g = File.basename File.dirname x - conf.gem :core => g unless g =~ /^mruby-(?:bin-debugger|test)$/ + conf.gem :core => g unless g =~ /^mruby-(print|sprintf|bin-debugger|test)$/ end end -- cgit v1.2.3 From ce5e45443eec8f51b781fda5db47c99c8425335f Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Sat, 29 Dec 2018 09:40:44 +0900 Subject: Fix Yacc running multiple times. Example: $ MRUBY_CONFIG=<(echo 'MRuby::Build.new{toolchain(:gcc);gem(core:"mruby-bin-mruby");enable_test}') ./minirake Before: ... CC build/host/mrbgems/gem_init.c -> build/host/mrbgems/gem_init.o YACC mrbgems/mruby-compiler/core/parse.y -> build/host/mrbgems/mruby-compiler/core/y.tab.c YACC mrbgems/mruby-compiler/core/parse.y -> build/host/mrbgems/mruby-compiler/core/y.tab.c YACC mrbgems/mruby-compiler/core/parse.y -> build/host/mrbgems/mruby-compiler/core/y.tab.c YACC mrbgems/mruby-compiler/core/parse.y -> build/host/mrbgems/mruby-compiler/core/y.tab.c CC build/host/mrbgems/mruby-compiler/core/y.tab.c -> build/host/mrbgems/mruby-compiler/core/y.tab.o CC build/host/mrbgems/mruby-compiler/core/y.tab.c -> build/host/mrbgems/mruby-compiler/core/y.tab.o CC build/host/mrbgems/mruby-compiler/core/y.tab.c -> build/host/mrbgems/mruby-compiler/core/y.tab.o CC build/host/mrbgems/mruby-compiler/core/y.tab.c -> build/host/mrbgems/mruby-compiler/core/y.tab.o AR build/host/lib/libmruby_core.a ... After: ... CC build/host/mrbgems/gem_init.c -> build/host/mrbgems/gem_init.o YACC mrbgems/mruby-compiler/core/parse.y -> build/host/mrbgems/mruby-compiler/core/y.tab.c CC build/host/mrbgems/mruby-compiler/core/y.tab.c -> build/host/mrbgems/mruby-compiler/core/y.tab.o AR build/host/lib/libmruby_core.a ... --- lib/mruby/gem.rb | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/lib/mruby/gem.rb b/lib/mruby/gem.rb index a1216aced..9f27f3ffc 100644 --- a/lib/mruby/gem.rb +++ b/lib/mruby/gem.rb @@ -52,6 +52,8 @@ module MRuby end def setup + return if defined?(@linker) # return if already set up + MRuby::Gem.current = self MRuby::Build::COMMANDS.each do |command| instance_variable_set("@#{command}", @build.send(command).clone) @@ -334,26 +336,26 @@ module MRuby end def generate_gem_table build - gem_table = @ary.reduce({}) { |res,v| res[v.name] = v; res } + gem_table = reduce({}) { |res,v| res[v.name] = v; res } - default_gems = [] + default_gems = {} each do |g| g.dependencies.each do |dep| - default_gems << default_gem_params(dep) unless gem_table.key? dep[:gem] + default_gems[dep[:gem]] ||= default_gem_params(dep) end end until default_gems.empty? - def_gem = default_gems.pop + def_name, def_gem = default_gems.shift + next if gem_table[def_name] - spec = build.gem def_gem[:default] - fail "Invalid gem name: #{spec.name} (Expected: #{def_gem[:gem]})" if spec.name != def_gem[:gem] + spec = gem_table[def_name] = build.gem(def_gem[:default]) + fail "Invalid gem name: #{spec.name} (Expected: #{def_name})" if spec.name != def_name spec.setup spec.dependencies.each do |dep| - default_gems << default_gem_params(dep) unless gem_table.key? dep[:gem] + default_gems[dep[:gem]] ||= default_gem_params(dep) end - gem_table[spec.name] = spec end each do |g| @@ -428,7 +430,7 @@ module MRuby end def import_include_paths(g) - gem_table = @ary.reduce({}) { |res,v| res[v.name] = v; res } + gem_table = reduce({}) { |res,v| res[v.name] = v; res } g.dependencies.each do |dep| dep_g = gem_table[dep[:gem]] # We can do recursive call safely -- cgit v1.2.3 From 482b2ea01e0bf13d0f7900272031ec6e0d2777a9 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Sun, 30 Dec 2018 11:16:00 +0900 Subject: Use `each_with_object` instead of `reduce`. For fix Codacy issue. --- lib/mruby/gem.rb | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/lib/mruby/gem.rb b/lib/mruby/gem.rb index 9f27f3ffc..b32b1eed2 100644 --- a/lib/mruby/gem.rb +++ b/lib/mruby/gem.rb @@ -336,7 +336,7 @@ module MRuby end def generate_gem_table build - gem_table = reduce({}) { |res,v| res[v.name] = v; res } + gem_table = each_with_object({}) { |spec, h| h[spec.name] = spec } default_gems = {} each do |g| @@ -430,7 +430,8 @@ module MRuby end def import_include_paths(g) - gem_table = reduce({}) { |res,v| res[v.name] = v; res } + gem_table = each_with_object({}) { |spec, h| h[spec.name] = spec } + g.dependencies.each do |dep| dep_g = gem_table[dep[:gem]] # We can do recursive call safely -- cgit v1.2.3 From bc03650c6abeb755b769355b703be7f240ae07e5 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Sun, 30 Dec 2018 09:46:48 +0900 Subject: mruby-enumerator: Refine accessors (obj/meth/args/fib). - `fib=` writer is not used. - All accessors are used as public (e.g. in `initialized_copy`). --- mrbgems/mruby-enumerator/mrblib/enumerator.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mrbgems/mruby-enumerator/mrblib/enumerator.rb b/mrbgems/mruby-enumerator/mrblib/enumerator.rb index 9d80bc552..5697c6609 100644 --- a/mrbgems/mruby-enumerator/mrblib/enumerator.rb +++ b/mrbgems/mruby-enumerator/mrblib/enumerator.rb @@ -128,8 +128,8 @@ class Enumerator @feedvalue = nil @stop_exc = false end - attr_accessor :obj, :meth, :args, :fib - private :obj, :meth, :args, :fib + attr_accessor :obj, :meth, :args + attr_reader :fib def initialize_copy(obj) raise TypeError, "can't copy type #{obj.class}" unless obj.kind_of? Enumerator -- cgit v1.2.3 From b04506cdcc4e389c9e157cefe6c3ad9e6afab7ca Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Mon, 31 Dec 2018 12:50:13 +0900 Subject: Should not check non-node value to `void_expr_error`; fix #4203 This is also a reason for #4192 as well. --- mrbgems/mruby-compiler/core/parse.y | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/mrbgems/mruby-compiler/core/parse.y b/mrbgems/mruby-compiler/core/parse.y index 0e67e5881..6a2defa8f 100644 --- a/mrbgems/mruby-compiler/core/parse.y +++ b/mrbgems/mruby-compiler/core/parse.y @@ -795,6 +795,13 @@ new_masgn(parser_state *p, node *a, node *b) return cons((node*)NODE_MASGN, cons(a, b)); } +/* (:masgn mlhs mrhs) no check */ +static node* +new_masgn_param(parser_state *p, node *a, node *b) +{ + return cons((node*)NODE_MASGN, cons(a, b)); +} + /* (:asgn lhs rhs) */ static node* new_op_asgn(parser_state *p, node *a, mrb_sym op, node *b) @@ -3302,7 +3309,7 @@ f_arg_item : f_norm_arg } f_margs rparen { - $$ = new_masgn(p, $3, p->locals->car); + $$ = new_masgn_param(p, $3, p->locals->car); local_resume(p, $2); local_add_f(p, 0); } -- cgit v1.2.3 From 4da687a6c3c9f1102c3ccd6f4dd12bea88683711 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Tue, 1 Jan 2019 09:38:58 +0900 Subject: Use `__send__` instead of `send` in a Range test. This assertion is accidentaly passed because `send` was removed from mruby core so `NoMethodError` is raised and `NoMethodError` is subclass of `NameError`. --- test/t/range.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/t/range.rb b/test/t/range.rb index 3e67fcc1c..5aee4d5cc 100644 --- a/test/t/range.rb +++ b/test/t/range.rb @@ -59,7 +59,7 @@ assert('Range#initialize', '15.2.14.4.9') do assert_equal (1..10), b assert_false b.exclude_end? - assert_raise(NameError) { (0..1).send(:initialize, 1, 3) } + assert_raise(NameError) { (0..1).__send__(:initialize, 1, 3) } end assert('Range#last', '15.2.14.4.10') do -- cgit v1.2.3 From 648b57620a6f0bd03ab11db61b1fee343c889dfe Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Tue, 1 Jan 2019 15:35:56 +0900 Subject: range: Embed edges in RRange on boxing environment. [Breaking changes] Developers must use following APIs for accessing attributes of RRange because RRange structure depends on boxing setting. - mrb_range_beg - mrb_range_end - mrb_range_excl_p --- include/mruby/range.h | 34 ++++++-- mrbgems/mruby-range-ext/src/range.c | 15 ++-- src/gc.c | 11 +-- src/range.c | 161 +++++++++++++++++++++--------------- test/t/range.rb | 16 ++++ 5 files changed, 147 insertions(+), 90 deletions(-) diff --git a/include/mruby/range.h b/include/mruby/range.h index b166e586b..4df5ccc70 100644 --- a/include/mruby/range.h +++ b/include/mruby/range.h @@ -14,20 +14,43 @@ */ MRB_BEGIN_DECL +#if defined(MRB_NAN_BOXING) || defined(MRB_WORD_BOXING) +# define MRB_RANGE_EMBED +#endif + +#ifdef MRB_RANGE_EMBED +struct RRange { + MRB_OBJECT_HEADER; + mrb_value beg; + mrb_value end; + mrb_bool excl; +}; +# define mrb_gc_free_range(mrb, p) ((void)0) +# define RANGE_BEG(p) ((p)->beg) +# define RANGE_END(p) ((p)->end) +#else typedef struct mrb_range_edges { mrb_value beg; mrb_value end; } mrb_range_edges; - struct RRange { MRB_OBJECT_HEADER; mrb_range_edges *edges; - mrb_bool excl : 1; + mrb_bool excl; }; +# define mrb_gc_free_range(mrb, p) mrb_free(mrb, ((struct RRange*)p)->edges) +# define RANGE_BEG(p) ((p)->edges->beg) +# define RANGE_END(p) ((p)->edges->end) +#endif + +#define mrb_range_beg(mrb, r) RANGE_BEG(mrb_range_ptr(mrb, r)) +#define mrb_range_end(mrb, r) RANGE_END(mrb_range_ptr(mrb, r)) +#define mrb_range_excl_p(mrb, r) RANGE_EXCL(mrb_range_ptr(mrb, r)) +#define mrb_range_raw_ptr(r) ((struct RRange*)mrb_ptr(r)) +#define mrb_range_value(p) mrb_obj_value((void*)(p)) +#define RANGE_EXCL(p) ((p)->excl) -MRB_API struct RRange* mrb_range_ptr(mrb_state *mrb, mrb_value v); -#define mrb_range_raw_ptr(v) ((struct RRange*)mrb_ptr(v)) -#define mrb_range_value(p) mrb_obj_value((void*)(p)) +MRB_API struct RRange* mrb_range_ptr(mrb_state *mrb, mrb_value range); /* * Initializes a Range. @@ -43,6 +66,7 @@ MRB_API mrb_value mrb_range_new(mrb_state *mrb, mrb_value start, mrb_value end, MRB_API mrb_int mrb_range_beg_len(mrb_state *mrb, mrb_value range, mrb_int *begp, mrb_int *lenp, mrb_int len, mrb_bool trunc); mrb_value mrb_get_values_at(mrb_state *mrb, mrb_value obj, mrb_int olen, mrb_int argc, const mrb_value *argv, mrb_value (*func)(mrb_state*, mrb_value, mrb_int)); +void mrb_gc_mark_range(mrb_state *mrb, struct RRange *r); MRB_END_DECL diff --git a/mrbgems/mruby-range-ext/src/range.c b/mrbgems/mruby-range-ext/src/range.c index aca71cc01..1fc383755 100644 --- a/mrbgems/mruby-range-ext/src/range.c +++ b/mrbgems/mruby-range-ext/src/range.c @@ -48,11 +48,11 @@ mrb_range_cover(mrb_state *mrb, mrb_value range) mrb_get_args(mrb, "o", &val); - beg = r->edges->beg; - end = r->edges->end; + beg = RANGE_BEG(r); + end = RANGE_END(r); if (r_le(mrb, beg, val)) { - if (r->excl) { + if (RANGE_EXCL(r)) { if (r_lt(mrb, val, end)) return mrb_true_value(); } @@ -86,10 +86,9 @@ mrb_range_last(mrb_state *mrb, mrb_value range) { mrb_value num; mrb_value array; - struct RRange *r = mrb_range_ptr(mrb, range); if (mrb_get_args(mrb, "|o", &num) == 0) { - return r->edges->end; + return mrb_range_end(mrb, range); } array = mrb_funcall(mrb, range, "to_a", 0); @@ -116,9 +115,9 @@ mrb_range_size(mrb_state *mrb, mrb_value range) mrb_bool num_p = TRUE; mrb_bool excl; - beg = r->edges->beg; - end = r->edges->end; - excl = r->excl; + beg = RANGE_BEG(r); + end = RANGE_END(r); + excl = RANGE_EXCL(r); if (mrb_fixnum_p(beg)) { beg_f = (mrb_float)mrb_fixnum(beg); } diff --git a/src/gc.c b/src/gc.c index a52c64bfa..ec52787e8 100644 --- a/src/gc.c +++ b/src/gc.c @@ -739,14 +739,7 @@ gc_mark_children(mrb_state *mrb, mrb_gc *gc, struct RBasic *obj) break; case MRB_TT_RANGE: - { - struct RRange *r = (struct RRange*)obj; - - if (r->edges) { - mrb_gc_mark_value(mrb, r->edges->beg); - mrb_gc_mark_value(mrb, r->edges->end); - } - } + mrb_gc_mark_range(mrb, (struct RRange*)obj); break; default: @@ -870,7 +863,7 @@ obj_free(mrb_state *mrb, struct RBasic *obj, int end) break; case MRB_TT_RANGE: - mrb_free(mrb, ((struct RRange*)obj)->edges); + mrb_gc_free_range(mrb, ((struct RRange*)obj)); break; case MRB_TT_DATA: diff --git a/src/range.c b/src/range.c index e45308d35..d2f897bd5 100644 --- a/src/range.c +++ b/src/range.c @@ -10,12 +10,17 @@ #include #include +#define RANGE_INITIALIZED_MASK 1 +#define RANGE_INITIALIZED(p) ((p)->flags |= RANGE_INITIALIZED_MASK) +#define RANGE_INITIALIZED_P(p) ((p)->flags & RANGE_INITIALIZED_MASK) + MRB_API struct RRange* -mrb_range_ptr(mrb_state *mrb, mrb_value v) +mrb_range_ptr(mrb_state *mrb, mrb_value range) { - struct RRange *r = (struct RRange*)mrb_ptr(v); + struct RRange *r = mrb_range_raw_ptr(range); - if (r->edges == NULL) { + /* check for if #initialize_copy was removed [#3320] */ + if (!RANGE_INITIALIZED_P(r)) { mrb_raise(mrb, E_ARGUMENT_ERROR, "uninitialized range"); } return r; @@ -46,17 +51,52 @@ range_check(mrb_state *mrb, mrb_value a, mrb_value b) } } -MRB_API mrb_value -mrb_range_new(mrb_state *mrb, mrb_value beg, mrb_value end, mrb_bool excl) +static void +range_ptr_alloc_edges(mrb_state *mrb, struct RRange *r) { - struct RRange *r; +#ifndef MRB_RANGE_EMBED + r->edges = (mrb_range_edges *)mrb_malloc(mrb, sizeof(mrb_range_edges)); +#endif +} +static struct RRange * +range_ptr_init(mrb_state *mrb, struct RRange *r, mrb_value beg, mrb_value end, mrb_bool excl) +{ range_check(mrb, beg, end); - r = (struct RRange*)mrb_obj_alloc(mrb, MRB_TT_RANGE, mrb->range_class); - r->edges = (mrb_range_edges *)mrb_malloc(mrb, sizeof(mrb_range_edges)); - r->edges->beg = beg; - r->edges->end = end; - r->excl = excl; + + if (r) { + if (RANGE_INITIALIZED_P(r)) { + /* Ranges are immutable, so that they should be initialized only once. */ + mrb_name_error(mrb, mrb_intern_lit(mrb, "initialize"), "`initialize' called twice"); + } + else { + range_ptr_alloc_edges(mrb, r); + } + } + else { + r = (struct RRange*)mrb_obj_alloc(mrb, MRB_TT_RANGE, mrb->range_class); + range_ptr_alloc_edges(mrb, r); + } + + RANGE_BEG(r) = beg; + RANGE_END(r) = end; + RANGE_EXCL(r) = excl; + RANGE_INITIALIZED(r); + + return r; +} + +static void +range_ptr_replace(mrb_state *mrb, struct RRange *r, mrb_value beg, mrb_value end, mrb_bool excl) +{ + range_ptr_init(mrb, r, beg, end, excl); + mrb_write_barrier(mrb, (struct RBasic*)r); +} + +MRB_API mrb_value +mrb_range_new(mrb_state *mrb, mrb_value beg, mrb_value end, mrb_bool excl) +{ + struct RRange *r = range_ptr_init(mrb, NULL, beg, end, excl); return mrb_range_value(r); } @@ -67,12 +107,10 @@ mrb_range_new(mrb_state *mrb, mrb_value beg, mrb_value end, mrb_bool excl) * * Returns the first object in rng. */ -mrb_value -mrb_range_beg(mrb_state *mrb, mrb_value range) +static mrb_value +range_beg(mrb_state *mrb, mrb_value range) { - struct RRange *r = mrb_range_ptr(mrb, range); - - return r->edges->beg; + return mrb_range_beg(mrb, range); } /* @@ -86,12 +124,10 @@ mrb_range_beg(mrb_state *mrb, mrb_value range) * (1...10).end #=> 10 */ -mrb_value -mrb_range_end(mrb_state *mrb, mrb_value range) +static mrb_value +range_end(mrb_state *mrb, mrb_value range) { - struct RRange *r = mrb_range_ptr(mrb, range); - - return r->edges->end; + return mrb_range_end(mrb, range); } /* @@ -103,25 +139,9 @@ mrb_range_end(mrb_state *mrb, mrb_value range) mrb_value mrb_range_excl(mrb_state *mrb, mrb_value range) { - struct RRange *r = mrb_range_ptr(mrb, range); - - return mrb_bool_value(r->excl); + return mrb_bool_value(mrb_range_excl_p(mrb, range)); } -static void -range_init(mrb_state *mrb, mrb_value range, mrb_value beg, mrb_value end, mrb_bool exclude_end) -{ - struct RRange *r = mrb_range_raw_ptr(range); - - range_check(mrb, beg, end); - r->excl = exclude_end; - if (!r->edges) { - r->edges = (mrb_range_edges *)mrb_malloc(mrb, sizeof(mrb_range_edges)); - } - r->edges->beg = beg; - r->edges->end = end; - mrb_write_barrier(mrb, (struct RBasic*)r); -} /* * call-seq: * Range.new(start, end, exclusive=false) => range @@ -142,11 +162,7 @@ mrb_range_initialize(mrb_state *mrb, mrb_value range) if (n != 3) { exclusive = FALSE; } - /* Ranges are immutable, so that they should be initialized only once. */ - if (mrb_range_raw_ptr(range)->edges) { - mrb_name_error(mrb, mrb_intern_lit(mrb, "initialize"), "`initialize' called twice"); - } - range_init(mrb, range, beg, end, exclusive); + range_ptr_replace(mrb, mrb_range_raw_ptr(range), beg, end, exclusive); return range; } /* @@ -180,9 +196,9 @@ mrb_range_eq(mrb_state *mrb, mrb_value range) rr = mrb_range_ptr(mrb, range); ro = mrb_range_ptr(mrb, obj); - v1 = mrb_funcall(mrb, rr->edges->beg, "==", 1, ro->edges->beg); - v2 = mrb_funcall(mrb, rr->edges->end, "==", 1, ro->edges->end); - if (!mrb_bool(v1) || !mrb_bool(v2) || rr->excl != ro->excl) { + v1 = mrb_funcall(mrb, RANGE_BEG(rr), "==", 1, RANGE_BEG(ro)); + v2 = mrb_funcall(mrb, RANGE_END(rr), "==", 1, RANGE_END(ro)); + if (!mrb_bool(v1) || !mrb_bool(v2) || RANGE_EXCL(rr) != RANGE_EXCL(ro)) { return mrb_false_value(); } return mrb_true_value(); @@ -242,11 +258,11 @@ mrb_range_include(mrb_state *mrb, mrb_value range) mrb_get_args(mrb, "o", &val); - beg = r->edges->beg; - end = r->edges->end; - include_p = r_le(mrb, beg, val) && /* beg <= val */ - (r->excl ? r_gt(mrb, end, val) /* end > val */ - : r_ge(mrb, end, val)); /* end >= val */ + beg = RANGE_BEG(r); + end = RANGE_END(r); + include_p = r_le(mrb, beg, val) && /* beg <= val */ + (RANGE_EXCL(r) ? r_gt(mrb, end, val) /* end > val */ + : r_ge(mrb, end, val)); /* end >= val */ return mrb_bool_value(include_p); } @@ -260,8 +276,8 @@ mrb_range_beg_len(mrb_state *mrb, mrb_value range, mrb_int *begp, mrb_int *lenp, if (mrb_type(range) != MRB_TT_RANGE) return 0; r = mrb_range_ptr(mrb, range); - beg = mrb_int(mrb, r->edges->beg); - end = mrb_int(mrb, r->edges->end); + beg = mrb_int(mrb, RANGE_BEG(r)); + end = mrb_int(mrb, RANGE_END(r)); if (beg < 0) { beg += len; @@ -274,7 +290,7 @@ mrb_range_beg_len(mrb_state *mrb, mrb_value range, mrb_int *begp, mrb_int *lenp, } if (end < 0) end += len; - if (!r->excl && (!trunc || end < len)) + if (!RANGE_EXCL(r) && (!trunc || end < len)) end++; /* include end point */ len = end - beg; if (len < 0) len = 0; @@ -298,10 +314,10 @@ range_to_s(mrb_state *mrb, mrb_value range) mrb_value str, str2; struct RRange *r = mrb_range_ptr(mrb, range); - str = mrb_obj_as_string(mrb, r->edges->beg); - str2 = mrb_obj_as_string(mrb, r->edges->end); + str = mrb_obj_as_string(mrb, RANGE_BEG(r)); + str2 = mrb_obj_as_string(mrb, RANGE_END(r)); str = mrb_str_dup(mrb, str); - mrb_str_cat(mrb, str, "...", r->excl ? 3 : 2); + mrb_str_cat(mrb, str, "...", RANGE_EXCL(r) ? 3 : 2); mrb_str_cat_str(mrb, str, str2); return str; @@ -323,10 +339,10 @@ range_inspect(mrb_state *mrb, mrb_value range) mrb_value str, str2; struct RRange *r = mrb_range_ptr(mrb, range); - str = mrb_inspect(mrb, r->edges->beg); - str2 = mrb_inspect(mrb, r->edges->end); + str = mrb_inspect(mrb, RANGE_BEG(r)); + str2 = mrb_inspect(mrb, RANGE_END(r)); str = mrb_str_dup(mrb, str); - mrb_str_cat(mrb, str, "...", r->excl ? 3 : 2); + mrb_str_cat(mrb, str, "...", RANGE_EXCL(r) ? 3 : 2); mrb_str_cat_str(mrb, str, str2); return str; @@ -363,9 +379,9 @@ range_eql(mrb_state *mrb, mrb_value range) r = mrb_range_ptr(mrb, range); o = mrb_range_ptr(mrb, obj); - if (!mrb_eql(mrb, r->edges->beg, o->edges->beg) || - !mrb_eql(mrb, r->edges->end, o->edges->end) || - (r->excl != o->excl)) { + if (!mrb_eql(mrb, RANGE_BEG(r), RANGE_BEG(o)) || + !mrb_eql(mrb, RANGE_END(r), RANGE_END(o)) || + (RANGE_EXCL(r) != RANGE_EXCL(o))) { return mrb_false_value(); } return mrb_true_value(); @@ -386,7 +402,7 @@ range_initialize_copy(mrb_state *mrb, mrb_value copy) } r = mrb_range_ptr(mrb, src); - range_init(mrb, copy, r->edges->beg, r->edges->end, r->excl); + range_ptr_replace(mrb, mrb_range_raw_ptr(copy), RANGE_BEG(r), RANGE_END(r), RANGE_EXCL(r)); return copy; } @@ -420,6 +436,15 @@ mrb_get_values_at(mrb_state *mrb, mrb_value obj, mrb_int olen, mrb_int argc, con return result; } +void +mrb_gc_mark_range(mrb_state *mrb, struct RRange *r) +{ + if (RANGE_INITIALIZED_P(r)) { + mrb_gc_mark_value(mrb, RANGE_BEG(r)); + mrb_gc_mark_value(mrb, RANGE_END(r)); + } +} + void mrb_init_range(mrb_state *mrb) { @@ -429,15 +454,15 @@ mrb_init_range(mrb_state *mrb) mrb->range_class = r; MRB_SET_INSTANCE_TT(r, MRB_TT_RANGE); - mrb_define_method(mrb, r, "begin", mrb_range_beg, MRB_ARGS_NONE()); /* 15.2.14.4.3 */ - mrb_define_method(mrb, r, "end", mrb_range_end, MRB_ARGS_NONE()); /* 15.2.14.4.5 */ + mrb_define_method(mrb, r, "begin", range_beg, MRB_ARGS_NONE()); /* 15.2.14.4.3 */ + mrb_define_method(mrb, r, "end", range_end, MRB_ARGS_NONE()); /* 15.2.14.4.5 */ mrb_define_method(mrb, r, "==", mrb_range_eq, MRB_ARGS_REQ(1)); /* 15.2.14.4.1 */ mrb_define_method(mrb, r, "===", mrb_range_include, MRB_ARGS_REQ(1)); /* 15.2.14.4.2 */ mrb_define_method(mrb, r, "exclude_end?", mrb_range_excl, MRB_ARGS_NONE()); /* 15.2.14.4.6 */ - mrb_define_method(mrb, r, "first", mrb_range_beg, MRB_ARGS_NONE()); /* 15.2.14.4.7 */ + mrb_define_method(mrb, r, "first", range_beg, MRB_ARGS_NONE()); /* 15.2.14.4.7 */ mrb_define_method(mrb, r, "include?", mrb_range_include, MRB_ARGS_REQ(1)); /* 15.2.14.4.8 */ mrb_define_method(mrb, r, "initialize", mrb_range_initialize, MRB_ARGS_ANY()); /* 15.2.14.4.9 */ - mrb_define_method(mrb, r, "last", mrb_range_end, MRB_ARGS_NONE()); /* 15.2.14.4.10 */ + mrb_define_method(mrb, r, "last", range_end, MRB_ARGS_NONE()); /* 15.2.14.4.10 */ mrb_define_method(mrb, r, "member?", mrb_range_include, MRB_ARGS_REQ(1)); /* 15.2.14.4.11 */ mrb_define_method(mrb, r, "to_s", range_to_s, MRB_ARGS_NONE()); /* 15.2.14.4.12(x) */ diff --git a/test/t/range.rb b/test/t/range.rb index 5aee4d5cc..64e7f9d9f 100644 --- a/test/t/range.rb +++ b/test/t/range.rb @@ -93,3 +93,19 @@ assert('Range#eql?', '15.2.14.4.14') do assert_false (1..10).eql? (Range.new(1.0, 10.0)) assert_false (1..10).eql? "1..10" end + +assert('Range#initialize_copy', '15.2.14.4.15') do + assert_raise(NameError) { (0..1).__send__(:initialize_copy, 1..3) } +end + +assert('Range#dup') do + r = (1..3).dup + assert_equal r.begin, 1 + assert_equal r.end, 3 + assert_false r.exclude_end? + + r = ("a"..."z").dup + assert_equal r.begin, "a" + assert_equal r.end, "z" + assert_true r.exclude_end? +end -- cgit v1.2.3 From ff0ab552d0f44c62ea9852f12353b9a6de5ab7d9 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Tue, 1 Jan 2019 19:25:12 +0900 Subject: io: Skip TTY test for environments that TTY device is unavailable. e.g. GitLab CI --- mrbgems/mruby-io/test/io.rb | 24 +++++++++++++++--------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/mrbgems/mruby-io/test/io.rb b/mrbgems/mruby-io/test/io.rb index 48a74f31e..e4a449696 100644 --- a/mrbgems/mruby-io/test/io.rb +++ b/mrbgems/mruby-io/test/io.rb @@ -344,15 +344,21 @@ end assert('IO#isatty') do skip "isatty is not supported on this platform" if MRubyIOTestUtil.win? - f1 = File.open("/dev/tty") - f2 = File.open($mrbtest_io_rfname) - - assert_true f1.isatty - assert_false f2.isatty - - f1.close - f2.close - true + begin + f = File.open("/dev/tty") + rescue RuntimeError => e + skip e.message + else + assert_true f.isatty + ensure + f&.close + end + begin + f = File.open($mrbtest_io_rfname) + assert_false f.isatty + ensure + f&.close + end end assert('IO#pos=, IO#seek') do -- cgit v1.2.3 From f9d89e3fa592706de6a6dee701af3961df914292 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Thu, 3 Jan 2019 11:29:10 +0900 Subject: `mruby-inline-struct` to support `MRB_WITHOUT_FLOAT`. --- mrbgems/mruby-inline-struct/test/inline.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/mrbgems/mruby-inline-struct/test/inline.c b/mrbgems/mruby-inline-struct/test/inline.c index 91c767f30..51804ae31 100644 --- a/mrbgems/mruby-inline-struct/test/inline.c +++ b/mrbgems/mruby-inline-struct/test/inline.c @@ -11,12 +11,14 @@ istruct_test_initialize(mrb_state *mrb, mrb_value self) mrb_value object; mrb_get_args(mrb, "o", &object); - if (mrb_float_p(object)) { - strncpy(string, "float", size-1); - } - else if (mrb_fixnum_p(object)) { + if (mrb_fixnum_p(object)) { strncpy(string, "fixnum", size-1); } +#ifndef MRB_WITHOUT_FLOAT + else if (mrb_float_p(object)) { + strncpy(string, "float", size-1); + } +#endif else if (mrb_string_p(object)) { strncpy(string, "string", size-1); } -- cgit v1.2.3 From cca19532c5f71e1bdc0b4947b2fcddd181f27781 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Thu, 3 Jan 2019 11:34:35 +0900 Subject: Remove `Kernel#class_defined?` which is not available in CRuby; #3829 --- mrbgems/mruby-kernel-ext/test/kernel.rb | 6 ++- mrbgems/mruby-numeric-ext/test/numeric.rb | 3 +- mrbgems/mruby-object-ext/test/nil.rb | 3 +- mrbgems/mruby-objectspace/test/objectspace.rb | 2 +- mrbgems/mruby-sprintf/test/sprintf.rb | 9 +++-- mrblib/float.rb | 2 +- mrblib/numeric.rb | 2 +- src/kernel.c | 12 ------ test/t/array.rb | 3 +- test/t/class.rb | 2 +- test/t/float.rb | 4 +- test/t/hash.rb | 3 +- test/t/integer.rb | 54 +++++++++++++-------------- test/t/numeric.rb | 3 +- test/t/range.rb | 3 +- test/t/string.rb | 4 +- 16 files changed, 56 insertions(+), 59 deletions(-) diff --git a/mrbgems/mruby-kernel-ext/test/kernel.rb b/mrbgems/mruby-kernel-ext/test/kernel.rb index 206b7ac74..28f089007 100644 --- a/mrbgems/mruby-kernel-ext/test/kernel.rb +++ b/mrbgems/mruby-kernel-ext/test/kernel.rb @@ -49,21 +49,23 @@ assert('Kernel#__method__') do end assert('Kernel#Integer') do - assert_equal(123, Integer(123.999)) if class_defined?("Float") assert_equal(26, Integer("0x1a")) assert_equal(930, Integer("0930", 10)) assert_equal(7, Integer("111", 2)) assert_equal(0, Integer("0")) assert_equal(0, Integer("00000")) assert_raise(TypeError) { Integer(nil) } + skip unless Object.const_defined?(:Float) + assert_equal(123, Integer(123.999)) end assert('Kernel#Float') do + skip unless Object.const_defined?(:Float) assert_equal(1.0, Float(1)) assert_equal(123.456, Float(123.456)) assert_equal(123.456, Float("123.456")) assert_raise(TypeError) { Float(nil) } -end if class_defined?("Float") +end assert('Kernel#String') do assert_equal("main", String(self)) diff --git a/mrbgems/mruby-numeric-ext/test/numeric.rb b/mrbgems/mruby-numeric-ext/test/numeric.rb index 6ea0c14e7..c85cb61f2 100644 --- a/mrbgems/mruby-numeric-ext/test/numeric.rb +++ b/mrbgems/mruby-numeric-ext/test/numeric.rb @@ -14,8 +14,9 @@ assert('Integer#div') do end assert('Float#div') do + skip unless Object.const_defined?(:Float) assert_float 52, 365.2425.div(7) -end if class_defined?("Float") +end assert('Integer#zero?') do assert_equal true, 0.zero? diff --git a/mrbgems/mruby-object-ext/test/nil.rb b/mrbgems/mruby-object-ext/test/nil.rb index 7f773637a..fbff20629 100644 --- a/mrbgems/mruby-object-ext/test/nil.rb +++ b/mrbgems/mruby-object-ext/test/nil.rb @@ -3,8 +3,9 @@ assert('NilClass#to_a') do end assert('NilClass#to_f') do + skip unless Object.const_defined?(:Float) assert_equal 0.0, nil.to_f -end if class_defined?("Float") +end assert('NilClass#to_i') do assert_equal 0, nil.to_i diff --git a/mrbgems/mruby-objectspace/test/objectspace.rb b/mrbgems/mruby-objectspace/test/objectspace.rb index 0553b97e2..8db89eeaf 100644 --- a/mrbgems/mruby-objectspace/test/objectspace.rb +++ b/mrbgems/mruby-objectspace/test/objectspace.rb @@ -1,6 +1,6 @@ assert('ObjectSpace.count_objects') do h = {} - f = Fiber.new {} if Object.const_defined? :Fiber + f = Fiber.new {} if Object.const_defined?(:Fiber) ObjectSpace.count_objects(h) assert_kind_of(Hash, h) assert_true(h.keys.all? {|x| x.is_a?(Symbol) || x.is_a?(Integer) }) diff --git a/mrbgems/mruby-sprintf/test/sprintf.rb b/mrbgems/mruby-sprintf/test/sprintf.rb index a5fd4e638..137812ae7 100644 --- a/mrbgems/mruby-sprintf/test/sprintf.rb +++ b/mrbgems/mruby-sprintf/test/sprintf.rb @@ -4,12 +4,14 @@ assert('String#%') do assert_equal "one=1", "one=%d" % 1 assert_equal "1 one", "%d %s" % [ 1, "one" ] - assert_equal "1.0", "%3.1f" % 1.01 if class_defined?("Float") assert_equal "123 < 456", "%{num} < %s" % { num: 123, str: "456" } assert_equal 15, ("%b" % (1<<14)).size + skip unless Object.const_defined?(:Float) + assert_equal "1.0", "%3.1f" % 1.01 end assert('String#% with inf') do + skip unless Object.const_defined?(:Float) inf = Float::INFINITY assert_equal "Inf", "%f" % inf @@ -35,9 +37,10 @@ assert('String#% with inf') do assert_equal " Inf", "% 3f" % inf assert_equal " Inf", "% 4f" % inf assert_equal " Inf", "% 5f" % inf -end if class_defined?("Float") +end assert('String#% with nan') do + skip unless Object.const_defined?(:Float) nan = Float::NAN assert_equal "NaN", "%f" % nan @@ -63,7 +66,7 @@ assert('String#% with nan') do assert_equal " NaN", "% 3f" % nan assert_equal " NaN", "% 4f" % nan assert_equal " NaN", "% 5f" % nan -end if class_defined?("Float") +end assert("String#% with invalid chr") do begin diff --git a/mrblib/float.rb b/mrblib/float.rb index 2b86dc1e5..421b8d851 100644 --- a/mrblib/float.rb +++ b/mrblib/float.rb @@ -6,4 +6,4 @@ class Float # mruby special - since mruby integers may be upgraded to floats, # floats should be compatible to integers. include Integral -end if class_defined?("Float") +end if Object.const_defined?(:Float) diff --git a/mrblib/numeric.rb b/mrblib/numeric.rb index 1b11e92ad..a2eb9c450 100644 --- a/mrblib/numeric.rb +++ b/mrblib/numeric.rb @@ -104,7 +104,7 @@ module Integral raise ArgumentError, "step can't be 0" if step == 0 return to_enum(:step, num, step) unless block - i = if class_defined?("Float") && num.kind_of?(Float) then self.to_f else self end + i = if Object.const_defined?(:Float) && num.kind_of?(Float) then self.to_f else self end if num == nil while true block.call(i) diff --git a/src/kernel.c b/src/kernel.c index ce9cd1d44..8845cbce6 100644 --- a/src/kernel.c +++ b/src/kernel.c @@ -640,16 +640,6 @@ mrb_f_raise(mrb_state *mrb, mrb_value self) return mrb_nil_value(); /* not reached */ } -static mrb_value -mrb_krn_class_defined(mrb_state *mrb, mrb_value self) -{ - mrb_value str; - - mrb_get_args(mrb, "S", &str); - return mrb_bool_value(mrb_class_defined(mrb, RSTRING_PTR(str))); -} - - /* 15.3.1.3.41 */ /* * call-seq: @@ -847,8 +837,6 @@ mrb_init_kernel(mrb_state *mrb) mrb_define_method(mrb, krn, "__to_int", mrb_to_int, MRB_ARGS_NONE()); /* internal */ mrb_define_method(mrb, krn, "__to_str", mrb_to_str, MRB_ARGS_NONE()); /* internal */ - mrb_define_method(mrb, krn, "class_defined?", mrb_krn_class_defined, MRB_ARGS_REQ(1)); - mrb_include_module(mrb, mrb->object_class, mrb->kernel_module); mrb_define_alias(mrb, mrb->module_class, "dup", "clone"); /* XXX */ } diff --git a/test/t/array.rb b/test/t/array.rb index 53fbdcf1a..c182d5e14 100644 --- a/test/t/array.rb +++ b/test/t/array.rb @@ -55,9 +55,10 @@ assert('Array#[]', '15.2.12.5.4') do assert_equal(nil, [1,2,3].[](-4)) a = [ "a", "b", "c", "d", "e" ] - assert_equal("b", a[1.1]) if class_defined?("Float") assert_equal(["b", "c"], a[1,2]) assert_equal(["b", "c", "d"], a[1..-2]) + skip unless Object.const_defined?(:Float) + assert_equal("b", a[1.1]) end assert('Array#[]=', '15.2.12.5.5') do diff --git a/test/t/class.rb b/test/t/class.rb index 85450f200..f37a891a4 100644 --- a/test/t/class.rb +++ b/test/t/class.rb @@ -350,7 +350,7 @@ assert('singleton tests') do 7 end end - end if class_defined?("Float") + end if Object.const_defined?(:Float) end assert('clone Class') do diff --git a/test/t/float.rb b/test/t/float.rb index 92f7a15f1..68fd31b9a 100644 --- a/test/t/float.rb +++ b/test/t/float.rb @@ -1,7 +1,7 @@ ## # Float ISO Test -if class_defined?("Float") +if Object.const_defined?(:Float) assert('Float', '15.2.9') do assert_equal Class, Float.class @@ -206,4 +206,4 @@ assert('Float#>>') do assert_equal(-1, -23.0 >> 128) end -end # class_defined?("Float") +end # const_defined?(:Float) diff --git a/test/t/hash.rb b/test/t/hash.rb index 8088bfa21..e3f917b6f 100644 --- a/test/t/hash.rb +++ b/test/t/hash.rb @@ -8,8 +8,9 @@ end assert('Hash#==', '15.2.13.4.1') do assert_true({ 'abc' => 'abc' } == { 'abc' => 'abc' }) assert_false({ 'abc' => 'abc' } == { 'cba' => 'cba' }) - assert_true({ :equal => 1 } == { :equal => 1.0 }) if class_defined?("Float") assert_false({ :a => 1 } == true) + skip unless Object.const_defined?(:Float) + assert_true({ :equal => 1 } == { :equal => 1.0 }) end assert('Hash#[]', '15.2.13.4.2') do diff --git a/test/t/integer.rb b/test/t/integer.rb index cea97a1e6..c37641e9f 100644 --- a/test/t/integer.rb +++ b/test/t/integer.rb @@ -7,10 +7,10 @@ end assert('Integer#+', '15.2.8.3.1') do a = 1+1 - b = 1+1.0 if class_defined?("Float") + b = 1+1.0 if Object.const_defined?(:Float) assert_equal 2, a - assert_equal 2.0, b if class_defined?("Float") + assert_equal 2.0, b if Object.const_defined?(:Float) assert_raise(TypeError){ 0+nil } assert_raise(TypeError){ 1+nil } @@ -18,40 +18,38 @@ assert('Integer#+', '15.2.8.3.1') do c = Mrbtest::FIXNUM_MAX + 1 d = Mrbtest::FIXNUM_MAX.__send__(:+, 1) - if class_defined?("Float") - e = Mrbtest::FIXNUM_MAX + 1.0 - assert_equal Float, c.class - assert_equal Float, d.class - assert_float e, c - assert_float e, d - end + skip unless Object.const_defined?(:Float) + e = Mrbtest::FIXNUM_MAX + 1.0 + assert_equal Float, c.class + assert_equal Float, d.class + assert_float e, c + assert_float e, d end assert('Integer#-', '15.2.8.3.2') do a = 2-1 - b = 2-1.0 if class_defined?("Float") + b = 2-1.0 if Object.const_defined?(:Float) assert_equal 1, a - assert_equal 1.0, b if class_defined?("Float") + assert_equal 1.0, b if Object.const_defined?(:Float) c = Mrbtest::FIXNUM_MIN - 1 d = Mrbtest::FIXNUM_MIN.__send__(:-, 1) - if class_defined?("Float") - e = Mrbtest::FIXNUM_MIN - 1.0 - assert_equal Float, c.class - assert_equal Float, d.class - assert_float e, c - assert_float e, d - end + skip unless Object.const_defined?(:Float) + e = Mrbtest::FIXNUM_MIN - 1.0 + assert_equal Float, c.class + assert_equal Float, d.class + assert_float e, c + assert_float e, d end assert('Integer#*', '15.2.8.3.3') do a = 1*1 - b = 1*1.0 if class_defined?("Float") + b = 1*1.0 if Object.const_defined?(:Float) assert_equal 1, a - assert_equal 1.0, b if class_defined?("Float") + assert_equal 1.0, b if Object.const_defined?(:Float) assert_raise(TypeError){ 0*nil } assert_raise(TypeError){ 1*nil } @@ -59,13 +57,12 @@ assert('Integer#*', '15.2.8.3.3') do c = Mrbtest::FIXNUM_MAX * 2 d = Mrbtest::FIXNUM_MAX.__send__(:*, 2) - if class_defined?("Float") - e = Mrbtest::FIXNUM_MAX * 2.0 - assert_equal Float, c.class - assert_equal Float, d.class - assert_float e, c - assert_float e, d - end + skip unless Object.const_defined?(:Float) + e = Mrbtest::FIXNUM_MAX * 2.0 + assert_equal Float, c.class + assert_equal Float, d.class + assert_float e, c + assert_float e, d end assert('Integer#/', '15.2.8.3.4') do @@ -226,8 +223,9 @@ assert('Integer#times', '15.2.8.3.22') do end assert('Integer#to_f', '15.2.8.3.23') do + skip unless Object.const_defined?(:Float) assert_equal 1.0, 1.to_f -end if class_defined?("Float") +end assert('Integer#to_i', '15.2.8.3.24') do assert_equal 1, 1.to_i diff --git a/test/t/numeric.rb b/test/t/numeric.rb index 38c62a669..9d6dc22cc 100644 --- a/test/t/numeric.rb +++ b/test/t/numeric.rb @@ -15,7 +15,8 @@ end assert('Numeric#abs', '15.2.7.4.3') do assert_equal(1, 1.abs) - assert_equal(1.0, -1.abs) if class_defined?("Float") + skip unless Object.const_defined?(:Float) + assert_equal(1.0, -1.abs) end assert('Numeric#pow') do diff --git a/test/t/range.rb b/test/t/range.rb index 64e7f9d9f..d71fe8946 100644 --- a/test/t/range.rb +++ b/test/t/range.rb @@ -8,7 +8,8 @@ end assert('Range#==', '15.2.14.4.1') do assert_true (1..10) == (1..10) assert_false (1..10) == (1..100) - assert_true (1..10) == Range.new(1.0, 10.0) if class_defined?("Float") + skip unless Object.const_defined?(:Float) + assert_true (1..10) == Range.new(1.0, 10.0) end assert('Range#===', '15.2.14.4.2') do diff --git a/test/t/string.rb b/test/t/string.rb index 3a1eced16..8f008c6a7 100644 --- a/test/t/string.rb +++ b/test/t/string.rb @@ -155,7 +155,7 @@ assert('String#[]=') do d[-10] = 'X' end - if class_defined?("Float") + if Object.const_defined?(:Float) e = 'abc' e[1.1] = 'X' assert_equal 'aXc', e @@ -618,7 +618,7 @@ assert('String#to_f', '15.2.10.5.38') do assert_float(12345.6789, c) assert_float(0, d) assert_float(Float::INFINITY, e) -end if class_defined?("Float") +end if Object.const_defined?(:Float) assert('String#to_i', '15.2.10.5.39') do a = ''.to_i -- cgit v1.2.3 From 9a9e12a1299181bc38abbb4e8dbb62569bcbc551 Mon Sep 17 00:00:00 2001 From: dearblue Date: Tue, 1 Jan 2019 13:15:48 +0900 Subject: Add proc composition feature (CRuby-2.6 compatible) - Proc#<< and Proc#>> - Method#<< and Method#>> --- mrbgems/mruby-method/mrblib/method.rb | 8 ++++++++ mrbgems/mruby-proc-ext/mrblib/proc.rb | 8 ++++++++ 2 files changed, 16 insertions(+) diff --git a/mrbgems/mruby-method/mrblib/method.rb b/mrbgems/mruby-method/mrblib/method.rb index 5de0afdf7..f7cefa2e5 100644 --- a/mrbgems/mruby-method/mrblib/method.rb +++ b/mrbgems/mruby-method/mrblib/method.rb @@ -17,4 +17,12 @@ class Method def name @name end + + def <<(other) + ->(*args, &block) { call(other.call(*args, &block)) } + end + + def >>(other) + ->(*args, &block) { other.call(call(*args, &block)) } + end end diff --git a/mrbgems/mruby-proc-ext/mrblib/proc.rb b/mrbgems/mruby-proc-ext/mrblib/proc.rb index 789b7a3ac..abe9c7944 100644 --- a/mrbgems/mruby-proc-ext/mrblib/proc.rb +++ b/mrbgems/mruby-proc-ext/mrblib/proc.rb @@ -39,4 +39,12 @@ class Proc make_curry.call end + def <<(other) + ->(*args, &block) { call(other.call(*args, &block)) } + end + + def >>(other) + ->(*args, &block) { other.call(call(*args, &block)) } + end + end -- cgit v1.2.3 From a98359faa7927a0443e25a7787546ddf93c06ba9 Mon Sep 17 00:00:00 2001 From: dearblue Date: Tue, 1 Jan 2019 13:21:12 +0900 Subject: Add enumerator chain feature (CRuby-2.6 compatible) - Enumerator::Chain - Enumerable#chain - Enumerable#+ --- mrbgems/mruby-enum-chain/mrbgem.rake | 6 ++++ mrbgems/mruby-enum-chain/mrblib/chain.rb | 60 ++++++++++++++++++++++++++++++++ 2 files changed, 66 insertions(+) create mode 100644 mrbgems/mruby-enum-chain/mrbgem.rake create mode 100644 mrbgems/mruby-enum-chain/mrblib/chain.rb diff --git a/mrbgems/mruby-enum-chain/mrbgem.rake b/mrbgems/mruby-enum-chain/mrbgem.rake new file mode 100644 index 000000000..7294f2644 --- /dev/null +++ b/mrbgems/mruby-enum-chain/mrbgem.rake @@ -0,0 +1,6 @@ +MRuby::Gem::Specification.new('mruby-enum-chain') do |spec| + spec.license = 'MIT' + spec.author = 'mruby developers' + spec.summary = 'Enumerator::Chain class' + spec.add_dependency('mruby-enumerator', :core => 'mruby-enumerator') +end diff --git a/mrbgems/mruby-enum-chain/mrblib/chain.rb b/mrbgems/mruby-enum-chain/mrblib/chain.rb new file mode 100644 index 000000000..98515ea14 --- /dev/null +++ b/mrbgems/mruby-enum-chain/mrblib/chain.rb @@ -0,0 +1,60 @@ +## +# chain.rb Enumerator::Chain class +# See Copyright Notice in mruby.h + +module Enumerable + def chain(*args) + Enumerator::Chain.new(self, *args) + end + + def +(other) + Enumerator::Chain.new(self, other) + end +end + +class Enumerator + class Chain + include Enumerable + + def initialize(*args) + @enums = args + end + + def initialize_copy(orig) + @enums = orig.__copy_enums + end + + def each(&block) + return to_enum unless block_given? + + @enums.each { |e| e.each(&block) } + + self + end + + def size + @enums.reduce(0) do |a, e| + return nil unless e.respond_to?(:size) + a + e.size + end + end + + def rewind + @enums.reverse_each do |e| + e.rewind if e.respond_to?(:rewind) + end + + self + end + + def inspect + "#<#{self.class}: #{@enums.inspect}>" + end + + def __copy_enums + @enums.each_with_object([]) do |e, a| + a << e.clone + end + end + end +end -- cgit v1.2.3 From fc20d0186dfa3a6bd72b4cf1e09a1497c50b536b Mon Sep 17 00:00:00 2001 From: dearblue Date: Thu, 3 Jan 2019 17:15:04 +0900 Subject: Add test for #<< and #>> for Proc and Method class --- mrbgems/mruby-method/test/method.rb | 19 +++++++++++++++++++ mrbgems/mruby-proc-ext/test/proc.rb | 13 +++++++++++++ 2 files changed, 32 insertions(+) diff --git a/mrbgems/mruby-method/test/method.rb b/mrbgems/mruby-method/test/method.rb index 9fd6a558e..dfddde9cc 100644 --- a/mrbgems/mruby-method/test/method.rb +++ b/mrbgems/mruby-method/test/method.rb @@ -371,6 +371,25 @@ assert "Method#initialize_copy" do assert_equal(m1, m2) end +assert "Method#<< and Method#>>" do + obj = Object.new + class << obj + def mul2(n); n * 2; end + def add3(n); n + 3; end + end + + f = obj.method(:mul2) + g = obj.method(:add3) + + m1 = f << g + assert_kind_of Proc, m1 + assert_equal 16, m1.call(5) + + m2 = f >> g + assert_kind_of Proc, m2 + assert_equal 13, m2.call(5) +end + assert 'UnboundMethod#arity' do c = Class.new { def foo(a, b) diff --git a/mrbgems/mruby-proc-ext/test/proc.rb b/mrbgems/mruby-proc-ext/test/proc.rb index 3e64bc103..1220841c8 100644 --- a/mrbgems/mruby-proc-ext/test/proc.rb +++ b/mrbgems/mruby-proc-ext/test/proc.rb @@ -77,6 +77,19 @@ assert('Kernel#proc') do end end +assert "Proc#<< and Proc#>>" do + add3 = ->(n) { n + 3 } + mul2 = ->(n) { n * 2 } + + f1 = mul2 << add3 + assert_kind_of Proc, f1 + assert_equal 16, f1.call(5) + + f2 = mul2 >> add3 + assert_kind_of Proc, f2 + assert_equal 13, f2.call(5) +end + assert('mrb_proc_new_cfunc_with_env') do ProcExtTest.mrb_proc_new_cfunc_with_env(:test) ProcExtTest.mrb_proc_new_cfunc_with_env(:mruby) -- cgit v1.2.3 From f392337e10708fa1fbe6f610a9d215835087bf05 Mon Sep 17 00:00:00 2001 From: dearblue Date: Tue, 1 Jan 2019 15:13:04 +0900 Subject: Add test for Enumerator::Chain --- mrbgems/mruby-enum-chain/test/enum_chain.rb | 76 +++++++++++++++++++++++++++++ 1 file changed, 76 insertions(+) create mode 100644 mrbgems/mruby-enum-chain/test/enum_chain.rb diff --git a/mrbgems/mruby-enum-chain/test/enum_chain.rb b/mrbgems/mruby-enum-chain/test/enum_chain.rb new file mode 100644 index 000000000..4dd59bd37 --- /dev/null +++ b/mrbgems/mruby-enum-chain/test/enum_chain.rb @@ -0,0 +1,76 @@ +## +# Enumerator::Chain test + +assert("Enumerable#chain") do + a = [] + b = {} + c = Object.new # not has #each method + + assert_kind_of Enumerator::Chain, a.chain + assert_kind_of Enumerator::Chain, a.chain(b) + assert_kind_of Enumerator::Chain, a.chain(b, c) + assert_raise(NoMethodError) { c.chain } +end + +assert("Enumerable#+") do + a = [].each + b = {}.reverse_each + c = Object.new # not has #each method + + assert_kind_of Enumerator::Chain, a + b + assert_kind_of Enumerator::Chain, a + c + assert_kind_of Enumerator::Chain, b + a + assert_kind_of Enumerator::Chain, b + c + assert_raise(NoMethodError) { c + a } +end + +assert("Enumerator.new") do + a = [] + b = {} + c = Object.new # not has #each method + + assert_kind_of Enumerator::Chain, Enumerator::Chain.new + assert_kind_of Enumerator::Chain, Enumerator::Chain.new(a, a) + assert_kind_of Enumerator::Chain, Enumerator::Chain.new(a, b) + assert_kind_of Enumerator::Chain, Enumerator::Chain.new(a, c) + assert_kind_of Enumerator::Chain, Enumerator::Chain.new(b, a) + assert_kind_of Enumerator::Chain, Enumerator::Chain.new(b, b) + assert_kind_of Enumerator::Chain, Enumerator::Chain.new(b, c) + assert_kind_of Enumerator::Chain, Enumerator::Chain.new(c, a) +end + +assert("Enumerator::Chain#each") do + a = [1, 2, 3] + + aa = a.chain(a) + assert_kind_of Enumerator, aa.each + assert_equal [1, 2, 3, 1, 2, 3], aa.each.to_a + + aa = a.chain(a.reverse_each) + assert_kind_of Enumerator, aa.each + assert_equal [1, 2, 3, 3, 2, 1], aa.each.to_a + + aa = a.chain(a.reverse_each, a) + assert_kind_of Enumerator, aa.each + assert_equal [1, 2, 3, 3, 2, 1, 1, 2, 3], aa.each.to_a + + aa = a.chain(Object.new) + assert_kind_of Enumerator, aa.each + assert_raise(NoMethodError) { aa.each.to_a } +end + +assert("Enumerator::Chain#size") do + a = [1, 2, 3] + + aa = a.chain(a) + assert_equal 6, aa.size + + aa = a.chain(a.reverse_each) + assert_nil aa.size + + aa = a.chain(a.reverse_each, a) + assert_nil aa.size + + aa = a.chain(Object.new) + assert_nil aa.size +end -- cgit v1.2.3 From 668d632c6e7c4a0ad89cc262d6124ad42a9e664f Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Thu, 3 Jan 2019 19:11:30 +0900 Subject: pack: Remove redundant float check in pack_utf8() The argument is converted to fixnum before calling. --- mrbgems/mruby-pack/src/pack.c | 8 -------- 1 file changed, 8 deletions(-) diff --git a/mrbgems/mruby-pack/src/pack.c b/mrbgems/mruby-pack/src/pack.c index f274ff11e..2e68f35ed 100644 --- a/mrbgems/mruby-pack/src/pack.c +++ b/mrbgems/mruby-pack/src/pack.c @@ -457,11 +457,6 @@ pack_utf8(mrb_state *mrb, mrb_value o, mrb_value str, mrb_int sidx, long count, int len = 0; uint32_t c = 0; -#ifndef MRB_WITHOUT_FLOAT - if (mrb_float_p(o)) { - goto range_error; - } -#endif c = (uint32_t)mrb_fixnum(o); /* Unicode character */ @@ -489,9 +484,6 @@ pack_utf8(mrb_state *mrb, mrb_value o, mrb_value str, mrb_int sidx, long count, len = 4; } else { -#ifndef MRB_WITHOUT_FLOAT -range_error: -#endif mrb_raise(mrb, E_RANGE_ERROR, "pack(U): value out of range"); } -- cgit v1.2.3 From eb216fc858f2dbb05731699b87e1d59619577e9d Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Thu, 3 Jan 2019 20:09:41 +0900 Subject: range: Refactor range.h/range.c Functions order, name, linkage and so on. --- include/mruby/range.h | 2 +- src/range.c | 229 +++++++++++++++++++++++--------------------------- 2 files changed, 108 insertions(+), 123 deletions(-) diff --git a/include/mruby/range.h b/include/mruby/range.h index 4df5ccc70..b5626993a 100644 --- a/include/mruby/range.h +++ b/include/mruby/range.h @@ -38,7 +38,7 @@ struct RRange { mrb_range_edges *edges; mrb_bool excl; }; -# define mrb_gc_free_range(mrb, p) mrb_free(mrb, ((struct RRange*)p)->edges) +# define mrb_gc_free_range(mrb, p) mrb_free(mrb, (p)->edges) # define RANGE_BEG(p) ((p)->edges->beg) # define RANGE_END(p) ((p)->edges->end) #endif diff --git a/src/range.c b/src/range.c index d2f897bd5..2f2521f5e 100644 --- a/src/range.c +++ b/src/range.c @@ -14,20 +14,8 @@ #define RANGE_INITIALIZED(p) ((p)->flags |= RANGE_INITIALIZED_MASK) #define RANGE_INITIALIZED_P(p) ((p)->flags & RANGE_INITIALIZED_MASK) -MRB_API struct RRange* -mrb_range_ptr(mrb_state *mrb, mrb_value range) -{ - struct RRange *r = mrb_range_raw_ptr(range); - - /* check for if #initialize_copy was removed [#3320] */ - if (!RANGE_INITIALIZED_P(r)) { - mrb_raise(mrb, E_ARGUMENT_ERROR, "uninitialized range"); - } - return r; -} - static void -range_check(mrb_state *mrb, mrb_value a, mrb_value b) +r_check(mrb_state *mrb, mrb_value a, mrb_value b) { mrb_value ans; enum mrb_vtype ta; @@ -51,6 +39,43 @@ range_check(mrb_state *mrb, mrb_value a, mrb_value b) } } +static mrb_bool +r_le(mrb_state *mrb, mrb_value a, mrb_value b) +{ + mrb_value r = mrb_funcall(mrb, a, "<=>", 1, b); /* compare result */ + /* output :a < b => -1, a = b => 0, a > b => +1 */ + + if (mrb_fixnum_p(r)) { + mrb_int c = mrb_fixnum(r); + if (c == 0 || c == -1) return TRUE; + } + + return FALSE; +} + +static mrb_bool +r_gt(mrb_state *mrb, mrb_value a, mrb_value b) +{ + mrb_value r = mrb_funcall(mrb, a, "<=>", 1, b); + /* output :a < b => -1, a = b => 0, a > b => +1 */ + + return mrb_fixnum_p(r) && mrb_fixnum(r) == 1; +} + +static mrb_bool +r_ge(mrb_state *mrb, mrb_value a, mrb_value b) +{ + mrb_value r = mrb_funcall(mrb, a, "<=>", 1, b); /* compare result */ + /* output :a < b => -1, a = b => 0, a > b => +1 */ + + if (mrb_fixnum_p(r)) { + mrb_int c = mrb_fixnum(r); + if (c == 0 || c == 1) return TRUE; + } + + return FALSE; +} + static void range_ptr_alloc_edges(mrb_state *mrb, struct RRange *r) { @@ -62,7 +87,7 @@ range_ptr_alloc_edges(mrb_state *mrb, struct RRange *r) static struct RRange * range_ptr_init(mrb_state *mrb, struct RRange *r, mrb_value beg, mrb_value end, mrb_bool excl) { - range_check(mrb, beg, end); + r_check(mrb, beg, end); if (r) { if (RANGE_INITIALIZED_P(r)) { @@ -93,13 +118,6 @@ range_ptr_replace(mrb_state *mrb, struct RRange *r, mrb_value beg, mrb_value end mrb_write_barrier(mrb, (struct RBasic*)r); } -MRB_API mrb_value -mrb_range_new(mrb_state *mrb, mrb_value beg, mrb_value end, mrb_bool excl) -{ - struct RRange *r = range_ptr_init(mrb, NULL, beg, end, excl); - return mrb_range_value(r); -} - /* * call-seq: * rng.first => obj @@ -123,7 +141,6 @@ range_beg(mrb_state *mrb, mrb_value range) * (1..10).end #=> 10 * (1...10).end #=> 10 */ - static mrb_value range_end(mrb_state *mrb, mrb_value range) { @@ -136,8 +153,8 @@ range_end(mrb_state *mrb, mrb_value range) * * Returns true if range excludes its end value. */ -mrb_value -mrb_range_excl(mrb_state *mrb, mrb_value range) +static mrb_value +range_excl(mrb_state *mrb, mrb_value range) { return mrb_bool_value(mrb_range_excl_p(mrb, range)); } @@ -150,21 +167,18 @@ mrb_range_excl(mrb_state *mrb, mrb_value range) * parameter is omitted or is false, the range will include * the end object; otherwise, it will be excluded. */ - -mrb_value -mrb_range_initialize(mrb_state *mrb, mrb_value range) +static mrb_value +range_initialize(mrb_state *mrb, mrb_value range) { mrb_value beg, end; - mrb_bool exclusive; + mrb_bool exclusive = FALSE; mrb_int n; n = mrb_get_args(mrb, "oo|b", &beg, &end, &exclusive); - if (n != 3) { - exclusive = FALSE; - } range_ptr_replace(mrb, mrb_range_raw_ptr(range), beg, end, exclusive); return range; } + /* * call-seq: * range == obj => true or false @@ -177,11 +191,9 @@ mrb_range_initialize(mrb_state *mrb, mrb_value range) * (0..2) == (0..2) #=> true * (0..2) == Range.new(0,2) #=> true * (0..2) == (0...2) #=> false - * */ - -mrb_value -mrb_range_eq(mrb_state *mrb, mrb_value range) +static mrb_value +range_eq(mrb_state *mrb, mrb_value range) { struct RRange *rr; struct RRange *ro; @@ -204,52 +216,14 @@ mrb_range_eq(mrb_state *mrb, mrb_value range) return mrb_true_value(); } -static mrb_bool -r_le(mrb_state *mrb, mrb_value a, mrb_value b) -{ - mrb_value r = mrb_funcall(mrb, a, "<=>", 1, b); /* compare result */ - /* output :a < b => -1, a = b => 0, a > b => +1 */ - - if (mrb_fixnum_p(r)) { - mrb_int c = mrb_fixnum(r); - if (c == 0 || c == -1) return TRUE; - } - - return FALSE; -} - -static mrb_bool -r_gt(mrb_state *mrb, mrb_value a, mrb_value b) -{ - mrb_value r = mrb_funcall(mrb, a, "<=>", 1, b); - /* output :a < b => -1, a = b => 0, a > b => +1 */ - - return mrb_fixnum_p(r) && mrb_fixnum(r) == 1; -} - -static mrb_bool -r_ge(mrb_state *mrb, mrb_value a, mrb_value b) -{ - mrb_value r = mrb_funcall(mrb, a, "<=>", 1, b); /* compare result */ - /* output :a < b => -1, a = b => 0, a > b => +1 */ - - if (mrb_fixnum_p(r)) { - mrb_int c = mrb_fixnum(r); - if (c == 0 || c == 1) return TRUE; - } - - return FALSE; -} - /* * call-seq: * range === obj => true or false * range.member?(val) => true or false * range.include?(val) => true or false - * */ -mrb_value -mrb_range_include(mrb_state *mrb, mrb_value range) +static mrb_value +range_include(mrb_state *mrb, mrb_value range) { mrb_value val; struct RRange *r = mrb_range_ptr(mrb, range); @@ -267,39 +241,6 @@ mrb_range_include(mrb_state *mrb, mrb_value range) return mrb_bool_value(include_p); } -MRB_API mrb_int -mrb_range_beg_len(mrb_state *mrb, mrb_value range, mrb_int *begp, mrb_int *lenp, mrb_int len, mrb_bool trunc) -{ - mrb_int beg, end; - struct RRange *r; - - if (mrb_type(range) != MRB_TT_RANGE) return 0; - r = mrb_range_ptr(mrb, range); - - beg = mrb_int(mrb, RANGE_BEG(r)); - end = mrb_int(mrb, RANGE_END(r)); - - if (beg < 0) { - beg += len; - if (beg < 0) return 2; - } - - if (trunc) { - if (beg > len) return 2; - if (end > len) end = len; - } - - if (end < 0) end += len; - if (!RANGE_EXCL(r) && (!trunc || end < len)) - end++; /* include end point */ - len = end - beg; - if (len < 0) len = 0; - - *begp = beg; - *lenp = len; - return 1; -} - /* 15.2.14.4.12(x) */ /* * call-seq: @@ -307,7 +248,6 @@ mrb_range_beg_len(mrb_state *mrb, mrb_value range, mrb_int *begp, mrb_int *lenp, * * Convert this range object to a printable form. */ - static mrb_value range_to_s(mrb_state *mrb, mrb_value range) { @@ -332,7 +272,6 @@ range_to_s(mrb_state *mrb, mrb_value range) * inspect to convert the start and end * objects). */ - static mrb_value range_inspect(mrb_state *mrb, mrb_value range) { @@ -360,9 +299,7 @@ range_inspect(mrb_state *mrb, mrb_value range) * (0..2).eql?(0..2) #=> true * (0..2).eql?(Range.new(0,2)) #=> true * (0..2).eql?(0...2) #=> false - * */ - static mrb_value range_eql(mrb_state *mrb, mrb_value range) { @@ -372,9 +309,7 @@ range_eql(mrb_state *mrb, mrb_value range) mrb_get_args(mrb, "o", &obj); if (mrb_obj_equal(mrb, range, obj)) return mrb_true_value(); - if (!mrb_obj_is_kind_of(mrb, obj, mrb->range_class)) { - return mrb_false_value(); - } + if (!mrb_obj_is_kind_of(mrb, obj, mrb->range_class)) return mrb_false_value(); if (mrb_type(obj) != MRB_TT_RANGE) return mrb_false_value(); r = mrb_range_ptr(mrb, range); @@ -445,6 +380,57 @@ mrb_gc_mark_range(mrb_state *mrb, struct RRange *r) } } +MRB_API struct RRange* +mrb_range_ptr(mrb_state *mrb, mrb_value range) +{ + struct RRange *r = mrb_range_raw_ptr(range); + + /* check for if #initialize_copy was removed [#3320] */ + if (!RANGE_INITIALIZED_P(r)) { + mrb_raise(mrb, E_ARGUMENT_ERROR, "uninitialized range"); + } + return r; +} + +MRB_API mrb_value +mrb_range_new(mrb_state *mrb, mrb_value beg, mrb_value end, mrb_bool excl) +{ + struct RRange *r = range_ptr_init(mrb, NULL, beg, end, excl); + return mrb_range_value(r); +} + +MRB_API mrb_int +mrb_range_beg_len(mrb_state *mrb, mrb_value range, mrb_int *begp, mrb_int *lenp, mrb_int len, mrb_bool trunc) +{ + mrb_int beg, end; + struct RRange *r; + + if (mrb_type(range) != MRB_TT_RANGE) return 0; + r = mrb_range_ptr(mrb, range); + + beg = mrb_int(mrb, RANGE_BEG(r)); + end = mrb_int(mrb, RANGE_END(r)); + + if (beg < 0) { + beg += len; + if (beg < 0) return 2; + } + + if (trunc) { + if (beg > len) return 2; + if (end > len) end = len; + } + + if (end < 0) end += len; + if (!RANGE_EXCL(r) && (!trunc || end < len)) end++; /* include end point */ + len = end - beg; + if (len < 0) len = 0; + + *begp = beg; + *lenp = len; + return 1; +} + void mrb_init_range(mrb_state *mrb) { @@ -456,15 +442,14 @@ mrb_init_range(mrb_state *mrb) mrb_define_method(mrb, r, "begin", range_beg, MRB_ARGS_NONE()); /* 15.2.14.4.3 */ mrb_define_method(mrb, r, "end", range_end, MRB_ARGS_NONE()); /* 15.2.14.4.5 */ - mrb_define_method(mrb, r, "==", mrb_range_eq, MRB_ARGS_REQ(1)); /* 15.2.14.4.1 */ - mrb_define_method(mrb, r, "===", mrb_range_include, MRB_ARGS_REQ(1)); /* 15.2.14.4.2 */ - mrb_define_method(mrb, r, "exclude_end?", mrb_range_excl, MRB_ARGS_NONE()); /* 15.2.14.4.6 */ + mrb_define_method(mrb, r, "==", range_eq, MRB_ARGS_REQ(1)); /* 15.2.14.4.1 */ + mrb_define_method(mrb, r, "===", range_include, MRB_ARGS_REQ(1)); /* 15.2.14.4.2 */ + mrb_define_method(mrb, r, "exclude_end?", range_excl, MRB_ARGS_NONE()); /* 15.2.14.4.6 */ mrb_define_method(mrb, r, "first", range_beg, MRB_ARGS_NONE()); /* 15.2.14.4.7 */ - mrb_define_method(mrb, r, "include?", mrb_range_include, MRB_ARGS_REQ(1)); /* 15.2.14.4.8 */ - mrb_define_method(mrb, r, "initialize", mrb_range_initialize, MRB_ARGS_ANY()); /* 15.2.14.4.9 */ + mrb_define_method(mrb, r, "include?", range_include, MRB_ARGS_REQ(1)); /* 15.2.14.4.8 */ + mrb_define_method(mrb, r, "initialize", range_initialize, MRB_ARGS_ANY()); /* 15.2.14.4.9 */ mrb_define_method(mrb, r, "last", range_end, MRB_ARGS_NONE()); /* 15.2.14.4.10 */ - mrb_define_method(mrb, r, "member?", mrb_range_include, MRB_ARGS_REQ(1)); /* 15.2.14.4.11 */ - + mrb_define_method(mrb, r, "member?", range_include, MRB_ARGS_REQ(1)); /* 15.2.14.4.11 */ mrb_define_method(mrb, r, "to_s", range_to_s, MRB_ARGS_NONE()); /* 15.2.14.4.12(x) */ mrb_define_method(mrb, r, "inspect", range_inspect, MRB_ARGS_NONE()); /* 15.2.14.4.13(x) */ mrb_define_method(mrb, r, "eql?", range_eql, MRB_ARGS_REQ(1)); /* 15.2.14.4.14(x) */ -- cgit v1.2.3 From 53d87c59c077238be261aad98ed720aebf6402d1 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Fri, 4 Jan 2019 14:40:58 +0900 Subject: Remove unused local variable `n` in `range_initialize`; #4213 --- src/range.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/range.c b/src/range.c index 2f2521f5e..21771c8ec 100644 --- a/src/range.c +++ b/src/range.c @@ -172,9 +172,8 @@ range_initialize(mrb_state *mrb, mrb_value range) { mrb_value beg, end; mrb_bool exclusive = FALSE; - mrb_int n; - n = mrb_get_args(mrb, "oo|b", &beg, &end, &exclusive); + mrb_get_args(mrb, "oo|b", &beg, &end, &exclusive); range_ptr_replace(mrb, mrb_range_raw_ptr(range), beg, end, exclusive); return range; } -- cgit v1.2.3 From 1c574b065d09d37da0673a9e0289e2e018413a80 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Fri, 4 Jan 2019 14:46:17 +0900 Subject: Remove `mrb_` prefix from static functions in `mruby-range-ext`; #4213 --- mrbgems/mruby-range-ext/src/range.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/mrbgems/mruby-range-ext/src/range.c b/mrbgems/mruby-range-ext/src/range.c index 1fc383755..1f6690904 100644 --- a/mrbgems/mruby-range-ext/src/range.c +++ b/mrbgems/mruby-range-ext/src/range.c @@ -40,7 +40,7 @@ r_lt(mrb_state *mrb, mrb_value a, mrb_value b) * ("a".."z").cover?("cc") #=> true */ static mrb_value -mrb_range_cover(mrb_state *mrb, mrb_value range) +range_cover(mrb_state *mrb, mrb_value range) { mrb_value val; struct RRange *r = mrb_range_ptr(mrb, range); @@ -82,7 +82,7 @@ mrb_range_cover(mrb_state *mrb, mrb_value range) * (10...20).last(3) #=> [17, 18, 19] */ static mrb_value -mrb_range_last(mrb_state *mrb, mrb_value range) +range_last(mrb_state *mrb, mrb_value range) { mrb_value num; mrb_value array; @@ -107,7 +107,7 @@ mrb_range_last(mrb_state *mrb, mrb_value range) */ static mrb_value -mrb_range_size(mrb_state *mrb, mrb_value range) +range_size(mrb_state *mrb, mrb_value range) { struct RRange *r = mrb_range_ptr(mrb, range); mrb_value beg, end; @@ -164,9 +164,9 @@ mrb_mruby_range_ext_gem_init(mrb_state* mrb) { struct RClass * s = mrb_class_get(mrb, "Range"); - mrb_define_method(mrb, s, "cover?", mrb_range_cover, MRB_ARGS_REQ(1)); - mrb_define_method(mrb, s, "last", mrb_range_last, MRB_ARGS_OPT(1)); - mrb_define_method(mrb, s, "size", mrb_range_size, MRB_ARGS_NONE()); + mrb_define_method(mrb, s, "cover?", range_cover, MRB_ARGS_REQ(1)); + mrb_define_method(mrb, s, "last", range_last, MRB_ARGS_OPT(1)); + mrb_define_method(mrb, s, "size", range_size, MRB_ARGS_NONE()); } void -- cgit v1.2.3 From b30ca87bd07a29a2dddc4960ce80f767ff9552ca Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Fri, 4 Jan 2019 20:31:05 +0900 Subject: Integrate mrblib/float.rb into src/numeric.c - Avoid hack for `MRB_WITHOUT_FLOAT` in build scripts - Avoid runtime dispatch for `MRB_WITHOUT_FLOAT` --- mrblib/float.rb | 9 --------- mrblib/mrblib.rake | 3 --- src/numeric.c | 7 +++++-- 3 files changed, 5 insertions(+), 14 deletions(-) delete mode 100644 mrblib/float.rb diff --git a/mrblib/float.rb b/mrblib/float.rb deleted file mode 100644 index 421b8d851..000000000 --- a/mrblib/float.rb +++ /dev/null @@ -1,9 +0,0 @@ -## -# Float -# -# ISO 15.2.9 -class Float - # mruby special - since mruby integers may be upgraded to floats, - # floats should be compatible to integers. - include Integral -end if Object.const_defined?(:Float) diff --git a/mrblib/mrblib.rake b/mrblib/mrblib.rake index 6895d4252..e96decb27 100644 --- a/mrblib/mrblib.rake +++ b/mrblib/mrblib.rake @@ -8,9 +8,6 @@ MRuby.each_target do file objfile("#{current_build_dir}/mrblib") => "#{current_build_dir}/mrblib.c" file "#{current_build_dir}/mrblib.c" => [mrbcfile, __FILE__] + Dir.glob("#{current_dir}/*.rb").sort do |t| _, _, *rbfiles = t.prerequisites - if self.cc.defines.flatten.include?("MRB_WITHOUT_FLOAT") - rbfiles.delete("#{current_dir}/float.rb") - end FileUtils.mkdir_p File.dirname(t.name) open(t.name, 'w') do |f| _pp "GEN", "*.rb", "#{t.name.relative_path}" diff --git a/src/numeric.c b/src/numeric.c index 077ae30aa..311bb4a38 100644 --- a/src/numeric.c +++ b/src/numeric.c @@ -1487,11 +1487,13 @@ flo_plus(mrb_state *mrb, mrb_value x) void mrb_init_numeric(mrb_state *mrb) { - struct RClass *numeric, *integer, *fixnum; + struct RClass *numeric, *integer, *fixnum, *integral; #ifndef MRB_WITHOUT_FLOAT struct RClass *fl; #endif + integral = mrb_define_module(mrb, "Integral"); + /* Numeric Class */ numeric = mrb_define_class(mrb, "Numeric", mrb->object_class); /* 15.2.7 */ @@ -1578,6 +1580,7 @@ mrb_init_numeric(mrb_state *mrb) #ifdef NAN mrb_define_const(mrb, fl, "NAN", mrb_float_value(mrb, NAN)); #endif + + mrb_include_module(mrb, fl, integral); #endif - mrb_define_module(mrb, "Integral"); } -- cgit v1.2.3 From 6f395a58d2a1f2e5fdfaf2933ee2e80d10abfd30 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Sat, 5 Jan 2019 20:41:09 +0900 Subject: Add `assert_same` and `assert_not_same` --- test/assert.rb | 26 ++++++++++++++++++++++++++ test/t/proc.rb | 2 +- test/t/string.rb | 2 +- 3 files changed, 28 insertions(+), 2 deletions(-) diff --git a/test/assert.rb b/test/assert.rb index 89d3a7969..196e71d39 100644 --- a/test/assert.rb +++ b/test/assert.rb @@ -124,6 +124,32 @@ def assert_not_equal(arg1, arg2 = nil, arg3 = nil) assert_false(exp == act, msg, diff) end +def assert_same(arg1, arg2 = nil, arg3 = nil) + if block_given? + exp, act, msg = arg1, yield, arg2 + else + exp, act, msg = arg1, arg2, arg3 + end + + msg ||= "Expected #{act.inspect} to be the same object as #{exp.inspect}" + diff = " Expected: #{exp.inspect} (class=#{exp.class}, oid=#{exp.__id__})\n" + + " Actual: #{act.inspect} (class=#{act.class}, oid=#{act.__id__})" + assert_true(exp.equal?(act), msg, diff) +end + +def assert_not_same(arg1, arg2 = nil, arg3 = nil) + if block_given? + exp, act, msg = arg1, yield, arg2 + else + exp, act, msg = arg1, arg2, arg3 + end + + msg ||= "Expected #{act.inspect} to not be the same object as #{exp.inspect}" + diff = " Expected: #{exp.inspect} (class=#{exp.class}, oid=#{exp.__id__})\n" + + " Actual: #{act.inspect} (class=#{act.class}, oid=#{act.__id__})" + assert_false(exp.equal?(act), msg, diff) +end + def assert_nil(obj, msg = nil) msg = "Expected #{obj.inspect} to be nil" unless msg diff = assertion_diff(nil, obj) diff --git a/test/t/proc.rb b/test/t/proc.rb index 42ac3b941..b17b21e8c 100644 --- a/test/t/proc.rb +++ b/test/t/proc.rb @@ -157,7 +157,7 @@ assert('&obj call to_proc if defined') do def mock(&b) b end - assert_equal pr.object_id, mock(&pr).object_id + assert_same pr, mock(&pr) assert_equal pr, mock(&pr) obj = Object.new diff --git a/test/t/string.rb b/test/t/string.rb index 8f008c6a7..e0f0eb99c 100644 --- a/test/t/string.rb +++ b/test/t/string.rb @@ -579,7 +579,7 @@ assert('String#sub', '15.2.10.5.36') do str = "abc" miss = str.sub("X", "Z") assert_equal str, miss - assert_not_equal str.object_id, miss.object_id + assert_not_same str, miss a = [] assert_equal '.abc', "abc".sub("") { |i| a << i; "." } -- cgit v1.2.3 From c8f904b7f5f53482293815822cebe7d5ac4247c1 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Sun, 6 Jan 2019 23:05:13 +0900 Subject: Fix 0.0 and -0.0 handling. Fix the following issue: Good: $ bin/mruby -e 'p(-0.0)' #=> "-0" Bad: $ bin/mruby -e 'a=0.0; p(-0.0)' #=> "0" --- mrbgems/mruby-compiler/core/codegen.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/mrbgems/mruby-compiler/core/codegen.c b/mrbgems/mruby-compiler/core/codegen.c index b3659863b..a17272ba7 100644 --- a/mrbgems/mruby-compiler/core/codegen.c +++ b/mrbgems/mruby-compiler/core/codegen.c @@ -8,6 +8,7 @@ #include #include #include +#include #include #include #include @@ -566,9 +567,12 @@ new_lit(codegen_scope *s, mrb_value val) #ifndef MRB_WITHOUT_FLOAT case MRB_TT_FLOAT: for (i=0; iirep->plen; i++) { + mrb_float f1, f2; pv = &s->irep->pool[i]; if (mrb_type(*pv) != MRB_TT_FLOAT) continue; - if (mrb_float(*pv) == mrb_float(val)) return i; + f1 = mrb_float(*pv); + f2 = mrb_float(val); + if (f1 == f2 && !signbit(f1) == !signbit(f2)) return i; } break; #endif -- cgit v1.2.3 From 3e7a3a0a1533586fc11907dfc82cb70b89b7533b Mon Sep 17 00:00:00 2001 From: take-cheeze Date: Tue, 8 Jan 2019 20:26:39 +0900 Subject: Export Time creation API --- mrbgems/mruby-time/include/mruby/time.h | 25 +++++++++++++++++++++++++ mrbgems/mruby-time/src/time.c | 18 +++++++++--------- 2 files changed, 34 insertions(+), 9 deletions(-) create mode 100644 mrbgems/mruby-time/include/mruby/time.h diff --git a/mrbgems/mruby-time/include/mruby/time.h b/mrbgems/mruby-time/include/mruby/time.h new file mode 100644 index 000000000..d71f4ccd3 --- /dev/null +++ b/mrbgems/mruby-time/include/mruby/time.h @@ -0,0 +1,25 @@ +/* +** mruby/time.h - Time class +** +** See Copyright Notice in mruby.h +*/ + +#ifndef MRUBY_TIME_H +#define MRUBY_TIME_H + +#include "mruby/common.h" + +MRB_BEGIN_DECL + +typedef enum mrb_timezone { + MRB_TIMEZONE_NONE = 0, + MRB_TIMEZONE_UTC = 1, + MRB_TIMEZONE_LOCAL = 2, + MRB_TIMEZONE_LAST = 3 +} mrb_timezone; + +MRB_API mrb_value mrb_time_at(mrb_state *mrb, double sec, double usec, mrb_timezone timezone); + +MRB_END_DECL + +#endif /* MRUBY_TIME_H */ diff --git a/mrbgems/mruby-time/src/time.c b/mrbgems/mruby-time/src/time.c index 2f79617ac..c3a0ac435 100644 --- a/mrbgems/mruby-time/src/time.c +++ b/mrbgems/mruby-time/src/time.c @@ -9,6 +9,7 @@ #include #include #include +#include #ifndef MRB_DISABLE_STDIO #include @@ -166,13 +167,6 @@ timegm(struct tm *tm) * second level. Also, there are only 2 timezones, namely UTC and LOCAL. */ -enum mrb_timezone { - MRB_TIMEZONE_NONE = 0, - MRB_TIMEZONE_UTC = 1, - MRB_TIMEZONE_LOCAL = 2, - MRB_TIMEZONE_LAST = 3 -}; - typedef struct mrb_timezone_name { const char name[8]; size_t len; @@ -343,10 +337,16 @@ mrb_time_now(mrb_state *mrb, mrb_value self) return mrb_time_wrap(mrb, mrb_class_ptr(self), current_mrb_time(mrb)); } +MRB_API mrb_value +mrb_time_at(mrb_state *mrb, double sec, double usec, enum mrb_timezone zone) +{ + return mrb_time_make(mrb, mrb_class_get(mrb, "Time"), sec, usec, zone); +} + /* 15.2.19.6.1 */ /* Creates an instance of time at the given time in seconds, etc. */ static mrb_value -mrb_time_at(mrb_state *mrb, mrb_value self) +mrb_time_at_m(mrb_state *mrb, mrb_value self) { mrb_float f, f2 = 0; @@ -830,7 +830,7 @@ mrb_mruby_time_gem_init(mrb_state* mrb) tc = mrb_define_class(mrb, "Time", mrb->object_class); MRB_SET_INSTANCE_TT(tc, MRB_TT_DATA); mrb_include_module(mrb, tc, mrb_module_get(mrb, "Comparable")); - mrb_define_class_method(mrb, tc, "at", mrb_time_at, MRB_ARGS_ARG(1, 1)); /* 15.2.19.6.1 */ + mrb_define_class_method(mrb, tc, "at", mrb_time_at_m, MRB_ARGS_ARG(1, 1)); /* 15.2.19.6.1 */ mrb_define_class_method(mrb, tc, "gm", mrb_time_gm, MRB_ARGS_ARG(1,6)); /* 15.2.19.6.2 */ mrb_define_class_method(mrb, tc, "local", mrb_time_local, MRB_ARGS_ARG(1,6)); /* 15.2.19.6.3 */ mrb_define_class_method(mrb, tc, "mktime", mrb_time_local, MRB_ARGS_ARG(1,6));/* 15.2.19.6.4 */ -- cgit v1.2.3 From 68735d12614ef72b620736a5cd3052fb79445483 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Tue, 8 Jan 2019 20:31:29 +0900 Subject: Fix dump/load float leteral evaluate to infinity Example: # example.rb p(2e308) p(-2e308) Good: $ bin/mruby example.rb inf -inf Bad: $ bin/mrbc example.rb $ bin/mruby -b example.mrb 0 -0 Cause: Float infinity representation is `inf` on dump and it is converted by corresponding `String#to_f` on load. Treatment: - Introduce new representations (`i`: +infinity, `I`: -infinity) - Allow old representations (`inf`, `-inf`, `infinity`, `-infinity`) too - Raise error for unknown representations (use corresponding `Kernel#Float`) --- mrbgems/mruby-bin-mruby/bintest/mruby.rb | 7 +++++++ src/dump.c | 17 +++++++++++++++-- src/load.c | 20 +++++++++++++++++++- 3 files changed, 41 insertions(+), 3 deletions(-) diff --git a/mrbgems/mruby-bin-mruby/bintest/mruby.rb b/mrbgems/mruby-bin-mruby/bintest/mruby.rb index a7fb63fa2..f3c7d8761 100644 --- a/mrbgems/mruby-bin-mruby/bintest/mruby.rb +++ b/mrbgems/mruby-bin-mruby/bintest/mruby.rb @@ -31,6 +31,13 @@ assert '$0 value' do assert_equal '"-e"', `#{cmd('mruby')} -e #{shellquote('p $0')}`.chomp end +assert('float literal') do + script, bin = Tempfile.new('test.rb'), Tempfile.new('test.mrb') + File.write script.path, 'p [3.21, 2e308.infinite?, -2e308.infinite?]' + system "#{cmd('mrbc')} -g -o #{bin.path} #{script.path}" + assert_equal "[3.21, 1, -1]", `#{cmd('mruby')} -b #{bin.path}`.chomp! +end + assert '__END__', '8.6' do script = Tempfile.new('test.rb') diff --git a/src/dump.c b/src/dump.c index 6ce9c4eb9..11eba4e40 100644 --- a/src/dump.c +++ b/src/dump.c @@ -6,6 +6,7 @@ #include #include +#include #include #include #include @@ -90,6 +91,18 @@ write_iseq_block(mrb_state *mrb, mrb_irep *irep, uint8_t *buf, uint8_t flags) return cur - buf; } +#ifndef MRB_WITHOUT_FLOAT +static mrb_value +float_to_str(mrb_state *mrb, mrb_value flt) +{ + mrb_float f = mrb_float(flt); + + if (isinf(f)) { + return f < 0 ? mrb_str_new_lit(mrb, "I") : mrb_str_new_lit(mrb, "i"); + } + return mrb_float_to_str(mrb, flt, MRB_FLOAT_FMT); +} +#endif static size_t get_pool_block_size(mrb_state *mrb, mrb_irep *irep) @@ -116,7 +129,7 @@ get_pool_block_size(mrb_state *mrb, mrb_irep *irep) #ifndef MRB_WITHOUT_FLOAT case MRB_TT_FLOAT: - str = mrb_float_to_str(mrb, irep->pool[pool_no], MRB_FLOAT_FMT); + str = float_to_str(mrb, irep->pool[pool_no]); { mrb_int len = RSTRING_LEN(str); mrb_assert_int_fit(mrb_int, len, size_t, SIZE_MAX); @@ -165,7 +178,7 @@ write_pool_block(mrb_state *mrb, mrb_irep *irep, uint8_t *buf) #ifndef MRB_WITHOUT_FLOAT case MRB_TT_FLOAT: cur += uint8_to_bin(IREP_TT_FLOAT, cur); /* data type */ - str = mrb_float_to_str(mrb, irep->pool[pool_no], MRB_FLOAT_FMT); + str = float_to_str(mrb, irep->pool[pool_no]); break; #endif diff --git a/src/load.c b/src/load.c index 559fff1d4..55e0845f3 100644 --- a/src/load.c +++ b/src/load.c @@ -7,6 +7,7 @@ #include #include #include +#include #include #include #include @@ -40,6 +41,23 @@ offset_crc_body(void) return ((uint8_t *)header.binary_crc - (uint8_t *)&header) + sizeof(header.binary_crc); } +#ifndef MRB_WITHOUT_FLOAT +static double +str_to_double(mrb_state *mrb, mrb_value str) +{ + const char *p = RSTRING_PTR(str); + mrb_int len = RSTRING_LEN(str); + + /* `i`, `inf`, `infinity` */ + if (len > 0 && p[0] == 'i') return INFINITY; + + /* `I`, `-inf`, `-infinity` */ + if (p[0] == 'I' || (len > 1 && p[0] == '-' && p[1] == 'i')) return -INFINITY; + + return mrb_str_to_dbl(mrb, str, TRUE); +} +#endif + static mrb_irep* read_irep_record_1(mrb_state *mrb, const uint8_t *bin, size_t *len, uint8_t flags) { @@ -125,7 +143,7 @@ read_irep_record_1(mrb_state *mrb, const uint8_t *bin, size_t *len, uint8_t flag #ifndef MRB_WITHOUT_FLOAT case IREP_TT_FLOAT: - irep->pool[i] = mrb_float_pool(mrb, mrb_str_to_dbl(mrb, s, FALSE)); + irep->pool[i] = mrb_float_pool(mrb, str_to_double(mrb, s)); break; #endif -- cgit v1.2.3 From d38a8e8807578e1091d94b8087d26f8d9783a2e6 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Mon, 7 Jan 2019 17:34:19 +0900 Subject: Update `OP_APOST` description (typo fixed). --- include/mruby/ops.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/mruby/ops.h b/include/mruby/ops.h index 7531a5ee2..d64594625 100644 --- a/include/mruby/ops.h +++ b/include/mruby/ops.h @@ -88,7 +88,7 @@ OPCODE(ARYPUSH, B) /* ary_push(R(a),R(a+1)) */ OPCODE(ARYDUP, B) /* R(a) = ary_dup(R(a)) */ OPCODE(AREF, BBB) /* R(a) = R(b)[c] */ OPCODE(ASET, BBB) /* R(a)[c] = R(b) */ -OPCODE(APOST, BBB) /* *R(a),R(a+1)..R(a+C) = R(a)[b..] */ +OPCODE(APOST, BBB) /* *R(a),R(a+1)..R(a+c) = R(a)[b..] */ OPCODE(INTERN, B) /* R(a) = intern(R(a)) */ OPCODE(STRING, BB) /* R(a) = str_dup(Lit(b)) */ OPCODE(STRCAT, B) /* str_cat(R(a),R(a+1)) */ -- cgit v1.2.3 From 81862fd689372dc31a0f0e71995e4cd6f771aea6 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Tue, 8 Jan 2019 21:44:40 +0900 Subject: Update compiled binary format version; ref #4219 --- include/mruby/dump.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/mruby/dump.h b/include/mruby/dump.h index bff838484..0234a362b 100644 --- a/include/mruby/dump.h +++ b/include/mruby/dump.h @@ -52,7 +52,7 @@ MRB_API mrb_irep *mrb_read_irep(mrb_state*, const uint8_t*); /* Rite Binary File header */ #define RITE_BINARY_IDENT "RITE" #define RITE_BINARY_IDENT_LIL "ETIR" -#define RITE_BINARY_FORMAT_VER "0005" +#define RITE_BINARY_FORMAT_VER "0006" #define RITE_COMPILER_NAME "MATZ" #define RITE_COMPILER_VERSION "0000" -- cgit v1.2.3 From d88d7aaf4b3c994d5f1e8903fb4b14752981f721 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Wed, 9 Jan 2019 13:04:23 +0900 Subject: Use `$mrbtest_io_wfname` for `chmod` test. --- mrbgems/mruby-io/test/file.rb | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/mrbgems/mruby-io/test/file.rb b/mrbgems/mruby-io/test/file.rb index ca285f5bd..8d2be04c8 100644 --- a/mrbgems/mruby-io/test/file.rb +++ b/mrbgems/mruby-io/test/file.rb @@ -200,11 +200,11 @@ assert('File.symlink') do end assert('File.chmod') do - File.open('chmod-test', 'w') {} + File.open("#{$mrbtest_io_wfname}.chmod-test", 'w') {} begin - assert_equal 1, File.chmod(0400, 'chmod-test') + assert_equal 1, File.chmod(0400, "#{$mrbtest_io_wfname}.chmod-test") ensure - File.delete('chmod-test') + File.delete("#{$mrbtest_io_wfname}.chmod-test") end end -- cgit v1.2.3 From 0740595f857d7c4a7420e7b6a68f307802561a1b Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Wed, 9 Jan 2019 20:00:17 +0900 Subject: Change the order of "expected" and "actual" in test --- mrbgems/mruby-bin-mruby/bintest/mruby.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mrbgems/mruby-bin-mruby/bintest/mruby.rb b/mrbgems/mruby-bin-mruby/bintest/mruby.rb index f3c7d8761..e8d1510f7 100644 --- a/mrbgems/mruby-bin-mruby/bintest/mruby.rb +++ b/mrbgems/mruby-bin-mruby/bintest/mruby.rb @@ -12,7 +12,7 @@ assert('regression for #1572') do File.write script.path, 'p "ok"' system "#{cmd('mrbc')} -g -o #{bin.path} #{script.path}" o = `#{cmd('mruby')} -b #{bin.path}`.strip - assert_equal o, '"ok"' + assert_equal '"ok"', o end assert '$0 value' do -- cgit v1.2.3 From 856b8d961015d67eb7b4958eb974bbfabbc1066a Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Thu, 10 Jan 2019 23:22:23 +0900 Subject: Remove duplicate code in numeric.c --- src/numeric.c | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/src/numeric.c b/src/numeric.c index 311bb4a38..089cc744d 100644 --- a/src/numeric.c +++ b/src/numeric.c @@ -1150,7 +1150,7 @@ fix_to_f(mrb_state *mrb, mrb_value num) * (in particular infinite or NaN) * to numerical classes which don't support them. * - * Float::INFINITY.to_r + * Float::INFINITY.to_i * * raises the exception: * @@ -1169,12 +1169,7 @@ mrb_flo_to_fixnum(mrb_state *mrb, mrb_value x) else { mrb_float d = mrb_float(x); - if (isinf(d)) { - mrb_raise(mrb, E_FLOATDOMAIN_ERROR, d < 0 ? "-Infinity" : "Infinity"); - } - if (isnan(d)) { - mrb_raise(mrb, E_FLOATDOMAIN_ERROR, "NaN"); - } + mrb_check_num_exact(mrb, d); if (FIXABLE_FLOAT(d)) { z = (mrb_int)d; } -- cgit v1.2.3 From 2d8aec2b8833065695f7e0fe42f70e0b5610afce Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Fri, 11 Jan 2019 19:54:46 +0900 Subject: Use `%g` instead of `%e` for float representation in dump format `%g` use shorter representation than `%e`. --- src/dump.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/dump.c b/src/dump.c index 11eba4e40..f1e167e35 100644 --- a/src/dump.c +++ b/src/dump.c @@ -18,9 +18,9 @@ #ifndef MRB_WITHOUT_FLOAT #ifdef MRB_USE_FLOAT -#define MRB_FLOAT_FMT "%.8e" +#define MRB_FLOAT_FMT "%.9g" #else -#define MRB_FLOAT_FMT "%.16e" +#define MRB_FLOAT_FMT "%.17g" #endif #endif -- cgit v1.2.3 From 8b951710fe535acf479672691720cf9b80bc5331 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Sat, 12 Jan 2019 22:21:34 +0900 Subject: Use `__send__` instead of `send`; ref #4207 --- test/t/exception.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/t/exception.rb b/test/t/exception.rb index ce7b5841e..bdf277c1e 100644 --- a/test/t/exception.rb +++ b/test/t/exception.rb @@ -263,10 +263,10 @@ assert('Exception 13') do end assert('Exception 14') do - def exception_test14; UnknownConstant; end + def (o = Object.new).exception_test14; UnknownConstant end a = :ng begin - send(:exception_test14) + o.__send__(:exception_test14) rescue a = :ok end -- cgit v1.2.3 From 9f081183d2351195c821fbe1520975ba000cafb5 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Sun, 13 Jan 2019 19:59:22 +0900 Subject: Improve compatibility to CRuby for `Float#to_s` Bfore: Float::INFINITY.to_s #=> "inf" 50.0.to_s #=> "50" 1e20.to_s #=> "1e+20" After / CRuby: Float::INFINITY.to_s #=> "Infinity" 50.0.to_s #=> "50.0" 1e20.to_s #=> "1.0e+20" --- src/numeric.c | 48 ++++++++++++++++++++++++++++++++++++++++++++---- test/t/float.rb | 33 +++++++++++++++++++++++++++++++++ 2 files changed, 77 insertions(+), 4 deletions(-) diff --git a/src/numeric.c b/src/numeric.c index 089cc744d..fc8460300 100644 --- a/src/numeric.c +++ b/src/numeric.c @@ -10,6 +10,7 @@ #endif #include #include +#include #include #include @@ -23,9 +24,9 @@ #define floor(f) floorf(f) #define ceil(f) ceilf(f) #define fmod(x,y) fmodf(x,y) -#define MRB_FLO_TO_STR_FMT "%.8g" +#define FLO_TO_STR_PREC 8 #else -#define MRB_FLO_TO_STR_FMT "%.16g" +#define FLO_TO_STR_PREC 16 #endif #endif @@ -177,10 +178,49 @@ num_div(mrb_state *mrb, mrb_value x) static mrb_value flo_to_s(mrb_state *mrb, mrb_value flt) { - if (isnan(mrb_float(flt))) { + mrb_float f = mrb_float(flt); + + if (isinf(f)) { + return f < 0 ? mrb_str_new_lit(mrb, "-Infinity") + : mrb_str_new_lit(mrb, "Infinity"); + } + else if (isnan(f)) { return mrb_str_new_lit(mrb, "NaN"); } - return mrb_float_to_str(mrb, flt, MRB_FLO_TO_STR_FMT); + else { + char fmt[] = "%." MRB_STRINGIZE(FLO_TO_STR_PREC) "g"; + mrb_value str = mrb_float_to_str(mrb, flt, fmt); + mrb_int len; + char *begp; + + insert_dot_zero: + begp = RSTRING_PTR(str); + len = RSTRING_LEN(str); + for (char *p = begp, *endp = p + len; p < endp; ++p) { + if (*p == '.') { + return str; + } + else if (*p == 'e') { + ptrdiff_t e_pos = p - begp; + mrb_str_cat(mrb, str, ".0", 2); + p = RSTRING_PTR(str) + e_pos; + memmove(p + 2, p, len - e_pos); + memcpy(p, ".0", 2); + return str; + } + } + + if (FLO_TO_STR_PREC + (begp[0] == '-') <= len) { + --fmt[sizeof(fmt) - 3]; /* %.16g(%.8g) -> %.15g(%.7g) */ + str = mrb_float_to_str(mrb, flt, fmt); + goto insert_dot_zero; + } + else { + mrb_str_cat(mrb, str, ".0", 2); + } + + return str; + } } /* 15.2.9.3.2 */ diff --git a/test/t/float.rb b/test/t/float.rb index 68fd31b9a..eac5c5792 100644 --- a/test/t/float.rb +++ b/test/t/float.rb @@ -206,4 +206,37 @@ assert('Float#>>') do assert_equal(-1, -23.0 >> 128) end +assert('Float#to_s') do + uses_float = 4e38.infinite? # enable MRB_USE_FLOAT? + + assert_equal("Infinity", Float::INFINITY.to_s) + assert_equal("-Infinity", (-Float::INFINITY).to_s) + assert_equal("NaN", Float::NAN.to_s) + assert_equal("0.0", 0.0.to_s) + assert_equal("-0.0", -0.0.to_s) + assert_equal("-3.21", -3.21.to_s) + assert_equal("50.0", 50.0.to_s) + assert_equal("0.00021", 0.00021.to_s) + assert_equal("-0.00021", -0.00021.to_s) + assert_equal("2.1e-05", 0.000021.to_s) + assert_equal("-2.1e-05", -0.000021.to_s) + assert_equal("1.0e+20", 1e20.to_s) + assert_equal("-1.0e+20", -1e20.to_s) + assert_equal("1.0e+16", 10000000000000000.0.to_s) + assert_equal("-1.0e+16", -10000000000000000.0.to_s) + assert_equal("100000.0", 100000.0.to_s) + assert_equal("-100000.0", -100000.0.to_s) + if uses_float + assert_equal("1.0e+08", 100000000.0.to_s) + assert_equal("-1.0e+08", -100000000.0.to_s) + assert_equal("1.0e+07", 10000000.0.to_s) + assert_equal("-1.0e+07", -10000000.0.to_s) + else + assert_equal("1.0e+15", 1000000000000000.0.to_s) + assert_equal("-1.0e+15", -1000000000000000.0.to_s) + assert_equal("100000000000000.0", 100000000000000.0.to_s) + assert_equal("-100000000000000.0", -100000000000000.0.to_s) + end +end + end # const_defined?(:Float) -- cgit v1.2.3 From 0e04c46261eb9d5193f21d423f5d00f1910a460a Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Sun, 13 Jan 2019 23:24:57 +0900 Subject: Use 2 digits exponent format for `printf` family on old MSVC For conforming C standard. --- src/state.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/state.c b/src/state.c index 5583a77e5..e678b37f3 100644 --- a/src/state.c +++ b/src/state.c @@ -41,6 +41,10 @@ mrb_open_core(mrb_allocf f, void *ud) mrb_init_core(mrb); +#if !defined(MRB_DISABLE_STDIO) && defined(_MSC_VER) && _MSC_VER < 1900 + _set_output_format(_TWO_DIGIT_EXPONENT); +#endif + return mrb; } -- cgit v1.2.3 From a7c2ef9dab4e5c28120bfb7a9b8fca332129bdde Mon Sep 17 00:00:00 2001 From: dearblue Date: Mon, 14 Jan 2019 15:21:21 +0900 Subject: Fix build failed when set `conf.build_dir=` and `conf.enable_cxx_exception` --- lib/mruby/build.rb | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/lib/mruby/build.rb b/lib/mruby/build.rb index e2d9fc41e..63125d4fa 100644 --- a/lib/mruby/build.rb +++ b/lib/mruby/build.rb @@ -162,8 +162,6 @@ module MRuby end def compile_as_cxx src, cxx_src, obj = nil, includes = [] - src = File.absolute_path src - cxx_src = File.absolute_path cxx_src obj = objfile(cxx_src) if obj.nil? file cxx_src => [src, __FILE__] do |t| @@ -175,7 +173,7 @@ module MRuby #ifndef MRB_ENABLE_CXX_ABI extern "C" { #endif -#include "#{src}" +#include "#{File.absolute_path src}" #ifndef MRB_ENABLE_CXX_ABI } #endif -- cgit v1.2.3 From bb52efd0fc7e5b9c1980a0d0467a9f821c7e1245 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Mon, 14 Jan 2019 21:45:57 +0900 Subject: Ignore compiler temporary files (for `-save-temps` flag) --- .gitignore | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.gitignore b/.gitignore index 9c34b5f29..f4efd8928 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,8 @@ # / *.bak +*.bc *.d +*.i *.o /benchmark/**/*.dat /benchmark/*.pdf @@ -8,6 +10,7 @@ *.orig *.pdb *.rej +*.s *.sav *.swp *.tmp -- cgit v1.2.3 From adfc2d08c96452a9954c2267f103d4acec17718b Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Tue, 15 Jan 2019 19:30:15 +0900 Subject: [ci skip] Sort `.gitignore` --- .gitignore | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/.gitignore b/.gitignore index f4efd8928..400c77386 100644 --- a/.gitignore +++ b/.gitignore @@ -1,12 +1,8 @@ -# / *.bak *.bc *.d *.i *.o -/benchmark/**/*.dat -/benchmark/*.pdf -/benchmark/*.png *.orig *.pdb *.rej @@ -19,13 +15,20 @@ .ccmalloc .svn .vscode -/.git +.yardoc cscope.files cscope.out tags -/src/y.tab.c + +/.git /bin /build /mruby-source-*.gem -doc/api -.yardoc + +/benchmark/**/*.dat +/benchmark/*.pdf +/benchmark/*.png + +/doc/api + +/src/y.tab.c -- cgit v1.2.3 From de5da4b7f6615610ee5935754ae76e71870380aa Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Tue, 15 Jan 2019 21:41:54 +0900 Subject: Fix coercing for first step counter in `Numeric#step` Before: a=[]; 7.step(4, -3.0) { |c| a << c }; p a #=> [7, 4.0] After / Ruby: a=[]; 7.step(4, -3.0) { |c| a << c }; p a #=> [7.0, 4.0] --- mrblib/numeric.rb | 11 +++++++++-- test/t/integer.rb | 16 ---------------- test/t/numeric.rb | 32 ++++++++++++++++++++++++++++++++ 3 files changed, 41 insertions(+), 18 deletions(-) diff --git a/mrblib/numeric.rb b/mrblib/numeric.rb index a2eb9c450..dfdaf9da8 100644 --- a/mrblib/numeric.rb +++ b/mrblib/numeric.rb @@ -104,11 +104,18 @@ module Integral raise ArgumentError, "step can't be 0" if step == 0 return to_enum(:step, num, step) unless block - i = if Object.const_defined?(:Float) && num.kind_of?(Float) then self.to_f else self end + i = self + if Object.const_defined?(:Float) && + (kind_of?(Float) || num.kind_of?(Float) || step.kind_of?(Float)) + i = i.to_f + num = num.to_f unless num == nil + step = step.to_f + end + if num == nil while true block.call(i) - i+=step + i += step end return self end diff --git a/test/t/integer.rb b/test/t/integer.rb index c37641e9f..4ab49eb0a 100644 --- a/test/t/integer.rb +++ b/test/t/integer.rb @@ -257,19 +257,3 @@ assert('Integer#divmod', '15.2.8.3.30') do assert_equal [-2, -1], 25.divmod(-13) assert_equal [ 1, -6], -13.divmod(-7) end - -# Not ISO specified - -assert('Integer#step') do - a = [] - b = [] - 1.step(3) do |i| - a << i - end - 1.step(6, 2) do |i| - b << i - end - - assert_equal [1, 2, 3], a - assert_equal [1, 3, 5], b -end diff --git a/test/t/numeric.rb b/test/t/numeric.rb index 9d6dc22cc..f58194fe5 100644 --- a/test/t/numeric.rb +++ b/test/t/numeric.rb @@ -42,3 +42,35 @@ end assert('Numeric#**') do assert_equal 8.0, 2.0**3 end + +assert('Numeric#step') do + assert_step = ->(exp, receiver, args) do + inf = !args[0] + act = [] + ret = receiver.step(*args) do |i| + act << i + break if inf && exp.size == act.size + end + expr = "#{receiver.inspect}.step(#{args.map(&:inspect).join(', ')})" + msg = "#{expr}: counters" + diff = assertion_diff(exp, act) + assert_true exp.map{|v|[v,v.class]} == act.map{|v|[v,v.class]}, msg, diff + assert_same receiver, ret, "#{expr}: return value" unless inf + end + + assert_raise(ArgumentError) { 1.step(2, 0) { break } } + assert_step.([2, 3, 4], 2, [4]) + assert_step.([10, 8, 6, 4, 2], 10, [1, -2]) + assert_step.([], 2, [1, 3]) + assert_step.([], -2, [-1, -3]) + assert_step.([10, 11, 12, 13], 10, []) + assert_step.([10, 7, 4], 10, [nil, -3]) + + skip unless Object.const_defined?(:Float) + assert_raise(ArgumentError) { 1.step(2, 0.0) { break } } + assert_step.([2.0, 3.0, 4.0], 2, [4.0]) + assert_step.([7.0, 4.0, 1.0, -2.0], 7, [-4, -3.0]) + assert_step.([2.0, 3.0, 4.0], 2.0, [4]) + assert_step.([10.0, 11.0, 12.0, 13.0], 10.0, []) + assert_step.([10.0, 7.0, 4.0], 10, [nil, -3.0]) +end -- cgit v1.2.3 From 8969edf03b2f4ff8537974c2bd30e9abe2002da6 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Wed, 16 Jan 2019 19:32:29 +0900 Subject: Avoid runtime evaluation for `MRB_WITHOUT_FLOAT` --- mrblib/numeric.rb | 9 +-------- src/numeric.c | 17 +++++++++++++++++ 2 files changed, 18 insertions(+), 8 deletions(-) diff --git a/mrblib/numeric.rb b/mrblib/numeric.rb index dfdaf9da8..5a3c5eb58 100644 --- a/mrblib/numeric.rb +++ b/mrblib/numeric.rb @@ -104,14 +104,7 @@ module Integral raise ArgumentError, "step can't be 0" if step == 0 return to_enum(:step, num, step) unless block - i = self - if Object.const_defined?(:Float) && - (kind_of?(Float) || num.kind_of?(Float) || step.kind_of?(Float)) - i = i.to_f - num = num.to_f unless num == nil - step = step.to_f - end - + i = __coerce_step_counter(num, step) if num == nil while true block.call(i) diff --git a/src/numeric.c b/src/numeric.c index fc8460300..fa9daf8a7 100644 --- a/src/numeric.c +++ b/src/numeric.c @@ -154,6 +154,22 @@ num_div(mrb_state *mrb, mrb_value x) #endif } +static mrb_value +num_coerce_step_counter(mrb_state *mrb, mrb_value self) +{ + mrb_value counter = self, num, step; + + mrb_get_args(mrb, "oo", &num, &step); + +#ifndef MRB_WITHOUT_FLOAT + if (mrb_float_p(self) || mrb_float_p(num) || mrb_float_p(step)) { + counter = mrb_funcall(mrb, counter, "to_f", 0); + } +#endif + + return counter; +} + #ifndef MRB_WITHOUT_FLOAT /******************************************************************** * @@ -1542,6 +1558,7 @@ mrb_init_numeric(mrb_state *mrb) mrb_define_method(mrb, numeric, ">=", num_ge, MRB_ARGS_REQ(1)); mrb_define_method(mrb, numeric, "finite?", num_finite_p, MRB_ARGS_NONE()); mrb_define_method(mrb, numeric, "infinite?",num_infinite_p, MRB_ARGS_NONE()); + mrb_define_method(mrb, numeric, "__coerce_step_counter", num_coerce_step_counter, MRB_ARGS_REQ(2)); /* Integer Class */ integer = mrb_define_class(mrb, "Integer", numeric); /* 15.2.8 */ -- cgit v1.2.3 From 366a14f297a6b31301b8e01f5ef21ad8fe184977 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Wed, 16 Jan 2019 23:48:59 +0900 Subject: Remove special treatments for `MRB_WITHOUT_FLOAT` in build scripts --- mrbgems/mruby-test/mrbgem.rake | 4 ---- src/mruby_core.rake | 1 - 2 files changed, 5 deletions(-) diff --git a/mrbgems/mruby-test/mrbgem.rake b/mrbgems/mruby-test/mrbgem.rake index 6f94da92d..61bdf9ced 100644 --- a/mrbgems/mruby-test/mrbgem.rake +++ b/mrbgems/mruby-test/mrbgem.rake @@ -7,10 +7,6 @@ MRuby::Gem::Specification.new('mruby-test') do |spec| spec.add_dependency('mruby-compiler', :core => 'mruby-compiler') spec.test_rbfiles = Dir.glob("#{MRUBY_ROOT}/test/t/*.rb") - if build.cc.defines.flatten.include?("MRB_WITHOUT_FLOAT") - spec.test_rbfiles.delete("#{MRUBY_ROOT}/test/t/float.rb") - end - clib = "#{build_dir}/mrbtest.c" mlib = clib.ext(exts.object) diff --git a/src/mruby_core.rake b/src/mruby_core.rake index 3024c8544..73fddb220 100644 --- a/src/mruby_core.rake +++ b/src/mruby_core.rake @@ -5,7 +5,6 @@ MRuby.each_target do objs = Dir.glob("#{current_dir}/*.c").map { |f| next nil if cxx_exception_enabled? and f =~ /(error|vm).c$/ - next nil if self.cc.defines.flatten.include?("MRB_WITHOUT_FLOAT") and f =~ /fmt_fp.c$/ objfile(f.pathmap("#{current_build_dir}/%n")) }.compact -- cgit v1.2.3 From cfe3654fd12d570c8e6b052d87ea0e8eae0ef9f1 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Thu, 17 Jan 2019 21:16:02 +0900 Subject: Fix assertion name for `Numeric#**` test --- test/t/numeric.rb | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/test/t/numeric.rb b/test/t/numeric.rb index f58194fe5..e22556a7e 100644 --- a/test/t/numeric.rb +++ b/test/t/numeric.rb @@ -19,14 +19,6 @@ assert('Numeric#abs', '15.2.7.4.3') do assert_equal(1.0, -1.abs) end -assert('Numeric#pow') do - assert_equal(8, 2 ** 3) - assert_equal(-8, -2 ** 3) - assert_equal(1, 2 ** 0) - assert_equal(1, 2.2 ** 0) - assert_equal(0.5, 2 ** -1) -end - assert('Numeric#/', '15.2.8.3.4') do n = Class.new(Numeric){ def /(x); 15.1;end }.new @@ -40,7 +32,13 @@ end # Not ISO specified assert('Numeric#**') do - assert_equal 8.0, 2.0**3 + assert_equal(8, 2 ** 3) + assert_equal(-8, -2 ** 3) + assert_equal(1, 2 ** 0) + skip unless Object.const_defined?(:Float) + assert_equal(1.0, 2.2 ** 0) + assert_equal(0.5, 2 ** -1) + assert_equal(8.0, 2.0**3) end assert('Numeric#step') do -- cgit v1.2.3 From 107dc0c7789acfeeed8de8b9d1f78996e0838f99 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Fri, 18 Jan 2019 23:29:35 +0900 Subject: Avoid a side effect when run Rake without execution of tasks Avoid directory creation when run `rake -T` etc. --- Rakefile | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/Rakefile b/Rakefile index 47da28166..6c160a5ed 100644 --- a/Rakefile +++ b/Rakefile @@ -32,20 +32,25 @@ load "#{MRUBY_ROOT}/tasks/benchmark.rake" load "#{MRUBY_ROOT}/tasks/gitlab.rake" +def install_D(src, dst) + opts = { :verbose => $verbose } + FileUtils.rm_f dst, opts + FileUtils.mkdir_p File.dirname(dst), opts + FileUtils.cp src, dst, opts +end + ############################## # generic build targets, rules task :default => :all bin_path = ENV['INSTALL_DIR'] || "#{MRUBY_ROOT}/bin" -FileUtils.mkdir_p bin_path, { :verbose => $verbose } depfiles = MRuby.targets['host'].bins.map do |bin| install_path = MRuby.targets['host'].exefile("#{bin_path}/#{bin}") source_path = MRuby.targets['host'].exefile("#{MRuby.targets['host'].build_dir}/bin/#{bin}") file install_path => source_path do |t| - FileUtils.rm_f t.name, { :verbose => $verbose } - FileUtils.cp t.prerequisites.first, t.name, { :verbose => $verbose } + install_D t.prerequisites.first, t.name end install_path @@ -78,8 +83,7 @@ MRuby.each_target do |target| install_path = MRuby.targets['host'].exefile("#{bin_path}/#{bin}") file install_path => exec do |t| - FileUtils.rm_f t.name, { :verbose => $verbose } - FileUtils.cp t.prerequisites.first, t.name, { :verbose => $verbose } + install_D t.prerequisites.first, t.name end depfiles += [ install_path ] elsif target == MRuby.targets['host-debug'] @@ -87,8 +91,7 @@ MRuby.each_target do |target| install_path = MRuby.targets['host-debug'].exefile("#{bin_path}/#{bin}") file install_path => exec do |t| - FileUtils.rm_f t.name, { :verbose => $verbose } - FileUtils.cp t.prerequisites.first, t.name, { :verbose => $verbose } + install_D t.prerequisites.first, t.name end depfiles += [ install_path ] end -- cgit v1.2.3 From dff0f2ee10c93a12fcc9cea1eb6b2c57667ee5de Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Sat, 19 Jan 2019 20:40:21 +0900 Subject: Remove `.gitkeep` files --- bin/.gitkeep | 0 src/ext/.gitkeep | 0 2 files changed, 0 insertions(+), 0 deletions(-) delete mode 100644 bin/.gitkeep delete mode 100644 src/ext/.gitkeep diff --git a/bin/.gitkeep b/bin/.gitkeep deleted file mode 100644 index e69de29bb..000000000 diff --git a/src/ext/.gitkeep b/src/ext/.gitkeep deleted file mode 100644 index e69de29bb..000000000 -- cgit v1.2.3 From d6d02774c55e294adfebf619ee4ce8298249bb0c Mon Sep 17 00:00:00 2001 From: dearblue Date: Thu, 17 Jan 2019 23:12:21 +0900 Subject: Fix memory leak `sval` when out of memory in `Data_Wrap_Struct()` --- include/mruby/data.h | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/include/mruby/data.h b/include/mruby/data.h index 31d6bd8fb..415684342 100644 --- a/include/mruby/data.h +++ b/include/mruby/data.h @@ -39,10 +39,11 @@ MRB_API struct RData *mrb_data_object_alloc(mrb_state *mrb, struct RClass* klass #define Data_Wrap_Struct(mrb,klass,type,ptr)\ mrb_data_object_alloc(mrb,klass,ptr,type) -#define Data_Make_Struct(mrb,klass,strct,type,sval,data) do { \ +#define Data_Make_Struct(mrb,klass,strct,type,sval,data_obj) do { \ + (data_obj) = Data_Wrap_Struct(mrb,klass,type,NULL);\ (sval) = mrb_malloc(mrb, sizeof(strct)); \ { static const strct zero = { 0 }; *(sval) = zero; };\ - (data) = Data_Wrap_Struct(mrb,klass,type,sval);\ + (data_obj)->data = (sval);\ } while (0) #define RDATA(obj) ((struct RData *)(mrb_ptr(obj))) -- cgit v1.2.3 From 8c22911c861c13cf53510d7e713cb12d042599f3 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Sun, 20 Jan 2019 19:47:58 +0900 Subject: Rename `mruby-bin-mruby-config` mrbgem to `mruby-bin-config` For brevity and consistency (e.g. `mruby-bin-strip` doesn't have `mruby-` after `bin-`). --- mrbgems/mruby-bin-config/mrbgem.rake | 31 ++++++++++++++++++ mrbgems/mruby-bin-config/mruby-config | 20 ++++++++++++ mrbgems/mruby-bin-config/mruby-config.bat | 42 +++++++++++++++++++++++++ mrbgems/mruby-bin-mruby-config/mrbgem.rake | 31 ------------------ mrbgems/mruby-bin-mruby-config/mruby-config | 20 ------------ mrbgems/mruby-bin-mruby-config/mruby-config.bat | 42 ------------------------- 6 files changed, 93 insertions(+), 93 deletions(-) create mode 100644 mrbgems/mruby-bin-config/mrbgem.rake create mode 100644 mrbgems/mruby-bin-config/mruby-config create mode 100644 mrbgems/mruby-bin-config/mruby-config.bat delete mode 100644 mrbgems/mruby-bin-mruby-config/mrbgem.rake delete mode 100644 mrbgems/mruby-bin-mruby-config/mruby-config delete mode 100644 mrbgems/mruby-bin-mruby-config/mruby-config.bat diff --git a/mrbgems/mruby-bin-config/mrbgem.rake b/mrbgems/mruby-bin-config/mrbgem.rake new file mode 100644 index 000000000..cca7423ac --- /dev/null +++ b/mrbgems/mruby-bin-config/mrbgem.rake @@ -0,0 +1,31 @@ +module MRuby + class Build + def exefile(name) + if name.is_a?(Array) + name.flatten.map { |n| exefile(n) } + elsif name !~ /\./ + "#{name}#{exts.executable}" + else + name + end + end + end +end + +MRuby.each_target do + next if kind_of? MRuby::CrossBuild + + mruby_config = 'mruby-config' + (ENV['OS'] == 'Windows_NT' ? '.bat' : '') + mruby_config_path = "#{build_dir}/bin/#{mruby_config}" + @bins << mruby_config + + make_cfg = "#{build_dir}/lib/libmruby.flags.mak" + file mruby_config_path => [libmruby_static, make_cfg] do |t| + FileUtils.copy "#{File.dirname(__FILE__)}/#{mruby_config}", t.name + config = Hash[open(make_cfg).read.split("\n").map {|x| a = x.split(/\s*=\s*/, 2); [a[0], a[1].gsub('\\"', '"') ]}] + IO.write(t.name, File.open(t.name) {|f| + f.read.gsub (/echo (MRUBY_CFLAGS|MRUBY_LIBS|MRUBY_LDFLAGS_BEFORE_LIBS|MRUBY_LDFLAGS|MRUBY_LIBMRUBY_PATH)/) {|x| config[$1].empty? ? '' : "echo #{config[$1]}"} + }) + FileUtils.chmod(0755, t.name) + end +end diff --git a/mrbgems/mruby-bin-config/mruby-config b/mrbgems/mruby-bin-config/mruby-config new file mode 100644 index 000000000..57346c03f --- /dev/null +++ b/mrbgems/mruby-bin-config/mruby-config @@ -0,0 +1,20 @@ +#!/bin/sh + +while [ $# -gt 0 ]; do + case $1 in + --cflags) echo MRUBY_CFLAGS;; + --ldflags) echo MRUBY_LDFLAGS;; + --ldflags-before-libs) echo MRUBY_LDFLAGS_BEFORE_LIBS;; + --libs) echo MRUBY_LIBS;; + --libmruby-path) echo MRUBY_LIBMRUBY_PATH;; + --help) echo "Usage: mruby-config [switches]" + echo " switches:" + echo " --cflags print flags passed to compiler" + echo " --ldflags print flags passed to linker" + echo " --ldflags-before-libs print flags passed to linker before linked libraries" + echo " --libs print linked libraries" + echo " --libmruby-path print libmruby path" + exit 0;; + esac + shift +done diff --git a/mrbgems/mruby-bin-config/mruby-config.bat b/mrbgems/mruby-bin-config/mruby-config.bat new file mode 100644 index 000000000..a1f7bfdd1 --- /dev/null +++ b/mrbgems/mruby-bin-config/mruby-config.bat @@ -0,0 +1,42 @@ +@echo off + +:top +shift +if "%0" equ "" goto :eof +if "%0" equ "--cflags" goto cflags +if "%0" equ "--ldflags" goto ldflags +if "%0" equ "--ldflags-before-libs" goto ldflagsbeforelibs +if "%0" equ "--libs" goto libs +if "%0" equ "--libmruby-path" goto libmrubypath +if "%0" equ "--help" goto showhelp +echo Invalid Option +goto :eof + +:cflags +echo MRUBY_CFLAGS +goto top + +:libs +echo MRUBY_LIBS +goto top + +:ldflags +echo MRUBY_LDFLAGS +goto top + +:ldflagsbeforelibs +echo MRUBY_LDFLAGS_BEFORE_LIBS +goto top + +:libmrubypath +echo MRUBY_LIBMRUBY_PATH +goto top + +:showhelp +echo Usage: mruby-config [switches] +echo switches: +echo --cflags print flags passed to compiler +echo --ldflags print flags passed to linker +echo --ldflags-before-libs print flags passed to linker before linked libraries +echo --libs print linked libraries +echo --libmruby-path print libmruby path diff --git a/mrbgems/mruby-bin-mruby-config/mrbgem.rake b/mrbgems/mruby-bin-mruby-config/mrbgem.rake deleted file mode 100644 index cca7423ac..000000000 --- a/mrbgems/mruby-bin-mruby-config/mrbgem.rake +++ /dev/null @@ -1,31 +0,0 @@ -module MRuby - class Build - def exefile(name) - if name.is_a?(Array) - name.flatten.map { |n| exefile(n) } - elsif name !~ /\./ - "#{name}#{exts.executable}" - else - name - end - end - end -end - -MRuby.each_target do - next if kind_of? MRuby::CrossBuild - - mruby_config = 'mruby-config' + (ENV['OS'] == 'Windows_NT' ? '.bat' : '') - mruby_config_path = "#{build_dir}/bin/#{mruby_config}" - @bins << mruby_config - - make_cfg = "#{build_dir}/lib/libmruby.flags.mak" - file mruby_config_path => [libmruby_static, make_cfg] do |t| - FileUtils.copy "#{File.dirname(__FILE__)}/#{mruby_config}", t.name - config = Hash[open(make_cfg).read.split("\n").map {|x| a = x.split(/\s*=\s*/, 2); [a[0], a[1].gsub('\\"', '"') ]}] - IO.write(t.name, File.open(t.name) {|f| - f.read.gsub (/echo (MRUBY_CFLAGS|MRUBY_LIBS|MRUBY_LDFLAGS_BEFORE_LIBS|MRUBY_LDFLAGS|MRUBY_LIBMRUBY_PATH)/) {|x| config[$1].empty? ? '' : "echo #{config[$1]}"} - }) - FileUtils.chmod(0755, t.name) - end -end diff --git a/mrbgems/mruby-bin-mruby-config/mruby-config b/mrbgems/mruby-bin-mruby-config/mruby-config deleted file mode 100644 index 57346c03f..000000000 --- a/mrbgems/mruby-bin-mruby-config/mruby-config +++ /dev/null @@ -1,20 +0,0 @@ -#!/bin/sh - -while [ $# -gt 0 ]; do - case $1 in - --cflags) echo MRUBY_CFLAGS;; - --ldflags) echo MRUBY_LDFLAGS;; - --ldflags-before-libs) echo MRUBY_LDFLAGS_BEFORE_LIBS;; - --libs) echo MRUBY_LIBS;; - --libmruby-path) echo MRUBY_LIBMRUBY_PATH;; - --help) echo "Usage: mruby-config [switches]" - echo " switches:" - echo " --cflags print flags passed to compiler" - echo " --ldflags print flags passed to linker" - echo " --ldflags-before-libs print flags passed to linker before linked libraries" - echo " --libs print linked libraries" - echo " --libmruby-path print libmruby path" - exit 0;; - esac - shift -done diff --git a/mrbgems/mruby-bin-mruby-config/mruby-config.bat b/mrbgems/mruby-bin-mruby-config/mruby-config.bat deleted file mode 100644 index a1f7bfdd1..000000000 --- a/mrbgems/mruby-bin-mruby-config/mruby-config.bat +++ /dev/null @@ -1,42 +0,0 @@ -@echo off - -:top -shift -if "%0" equ "" goto :eof -if "%0" equ "--cflags" goto cflags -if "%0" equ "--ldflags" goto ldflags -if "%0" equ "--ldflags-before-libs" goto ldflagsbeforelibs -if "%0" equ "--libs" goto libs -if "%0" equ "--libmruby-path" goto libmrubypath -if "%0" equ "--help" goto showhelp -echo Invalid Option -goto :eof - -:cflags -echo MRUBY_CFLAGS -goto top - -:libs -echo MRUBY_LIBS -goto top - -:ldflags -echo MRUBY_LDFLAGS -goto top - -:ldflagsbeforelibs -echo MRUBY_LDFLAGS_BEFORE_LIBS -goto top - -:libmrubypath -echo MRUBY_LIBMRUBY_PATH -goto top - -:showhelp -echo Usage: mruby-config [switches] -echo switches: -echo --cflags print flags passed to compiler -echo --ldflags print flags passed to linker -echo --ldflags-before-libs print flags passed to linker before linked libraries -echo --libs print linked libraries -echo --libmruby-path print libmruby path -- cgit v1.2.3 From 3707ef3d1cd2ed1ef0c2c15a05018efd0dc37273 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Mon, 21 Jan 2019 19:37:20 +0900 Subject: Use `assert_raise` and `assert_nothing_raised` in `mruby-sleep` tests --- mrbgems/mruby-sleep/test/sleep_test.rb | 29 ++++------------------------- 1 file changed, 4 insertions(+), 25 deletions(-) diff --git a/mrbgems/mruby-sleep/test/sleep_test.rb b/mrbgems/mruby-sleep/test/sleep_test.rb index 349f169b3..06a6d73fa 100644 --- a/mrbgems/mruby-sleep/test/sleep_test.rb +++ b/mrbgems/mruby-sleep/test/sleep_test.rb @@ -1,36 +1,15 @@ -def run_with_catching_error &b - e = nil - begin - b.call - rescue => _e - e = _e - end - - return e -end - assert("sleep works") do - e = run_with_catching_error { sleep 1 } - - assert_nil e + assert_nothing_raised { sleep(1) } end assert("sleep would not accept negative value") do - e = run_with_catching_error{ sleep(-1) } - - assert_not_equal e, nil - assert_equal e.class, ArgumentError + assert_raise(ArgumentError) { sleep(-1) } end assert("usleep works") do - e = run_with_catching_error { usleep 100 } - - assert_nil e + assert_nothing_raised { usleep(100) } end assert("usleep would not accept negative value") do - e = run_with_catching_error{ usleep(-100) } - - assert_not_equal e, nil - assert_equal e.class, ArgumentError + assert_raise(ArgumentError) { usleep(-100) } end -- cgit v1.2.3 From 6d5a62cf5fc8b2e34c86042db9362aa81206fb81 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Tue, 22 Jan 2019 19:37:14 +0900 Subject: Fix tests for `String#reverse` with `MRB_UTF8_STRING` --- test/t/string.rb | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/test/t/string.rb b/test/t/string.rb index e0f0eb99c..7f81c9335 100644 --- a/test/t/string.rb +++ b/test/t/string.rb @@ -464,12 +464,11 @@ assert('String#reverse', '15.2.10.5.29') do end assert('String#reverse(UTF-8)', '15.2.10.5.29') do - assert_equal "ち", "こんにちは世界"[3] - assert_equal nil, "こんにちは世界"[20] - assert_equal "世", "こんにちは世界"[-2] - assert_equal "世界", "こんにちは世界"[-2..-1] - assert_equal "んに", "こんにちは世界"[1,2] - assert_equal "世", "こんにちは世界"["世"] + a = 'こんにちは世界!' + a.reverse + + assert_equal 'こんにちは世界!', a + assert_equal '!界世はちにんこ', 'こんにちは世界!'.reverse end if UTF8STRING assert('String#reverse!', '15.2.10.5.30') do -- cgit v1.2.3 From f54262776ec012ae5001b5d43899cbdca02fc936 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Wed, 23 Jan 2019 21:18:14 +0900 Subject: [ci skip] Remove no meaning statement in `bm_app_lc_fizzbuzz.rb` --- benchmark/bm_app_lc_fizzbuzz.rb | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/benchmark/bm_app_lc_fizzbuzz.rb b/benchmark/bm_app_lc_fizzbuzz.rb index 26283cc3f..de8268577 100644 --- a/benchmark/bm_app_lc_fizzbuzz.rb +++ b/benchmark/bm_app_lc_fizzbuzz.rb @@ -48,5 +48,4 @@ answer = to_array(solution).map do |p| to_string(p) end -answer_str = answer.to_a -# puts answer_str +# puts answer -- cgit v1.2.3 From 1d6679e9d13078b279b81a1241e632540672524c Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Thu, 24 Jan 2019 20:44:55 +0900 Subject: Remove definition of `Kernel#sprintf` in `mruby-print` --- mrbgems/mruby-print/mrblib/print.rb | 3 --- 1 file changed, 3 deletions(-) diff --git a/mrbgems/mruby-print/mrblib/print.rb b/mrbgems/mruby-print/mrblib/print.rb index fa83c47de..27567d858 100644 --- a/mrbgems/mruby-print/mrblib/print.rb +++ b/mrbgems/mruby-print/mrblib/print.rb @@ -52,9 +52,6 @@ module Kernel def printf(*args) raise NotImplementedError.new('printf not available') end - def sprintf(*args) - raise NotImplementedError.new('sprintf not available') - end else def printf(*args) __printstr__(sprintf(*args)) -- cgit v1.2.3 From a4c5fcc0388c80f72f004ff719c7580a98e1e516 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Thu, 24 Jan 2019 20:53:40 +0900 Subject: Remove redundant `NULL` check for `mrb_malloc` --- mrbgems/mruby-print/src/print.c | 1 - 1 file changed, 1 deletion(-) diff --git a/mrbgems/mruby-print/src/print.c b/mrbgems/mruby-print/src/print.c index e181b06e0..f7f99fc77 100644 --- a/mrbgems/mruby-print/src/print.c +++ b/mrbgems/mruby-print/src/print.c @@ -23,7 +23,6 @@ printstr(mrb_state *mrb, mrb_value obj) char* utf8 = RSTRING_PTR(obj); int wlen = MultiByteToWideChar(CP_UTF8, 0, utf8, mlen, NULL, 0); wchar_t* utf16 = (wchar_t*)mrb_malloc(mrb, (wlen+1) * sizeof(wchar_t)); - if (utf16 == NULL) return; if (MultiByteToWideChar(CP_UTF8, 0, utf8, mlen, utf16, wlen) > 0) { utf16[wlen] = 0; WriteConsoleW(GetStdHandle(STD_OUTPUT_HANDLE), -- cgit v1.2.3 From bdbbac999f00532559c1b3b9aa2b372cd26eddc0 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Fri, 25 Jan 2019 20:02:45 +0900 Subject: Remove definition of `assert_nothing_raised` in `IO` test --- mrbgems/mruby-io/test/io.rb | 20 -------------------- 1 file changed, 20 deletions(-) diff --git a/mrbgems/mruby-io/test/io.rb b/mrbgems/mruby-io/test/io.rb index e4a449696..881e94185 100644 --- a/mrbgems/mruby-io/test/io.rb +++ b/mrbgems/mruby-io/test/io.rb @@ -1,26 +1,6 @@ ## # IO Test -unless Object.respond_to? :assert_nothing_raised - def assert_nothing_raised(*exp) - ret = true - if $mrbtest_assert - $mrbtest_assert_idx += 1 - msg = exp.last.class == String ? exp.pop : "" - begin - yield - rescue Exception => e - msg = "#{msg} exception raised." - diff = " Class: <#{e.class}>\n" + - " Message: #{e.message}" - $mrbtest_assert.push([$mrbtest_assert_idx, msg, diff]) - ret = false - end - end - ret - end -end - assert('IO TEST SETUP') do MRubyIOTestUtil.io_test_setup $cr = MRubyIOTestUtil.win? ? 1 : 0 # "\n" include CR or not -- cgit v1.2.3 From e9a6ec05b69e2463711e584eb336c56dc06fbe71 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Fri, 25 Jan 2019 20:12:24 +0900 Subject: Use assertion methods in `File` test --- mrbgems/mruby-io/test/file.rb | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/mrbgems/mruby-io/test/file.rb b/mrbgems/mruby-io/test/file.rb index 8d2be04c8..7b67ded26 100644 --- a/mrbgems/mruby-io/test/file.rb +++ b/mrbgems/mruby-io/test/file.rb @@ -1,16 +1,16 @@ ## -# IO Test +# File Test -assert('File', '15.2.21') do - File.class == Class +assert('File TEST SETUP') do + MRubyIOTestUtil.io_test_setup end -assert('File', '15.2.21.2') do - File.superclass == IO +assert('File', '15.2.21') do + assert_equal Class, File.class end -assert('File TEST SETUP') do - MRubyIOTestUtil.io_test_setup +assert('File', '15.2.21.2') do + assert_equal IO, File.superclass end assert('File#initialize', '15.2.21.4.1') do @@ -27,7 +27,7 @@ assert('File#path', '15.2.21.4.2') do assert_equal $mrbtest_io_rfname, io.path io.close assert_equal $mrbtest_io_rfname, io.path - io.closed? + assert_true io.closed? end assert('File.basename') do -- cgit v1.2.3 From b91a17b33b93966feeea75facad42cc4730e7485 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Fri, 25 Jan 2019 20:35:55 +0900 Subject: Remove unused file for `mruby-io` test --- mrbgems/mruby-io/test/gc_filedes.sh | 4 ---- 1 file changed, 4 deletions(-) delete mode 100644 mrbgems/mruby-io/test/gc_filedes.sh diff --git a/mrbgems/mruby-io/test/gc_filedes.sh b/mrbgems/mruby-io/test/gc_filedes.sh deleted file mode 100644 index 6e5d1bbf1..000000000 --- a/mrbgems/mruby-io/test/gc_filedes.sh +++ /dev/null @@ -1,4 +0,0 @@ -#!/bin/sh - -ulimit -n 20 -mruby -e '100.times { File.open "'$0'" }' -- cgit v1.2.3 From 1cd57006f37c9f86b85491ceacf6ab285bb85475 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Sat, 26 Jan 2019 18:37:53 +0900 Subject: Refine error message for time interval Time interval value can be zero, and float (in `Kernel#sleep`) --- mrbgems/mruby-sleep/src/mrb_sleep.c | 6 +++--- mrbgems/mruby-sleep/test/sleep_test.rb | 16 +++++++++++++++- 2 files changed, 18 insertions(+), 4 deletions(-) diff --git a/mrbgems/mruby-sleep/src/mrb_sleep.c b/mrbgems/mruby-sleep/src/mrb_sleep.c index 0428f29eb..3f8ef90cf 100644 --- a/mrbgems/mruby-sleep/src/mrb_sleep.c +++ b/mrbgems/mruby-sleep/src/mrb_sleep.c @@ -51,7 +51,7 @@ mrb_f_sleep(mrb_state *mrb, mrb_value self) usleep(sec * 1000000); } else { - mrb_raise(mrb, E_ARGUMENT_ERROR, "time interval must be positive integer"); + mrb_raise(mrb, E_ARGUMENT_ERROR, "time interval must not be negative"); } #else mrb_int sec; @@ -60,7 +60,7 @@ mrb_f_sleep(mrb_state *mrb, mrb_value self) if (sec >= 0) { sleep(sec); } else { - mrb_raise(mrb, E_ARGUMENT_ERROR, "time interval must be positive integer"); + mrb_raise(mrb, E_ARGUMENT_ERROR, "time interval must not be negative"); } #endif end = time(0) - beg; @@ -94,7 +94,7 @@ mrb_f_usleep(mrb_state *mrb, mrb_value self) if (usec >= 0) { usleep(usec); } else { - mrb_raise(mrb, E_ARGUMENT_ERROR, "time interval must be positive integer"); + mrb_raise(mrb, E_ARGUMENT_ERROR, "time interval must not be negative integer"); } #ifdef _WIN32 diff --git a/mrbgems/mruby-sleep/test/sleep_test.rb b/mrbgems/mruby-sleep/test/sleep_test.rb index 06a6d73fa..f05b7a30b 100644 --- a/mrbgems/mruby-sleep/test/sleep_test.rb +++ b/mrbgems/mruby-sleep/test/sleep_test.rb @@ -1,13 +1,27 @@ assert("sleep works") do assert_nothing_raised { sleep(1) } + assert_nothing_raised { sleep(0) } end -assert("sleep would not accept negative value") do +assert("sleep would accept non-negative float value") do + skip unless Object.const_defined?(:Float) + assert_nothing_raised { sleep(0.01) } + assert_nothing_raised { sleep(0.0) } + assert_nothing_raised { sleep(-0.0) } +end + +assert("sleep would not accept negative integer value") do assert_raise(ArgumentError) { sleep(-1) } end +assert("sleep would not accept negative float value") do + skip unless Object.const_defined?(:Float) + assert_raise(ArgumentError) { sleep(-0.1) } +end + assert("usleep works") do assert_nothing_raised { usleep(100) } + assert_nothing_raised { usleep(0) } end assert("usleep would not accept negative value") do -- cgit v1.2.3 From 995a329bf4983beb1322c2e2c4399c11bdb852fa Mon Sep 17 00:00:00 2001 From: takkaw Date: Sat, 26 Jan 2019 23:19:53 +0900 Subject: fix Time about carry-up and carry-down --- mrbgems/mruby-time/src/time.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mrbgems/mruby-time/src/time.c b/mrbgems/mruby-time/src/time.c index c3a0ac435..d70fb442c 100644 --- a/mrbgems/mruby-time/src/time.c +++ b/mrbgems/mruby-time/src/time.c @@ -263,12 +263,12 @@ time_alloc(mrb_state *mrb, double sec, double usec, enum mrb_timezone timezone) tm->sec = tsec; tm->usec = (time_t)llround((sec - tm->sec) * 1.0e6 + usec); if (tm->usec < 0) { - long sec2 = (long)NDIV(usec,1000000); /* negative div */ + long sec2 = (long)NDIV(tm->usec,1000000); /* negative div */ tm->usec -= sec2 * 1000000; tm->sec += sec2; } else if (tm->usec >= 1000000) { - long sec2 = (long)(usec / 1000000); + long sec2 = (long)(tm->usec / 1000000); tm->usec -= sec2 * 1000000; tm->sec += sec2; } -- cgit v1.2.3 From e85cb9799cd54d5fa79500f07e559a4169d4243f Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Sun, 27 Jan 2019 20:35:41 +0900 Subject: Remove no meaning statements in `mruby-io` tests --- mrbgems/mruby-io/test/file.rb | 1 - mrbgems/mruby-io/test/file_test.rb | 4 ---- mrbgems/mruby-io/test/io.rb | 23 ----------------------- 3 files changed, 28 deletions(-) diff --git a/mrbgems/mruby-io/test/file.rb b/mrbgems/mruby-io/test/file.rb index 7b67ded26..539e25047 100644 --- a/mrbgems/mruby-io/test/file.rb +++ b/mrbgems/mruby-io/test/file.rb @@ -177,7 +177,6 @@ assert('File.path') do assert_equal "a/../b/./c", File.path("a/../b/./c") assert_raise(TypeError) { File.path(nil) } assert_raise(TypeError) { File.path(123) } - end assert('File.symlink') do diff --git a/mrbgems/mruby-io/test/file_test.rb b/mrbgems/mruby-io/test/file_test.rb index 2c831f0d5..7148e9dc2 100644 --- a/mrbgems/mruby-io/test/file_test.rb +++ b/mrbgems/mruby-io/test/file_test.rb @@ -70,8 +70,6 @@ assert("FileTest.size?") do assert_raise IOError do FileTest.size?(fp2) end - - fp1.closed? && fp2.closed? end assert("FileTest.socket?") do @@ -108,8 +106,6 @@ assert("FileTest.zero?") do assert_raise IOError do FileTest.zero?(fp2) end - - fp1.closed? && fp2.closed? end assert('FileTest TEST CLEANUP') do diff --git a/mrbgems/mruby-io/test/io.rb b/mrbgems/mruby-io/test/io.rb index 881e94185..85852c179 100644 --- a/mrbgems/mruby-io/test/io.rb +++ b/mrbgems/mruby-io/test/io.rb @@ -30,8 +30,6 @@ assert('IO.open', '15.2.20.4.1') do IO.open(fd) do |io| assert_equal $mrbtest_io_msg, io.read end - - true end assert('IO#close', '15.2.20.5.1') do @@ -72,8 +70,6 @@ assert('IO#eof?', '15.2.20.5.6') do io.read assert_true io.eof? io.close - - true end assert('IO#flush', '15.2.20.5.7') do @@ -93,7 +89,6 @@ assert('IO#getc', '15.2.20.5.8') do } assert_equal nil, io.getc io.close - true end #assert('IO#gets', '15.2.20.5.9') do @@ -179,8 +174,6 @@ assert('IO#write', '15.2.20.5.20') do io.rewind assert_equal "ab123fg", io.read io.close - - true end assert('IO#<<') do @@ -188,7 +181,6 @@ assert('IO#<<') do io << "" << "" assert_equal 0, io.pos io.close - true end assert('IO#dup for readable') do @@ -208,7 +200,6 @@ assert('IO#dup for readable') do dup.close assert_false io.closed? io.close - true end assert('IO#dup for writable') do @@ -221,7 +212,6 @@ assert('IO#dup for writable') do assert_equal "mruby", dup.sysread(5) dup.close io.close - true end assert('IO.for_fd') do @@ -229,13 +219,11 @@ assert('IO.for_fd') do io = IO.for_fd(fd) assert_equal $mrbtest_io_msg, io.read io.close - true end assert('IO.new') do io = IO.new(0) io.close - true end assert('IO gc check') do @@ -280,7 +268,6 @@ assert('IO.sysopen, IO#sysread') do io = IO.new fd, "w" assert_raise(IOError) { io.sysread(1) } io.close - true end assert('IO.sysopen, IO#syswrite') do @@ -294,8 +281,6 @@ assert('IO.sysopen, IO#syswrite') do io = IO.new(IO.sysopen($mrbtest_io_rfname), "r") assert_raise(IOError) { io.syswrite("a") } io.close - - true end assert('IO#_read_buf') do @@ -319,7 +304,6 @@ assert('IO#_read_buf') do assert_equal true, io.eof assert_equal true, io.eof? io.close - io.closed? end assert('IO#isatty') do @@ -352,7 +336,6 @@ assert('IO#pos=, IO#seek') do assert_equal 0, io.seek(0) assert_equal 0, io.pos io.close - io.closed? end assert('IO#rewind') do @@ -363,7 +346,6 @@ assert('IO#rewind') do assert_equal 0, io.rewind assert_equal 0, io.pos io.close - io.closed? end assert('IO#gets') do @@ -412,7 +394,6 @@ assert('IO#gets') do assert_equal nil, io.gets, "gets third line; returns nil" io.close - io.closed? end assert('IO#gets - paragraph mode') do @@ -423,7 +404,6 @@ assert('IO#gets - paragraph mode') do io.write "2" * 10 + "\n" assert_equal 34 + $cr * 4, io.pos io.close - assert_equal true, io.closed? fd = IO.sysopen $mrbtest_io_wfname io = IO.new fd @@ -434,7 +414,6 @@ assert('IO#gets - paragraph mode') do text2 = io.gets("") assert_equal para2, text2 io.close - io.closed? end assert('IO.popen') do @@ -528,7 +507,6 @@ assert('IO#fileno') do assert_equal io.fileno, fd assert_equal io.to_i, fd io.close - io.closed? end assert('IO#close_on_exec') do @@ -550,7 +528,6 @@ assert('IO#close_on_exec') do assert_equal(false, io.close_on_exec?) io.close - io.closed? begin r, w = IO.pipe -- cgit v1.2.3 From 12ba571a1385dd83bdccb63aab3b0ce34720c694 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Mon, 28 Jan 2019 12:17:41 +0900 Subject: Use assertion methods in `FileTest` tests --- mrbgems/mruby-io/test/file_test.rb | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/mrbgems/mruby-io/test/file_test.rb b/mrbgems/mruby-io/test/file_test.rb index 7148e9dc2..04e10e0c8 100644 --- a/mrbgems/mruby-io/test/file_test.rb +++ b/mrbgems/mruby-io/test/file_test.rb @@ -67,9 +67,11 @@ assert("FileTest.size?") do assert_raise IOError do FileTest.size?(fp1) end + assert_true fp1.closed? assert_raise IOError do FileTest.size?(fp2) end + assert_true fp2.closed? end assert("FileTest.socket?") do @@ -103,9 +105,11 @@ assert("FileTest.zero?") do assert_raise IOError do FileTest.zero?(fp1) end + assert_true fp1.closed? assert_raise IOError do FileTest.zero?(fp2) end + assert_true fp2.closed? end assert('FileTest TEST CLEANUP') do -- cgit v1.2.3 From abbc50143364dd84111573e594d24f6ace256eeb Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Mon, 28 Jan 2019 21:29:55 +0900 Subject: `class`/`module` expression with empty body should return `nil` Before: p(class A end) #=> A p(class << self; end) #=> #> p(module B end) #=> B After/Ruby: p(class A end) #=> nil p(class << self; end) #=> nil p(module B end) #=> nil --- mrbgems/mruby-compiler/core/codegen.c | 19 ++++++++++++++----- test/t/class.rb | 5 +++++ test/t/module.rb | 9 +++++++++ 3 files changed, 28 insertions(+), 5 deletions(-) diff --git a/mrbgems/mruby-compiler/core/codegen.c b/mrbgems/mruby-compiler/core/codegen.c index a17272ba7..cc46f835f 100644 --- a/mrbgems/mruby-compiler/core/codegen.c +++ b/mrbgems/mruby-compiler/core/codegen.c @@ -2806,7 +2806,10 @@ codegen(codegen_scope *s, node *tree, int val) idx = new_sym(s, nsym(tree->car->cdr)); genop_2(s, OP_CLASS, cursp(), idx); body = tree->cdr->cdr->car; - if (!(nint(body->cdr->car) == NODE_BEGIN && body->cdr->cdr == NULL)) { + if (nint(body->cdr->car) == NODE_BEGIN && body->cdr->cdr == NULL) { + genop_1(s, OP_LOADNIL, cursp()); + } + else { idx = scope_body(s, body, val); genop_2(s, OP_EXEC, cursp(), idx); } @@ -2834,8 +2837,11 @@ codegen(codegen_scope *s, node *tree, int val) pop(); idx = new_sym(s, nsym(tree->car->cdr)); genop_2(s, OP_MODULE, cursp(), idx); - if (!(nint(tree->cdr->car->cdr->car) == NODE_BEGIN && - tree->cdr->car->cdr->cdr == NULL)) { + if (nint(tree->cdr->car->cdr->car) == NODE_BEGIN && + tree->cdr->car->cdr->cdr == NULL) { + genop_1(s, OP_LOADNIL, cursp()); + } + else { idx = scope_body(s, tree->cdr->car, val); genop_2(s, OP_EXEC, cursp(), idx); } @@ -2852,8 +2858,11 @@ codegen(codegen_scope *s, node *tree, int val) codegen(s, tree->car, VAL); pop(); genop_1(s, OP_SCLASS, cursp()); - if (!(nint(tree->cdr->car->cdr->car) == NODE_BEGIN && - tree->cdr->car->cdr->cdr == NULL)) { + if (nint(tree->cdr->car->cdr->car) == NODE_BEGIN && + tree->cdr->car->cdr->cdr == NULL) { + genop_1(s, OP_LOADNIL, cursp()); + } + else { idx = scope_body(s, tree->cdr->car, val); genop_2(s, OP_EXEC, cursp(), idx); } diff --git a/test/t/class.rb b/test/t/class.rb index f37a891a4..6a0a3225c 100644 --- a/test/t/class.rb +++ b/test/t/class.rb @@ -236,6 +236,11 @@ assert('class to return the last value') do assert_equal(m, :m) end +assert('class to return nil if body is empty') do + assert_nil(class C end) + assert_nil(class << self; end) +end + assert('raise when superclass is not a class') do module FirstModule; end assert_raise(TypeError, 'should raise TypeError') do diff --git a/test/t/module.rb b/test/t/module.rb index 78cb5d07f..f01245e88 100644 --- a/test/t/module.rb +++ b/test/t/module.rb @@ -708,6 +708,15 @@ assert('module with non-class/module outer raises TypeError') do assert_raise(TypeError) { module []::M2 end } end +assert('module to return the last value') do + m = module M; :m end + assert_equal(m, :m) +end + +assert('module to return nil if body is empty') do + assert_nil(module M end) +end + assert('get constant of parent module in singleton class; issue #3568') do actual = module GetConstantInSingletonTest EXPECTED = "value" -- cgit v1.2.3 From 486154ce34580620a27cd2da506994248e830ca2 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Tue, 29 Jan 2019 20:21:25 +0900 Subject: Remove unused macro in `src/string.c` --- src/string.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/string.c b/src/string.c index 52941473c..52b869eca 100644 --- a/src/string.c +++ b/src/string.c @@ -1587,8 +1587,6 @@ mrb_str_index_m(mrb_state *mrb, mrb_value str) return mrb_fixnum_value(pos); } -#define STR_REPLACE_SHARED_MIN 10 - /* 15.2.10.5.24 */ /* 15.2.10.5.28 */ /* -- cgit v1.2.3 From 6218585968250ae5a1c0aa17e9cc7f2d2404b40e Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Wed, 30 Jan 2019 19:41:32 +0900 Subject: Remove unneeded `dup` in `Enumerator#initialize` --- mrbgems/mruby-enumerator/mrblib/enumerator.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mrbgems/mruby-enumerator/mrblib/enumerator.rb b/mrbgems/mruby-enumerator/mrblib/enumerator.rb index 5697c6609..cbf53974a 100644 --- a/mrbgems/mruby-enumerator/mrblib/enumerator.rb +++ b/mrbgems/mruby-enumerator/mrblib/enumerator.rb @@ -121,7 +121,7 @@ class Enumerator @obj = obj @meth = meth - @args = args.dup + @args = args @fib = nil @dst = nil @lookahead = nil -- cgit v1.2.3 From 6da3cd5d2296b9cd205772851f0a30e3af730c70 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Fri, 1 Feb 2019 16:02:01 +0900 Subject: Move `NONE` to `mrblib/enum.rb` --- mrbgems/mruby-array-ext/mrblib/array.rb | 1 - mrbgems/mruby-enum-ext/mrblib/enum.rb | 1 - mrblib/enum.rb | 2 ++ 3 files changed, 2 insertions(+), 2 deletions(-) diff --git a/mrbgems/mruby-array-ext/mrblib/array.rb b/mrbgems/mruby-array-ext/mrblib/array.rb index 6096696cb..387bd6c90 100644 --- a/mrbgems/mruby-array-ext/mrblib/array.rb +++ b/mrbgems/mruby-array-ext/mrblib/array.rb @@ -266,7 +266,6 @@ class Array self end - NONE=Object.new ## # call-seq: # ary.fetch(index) -> obj diff --git a/mrbgems/mruby-enum-ext/mrblib/enum.rb b/mrbgems/mruby-enum-ext/mrblib/enum.rb index fedf8b1ae..99b9cddba 100644 --- a/mrbgems/mruby-enum-ext/mrblib/enum.rb +++ b/mrbgems/mruby-enum-ext/mrblib/enum.rb @@ -205,7 +205,6 @@ module Enumerable ary.collect{|e,i| orig[i]} end - NONE = Object.new ## # call-seq: # enum.first -> obj or nil diff --git a/mrblib/enum.rb b/mrblib/enum.rb index a97a26f97..9bd74e1c4 100644 --- a/mrblib/enum.rb +++ b/mrblib/enum.rb @@ -13,6 +13,8 @@ # @ISO 15.3.2 module Enumerable + NONE = Object.new + ## # Call the given block for each element # which is yield by +each+. Return false -- cgit v1.2.3 From 668ed605219706cbc9b45f21752fe471dd368e02 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Sat, 2 Feb 2019 18:53:49 +0900 Subject: Extend only when necessary in `lib/mruby-core-ext.rb` --- lib/mruby-core-ext.rb | 40 +++++++++++++++++++++++----------------- 1 file changed, 23 insertions(+), 17 deletions(-) diff --git a/lib/mruby-core-ext.rb b/lib/mruby-core-ext.rb index 4c6d3ca76..08e6f6148 100644 --- a/lib/mruby-core-ext.rb +++ b/lib/mruby-core-ext.rb @@ -18,18 +18,20 @@ class String end # Compatible with 1.9 on 1.8 - def %(params) - if params.is_a?(Hash) - str = self.clone - params.each do |k, v| - str.gsub!("%{#{k}}") { v } - end - str - else - if params.is_a?(Array) - sprintf(self, *params) + unless (sprintf("%{a}", :a => 1) rescue false) + def %(params) + if params.is_a?(Hash) + str = self.clone + params.each do |k, v| + str.gsub!("%{#{k}}") { v } + end + str else - sprintf(self, params) + if params.is_a?(Array) + sprintf(self, *params) + else + sprintf(self, params) + end end end end @@ -37,17 +39,21 @@ end class Symbol # Compatible with 1.9 on 1.8 - def to_proc - proc { |obj, *args| obj.send(self, *args) } + unless method_defined?(:to_proc) + def to_proc + proc { |obj, *args| obj.send(self, *args) } + end end end module Enumerable # Compatible with 1.9 on 1.8 - def each_with_object(memo) - return to_enum :each_with_object, memo unless block_given? - each { |obj| yield obj, memo } - memo + unless method_defined?(:each_with_object) + def each_with_object(memo) + return to_enum :each_with_object, memo unless block_given? + each { |obj| yield obj, memo } + memo + end end end -- cgit v1.2.3 From c86861bddf2af1fc8b17f695be65c2e7a140601f Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Sun, 3 Feb 2019 22:00:55 +0900 Subject: Use `mrb->eException_class` instead of `mrb_class_get()` --- mrbgems/mruby-bin-debugger/tools/mrdb/cmdmisc.c | 2 +- mrbgems/mruby-bin-debugger/tools/mrdb/cmdrun.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/mrbgems/mruby-bin-debugger/tools/mrdb/cmdmisc.c b/mrbgems/mruby-bin-debugger/tools/mrdb/cmdmisc.c index 0a864567d..2fc661cdf 100644 --- a/mrbgems/mruby-bin-debugger/tools/mrdb/cmdmisc.c +++ b/mrbgems/mruby-bin-debugger/tools/mrdb/cmdmisc.c @@ -495,7 +495,7 @@ dbgcmd_quit(mrb_state *mrb, mrdb_state *mrdb) if (mrdb->dbg->xm == DBG_QUIT) { struct RClass *exc; - exc = mrb_define_class(mrb, "DebuggerExit", mrb_class_get(mrb, "Exception")); + exc = mrb_define_class(mrb, "DebuggerExit", mrb->eException_class); mrb_raise(mrb, exc, "Exit mrdb."); } return DBGST_PROMPT; diff --git a/mrbgems/mruby-bin-debugger/tools/mrdb/cmdrun.c b/mrbgems/mruby-bin-debugger/tools/mrdb/cmdrun.c index cb4c738fc..233c86cef 100644 --- a/mrbgems/mruby-bin-debugger/tools/mrdb/cmdrun.c +++ b/mrbgems/mruby-bin-debugger/tools/mrdb/cmdrun.c @@ -19,7 +19,7 @@ dbgcmd_run(mrb_state *mrb, mrdb_state *mrdb) if (dbg->xphase == DBG_PHASE_RUNNING){ struct RClass *exc; puts("Start it from the beginning."); - exc = mrb_define_class(mrb, "DebuggerRestart", mrb_class_get(mrb, "Exception")); + exc = mrb_define_class(mrb, "DebuggerRestart", mrb->eException_class); mrb_raise(mrb, exc, "Restart mrdb."); } } -- cgit v1.2.3 From 69fd1a592560d321061790c94f93532db93dccb9 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Mon, 4 Feb 2019 18:11:22 +0900 Subject: Fix `Symbol#size` for multi-byte characters with `MRB_UTF8_STRING` MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Before: p :あ.size #=> 3 After: p :あ.size #=> 1 --- include/mruby/string.h | 4 ++++ mrbgems/mruby-symbol-ext/src/symbol.c | 7 +++++++ mrbgems/mruby-symbol-ext/test/symbol.rb | 15 +++++++++++--- src/string.c | 35 +++++++++++++++++++++------------ 4 files changed, 45 insertions(+), 16 deletions(-) diff --git a/include/mruby/string.h b/include/mruby/string.h index 3fe8295ff..6fe0556b0 100644 --- a/include/mruby/string.h +++ b/include/mruby/string.h @@ -439,6 +439,10 @@ void mrb_regexp_check(mrb_state *mrb, mrb_value obj); #define mrb_str_buf_cat(mrb, str, ptr, len) mrb_str_cat(mrb, str, ptr, len) #define mrb_str_buf_append(mrb, str, str2) mrb_str_cat_str(mrb, str, str2) +#ifdef MRB_UTF8_STRING +mrb_int mrb_utf8_len(const char *str, mrb_int byte_len); +#endif + MRB_END_DECL #endif /* MRUBY_STRING_H */ diff --git a/mrbgems/mruby-symbol-ext/src/symbol.c b/mrbgems/mruby-symbol-ext/src/symbol.c index a992dbfce..215226502 100644 --- a/mrbgems/mruby-symbol-ext/src/symbol.c +++ b/mrbgems/mruby-symbol-ext/src/symbol.c @@ -1,6 +1,7 @@ #include #include #include +#include typedef struct symbol_name { size_t len; @@ -45,7 +46,13 @@ static mrb_value mrb_sym_length(mrb_state *mrb, mrb_value self) { mrb_int len; +#ifdef MRB_UTF8_STRING + mrb_int byte_len; + const char *name = mrb_sym2name_len(mrb, mrb_symbol(self), &byte_len); + len = mrb_utf8_len(name, byte_len); +#else mrb_sym2name_len(mrb, mrb_symbol(self), &len); +#endif return mrb_fixnum_value(len); } diff --git a/mrbgems/mruby-symbol-ext/test/symbol.rb b/mrbgems/mruby-symbol-ext/test/symbol.rb index 63c1bd826..2c7a62b0c 100644 --- a/mrbgems/mruby-symbol-ext/test/symbol.rb +++ b/mrbgems/mruby-symbol-ext/test/symbol.rb @@ -7,9 +7,18 @@ assert('Symbol.all_symbols') do assert_equal foo, symbols end -assert("Symbol#length") do - assert_equal 5, :hello.size - assert_equal 5, :mruby.length +%w[size length].each do |n| + assert("Symbol##{n}") do + assert_equal 5, :hello.__send__(n) + assert_equal 4, :"aA\0b".__send__(n) + if "あ".size == 1 # enable MRB_UTF8_STRING? + assert_equal 8, :"こんにちは世界!".__send__(n) + assert_equal 4, :"aあ\0b".__send__(n) + else + assert_equal 22, :"こんにちは世界!".__send__(n) + assert_equal 6, :"aあ\0b".__send__(n) + end + end end assert("Symbol#capitalize") do diff --git a/src/string.c b/src/string.c index 52b869eca..148e2fee2 100644 --- a/src/string.c +++ b/src/string.c @@ -238,27 +238,36 @@ utf8len(const char* p, const char* e) return len; } -static mrb_int -utf8_strlen(mrb_value str, mrb_int len) +mrb_int +mrb_utf8_len(const char *str, mrb_int byte_len) { mrb_int total = 0; - char* p = RSTRING_PTR(str); - char* e = p; - if (RSTRING(str)->flags & MRB_STR_NO_UTF) { - return RSTRING_LEN(str); - } - e += len < 0 ? RSTRING_LEN(str) : len; - while (pflags |= MRB_STR_NO_UTF; - } return total; } -#define RSTRING_CHAR_LEN(s) utf8_strlen(s, -1) +static mrb_int +utf8_strlen(mrb_value str) +{ + mrb_int byte_len = RSTRING_LEN(str); + + if (RSTRING(str)->flags & MRB_STR_NO_UTF) { + return byte_len; + } + else { + mrb_int utf8_len = mrb_utf8_len(RSTRING_PTR(str), byte_len); + if (byte_len == utf8_len) RSTRING(str)->flags |= MRB_STR_NO_UTF; + return utf8_len; + } +} + +#define RSTRING_CHAR_LEN(s) utf8_strlen(s) /* map character index to byte offset index */ static mrb_int -- cgit v1.2.3 From 7a2865cfef443e28cd377f359b1a3c98b101c517 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Tue, 5 Feb 2019 19:08:53 +0900 Subject: Fix markup and remove unneeded comment for doc in `src/string.c` [ci skip] --- src/string.c | 28 ++++++---------------------- 1 file changed, 6 insertions(+), 22 deletions(-) diff --git a/src/string.c b/src/string.c index 148e2fee2..d26d6f4c9 100644 --- a/src/string.c +++ b/src/string.c @@ -156,13 +156,6 @@ mrb_str_new(mrb_state *mrb, const char *p, size_t len) return mrb_obj_value(str_new(mrb, p, len)); } -/* - * call-seq: (Caution! NULL string) - * String.new(str="") => new_str - * - * Returns a new string object containing a copy of str. - */ - MRB_API mrb_value mrb_str_new_cstr(mrb_state *mrb, const char *p) { @@ -748,12 +741,6 @@ mrb_str_to_cstr(mrb_state *mrb, mrb_value str0) return RSTR_PTR(s); } -/* - * call-seq: (Caution! String("abcd") change) - * String("abcdefg") = String("abcd") + String("efg") - * - * Returns a new string object containing a copy of str. - */ MRB_API void mrb_str_concat(mrb_state *mrb, mrb_value self, mrb_value other) { @@ -761,12 +748,6 @@ mrb_str_concat(mrb_state *mrb, mrb_value self, mrb_value other) mrb_str_cat_str(mrb, self, other); } -/* - * call-seq: (Caution! String("abcd") remain) - * String("abcdefg") = String("abcd") + String("efg") - * - * Returns a new string object containing a copy of str. - */ MRB_API mrb_value mrb_str_plus(mrb_state *mrb, mrb_value a, mrb_value b) { @@ -784,10 +765,13 @@ mrb_str_plus(mrb_state *mrb, mrb_value a, mrb_value b) /* 15.2.10.5.2 */ /* - * call-seq: (Caution! String("abcd") remain) for stack_argument - * String("abcdefg") = String("abcd") + String("efg") + * call-seq: + * str + other_str -> new_str * - * Returns a new string object containing a copy of str. + * Concatenation---Returns a new String containing + * other_str concatenated to str. + * + * "Hello from " + self.to_s #=> "Hello from main" */ static mrb_value mrb_str_plus_m(mrb_state *mrb, mrb_value self) -- cgit v1.2.3 From 5ef1e479da7e1864067092ed87f83f85120c8324 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Tue, 5 Feb 2019 19:15:52 +0900 Subject: Remove old comment for `mrb_sym2name_len()` [ci skip] --- src/symbol.c | 1 - 1 file changed, 1 deletion(-) diff --git a/src/symbol.c b/src/symbol.c index 6b4c7200c..bed918241 100644 --- a/src/symbol.c +++ b/src/symbol.c @@ -143,7 +143,6 @@ mrb_check_intern_str(mrb_state *mrb, mrb_value str) return mrb_check_intern(mrb, RSTRING_PTR(str), RSTRING_LEN(str)); } -/* lenp must be a pointer to a size_t variable */ MRB_API const char* mrb_sym2name_len(mrb_state *mrb, mrb_sym sym, mrb_int *lenp) { -- cgit v1.2.3 From c8628f7ca43d2e660efc3cde3c6a83b5f64438f4 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Wed, 6 Feb 2019 22:05:10 +0900 Subject: Integrate definition of `MRuby::Build#exefile` --- lib/mruby/build.rb | 5 ++++- mrbgems/mruby-bin-mruby-config/mrbgem.rake | 14 -------------- 2 files changed, 4 insertions(+), 15 deletions(-) diff --git a/lib/mruby/build.rb b/lib/mruby/build.rb index 63125d4fa..4f81a970b 100644 --- a/lib/mruby/build.rb +++ b/lib/mruby/build.rb @@ -270,8 +270,11 @@ EOS def exefile(name) if name.is_a?(Array) name.flatten.map { |n| exefile(n) } - else + elsif File.extname(name).empty? "#{name}#{exts.executable}" + else + # `name` sometimes have (non-standard) extension (e.g. `.bat`). + name end end diff --git a/mrbgems/mruby-bin-mruby-config/mrbgem.rake b/mrbgems/mruby-bin-mruby-config/mrbgem.rake index cca7423ac..b9ba0e42c 100644 --- a/mrbgems/mruby-bin-mruby-config/mrbgem.rake +++ b/mrbgems/mruby-bin-mruby-config/mrbgem.rake @@ -1,17 +1,3 @@ -module MRuby - class Build - def exefile(name) - if name.is_a?(Array) - name.flatten.map { |n| exefile(n) } - elsif name !~ /\./ - "#{name}#{exts.executable}" - else - name - end - end - end -end - MRuby.each_target do next if kind_of? MRuby::CrossBuild -- cgit v1.2.3 From 02fbb2c21134ad0e8df0b723a4b11f7d7e21edcd Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Thu, 24 Jan 2019 17:57:12 +0900 Subject: Remove symbol hash table from `mrb_state` structure. Use linear search instead. Number of symbols is usually small (<1K), so we don't need performance boost from hash tables. In our benchmark measurement, hash tables consumes 790KB for `build/full-debug/mrbtest`. --- include/mruby.h | 1 - src/symbol.c | 69 ++++++++++++++++++++------------------------------------- 2 files changed, 24 insertions(+), 46 deletions(-) diff --git a/include/mruby.h b/include/mruby.h index 8c8360784..7fe2330be 100644 --- a/include/mruby.h +++ b/include/mruby.h @@ -239,7 +239,6 @@ typedef struct mrb_state { #endif mrb_sym symidx; - struct kh_n2s *name2sym; /* symbol hash */ struct symbol_name *symtbl; /* symbol table */ size_t symcapa; diff --git a/src/symbol.c b/src/symbol.c index bed918241..bebbb8e85 100644 --- a/src/symbol.c +++ b/src/symbol.c @@ -19,24 +19,6 @@ typedef struct symbol_name { const char *name; } symbol_name; -static inline khint_t -sym_hash_func(mrb_state *mrb, mrb_sym s) -{ - khint_t h = 0; - size_t i, len = mrb->symtbl[s].len; - const char *p = mrb->symtbl[s].name; - - for (i=0; isymtbl[a].len == mrb->symtbl[b].len && memcmp(mrb->symtbl[a].name, mrb->symtbl[b].name, mrb->symtbl[a].len) == 0) - -KHASH_DECLARE(n2s, mrb_sym, mrb_sym, FALSE) -KHASH_DEFINE (n2s, mrb_sym, mrb_sym, FALSE, sym_hash_func, sym_hash_equal) -/* ------------------------------------------------------ */ - static void sym_validate_len(mrb_state *mrb, size_t len) { @@ -45,24 +27,31 @@ sym_validate_len(mrb_state *mrb, size_t len) } } +static mrb_sym +find_symbol(mrb_state *mrb, const char *name, uint16_t len) +{ + mrb_sym i; + symbol_name *sname; + + /* search for a symbol */ + for (i=1; i<=mrb->symidx; i++) { + sname = &mrb->symtbl[i]; + if (sname->len == len && memcmp(sname->name, name, len) == 0) { + return i; + } + } + return 0; +} + static mrb_sym sym_intern(mrb_state *mrb, const char *name, size_t len, mrb_bool lit) { - khash_t(n2s) *h = mrb->name2sym; - symbol_name *sname = mrb->symtbl; /* symtbl[0] for working memory */ - khiter_t k; mrb_sym sym; - char *p; + symbol_name *sname; sym_validate_len(mrb, len); - if (sname) { - sname->lit = lit; - sname->len = (uint16_t)len; - sname->name = name; - k = kh_get(n2s, mrb, h, 0); - if (k != kh_end(h)) - return kh_key(h, k); - } + sym = find_symbol(mrb, name, len); + if (sym > 0) return sym; /* registering a new symbol */ sym = ++mrb->symidx; @@ -78,13 +67,12 @@ sym_intern(mrb_state *mrb, const char *name, size_t len, mrb_bool lit) sname->lit = TRUE; } else { - p = (char *)mrb_malloc(mrb, len+1); + char *p = (char *)mrb_malloc(mrb, len+1); memcpy(p, name, len); p[len] = 0; sname->name = (const char*)p; sname->lit = FALSE; } - kh_put(n2s, mrb, h, sym); return sym; } @@ -116,25 +104,18 @@ mrb_intern_str(mrb_state *mrb, mrb_value str) MRB_API mrb_value mrb_check_intern(mrb_state *mrb, const char *name, size_t len) { - khash_t(n2s) *h = mrb->name2sym; - symbol_name *sname = mrb->symtbl; - khiter_t k; + mrb_sym sym; sym_validate_len(mrb, len); - sname->len = (uint16_t)len; - sname->name = name; - - k = kh_get(n2s, mrb, h, 0); - if (k != kh_end(h)) { - return mrb_symbol_value(kh_key(h, k)); - } + sym = find_symbol(mrb, name, len); + if (sym > 0) return mrb_symbol_value(sym); return mrb_nil_value(); } MRB_API mrb_value mrb_check_intern_cstr(mrb_state *mrb, const char *name) { - return mrb_check_intern(mrb, name, (mrb_int)strlen(name)); + return mrb_check_intern(mrb, name, strlen(name)); } MRB_API mrb_value @@ -166,13 +147,11 @@ mrb_free_symtbl(mrb_state *mrb) } } mrb_free(mrb, mrb->symtbl); - kh_destroy(n2s, mrb, mrb->name2sym); } void mrb_init_symtbl(mrb_state *mrb) { - mrb->name2sym = kh_init(n2s, mrb); } /********************************************************************** -- cgit v1.2.3 From 905fef2669f4dd0efb71205219872d9fb4b135b6 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Tue, 5 Feb 2019 14:20:58 +0900 Subject: Reduce invocation of `mrb_convert_type()` from `mrb_str_to_str()`. --- src/class.c | 2 +- src/string.c | 14 ++++++++++++-- 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/src/class.c b/src/class.c index dd5b65cc3..359bb4fea 100644 --- a/src/class.c +++ b/src/class.c @@ -1815,7 +1815,7 @@ mrb_define_alias(mrb_state *mrb, struct RClass *klass, const char *name1, const * show information on the thing we're attached to as well. */ -static mrb_value +mrb_value mrb_mod_to_s(mrb_state *mrb, mrb_value klass) { mrb_value str; diff --git a/src/string.c b/src/string.c index d26d6f4c9..19962fb30 100644 --- a/src/string.c +++ b/src/string.c @@ -20,6 +20,7 @@ #include #include #include +#include #include typedef struct mrb_shared_string { @@ -972,13 +973,22 @@ mrb_str_equal_m(mrb_state *mrb, mrb_value str1) return mrb_bool_value(mrb_str_equal(mrb, str1, str2)); } /* ---------------------------------- */ +mrb_value mrb_mod_to_s(mrb_state *mrb, mrb_value klass); + MRB_API mrb_value mrb_str_to_str(mrb_state *mrb, mrb_value str) { - if (!mrb_string_p(str)) { + switch (mrb_type(str)) { + case MRB_TT_STRING: + return str; + case MRB_TT_FIXNUM: + return mrb_fixnum_to_str(mrb, str, 10); + case MRB_TT_CLASS: + case MRB_TT_MODULE: + return mrb_mod_to_s(mrb, str); + default: return mrb_convert_type(mrb, str, MRB_TT_STRING, "String", "to_s"); } - return str; } MRB_API const char* -- cgit v1.2.3 From d52f46da4571c7c44954b15f85a00d74ab86f7f3 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Tue, 5 Feb 2019 17:27:24 +0900 Subject: Implement symbol hash table to boost `find_symbol`. In 4174e02, we removed the symbol hash table from `mrb_state` but `find_symbol` was too slow with linear search. My performance estimation was wrong. So we implemented a new compact hash table for symbols. --- include/mruby.h | 1 + src/symbol.c | 55 +++++++++++++++++++++++++++++++++++++++++++++++++------ 2 files changed, 50 insertions(+), 6 deletions(-) diff --git a/include/mruby.h b/include/mruby.h index 7fe2330be..2f2d98677 100644 --- a/include/mruby.h +++ b/include/mruby.h @@ -240,6 +240,7 @@ typedef struct mrb_state { mrb_sym symidx; struct symbol_name *symtbl; /* symbol table */ + mrb_sym symhash[256]; size_t symcapa; #ifdef MRB_ENABLE_DEBUG_HOOK diff --git a/src/symbol.c b/src/symbol.c index bebbb8e85..4242f3d8e 100644 --- a/src/symbol.c +++ b/src/symbol.c @@ -15,6 +15,7 @@ /* ------------------------------------------------------ */ typedef struct symbol_name { mrb_bool lit : 1; + uint8_t prev; uint16_t len; const char *name; } symbol_name; @@ -27,19 +28,48 @@ sym_validate_len(mrb_state *mrb, size_t len) } } +uint8_t +symhash(const char *key, size_t len) +{ + uint32_t hash, i; + + for(hash = i = 0; i < len; ++i) { + hash += key[i]; + hash += (hash << 10); + hash ^= (hash >> 6); + } + hash += (hash << 3); + hash ^= (hash >> 11); + hash += (hash << 15); + return hash & 0xff; +} + static mrb_sym -find_symbol(mrb_state *mrb, const char *name, uint16_t len) +find_symbol(mrb_state *mrb, const char *name, uint16_t len, uint8_t hash) { mrb_sym i; symbol_name *sname; - /* search for a symbol */ - for (i=1; i<=mrb->symidx; i++) { + i = mrb->symhash[hash]; + if (i == 0) return 0; + do { sname = &mrb->symtbl[i]; if (sname->len == len && memcmp(sname->name, name, len) == 0) { return i; } - } + if (sname->prev == 0xff) { + i -= 0xff; + sname = &mrb->symtbl[i]; + while (mrb->symtbl < sname) { + if (sname->len == len && memcmp(sname->name, name, len) == 0) { + return (mrb_sym)(sname - mrb->symtbl); + } + sname--; + } + return 0; + } + i -= sname->prev; + } while (sname->prev > 0); return 0; } @@ -48,9 +78,11 @@ sym_intern(mrb_state *mrb, const char *name, size_t len, mrb_bool lit) { mrb_sym sym; symbol_name *sname; + uint8_t hash; sym_validate_len(mrb, len); - sym = find_symbol(mrb, name, len); + hash = symhash(name, len); + sym = find_symbol(mrb, name, len, hash); if (sym > 0) return sym; /* registering a new symbol */ @@ -73,6 +105,17 @@ sym_intern(mrb_state *mrb, const char *name, size_t len, mrb_bool lit) sname->name = (const char*)p; sname->lit = FALSE; } + if (mrb->symhash[hash]) { + mrb_sym i = sym - mrb->symhash[hash]; + if (i > 0xff) + sname->prev = 0xff; + else + sname->prev = i; + } + else { + sname->prev = 0; + } + mrb->symhash[hash] = sym; return sym; } @@ -107,7 +150,7 @@ mrb_check_intern(mrb_state *mrb, const char *name, size_t len) mrb_sym sym; sym_validate_len(mrb, len); - sym = find_symbol(mrb, name, len); + sym = find_symbol(mrb, name, len, symhash(name, len)); if (sym > 0) return mrb_symbol_value(sym); return mrb_nil_value(); } -- cgit v1.2.3 From 6397ec727feb053e9251d75efdc3b0ba9c397eef Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Wed, 6 Feb 2019 22:00:27 +0900 Subject: Raise `NameError` for symbol struct access. --- mrbgems/mruby-struct/src/struct.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mrbgems/mruby-struct/src/struct.c b/mrbgems/mruby-struct/src/struct.c index 832583f35..c0ce71219 100644 --- a/mrbgems/mruby-struct/src/struct.c +++ b/mrbgems/mruby-struct/src/struct.c @@ -399,7 +399,7 @@ struct_aref_sym(mrb_state *mrb, mrb_value obj, mrb_sym id) return ptr[i]; } } - mrb_raisef(mrb, E_INDEX_ERROR, "'%S' is not a struct member", mrb_sym2str(mrb, id)); + mrb_name_error(mrb, id, "no member '%S' in struct", mrb_sym2str(mrb, id)); return mrb_nil_value(); /* not reached */ } -- cgit v1.2.3 From bdc9de875f5545d4dbf8136dbfb576a0caacf7e3 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Thu, 7 Feb 2019 22:44:36 +0900 Subject: Add `OP_ENTER` to blocks without parameters; fix #4175 So that `lambda{}.call(1)` raises `ArgumentError` as CRuby does. Also, fixed junk assignment for `lambda{|;a|p a}.call{}`. --- mrbgems/mruby-compiler/core/codegen.c | 5 ++++- mrbgems/mruby-compiler/core/parse.y | 33 +++++++++++++++++++++++++-------- 2 files changed, 29 insertions(+), 9 deletions(-) diff --git a/mrbgems/mruby-compiler/core/codegen.c b/mrbgems/mruby-compiler/core/codegen.c index cc46f835f..48bf06461 100644 --- a/mrbgems/mruby-compiler/core/codegen.c +++ b/mrbgems/mruby-compiler/core/codegen.c @@ -734,7 +734,10 @@ lambda_body(codegen_scope *s, node *tree, int blk) lp->pc0 = new_label(s); } tree = tree->cdr; - if (tree->car) { + if (tree->car == NULL) { + genop_W(s, OP_ENTER, 0); + } + else { mrb_aspec a; int ma, oa, ra, pa, ka, kd, ba; int pos, i; diff --git a/mrbgems/mruby-compiler/core/parse.y b/mrbgems/mruby-compiler/core/parse.y index 6a2defa8f..1b2d64b25 100644 --- a/mrbgems/mruby-compiler/core/parse.y +++ b/mrbgems/mruby-compiler/core/parse.y @@ -283,6 +283,20 @@ local_add(parser_state *p, mrb_sym sym) } } +static void +local_add_blk(parser_state *p, mrb_sym blk) +{ + /* allocate register for block */ + local_add_f(p, blk ? blk : mrb_intern_lit(p->mrb, "&")); +} + +static void +local_add_kw(parser_state *p, mrb_sym kwd) +{ + /* allocate register for keywords hash */ + local_add_f(p, kwd ? kwd : mrb_intern_lit(p->mrb, "**")); +} + static node* locals_node(parser_state *p) { @@ -726,13 +740,11 @@ new_args_tail(parser_state *p, node *kws, node *kwrest, mrb_sym blk) { node *k; - /* allocate register for keywords hash */ if (kws || kwrest) { - local_add_f(p, (kwrest && kwrest->cdr)? sym(kwrest->cdr) : mrb_intern_lit(p->mrb, "**")); + local_add_kw(p, (kwrest && kwrest->cdr)? sym(kwrest->cdr) : 0); } - /* allocate register for block */ - local_add_f(p, blk? blk : mrb_intern_lit(p->mrb, "&")); + local_add_blk(p, blk); // allocate register for keywords arguments // order is for Proc#parameters @@ -2567,9 +2579,9 @@ block_param : f_arg ',' f_block_optarg ',' f_rest_arg opt_block_args_tail { $$ = new_args(p, $1, 0, $3, 0, $4); } - | f_arg ',' + | f_arg ',' opt_block_args_tail { - $$ = new_args(p, $1, 0, 0, 0, 0); + $$ = new_args(p, $1, 0, 0, 0, $3); } | f_arg ',' f_rest_arg ',' f_arg opt_block_args_tail { @@ -2610,19 +2622,24 @@ block_param : f_arg ',' f_block_optarg ',' f_rest_arg opt_block_args_tail ; opt_block_param : none - | block_param_def { + local_add_blk(p, 0); + $$ = 0; + } + | block_param_def + { p->cmd_start = TRUE; $$ = $1; } ; -block_param_def : '|' opt_bv_decl '|' +block_param_def : '|' {local_add_blk(p, 0);} opt_bv_decl '|' { $$ = 0; } | tOROP { + local_add_blk(p, 0); $$ = 0; } | '|' block_param opt_bv_decl '|' -- cgit v1.2.3 From e846db709f2ce879a91dcc4c90b7f348020ff6b0 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Thu, 7 Feb 2019 23:52:08 +0900 Subject: Fix `Enumerator#(initialize|inspect)` for `nil`/`false` --- mrbgems/mruby-enumerator/mrblib/enumerator.rb | 12 +++++------- mrbgems/mruby-enumerator/test/enumerator.rb | 13 ++++++++----- 2 files changed, 13 insertions(+), 12 deletions(-) diff --git a/mrbgems/mruby-enumerator/mrblib/enumerator.rb b/mrbgems/mruby-enumerator/mrblib/enumerator.rb index cbf53974a..143f2b74f 100644 --- a/mrbgems/mruby-enumerator/mrblib/enumerator.rb +++ b/mrbgems/mruby-enumerator/mrblib/enumerator.rb @@ -109,11 +109,11 @@ class Enumerator # # p fib.take(10) # => [1, 1, 2, 3, 5, 8, 13, 21, 34, 55] # - def initialize(obj=nil, meth=:each, *args, &block) + def initialize(obj=NONE, meth=:each, *args, &block) if block obj = Generator.new(&block) - else - raise ArgumentError unless obj + elsif obj == NONE + raise ArgumentError, "wrong number of arguments (given 0, expected 1+)" end if @obj and !self.respond_to?(meth) raise NoMethodError, "undefined method #{meth}" @@ -221,13 +221,11 @@ class Enumerator end def inspect - return "#<#{self.class}: uninitialized>" unless @obj - if @args && @args.size > 0 args = @args.join(", ") - "#<#{self.class}: #{@obj}:#{@meth}(#{args})>" + "#<#{self.class}: #{@obj.inspect}:#{@meth}(#{args})>" else - "#<#{self.class}: #{@obj}:#{@meth}>" + "#<#{self.class}: #{@obj.inspect}:#{@meth}>" end end diff --git a/mrbgems/mruby-enumerator/test/enumerator.rb b/mrbgems/mruby-enumerator/test/enumerator.rb index f3bd1bdba..0d2a95292 100644 --- a/mrbgems/mruby-enumerator/test/enumerator.rb +++ b/mrbgems/mruby-enumerator/test/enumerator.rb @@ -21,6 +21,7 @@ assert 'Enumerator.new' do assert_equal [1,2,3], @obj.to_enum(:foo, 1,2,3).to_a assert_equal [1,2,3], Enumerator.new(@obj, :foo, 1,2,3).to_a assert_equal [1,2,3], Enumerator.new { |y| i = 0; loop { y << (i += 1) } }.take(3) + assert_equal [], Enumerator.new(false, :__id__).to_a assert_raise(ArgumentError) { Enumerator.new } assert_raise(ArgumentError) { @obj.to_enum } @@ -92,11 +93,13 @@ end assert 'Enumerator#inspect' do e = (0..10).each - assert_equal("#", e.inspect) - e = Enumerator.new("FooObject", :foo, 1) - assert_equal("#", e.inspect) - e = Enumerator.new("FooObject", :foo, 1, 2, 3) - assert_equal("#", e.inspect) + assert_equal('#', e.inspect) + e = Enumerator.new('FooObject', :foo, 1) + assert_equal('#', e.inspect) + e = Enumerator.new('FooObject', :foo, 1, 2, 3) + assert_equal('#', e.inspect) + e = Enumerator.new(nil, :to_s) + assert_equal('#', e.inspect) end assert 'Enumerator#each' do -- cgit v1.2.3 From 32f3ffa2c9ab4f02b085ef6d8c0fa1c9f2eda799 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Fri, 8 Feb 2019 09:31:55 +0900 Subject: Update #4265 patch. * Update doc comment to clarify `Enumerator.new` without a block is deprecated and left only for internal use. * Fixed some cases `mruby` raise `ArgumentError` too eagerly compared with `CRuby`. --- mrbgems/mruby-enumerator/mrblib/enumerator.rb | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/mrbgems/mruby-enumerator/mrblib/enumerator.rb b/mrbgems/mruby-enumerator/mrblib/enumerator.rb index 143f2b74f..cecc424e6 100644 --- a/mrbgems/mruby-enumerator/mrblib/enumerator.rb +++ b/mrbgems/mruby-enumerator/mrblib/enumerator.rb @@ -109,14 +109,22 @@ class Enumerator # # p fib.take(10) # => [1, 1, 2, 3, 5, 8, 13, 21, 34, 55] # + # In the second, deprecated, form, a generated Enumerator iterates over the + # given object using the given method with the given arguments passed. This + # form is left only for internal use. + # + # Use of this form is discouraged. Use Kernel#enum_for or Kernel#to_enum + # instead. def initialize(obj=NONE, meth=:each, *args, &block) if block obj = Generator.new(&block) - elsif obj == NONE - raise ArgumentError, "wrong number of arguments (given 0, expected 1+)" - end - if @obj and !self.respond_to?(meth) - raise NoMethodError, "undefined method #{meth}" + else + if obj == NONE + raise ArgumentError, "wrong number of arguments (given 0, expected 1+)" + end + if @obj && !self.respond_to?(meth) + raise NoMethodError, "undefined method #{meth}" + end end @obj = obj @@ -610,9 +618,6 @@ module Kernel # enum.first(4) # => [1, 1, 1, 2] # def to_enum(meth=:each, *args) - unless self.respond_to?(meth) - raise ArgumentError, "undefined method #{meth}" - end Enumerator.new self, meth, *args end alias enum_for to_enum -- cgit v1.2.3 From c32e3158f50fb9018702d356c303e61ee3a2e1ea Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Fri, 8 Feb 2019 09:34:31 +0900 Subject: Update `mruby-enumerator` test to conform the last update. --- mrbgems/mruby-enumerator/test/enumerator.rb | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/mrbgems/mruby-enumerator/test/enumerator.rb b/mrbgems/mruby-enumerator/test/enumerator.rb index 0d2a95292..57f971fba 100644 --- a/mrbgems/mruby-enumerator/test/enumerator.rb +++ b/mrbgems/mruby-enumerator/test/enumerator.rb @@ -19,11 +19,8 @@ assert 'Enumerator.new' do assert_equal [:x,:y,:z], [:x,:y,:z].each.map{|i| i}.sort assert_equal [[:x,1],[:y,2]], {x:1, y:2}.each.map{|i| i}.sort assert_equal [1,2,3], @obj.to_enum(:foo, 1,2,3).to_a - assert_equal [1,2,3], Enumerator.new(@obj, :foo, 1,2,3).to_a assert_equal [1,2,3], Enumerator.new { |y| i = 0; loop { y << (i += 1) } }.take(3) - assert_equal [], Enumerator.new(false, :__id__).to_a assert_raise(ArgumentError) { Enumerator.new } - assert_raise(ArgumentError) { @obj.to_enum } # examples fib = Enumerator.new do |y| @@ -94,11 +91,11 @@ end assert 'Enumerator#inspect' do e = (0..10).each assert_equal('#', e.inspect) - e = Enumerator.new('FooObject', :foo, 1) + e = 'FooObject'.enum_for(:foo, 1) assert_equal('#', e.inspect) - e = Enumerator.new('FooObject', :foo, 1, 2, 3) + e = 'FooObject'.enum_for(:foo, 1, 2, 3) assert_equal('#', e.inspect) - e = Enumerator.new(nil, :to_s) + e = nil.enum_for(:to_s) assert_equal('#', e.inspect) end @@ -422,7 +419,6 @@ end assert 'Kernel#to_enum' do assert_equal Enumerator, [].to_enum.class - assert_raise(ArgumentError){ nil.to_enum } end assert 'modifying existing methods' do -- cgit v1.2.3 From 2650999092cac630e5bacb0a12c96bc642e939e6 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Thu, 7 Feb 2019 23:52:08 +0900 Subject: Fix `Enumerator#(initialize|inspect)` for `nil`/`false` --- mrbgems/mruby-enumerator/mrblib/enumerator.rb | 12 +++++------- mrbgems/mruby-enumerator/test/enumerator.rb | 13 ++++++++----- 2 files changed, 13 insertions(+), 12 deletions(-) diff --git a/mrbgems/mruby-enumerator/mrblib/enumerator.rb b/mrbgems/mruby-enumerator/mrblib/enumerator.rb index cbf53974a..143f2b74f 100644 --- a/mrbgems/mruby-enumerator/mrblib/enumerator.rb +++ b/mrbgems/mruby-enumerator/mrblib/enumerator.rb @@ -109,11 +109,11 @@ class Enumerator # # p fib.take(10) # => [1, 1, 2, 3, 5, 8, 13, 21, 34, 55] # - def initialize(obj=nil, meth=:each, *args, &block) + def initialize(obj=NONE, meth=:each, *args, &block) if block obj = Generator.new(&block) - else - raise ArgumentError unless obj + elsif obj == NONE + raise ArgumentError, "wrong number of arguments (given 0, expected 1+)" end if @obj and !self.respond_to?(meth) raise NoMethodError, "undefined method #{meth}" @@ -221,13 +221,11 @@ class Enumerator end def inspect - return "#<#{self.class}: uninitialized>" unless @obj - if @args && @args.size > 0 args = @args.join(", ") - "#<#{self.class}: #{@obj}:#{@meth}(#{args})>" + "#<#{self.class}: #{@obj.inspect}:#{@meth}(#{args})>" else - "#<#{self.class}: #{@obj}:#{@meth}>" + "#<#{self.class}: #{@obj.inspect}:#{@meth}>" end end diff --git a/mrbgems/mruby-enumerator/test/enumerator.rb b/mrbgems/mruby-enumerator/test/enumerator.rb index f3bd1bdba..0d2a95292 100644 --- a/mrbgems/mruby-enumerator/test/enumerator.rb +++ b/mrbgems/mruby-enumerator/test/enumerator.rb @@ -21,6 +21,7 @@ assert 'Enumerator.new' do assert_equal [1,2,3], @obj.to_enum(:foo, 1,2,3).to_a assert_equal [1,2,3], Enumerator.new(@obj, :foo, 1,2,3).to_a assert_equal [1,2,3], Enumerator.new { |y| i = 0; loop { y << (i += 1) } }.take(3) + assert_equal [], Enumerator.new(false, :__id__).to_a assert_raise(ArgumentError) { Enumerator.new } assert_raise(ArgumentError) { @obj.to_enum } @@ -92,11 +93,13 @@ end assert 'Enumerator#inspect' do e = (0..10).each - assert_equal("#", e.inspect) - e = Enumerator.new("FooObject", :foo, 1) - assert_equal("#", e.inspect) - e = Enumerator.new("FooObject", :foo, 1, 2, 3) - assert_equal("#", e.inspect) + assert_equal('#', e.inspect) + e = Enumerator.new('FooObject', :foo, 1) + assert_equal('#', e.inspect) + e = Enumerator.new('FooObject', :foo, 1, 2, 3) + assert_equal('#', e.inspect) + e = Enumerator.new(nil, :to_s) + assert_equal('#', e.inspect) end assert 'Enumerator#each' do -- cgit v1.2.3 From 9ab7c1111bf018ce7acd6ed05eb03843d5c91683 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Fri, 8 Feb 2019 09:31:55 +0900 Subject: Update #4265 patch. * Update doc comment to clarify `Enumerator.new` without a block is deprecated and left only for internal use. * Fixed some cases `mruby` raise `ArgumentError` too eagerly compared with `CRuby`. --- mrbgems/mruby-enumerator/mrblib/enumerator.rb | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/mrbgems/mruby-enumerator/mrblib/enumerator.rb b/mrbgems/mruby-enumerator/mrblib/enumerator.rb index 143f2b74f..cecc424e6 100644 --- a/mrbgems/mruby-enumerator/mrblib/enumerator.rb +++ b/mrbgems/mruby-enumerator/mrblib/enumerator.rb @@ -109,14 +109,22 @@ class Enumerator # # p fib.take(10) # => [1, 1, 2, 3, 5, 8, 13, 21, 34, 55] # + # In the second, deprecated, form, a generated Enumerator iterates over the + # given object using the given method with the given arguments passed. This + # form is left only for internal use. + # + # Use of this form is discouraged. Use Kernel#enum_for or Kernel#to_enum + # instead. def initialize(obj=NONE, meth=:each, *args, &block) if block obj = Generator.new(&block) - elsif obj == NONE - raise ArgumentError, "wrong number of arguments (given 0, expected 1+)" - end - if @obj and !self.respond_to?(meth) - raise NoMethodError, "undefined method #{meth}" + else + if obj == NONE + raise ArgumentError, "wrong number of arguments (given 0, expected 1+)" + end + if @obj && !self.respond_to?(meth) + raise NoMethodError, "undefined method #{meth}" + end end @obj = obj @@ -610,9 +618,6 @@ module Kernel # enum.first(4) # => [1, 1, 1, 2] # def to_enum(meth=:each, *args) - unless self.respond_to?(meth) - raise ArgumentError, "undefined method #{meth}" - end Enumerator.new self, meth, *args end alias enum_for to_enum -- cgit v1.2.3 From e0bc87297e30f41d9e50299d55696759f11a1ad6 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Fri, 8 Feb 2019 09:34:31 +0900 Subject: Update `mruby-enumerator` test to conform the last update. --- mrbgems/mruby-enumerator/test/enumerator.rb | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/mrbgems/mruby-enumerator/test/enumerator.rb b/mrbgems/mruby-enumerator/test/enumerator.rb index 0d2a95292..57f971fba 100644 --- a/mrbgems/mruby-enumerator/test/enumerator.rb +++ b/mrbgems/mruby-enumerator/test/enumerator.rb @@ -19,11 +19,8 @@ assert 'Enumerator.new' do assert_equal [:x,:y,:z], [:x,:y,:z].each.map{|i| i}.sort assert_equal [[:x,1],[:y,2]], {x:1, y:2}.each.map{|i| i}.sort assert_equal [1,2,3], @obj.to_enum(:foo, 1,2,3).to_a - assert_equal [1,2,3], Enumerator.new(@obj, :foo, 1,2,3).to_a assert_equal [1,2,3], Enumerator.new { |y| i = 0; loop { y << (i += 1) } }.take(3) - assert_equal [], Enumerator.new(false, :__id__).to_a assert_raise(ArgumentError) { Enumerator.new } - assert_raise(ArgumentError) { @obj.to_enum } # examples fib = Enumerator.new do |y| @@ -94,11 +91,11 @@ end assert 'Enumerator#inspect' do e = (0..10).each assert_equal('#', e.inspect) - e = Enumerator.new('FooObject', :foo, 1) + e = 'FooObject'.enum_for(:foo, 1) assert_equal('#', e.inspect) - e = Enumerator.new('FooObject', :foo, 1, 2, 3) + e = 'FooObject'.enum_for(:foo, 1, 2, 3) assert_equal('#', e.inspect) - e = Enumerator.new(nil, :to_s) + e = nil.enum_for(:to_s) assert_equal('#', e.inspect) end @@ -422,7 +419,6 @@ end assert 'Kernel#to_enum' do assert_equal Enumerator, [].to_enum.class - assert_raise(ArgumentError){ nil.to_enum } end assert 'modifying existing methods' do -- cgit v1.2.3 From 19740d45a1dc51627076f19578fe837c63de7c25 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Fri, 8 Feb 2019 17:40:12 +0900 Subject: Add `NoMethodError` tests to `mruby-enumerator` --- mrbgems/mruby-enumerator/mrblib/enumerator.rb | 9 ++------- mrbgems/mruby-enumerator/test/enumerator.rb | 7 +++++-- 2 files changed, 7 insertions(+), 9 deletions(-) diff --git a/mrbgems/mruby-enumerator/mrblib/enumerator.rb b/mrbgems/mruby-enumerator/mrblib/enumerator.rb index cecc424e6..457687268 100644 --- a/mrbgems/mruby-enumerator/mrblib/enumerator.rb +++ b/mrbgems/mruby-enumerator/mrblib/enumerator.rb @@ -118,13 +118,8 @@ class Enumerator def initialize(obj=NONE, meth=:each, *args, &block) if block obj = Generator.new(&block) - else - if obj == NONE - raise ArgumentError, "wrong number of arguments (given 0, expected 1+)" - end - if @obj && !self.respond_to?(meth) - raise NoMethodError, "undefined method #{meth}" - end + elsif obj == NONE + raise ArgumentError, "wrong number of arguments (given 0, expected 1+)" end @obj = obj diff --git a/mrbgems/mruby-enumerator/test/enumerator.rb b/mrbgems/mruby-enumerator/test/enumerator.rb index 57f971fba..d609cadb5 100644 --- a/mrbgems/mruby-enumerator/test/enumerator.rb +++ b/mrbgems/mruby-enumerator/test/enumerator.rb @@ -6,11 +6,11 @@ class << @obj end end -assert 'Enumerator' do +assert 'Enumerator.class' do assert_equal Class, Enumerator.class end -assert 'Enumerator' do +assert 'Enumerator.superclass' do assert_equal Object, Enumerator.superclass end @@ -418,7 +418,10 @@ assert 'nested iteration' do end assert 'Kernel#to_enum' do + e = nil assert_equal Enumerator, [].to_enum.class + assert_nothing_raised { e = [].to_enum(:_not_implemented_) } + assert_raise(NoMethodError) { e.first } end assert 'modifying existing methods' do -- cgit v1.2.3 From eb6aee117b8f33810a285a248cf21d2e2409823a Mon Sep 17 00:00:00 2001 From: dearblue Date: Sat, 9 Feb 2019 20:22:08 +0900 Subject: `mrb_default_allocf()` is default allocator for NULL safe --- src/state.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/state.c b/src/state.c index e678b37f3..c3ce1dc33 100644 --- a/src/state.c +++ b/src/state.c @@ -26,6 +26,7 @@ mrb_open_core(mrb_allocf f, void *ud) static const struct mrb_context mrb_context_zero = { 0 }; mrb_state *mrb; + if (f == NULL) f = mrb_default_allocf; mrb = (mrb_state *)(f)(NULL, NULL, sizeof(mrb_state), ud); if (mrb == NULL) return NULL; -- cgit v1.2.3 From e60f5f5ceef53ff757b6e6e3e1e4d16e091ed642 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Sat, 9 Feb 2019 21:48:12 +0900 Subject: Always through `assert_true` for assertion methods in `test/assert.rb` --- test/assert.rb | 38 +++++++++++++------------------------- 1 file changed, 13 insertions(+), 25 deletions(-) diff --git a/test/assert.rb b/test/assert.rb index 196e71d39..3ca8c8a3c 100644 --- a/test/assert.rb +++ b/test/assert.rb @@ -88,15 +88,11 @@ def assert_true(ret, msg = nil, diff = nil) end def assert_false(ret, msg = nil, diff = nil) - if $mrbtest_assert - $mrbtest_assert_idx += 1 - if ret - msg = "Expected #{ret.inspect} to be false" unless msg - diff = assertion_diff(false, ret) unless diff - - $mrbtest_assert.push([$mrbtest_assert_idx, msg, diff]) - end + if ret + msg ||= "Expected #{ret.inspect} to be false" + diff ||= assertion_diff(false, ret) end + assert_true(!ret, msg, diff) !ret end @@ -171,41 +167,33 @@ def assert_not_include(collection, obj, msg = nil) end def assert_raise(*exc) - return true unless $mrbtest_assert - $mrbtest_assert_idx += 1 - msg = (exc.last.is_a? String) ? exc.pop : nil - begin yield - msg ||= "Expected to raise #{exc} but nothing was raised." - diff = nil - $mrbtest_assert.push [$mrbtest_assert_idx, msg, diff] - false rescue *exc - true + assert_true(true) rescue Exception => e msg ||= "Expected to raise #{exc}, not" diff = " Class: <#{e.class}>\n" + " Message: #{e.message}" - $mrbtest_assert.push [$mrbtest_assert_idx, msg, diff] - false + assert_true(false, msg, diff) + else + msg ||= "Expected to raise #{exc} but nothing was raised." + diff = "" + assert_true(false, msg, diff) end end def assert_nothing_raised(msg = nil) - return true unless $mrbtest_assert - $mrbtest_assert_idx += 1 - begin yield - true rescue Exception => e msg ||= "Expected not to raise #{e} but it raised" diff = " Class: <#{e.class}>\n" + " Message: #{e.message}" - $mrbtest_assert.push [$mrbtest_assert_idx, msg, diff] - false + assert_true(false, msg, diff) + else + assert_true(true) end end -- cgit v1.2.3 From 639f6e2799f33a7889c4ca48ae0e314e67214dfc Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Mon, 11 Feb 2019 15:17:56 +0900 Subject: No strict argument check for blocks when keyword arguments exist; ref #4270 --- src/vm.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/vm.c b/src/vm.c index 49c2bb85c..7904162be 100644 --- a/src/vm.c +++ b/src/vm.c @@ -1810,7 +1810,8 @@ RETRY_TRY_BLOCK: kdict = argv[argc-1]; mrb_hash_check_kdict(mrb, kdict); } - else if (r || argc <= m1+m2+o) { + else if (r || argc <= m1+m2+o + || !(mrb->c->ci->proc && MRB_PROC_STRICT_P(mrb->c->ci->proc))) { kdict = mrb_hash_new(mrb); kargs = 0; } -- cgit v1.2.3 From ef93ff64054f2aa7e4451387fb768fe2307247a9 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Mon, 11 Feb 2019 15:19:20 +0900 Subject: Should not copy keys&values when a hash table is empty; fix #4270 --- src/hash.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/hash.c b/src/hash.c index 6b92344c3..fd963c3de 100644 --- a/src/hash.c +++ b/src/hash.c @@ -536,6 +536,7 @@ ht_copy(mrb_state *mrb, htable *t) seg = t->rootseg; t2 = ht_new(mrb); + if (t->size == 0) return t2; while (seg) { for (i=0; isize; i++) { -- cgit v1.2.3 From c6e2d91536acfb05803323c42eccef1811e7bf23 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Mon, 11 Feb 2019 21:09:40 +0900 Subject: Small refactoring in `codegen.c` --- mrbgems/mruby-compiler/core/codegen.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/mrbgems/mruby-compiler/core/codegen.c b/mrbgems/mruby-compiler/core/codegen.c index 48bf06461..bfc08cd94 100644 --- a/mrbgems/mruby-compiler/core/codegen.c +++ b/mrbgems/mruby-compiler/core/codegen.c @@ -2357,13 +2357,9 @@ codegen(codegen_scope *s, node *tree, int val) case NODE_BACK_REF: if (val) { - char buf[3]; - int sym; + char buf[] = {'$', nchar(tree)}; + int sym = new_sym(s, mrb_intern(s->mrb, buf, sizeof(buf))); - buf[0] = '$'; - buf[1] = nchar(tree); - buf[2] = 0; - sym = new_sym(s, mrb_intern_cstr(s->mrb, buf)); genop_2(s, OP_GETGV, cursp(), sym); push(); } -- cgit v1.2.3 From 06ba5905f019ca1a8d8e498fe6dce7a94702c9ad Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Wed, 6 Feb 2019 22:01:45 +0900 Subject: Implement inline packed symbols. Small symbols with all alphanumeric characters (<5) are packed in 32bit symbol integer a la base64. This means those small symbols are not listed in `Symbol.all_symbols`. --- include/mruby.h | 3 ++ mrbgems/mruby-symbol-ext/src/symbol.c | 3 +- src/symbol.c | 93 +++++++++++++++++++++++++++++++++-- 3 files changed, 95 insertions(+), 4 deletions(-) diff --git a/include/mruby.h b/include/mruby.h index 2f2d98677..e9fd08102 100644 --- a/include/mruby.h +++ b/include/mruby.h @@ -242,6 +242,9 @@ typedef struct mrb_state { struct symbol_name *symtbl; /* symbol table */ mrb_sym symhash[256]; size_t symcapa; +#ifndef MRB_ENABLE_SYMBOLL_ALL + char symbuf[8]; /* buffer for small symbol names */ +#endif #ifdef MRB_ENABLE_DEBUG_HOOK void (*code_fetch_hook)(struct mrb_state* mrb, struct mrb_irep *irep, mrb_code *pc, mrb_value *regs); diff --git a/mrbgems/mruby-symbol-ext/src/symbol.c b/mrbgems/mruby-symbol-ext/src/symbol.c index 215226502..05e7d5b91 100644 --- a/mrbgems/mruby-symbol-ext/src/symbol.c +++ b/mrbgems/mruby-symbol-ext/src/symbol.c @@ -30,7 +30,8 @@ mrb_sym_all_symbols(mrb_state *mrb, mrb_value self) mrb_value ary = mrb_ary_new_capa(mrb, mrb->symidx); for (i=1, lim=mrb->symidx+1; i 6) return 0; /* too long */ + for (i=0; i 27) lower = 0; + sym |= bits<<(i*6+2); + } + if (lower) { + sym = 0; + for (i=0; i>(i*5+2) & 31; + if (bits == 0) break; + c = pack_table[bits-1]; + buf[i] = c; + } + buf[i] = '\0'; + return buf; + } + + for (i=0; i<5; i++) { + uint32_t bits; + char c; + + bits = sym>>(i*6+2) & 63; + if (bits == 0) break; + c = pack_table[bits-1]; + buf[i] = c; + } + buf[i] = '\0'; + return buf; +} + uint8_t symhash(const char *key, size_t len) { @@ -50,19 +123,23 @@ find_symbol(mrb_state *mrb, const char *name, uint16_t len, uint8_t hash) mrb_sym i; symbol_name *sname; + /* inline symbol */ + i = sym_inline_pack(name, len); + if (i > 0) return i; + i = mrb->symhash[hash]; if (i == 0) return 0; do { sname = &mrb->symtbl[i]; if (sname->len == len && memcmp(sname->name, name, len) == 0) { - return i; + return i<<1; } if (sname->prev == 0xff) { i -= 0xff; sname = &mrb->symtbl[i]; while (mrb->symtbl < sname) { if (sname->len == len && memcmp(sname->name, name, len) == 0) { - return (mrb_sym)(sname - mrb->symtbl); + return (mrb_sym)(sname - mrb->symtbl)<<1; } sname--; } @@ -117,7 +194,7 @@ sym_intern(mrb_state *mrb, const char *name, size_t len, mrb_bool lit) } mrb->symhash[hash] = sym; - return sym; + return sym<<1; } MRB_API mrb_sym @@ -170,6 +247,13 @@ mrb_check_intern_str(mrb_state *mrb, mrb_value str) MRB_API const char* mrb_sym2name_len(mrb_state *mrb, mrb_sym sym, mrb_int *lenp) { + if (sym & 1) { /* inline packed symbol */ + sym_inline_unpack(sym, mrb->symbuf); + if (lenp) *lenp = strlen(mrb->symbuf); + return mrb->symbuf; + } + + sym >>= 1; if (sym == 0 || mrb->symidx < sym) { if (lenp) *lenp = 0; return NULL; @@ -446,6 +530,9 @@ mrb_sym2str(mrb_state *mrb, mrb_sym sym) const char *name = mrb_sym2name_len(mrb, sym, &len); if (!name) return mrb_undef_value(); /* can't happen */ + if (sym&1) { /* inline symbol */ + return mrb_str_new(mrb, name, len); + } return mrb_str_new_static(mrb, name, len); } -- cgit v1.2.3 From 37bc343e0ad6b837de672c8c0cf6bf00876f746b Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Wed, 6 Feb 2019 23:35:26 +0900 Subject: Disable `Symbol.all_symbols`. --- include/mrbconf.h | 1 + mrbgems/mruby-symbol-ext/src/symbol.c | 9 ++++----- mrbgems/mruby-symbol-ext/test/symbol.rb | 11 +++++++---- src/symbol.c | 6 ++++++ 4 files changed, 18 insertions(+), 9 deletions(-) diff --git a/include/mrbconf.h b/include/mrbconf.h index b1aec8334..08e69d3aa 100644 --- a/include/mrbconf.h +++ b/include/mrbconf.h @@ -120,6 +120,7 @@ /* -DMRB_ENABLE_XXXX to enable following features */ //#define MRB_ENABLE_DEBUG_HOOK /* hooks for debugger */ +//#define MRB_ENABLE_ALL_SYMBOLS /* Symbols.all_symbols */ /* end of configuration */ diff --git a/mrbgems/mruby-symbol-ext/src/symbol.c b/mrbgems/mruby-symbol-ext/src/symbol.c index 05e7d5b91..ccb2971dc 100644 --- a/mrbgems/mruby-symbol-ext/src/symbol.c +++ b/mrbgems/mruby-symbol-ext/src/symbol.c @@ -3,11 +3,6 @@ #include #include -typedef struct symbol_name { - size_t len; - const char *name; -} symbol_name; - /* * call-seq: * Symbol.all_symbols => array @@ -23,6 +18,7 @@ typedef struct symbol_name { * :Tms, :getwd, :$=, :ThreadGroup, * :wait2, :$>] */ +#ifdef MRB_ENABLE_ALL_SYMBOLS static mrb_value mrb_sym_all_symbols(mrb_state *mrb, mrb_value self) { @@ -36,6 +32,7 @@ mrb_sym_all_symbols(mrb_state *mrb, mrb_value self) return ary; } +#endif /* * call-seq: @@ -61,7 +58,9 @@ void mrb_mruby_symbol_ext_gem_init(mrb_state* mrb) { struct RClass *s = mrb->symbol_class; +#ifdef MRB_ENABLE_ALL_SYMBOLS mrb_define_class_method(mrb, s, "all_symbols", mrb_sym_all_symbols, MRB_ARGS_NONE()); +#endif mrb_define_method(mrb, s, "length", mrb_sym_length, MRB_ARGS_NONE()); mrb_define_method(mrb, s, "size", mrb_sym_length, MRB_ARGS_NONE()); } diff --git a/mrbgems/mruby-symbol-ext/test/symbol.rb b/mrbgems/mruby-symbol-ext/test/symbol.rb index 2c7a62b0c..61ecad247 100644 --- a/mrbgems/mruby-symbol-ext/test/symbol.rb +++ b/mrbgems/mruby-symbol-ext/test/symbol.rb @@ -1,10 +1,13 @@ +# coding: utf-8 ## # Symbol(Ext) Test -assert('Symbol.all_symbols') do - foo = [:__symbol_test_1, :__symbol_test_2, :__symbol_test_3].sort - symbols = Symbol.all_symbols.select{|sym|sym.to_s.include? '__symbol_test'}.sort - assert_equal foo, symbols +if Symbol.respond_to?(:all_symbols) + assert('Symbol.all_symbols') do + foo = [:__symbol_test_1, :__symbol_test_2, :__symbol_test_3].sort + symbols = Symbol.all_symbols.select{|sym|sym.to_s.include? '__symbol_test'}.sort + assert_equal foo, symbols + end end %w[size length].each do |n| diff --git a/src/symbol.c b/src/symbol.c index ab7504772..9cc566245 100644 --- a/src/symbol.c +++ b/src/symbol.c @@ -28,6 +28,7 @@ sym_validate_len(mrb_state *mrb, size_t len) } } +#ifndef MRB_ENABLE_ALL_SYMBOLS static char pack_table[] = "_abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; static mrb_sym @@ -100,6 +101,7 @@ sym_inline_unpack(mrb_sym sym, char *buf) buf[i] = '\0'; return buf; } +#endif uint8_t symhash(const char *key, size_t len) @@ -123,9 +125,11 @@ find_symbol(mrb_state *mrb, const char *name, uint16_t len, uint8_t hash) mrb_sym i; symbol_name *sname; +#ifndef MRB_ENABLE_ALL_SYMBOLS /* inline symbol */ i = sym_inline_pack(name, len); if (i > 0) return i; +#endif i = mrb->symhash[hash]; if (i == 0) return 0; @@ -247,11 +251,13 @@ mrb_check_intern_str(mrb_state *mrb, mrb_value str) MRB_API const char* mrb_sym2name_len(mrb_state *mrb, mrb_sym sym, mrb_int *lenp) { +#ifndef MRB_ENABLE_ALL_SYMBOLS if (sym & 1) { /* inline packed symbol */ sym_inline_unpack(sym, mrb->symbuf); if (lenp) *lenp = strlen(mrb->symbuf); return mrb->symbuf; } +#endif sym >>= 1; if (sym == 0 || mrb->symidx < sym) { -- cgit v1.2.3 From c592c093aa654be121a8c7884c32b80c1d6f058f Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Tue, 12 Feb 2019 21:32:39 +0900 Subject: Refine `mrbgems/mruby-bin-config/mrbgem.rake` - Use `MRuby::Gem::Specification` - Fix a binary name is added to `MRuby::Build#bins` multiple times - Close file immediately (avoid using `open(...).read`) - Simplify --- mrbgems/mruby-bin-config/mrbgem.rake | 31 ++++++++++++++++++------------- 1 file changed, 18 insertions(+), 13 deletions(-) diff --git a/mrbgems/mruby-bin-config/mrbgem.rake b/mrbgems/mruby-bin-config/mrbgem.rake index b9ba0e42c..f293c1b9b 100644 --- a/mrbgems/mruby-bin-config/mrbgem.rake +++ b/mrbgems/mruby-bin-config/mrbgem.rake @@ -1,17 +1,22 @@ -MRuby.each_target do - next if kind_of? MRuby::CrossBuild +unless MRuby::Build.current.kind_of?(MRuby::CrossBuild) + MRuby::Gem::Specification.new('mruby-bin-config') do |spec| + name = 'mruby-config' + spec.license = 'MIT' + spec.author = 'mruby developers' + spec.summary = "#{name} command" - mruby_config = 'mruby-config' + (ENV['OS'] == 'Windows_NT' ? '.bat' : '') - mruby_config_path = "#{build_dir}/bin/#{mruby_config}" - @bins << mruby_config + mruby_config = name + (ENV['OS'] == 'Windows_NT' ? '.bat' : '') + mruby_config_path = "#{build.build_dir}/bin/#{mruby_config}" + make_cfg = "#{build.build_dir}/lib/libmruby.flags.mak" + build.bins << mruby_config - make_cfg = "#{build_dir}/lib/libmruby.flags.mak" - file mruby_config_path => [libmruby_static, make_cfg] do |t| - FileUtils.copy "#{File.dirname(__FILE__)}/#{mruby_config}", t.name - config = Hash[open(make_cfg).read.split("\n").map {|x| a = x.split(/\s*=\s*/, 2); [a[0], a[1].gsub('\\"', '"') ]}] - IO.write(t.name, File.open(t.name) {|f| - f.read.gsub (/echo (MRUBY_CFLAGS|MRUBY_LIBS|MRUBY_LDFLAGS_BEFORE_LIBS|MRUBY_LDFLAGS|MRUBY_LIBMRUBY_PATH)/) {|x| config[$1].empty? ? '' : "echo #{config[$1]}"} - }) - FileUtils.chmod(0755, t.name) + file mruby_config_path => [build.libmruby_static, make_cfg] do |t| + config = Hash[File.readlines(make_cfg).map(&:chomp).map {|l| + l.gsub('\\"', '"').split(' = ', 2).map! {|s| s.sub(/^(?=.)/, 'echo ')} + }] + tmplt = File.read("#{__dir__}/#{mruby_config}") + File.write(t.name, tmplt.gsub(/(#{Regexp.union(*config.keys)})\b/, config)) + FileUtils.chmod(0755, t.name) + end end end -- cgit v1.2.3 From 6cdac5efb625aea72740acb7403896a44fe56209 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Wed, 13 Feb 2019 21:57:25 +0900 Subject: Lazy message/diff creation for assertion in `test/assert.rb` Include the following changes too: - Extract part of logic with block to a method - Use `var ||= ...` instead of `var = ... unless var` - Unify using parentheses for `t_print` - Change methods order --- test/assert.rb | 143 ++++++++++++++++++++++++++++++--------------------------- 1 file changed, 75 insertions(+), 68 deletions(-) diff --git a/test/assert.rb b/test/assert.rb index 3ca8c8a3c..ec6fa98ad 100644 --- a/test/assert.rb +++ b/test/assert.rb @@ -79,8 +79,8 @@ def assert_true(ret, msg = nil, diff = nil) if $mrbtest_assert $mrbtest_assert_idx += 1 unless ret - msg = "Expected #{ret.inspect} to be true" unless msg - diff = assertion_diff(true, ret) unless diff + msg ||= "Expected #{ret.inspect} to be true" + diff ||= assertion_diff(true, ret) $mrbtest_assert.push([$mrbtest_assert_idx, msg, diff]) end end @@ -96,74 +96,88 @@ def assert_false(ret, msg = nil, diff = nil) !ret end -def assert_equal(arg1, arg2 = nil, arg3 = nil) - if block_given? - exp, act, msg = arg1, yield, arg2 - else - exp, act, msg = arg1, arg2, arg3 +def assert_equal(exp, act_or_msg = nil, msg = nil, &block) + ret, exp, act, msg = _eval_assertion(:==, exp, act_or_msg, msg, block) + unless ret + msg ||= "Expected to be equal" + diff = assertion_diff(exp, act) end - - msg = "Expected to be equal" unless msg - diff = assertion_diff(exp, act) - assert_true(exp == act, msg, diff) + assert_true(ret, msg, diff) end -def assert_not_equal(arg1, arg2 = nil, arg3 = nil) - if block_given? - exp, act, msg = arg1, yield, arg2 - else - exp, act, msg = arg1, arg2, arg3 +def assert_not_equal(exp, act_or_msg = nil, msg = nil, &block) + ret, exp, act, msg = _eval_assertion(:==, exp, act_or_msg, msg, block) + if ret + msg ||= "Expected to be not equal" + diff = assertion_diff(exp, act) end - - msg = "Expected to be not equal" unless msg - diff = assertion_diff(exp, act) - assert_false(exp == act, msg, diff) + assert_true(!ret, msg, diff) end -def assert_same(arg1, arg2 = nil, arg3 = nil) - if block_given? - exp, act, msg = arg1, yield, arg2 - else - exp, act, msg = arg1, arg2, arg3 +def assert_same(exp, act_or_msg = nil, msg = nil, &block) + ret, exp, act, msg = _eval_assertion(:equal?, exp, act_or_msg, msg, block) + unless ret + msg ||= "Expected #{act.inspect} to be the same object as #{exp.inspect}" + diff = " Expected: #{exp.inspect} (class=#{exp.class}, oid=#{exp.__id__})\n" + + " Actual: #{act.inspect} (class=#{act.class}, oid=#{act.__id__})" end - - msg ||= "Expected #{act.inspect} to be the same object as #{exp.inspect}" - diff = " Expected: #{exp.inspect} (class=#{exp.class}, oid=#{exp.__id__})\n" + - " Actual: #{act.inspect} (class=#{act.class}, oid=#{act.__id__})" - assert_true(exp.equal?(act), msg, diff) + assert_true(ret, msg, diff) end -def assert_not_same(arg1, arg2 = nil, arg3 = nil) - if block_given? - exp, act, msg = arg1, yield, arg2 - else - exp, act, msg = arg1, arg2, arg3 +def assert_not_same(exp, act_or_msg = nil, msg = nil, &block) + ret, exp, act, msg = _eval_assertion(:equal?, exp, act_or_msg, msg, block) + if ret + msg ||= "Expected #{act.inspect} to not be the same object as #{exp.inspect}" + diff = " Expected: #{exp.inspect} (class=#{exp.class}, oid=#{exp.__id__})\n" + + " Actual: #{act.inspect} (class=#{act.class}, oid=#{act.__id__})" end - - msg ||= "Expected #{act.inspect} to not be the same object as #{exp.inspect}" - diff = " Expected: #{exp.inspect} (class=#{exp.class}, oid=#{exp.__id__})\n" + - " Actual: #{act.inspect} (class=#{act.class}, oid=#{act.__id__})" - assert_false(exp.equal?(act), msg, diff) + assert_true(!ret, msg, diff) end def assert_nil(obj, msg = nil) - msg = "Expected #{obj.inspect} to be nil" unless msg - diff = assertion_diff(nil, obj) - assert_true(obj.nil?, msg, diff) + unless ret = obj.nil? + msg ||= "Expected #{obj.inspect} to be nil" + diff = assertion_diff(nil, obj) + end + assert_true(ret, msg, diff) end def assert_include(collection, obj, msg = nil) - msg = "Expected #{collection.inspect} to include #{obj.inspect}" unless msg - diff = " Collection: #{collection.inspect}\n" + - " Object: #{obj.inspect}" - assert_true(collection.include?(obj), msg, diff) + unless ret = collection.include?(obj) + msg ||= "Expected #{collection.inspect} to include #{obj.inspect}" + diff = " Collection: #{collection.inspect}\n" + + " Object: #{obj.inspect}" + end + assert_true(ret, msg, diff) end def assert_not_include(collection, obj, msg = nil) - msg = "Expected #{collection.inspect} to not include #{obj.inspect}" unless msg - diff = " Collection: #{collection.inspect}\n" + - " Object: #{obj.inspect}" - assert_false(collection.include?(obj), msg, diff) + if ret = collection.include?(obj) + msg ||= "Expected #{collection.inspect} to not include #{obj.inspect}" + diff = " Collection: #{collection.inspect}\n" + + " Object: #{obj.inspect}" + end + assert_true(!ret, msg, diff) +end + +## +# Fails unless +obj+ is a kind of +cls+. +def assert_kind_of(cls, obj, msg = nil) + unless ret = obj.kind_of?(cls) + msg ||= "Expected #{obj.inspect} to be a kind of #{cls}, not #{obj.class}" + diff = assertion_diff(cls, obj.class) + end + assert_true(ret, msg, diff) +end + +## +# Fails unless +exp+ is equal to +act+ in terms of a Float +def assert_float(exp, act, msg = nil) + unless ret = check_float(exp, act) + msg ||= "Float #{exp} expected to be equal to float #{act}" + diff = assertion_diff(exp, act) + end + assert_true(ret, msg, diff) end def assert_raise(*exc) @@ -197,22 +211,6 @@ def assert_nothing_raised(msg = nil) end end -## -# Fails unless +obj+ is a kind of +cls+. -def assert_kind_of(cls, obj, msg = nil) - msg = "Expected #{obj.inspect} to be a kind of #{cls}, not #{obj.class}" unless msg - diff = assertion_diff(cls, obj.class) - assert_true(obj.kind_of?(cls), msg, diff) -end - -## -# Fails unless +exp+ is equal to +act+ in terms of a Float -def assert_float(exp, act, msg = nil) - msg = "Float #{exp} expected to be equal to float #{act}" unless msg - diff = assertion_diff(exp, act) - assert_true check_float(exp, act), msg, diff -end - ## # Report the test result and print all assertions # which were reported broken. @@ -220,7 +218,7 @@ def report() t_print("\n") $asserts.each do |msg| - t_print "#{msg}\n" + t_print("#{msg}\n") end $total_test = $ok_test+$ko_test+$kill_test @@ -249,6 +247,15 @@ def check_float(a, b) end end +def _eval_assertion(meth, exp, act_or_msg, msg, block) + if block + exp, act, msg = exp, block.call, act_or_msg + else + exp, act, msg = exp, act_or_msg, msg + end + return exp.__send__(meth, act), exp, act, msg +end + ## # Skip the test class MRubyTestSkip < NotImplementedError -- cgit v1.2.3 From bedd67257190d0f290d37938cfbd9e7936dd6f73 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Thu, 14 Feb 2019 18:44:00 +0900 Subject: Add `const` to `pack_table` to `src/symbol.c` --- src/symbol.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/symbol.c b/src/symbol.c index 9cc566245..c3f06be66 100644 --- a/src/symbol.c +++ b/src/symbol.c @@ -29,13 +29,13 @@ sym_validate_len(mrb_state *mrb, size_t len) } #ifndef MRB_ENABLE_ALL_SYMBOLS -static char pack_table[] = "_abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; +static const char pack_table[] = "_abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; static mrb_sym sym_inline_pack(const char *name, uint16_t len) { char c; - char *p; + const char *p; int i; mrb_sym sym = 0; int lower = 1; -- cgit v1.2.3 From 921af6923d5e55992983d2f4e7930b8a97571448 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Thu, 14 Feb 2019 18:48:41 +0900 Subject: Use `mrb_assert()` for checking `sym` in `sym_inline_unpack()` --- src/symbol.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/symbol.c b/src/symbol.c index 9cc566245..ac313665c 100644 --- a/src/symbol.c +++ b/src/symbol.c @@ -73,9 +73,9 @@ sym_inline_unpack(mrb_sym sym, char *buf) { int i; - if (sym == 0) return NULL; - if ((sym&1) == 0) return NULL; /* need to be inline sym */ - if (sym&2) { /* all lower case (5bits/char) */ + mrb_assert(sym&1); + + if (sym&2) { /* all lower case (5bits/char) */ for (i=0; i<6; i++) { uint32_t bits; char c; -- cgit v1.2.3 From 5b10439f6fcf49a5283e4e01b920f350db36e684 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Fri, 15 Feb 2019 19:48:00 +0900 Subject: Extract code fragment for unpacking into method in `sym_inline_unpack()` --- src/symbol.c | 33 ++++++++++++++------------------- 1 file changed, 14 insertions(+), 19 deletions(-) diff --git a/src/symbol.c b/src/symbol.c index 19e5c2d62..620ae3418 100644 --- a/src/symbol.c +++ b/src/symbol.c @@ -69,31 +69,15 @@ sym_inline_pack(const char *name, uint16_t len) } static const char* -sym_inline_unpack(mrb_sym sym, char *buf) +sym_inline_unpack_with_bit(mrb_sym sym, char *buf, int bit_per_char) { int i; - mrb_assert(sym&1); - - if (sym&2) { /* all lower case (5bits/char) */ - for (i=0; i<6; i++) { - uint32_t bits; - char c; - - bits = sym>>(i*5+2) & 31; - if (bits == 0) break; - c = pack_table[bits-1]; - buf[i] = c; - } - buf[i] = '\0'; - return buf; - } - - for (i=0; i<5; i++) { + for (i=0; i<30/bit_per_char; i++) { uint32_t bits; char c; - bits = sym>>(i*6+2) & 63; + bits = sym>>(i*bit_per_char+2) & (1< Date: Sat, 16 Feb 2019 20:48:33 +0900 Subject: Add length argument for `sym_inline_unpack()` `sym_inline_unpack_with_bit()` is moved inside of `sym_inline_unpack()` because this is used only one place. --- src/symbol.c | 29 ++++++++--------------------- 1 file changed, 8 insertions(+), 21 deletions(-) diff --git a/src/symbol.c b/src/symbol.c index 620ae3418..e09e9019d 100644 --- a/src/symbol.c +++ b/src/symbol.c @@ -69,33 +69,22 @@ sym_inline_pack(const char *name, uint16_t len) } static const char* -sym_inline_unpack_with_bit(mrb_sym sym, char *buf, int bit_per_char) +sym_inline_unpack(mrb_sym sym, char *buf, mrb_int *lenp) { + int bit_per_char = sym&2 ? 5 : 6; /* all lower case if `sym&2` is true */ int i; - for (i=0; i<30/bit_per_char; i++) { - uint32_t bits; - char c; + mrb_assert(sym&1); - bits = sym>>(i*bit_per_char+2) & (1<>(i*bit_per_char+2) & (1<symbuf); - if (lenp) *lenp = strlen(mrb->symbuf); - return mrb->symbuf; + return sym_inline_unpack(sym, mrb->symbuf, lenp); } #endif -- cgit v1.2.3 From d1db959cabd017ecf167edff343d6aacf25142fe Mon Sep 17 00:00:00 2001 From: dearblue Date: Sat, 16 Feb 2019 21:24:05 +0900 Subject: Fix to defined `MRB_SYMBOL_BITSIZE` and `MRB_SYMBOL_MAX` always; ref #4077 --- include/mruby/value.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/include/mruby/value.h b/include/mruby/value.h index f988826ca..1ed20858f 100644 --- a/include/mruby/value.h +++ b/include/mruby/value.h @@ -160,6 +160,10 @@ typedef void mrb_value; #ifndef mrb_bool #define mrb_bool(o) (mrb_type(o) != MRB_TT_FALSE) #endif +#if !defined(MRB_SYMBOL_BITSIZE) +#define MRB_SYMBOL_BITSIZE (sizeof(mrb_sym) * CHAR_BIT) +#define MRB_SYMBOL_MAX UINT32_MAX +#endif #ifndef MRB_WITHOUT_FLOAT #define mrb_float_p(o) (mrb_type(o) == MRB_TT_FLOAT) #endif -- cgit v1.2.3 From 81cbc92513b82bf4ee173fab0a7779ac05a8ef04 Mon Sep 17 00:00:00 2001 From: dearblue Date: Sat, 16 Feb 2019 21:26:45 +0900 Subject: Fix inline packed symbols on 32 bit mode with MRB_WORD_BOXING --- src/symbol.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/symbol.c b/src/symbol.c index 620ae3418..1bc9f2676 100644 --- a/src/symbol.c +++ b/src/symbol.c @@ -34,13 +34,18 @@ static const char pack_table[] = "_abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRS static mrb_sym sym_inline_pack(const char *name, uint16_t len) { + enum { + lower_length_max = (MRB_SYMBOL_BITSIZE - 2) / 5, + mix_length_max = (MRB_SYMBOL_BITSIZE - 2) / 6 + }; + char c; const char *p; int i; mrb_sym sym = 0; int lower = 1; - if (len > 6) return 0; /* too long */ + if (len > lower_length_max) return 0; /* too long */ for (i=0; i mix_length_max) return 0; return sym | 1; } -- cgit v1.2.3 From 5067a5cd584c4457934872d50cfb33735d55241d Mon Sep 17 00:00:00 2001 From: dearblue Date: Sat, 16 Feb 2019 22:13:16 +0900 Subject: Use `const int` instead of `enum` --- src/symbol.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/symbol.c b/src/symbol.c index 1bc9f2676..80437e39e 100644 --- a/src/symbol.c +++ b/src/symbol.c @@ -34,10 +34,8 @@ static const char pack_table[] = "_abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRS static mrb_sym sym_inline_pack(const char *name, uint16_t len) { - enum { - lower_length_max = (MRB_SYMBOL_BITSIZE - 2) / 5, - mix_length_max = (MRB_SYMBOL_BITSIZE - 2) / 6 - }; + const int lower_length_max = (MRB_SYMBOL_BITSIZE - 2) / 5; + const int mix_length_max = (MRB_SYMBOL_BITSIZE - 2) / 6; char c; const char *p; -- cgit v1.2.3 From b3e0a1398945faa5375809f75fb9727f4982b4dc Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Sun, 17 Feb 2019 15:52:16 +0900 Subject: Refine dependencies for `mruby-config` --- mrbgems/mruby-bin-config/mrbgem.rake | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/mrbgems/mruby-bin-config/mrbgem.rake b/mrbgems/mruby-bin-config/mrbgem.rake index f293c1b9b..3a0a1b897 100644 --- a/mrbgems/mruby-bin-config/mrbgem.rake +++ b/mrbgems/mruby-bin-config/mrbgem.rake @@ -8,13 +8,14 @@ unless MRuby::Build.current.kind_of?(MRuby::CrossBuild) mruby_config = name + (ENV['OS'] == 'Windows_NT' ? '.bat' : '') mruby_config_path = "#{build.build_dir}/bin/#{mruby_config}" make_cfg = "#{build.build_dir}/lib/libmruby.flags.mak" + tmplt_path = "#{__dir__}/#{mruby_config}" build.bins << mruby_config - file mruby_config_path => [build.libmruby_static, make_cfg] do |t| - config = Hash[File.readlines(make_cfg).map(&:chomp).map {|l| + file mruby_config_path => [make_cfg, tmplt_path] do |t| + config = Hash[File.readlines(make_cfg).map!(&:chomp).map! {|l| l.gsub('\\"', '"').split(' = ', 2).map! {|s| s.sub(/^(?=.)/, 'echo ')} }] - tmplt = File.read("#{__dir__}/#{mruby_config}") + tmplt = File.read(tmplt_path) File.write(t.name, tmplt.gsub(/(#{Regexp.union(*config.keys)})\b/, config)) FileUtils.chmod(0755, t.name) end -- cgit v1.2.3 From f614eed13abfc0d49e4d9e334f547f6fa9179389 Mon Sep 17 00:00:00 2001 From: yui-knk Date: Sun, 17 Feb 2019 21:34:33 +0900 Subject: Fix typos --- include/mruby.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/mruby.h b/include/mruby.h index e9fd08102..9792d7482 100644 --- a/include/mruby.h +++ b/include/mruby.h @@ -489,7 +489,7 @@ MRB_API void mrb_define_const(mrb_state*, struct RClass*, const char *name, mrb_ * } * @param [mrb_state*] mrb_state* The mruby state reference. * @param [struct RClass*] RClass* A class the method will be undefined from. - * @param [const char] const char* The name of the method to be undefined. + * @param [const char*] const char* The name of the method to be undefined. */ MRB_API void mrb_undef_method(mrb_state*, struct RClass*, const char*); MRB_API void mrb_undef_method_id(mrb_state*, struct RClass*, mrb_sym); @@ -529,7 +529,7 @@ MRB_API void mrb_undef_method_id(mrb_state*, struct RClass*, mrb_sym); * } * @param [mrb_state*] mrb_state* The mruby state reference. * @param [RClass*] RClass* A class the class method will be undefined from. - * @param [constchar*] constchar* The name of the class method to be undefined. + * @param [const char*] const char* The name of the class method to be undefined. */ MRB_API void mrb_undef_class_method(mrb_state*, struct RClass*, const char*); -- cgit v1.2.3 From 15344dfd0b605f391ea2c1f171eb8595c9831df1 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Mon, 18 Feb 2019 16:12:12 +0900 Subject: Remove unneeded `memset()` in `src/backtrace.c` --- src/backtrace.c | 1 - 1 file changed, 1 deletion(-) diff --git a/src/backtrace.c b/src/backtrace.c index 57ae7fd7f..c9da2026e 100644 --- a/src/backtrace.c +++ b/src/backtrace.c @@ -206,7 +206,6 @@ packed_backtrace(mrb_state *mrb) each_backtrace(mrb, ciidx, mrb->c->ci->pc, count_backtrace_i, &len); size = len * sizeof(struct backtrace_location); ptr = mrb_malloc(mrb, size); - if (ptr) memset(ptr, 0, size); backtrace = mrb_data_object_alloc(mrb, NULL, ptr, &bt_type); backtrace->flags = (unsigned int)len; each_backtrace(mrb, ciidx, mrb->c->ci->pc, pack_backtrace_i, &ptr); -- cgit v1.2.3 From a28d7143986de8bcb1dbfa3a202079b3a25bf6f2 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Mon, 18 Feb 2019 16:38:56 +0900 Subject: Reorder members in `struct backtrace_location` `sizeof(struct backtrace_location)` is 24 bytes -> 16 bytes in LP64 data model etc. --- src/backtrace.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/backtrace.c b/src/backtrace.c index 57ae7fd7f..ef5f0dc38 100644 --- a/src/backtrace.c +++ b/src/backtrace.c @@ -17,8 +17,8 @@ struct backtrace_location { int lineno; - const char *filename; mrb_sym method_id; + const char *filename; }; typedef void (*each_backtrace_func)(mrb_state*, struct backtrace_location*, void*); -- cgit v1.2.3 From 4ccc3f15259c9857255c5af9f35e56c742aca2c3 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Wed, 13 Feb 2019 07:28:33 +0900 Subject: Use key argument register for `OP_KEY_P` to reduce register use. --- mrbgems/mruby-compiler/core/codegen.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mrbgems/mruby-compiler/core/codegen.c b/mrbgems/mruby-compiler/core/codegen.c index bfc08cd94..a2d790e32 100644 --- a/mrbgems/mruby-compiler/core/codegen.c +++ b/mrbgems/mruby-compiler/core/codegen.c @@ -823,8 +823,8 @@ lambda_body(codegen_scope *s, node *tree, int blk) mrb_assert(nint(kwd->car) == NODE_KW_ARG); if (def_arg) { - genop_2(s, OP_KEY_P, cursp(), new_sym(s, kwd_sym)); - jmpif_key_p = genjmp2(s, OP_JMPIF, cursp(), 0, 0); + genop_2(s, OP_KEY_P, lv_idx(s, kwd_sym), new_sym(s, kwd_sym)); + jmpif_key_p = genjmp2(s, OP_JMPIF, lv_idx(s, kwd_sym), 0, 0); codegen(s, def_arg, VAL); pop(); gen_move(s, lv_idx(s, kwd_sym), cursp(), 0); -- cgit v1.2.3 From 9215c854502da336efe8ece755450478f320349f Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Mon, 18 Feb 2019 17:21:08 +0900 Subject: Parenthesize expression to suppress warning; ref #4278 --- src/symbol.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/symbol.c b/src/symbol.c index 8424cecd9..87c4ca11e 100644 --- a/src/symbol.c +++ b/src/symbol.c @@ -80,7 +80,7 @@ sym_inline_unpack(mrb_sym sym, char *buf, mrb_int *lenp) mrb_assert(sym&1); for (i=0; i<30/bit_per_char; i++) { - uint32_t bits = sym>>(i*bit_per_char+2) & (1<>(i*bit_per_char+2) & ((1< Date: Mon, 18 Feb 2019 21:06:18 +0900 Subject: Use `assert_same` instead of `assert_equal` in `Enumerable#reverse_each` test --- mrbgems/mruby-enum-ext/test/enum.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mrbgems/mruby-enum-ext/test/enum.rb b/mrbgems/mruby-enum-ext/test/enum.rb index b2d7297a4..53747c0dc 100644 --- a/mrbgems/mruby-enum-ext/test/enum.rb +++ b/mrbgems/mruby-enum-ext/test/enum.rb @@ -135,7 +135,7 @@ end assert("Enumerable#reverse_each") do r = (1..3) a = [] - assert_equal (1..3), r.reverse_each { |v| a << v } + assert_same r, r.reverse_each { |v| a << v } assert_equal [3, 2, 1], a end -- cgit v1.2.3 From d68eb3d0434ad55d7e139e2ff8aefb97d02b8902 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Mon, 18 Feb 2019 21:24:20 +0900 Subject: Fix wrong assertion method in some tests --- mrbgems/mruby-enum-ext/test/enum.rb | 2 +- mrbgems/mruby-socket/test/socket.rb | 2 +- test/t/enumerable.rb | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/mrbgems/mruby-enum-ext/test/enum.rb b/mrbgems/mruby-enum-ext/test/enum.rb index b2d7297a4..5625d0853 100644 --- a/mrbgems/mruby-enum-ext/test/enum.rb +++ b/mrbgems/mruby-enum-ext/test/enum.rb @@ -128,7 +128,7 @@ assert("Enumerable#any? (enhancement)") do end assert("Enumerable#each_with_object") do - assert_true [2, 4, 6, 8, 10, 12, 14, 16, 18, 20], (1..10).each_with_object([]) { |i, a| a << i*2 } + assert_equal [2, 4, 6, 8, 10, 12, 14, 16, 18, 20], (1..10).each_with_object([]) { |i, a| a << i*2 } assert_raise(ArgumentError) { (1..10).each_with_object() { |i, a| a << i*2 } } end diff --git a/mrbgems/mruby-socket/test/socket.rb b/mrbgems/mruby-socket/test/socket.rb index efd8fc28e..b64a67919 100644 --- a/mrbgems/mruby-socket/test/socket.rb +++ b/mrbgems/mruby-socket/test/socket.rb @@ -28,7 +28,7 @@ assert('Socket#recvfrom') do rstr, ai = s.recvfrom sstr.size assert_equal sstr, rstr - assert_true "127.0.0.1", ai.ip_address + assert_equal "127.0.0.1", ai.ip_address ensure s.close rescue nil c.close rescue nil diff --git a/test/t/enumerable.rb b/test/t/enumerable.rb index 359c3451b..652c304da 100644 --- a/test/t/enumerable.rb +++ b/test/t/enumerable.rb @@ -68,7 +68,7 @@ assert('Enumerable#find', '15.3.2.2.7') do end assert('Enumerable#find_all', '15.3.2.2.8') do - assert_true [1,2,3,4,5,6,7,8,9].find_all() {|i| i%2 == 0}, [2,4,6,8] + assert_equal [2,4,6,8], [1,2,3,4,5,6,7,8,9].find_all() {|i| i%2 == 0} end assert('Enumerable#grep', '15.3.2.2.9') do -- cgit v1.2.3 From 477ffc747368f26ee90cb03fa69d23690298fc3d Mon Sep 17 00:00:00 2001 From: kimu_shu Date: Tue, 19 Feb 2019 18:10:05 +0900 Subject: Add "info locals" command to mrdb --- mrbgems/mruby-bin-debugger/tools/mrdb/apiprint.c | 7 ++++++- mrbgems/mruby-bin-debugger/tools/mrdb/apiprint.h | 2 +- mrbgems/mruby-bin-debugger/tools/mrdb/cmdmisc.c | 6 ++++++ mrbgems/mruby-bin-debugger/tools/mrdb/cmdprint.c | 25 +++++++++++++++++++++++- mrbgems/mruby-bin-debugger/tools/mrdb/mrdb.c | 1 + mrbgems/mruby-bin-debugger/tools/mrdb/mrdb.h | 2 ++ 6 files changed, 40 insertions(+), 3 deletions(-) diff --git a/mrbgems/mruby-bin-debugger/tools/mrdb/apiprint.c b/mrbgems/mruby-bin-debugger/tools/mrdb/apiprint.c index c8700530f..f888d1430 100644 --- a/mrbgems/mruby-bin-debugger/tools/mrdb/apiprint.c +++ b/mrbgems/mruby-bin-debugger/tools/mrdb/apiprint.c @@ -31,7 +31,7 @@ mrdb_check_syntax(mrb_state *mrb, mrb_debug_context *dbg, const char *expr, size } mrb_value -mrb_debug_eval(mrb_state *mrb, mrb_debug_context *dbg, const char *expr, size_t len, mrb_bool *exc) +mrb_debug_eval(mrb_state *mrb, mrb_debug_context *dbg, const char *expr, size_t len, mrb_bool *exc, int direct_eval) { void (*tmp)(struct mrb_state *, struct mrb_irep *, mrb_code *, mrb_value *); mrb_value ruby_code; @@ -48,6 +48,11 @@ mrb_debug_eval(mrb_state *mrb, mrb_debug_context *dbg, const char *expr, size_t v = mrb_obj_value(mrb->exc); mrb->exc = 0; } + else if (direct_eval) { + recv = dbg->regs[0]; + + v = mrb_funcall(mrb, recv, expr, 0); + } else { /* * begin diff --git a/mrbgems/mruby-bin-debugger/tools/mrdb/apiprint.h b/mrbgems/mruby-bin-debugger/tools/mrdb/apiprint.h index e256f6262..ab8c08869 100644 --- a/mrbgems/mruby-bin-debugger/tools/mrdb/apiprint.h +++ b/mrbgems/mruby-bin-debugger/tools/mrdb/apiprint.h @@ -8,6 +8,6 @@ #include #include "mrdb.h" -mrb_value mrb_debug_eval(mrb_state*, mrb_debug_context*, const char*, size_t, mrb_bool*); +mrb_value mrb_debug_eval(mrb_state*, mrb_debug_context*, const char*, size_t, mrb_bool*, int); #endif /* APIPRINT_H_ */ diff --git a/mrbgems/mruby-bin-debugger/tools/mrdb/cmdmisc.c b/mrbgems/mruby-bin-debugger/tools/mrdb/cmdmisc.c index 2fc661cdf..db28e4229 100644 --- a/mrbgems/mruby-bin-debugger/tools/mrdb/cmdmisc.c +++ b/mrbgems/mruby-bin-debugger/tools/mrdb/cmdmisc.c @@ -81,6 +81,12 @@ static help_msg help_msg_list[] = { "Status of specified breakpoints (all user-settable breakpoints if no argument).\n" "Arguments are breakpoint numbers with spaces in between.\n" }, + { + "i[nfo]", "l[ocals]", "Print name of local variables", + "Usage: info locals\n" + "\n" + "Print name of local variables.\n" + }, { "l[ist]", NULL, "List specified line", "Usage: list\n" diff --git a/mrbgems/mruby-bin-debugger/tools/mrdb/cmdprint.c b/mrbgems/mruby-bin-debugger/tools/mrdb/cmdprint.c index cca636711..25f071589 100644 --- a/mrbgems/mruby-bin-debugger/tools/mrdb/cmdprint.c +++ b/mrbgems/mruby-bin-debugger/tools/mrdb/cmdprint.c @@ -36,7 +36,7 @@ dbgcmd_print(mrb_state *mrb, mrdb_state *mrdb) expr = mrb_str_cat_cstr(mrb, expr, mrdb->words[wcnt]); } - result = mrb_debug_eval(mrb, mrdb->dbg, RSTRING_PTR(expr), RSTRING_LEN(expr), NULL); + result = mrb_debug_eval(mrb, mrdb->dbg, RSTRING_PTR(expr), RSTRING_LEN(expr), NULL, 0); /* $print_no = result */ s = mrb_str_cat_lit(mrb, result, "\0"); @@ -56,3 +56,26 @@ dbgcmd_eval(mrb_state *mrb, mrdb_state *mrdb) { return dbgcmd_print(mrb, mrdb); } + +dbgcmd_state +dbgcmd_info_local(mrb_state *mrb, mrdb_state *mrdb) +{ + mrb_value result; + mrb_value s; + int ai; + + ai = mrb_gc_arena_save(mrb); + + result = mrb_debug_eval(mrb, mrdb->dbg, "local_variables", 0, NULL, 1); + + s = mrb_str_cat_lit(mrb, result, "\0"); + printf("$%lu = %s\n", (unsigned long)mrdb->print_no++, RSTRING_PTR(s)); + + if (mrdb->print_no == 0) { + mrdb->print_no = 1; + } + + mrb_gc_arena_restore(mrb, ai); + + return DBGST_PROMPT; +} diff --git a/mrbgems/mruby-bin-debugger/tools/mrdb/mrdb.c b/mrbgems/mruby-bin-debugger/tools/mrdb/mrdb.c index 05a6f3622..5256ac5e3 100644 --- a/mrbgems/mruby-bin-debugger/tools/mrdb/mrdb.c +++ b/mrbgems/mruby-bin-debugger/tools/mrdb/mrdb.c @@ -52,6 +52,7 @@ static const debug_command debug_command_list[] = { {"eval", NULL, 2, 0, 0, DBGCMD_EVAL, dbgcmd_eval}, /* ev[al] */ {"help", NULL, 1, 0, 1, DBGCMD_HELP, dbgcmd_help}, /* h[elp] */ {"info", "breakpoints", 1, 1, 1, DBGCMD_INFO_BREAK, dbgcmd_info_break}, /* i[nfo] b[reakpoints] */ + {"info", "locals", 1, 1, 0, DBGCMD_INFO_LOCAL, dbgcmd_info_local}, /* i[nfo] l[ocals] */ {"list", NULL, 1, 0, 1, DBGCMD_LIST, dbgcmd_list}, /* l[ist] */ {"print", NULL, 1, 0, 0, DBGCMD_PRINT, dbgcmd_print}, /* p[rint] */ {"quit", NULL, 1, 0, 0, DBGCMD_QUIT, dbgcmd_quit}, /* q[uit] */ diff --git a/mrbgems/mruby-bin-debugger/tools/mrdb/mrdb.h b/mrbgems/mruby-bin-debugger/tools/mrdb/mrdb.h index 5ac12c1cd..7b14a899f 100644 --- a/mrbgems/mruby-bin-debugger/tools/mrdb/mrdb.h +++ b/mrbgems/mruby-bin-debugger/tools/mrdb/mrdb.h @@ -23,6 +23,7 @@ typedef enum debug_command_id { DBGCMD_STEP, DBGCMD_BREAK, DBGCMD_INFO_BREAK, + DBGCMD_INFO_LOCAL, DBGCMD_WATCH, DBGCMD_INFO_WATCH, DBGCMD_ENABLE, @@ -151,6 +152,7 @@ dbgcmd_state dbgcmd_next(mrb_state*, mrdb_state*); /* cmdbreak.c */ dbgcmd_state dbgcmd_break(mrb_state*, mrdb_state*); dbgcmd_state dbgcmd_info_break(mrb_state*, mrdb_state*); +dbgcmd_state dbgcmd_info_local(mrb_state*, mrdb_state*); dbgcmd_state dbgcmd_delete(mrb_state*, mrdb_state*); dbgcmd_state dbgcmd_enable(mrb_state*, mrdb_state*); dbgcmd_state dbgcmd_disable(mrb_state*, mrdb_state*); -- cgit v1.2.3 From 8a7298e069023b634c2011c4727d12f9fea725c2 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Tue, 19 Feb 2019 20:02:50 +0900 Subject: Use more appropriate assertion methods --- mrbgems/mruby-metaprog/test/metaprog.rb | 11 +++--- test/t/bs_block.rb | 63 +++++++++++++++++---------------- test/t/module.rb | 2 +- 3 files changed, 39 insertions(+), 37 deletions(-) diff --git a/mrbgems/mruby-metaprog/test/metaprog.rb b/mrbgems/mruby-metaprog/test/metaprog.rb index 748fe9c6c..8bc3719b8 100644 --- a/mrbgems/mruby-metaprog/test/metaprog.rb +++ b/mrbgems/mruby-metaprog/test/metaprog.rb @@ -143,8 +143,8 @@ assert('Module#class_variable_set', '15.2.2.4.18') do end end - assert_true Test4ClassVariableSet.class_variable_set(:@@cv, 99) - assert_true Test4ClassVariableSet.class_variable_set(:@@foo, 101) + assert_equal 99, Test4ClassVariableSet.class_variable_set(:@@cv, 99) + assert_equal 101, Test4ClassVariableSet.class_variable_set(:@@foo, 101) assert_true Test4ClassVariableSet.class_variables.include? :@@cv assert_equal 99, Test4ClassVariableSet.class_variable_get(:@@cv) assert_equal 101, Test4ClassVariableSet.new.foo @@ -238,9 +238,10 @@ assert('Module#remove_method', '15.2.2.4.41') do end end - assert_true Test4RemoveMethod::Child.class_eval{ remove_method :hello } - assert_true Test4RemoveMethod::Child.instance_methods.include? :hello - assert_false Test4RemoveMethod::Child.instance_methods(false).include? :hello + klass = Test4RemoveMethod::Child + assert_same klass, klass.class_eval{ remove_method :hello } + assert_true klass.instance_methods.include? :hello + assert_false klass.instance_methods(false).include? :hello end assert('Module.nesting', '15.2.2.2.2') do diff --git a/test/t/bs_block.rb b/test/t/bs_block.rb index 62eb7e32e..995e52559 100644 --- a/test/t/bs_block.rb +++ b/test/t/bs_block.rb @@ -408,42 +408,43 @@ assert('BS Block 32') do end assert('BS Block [ruby-core:14395]') do - class Controller - def respond_to(&block) - responder = Responder.new - block.call(responder) - responder.respond - end - def test_for_bug - respond_to{|format| - format.js{ - "in test" - render{|obj| - obj + assert_nothing_raised do + class Controller + def respond_to(&block) + responder = Responder.new + block.call(responder) + responder.respond + end + def test_for_bug + respond_to{|format| + format.js{ + "in test" + render{|obj| + obj + } } } - } - end - def render(&block) - "in render" - end - end - - class Responder - def method_missing(symbol, &block) - "enter method_missing" - @response = Proc.new{ - 'in method missing' - block.call - } - "leave method_missing" + end + def render(&block) + "in render" + end end - def respond - @response.call + class Responder + def method_missing(symbol, &block) + "enter method_missing" + @response = Proc.new{ + 'in method missing' + block.call + } + "leave method_missing" + end + def respond + @response.call + end end + t = Controller.new + t.test_for_bug end - t = Controller.new - assert_true t.test_for_bug end assert("BS Block 33") do diff --git a/test/t/module.rb b/test/t/module.rb index f01245e88..b2dbe52a2 100644 --- a/test/t/module.rb +++ b/test/t/module.rb @@ -231,7 +231,7 @@ assert('Module#const_set', '15.2.2.4.23') do Const4Test4ConstSet = 42 end - assert_true Test4ConstSet.const_set(:Const4Test4ConstSet, 23) + assert_equal 23, Test4ConstSet.const_set(:Const4Test4ConstSet, 23) assert_equal 23, Test4ConstSet.const_get(:Const4Test4ConstSet) end -- cgit v1.2.3 From 244abdae09459e6dd8acf2d9a770925631088e60 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Wed, 20 Feb 2019 18:49:38 +0900 Subject: `assert_true`/`assert_false` should pass when actual is only `true`/`false` For the following reasons: - Previous behavior is confusable because it's different from test/unit rubygem's `assert_true` - Tests may pass unintentionally in an inappropriate way; ref #4285 #4287 --- test/assert.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/assert.rb b/test/assert.rb index ec6fa98ad..fbf1d926d 100644 --- a/test/assert.rb +++ b/test/assert.rb @@ -78,7 +78,7 @@ end def assert_true(ret, msg = nil, diff = nil) if $mrbtest_assert $mrbtest_assert_idx += 1 - unless ret + unless ret == true msg ||= "Expected #{ret.inspect} to be true" diff ||= assertion_diff(true, ret) $mrbtest_assert.push([$mrbtest_assert_idx, msg, diff]) @@ -88,7 +88,7 @@ def assert_true(ret, msg = nil, diff = nil) end def assert_false(ret, msg = nil, diff = nil) - if ret + unless ret == false msg ||= "Expected #{ret.inspect} to be false" diff ||= assertion_diff(false, ret) end -- cgit v1.2.3 From ad789944dbd53610fa1e1c7f80b125270d4bcc70 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Thu, 21 Feb 2019 17:44:45 +0900 Subject: Refactor exception handling in `assert` --- test/assert.rb | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/test/assert.rb b/test/assert.rb index ec6fa98ad..d8e8a0470 100644 --- a/test/assert.rb +++ b/test/assert.rb @@ -47,23 +47,21 @@ def assert(str = 'Assertion failed', iso = '') $mrbtest_assert_idx = 0 yield if($mrbtest_assert.size > 0) - $asserts.push(assertion_string('Fail: ', str, iso, nil)) + $asserts.push(assertion_string('Fail: ', str, iso)) $ko_test += 1 t_print('F') else $ok_test += 1 t_print('.') end + rescue MRubyTestSkip => e + $asserts.push(assertion_string('Skip: ', str, iso, e)) + t_print('?') rescue Exception => e bt = e.backtrace if $mrbtest_verbose - if e.class.to_s == 'MRubyTestSkip' - $asserts.push(assertion_string('Skip: ', str, iso, e, nil)) - t_print('?') - else - $asserts.push(assertion_string("#{e.class}: ", str, iso, e, bt)) - $kill_test += 1 - t_print('X') - end + $asserts.push(assertion_string("#{e.class}: ", str, iso, e, bt)) + $kill_test += 1 + t_print('X') ensure $mrbtest_assert = nil end -- cgit v1.2.3 From 37fb5f929ff5669af14b7753ce7c515f0839066d Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Thu, 21 Feb 2019 19:47:00 +0900 Subject: Fix typo in `lib/mruby/build/command.rb` --- lib/mruby/build/command.rb | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/lib/mruby/build/command.rb b/lib/mruby/build/command.rb index 694b4a24c..0f18e0e62 100644 --- a/lib/mruby/build/command.rb +++ b/lib/mruby/build/command.rb @@ -67,8 +67,8 @@ module MRuby path && build.filename("#{path}/#{name}").sub(/^"(.*)"$/, '\1') end - def all_flags(_defineds=[], _include_paths=[], _flags=[]) - define_flags = [defines, _defineds].flatten.map{ |d| option_define % d } + def all_flags(_defines=[], _include_paths=[], _flags=[]) + define_flags = [defines, _defines].flatten.map{ |d| option_define % d } include_path_flags = [include_paths, _include_paths].flatten.map do |f| if MRUBY_BUILD_HOST_IS_CYGWIN option_include_path % cygwin_filename(f) @@ -79,14 +79,14 @@ module MRuby [flags, define_flags, include_path_flags, _flags].flatten.join(' ') end - def run(outfile, infile, _defineds=[], _include_paths=[], _flags=[]) + def run(outfile, infile, _defines=[], _include_paths=[], _flags=[]) FileUtils.mkdir_p File.dirname(outfile) _pp "CC", infile.relative_path, outfile.relative_path if MRUBY_BUILD_HOST_IS_CYGWIN - _run compile_options, { :flags => all_flags(_defineds, _include_paths, _flags), + _run compile_options, { :flags => all_flags(_defines, _include_paths, _flags), :infile => cygwin_filename(infile), :outfile => cygwin_filename(outfile) } else - _run compile_options, { :flags => all_flags(_defineds, _include_paths, _flags), + _run compile_options, { :flags => all_flags(_defines, _include_paths, _flags), :infile => filename(infile), :outfile => filename(outfile) } end end -- cgit v1.2.3 From f209f781acdeb6dabafdab955f685daf6c5d1421 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Fri, 22 Feb 2019 20:41:20 +0900 Subject: Integrate `init_mrbtest.c` to `driver.c` in `mruby-test` mrbgem - `mrbgemtest_init()` is needed if `DISABLE_GEMS` is enabled because core tests are run as part of `mruby-test` mrbgem (moreover, `DISABLE_GEMS` is disabled when `enable_test` is used in build config). - For the same reason `mrb_open_core()` etc for core tests is unneeded. --- mrbgems/mruby-test/driver.c | 8 +++++--- mrbgems/mruby-test/init_mrbtest.c | 39 --------------------------------------- mrbgems/mruby-test/mrbgem.rake | 7 +++---- 3 files changed, 8 insertions(+), 46 deletions(-) delete mode 100644 mrbgems/mruby-test/init_mrbtest.c diff --git a/mrbgems/mruby-test/driver.c b/mrbgems/mruby-test/driver.c index 434d1fee5..4b2707319 100644 --- a/mrbgems/mruby-test/driver.c +++ b/mrbgems/mruby-test/driver.c @@ -18,8 +18,9 @@ #include #include -void -mrb_init_mrbtest(mrb_state *); +extern const uint8_t mrbtest_assert_irep[]; + +void mrbgemtest_init(mrb_state* mrb); /* Print a short remark for the user */ static void @@ -167,7 +168,8 @@ main(int argc, char **argv) } mrb_init_test_driver(mrb, verbose); - mrb_init_mrbtest(mrb); + mrb_load_irep(mrb, mrbtest_assert_irep); + mrbgemtest_init(mrb); ret = eval_test(mrb); mrb_close(mrb); diff --git a/mrbgems/mruby-test/init_mrbtest.c b/mrbgems/mruby-test/init_mrbtest.c deleted file mode 100644 index 7678a5200..000000000 --- a/mrbgems/mruby-test/init_mrbtest.c +++ /dev/null @@ -1,39 +0,0 @@ -#include -#include -#include -#include - -extern const uint8_t mrbtest_assert_irep[]; - -void mrbgemtest_init(mrb_state* mrb); -void mrb_init_test_driver(mrb_state* mrb, mrb_bool verbose); -void mrb_t_pass_result(mrb_state *mrb_dst, mrb_state *mrb_src); - -void -mrb_init_mrbtest(mrb_state *mrb) -{ - mrb_state *core_test; - - mrb_load_irep(mrb, mrbtest_assert_irep); - - core_test = mrb_open_core(mrb_default_allocf, NULL); - if (core_test == NULL) { - fprintf(stderr, "Invalid mrb_state, exiting %s", __FUNCTION__); - exit(EXIT_FAILURE); - } - mrb_init_test_driver(core_test, mrb_test(mrb_gv_get(mrb, mrb_intern_lit(mrb, "$mrbtest_verbose")))); - mrb_load_irep(core_test, mrbtest_assert_irep); - mrb_t_pass_result(mrb, core_test); - -#ifndef DISABLE_GEMS - mrbgemtest_init(mrb); -#endif - - if (mrb->exc) { - mrb_print_error(mrb); - mrb_close(mrb); - exit(EXIT_FAILURE); - } - mrb_close(core_test); -} - diff --git a/mrbgems/mruby-test/mrbgem.rake b/mrbgems/mruby-test/mrbgem.rake index 61bdf9ced..dcb7bb719 100644 --- a/mrbgems/mruby-test/mrbgem.rake +++ b/mrbgems/mruby-test/mrbgem.rake @@ -144,8 +144,6 @@ MRuby::Gem::Specification.new('mruby-test') do |spec| end end - init = "#{spec.dir}/init_mrbtest.c" - # store the last gem selection and make the re-build # of the test gem depending on a change to the gem # selection @@ -164,7 +162,7 @@ MRuby::Gem::Specification.new('mruby-test') do |spec| file clib => active_gems_path if active_gem_list != current_gem_list file mlib => clib - file clib => [init, build.mrbcfile, __FILE__] do |_t| + file clib => [build.mrbcfile, __FILE__] do |_t| _pp "GEN", "*.rb", "#{clib.relative_path}" FileUtils.mkdir_p File.dirname(clib) open(clib, 'w') do |f| @@ -177,7 +175,8 @@ MRuby::Gem::Specification.new('mruby-test') do |spec| f.puts %Q[ * All manual changes will get lost.] f.puts %Q[ */] f.puts %Q[] - f.puts IO.read(init) + f.puts %Q[struct mrb_state;] + f.puts %Q[typedef struct mrb_state mrb_state;] build.gems.each do |g| f.puts %Q[void GENERATED_TMP_mrb_#{g.funcname}_gem_test(mrb_state *mrb);] end -- cgit v1.2.3 From 31f1b4a553c4c887c2435440e044f79eceb4dc4c Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Sat, 23 Feb 2019 18:29:37 +0900 Subject: Remove explicit set of `DISABLE_GEMS` `DISABLE_GEMS` is automatically set (or unset); ref #790 --- build_config.rb | 2 +- tasks/toolchains/gcc.rake | 2 -- tasks/toolchains/openwrt.rake | 2 -- tasks/toolchains/visualcpp.rake | 4 ++-- 4 files changed, 3 insertions(+), 7 deletions(-) diff --git a/build_config.rb b/build_config.rb index 7f52b5ee9..751317c7a 100644 --- a/build_config.rb +++ b/build_config.rb @@ -29,7 +29,7 @@ MRuby::Build.new do |conf| # cc.command = ENV['CC'] || 'gcc' # cc.flags = [ENV['CFLAGS'] || %w()] # cc.include_paths = ["#{root}/include"] - # cc.defines = %w(DISABLE_GEMS) + # cc.defines = %w() # cc.option_include_path = '-I%s' # cc.option_define = '-D%s' # cc.compile_options = "%{flags} -MMD -o %{outfile} -c %{infile}" diff --git a/tasks/toolchains/gcc.rake b/tasks/toolchains/gcc.rake index 4929811c4..2d1e70e6e 100644 --- a/tasks/toolchains/gcc.rake +++ b/tasks/toolchains/gcc.rake @@ -2,7 +2,6 @@ MRuby::Toolchain.new(:gcc) do |conf, _params| [conf.cc, conf.objc, conf.asm].each do |cc| cc.command = ENV['CC'] || 'gcc' cc.flags = [ENV['CFLAGS'] || %w(-g -std=gnu99 -O3 -Wall -Werror-implicit-function-declaration -Wdeclaration-after-statement -Wwrite-strings -Wundef)] - cc.defines = %w(DISABLE_GEMS) cc.option_include_path = '-I%s' cc.option_define = '-D%s' cc.compile_options = '%{flags} -MMD -o %{outfile} -c %{infile}' @@ -13,7 +12,6 @@ MRuby::Toolchain.new(:gcc) do |conf, _params| [conf.cxx].each do |cxx| cxx.command = ENV['CXX'] || 'g++' cxx.flags = [ENV['CXXFLAGS'] || ENV['CFLAGS'] || %w(-g -O3 -Wall -Werror-implicit-function-declaration -Wundef)] - cxx.defines = %w(DISABLE_GEMS) cxx.option_include_path = '-I%s' cxx.option_define = '-D%s' cxx.compile_options = '%{flags} -MMD -o %{outfile} -c %{infile}' diff --git a/tasks/toolchains/openwrt.rake b/tasks/toolchains/openwrt.rake index 1637f6d91..aeb6dbcbc 100644 --- a/tasks/toolchains/openwrt.rake +++ b/tasks/toolchains/openwrt.rake @@ -5,7 +5,6 @@ MRuby::Toolchain.new(:openwrt) do |conf| cc.command = ENV['TARGET_CC'] cc.flags = ENV['TARGET_CFLAGS'] cc.include_paths = ["#{MRUBY_ROOT}/include"] - cc.defines = %w(DISABLE_GEMS) cc.option_include_path = '-I%s' cc.option_define = '-D%s' cc.compile_options = '%{flags} -MMD -o %{outfile} -c %{infile}' @@ -15,7 +14,6 @@ MRuby::Toolchain.new(:openwrt) do |conf| cxx.command = ENV['TARGET_CXX'] cxx.flags = ENV['TARGET_CXXFLAGS'] cxx.include_paths = ["#{MRUBY_ROOT}/include"] - cxx.defines = %w(DISABLE_GEMS) cxx.option_include_path = '-I%s' cxx.option_define = '-D%s' cxx.compile_options = '%{flags} -MMD -o %{outfile} -c %{infile}' diff --git a/tasks/toolchains/visualcpp.rake b/tasks/toolchains/visualcpp.rake index b008273a2..6275059bb 100644 --- a/tasks/toolchains/visualcpp.rake +++ b/tasks/toolchains/visualcpp.rake @@ -3,7 +3,7 @@ MRuby::Toolchain.new(:visualcpp) do |conf, _params| cc.command = ENV['CC'] || 'cl.exe' # C4013: implicit function declaration cc.flags = [ENV['CFLAGS'] || %w(/c /nologo /W3 /we4013 /Zi /MD /O2 /D_CRT_SECURE_NO_WARNINGS)] - cc.defines = %w(DISABLE_GEMS MRB_STACK_EXTEND_DOUBLING) + cc.defines = %w(MRB_STACK_EXTEND_DOUBLING) cc.option_include_path = '/I%s' cc.option_define = '/D%s' cc.compile_options = "%{flags} /Fo%{outfile} %{infile}" @@ -14,7 +14,7 @@ MRuby::Toolchain.new(:visualcpp) do |conf, _params| conf.cxx do |cxx| cxx.command = ENV['CXX'] || 'cl.exe' cxx.flags = [ENV['CXXFLAGS'] || ENV['CFLAGS'] || %w(/c /nologo /W3 /Zi /MD /O2 /EHs /D_CRT_SECURE_NO_WARNINGS)] - cxx.defines = %w(DISABLE_GEMS MRB_STACK_EXTEND_DOUBLING) + cxx.defines = %w(MRB_STACK_EXTEND_DOUBLING) cxx.option_include_path = '/I%s' cxx.option_define = '/D%s' cxx.compile_options = "%{flags} /Fo%{outfile} %{infile}" -- cgit v1.2.3 From e91f3ec770e2dd5e2828e510f8566f86136d9f6a Mon Sep 17 00:00:00 2001 From: Wataru Ashihara Date: Sun, 24 Feb 2019 16:57:22 +0900 Subject: Move `Object#dig` to `Struct#dig` This method seems to be mistakenly put into `Object` instead of `Struct` since it's in `struct.rb` and daf83946b says: add #dig to Array,Hash and Struct --- mrbgems/mruby-struct/mrblib/struct.rb | 31 +++++++++++++++---------------- 1 file changed, 15 insertions(+), 16 deletions(-) diff --git a/mrbgems/mruby-struct/mrblib/struct.rb b/mrbgems/mruby-struct/mrblib/struct.rb index 7cf3dd3ab..c5b5354be 100644 --- a/mrbgems/mruby-struct/mrblib/struct.rb +++ b/mrbgems/mruby-struct/mrblib/struct.rb @@ -81,23 +81,22 @@ if Object.const_defined?(:Struct) # 15.2.18.4.11(x) # alias to_s inspect - end - ## - # call-seq: - # hsh.dig(key,...) -> object - # - # Extracts the nested value specified by the sequence of key - # objects by calling +dig+ at each step, returning +nil+ if any - # intermediate step is +nil+. - # - def dig(idx,*args) - n = self[idx] - if args.size > 0 - n&.dig(*args) - else - n + ## + # call-seq: + # hsh.dig(key,...) -> object + # + # Extracts the nested value specified by the sequence of key + # objects by calling +dig+ at each step, returning +nil+ if any + # intermediate step is +nil+. + # + def dig(idx,*args) + n = self[idx] + if args.size > 0 + n&.dig(*args) + else + n + end end end end - -- cgit v1.2.3 From 5c402039306346e85646cd2818fc401890dd6914 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Sun, 24 Feb 2019 19:21:40 +0900 Subject: Refine mrbgem name in assertion failure/skip message for core test --- test/assert.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/assert.rb b/test/assert.rb index 3bbe79e2e..a1d3482f4 100644 --- a/test/assert.rb +++ b/test/assert.rb @@ -22,7 +22,7 @@ def assertion_string(err, str, iso=nil, e=nil, bt=nil) msg += " [#{iso}]" if iso && iso != '' msg += " => #{e.cause}" if e && e.respond_to?(:cause) msg += " => #{e.message}" if e && !e.respond_to?(:cause) - msg += " (mrbgems: #{GEMNAME})" if Object.const_defined?(:GEMNAME) + msg += " (#{GEMNAME == 'mruby-test' ? 'core' : "mrbgems: #{GEMNAME}"})" if $mrbtest_assert && $mrbtest_assert.size > 0 $mrbtest_assert.each do |idx, assert_msg, diff| msg += "\n - Assertion[#{idx}] Failed: #{assert_msg}\n#{diff}" -- cgit v1.2.3 From c49a10f9a0bb0b07bd15806520f10dd4bb3b4767 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Mon, 25 Feb 2019 20:39:20 +0900 Subject: Refactor `src/backtrace.c` - Move calling `mrb_debug_get_filename()` to after `lineno` check. - Remove unneeded array check in `print_backtrace()`. - Add a few `const` qualifier. --- src/backtrace.c | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/src/backtrace.c b/src/backtrace.c index 8f28c71cb..521cd6c1b 100644 --- a/src/backtrace.c +++ b/src/backtrace.c @@ -21,7 +21,7 @@ struct backtrace_location { const char *filename; }; -typedef void (*each_backtrace_func)(mrb_state*, struct backtrace_location*, void*); +typedef void (*each_backtrace_func)(mrb_state*, const struct backtrace_location*, void*); static const mrb_data_type bt_type = { "Backtrace", mrb_free }; @@ -57,11 +57,11 @@ each_backtrace(mrb_state *mrb, ptrdiff_t ciidx, mrb_code *pc0, each_backtrace_fu else { pc = pc0; } - loc.filename = mrb_debug_get_filename(irep, pc - irep->iseq); - loc.lineno = mrb_debug_get_line(irep, pc - irep->iseq); + loc.lineno = mrb_debug_get_line(irep, pc - irep->iseq); if (loc.lineno == -1) continue; + loc.filename = mrb_debug_get_filename(irep, pc - irep->iseq); if (!loc.filename) { loc.filename = "(unknown)"; } @@ -80,8 +80,6 @@ print_backtrace(mrb_state *mrb, mrb_value backtrace) mrb_int n; FILE *stream = stderr; - if (!mrb_array_p(backtrace)) return; - n = RARRAY_LEN(backtrace) - 1; if (n == 0) return; @@ -96,7 +94,7 @@ print_backtrace(mrb_state *mrb, mrb_value backtrace) } static int -packed_bt_len(struct backtrace_location *bt, int n) +packed_bt_len(const struct backtrace_location *bt, int n) { int len = 0; int i; @@ -113,7 +111,7 @@ static void print_packed_backtrace(mrb_state *mrb, mrb_value packed) { FILE *stream = stderr; - struct backtrace_location *bt; + const struct backtrace_location *bt; int n, i; int ai = mrb_gc_arena_save(mrb); @@ -124,7 +122,7 @@ print_packed_backtrace(mrb_state *mrb, mrb_value packed) if (packed_bt_len(bt, n) == 0) return; fprintf(stream, "trace (most recent call last):\n"); for (i = 0; ifilename == NULL) continue; fprintf(stream, "\t[%d] %s:%d", i, entry->filename, entry->lineno); if (entry->method_id != 0) { @@ -172,7 +170,7 @@ mrb_print_backtrace(mrb_state *mrb) static void count_backtrace_i(mrb_state *mrb, - struct backtrace_location *loc, + const struct backtrace_location *loc, void *data) { int *lenp = (int*)data; @@ -183,7 +181,7 @@ count_backtrace_i(mrb_state *mrb, static void pack_backtrace_i(mrb_state *mrb, - struct backtrace_location *loc, + const struct backtrace_location *loc, void *data) { struct backtrace_location **pptr = (struct backtrace_location**)data; @@ -229,7 +227,7 @@ mrb_keep_backtrace(mrb_state *mrb, mrb_value exc) mrb_value mrb_unpack_backtrace(mrb_state *mrb, mrb_value backtrace) { - struct backtrace_location *bt; + const struct backtrace_location *bt; mrb_int n, i; int ai; @@ -244,7 +242,7 @@ mrb_unpack_backtrace(mrb_state *mrb, mrb_value backtrace) backtrace = mrb_ary_new_capa(mrb, n); ai = mrb_gc_arena_save(mrb); for (i = 0; i < n; i++) { - struct backtrace_location *entry = &bt[i]; + const struct backtrace_location *entry = &bt[i]; mrb_value btline; if (entry->filename == NULL) continue; -- cgit v1.2.3 From c6cd69970bcb43adbba40111757d57ea85a4899b Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Tue, 26 Feb 2019 21:12:41 +0900 Subject: Remove unneeded `const_defined?(:Time)` in `mruby-io` test `mruby-time` is included in test dependencies. --- mrbgems/mruby-io/test/file.rb | 3 --- 1 file changed, 3 deletions(-) diff --git a/mrbgems/mruby-io/test/file.rb b/mrbgems/mruby-io/test/file.rb index 539e25047..ba4100492 100644 --- a/mrbgems/mruby-io/test/file.rb +++ b/mrbgems/mruby-io/test/file.rb @@ -69,9 +69,6 @@ assert('File#flock') do end assert('File#mtime') do - unless Object.const_defined?(:Time) - skip "File#mtime require Time" - end begin File.open("#{$mrbtest_io_wfname}.mtime", 'w') do |f| assert_equal Time, f.mtime.class -- cgit v1.2.3 From fdb7f9dad3be87e782831aae94188039dd0fecf9 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Tue, 26 Feb 2019 21:32:34 +0900 Subject: Remove unneeded `=>` in test skip/error messages --- test/assert.rb | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/test/assert.rb b/test/assert.rb index a1d3482f4..d6e394a9f 100644 --- a/test/assert.rb +++ b/test/assert.rb @@ -20,8 +20,10 @@ end def assertion_string(err, str, iso=nil, e=nil, bt=nil) msg = "#{err}#{str}" msg += " [#{iso}]" if iso && iso != '' - msg += " => #{e.cause}" if e && e.respond_to?(:cause) - msg += " => #{e.message}" if e && !e.respond_to?(:cause) + if e + m = e.respond_to?(:cause) ? e.cause : e.message + msg += " => #{m}" if m && !m.empty? + end msg += " (#{GEMNAME == 'mruby-test' ? 'core' : "mrbgems: #{GEMNAME}"})" if $mrbtest_assert && $mrbtest_assert.size > 0 $mrbtest_assert.each do |idx, assert_msg, diff| -- cgit v1.2.3 From 289462508980b5231f812f8a34229ad8cdb33ca9 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Wed, 27 Feb 2019 20:21:40 +0900 Subject: Use `yywarning()` instead of `yywarning_s()` for `MRB_WITHOUT_FLOAT` --- mrbgems/mruby-compiler/core/parse.y | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mrbgems/mruby-compiler/core/parse.y b/mrbgems/mruby-compiler/core/parse.y index 1b2d64b25..82aa346d0 100644 --- a/mrbgems/mruby-compiler/core/parse.y +++ b/mrbgems/mruby-compiler/core/parse.y @@ -5167,7 +5167,7 @@ parser_yylex(parser_state *p) tokfix(p); if (is_float) { #ifdef MRB_WITHOUT_FLOAT - yywarning_s(p, "floating point numbers are not supported", tok(p)); + yywarning(p, "floating point numbers are not supported"); pylval.nd = new_int(p, "0", 10); return tINTEGER; #else -- cgit v1.2.3 From c11bd075f78e1f9d4b9a18401ce3292809433038 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Wed, 27 Feb 2019 20:27:29 +0900 Subject: Remove unnecessary backticks; ref #2858 --- mrbgems/mruby-compiler/core/parse.y | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mrbgems/mruby-compiler/core/parse.y b/mrbgems/mruby-compiler/core/parse.y index 1b2d64b25..1efc0ea9d 100644 --- a/mrbgems/mruby-compiler/core/parse.y +++ b/mrbgems/mruby-compiler/core/parse.y @@ -4568,7 +4568,7 @@ parser_yylex(parser_state *p) } pushback(p, c); if (IS_SPCARG(c)) { - yywarning(p, "`**' interpreted as argument prefix"); + yywarning(p, "'**' interpreted as argument prefix"); c = tDSTAR; } else if (IS_BEG()) { -- cgit v1.2.3 From 62bb9c643629883c8e1b6ea37791f4c64468f4c2 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Wed, 27 Feb 2019 20:58:20 +0900 Subject: Add newline to warning by `mrb_warn()` --- src/error.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/error.c b/src/error.c index 57cdfcfe1..50d1ab6f9 100644 --- a/src/error.c +++ b/src/error.c @@ -376,6 +376,7 @@ mrb_warn(mrb_state *mrb, const char *fmt, ...) str = mrb_vformat(mrb, fmt, ap); fputs("warning: ", stderr); fwrite(RSTRING_PTR(str), RSTRING_LEN(str), 1, stderr); + putc('\n', stderr); va_end(ap); #endif } -- cgit v1.2.3 From cece0163895c9f62b6b7ffb8724acba1217bf9ab Mon Sep 17 00:00:00 2001 From: dearblue Date: Wed, 27 Feb 2019 20:18:50 +0900 Subject: Concatenate string literals --- mrbgems/mruby-compiler/core/parse.y | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/mrbgems/mruby-compiler/core/parse.y b/mrbgems/mruby-compiler/core/parse.y index 82aa346d0..09088f3c3 100644 --- a/mrbgems/mruby-compiler/core/parse.y +++ b/mrbgems/mruby-compiler/core/parse.y @@ -852,6 +852,12 @@ new_dstr(parser_state *p, node *a) return cons((node*)NODE_DSTR, a); } +static node* +concat_string(parser_state *p, node *a, node *b) +{ + return new_dstr(p, list2(a, b)); +} + /* (:str . (s . len)) */ static node* new_xstr(parser_state *p, const char *s, int len) @@ -1200,7 +1206,7 @@ heredoc_end(parser_state *p) %token tNTH_REF tBACK_REF %token tREGEXP_END -%type singleton string string_rep string_interp xstring regexp +%type singleton string string_fragment string_rep string_interp xstring regexp %type literal numeric cpath symbol %type top_compstmt top_stmts top_stmt %type bodystmt compstmt stmts stmt expr arg primary command command_call method_call @@ -2852,7 +2858,14 @@ literal : numeric | symbols ; -string : tCHAR +string : string_fragment + | string string_fragment + { + $$ = concat_string(p, $1, $2); + } + ; + +string_fragment : tCHAR | tSTRING | tSTRING_BEG tSTRING { @@ -3478,7 +3491,7 @@ assoc : arg tASSOC arg void_expr_error(p, $3); $$ = cons(new_sym(p, $1), $3); } - | string tLABEL_TAG arg + | string_fragment tLABEL_TAG arg { void_expr_error(p, $3); if ($1->car == (node*)NODE_DSTR) { -- cgit v1.2.3 From 9913643ed8a6d778bc90a932e30e6113e8b3f9e3 Mon Sep 17 00:00:00 2001 From: dearblue Date: Wed, 27 Feb 2019 21:42:37 +0900 Subject: Compositing `NODE_STR` and `NODE_STR` --- mrbgems/mruby-compiler/core/parse.y | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/mrbgems/mruby-compiler/core/parse.y b/mrbgems/mruby-compiler/core/parse.y index 09088f3c3..e80af7d6d 100644 --- a/mrbgems/mruby-compiler/core/parse.y +++ b/mrbgems/mruby-compiler/core/parse.y @@ -855,6 +855,21 @@ new_dstr(parser_state *p, node *a) static node* concat_string(parser_state *p, node *a, node *b) { + if ((enum node_type)(intptr_t)a->car == NODE_STR) { + if ((enum node_type)(intptr_t)b->car == NODE_STR) { + /* a == NODE_STR && b == NODE_STR */ + size_t newlen = (size_t)a->cdr->cdr + (size_t)b->cdr->cdr; + char *str = (char*)mrb_pool_realloc(p->pool, a->cdr->car, (size_t)a->cdr->cdr + 1, newlen + 1); + memcpy(str + (size_t)a->cdr->cdr, b->cdr->car, (size_t)b->cdr->cdr); + str[newlen] = '\0'; + a->cdr->car = (node*)str; + a->cdr->cdr = (node*)newlen; + cons_free(b->cdr); + cons_free(b); + return a; + } + } + return new_dstr(p, list2(a, b)); } -- cgit v1.2.3 From 477e5285e86afb5f33e74747a54201718a249489 Mon Sep 17 00:00:00 2001 From: dearblue Date: Wed, 27 Feb 2019 21:46:07 +0900 Subject: Replacement to function for `NODE_STR` cheking --- mrbgems/mruby-compiler/core/parse.y | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/mrbgems/mruby-compiler/core/parse.y b/mrbgems/mruby-compiler/core/parse.y index e80af7d6d..2771ddeed 100644 --- a/mrbgems/mruby-compiler/core/parse.y +++ b/mrbgems/mruby-compiler/core/parse.y @@ -852,11 +852,17 @@ new_dstr(parser_state *p, node *a) return cons((node*)NODE_DSTR, a); } +static int +string_node_p(node *n) +{ + return (int)((enum node_type)(intptr_t)n->car == NODE_STR); +} + static node* concat_string(parser_state *p, node *a, node *b) { - if ((enum node_type)(intptr_t)a->car == NODE_STR) { - if ((enum node_type)(intptr_t)b->car == NODE_STR) { + if (string_node_p(a)) { + if (string_node_p(b)) { /* a == NODE_STR && b == NODE_STR */ size_t newlen = (size_t)a->cdr->cdr + (size_t)b->cdr->cdr; char *str = (char*)mrb_pool_realloc(p->pool, a->cdr->car, (size_t)a->cdr->cdr + 1, newlen + 1); -- cgit v1.2.3 From 25957421bcea8070a796428c4dc6638142ffbb56 Mon Sep 17 00:00:00 2001 From: dearblue Date: Wed, 27 Feb 2019 21:49:41 +0900 Subject: Replacement to function for composite two string nodes --- mrbgems/mruby-compiler/core/parse.y | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/mrbgems/mruby-compiler/core/parse.y b/mrbgems/mruby-compiler/core/parse.y index 2771ddeed..ea292c3b9 100644 --- a/mrbgems/mruby-compiler/core/parse.y +++ b/mrbgems/mruby-compiler/core/parse.y @@ -858,19 +858,26 @@ string_node_p(node *n) return (int)((enum node_type)(intptr_t)n->car == NODE_STR); } +static node* +composite_string_node(parser_state *p, node *a, node *b) +{ + size_t newlen = (size_t)a->cdr + (size_t)b->cdr; + char *str = (char*)mrb_pool_realloc(p->pool, a->car, (size_t)a->cdr + 1, newlen + 1); + memcpy(str + (size_t)a->cdr, b->car, (size_t)b->cdr); + str[newlen] = '\0'; + a->car = (node*)str; + a->cdr = (node*)newlen; + cons_free(b); + return a; +} + static node* concat_string(parser_state *p, node *a, node *b) { if (string_node_p(a)) { if (string_node_p(b)) { /* a == NODE_STR && b == NODE_STR */ - size_t newlen = (size_t)a->cdr->cdr + (size_t)b->cdr->cdr; - char *str = (char*)mrb_pool_realloc(p->pool, a->cdr->car, (size_t)a->cdr->cdr + 1, newlen + 1); - memcpy(str + (size_t)a->cdr->cdr, b->cdr->car, (size_t)b->cdr->cdr); - str[newlen] = '\0'; - a->cdr->car = (node*)str; - a->cdr->cdr = (node*)newlen; - cons_free(b->cdr); + composite_string_node(p, a->cdr, b->cdr); cons_free(b); return a; } -- cgit v1.2.3 From 8ead6da9132e57f2b8e47e4dfb793aa1b90e5daa Mon Sep 17 00:00:00 2001 From: dearblue Date: Wed, 27 Feb 2019 20:21:35 +0900 Subject: Compositing `NODE_STR` and `NODE_DSTR` --- mrbgems/mruby-compiler/core/parse.y | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/mrbgems/mruby-compiler/core/parse.y b/mrbgems/mruby-compiler/core/parse.y index ea292c3b9..4c884fa92 100644 --- a/mrbgems/mruby-compiler/core/parse.y +++ b/mrbgems/mruby-compiler/core/parse.y @@ -881,6 +881,17 @@ concat_string(parser_state *p, node *a, node *b) cons_free(b); return a; } + else { + /* a == NODE_STR && b == NODE_DSTR */ + + if (string_node_p(b->cdr->car)) { + /* a == NODE_STR && b->[NODE_STR, ...] */ + composite_string_node(p, a->cdr, b->cdr->car->cdr); + cons_free(b->cdr->car); + b->cdr->car = a; + return b; + } + } } return new_dstr(p, list2(a, b)); -- cgit v1.2.3 From 4d2bb3cb47b3628eb140d1d28f79f29887cf6262 Mon Sep 17 00:00:00 2001 From: dearblue Date: Wed, 27 Feb 2019 20:22:24 +0900 Subject: Compositing `NODE_DSTR` and `NODE_STR` --- mrbgems/mruby-compiler/core/parse.y | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/mrbgems/mruby-compiler/core/parse.y b/mrbgems/mruby-compiler/core/parse.y index 4c884fa92..fed8cfbbc 100644 --- a/mrbgems/mruby-compiler/core/parse.y +++ b/mrbgems/mruby-compiler/core/parse.y @@ -893,6 +893,21 @@ concat_string(parser_state *p, node *a, node *b) } } } + else if (string_node_p(b)) { + /* a == NODE_DSTR && b == NODE_STR */ + + node *c; + for (c = a; c->cdr != NULL; c = c->cdr) ; + if (string_node_p(c->car)) { + /* a->[..., NODE_STR] && b == NODE_STR */ + composite_string_node(p, c->car->cdr, b->cdr); + cons_free(b); + return a; + } + + push(a, b); + return a; + } return new_dstr(p, list2(a, b)); } -- cgit v1.2.3 From e871a1538d2c84c56d102656d393ecf630f4deef Mon Sep 17 00:00:00 2001 From: dearblue Date: Wed, 27 Feb 2019 20:22:55 +0900 Subject: Compositing `NODE_DSTR` and `NODE_DSTR` --- mrbgems/mruby-compiler/core/parse.y | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/mrbgems/mruby-compiler/core/parse.y b/mrbgems/mruby-compiler/core/parse.y index fed8cfbbc..57eb03cc6 100644 --- a/mrbgems/mruby-compiler/core/parse.y +++ b/mrbgems/mruby-compiler/core/parse.y @@ -908,6 +908,27 @@ concat_string(parser_state *p, node *a, node *b) push(a, b); return a; } + else { + /* a == NODE_DSTR && b == NODE_DSTR */ + + node *c, *d; + for (c = a; c->cdr != NULL; c = c->cdr) ; + if (string_node_p(c->car) && string_node_p(b->cdr->car)) { + /* a->[..., NODE_STR] && b->[NODE_STR, ...] */ + d = b->cdr; + cons_free(b); + composite_string_node(p, c->car->cdr, d->car->cdr); + cons_free(d->car); + c->cdr = d->cdr; + cons_free(d); + return a; + } + else { + c->cdr = b->cdr; + cons_free(b); + return a; + } + } return new_dstr(p, list2(a, b)); } -- cgit v1.2.3 From f9a568adcb1bd00a5580c0663ccad0a4db5719db Mon Sep 17 00:00:00 2001 From: dearblue Date: Wed, 27 Feb 2019 22:29:55 +0900 Subject: Add test for string literal concatenation --- test/t/string.rb | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/test/t/string.rb b/test/t/string.rb index 7f81c9335..5e92ae345 100644 --- a/test/t/string.rb +++ b/test/t/string.rb @@ -713,3 +713,10 @@ assert('String#freeze') do assert_raise(RuntimeError) { str.upcase! } end + +assert('String literal concatenation') do + assert_equal 2, ("A" "B").size + assert_equal 3, ('A' "B" 'C').size + assert_equal 3, (?A "#{?B}C").size + assert_equal 4, (%(A) "B#{?C}" "D").size +end -- cgit v1.2.3 From f1fb2bf29eeb8144326230b62c83b9ec72a89a59 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Thu, 28 Feb 2019 08:38:01 +0900 Subject: Remove `?A` style string literals from string tests; #4303 We have a plan to obsolete this style in the future. --- test/t/string.rb | 1 - 1 file changed, 1 deletion(-) diff --git a/test/t/string.rb b/test/t/string.rb index 5e92ae345..7d3dd3c9c 100644 --- a/test/t/string.rb +++ b/test/t/string.rb @@ -717,6 +717,5 @@ end assert('String literal concatenation') do assert_equal 2, ("A" "B").size assert_equal 3, ('A' "B" 'C').size - assert_equal 3, (?A "#{?B}C").size assert_equal 4, (%(A) "B#{?C}" "D").size end -- cgit v1.2.3 From d25b9c9d0ef6498dd9ae58fcf6bb9b438cfcccb0 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Thu, 28 Feb 2019 12:59:16 +0900 Subject: Remove unnecessary backticks; ref #4301 --- mrbgems/mruby-method/mrblib/kernel.rb | 2 +- mrbgems/mruby-method/src/method.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/mrbgems/mruby-method/mrblib/kernel.rb b/mrbgems/mruby-method/mrblib/kernel.rb index 2efc93f37..eb17df5a6 100644 --- a/mrbgems/mruby-method/mrblib/kernel.rb +++ b/mrbgems/mruby-method/mrblib/kernel.rb @@ -3,7 +3,7 @@ module Kernel m = method(name) sc = (class < Date: Thu, 28 Feb 2019 19:54:45 +0900 Subject: Add `warning: ` prefix to parser warning message --- mrbgems/mruby-compiler/core/parse.y | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mrbgems/mruby-compiler/core/parse.y b/mrbgems/mruby-compiler/core/parse.y index e281a5a6d..0aabc2f34 100644 --- a/mrbgems/mruby-compiler/core/parse.y +++ b/mrbgems/mruby-compiler/core/parse.y @@ -3708,10 +3708,10 @@ yywarn(parser_state *p, const char *s) if (! p->capture_errors) { #ifndef MRB_DISABLE_STDIO if (p->filename) { - fprintf(stderr, "%s:%d:%d: %s\n", p->filename, p->lineno, p->column, s); + fprintf(stderr, "%s:%d:%d: warning: %s\n", p->filename, p->lineno, p->column, s); } else { - fprintf(stderr, "line %d:%d: %s\n", p->lineno, p->column, s); + fprintf(stderr, "line %d:%d: warning: %s\n", p->lineno, p->column, s); } #endif } -- cgit v1.2.3 From 13e0a48e3cac92d9d6063769ab6ac60ada8d393e Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Sat, 2 Mar 2019 13:50:56 +0900 Subject: Print length of the `iseq` in code dump header; fix #4304 --- src/codedump.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/codedump.c b/src/codedump.c index 4d56fd427..c9c3b25ef 100644 --- a/src/codedump.c +++ b/src/codedump.c @@ -74,8 +74,8 @@ codedump(mrb_state *mrb, mrb_irep *irep) const char *file = NULL, *next_file; if (!irep) return; - printf("irep %p nregs=%d nlocals=%d pools=%d syms=%d reps=%d\n", (void*)irep, - irep->nregs, irep->nlocals, (int)irep->plen, (int)irep->slen, (int)irep->rlen); + printf("irep %p nregs=%d nlocals=%d pools=%d syms=%d reps=%d iseq=%d\n", (void*)irep, + irep->nregs, irep->nlocals, (int)irep->plen, (int)irep->slen, (int)irep->rlen, (int)irep->ilen); if (irep->lv) { int i; -- cgit v1.2.3 From 997cc8238d44ce1919c82a6bfdf1d35e2b783fd2 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Sat, 2 Mar 2019 14:00:25 +0900 Subject: Remove useless regression tests; fix #4306 --- test/t/array.rb | 7 ------- 1 file changed, 7 deletions(-) diff --git a/test/t/array.rb b/test/t/array.rb index c182d5e14..38d5732ac 100644 --- a/test/t/array.rb +++ b/test/t/array.rb @@ -361,13 +361,6 @@ end # Not ISO specified -assert("Array (Shared Array Corruption)") do - a = [ "a", "b", "c", "d", "e", "f" ] - b = a.slice(1, 3) - a.clear - b.clear -end - assert("Array (Longish inline array)") do ary = [[0, 0], [1, 1], [2, 2], [3, 3], [4, 4], [5, 5], [6, 6], [7, 7], [8, 8], [9, 9], [10, 10], [11, 11], [12, 12], [13, 13], [14, 14], [15, 15], [16, 16], [17, 17], [18, 18], [19, 19], [20, 20], [21, 21], [22, 22], [23, 23], [24, 24], [25, 25], [26, 26], [27, 27], [28, 28], [29, 29], [30, 30], [31, 31], [32, 32], [33, 33], [34, 34], [35, 35], [36, 36], [37, 37], [38, 38], [39, 39], [40, 40], [41, 41], [42, 42], [43, 43], [44, 44], [45, 45], [46, 46], [47, 47], [48, 48], [49, 49], [50, 50], [51, 51], [52, 52], [53, 53], [54, 54], [55, 55], [56, 56], [57, 57], [58, 58], [59, 59], [60, 60], [61, 61], [62, 62], [63, 63], [64, 64], [65, 65], [66, 66], [67, 67], [68, 68], [69, 69], [70, 70], [71, 71], [72, 72], [73, 73], [74, 74], [75, 75], [76, 76], [77, 77], [78, 78], [79, 79], [80, 80], [81, 81], [82, 82], [83, 83], [84, 84], [85, 85], [86, 86], [87, 87], [88, 88], [89, 89], [90, 90], [91, 91], [92, 92], [93, 93], [94, 94], [95, 95], [96, 96], [97, 97], [98, 98], [99, 99], [100, 100], [101, 101], [102, 102], [103, 103], [104, 104], [105, 105], [106, 106], [107, 107], [108, 108], [109, 109], [110, 110], [111, 111], [112, 112], [113, 113], [114, 114], [115, 115], [116, 116], [117, 117], [118, 118], [119, 119], [120, 120], [121, 121], [122, 122], [123, 123], [124, 124], [125, 125], [126, 126], [127, 127], [128, 128], [129, 129], [130, 130], [131, 131], [132, 132], [133, 133], [134, 134], [135, 135], [136, 136], [137, 137], [138, 138], [139, 139], [140, 140], [141, 141], [142, 142], [143, 143], [144, 144], [145, 145], [146, 146], [147, 147], [148, 148], [149, 149], [150, 150], [151, 151], [152, 152], [153, 153], [154, 154], [155, 155], [156, 156], [157, 157], [158, 158], [159, 159], [160, 160], [161, 161], [162, 162], [163, 163], [164, 164], [165, 165], [166, 166], [167, 167], [168, 168], [169, 169], [170, 170], [171, 171], [172, 172], [173, 173], [174, 174], [175, 175], [176, 176], [177, 177], [178, 178], [179, 179], [180, 180], [181, 181], [182, 182], [183, 183], [184, 184], [185, 185], [186, 186], [187, 187], [188, 188], [189, 189], [190, 190], [191, 191], [192, 192], [193, 193], [194, 194], [195, 195], [196, 196], [197, 197], [198, 198], [199, 199]] h = Hash.new(0) -- cgit v1.2.3 From e5649eba709a1479e32f332acdb0d847ef10c582 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Sat, 2 Mar 2019 14:01:52 +0900 Subject: Remove useless regression tests; ref #4306 --- test/t/array.rb | 7 ------- 1 file changed, 7 deletions(-) diff --git a/test/t/array.rb b/test/t/array.rb index 38d5732ac..f9f4ce19a 100644 --- a/test/t/array.rb +++ b/test/t/array.rb @@ -392,10 +392,3 @@ assert('Array#freeze') do a[0] = 1 end end - -assert('shared array replace') do - a = [0] * 40 - b = [0, 1, 2] - b.replace a[1, 20].dup - assert_equal 20, b.size -end -- cgit v1.2.3 From ca0dcbb22662eda2f6843cca14256c57cbd585e4 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Sat, 2 Mar 2019 14:13:06 +0900 Subject: Free `struct mrb_time` before error; fix #4308 To avoid memory leak from `time_update_datetime`. --- mrbgems/mruby-time/src/time.c | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/mrbgems/mruby-time/src/time.c b/mrbgems/mruby-time/src/time.c index d70fb442c..7f6c3004d 100644 --- a/mrbgems/mruby-time/src/time.c +++ b/mrbgems/mruby-time/src/time.c @@ -198,9 +198,10 @@ struct mrb_time { static const struct mrb_data_type mrb_time_type = { "Time", mrb_free }; /** Updates the datetime of a mrb_time based on it's timezone and -seconds setting. Returns self on success, NULL of failure. */ + seconds setting. Returns self on success, NULL of failure. + if `dealloc` is set `true`, it frees `self` on error. */ static struct mrb_time* -time_update_datetime(mrb_state *mrb, struct mrb_time *self) +time_update_datetime(mrb_state *mrb, struct mrb_time *self, int dealloc) { struct tm *aid; @@ -211,7 +212,10 @@ time_update_datetime(mrb_state *mrb, struct mrb_time *self) aid = localtime_r(&self->sec, &self->datetime); } if (!aid) { - mrb_raisef(mrb, E_ARGUMENT_ERROR, "%S out of Time range", mrb_float_value(mrb, (mrb_float)self->sec)); + mrb_float sec = (mrb_float)self->sec; + + mrb_free(mrb, self); + mrb_raisef(mrb, E_ARGUMENT_ERROR, "%S out of Time range", mrb_float_value(mrb, sec)); /* not reached */ return NULL; } @@ -273,7 +277,7 @@ time_alloc(mrb_state *mrb, double sec, double usec, enum mrb_timezone timezone) tm->sec += sec2; } tm->timezone = timezone; - time_update_datetime(mrb, tm); + time_update_datetime(mrb, tm, TRUE); return tm; } @@ -325,7 +329,7 @@ current_mrb_time(mrb_state *mrb) } #endif tm->timezone = MRB_TIMEZONE_LOCAL; - time_update_datetime(mrb, tm); + time_update_datetime(mrb, tm, TRUE); return tm; } @@ -616,7 +620,7 @@ mrb_time_getutc(mrb_state *mrb, mrb_value self) tm2 = (struct mrb_time *)mrb_malloc(mrb, sizeof(*tm)); *tm2 = *tm; tm2->timezone = MRB_TIMEZONE_UTC; - time_update_datetime(mrb, tm2); + time_update_datetime(mrb, tm2, TRUE); return mrb_time_wrap(mrb, mrb_obj_class(mrb, self), tm2); } @@ -631,7 +635,7 @@ mrb_time_getlocal(mrb_state *mrb, mrb_value self) tm2 = (struct mrb_time *)mrb_malloc(mrb, sizeof(*tm)); *tm2 = *tm; tm2->timezone = MRB_TIMEZONE_LOCAL; - time_update_datetime(mrb, tm2); + time_update_datetime(mrb, tm2, TRUE); return mrb_time_wrap(mrb, mrb_obj_class(mrb, self), tm2); } @@ -709,7 +713,7 @@ mrb_time_localtime(mrb_state *mrb, mrb_value self) tm = time_get_ptr(mrb, self); tm->timezone = MRB_TIMEZONE_LOCAL; - time_update_datetime(mrb, tm); + time_update_datetime(mrb, tm, FALSE); return self; } @@ -806,7 +810,7 @@ mrb_time_utc(mrb_state *mrb, mrb_value self) tm = time_get_ptr(mrb, self); tm->timezone = MRB_TIMEZONE_UTC; - time_update_datetime(mrb, tm); + time_update_datetime(mrb, tm, FALSE); return self; } -- cgit v1.2.3 From 73091ab20288d196e774cefd234660e5c6fefc14 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Sat, 2 Mar 2019 15:45:15 +0900 Subject: Do not apply `mrb_ptr()` to immediate objects; fix #4307 --- src/object.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/object.c b/src/object.c index b764fc8ef..d45ab27c7 100644 --- a/src/object.c +++ b/src/object.c @@ -434,8 +434,10 @@ mrb_any_to_s(mrb_state *mrb, mrb_value obj) mrb_str_cat_lit(mrb, str, "#<"); mrb_str_cat_cstr(mrb, str, cname); - mrb_str_cat_lit(mrb, str, ":"); - mrb_str_concat(mrb, str, mrb_ptr_to_str(mrb, mrb_ptr(obj))); + if (!mrb_immediate_p(obj)) { + mrb_str_cat_lit(mrb, str, ":"); + mrb_str_concat(mrb, str, mrb_ptr_to_str(mrb, mrb_ptr(obj))); + } mrb_str_cat_lit(mrb, str, ">"); return str; -- cgit v1.2.3 From af51119d3a4d56cead0e6b4da69efc78667314d2 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Sat, 2 Mar 2019 15:46:50 +0900 Subject: Raise error on failed comparison in `sort`; ref #4307 --- mrblib/array.rb | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/mrblib/array.rb b/mrblib/array.rb index a677b2a1f..d598efc77 100644 --- a/mrblib/array.rb +++ b/mrblib/array.rb @@ -213,7 +213,11 @@ class Array if left + 1 == right lval = self[left] rval = self[right] - if (block&.call(lval, rval) || (lval <=> rval)) > 0 + cmp = if block then block.call(lval,rval) else lval <=> rval end + if cmp.nil? + raise ArgumentError, "comparison of #{lval.inspect} and #{rval.inspect} failed" + end + if cmp > 0 self[left] = rval self[right] = lval end @@ -245,7 +249,11 @@ class Array else lval = lary[lidx] rval = self[ridx] - if (block&.call(lval, rval) || (lval <=> rval)) <= 0 + cmp = if block then block.call(lval,rval) else lval <=> rval end + if cmp.nil? + raise ArgumentError, "comparison of #{lval.inspect} and #{rval.inspect} failed" + end + if cmp <= 0 self[i] = lval lidx += 1 else -- cgit v1.2.3 From ad45f51cafd046d41c437df35e453f5450ae6ee9 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Sat, 2 Mar 2019 15:57:39 +0900 Subject: Remove unused `gem.bin=` method; close #4271 --- lib/mruby/gem.rb | 4 ---- 1 file changed, 4 deletions(-) diff --git a/lib/mruby/gem.rb b/lib/mruby/gem.rb index b32b1eed2..33396803a 100644 --- a/lib/mruby/gem.rb +++ b/lib/mruby/gem.rb @@ -119,10 +119,6 @@ module MRuby @conflicts << {:gem => name, :requirements => req.empty? ? nil : req} end - def self.bin=(bin) - @bins = [bin].flatten - end - def build_dir "#{build.build_dir}/mrbgems/#{name}" end -- cgit v1.2.3 From 729ab86d491c8dbdf8c7fb4c96169eb4af9f4129 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Sat, 2 Mar 2019 18:55:02 +0900 Subject: Fix missing assertion in `test/t/class.rb` --- test/t/class.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/t/class.rb b/test/t/class.rb index 6a0a3225c..290ecf74a 100644 --- a/test/t/class.rb +++ b/test/t/class.rb @@ -365,7 +365,7 @@ assert('clone Class') do end end - Foo.clone.new.func + assert_true(Foo.clone.new.func) end assert('class variable and class << self style class method') do -- cgit v1.2.3 From c6b81069246a89b214964f1c7f13d729c2f14918 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Sun, 3 Mar 2019 18:58:11 +0900 Subject: Simplify `MRubyTestSkip` in `test/assert.rb` --- test/assert.rb | 14 +++----------- 1 file changed, 3 insertions(+), 11 deletions(-) diff --git a/test/assert.rb b/test/assert.rb index d6e394a9f..9d807d52c 100644 --- a/test/assert.rb +++ b/test/assert.rb @@ -19,11 +19,8 @@ end # Create the assertion in a readable way def assertion_string(err, str, iso=nil, e=nil, bt=nil) msg = "#{err}#{str}" - msg += " [#{iso}]" if iso && iso != '' - if e - m = e.respond_to?(:cause) ? e.cause : e.message - msg += " => #{m}" if m && !m.empty? - end + msg += " [#{iso}]" if iso && !iso.empty? + msg += " => #{e}" if e && !e.to_s.empty? msg += " (#{GEMNAME == 'mruby-test' ? 'core' : "mrbgems: #{GEMNAME}"})" if $mrbtest_assert && $mrbtest_assert.size > 0 $mrbtest_assert.each do |idx, assert_msg, diff| @@ -258,12 +255,7 @@ end ## # Skip the test -class MRubyTestSkip < NotImplementedError - attr_accessor :cause - def initialize(cause) - @cause = cause - end -end +class MRubyTestSkip < NotImplementedError; end def skip(cause = "") raise MRubyTestSkip.new(cause) -- cgit v1.2.3 From 376dd992f1a61002a567ef371dd3cdd070bc8376 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Sun, 3 Mar 2019 20:45:44 +0900 Subject: Extract similar code fragment to method in `src/class.c` --- src/class.c | 56 +++++++++++++++++--------------------------------------- 1 file changed, 17 insertions(+), 39 deletions(-) diff --git a/src/class.c b/src/class.c index 359bb4fea..bb9515bbd 100644 --- a/src/class.c +++ b/src/class.c @@ -122,6 +122,19 @@ prepare_singleton_class(mrb_state *mrb, struct RBasic *o) mrb_obj_iv_set(mrb, (struct RObject*)sc, mrb_intern_lit(mrb, "__attached__"), mrb_obj_value(o)); } +static mrb_value +class_name_str(mrb_state *mrb, struct RClass* c) +{ + mrb_value path = mrb_class_path(mrb, c); + if (mrb_nil_p(path)) { + path = c->tt == MRB_TT_MODULE ? mrb_str_new_lit(mrb, "#"); + } + return path; +} + static struct RClass* class_from_sym(mrb_state *mrb, struct RClass *klass, mrb_sym id) { @@ -1696,14 +1709,8 @@ mrb_class_real(struct RClass* cl) MRB_API const char* mrb_class_name(mrb_state *mrb, struct RClass* c) { - mrb_value path = mrb_class_path(mrb, c); - if (mrb_nil_p(path)) { - path = c->tt == MRB_TT_MODULE ? mrb_str_new_lit(mrb, "#"); - } - return RSTRING_PTR(path); + mrb_value name = class_name_str(mrb, c); + return RSTRING_PTR(name); } MRB_API const char* @@ -1818,12 +1825,10 @@ mrb_define_alias(mrb_state *mrb, struct RClass *klass, const char *name1, const mrb_value mrb_mod_to_s(mrb_state *mrb, mrb_value klass) { - mrb_value str; if (mrb_type(klass) == MRB_TT_SCLASS) { mrb_value v = mrb_iv_get(mrb, klass, mrb_intern_lit(mrb, "__attached__")); - - str = mrb_str_new_lit(mrb, "#"); } else { - struct RClass *c; - mrb_value path; - - str = mrb_str_new_capa(mrb, 32); - c = mrb_class_ptr(klass); - path = mrb_class_path(mrb, c); - - if (mrb_nil_p(path)) { - switch (mrb_type(klass)) { - case MRB_TT_CLASS: - mrb_str_cat_lit(mrb, str, "#"); - } - else { - return path; - } + return class_name_str(mrb, mrb_class_ptr(klass)); } } -- cgit v1.2.3 From ee537eceeea31d071db3bcead8153f683c9cb5f9 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Mon, 4 Mar 2019 00:18:54 +0900 Subject: `GEMNAME` is undefined in bintest ref: https://github.com/mruby/mruby/pull/4296#discussion_r261868710 --- test/assert.rb | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/test/assert.rb b/test/assert.rb index 9d807d52c..158fc8ead 100644 --- a/test/assert.rb +++ b/test/assert.rb @@ -21,7 +21,9 @@ def assertion_string(err, str, iso=nil, e=nil, bt=nil) msg = "#{err}#{str}" msg += " [#{iso}]" if iso && !iso.empty? msg += " => #{e}" if e && !e.to_s.empty? - msg += " (#{GEMNAME == 'mruby-test' ? 'core' : "mrbgems: #{GEMNAME}"})" + if Object.const_defined?(:GEMNAME) + msg += " (#{GEMNAME == 'mruby-test' ? 'core' : "mrbgems: #{GEMNAME}"})" + end if $mrbtest_assert && $mrbtest_assert.size > 0 $mrbtest_assert.each do |idx, assert_msg, diff| msg += "\n - Assertion[#{idx}] Failed: #{assert_msg}\n#{diff}" -- cgit v1.2.3 From 650ca7da17c4cc784c42fb5fe75b3e923186e378 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Tue, 5 Mar 2019 19:53:25 +0900 Subject: Count skip tests --- test/assert.rb | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/test/assert.rb b/test/assert.rb index 158fc8ead..8a723762e 100644 --- a/test/assert.rb +++ b/test/assert.rb @@ -1,6 +1,7 @@ $ok_test = 0 $ko_test = 0 $kill_test = 0 +$skip_test = 0 $asserts = [] $test_start = Time.now if Object.const_defined?(:Time) @@ -57,6 +58,7 @@ def assert(str = 'Assertion failed', iso = '') end rescue MRubyTestSkip => e $asserts.push(assertion_string('Skip: ', str, iso, e)) + $skip_test += 1 t_print('?') rescue Exception => e bt = e.backtrace if $mrbtest_verbose @@ -220,12 +222,13 @@ def report() t_print("#{msg}\n") end - $total_test = $ok_test+$ko_test+$kill_test + $total_test = $ok_test + $ko_test + $kill_test + $skip_test t_print("Total: #{$total_test}\n") t_print(" OK: #{$ok_test}\n") t_print(" KO: #{$ko_test}\n") t_print("Crash: #{$kill_test}\n") + t_print(" Skip: #{$skip_test}\n") if Object.const_defined?(:Time) t_time = Time.now - $test_start -- cgit v1.2.3 From e2bb5ce079b478fd4c0f7724ed80d41216b228b8 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Wed, 6 Mar 2019 20:42:31 +0900 Subject: Refer also CXX and CC env vars as linker command in gcc and clang toolchain ref #4292 --- tasks/toolchains/clang.rake | 2 +- tasks/toolchains/gcc.rake | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/tasks/toolchains/clang.rake b/tasks/toolchains/clang.rake index c75fa030c..2832dad5f 100644 --- a/tasks/toolchains/clang.rake +++ b/tasks/toolchains/clang.rake @@ -5,5 +5,5 @@ MRuby::Toolchain.new(:clang) do |conf, _params| cc.command = ENV['CC'] || 'clang' end conf.cxx.command = ENV['CXX'] || 'clang++' - conf.linker.command = ENV['LD'] || 'clang' + conf.linker.command = ENV['LD'] || ENV['CXX'] || ENV['CC'] || 'clang' end diff --git a/tasks/toolchains/gcc.rake b/tasks/toolchains/gcc.rake index 2d1e70e6e..663fef9e6 100644 --- a/tasks/toolchains/gcc.rake +++ b/tasks/toolchains/gcc.rake @@ -20,7 +20,7 @@ MRuby::Toolchain.new(:gcc) do |conf, _params| end conf.linker do |linker| - linker.command = ENV['LD'] || 'gcc' + linker.command = ENV['LD'] || ENV['CXX'] || ENV['CC'] || 'gcc' linker.flags = [ENV['LDFLAGS'] || %w()] linker.libraries = %w(m) linker.library_paths = [] -- cgit v1.2.3 From f6326803c744e05918a1f124d0055bf35e0f6851 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Thu, 7 Mar 2019 21:36:54 +0900 Subject: Add a missing file for #4314 --- mrbgems/mruby-test/driver.c | 1 + 1 file changed, 1 insertion(+) diff --git a/mrbgems/mruby-test/driver.c b/mrbgems/mruby-test/driver.c index 4b2707319..6e58c3e28 100644 --- a/mrbgems/mruby-test/driver.c +++ b/mrbgems/mruby-test/driver.c @@ -131,6 +131,7 @@ mrb_t_pass_result(mrb_state *mrb_dst, mrb_state *mrb_src) TEST_COUNT_PASS(ok_test); TEST_COUNT_PASS(ko_test); TEST_COUNT_PASS(kill_test); + TEST_COUNT_PASS(skip_test); #undef TEST_COUNT_PASS -- cgit v1.2.3 From 968e3b94005e8b7f8882c274259cba6f81345ad9 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Thu, 7 Mar 2019 22:16:47 +0900 Subject: Set `GEMNAME` on bintest --- test/assert.rb | 4 +--- test/bintest.rb | 3 +++ 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/test/assert.rb b/test/assert.rb index 8a723762e..623ec9138 100644 --- a/test/assert.rb +++ b/test/assert.rb @@ -22,9 +22,7 @@ def assertion_string(err, str, iso=nil, e=nil, bt=nil) msg = "#{err}#{str}" msg += " [#{iso}]" if iso && !iso.empty? msg += " => #{e}" if e && !e.to_s.empty? - if Object.const_defined?(:GEMNAME) - msg += " (#{GEMNAME == 'mruby-test' ? 'core' : "mrbgems: #{GEMNAME}"})" - end + msg += " (#{GEMNAME == 'mruby-test' ? 'core' : "mrbgems: #{GEMNAME}"})" if $mrbtest_assert && $mrbtest_assert.size > 0 $mrbtest_assert.each do |idx, assert_msg, diff| msg += "\n - Assertion[#{idx}] Failed: #{assert_msg}\n#{diff}" diff --git a/test/bintest.rb b/test/bintest.rb index b62419d44..d0126cfa0 100644 --- a/test/bintest.rb +++ b/test/bintest.rb @@ -1,6 +1,8 @@ $:.unshift File.dirname(File.dirname(File.expand_path(__FILE__))) require 'test/assert.rb' +GEMNAME = "" + def cmd(s) case RbConfig::CONFIG['host_os'] when /mswin(?!ce)|mingw|bccwin/ @@ -30,6 +32,7 @@ ARGV.each do |gem| end Dir["#{gem}/bintest/**/*.rb"].each do |file| + GEMNAME.replace(File.basename(gem)) load file end end -- cgit v1.2.3 From 441c964716a0279f7f37cad06978d6261a1651db Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Fri, 8 Mar 2019 22:00:06 +0900 Subject: Allow `enable_bintest` without `enable_test` in build config --- Rakefile | 23 ++++++++++++----------- lib/mruby/gem.rb | 2 +- 2 files changed, 13 insertions(+), 12 deletions(-) diff --git a/Rakefile b/Rakefile index 6c160a5ed..533153290 100644 --- a/Rakefile +++ b/Rakefile @@ -123,20 +123,21 @@ end desc "run all mruby tests" task :test MRuby.each_target do - next unless test_enabled? - - t = :"test_#{self.name}" - task t => ["all"] do - run_test + if test_enabled? + t = :"test_#{self.name}" + task t => ["all"] do + run_test + end + task :test => t end - task :test => t - next unless bintest_enabled? - t = :"bintest_#{self.name}" - task t => ["all"] do - run_bintest + if bintest_enabled? + t = :"bintest_#{self.name}" + task t => ["all"] do + run_bintest + end + task :test => t end - task :test => t end desc "clean all built and in-repo installed artifacts" diff --git a/lib/mruby/gem.rb b/lib/mruby/gem.rb index 33396803a..ce2e01ab1 100644 --- a/lib/mruby/gem.rb +++ b/lib/mruby/gem.rb @@ -112,7 +112,7 @@ module MRuby end def add_test_dependency(*args) - add_dependency(*args) if build.test_enabled? + add_dependency(*args) if build.test_enabled? || build.bintest_enabled? end def add_conflict(name, *req) -- cgit v1.2.3 From 7d1a8d3f8e9e8d96a79499d84d80fdc04f287298 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Sun, 10 Mar 2019 21:46:24 +0900 Subject: Add bintest header --- lib/mruby/build.rb | 1 + test/bintest.rb | 2 ++ 2 files changed, 3 insertions(+) diff --git a/lib/mruby/build.rb b/lib/mruby/build.rb index 4f81a970b..016b32b3e 100644 --- a/lib/mruby/build.rb +++ b/lib/mruby/build.rb @@ -314,6 +314,7 @@ EOS end def run_bintest + puts ">>> Bintest #{name} <<<" targets = @gems.select { |v| File.directory? "#{v.dir}/bintest" }.map { |v| filename v.dir } targets << filename(".") if File.directory? "./bintest" sh "ruby test/bintest.rb#{verbose_flag} #{targets.join ' '}" diff --git a/test/bintest.rb b/test/bintest.rb index d0126cfa0..2bcecaec5 100644 --- a/test/bintest.rb +++ b/test/bintest.rb @@ -21,6 +21,8 @@ def shellquote(s) end end +print "bintest - Command Binary Test\n\n" + ARGV.each do |gem| case gem when '-v'; $mrbtest_verbose = true -- cgit v1.2.3 From 425e6e0ffb0e2935b800866443fb18ccb26a97e4 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Mon, 11 Mar 2019 17:26:19 +0900 Subject: Reduce `String` creation in `check_(cv|const)_name_sym` --- mrbgems/mruby-metaprog/src/metaprog.c | 17 ++++++++--------- src/class.c | 14 ++++++++------ 2 files changed, 16 insertions(+), 15 deletions(-) diff --git a/mrbgems/mruby-metaprog/src/metaprog.c b/mrbgems/mruby-metaprog/src/metaprog.c index 25c153cee..75913dab5 100644 --- a/mrbgems/mruby-metaprog/src/metaprog.c +++ b/mrbgems/mruby-metaprog/src/metaprog.c @@ -400,21 +400,20 @@ mod_define_singleton_method(mrb_state *mrb, mrb_value self) return mrb_symbol_value(mid); } -static void -check_cv_name_str(mrb_state *mrb, mrb_value str) +static mrb_bool +cv_name_p(mrb_state *mrb, const char *name, mrb_int len) { - const char *s = RSTRING_PTR(str); - mrb_int len = RSTRING_LEN(str); - - if (len < 3 || !(s[0] == '@' && s[1] == '@')) { - mrb_name_error(mrb, mrb_intern_str(mrb, str), "'%S' is not allowed as a class variable name", str); - } + return len > 2 && name[0] == '@' && name[1] == '@'; } static void check_cv_name_sym(mrb_state *mrb, mrb_sym id) { - check_cv_name_str(mrb, mrb_sym2str(mrb, id)); + mrb_int len; + const char *name = mrb_sym2name_len(mrb, id, &len); + if (!cv_name_p(mrb, name, len)) { + mrb_name_error(mrb, id, "'%S' is not allowed as a class variable name", mrb_sym2str(mrb, id)); + } } /* 15.2.2.4.39 */ diff --git a/src/class.c b/src/class.c index bb9515bbd..9d6fd631f 100644 --- a/src/class.c +++ b/src/class.c @@ -1895,18 +1895,20 @@ mrb_mod_undef(mrb_state *mrb, mrb_value mod) return mrb_nil_value(); } -static void -check_const_name_str(mrb_state *mrb, mrb_value str) +static mrb_bool +const_name_p(mrb_state *mrb, const char *name, mrb_int len) { - if (RSTRING_LEN(str) < 1 || !ISUPPER(*RSTRING_PTR(str))) { - mrb_name_error(mrb, mrb_intern_str(mrb, str), "wrong constant name %S", str); - } + return len > 0 && ISUPPER(name[0]); } static void check_const_name_sym(mrb_state *mrb, mrb_sym id) { - check_const_name_str(mrb, mrb_sym2str(mrb, id)); + mrb_int len; + const char *name = mrb_sym2name_len(mrb, id, &len); + if (!const_name_p(mrb, name, len)) { + mrb_name_error(mrb, id, "wrong constant name %S", mrb_sym2str(mrb, id)); + } } static mrb_value -- cgit v1.2.3 From 67728c15767a238a5679b5465aff01d364f6fb44 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Tue, 12 Mar 2019 07:53:07 +0900 Subject: Rename `MITL` to `LICENSE` to conform GitHub convention. --- LEGAL | 2 +- LICENSE | 20 ++++++++++++++++++++ MITL | 20 -------------------- README.md | 2 +- 4 files changed, 22 insertions(+), 22 deletions(-) create mode 100644 LICENSE delete mode 100644 MITL diff --git a/LEGAL b/LEGAL index 84929998c..53de0cd9f 100644 --- a/LEGAL +++ b/LEGAL @@ -2,5 +2,5 @@ LEGAL NOTICE INFORMATION ------------------------ All the files in this distribution are covered under the MIT license -(see the file MITL) except some files mentioned below: +(see the file LICENSE) except some files mentioned below: diff --git a/LICENSE b/LICENSE new file mode 100644 index 000000000..ab5432331 --- /dev/null +++ b/LICENSE @@ -0,0 +1,20 @@ +Copyright (c) 2019 mruby developers + +Permission is hereby granted, free of charge, to any person obtaining a +copy of this software and associated documentation files (the "Software"), +to deal in the Software without restriction, including without limitation +the rights to use, copy, modify, merge, publish, distribute, sublicense, +and/or sell copies of the Software, and to permit persons to whom the +Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. + diff --git a/MITL b/MITL deleted file mode 100644 index 8d8c78fab..000000000 --- a/MITL +++ /dev/null @@ -1,20 +0,0 @@ -Copyright (c) 2018 mruby developers - -Permission is hereby granted, free of charge, to any person obtaining a -copy of this software and associated documentation files (the "Software"), -to deal in the Software without restriction, including without limitation -the rights to use, copy, modify, merge, publish, distribute, sublicense, -and/or sell copies of the Software, and to permit persons to whom the -Software is furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -DEALINGS IN THE SOFTWARE. - diff --git a/README.md b/README.md index e43510ebe..c3e9ae10a 100644 --- a/README.md +++ b/README.md @@ -59,7 +59,7 @@ how to use mrbgems look into the folder *examples/mrbgems/*. ## License -mruby is released under the [MIT License](MITL). +mruby is released under the [MIT License](LICENSE). ## Note for License -- cgit v1.2.3 From e2976172c5979a3c3b0e496ee155b5c1dffdbb5f Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Tue, 12 Mar 2019 09:20:59 +0900 Subject: Rename `MITL` to `LICENSE` in `.yardopts`; ref 67728c1 [ci skip] --- .yardopts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.yardopts b/.yardopts index 27f6d59a1..4499bf513 100644 --- a/.yardopts +++ b/.yardopts @@ -12,6 +12,6 @@ mrbgems/*/mrblib/**/*.rb mrbgems/*/include/**/*.h - AUTHORS -MITL +LICENSE CONTRIBUTING.md doc/guides/*.md -- cgit v1.2.3 From fc96dbcac616155ce3bbf3da11843bf46f8c8d7f Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Tue, 12 Mar 2019 09:46:29 +0900 Subject: Update `AUTHORS` [ci skip] --- AUTHORS | 1 + 1 file changed, 1 insertion(+) diff --git a/AUTHORS b/AUTHORS index 4265f7f58..801b78b42 100644 --- a/AUTHORS +++ b/AUTHORS @@ -38,3 +38,4 @@ Original Authors "mruby developers" are: Christopher Aue Masahiro Wakame YAMAMOTO Masaya + KOBAYASHI Shuji -- cgit v1.2.3 From e3b339bec6c38cf6ea7d763cba3b81e21e5c7700 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Tue, 12 Mar 2019 21:47:33 +0900 Subject: Fix missing assertions in `mruby-string-ext` test --- mrbgems/mruby-string-ext/test/string.rb | 72 +++++++++++++++++++-------------- 1 file changed, 41 insertions(+), 31 deletions(-) diff --git a/mrbgems/mruby-string-ext/test/string.rb b/mrbgems/mruby-string-ext/test/string.rb index 7c96ab694..44ca1fde2 100644 --- a/mrbgems/mruby-string-ext/test/string.rb +++ b/mrbgems/mruby-string-ext/test/string.rb @@ -33,62 +33,72 @@ assert('String#byteslice') do end assert('String#dump') do - ("\1" * 100).dump # should not raise an exception - regress #1210 - "\0".inspect == "\"\\000\"" and - "foo".dump == "\"foo\"" + assert_equal("\"\\x00\"", "\0".dump) + assert_equal("\"foo\"", "foo".dump) + assert_nothing_raised { ("\1" * 100).dump } # regress #1210 end assert('String#strip') do s = " abc " - "".strip == "" and " \t\r\n\f\v".strip == "" and - "\0a\0".strip == "\0a" and - "abc".strip == "abc" and - " abc".strip == "abc" and - "abc ".strip == "abc" and - " abc ".strip == "abc" and - s == " abc " + assert_equal("abc", s.strip) + assert_equal(" abc ", s) + assert_equal("", "".strip) + assert_equal("", " \t\r\n\f\v".strip) + assert_equal("\0a", "\0a\0".strip) + assert_equal("abc", "abc".strip) + assert_equal("abc", " abc".strip) + assert_equal("abc", "abc ".strip) end assert('String#lstrip') do s = " abc " - s.lstrip - "".lstrip == "" and " \t\r\n\f\v".lstrip == "" and - "\0a\0".lstrip == "\0a\0" and - "abc".lstrip == "abc" and - " abc".lstrip == "abc" and - "abc ".lstrip == "abc " and - " abc ".lstrip == "abc " and - s == " abc " + assert_equal("abc ", s.lstrip) + assert_equal(" abc ", s) + assert_equal("", "".lstrip) + assert_equal("", " \t\r\n\f\v".lstrip) + assert_equal("\0a\0", "\0a\0".lstrip) + assert_equal("abc", "abc".lstrip) + assert_equal("abc", " abc".lstrip) + assert_equal("abc ", "abc ".lstrip) end assert('String#rstrip') do s = " abc " - s.rstrip - "".rstrip == "" and " \t\r\n\f\v".rstrip == "" and - "\0a\0".rstrip == "\0a" and - "abc".rstrip == "abc" and - " abc".rstrip == " abc" and - "abc ".rstrip == "abc" and - " abc ".rstrip == " abc" and - s == " abc " + assert_equal(" abc", s.rstrip) + assert_equal(" abc ", s) + assert_equal("", "".rstrip) + assert_equal("", " \t\r\n\f\v".rstrip) + assert_equal("\0a", "\0a\0".rstrip) + assert_equal("abc", "abc".rstrip) + assert_equal(" abc", " abc".rstrip) + assert_equal("abc", "abc ".rstrip) end assert('String#strip!') do s = " abc " t = "abc" - s.strip! == "abc" and s == "abc" and t.strip! == nil + assert_equal("abc", s.strip!) + assert_equal("abc", s) + assert_nil(t.strip!) + assert_equal("abc", t) end assert('String#lstrip!') do s = " abc " t = "abc " - s.lstrip! == "abc " and s == "abc " and t.lstrip! == nil + assert_equal("abc ", s.lstrip!) + assert_equal("abc ", s) + assert_nil(t.lstrip!) + assert_equal("abc ", t) end assert('String#rstrip!') do s = " abc " t = " abc" - s.rstrip! == " abc" and s == " abc" and t.rstrip! == nil + assert_equal(" abc", s.rstrip!) + assert_equal(" abc", s) + assert_nil(t.rstrip!) + assert_equal(" abc", t) end assert('String#swapcase') do @@ -127,7 +137,7 @@ assert('String#count') do assert_equal 4, s.count("a0-9") end -assert('String#tr') do +assert('String#tr') do assert_equal "ABC", "abc".tr('a-z', 'A-Z') assert_equal "hippo", "hello".tr('el', 'ip') assert_equal "Ruby", "Lisp".tr("Lisp", "Ruby") @@ -141,7 +151,7 @@ assert('String#tr!') do assert_equal "ab12222hijklmnopqR", s end -assert('String#tr_s') do +assert('String#tr_s') do assert_equal "hero", "hello".tr_s('l', 'r') assert_equal "h*o", "hello".tr_s('el', '*') assert_equal "hhxo", "hello".tr_s('el', 'hx') -- cgit v1.2.3 From 07b9a10c06da15a327fed5342fefedcffb955275 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Tue, 12 Mar 2019 23:36:26 +0900 Subject: Update the description at the head of `AUTHORS`; ref #4324 --- AUTHORS | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/AUTHORS b/AUTHORS index 801b78b42..859693c29 100644 --- a/AUTHORS +++ b/AUTHORS @@ -1,5 +1,8 @@ -Original Authors "mruby developers" are: - Yukihiro Matsumoto +This is the (likely incomplete) list of of "mruby developers". +If you submit a patch to mruby, please add your name to the end +of this list. + + Yukihiro Matsumoto (Matz) SCSK KYUSHU CORPORATION Kyushu Institute of Technology Network Applied Communication Laboratory, Inc. -- cgit v1.2.3 From 29951a6d0734acaeeb1d5388e5280fa8dc005a6e Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Wed, 13 Mar 2019 07:56:32 +0900 Subject: Fix typo in `AUTHORS` [ci skip] --- AUTHORS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/AUTHORS b/AUTHORS index 859693c29..2353ff683 100644 --- a/AUTHORS +++ b/AUTHORS @@ -1,4 +1,4 @@ -This is the (likely incomplete) list of of "mruby developers". +This is the (likely incomplete) list of "mruby developers". If you submit a patch to mruby, please add your name to the end of this list. -- cgit v1.2.3 From c3122c887a7fb842aac78b4735a64004a9b71a20 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Wed, 13 Mar 2019 22:04:14 +0900 Subject: Do not raise an exception when bintest fail - An exception do not raise when mrbtest fail. - There are no useful informations in exception message and backtrace. --- mrbgems/mruby-test/driver.c | 18 +++--------------- test/assert.rb | 4 +++- test/bintest.rb | 2 +- test/report.rb | 4 ---- 4 files changed, 7 insertions(+), 21 deletions(-) delete mode 100644 test/report.rb diff --git a/mrbgems/mruby-test/driver.c b/mrbgems/mruby-test/driver.c index 6e58c3e28..6b91b7457 100644 --- a/mrbgems/mruby-test/driver.c +++ b/mrbgems/mruby-test/driver.c @@ -29,32 +29,20 @@ print_hint(void) printf("mrbtest - Embeddable Ruby Test\n\n"); } -static int -check_error(mrb_state *mrb) -{ - /* Error check */ - /* $ko_test and $kill_test should be 0 */ - mrb_value ko_test = mrb_gv_get(mrb, mrb_intern_lit(mrb, "$ko_test")); - mrb_value kill_test = mrb_gv_get(mrb, mrb_intern_lit(mrb, "$kill_test")); - - return mrb_fixnum_p(ko_test) && mrb_fixnum(ko_test) == 0 && mrb_fixnum_p(kill_test) && mrb_fixnum(kill_test) == 0; -} - static int eval_test(mrb_state *mrb) { /* evaluate the test */ - mrb_funcall(mrb, mrb_top_self(mrb), "report", 0); + mrb_value result = mrb_funcall(mrb, mrb_top_self(mrb), "report", 0); /* did an exception occur? */ if (mrb->exc) { mrb_print_error(mrb); mrb->exc = 0; return EXIT_FAILURE; } - else if (!check_error(mrb)) { - return EXIT_FAILURE; + else { + return mrb_bool(result) ? EXIT_SUCCESS : EXIT_FAILURE; } - return EXIT_SUCCESS; } static void diff --git a/test/assert.rb b/test/assert.rb index 623ec9138..2873eece1 100644 --- a/test/assert.rb +++ b/test/assert.rb @@ -213,7 +213,7 @@ end ## # Report the test result and print all assertions # which were reported broken. -def report() +def report t_print("\n") $asserts.each do |msg| @@ -232,6 +232,8 @@ def report() t_time = Time.now - $test_start t_print(" Time: #{t_time.round(2)} seconds\n") end + + $ko_test == 0 && $kill_test == 0 end ## diff --git a/test/bintest.rb b/test/bintest.rb index 2bcecaec5..ed71e57fd 100644 --- a/test/bintest.rb +++ b/test/bintest.rb @@ -39,4 +39,4 @@ ARGV.each do |gem| end end -load 'test/report.rb' +exit report diff --git a/test/report.rb b/test/report.rb deleted file mode 100644 index fb77fd0aa..000000000 --- a/test/report.rb +++ /dev/null @@ -1,4 +0,0 @@ -report -if $ko_test > 0 or $kill_test > 0 - raise "mrbtest failed (KO:#{$ko_test}, Crash:#{$kill_test})" -end -- cgit v1.2.3 From 16b1b2978e4f4d838f3d12e7221139a92429603b Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Thu, 14 Mar 2019 23:09:05 +0900 Subject: Fix constant name validation `X!` etc are invalid constant name. --- include/mruby/variable.h | 1 + src/class.c | 2 +- src/variable.c | 20 +++++++++++++------- test/t/module.rb | 24 ++++++++++-------------- 4 files changed, 25 insertions(+), 22 deletions(-) diff --git a/include/mruby/variable.h b/include/mruby/variable.h index 68a2a7121..ba6037959 100644 --- a/include/mruby/variable.h +++ b/include/mruby/variable.h @@ -123,6 +123,7 @@ mrb_value mrb_obj_instance_variables(mrb_state*, mrb_value); mrb_value mrb_mod_class_variables(mrb_state*, mrb_value); mrb_value mrb_mod_cv_get(mrb_state *mrb, struct RClass * c, mrb_sym sym); mrb_bool mrb_mod_cv_defined(mrb_state *mrb, struct RClass * c, mrb_sym sym); +mrb_bool mrb_ident_p(const char *s, mrb_int len); /* GC functions */ void mrb_gc_mark_gv(mrb_state*); diff --git a/src/class.c b/src/class.c index 9d6fd631f..da95f5c22 100644 --- a/src/class.c +++ b/src/class.c @@ -1898,7 +1898,7 @@ mrb_mod_undef(mrb_state *mrb, mrb_value mod) static mrb_bool const_name_p(mrb_state *mrb, const char *name, mrb_int len) { - return len > 0 && ISUPPER(name[0]); + return len > 0 && ISUPPER(name[0]) && mrb_ident_p(name+1, len-1); } static void diff --git a/src/variable.c b/src/variable.c index 14e9da9ef..b712af261 100644 --- a/src/variable.c +++ b/src/variable.c @@ -428,22 +428,17 @@ mrb_iv_defined(mrb_state *mrb, mrb_value obj, mrb_sym sym) return mrb_obj_iv_defined(mrb, mrb_obj_ptr(obj), sym); } -#define identchar(c) (ISALNUM(c) || (c) == '_' || !ISASCII(c)) - MRB_API mrb_bool mrb_iv_name_sym_p(mrb_state *mrb, mrb_sym iv_name) { const char *s; - mrb_int i, len; + mrb_int len; s = mrb_sym2name_len(mrb, iv_name, &len); if (len < 2) return FALSE; if (s[0] != '@') return FALSE; if (s[1] == '@') return FALSE; - for (i=1; i Date: Fri, 15 Mar 2019 13:17:40 +0900 Subject: Use `fmt_fp()` for portable float representation. --- src/fmt_fp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/fmt_fp.c b/src/fmt_fp.c index 7028d3aac..14c74ef9e 100644 --- a/src/fmt_fp.c +++ b/src/fmt_fp.c @@ -1,5 +1,5 @@ #ifndef MRB_WITHOUT_FLOAT -#ifdef MRB_DISABLE_STDIO +#if defined(MRB_DISABLE_STDIO) || defined(_WIN32) || defined(_WIN64) /* Most code in this file originates from musl (src/stdio/vfprintf.c) -- cgit v1.2.3 From 298807fa4e6550958de9cd77e1fa12dfd9a399e4 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Fri, 15 Mar 2019 13:24:39 +0900 Subject: Avoid using infinite binary floating point numbers in tests. --- test/t/float.rb | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/test/t/float.rb b/test/t/float.rb index eac5c5792..c137698d3 100644 --- a/test/t/float.rb +++ b/test/t/float.rb @@ -214,12 +214,12 @@ assert('Float#to_s') do assert_equal("NaN", Float::NAN.to_s) assert_equal("0.0", 0.0.to_s) assert_equal("-0.0", -0.0.to_s) - assert_equal("-3.21", -3.21.to_s) + assert_equal("-3.25", -3.25.to_s) assert_equal("50.0", 50.0.to_s) - assert_equal("0.00021", 0.00021.to_s) - assert_equal("-0.00021", -0.00021.to_s) - assert_equal("2.1e-05", 0.000021.to_s) - assert_equal("-2.1e-05", -0.000021.to_s) + assert_equal("0.00025", 0.00025.to_s) + assert_equal("-0.00025", -0.00025.to_s) + assert_equal("2.5e-05", 0.000025.to_s) + assert_equal("-2.5e-05", -0.000025.to_s) assert_equal("1.0e+20", 1e20.to_s) assert_equal("-1.0e+20", -1e20.to_s) assert_equal("1.0e+16", 10000000000000000.0.to_s) -- cgit v1.2.3 From cd4daf78ec773533f49a600a20cfe9cb2258dc2e Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Fri, 15 Mar 2019 22:49:40 +0900 Subject: Use `FrozenError` instead of `RuntimeError` in `String#rstrip!` --- mrbgems/mruby-string-ext/mrblib/string.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mrbgems/mruby-string-ext/mrblib/string.rb b/mrbgems/mruby-string-ext/mrblib/string.rb index 2a323c858..311803ea2 100644 --- a/mrbgems/mruby-string-ext/mrblib/string.rb +++ b/mrbgems/mruby-string-ext/mrblib/string.rb @@ -93,7 +93,7 @@ class String # "hello".rstrip! #=> nil # def rstrip! - raise RuntimeError, "can't modify frozen String" if frozen? + raise FrozenError, "can't modify frozen String" if frozen? s = self.rstrip (s == self) ? nil : self.replace(s) end -- cgit v1.2.3 From 1809fb755a3bef34c18fe459d05e235b12fa1d5c Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Sat, 16 Mar 2019 12:48:14 +0900 Subject: Refine `appveyor.yml` - Add Visual Studio 2017. - Enable `shallow_clone` for saving build time. - Cache extracted WinFlexBison. --- appveyor.yml | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/appveyor.yml b/appveyor.yml index b4514ec27..74cc6febb 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -1,16 +1,19 @@ version: "{build}" -os: Visual Studio 2015 +os: Visual Studio 2017 -clone_depth: 50 +shallow_clone: true cache: - - win_flex_bison-2.5.10.zip + - win_flex_bison environment: matrix: + # Visual Studio 2017 64bit + - visualcpp: C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Auxiliary\Build\vcvars64.bat + # Visual Studio 2015 64bit - visualcpp: C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat machine: amd64 @@ -28,11 +31,12 @@ init: install: - - if not exist win_flex_bison-2.5.10.zip appveyor DownloadFile "https://github.com/lexxmark/winflexbison/releases/download/v.2.5.10/win_flex_bison-2.5.10.zip" - - 7z x -y -owin_flex_bison win_flex_bison-2.5.10.zip > nul - + - if not exist win_flex_bison ( + appveyor DownloadFile "https://github.com/lexxmark/winflexbison/releases/download/v.2.5.10/win_flex_bison-2.5.10.zip" & + 7z x -y -owin_flex_bison win_flex_bison-2.5.10.zip + ) build_script: - set YACC=.\win_flex_bison\win_bison.exe - set MRUBY_CONFIG=appveyor_config.rb - - ruby .\minirake test all + - ruby .\minirake test -- cgit v1.2.3 From b588e5a5b7cfc0e7a1c84c235a0f5daa5bf83a47 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Sun, 17 Mar 2019 16:58:31 +0900 Subject: Fix class/instance variable name validation - `@@?` etc are invalid class variable name. - `@1` etc are invalid instance variable name. --- mrbgems/mruby-metaprog/src/metaprog.c | 3 ++- mrbgems/mruby-metaprog/test/metaprog.rb | 38 +++++++++++++++++++++++++++++++++ src/variable.c | 2 +- test/t/kernel.rb | 7 +++--- 4 files changed, 44 insertions(+), 6 deletions(-) diff --git a/mrbgems/mruby-metaprog/src/metaprog.c b/mrbgems/mruby-metaprog/src/metaprog.c index 75913dab5..0aafb4c34 100644 --- a/mrbgems/mruby-metaprog/src/metaprog.c +++ b/mrbgems/mruby-metaprog/src/metaprog.c @@ -403,7 +403,8 @@ mod_define_singleton_method(mrb_state *mrb, mrb_value self) static mrb_bool cv_name_p(mrb_state *mrb, const char *name, mrb_int len) { - return len > 2 && name[0] == '@' && name[1] == '@'; + return len > 2 && name[0] == '@' && name[1] == '@' && + !ISDIGIT(name[2]) && mrb_ident_p(name+2, len-2); } static void diff --git a/mrbgems/mruby-metaprog/test/metaprog.rb b/mrbgems/mruby-metaprog/test/metaprog.rb index 8bc3719b8..1262c9945 100644 --- a/mrbgems/mruby-metaprog/test/metaprog.rb +++ b/mrbgems/mruby-metaprog/test/metaprog.rb @@ -34,6 +34,30 @@ assert('Kernel#instance_variable_defined?', '15.3.1.3.20') do assert_false o.instance_variable_defined?("@b") assert_true o.instance_variable_defined?("@a"[0,2]) assert_true o.instance_variable_defined?("@abc"[0,2]) + assert_raise(NameError) { o.instance_variable_defined?("@0") } +end + +assert('Kernel#instance_variable_get', '15.3.1.3.21') do + o = Class.new { attr_accessor :foo, :bar }.new + o.foo = "one" + o.bar = 2 + assert_equal("one", o.instance_variable_get(:@foo)) + assert_equal(2, o.instance_variable_get("@bar")) + assert_equal(nil, o.instance_variable_get(:@baz)) + %w[foo @1].each do |n| + assert_raise(NameError) { o.instance_variable_get(n) } + end +end + +assert('Kernel#instance_variable_set', '15.3.1.3.22') do + o = Class.new { attr_reader :foo, :_bar }.new + assert_equal("one", o.instance_variable_set(:@foo, "one")) + assert_equal("one", o.foo) + assert_equal(2, o.instance_variable_set("@_bar", 2)) + assert_equal(2, o._bar) + %w[@6 @% @@a @ a].each do |n| + assert_raise(NameError) { o.instance_variable_set(n, 1) } + end end assert('Kernel#instance_variables', '15.3.1.3.23') do @@ -125,6 +149,7 @@ assert('Module#class_variable_defined?', '15.2.2.4.16') do assert_true Test4ClassVariableDefined.class_variable_defined?(:@@cv) assert_false Test4ClassVariableDefined.class_variable_defined?(:@@noexisting) + assert_raise(NameError) { Test4ClassVariableDefined.class_variable_defined?("@@2") } end assert('Module#class_variable_get', '15.2.2.4.17') do @@ -133,6 +158,10 @@ assert('Module#class_variable_get', '15.2.2.4.17') do end assert_equal 99, Test4ClassVariableGet.class_variable_get(:@@cv) + assert_raise(NameError) { Test4ClassVariableGet.class_variable_get(:@@a) } + %w[@@a? @@! @a a].each do |n| + assert_raise(NameError) { Test4ClassVariableGet.class_variable_get(n) } + end end assert('Module#class_variable_set', '15.2.2.4.18') do @@ -148,6 +177,9 @@ assert('Module#class_variable_set', '15.2.2.4.18') do assert_true Test4ClassVariableSet.class_variables.include? :@@cv assert_equal 99, Test4ClassVariableSet.class_variable_get(:@@cv) assert_equal 101, Test4ClassVariableSet.new.foo + %w[@@ @@1 @@x= @x @ x 1].each do |n| + assert_raise(NameError) { Test4ClassVariableSet.class_variable_set(n, 1) } + end end assert('Module#class_variables', '15.2.2.4.19') do @@ -223,6 +255,12 @@ assert('Module#remove_class_variable', '15.2.2.4.39') do assert_equal 99, Test4RemoveClassVariable.remove_class_variable(:@@cv) assert_false Test4RemoveClassVariable.class_variables.include? :@@cv + assert_raise(NameError) do + Test4RemoveClassVariable.remove_class_variable(:@@cv) + end + assert_raise(NameError) do + Test4RemoveClassVariable.remove_class_variable(:@v) + end end assert('Module#remove_method', '15.2.2.4.41') do diff --git a/src/variable.c b/src/variable.c index b712af261..90efe9e0e 100644 --- a/src/variable.c +++ b/src/variable.c @@ -437,7 +437,7 @@ mrb_iv_name_sym_p(mrb_state *mrb, mrb_sym iv_name) s = mrb_sym2name_len(mrb, iv_name, &len); if (len < 2) return FALSE; if (s[0] != '@') return FALSE; - if (s[1] == '@') return FALSE; + if (ISDIGIT(s[1])) return FALSE; return mrb_ident_p(s+1, len-1); } diff --git a/test/t/kernel.rb b/test/t/kernel.rb index 74176fbd0..d99358c0c 100644 --- a/test/t/kernel.rb +++ b/test/t/kernel.rb @@ -391,11 +391,10 @@ assert('Kernel#remove_instance_variable', '15.3.1.3.41') do tri = Test4RemoveInstanceVar.new assert_equal 99, tri.var - tri.remove + assert_equal 99, tri.remove assert_equal nil, tri.var - assert_raise NameError do - tri.remove - end + assert_raise(NameError) { tri.remove } + assert_raise(NameError) { tri.remove_instance_variable(:var) } end # Kernel#require is defined in mruby-require. '15.3.1.3.42' -- cgit v1.2.3 From bc321ece4c1ee754034449342ac3bf10ecd307b6 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Mon, 18 Mar 2019 12:50:39 +0900 Subject: Use Rake instead of MiniRake on AppVeyor 1. Reduce build time Build time becomes less than half. In MiniRake, a way of using fiber may not be good. 2. Synchronize standard output No synchronized: mrbtest - Embeddable Ruby Test ........................... Total: 1165 (snip) Time: 1.19 seconds bintest - Command Binary Test ..................... Total: 21 (snip) Time: 0.39 seconds mrbtest - Embeddable Ruby Test ........................... Total: 1165 (snip) Skip: 23 Time: 1.15 seconds (snip) >>> Test cxx_abi <<< >>> Bintest host <<< >>> Test host <<< >>> Test full-debug <<< >>> Bintest cxx_abi <<< Synchronized: >>> Test full-debug <<< mrbtest - Embeddable Ruby Test ........................... Total: 1165 (snip) Time: 1.25 seconds >>> Test host <<< mrbtest - Embeddable Ruby Test ........................... Total: 1165 (snip) Time: 1.16 seconds >>> Bintest host <<< bintest - Command Binary Test ..................... Total: 21 (snip) Time: 0.41 seconds >>> Test cxx_abi <<< mrbtest - Embeddable Ruby Test (snip) --- appveyor.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/appveyor.yml b/appveyor.yml index 74cc6febb..a91834cef 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -39,4 +39,4 @@ install: build_script: - set YACC=.\win_flex_bison\win_bison.exe - set MRUBY_CONFIG=appveyor_config.rb - - ruby .\minirake test + - rake -E $stdout.sync=true test -- cgit v1.2.3 From fbad7a15953deb718c350eda42ce389b606088fe Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Tue, 19 Mar 2019 20:48:32 +0900 Subject: Use `FrozenError` instead of `RuntimeError` in frozen object modification test --- mrbgems/mruby-struct/test/struct.rb | 4 ++-- test/t/array.rb | 6 +++--- test/t/hash.rb | 2 +- test/t/string.rb | 2 +- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/mrbgems/mruby-struct/test/struct.rb b/mrbgems/mruby-struct/test/struct.rb index 982e344e2..c298fef9f 100644 --- a/mrbgems/mruby-struct/test/struct.rb +++ b/mrbgems/mruby-struct/test/struct.rb @@ -199,7 +199,7 @@ assert 'Struct#freeze' do assert_equal :test, o.m o.freeze - assert_raise(RuntimeError) { o.m = :modify } - assert_raise(RuntimeError) { o[:m] = :modify } + assert_raise(FrozenError) { o.m = :modify } + assert_raise(FrozenError) { o[:m] = :modify } assert_equal :test, o.m end diff --git a/test/t/array.rb b/test/t/array.rb index f9f4ce19a..2b19fe0d4 100644 --- a/test/t/array.rb +++ b/test/t/array.rb @@ -239,7 +239,7 @@ assert('Array#pop', '15.2.12.5.21') do assert_equal([1,2], a) assert_equal(3, b) - assert_raise(RuntimeError) { [].freeze.pop } + assert_raise(FrozenError) { [].freeze.pop } end assert('Array#push', '15.2.12.5.22') do @@ -288,7 +288,7 @@ assert('Array#shift', '15.2.12.5.27') do assert_equal([2,3], a) assert_equal(1, b) - assert_raise(RuntimeError) { [].freeze.shift } + assert_raise(FrozenError) { [].freeze.shift } end assert('Array#size', '15.2.12.5.28') do @@ -388,7 +388,7 @@ end assert('Array#freeze') do a = [].freeze - assert_raise(RuntimeError) do + assert_raise(FrozenError) do a[0] = 1 end end diff --git a/test/t/hash.rb b/test/t/hash.rb index e3f917b6f..156991f4a 100644 --- a/test/t/hash.rb +++ b/test/t/hash.rb @@ -370,7 +370,7 @@ end assert('Hash#freeze') do h = {}.freeze - assert_raise(RuntimeError) do + assert_raise(FrozenError) do h[:a] = 'b' end end diff --git a/test/t/string.rb b/test/t/string.rb index 7d3dd3c9c..cf3702cbe 100644 --- a/test/t/string.rb +++ b/test/t/string.rb @@ -711,7 +711,7 @@ assert('String#freeze') do str = "hello" str.freeze - assert_raise(RuntimeError) { str.upcase! } + assert_raise(FrozenError) { str.upcase! } end assert('String literal concatenation') do -- cgit v1.2.3 From 2b72baccf3f1705928ab8556ef376bdb09f74e4e Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Wed, 20 Mar 2019 23:36:28 +0900 Subject: Remove redundant content in assertion failure message and diff Based on minitest RubyGem. Example of before this patch: - Assertion[1] Failed: Expected 1 to be 2 Expected: 2 Actual: 1 - Assertion[2] Failed: Expected [1, 3] to include 2 Collection: [1, 3] Object: 2 Example of after this patch: - Assertion[1] Expected: 2 Actual: 1 - Assertion[2] Expected [1, 3] to include 2. --- test/assert.rb | 97 ++++++++++++++++++++++------------------------------------ 1 file changed, 37 insertions(+), 60 deletions(-) diff --git a/test/assert.rb b/test/assert.rb index 2873eece1..d6359022f 100644 --- a/test/assert.rb +++ b/test/assert.rb @@ -25,7 +25,9 @@ def assertion_string(err, str, iso=nil, e=nil, bt=nil) msg += " (#{GEMNAME == 'mruby-test' ? 'core' : "mrbgems: #{GEMNAME}"})" if $mrbtest_assert && $mrbtest_assert.size > 0 $mrbtest_assert.each do |idx, assert_msg, diff| - msg += "\n - Assertion[#{idx}] Failed: #{assert_msg}\n#{diff}" + msg += "\n - Assertion[#{idx}]" + msg += " #{assert_msg}." if assert_msg && !assert_msg.empty? + msg += "\n#{diff}" if diff && !diff.empty? end end msg += "\nbacktrace:\n\t#{bt.join("\n\t")}" if bt @@ -70,35 +72,31 @@ def assert(str = 'Assertion failed', iso = '') end def assertion_diff(exp, act) - " Expected: #{exp.inspect}\n" + + " Expected: #{exp.inspect}\n" \ " Actual: #{act.inspect}" end -def assert_true(ret, msg = nil, diff = nil) +def assert_true(obj, msg = nil, diff = nil) if $mrbtest_assert $mrbtest_assert_idx += 1 - unless ret == true - msg ||= "Expected #{ret.inspect} to be true" - diff ||= assertion_diff(true, ret) + unless obj == true + diff ||= " Expected #{obj.inspect} to be true." $mrbtest_assert.push([$mrbtest_assert_idx, msg, diff]) end end - ret + obj end -def assert_false(ret, msg = nil, diff = nil) - unless ret == false - msg ||= "Expected #{ret.inspect} to be false" - diff ||= assertion_diff(false, ret) +def assert_false(obj, msg = nil, diff = nil) + unless obj == false + diff ||= " Expected #{obj.inspect} to be false." end - assert_true(!ret, msg, diff) - !ret + assert_true(!obj, msg, diff) end def assert_equal(exp, act_or_msg = nil, msg = nil, &block) ret, exp, act, msg = _eval_assertion(:==, exp, act_or_msg, msg, block) unless ret - msg ||= "Expected to be equal" diff = assertion_diff(exp, act) end assert_true(ret, msg, diff) @@ -107,64 +105,44 @@ end def assert_not_equal(exp, act_or_msg = nil, msg = nil, &block) ret, exp, act, msg = _eval_assertion(:==, exp, act_or_msg, msg, block) if ret - msg ||= "Expected to be not equal" - diff = assertion_diff(exp, act) + diff = " Expected #{act.inspect} to not be equal to #{exp.inspect}." end assert_true(!ret, msg, diff) end -def assert_same(exp, act_or_msg = nil, msg = nil, &block) - ret, exp, act, msg = _eval_assertion(:equal?, exp, act_or_msg, msg, block) - unless ret - msg ||= "Expected #{act.inspect} to be the same object as #{exp.inspect}" - diff = " Expected: #{exp.inspect} (class=#{exp.class}, oid=#{exp.__id__})\n" + - " Actual: #{act.inspect} (class=#{act.class}, oid=#{act.__id__})" +def assert_same(*args); _assert_same(true, *args) end +def assert_not_same(*args); _assert_same(false, *args) end +def _assert_same(affirmed, exp, act, msg = nil) + unless ret = exp.equal?(act) == affirmed + exp_str, act_str = [exp, act].map do |o| + "#{o.inspect} (class=#{o.class}, oid=#{o.__id__})" + end + diff = " Expected #{act_str} to #{'not ' unless affirmed}be the same as #{exp_str}." end assert_true(ret, msg, diff) end -def assert_not_same(exp, act_or_msg = nil, msg = nil, &block) - ret, exp, act, msg = _eval_assertion(:equal?, exp, act_or_msg, msg, block) - if ret - msg ||= "Expected #{act.inspect} to not be the same object as #{exp.inspect}" - diff = " Expected: #{exp.inspect} (class=#{exp.class}, oid=#{exp.__id__})\n" + - " Actual: #{act.inspect} (class=#{act.class}, oid=#{act.__id__})" - end - assert_true(!ret, msg, diff) -end - def assert_nil(obj, msg = nil) unless ret = obj.nil? - msg ||= "Expected #{obj.inspect} to be nil" - diff = assertion_diff(nil, obj) + diff = " Expected #{obj.inspect} to be nil." end assert_true(ret, msg, diff) end -def assert_include(collection, obj, msg = nil) - unless ret = collection.include?(obj) - msg ||= "Expected #{collection.inspect} to include #{obj.inspect}" - diff = " Collection: #{collection.inspect}\n" + - " Object: #{obj.inspect}" +def assert_include(*args); _assert_include(true, *args) end +def assert_not_include(*args); _assert_include(false, *args) end +def _assert_include(affirmed, collection, obj, msg = nil) + unless ret = collection.include?(obj) == affirmed + diff = " Expected #{collection.inspect} to #{'not ' unless affirmed}include #{obj.inspect}." end assert_true(ret, msg, diff) end -def assert_not_include(collection, obj, msg = nil) - if ret = collection.include?(obj) - msg ||= "Expected #{collection.inspect} to not include #{obj.inspect}" - diff = " Collection: #{collection.inspect}\n" + - " Object: #{obj.inspect}" - end - assert_true(!ret, msg, diff) -end - ## # Fails unless +obj+ is a kind of +cls+. def assert_kind_of(cls, obj, msg = nil) unless ret = obj.kind_of?(cls) - msg ||= "Expected #{obj.inspect} to be a kind of #{cls}, not #{obj.class}" - diff = assertion_diff(cls, obj.class) + diff = " Expected #{obj.inspect} to be a kind of #{cls}, not #{obj.class}." end assert_true(ret, msg, diff) end @@ -173,26 +151,25 @@ end # Fails unless +exp+ is equal to +act+ in terms of a Float def assert_float(exp, act, msg = nil) unless ret = check_float(exp, act) - msg ||= "Float #{exp} expected to be equal to float #{act}" - diff = assertion_diff(exp, act) + diff = " Expected |#{exp} - #{act}| (#{(exp-act).abs}) to be <= #{Mrbtest::FLOAT_TOLERANCE}." end assert_true(ret, msg, diff) end def assert_raise(*exc) msg = (exc.last.is_a? String) ? exc.pop : nil + exc = exc.empty? ? StandardError : exc.size == 1 ? exc[0] : exc begin yield rescue *exc assert_true(true) rescue Exception => e - msg ||= "Expected to raise #{exc}, not" - diff = " Class: <#{e.class}>\n" + - " Message: #{e.message}" + diff = " #{exc} exception expected, not\n" \ + " Class: <#{e.class}>\n" \ + " Message: <#{e}>" assert_true(false, msg, diff) else - msg ||= "Expected to raise #{exc} but nothing was raised." - diff = "" + diff = " #{exc} expected but nothing was raised." assert_true(false, msg, diff) end end @@ -201,9 +178,9 @@ def assert_nothing_raised(msg = nil) begin yield rescue Exception => e - msg ||= "Expected not to raise #{e} but it raised" - diff = " Class: <#{e.class}>\n" + - " Message: #{e.message}" + diff = " Exception raised:\n" \ + " Class: <#{e.class}>\n" \ + " Message: <#{e}>" assert_true(false, msg, diff) else assert_true(true) -- cgit v1.2.3 From a41b02ab918d7fb976234e1b07e2e60eff4d9f96 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Thu, 21 Mar 2019 21:36:54 +0900 Subject: Fix `Float#eql?` --- src/numeric.c | 2 +- test/t/float.rb | 6 ++++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/src/numeric.c b/src/numeric.c index fa9daf8a7..4128ea3a6 100644 --- a/src/numeric.c +++ b/src/numeric.c @@ -369,7 +369,7 @@ flo_eql(mrb_state *mrb, mrb_value x) mrb_get_args(mrb, "o", &y); if (!mrb_float_p(y)) return mrb_false_value(); - return mrb_bool_value(mrb_float(x) == (mrb_float)mrb_fixnum(y)); + return mrb_bool_value(mrb_float(x) == mrb_float(y)); } /* 15.2.9.3.7 */ diff --git a/test/t/float.rb b/test/t/float.rb index c137698d3..910d7b1d5 100644 --- a/test/t/float.rb +++ b/test/t/float.rb @@ -239,4 +239,10 @@ assert('Float#to_s') do end end +assert('Float#eql?') do + assert_true(5.0.eql?(5.0)) + assert_false(5.0.eql?(5)) + assert_false(5.0.eql?("5.0")) +end + end # const_defined?(:Float) -- cgit v1.2.3 From 04fc265858174ed6d36e492272e39e01e062499e Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Fri, 22 Mar 2019 18:37:37 +0900 Subject: Simplify `assert_step` in `test/t/numeric.rb` --- test/t/numeric.rb | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/test/t/numeric.rb b/test/t/numeric.rb index e22556a7e..d73dfdb61 100644 --- a/test/t/numeric.rb +++ b/test/t/numeric.rb @@ -2,7 +2,7 @@ # Numeric ISO Test assert('Numeric', '15.2.7') do - assert_equal Class, Numeric.class + assert_equal(Class, Numeric.class) end assert('Numeric#+@', '15.2.7.4.1') do @@ -50,10 +50,8 @@ assert('Numeric#step') do break if inf && exp.size == act.size end expr = "#{receiver.inspect}.step(#{args.map(&:inspect).join(', ')})" - msg = "#{expr}: counters" - diff = assertion_diff(exp, act) - assert_true exp.map{|v|[v,v.class]} == act.map{|v|[v,v.class]}, msg, diff - assert_same receiver, ret, "#{expr}: return value" unless inf + assert_true(exp.eql?(act), "#{expr}: counters", assertion_diff(exp, act)) + assert_same(receiver, ret, "#{expr}: return value") unless inf end assert_raise(ArgumentError) { 1.step(2, 0) { break } } -- cgit v1.2.3 From df4b08139200bf6f1c941914d5059d51b91f25b1 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Sat, 23 Mar 2019 19:27:21 +0900 Subject: Refactor `t_print` for test --- mrbgems/mruby-test/driver.c | 34 +++++++++++++--------------------- test/assert.rb | 18 ++++++++---------- 2 files changed, 21 insertions(+), 31 deletions(-) diff --git a/mrbgems/mruby-test/driver.c b/mrbgems/mruby-test/driver.c index 6b91b7457..fd180b1bb 100644 --- a/mrbgems/mruby-test/driver.c +++ b/mrbgems/mruby-test/driver.c @@ -45,29 +45,21 @@ eval_test(mrb_state *mrb) } } -static void -t_printstr(mrb_state *mrb, mrb_value obj) -{ - char *s; - mrb_int len; - - if (mrb_string_p(obj)) { - s = RSTRING_PTR(obj); - len = RSTRING_LEN(obj); - fwrite(s, len, 1, stdout); - fflush(stdout); - } -} - -mrb_value -mrb_t_printstr(mrb_state *mrb, mrb_value self) +/* Implementation of print due to the reason that there might be no print */ +static mrb_value +t_print(mrb_state *mrb, mrb_value self) { - mrb_value argv; + mrb_value *argv; + mrb_int argc; - mrb_get_args(mrb, "o", &argv); - t_printstr(mrb, argv); + mrb_get_args(mrb, "*!", &argv, &argc); + for (mrb_int i = 0; i < argc; ++i) { + mrb_value s = mrb_obj_as_string(mrb, argv[i]); + fwrite(RSTRING_PTR(s), RSTRING_LEN(s), 1, stdout); + } + fflush(stdout); - return argv; + return mrb_nil_value(); } void @@ -76,7 +68,7 @@ mrb_init_test_driver(mrb_state *mrb, mrb_bool verbose) struct RClass *krn, *mrbtest; krn = mrb->kernel_module; - mrb_define_method(mrb, krn, "__t_printstr__", mrb_t_printstr, MRB_ARGS_REQ(1)); + mrb_define_method(mrb, krn, "t_print", t_print, MRB_ARGS_ANY()); mrbtest = mrb_define_module(mrb, "Mrbtest"); diff --git a/test/assert.rb b/test/assert.rb index d6359022f..f6914cf81 100644 --- a/test/assert.rb +++ b/test/assert.rb @@ -5,14 +5,12 @@ $skip_test = 0 $asserts = [] $test_start = Time.now if Object.const_defined?(:Time) -# Implementation of print due to the reason that there might be no print -def t_print(*args) - i = 0 - len = args.size - while i < len - str = args[i].to_s - __t_printstr__ str rescue print str - i += 1 +unless RUBY_ENGINE == "mruby" + # For bintest on Ruby + def t_print(*args) + print *args + $stdout.flush + nil end end @@ -110,8 +108,8 @@ def assert_not_equal(exp, act_or_msg = nil, msg = nil, &block) assert_true(!ret, msg, diff) end -def assert_same(*args); _assert_same(true, *args) end -def assert_not_same(*args); _assert_same(false, *args) end +def assert_same(*args); _assert_same(true, *args) end +def assert_not_same(*args); _assert_same(false, *args) end def _assert_same(affirmed, exp, act, msg = nil) unless ret = exp.equal?(act) == affirmed exp_str, act_str = [exp, act].map do |o| -- cgit v1.2.3 From 10a8e0f1058ef5a1f8af132616e92163c7159cd3 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Sun, 24 Mar 2019 20:55:04 +0900 Subject: Fix arguments spec in `src/proc.c` --- src/proc.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/proc.c b/src/proc.c index dcbeb4f62..dab95e465 100644 --- a/src/proc.c +++ b/src/proc.c @@ -301,7 +301,7 @@ mrb_init_proc(mrb_state *mrb) call_irep->ilen = 1; call_irep->nregs = 2; /* receiver and block */ - mrb_define_class_method(mrb, mrb->proc_class, "new", mrb_proc_s_new, MRB_ARGS_ANY()); + mrb_define_class_method(mrb, mrb->proc_class, "new", mrb_proc_s_new, MRB_ARGS_NONE()|MRB_ARGS_BLOCK()); mrb_define_method(mrb, mrb->proc_class, "initialize_copy", mrb_proc_init_copy, MRB_ARGS_REQ(1)); mrb_define_method(mrb, mrb->proc_class, "arity", mrb_proc_arity, MRB_ARGS_NONE()); @@ -310,6 +310,6 @@ mrb_init_proc(mrb_state *mrb) mrb_define_method_raw(mrb, mrb->proc_class, mrb_intern_lit(mrb, "call"), m); mrb_define_method_raw(mrb, mrb->proc_class, mrb_intern_lit(mrb, "[]"), m); - mrb_define_class_method(mrb, mrb->kernel_module, "lambda", proc_lambda, MRB_ARGS_NONE()); /* 15.3.1.2.6 */ - mrb_define_method(mrb, mrb->kernel_module, "lambda", proc_lambda, MRB_ARGS_NONE()); /* 15.3.1.3.27 */ + mrb_define_class_method(mrb, mrb->kernel_module, "lambda", proc_lambda, MRB_ARGS_NONE()|MRB_ARGS_BLOCK()); /* 15.3.1.2.6 */ + mrb_define_method(mrb, mrb->kernel_module, "lambda", proc_lambda, MRB_ARGS_NONE()|MRB_ARGS_BLOCK()); /* 15.3.1.3.27 */ } -- cgit v1.2.3 From ce675615110e62d1e4e55b197dcb37a62930629d Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Fri, 15 Mar 2019 23:12:44 +0900 Subject: Avoid infinite binary floating numbers in `float`. --- test/t/float.rb | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/test/t/float.rb b/test/t/float.rb index 910d7b1d5..b919c6e3a 100644 --- a/test/t/float.rb +++ b/test/t/float.rb @@ -216,10 +216,10 @@ assert('Float#to_s') do assert_equal("-0.0", -0.0.to_s) assert_equal("-3.25", -3.25.to_s) assert_equal("50.0", 50.0.to_s) - assert_equal("0.00025", 0.00025.to_s) - assert_equal("-0.00025", -0.00025.to_s) - assert_equal("2.5e-05", 0.000025.to_s) - assert_equal("-2.5e-05", -0.000025.to_s) + assert_equal("0.00125", 0.00125.to_s) + assert_equal("-0.00125", -0.00125.to_s) + assert_equal("1.5e-05", 0.000015.to_s) + assert_equal("-1.5e-05", -0.000015.to_s) assert_equal("1.0e+20", 1e20.to_s) assert_equal("-1.0e+20", -1e20.to_s) assert_equal("1.0e+16", 10000000000000000.0.to_s) -- cgit v1.2.3 From f7e05c7d226d259eb2402d0e6c6d84233081be39 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Mon, 25 Mar 2019 16:54:34 +0900 Subject: Update float test values to avoid precision errors. --- test/t/float.rb | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/test/t/float.rb b/test/t/float.rb index b919c6e3a..4e9d347b8 100644 --- a/test/t/float.rb +++ b/test/t/float.rb @@ -216,10 +216,10 @@ assert('Float#to_s') do assert_equal("-0.0", -0.0.to_s) assert_equal("-3.25", -3.25.to_s) assert_equal("50.0", 50.0.to_s) - assert_equal("0.00125", 0.00125.to_s) - assert_equal("-0.00125", -0.00125.to_s) - assert_equal("1.5e-05", 0.000015.to_s) - assert_equal("-1.5e-05", -0.000015.to_s) + assert_equal("0.0125", 0.0125.to_s) + assert_equal("-0.0125", -0.0125.to_s) + assert_equal("1.0e-10", 0.0000000001.to_s) + assert_equal("-1.0e-10", -0.0000000001.to_s) assert_equal("1.0e+20", 1e20.to_s) assert_equal("-1.0e+20", -1e20.to_s) assert_equal("1.0e+16", 10000000000000000.0.to_s) -- cgit v1.2.3 From 33a9840e4a2db7b5136850f23b0185a7d0a6c9c9 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Mon, 25 Mar 2019 20:28:21 +0900 Subject: Need to check length before packing a symbol; fix #4340 --- src/symbol.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/symbol.c b/src/symbol.c index 87c4ca11e..561c5e2fb 100644 --- a/src/symbol.c +++ b/src/symbol.c @@ -53,6 +53,7 @@ sym_inline_pack(const char *name, uint16_t len) if (p == 0) return 0; /* non alnum char */ bits = (uint32_t)(p - pack_table)+1; if (bits > 27) lower = 0; + if (i >= mix_length_max) break; sym |= bits<<(i*6+2); } if (lower) { -- cgit v1.2.3 From b489ddcbd16535b1a4bd89d4890135fe2c734baa Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Mon, 25 Mar 2019 21:39:11 +0900 Subject: Remove implementation of `Symbol#===` For reducing program size. --- src/symbol.c | 21 --------------------- test/t/symbol.rb | 4 ++-- 2 files changed, 2 insertions(+), 23 deletions(-) diff --git a/src/symbol.c b/src/symbol.c index 561c5e2fb..9500e6e36 100644 --- a/src/symbol.c +++ b/src/symbol.c @@ -306,26 +306,6 @@ mrb_init_symtbl(mrb_state *mrb) * */ - -/* 15.2.11.3.1 */ -/* - * call-seq: - * sym == obj -> true or false - * - * Equality---If sym and obj are exactly the same - * symbol, returns true. - */ - -static mrb_value -sym_equal(mrb_state *mrb, mrb_value sym1) -{ - mrb_value sym2; - - mrb_get_args(mrb, "o", &sym2); - - return mrb_bool_value(mrb_obj_equal(mrb, sym1, sym2)); -} - /* 15.2.11.3.2 */ /* 15.2.11.3.3 */ /* @@ -585,7 +565,6 @@ mrb_init_symbol(mrb_state *mrb) MRB_SET_INSTANCE_TT(sym, MRB_TT_SYMBOL); mrb_undef_class_method(mrb, sym, "new"); - mrb_define_method(mrb, sym, "===", sym_equal, MRB_ARGS_REQ(1)); /* 15.2.11.3.1 */ mrb_define_method(mrb, sym, "id2name", mrb_sym_to_s, MRB_ARGS_NONE()); /* 15.2.11.3.2 */ mrb_define_method(mrb, sym, "to_s", mrb_sym_to_s, MRB_ARGS_NONE()); /* 15.2.11.3.3 */ mrb_define_method(mrb, sym, "to_sym", sym_to_sym, MRB_ARGS_NONE()); /* 15.2.11.3.4 */ diff --git a/test/t/symbol.rb b/test/t/symbol.rb index fdce0f378..5c674a9cb 100644 --- a/test/t/symbol.rb +++ b/test/t/symbol.rb @@ -13,8 +13,8 @@ assert('Symbol', '15.2.11') do end assert('Symbol#===', '15.2.11.3.1') do - assert_true :abc == :abc - assert_false :abc == :cba + assert_true :abc === :abc + assert_false :abc === :cba end assert('Symbol#id2name', '15.2.11.3.2') do -- cgit v1.2.3 From a5a6b51126875e578ef1834c8af06141934df7dd Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Mon, 25 Mar 2019 21:06:54 +0900 Subject: Use uppercase version of `ctype` macros e.g. `ISSPACE`; fix #4338 --- mrbgems/mruby-bin-mirb/tools/mirb/mirb.c | 22 +++++++++++----------- mrbgems/mruby-compiler/core/parse.y | 12 ++++++------ mrbgems/mruby-pack/src/pack.c | 6 +++--- src/string.c | 6 +++--- 4 files changed, 23 insertions(+), 23 deletions(-) diff --git a/mrbgems/mruby-bin-mirb/tools/mirb/mirb.c b/mrbgems/mruby-bin-mirb/tools/mirb/mirb.c index 9519d88bb..17b2ca16c 100644 --- a/mrbgems/mruby-bin-mirb/tools/mirb/mirb.c +++ b/mrbgems/mruby-bin-mirb/tools/mirb/mirb.c @@ -6,6 +6,15 @@ ** immediately. It's a REPL... */ +#include +#include +#include +#include +#include +#include +#include +#include + #include #include #include @@ -49,15 +58,6 @@ #define SIGJMP_BUF jmp_buf #endif -#include -#include -#include -#include -#include -#include -#include -#include - #ifdef ENABLE_READLINE static const char history_file_name[] = ".mirb_history"; @@ -373,7 +373,7 @@ check_keyword(const char *buf, const char *word) size_t len = strlen(word); /* skip preceding spaces */ - while (*p && isspace((unsigned char)*p)) { + while (*p && ISSPACE(*p)) { p++; } /* check keyword */ @@ -383,7 +383,7 @@ check_keyword(const char *buf, const char *word) p += len; /* skip trailing spaces */ while (*p) { - if (!isspace((unsigned char)*p)) return 0; + if (!ISSPACE(*p)) return 0; p++; } return 1; diff --git a/mrbgems/mruby-compiler/core/parse.y b/mrbgems/mruby-compiler/core/parse.y index 0aabc2f34..90f01e3a8 100644 --- a/mrbgems/mruby-compiler/core/parse.y +++ b/mrbgems/mruby-compiler/core/parse.y @@ -4888,10 +4888,10 @@ parser_yylex(parser_state *p) } newtok(p); /* need support UTF-8 if configured */ - if ((isalnum(c) || c == '_')) { + if ((ISALNUM(c) || c == '_')) { int c2 = nextc(p); pushback(p, c2); - if ((isalnum(c2) || c2 == '_')) { + if ((ISALNUM(c2) || c2 == '_')) { goto ternary; } } @@ -5459,7 +5459,7 @@ parser_yylex(parser_state *p) } else { term = nextc(p); - if (isalnum(term)) { + if (ISALNUM(term)) { yyerror(p, "unknown type of %string"); return 0; } @@ -5603,7 +5603,7 @@ parser_yylex(parser_state *p) do { tokadd(p, c); c = nextc(p); - } while (c >= 0 && isdigit(c)); + } while (c >= 0 && ISDIGIT(c)); pushback(p, c); if (last_state == EXPR_FNAME) goto gvar; tokfix(p); @@ -5645,7 +5645,7 @@ parser_yylex(parser_state *p) } return 0; } - else if (isdigit(c)) { + else if (ISDIGIT(c)) { if (p->tidx == 1) { yyerror_i(p, "'@%c' is not allowed as an instance variable name", c); } @@ -5802,7 +5802,7 @@ parser_yylex(parser_state *p) mrb_sym ident = intern_cstr(tok(p)); pylval.id = ident; - if (last_state != EXPR_DOT && islower(tok(p)[0]) && local_var_p(p, ident)) { + if (last_state != EXPR_DOT && ISLOWER(tok(p)[0]) && local_var_p(p, ident)) { p->lstate = EXPR_END; } } diff --git a/mrbgems/mruby-pack/src/pack.c b/mrbgems/mruby-pack/src/pack.c index 2e68f35ed..ac29fdbf3 100644 --- a/mrbgems/mruby-pack/src/pack.c +++ b/mrbgems/mruby-pack/src/pack.c @@ -627,7 +627,7 @@ unpack_a(mrb_state *mrb, const void *src, int slen, mrb_value ary, long count, u } } else if (!(flags & PACK_FLAG_a)) { /* "A" */ - while (copylen > 0 && (sptr[copylen - 1] == '\0' || isspace(sptr[copylen - 1]))) { + while (copylen > 0 && (sptr[copylen - 1] == '\0' || ISSPACE(sptr[copylen - 1]))) { copylen--; } } @@ -1072,9 +1072,9 @@ alias: /* read suffix [0-9*_!<>] */ while (tmpl->idx < tlen) { ch = tptr[tmpl->idx++]; - if (isdigit(ch)) { + if (ISDIGIT(ch)) { count = ch - '0'; - while (tmpl->idx < tlen && isdigit(tptr[tmpl->idx])) { + while (tmpl->idx < tlen && ISDIGIT(tptr[tmpl->idx])) { count = count * 10 + (tptr[tmpl->idx++] - '0'); if (count < 0) { mrb_raise(mrb, E_RUNTIME_ERROR, "too big template length"); diff --git a/src/string.c b/src/string.c index 19962fb30..8efea84ab 100644 --- a/src/string.c +++ b/src/string.c @@ -2844,7 +2844,7 @@ mrb_float_read(const char *string, char **endPtr) */ p = string; - while (isspace(*p)) { + while (ISSPACE(*p)) { p += 1; } if (*p == '-') { @@ -2867,7 +2867,7 @@ mrb_float_read(const char *string, char **endPtr) for (mantSize = 0; ; mantSize += 1) { c = *p; - if (!isdigit(c)) { + if (!ISDIGIT(c)) { if ((c != '.') || (decPt >= 0)) { break; } @@ -2952,7 +2952,7 @@ mrb_float_read(const char *string, char **endPtr) } expSign = FALSE; } - while (isdigit(*p)) { + while (ISDIGIT(*p)) { exp = exp * 10 + (*p - '0'); if (exp > 19999) { exp = 19999; -- cgit v1.2.3 From c2660b8111cd6cd98a41aa257c503cbd3a7cf881 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Tue, 26 Mar 2019 10:23:52 +0900 Subject: Fix missing `MRB_API` prefix for functions below; clse #4267 Functions to add prototypes to headers: * mrb_ary_splice() * mrb_notimplement() * mrb_vformat() * mrb_cstr_to_dbl() * mrb_cstr_to_inum() Functions to be made `static` (`MRB_API` was not needed): * mrb_mod_module_function() * mrb_obj_hash() * mrb_str_len_to_inum() Functions to remove `MRB_API` from definitions (referenced from within `libmruby`): * mrb_mod_cv_defined() * mrb_mod_cv_get() * mrb_f_send() --- include/mruby.h | 5 +++++ include/mruby/array.h | 16 ++++++++++++++++ include/mruby/error.h | 2 +- include/mruby/string.h | 2 ++ src/class.c | 2 +- src/kernel.c | 2 +- src/string.c | 4 ++-- src/variable.c | 4 ++-- src/vm.c | 2 +- 9 files changed, 31 insertions(+), 8 deletions(-) diff --git a/include/mruby.h b/include/mruby.h index 9792d7482..f2c800eec 100644 --- a/include/mruby.h +++ b/include/mruby.h @@ -708,6 +708,9 @@ MRB_API struct RClass * mrb_module_get(mrb_state *mrb, const char *name); * @return [struct RClass *] A reference to the module. */ MRB_API struct RClass * mrb_module_get_under(mrb_state *mrb, struct RClass *outer, const char *name); +/* a function to raise NotImplementedError with current method name */ +MRB_API void mrb_notimplement(mrb_state*); +/* a function to be replacement of unimplemented method */ MRB_API mrb_value mrb_notimplement_m(mrb_state*, mrb_value); /** @@ -1143,6 +1146,8 @@ MRB_API void mrb_warn(mrb_state *mrb, const char *fmt, ...); MRB_API mrb_noreturn void mrb_bug(mrb_state *mrb, const char *fmt, ...); MRB_API void mrb_print_backtrace(mrb_state *mrb); MRB_API void mrb_print_error(mrb_state *mrb); +/* function for `raisef` formatting */ +MRB_API mrb_value mrb_vformat(mrb_state *mrb, const char *format, va_list ap); /* macros to get typical exception objects note: diff --git a/include/mruby/array.h b/include/mruby/array.h index 2457f68f2..2e6951c0d 100644 --- a/include/mruby/array.h +++ b/include/mruby/array.h @@ -227,6 +227,22 @@ MRB_API mrb_value mrb_ary_unshift(mrb_state *mrb, mrb_value self, mrb_value item */ MRB_API mrb_value mrb_ary_entry(mrb_value ary, mrb_int offset); +/* + * Replace subsequence of an array. + * + * Equivalent to: + * + * ary.shift + * + * @param mrb The mruby state reference. + * @param self The array from which the value will be shifted. + * @param head Beginning position of a replacement subsequence. + * @param len Length of a replacement subsequence. + * @param rpl The array of replacement elements. + * @return The receiver array. + */ +MRB_API mrb_value mrb_ary_splice(mrb_state *mrb, mrb_value self, mrb_int head, mrb_int len, mrb_value rpl); + /* * Shifts the first element from the array. * diff --git a/include/mruby/error.h b/include/mruby/error.h index 1587795fc..237c701ad 100644 --- a/include/mruby/error.h +++ b/include/mruby/error.h @@ -29,7 +29,7 @@ MRB_API mrb_value mrb_exc_backtrace(mrb_state *mrb, mrb_value exc); MRB_API mrb_value mrb_get_backtrace(mrb_state *mrb); MRB_API mrb_noreturn void mrb_no_method_error(mrb_state *mrb, mrb_sym id, mrb_value args, const char *fmt, ...); -/* declaration for fail method */ +/* declaration for `fail` method */ MRB_API mrb_value mrb_f_raise(mrb_state*, mrb_value); struct RBreak { diff --git a/include/mruby/string.h b/include/mruby/string.h index 6fe0556b0..0b90debec 100644 --- a/include/mruby/string.h +++ b/include/mruby/string.h @@ -352,7 +352,9 @@ MRB_API mrb_value mrb_str_dup(mrb_state *mrb, mrb_value str); MRB_API mrb_value mrb_str_intern(mrb_state *mrb, mrb_value self); MRB_API mrb_value mrb_str_to_inum(mrb_state *mrb, mrb_value str, mrb_int base, mrb_bool badcheck); +MRB_API mrb_value mrb_cstr_to_inum(mrb_state *mrb, const char *s, mrb_int base, mrb_bool badcheck); MRB_API double mrb_str_to_dbl(mrb_state *mrb, mrb_value str, mrb_bool badcheck); +MRB_API double mrb_cstr_to_dbl(mrb_state *mrb, const char *s, mrb_bool badcheck); /* * Returns a converted string type. diff --git a/src/class.c b/src/class.c index da95f5c22..3354617bb 100644 --- a/src/class.c +++ b/src/class.c @@ -2106,7 +2106,7 @@ mrb_mod_eqq(mrb_state *mrb, mrb_value mod) return mrb_bool_value(eqq); } -MRB_API mrb_value +static mrb_value mrb_mod_module_function(mrb_state *mrb, mrb_value mod) { mrb_value *argv; diff --git a/src/kernel.c b/src/kernel.c index 8845cbce6..7890e3dac 100644 --- a/src/kernel.c +++ b/src/kernel.c @@ -492,7 +492,7 @@ mrb_obj_frozen(mrb_state *mrb, mrb_value self) * Hash. Any hash value that exceeds the capacity of a * Fixnum will be truncated before being used. */ -MRB_API mrb_value +static mrb_value mrb_obj_hash(mrb_state *mrb, mrb_value self) { return mrb_fixnum_value(mrb_obj_id(self)); diff --git a/src/string.c b/src/string.c index 8efea84ab..63c592d59 100644 --- a/src/string.c +++ b/src/string.c @@ -2006,7 +2006,7 @@ mrb_str_split_m(mrb_state *mrb, mrb_value str) return result; } -MRB_API mrb_value +static mrb_value mrb_str_len_to_inum(mrb_state *mrb, const char *str, mrb_int len, mrb_int base, int badcheck) { const char *p = str; @@ -2174,7 +2174,7 @@ mrb_str_len_to_inum(mrb_state *mrb, const char *str, mrb_int len, mrb_int base, } MRB_API mrb_value -mrb_cstr_to_inum(mrb_state *mrb, const char *str, int base, int badcheck) +mrb_cstr_to_inum(mrb_state *mrb, const char *str, mrb_int base, mrb_bool badcheck) { return mrb_str_len_to_inum(mrb, str, strlen(str), base, badcheck); } diff --git a/src/variable.c b/src/variable.c index 90efe9e0e..724b153fe 100644 --- a/src/variable.c +++ b/src/variable.c @@ -621,7 +621,7 @@ mrb_mod_class_variables(mrb_state *mrb, mrb_value mod) return ary; } -MRB_API mrb_value +mrb_value mrb_mod_cv_get(mrb_state *mrb, struct RClass *c, mrb_sym sym) { struct RClass * cls = c; @@ -714,7 +714,7 @@ mrb_cv_set(mrb_state *mrb, mrb_value mod, mrb_sym sym, mrb_value v) mrb_mod_cv_set(mrb, mrb_class_ptr(mod), sym, v); } -MRB_API mrb_bool +mrb_bool mrb_mod_cv_defined(mrb_state *mrb, struct RClass * c, mrb_sym sym) { while (c) { diff --git a/src/vm.c b/src/vm.c index 7904162be..a381de21f 100644 --- a/src/vm.c +++ b/src/vm.c @@ -593,7 +593,7 @@ mrb_exec_irep(mrb_state *mrb, mrb_value self, struct RProc *p) * k = Klass.new * k.send :hello, "gentle", "readers" #=> "Hello gentle readers" */ -MRB_API mrb_value +mrb_value mrb_f_send(mrb_state *mrb, mrb_value self) { mrb_sym name; -- cgit v1.2.3 From 0b6696cc2872c9b33efa48c7dcd45dc4a17f3686 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Tue, 26 Mar 2019 22:12:09 +0900 Subject: Fix dealing with infinity and NaN in `test/assert.rb:assert_float` `assert_float` is always passed when expected value and/or actual value are infinity or NaN. This behavior seems unintentional. Before this patch: assert_float(Float::INFINITY, 1.0) #=> pass assert_float(-Float::INFINITY, 1) #=> pass assert_float(1, 1/0) #=> pass assert_float(1, -1/0) #=> pass assert_float(1.0, Float::NAN) #=> pass assert_float(Float::NAN, 1) #=> pass After this patch: assert_float(Float::INFINITY, 1.0) #=> fail: Expected 1.0 to be Infinity. assert_float(-Float::INFINITY, 1) #=> fail: Expected 1 to be -Infinity. assert_float(1, 1/0) #=> fail: Expected Infinity to be 1. assert_float(1, -1/0) #=> fail: Expected -Infinity to be 1. assert_float(1.0, Float::NAN) #=> fail: Expected NaN to be 1.0. assert_float(Float::NAN, 1) #=> fail: Expected 1 to be NaN. --- test/assert.rb | 24 ++++++++---------------- 1 file changed, 8 insertions(+), 16 deletions(-) diff --git a/test/assert.rb b/test/assert.rb index f6914cf81..33d9285ce 100644 --- a/test/assert.rb +++ b/test/assert.rb @@ -148,10 +148,15 @@ end ## # Fails unless +exp+ is equal to +act+ in terms of a Float def assert_float(exp, act, msg = nil) - unless ret = check_float(exp, act) - diff = " Expected |#{exp} - #{act}| (#{(exp-act).abs}) to be <= #{Mrbtest::FLOAT_TOLERANCE}." + e, a = exp.to_f, act.to_f + if (e.infinite? || a.infinite?) && e != a || + e.nan? && !a.nan? || !e.nan? && a.nan? + assert_true(false, msg, " Expected #{act} to be #{exp}.") + elsif (n = (e - a).abs) > Mrbtest::FLOAT_TOLERANCE + assert_true(false, msg, " Expected |#{exp} - #{act}| (#{n}) to be <= #{Mrbtest::FLOAT_TOLERANCE}.") + else + assert_true(true) end - assert_true(ret, msg, diff) end def assert_raise(*exc) @@ -211,19 +216,6 @@ def report $ko_test == 0 && $kill_test == 0 end -## -# Performs fuzzy check for equality on methods returning floats -def check_float(a, b) - tolerance = Mrbtest::FLOAT_TOLERANCE - a = a.to_f - b = b.to_f - if a.finite? and b.finite? - (a-b).abs < tolerance - else - true - end -end - def _eval_assertion(meth, exp, act_or_msg, msg, block) if block exp, act, msg = exp, block.call, act_or_msg -- cgit v1.2.3 From b8f00e439dd0eaa8282b635bfdaff446ae52d760 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Wed, 27 Mar 2019 12:53:24 +0900 Subject: Avoid using 'mrb_str_new_static` if a symbol is packed; fix #4342 --- src/symbol.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/symbol.c b/src/symbol.c index 9500e6e36..4d6c20e68 100644 --- a/src/symbol.c +++ b/src/symbol.c @@ -325,6 +325,10 @@ mrb_sym_to_s(mrb_state *mrb, mrb_value sym) mrb_int len; p = mrb_sym2name_len(mrb, id, &len); +#ifndef MRB_ENABLE_SYMBOLL_ALL + if (p == mrb->symbuf) + return mrb_str_new(mrb, p, len); +#endif return mrb_str_new_static(mrb, p, len); } -- cgit v1.2.3 From 92dce053ad3432587425ad5b1e4a3cc12b190edc Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Wed, 27 Mar 2019 17:38:06 +0900 Subject: Fix another bug related to #4342 For short symbols with alpha numeric characters, `mrb_sym2name_len()` returns the same buffer `mrb->symbuf`. Some occasion, we forget the fact that the second call could overwrite the result of first call of the function. We have prepared the static function `sym2name()` which specifies the buffer region for inline packed symbols and use the function in `mrb_sym_to_s`. --- src/symbol.c | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/src/symbol.c b/src/symbol.c index 4d6c20e68..4cf79046e 100644 --- a/src/symbol.c +++ b/src/symbol.c @@ -237,11 +237,11 @@ mrb_check_intern_str(mrb_state *mrb, mrb_value str) } MRB_API const char* -mrb_sym2name_len(mrb_state *mrb, mrb_sym sym, mrb_int *lenp) +sym2name(mrb_state *mrb, mrb_sym sym, char *buf, mrb_int *lenp) { #ifndef MRB_ENABLE_ALL_SYMBOLS if (sym & 1) { /* inline packed symbol */ - return sym_inline_unpack(sym, mrb->symbuf, lenp); + return sym_inline_unpack(sym, buf, lenp); } #endif @@ -255,6 +255,12 @@ mrb_sym2name_len(mrb_state *mrb, mrb_sym sym, mrb_int *lenp) return mrb->symtbl[sym].name; } +MRB_API const char* +mrb_sym2name_len(mrb_state *mrb, mrb_sym sym, mrb_int *lenp) +{ + return sym2name(mrb, sym, mrb->symbuf, lenp); +} + void mrb_free_symtbl(mrb_state *mrb) { @@ -325,10 +331,9 @@ mrb_sym_to_s(mrb_state *mrb, mrb_value sym) mrb_int len; p = mrb_sym2name_len(mrb, id, &len); -#ifndef MRB_ENABLE_SYMBOLL_ALL - if (p == mrb->symbuf) + if (id&1) { /* inline symbol */ return mrb_str_new(mrb, p, len); -#endif + } return mrb_str_new_static(mrb, p, len); } @@ -545,9 +550,10 @@ sym_cmp(mrb_state *mrb, mrb_value s1) const char *p1, *p2; int retval; mrb_int len, len1, len2; + char buf1[8], buf2[8]; - p1 = mrb_sym2name_len(mrb, sym1, &len1); - p2 = mrb_sym2name_len(mrb, sym2, &len2); + p1 = sym2name(mrb, sym1, buf1, &len1); + p2 = sym2name(mrb, sym2, buf2, &len2); len = lesser(len1, len2); retval = memcmp(p1, p2, len); if (retval == 0) { -- cgit v1.2.3 From 58ca4061b59b35e5fb349aba84754c26939b695c Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Wed, 27 Mar 2019 19:27:00 +0900 Subject: Remove unused variable in `each_backtrace()` --- src/backtrace.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/backtrace.c b/src/backtrace.c index 521cd6c1b..efca2562f 100644 --- a/src/backtrace.c +++ b/src/backtrace.c @@ -28,12 +28,12 @@ static const mrb_data_type bt_type = { "Backtrace", mrb_free }; static void each_backtrace(mrb_state *mrb, ptrdiff_t ciidx, mrb_code *pc0, each_backtrace_func func, void *data) { - ptrdiff_t i, j; + ptrdiff_t i; if (ciidx >= mrb->c->ciend - mrb->c->cibase) ciidx = 10; /* ciidx is broken... */ - for (i=ciidx, j=0; i >= 0; i--,j++) { + for (i=ciidx; i >= 0; i--) { struct backtrace_location loc; mrb_callinfo *ci; mrb_irep *irep; -- cgit v1.2.3 From 21b8d20d7e33bc3d39e8759747f0d82e2f479cd2 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Thu, 28 Mar 2019 07:01:34 +0900 Subject: Fixed mistakes in 92dce05 * rename `sym2name` to `sym2name_len`. * `MRB_API` -> `static` --- src/symbol.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/symbol.c b/src/symbol.c index 4cf79046e..a7441565a 100644 --- a/src/symbol.c +++ b/src/symbol.c @@ -236,8 +236,8 @@ mrb_check_intern_str(mrb_state *mrb, mrb_value str) return mrb_check_intern(mrb, RSTRING_PTR(str), RSTRING_LEN(str)); } -MRB_API const char* -sym2name(mrb_state *mrb, mrb_sym sym, char *buf, mrb_int *lenp) +static const char* +sym2name_len(mrb_state *mrb, mrb_sym sym, char *buf, mrb_int *lenp) { #ifndef MRB_ENABLE_ALL_SYMBOLS if (sym & 1) { /* inline packed symbol */ @@ -258,7 +258,7 @@ sym2name(mrb_state *mrb, mrb_sym sym, char *buf, mrb_int *lenp) MRB_API const char* mrb_sym2name_len(mrb_state *mrb, mrb_sym sym, mrb_int *lenp) { - return sym2name(mrb, sym, mrb->symbuf, lenp); + return sym2name_len(mrb, sym, mrb->symbuf, lenp); } void @@ -552,8 +552,8 @@ sym_cmp(mrb_state *mrb, mrb_value s1) mrb_int len, len1, len2; char buf1[8], buf2[8]; - p1 = sym2name(mrb, sym1, buf1, &len1); - p2 = sym2name(mrb, sym2, buf2, &len2); + p1 = sym2name_len(mrb, sym1, buf1, &len1); + p2 = sym2name_len(mrb, sym2, buf2, &len2); len = lesser(len1, len2); retval = memcmp(p1, p2, len); if (retval == 0) { -- cgit v1.2.3 From da2bc9e678d9f2cb4d0402701175e303a55308df Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Thu, 28 Mar 2019 19:56:51 +0900 Subject: Use `mrb_sym2str` in implementation of `Symbol#to_s` --- src/symbol.c | 24 ++++++++---------------- 1 file changed, 8 insertions(+), 16 deletions(-) diff --git a/src/symbol.c b/src/symbol.c index a7441565a..8ca03344c 100644 --- a/src/symbol.c +++ b/src/symbol.c @@ -324,17 +324,9 @@ mrb_init_symtbl(mrb_state *mrb) * :fred.id2name #=> "fred" */ static mrb_value -mrb_sym_to_s(mrb_state *mrb, mrb_value sym) +sym_to_s(mrb_state *mrb, mrb_value sym) { - mrb_sym id = mrb_symbol(sym); - const char *p; - mrb_int len; - - p = mrb_sym2name_len(mrb, id, &len); - if (id&1) { /* inline symbol */ - return mrb_str_new(mrb, p, len); - } - return mrb_str_new_static(mrb, p, len); + return mrb_sym2str(mrb, mrb_symbol(sym)); } /* 15.2.11.3.4 */ @@ -571,13 +563,13 @@ mrb_init_symbol(mrb_state *mrb) { struct RClass *sym; - mrb->symbol_class = sym = mrb_define_class(mrb, "Symbol", mrb->object_class); /* 15.2.11 */ + mrb->symbol_class = sym = mrb_define_class(mrb, "Symbol", mrb->object_class); /* 15.2.11 */ MRB_SET_INSTANCE_TT(sym, MRB_TT_SYMBOL); mrb_undef_class_method(mrb, sym, "new"); - mrb_define_method(mrb, sym, "id2name", mrb_sym_to_s, MRB_ARGS_NONE()); /* 15.2.11.3.2 */ - mrb_define_method(mrb, sym, "to_s", mrb_sym_to_s, MRB_ARGS_NONE()); /* 15.2.11.3.3 */ - mrb_define_method(mrb, sym, "to_sym", sym_to_sym, MRB_ARGS_NONE()); /* 15.2.11.3.4 */ - mrb_define_method(mrb, sym, "inspect", sym_inspect, MRB_ARGS_NONE()); /* 15.2.11.3.5(x) */ - mrb_define_method(mrb, sym, "<=>", sym_cmp, MRB_ARGS_REQ(1)); + mrb_define_method(mrb, sym, "id2name", sym_to_s, MRB_ARGS_NONE()); /* 15.2.11.3.2 */ + mrb_define_method(mrb, sym, "to_s", sym_to_s, MRB_ARGS_NONE()); /* 15.2.11.3.3 */ + mrb_define_method(mrb, sym, "to_sym", sym_to_sym, MRB_ARGS_NONE()); /* 15.2.11.3.4 */ + mrb_define_method(mrb, sym, "inspect", sym_inspect, MRB_ARGS_NONE()); /* 15.2.11.3.5(x) */ + mrb_define_method(mrb, sym, "<=>", sym_cmp, MRB_ARGS_REQ(1)); } -- cgit v1.2.3 From a26856f88313679c24ec7f9f098082e0949f9d44 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Thu, 28 Mar 2019 14:01:18 +0900 Subject: Use `DBL_EPSILON` instead of `1E-12`; ref #4345 --- mrbgems/mruby-math/src/math.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/mrbgems/mruby-math/src/math.c b/mrbgems/mruby-math/src/math.c index c29ba6808..39fed6cd3 100644 --- a/mrbgems/mruby-math/src/math.c +++ b/mrbgems/mruby-math/src/math.c @@ -23,8 +23,6 @@ domain_error(mrb_state *mrb, const char *func) #include -#define MATH_TOLERANCE 1E-12 - double asinh(double x) { @@ -122,7 +120,7 @@ erf(double x) term *= xsqr/j; sum += term/(2*j+1); ++j; - } while (fabs(term/sum) > MATH_TOLERANCE); + } while (fabs(term/sum) > DBL_EPSILON); return two_sqrtpi*sum; } @@ -155,7 +153,7 @@ erfc(double x) n += 0.5; q1 = q2; q2 = b/d; - } while (fabs(q1-q2)/q2 > MATH_TOLERANCE); + } while (fabs(q1-q2)/q2 > DBL_EPSILON); return one_sqrtpi*exp(-x*x)*q2; } -- cgit v1.2.3 From 3b92b642eb3f7e3ed1b68bda86d073d310c5d131 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Thu, 28 Mar 2019 14:02:30 +0900 Subject: Break loop whem `sum==0` to avoid zero division; ref #4345 --- mrbgems/mruby-math/src/math.c | 1 + 1 file changed, 1 insertion(+) diff --git a/mrbgems/mruby-math/src/math.c b/mrbgems/mruby-math/src/math.c index 39fed6cd3..ef0dc1857 100644 --- a/mrbgems/mruby-math/src/math.c +++ b/mrbgems/mruby-math/src/math.c @@ -120,6 +120,7 @@ erf(double x) term *= xsqr/j; sum += term/(2*j+1); ++j; + if (sum == 0) break; } while (fabs(term/sum) > DBL_EPSILON); return two_sqrtpi*sum; } -- cgit v1.2.3 From 42f240796f653348ba0e0feefdec714b06cd3479 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Thu, 28 Mar 2019 14:06:01 +0900 Subject: Use `Mrbtest::FLOAT_TOLERANCE` instead of `Math::TORELANCE`; ref #4345 --- mrbgems/mruby-math/src/math.c | 6 ------ mrbgems/mruby-math/test/math.rb | 4 ++-- 2 files changed, 2 insertions(+), 8 deletions(-) diff --git a/mrbgems/mruby-math/src/math.c b/mrbgems/mruby-math/src/math.c index ef0dc1857..caa16b789 100644 --- a/mrbgems/mruby-math/src/math.c +++ b/mrbgems/mruby-math/src/math.c @@ -741,12 +741,6 @@ mrb_mruby_math_gem_init(mrb_state* mrb) mrb_define_const(mrb, mrb_math, "E", mrb_float_value(mrb, exp(1.0))); #endif -#ifdef MRB_USE_FLOAT - mrb_define_const(mrb, mrb_math, "TOLERANCE", mrb_float_value(mrb, 1e-5)); -#else - mrb_define_const(mrb, mrb_math, "TOLERANCE", mrb_float_value(mrb, 1e-12)); -#endif - mrb_define_module_function(mrb, mrb_math, "sin", math_sin, MRB_ARGS_REQ(1)); mrb_define_module_function(mrb, mrb_math, "cos", math_cos, MRB_ARGS_REQ(1)); mrb_define_module_function(mrb, mrb_math, "tan", math_tan, MRB_ARGS_REQ(1)); diff --git a/mrbgems/mruby-math/test/math.rb b/mrbgems/mruby-math/test/math.rb index e9ea07cc1..4b474f212 100644 --- a/mrbgems/mruby-math/test/math.rb +++ b/mrbgems/mruby-math/test/math.rb @@ -3,9 +3,9 @@ ## # Performs fuzzy check for equality on methods returning floats -# on the basis of the Math::TOLERANCE constant. +# on the basis of the Mrbtest::FLOAT_TOLERANCE constant. def check_float(a, b) - tolerance = Math::TOLERANCE + tolerance = Mrbtest::FLOAT_TOLERANCE a = a.to_f b = b.to_f if a.finite? and b.finite? -- cgit v1.2.3 From d1f937e1f4d73b0dc3fbc5a3afe8a585e83290c3 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Fri, 29 Mar 2019 09:40:13 +0900 Subject: Fix missing assertions in `mruby-math` test --- mrbgems/mruby-math/test/math.rb | 82 ++++++++++++++++------------------------- 1 file changed, 31 insertions(+), 51 deletions(-) diff --git a/mrbgems/mruby-math/test/math.rb b/mrbgems/mruby-math/test/math.rb index 4b474f212..86a4fc12c 100644 --- a/mrbgems/mruby-math/test/math.rb +++ b/mrbgems/mruby-math/test/math.rb @@ -1,46 +1,31 @@ ## # Math Test -## -# Performs fuzzy check for equality on methods returning floats -# on the basis of the Mrbtest::FLOAT_TOLERANCE constant. -def check_float(a, b) - tolerance = Mrbtest::FLOAT_TOLERANCE - a = a.to_f - b = b.to_f - if a.finite? and b.finite? - (a-b).abs < tolerance - else - true - end -end - assert('Math.sin 0') do - check_float(Math.sin(0), 0) + assert_float(0, Math.sin(0)) end assert('Math.sin PI/2') do - check_float(Math.sin(Math::PI / 2), 1) + assert_float(1, Math.sin(Math::PI / 2)) end assert('Math.cos 0') do - check_float(Math.cos(0), 1) + assert_float(1, Math.cos(0)) end assert('Math.cos PI/2') do - check_float(Math.cos(Math::PI / 2), 0) + assert_float(0, Math.cos(Math::PI / 2)) end assert('Math.tan 0') do - check_float(Math.tan(0), 0) + assert_float(0, Math.tan(0)) end assert('Math.tan PI/4') do - check_float(Math.tan(Math::PI / 4), 1) + assert_float(1, Math.tan(Math::PI / 4)) end assert('Fundamental trig identities') do - result = true N = 13 N.times do |i| a = Math::PI / N * i @@ -48,105 +33,100 @@ assert('Fundamental trig identities') do s = Math.sin(a) c = Math.cos(a) t = Math.tan(a) - result &= check_float(s, Math.cos(ca)) - result &= check_float(t, 1 / Math.tan(ca)) - result &= check_float(s ** 2 + c ** 2, 1) - result &= check_float(t ** 2 + 1, (1/c) ** 2) - result &= check_float((1/t) ** 2 + 1, (1/s) ** 2) + assert_float(Math.cos(ca), s) + assert_float(1 / Math.tan(ca), t) + assert_float(1, s ** 2 + c ** 2) + assert_float((1/c) ** 2, t ** 2 + 1) + assert_float((1/s) ** 2, (1/t) ** 2 + 1) end - result end assert('Math.erf 0') do - check_float(Math.erf(0), 0) + assert_float(0, Math.erf(0)) end assert('Math.exp 0') do - check_float(Math.exp(0), 1.0) + assert_float(1.0, Math.exp(0)) end assert('Math.exp 1') do - check_float(Math.exp(1), 2.718281828459045) + assert_float(2.718281828459045, Math.exp(1)) end assert('Math.exp 1.5') do - check_float(Math.exp(1.5), 4.4816890703380645) + assert_float(4.4816890703380645, Math.exp(1.5)) end assert('Math.log 1') do - check_float(Math.log(1), 0) + assert_float(0, Math.log(1)) end assert('Math.log E') do - check_float(Math.log(Math::E), 1.0) + assert_float(1.0, Math.log(Math::E)) end assert('Math.log E**3') do - check_float(Math.log(Math::E**3), 3.0) + assert_float(3.0, Math.log(Math::E**3)) end assert('Math.log2 1') do - check_float(Math.log2(1), 0.0) + assert_float(0.0, Math.log2(1)) end assert('Math.log2 2') do - check_float(Math.log2(2), 1.0) + assert_float(1.0, Math.log2(2)) end assert('Math.log10 1') do - check_float(Math.log10(1), 0.0) + assert_float(0.0, Math.log10(1)) end assert('Math.log10 10') do - check_float(Math.log10(10), 1.0) + assert_float(1.0, Math.log10(10)) end assert('Math.log10 10**100') do - check_float(Math.log10(10**100), 100.0) + assert_float(100.0, Math.log10(10**100)) end assert('Math.sqrt') do num = [0.0, 1.0, 2.0, 3.0, 4.0] sqr = [0, 1, 4, 9, 16] - result = true sqr.each_with_index do |v,i| - result &= check_float(Math.sqrt(v), num[i]) + assert_float(num[i], Math.sqrt(v)) end - result end assert('Math.cbrt') do num = [-2.0, -1.0, 0.0, 1.0, 2.0] cub = [-8, -1, 0, 1, 8] - result = true cub.each_with_index do |v,i| - result &= check_float(Math.cbrt(v), num[i]) + assert_float(num[i], Math.cbrt(v)) end - result end assert('Math.hypot') do - check_float(Math.hypot(3, 4), 5.0) + assert_float(5.0, Math.hypot(3, 4)) end assert('Math.frexp 1234') do n = 1234 fraction, exponent = Math.frexp(n) - check_float(Math.ldexp(fraction, exponent), n) + assert_float(n, Math.ldexp(fraction, exponent)) end assert('Math.erf 1') do - check_float(Math.erf(1), 0.842700792949715) + assert_float(0.842700792949715, Math.erf(1)) end assert('Math.erfc 1') do - check_float(Math.erfc(1), 0.157299207050285) + assert_float(0.157299207050285, Math.erfc(1)) end assert('Math.erf -1') do - check_float(Math.erf(-1), -0.8427007929497148) + assert_float(-0.8427007929497148, Math.erf(-1)) end assert('Math.erfc -1') do - check_float(Math.erfc(-1), 1.8427007929497148) + assert_float(1.8427007929497148, Math.erfc(-1)) end -- cgit v1.2.3 From d8d59f70c1a3a203517a542e0f6ab401d94746f6 Mon Sep 17 00:00:00 2001 From: Tomoyuki Sahara Date: Fri, 29 Mar 2019 11:54:19 +0900 Subject: va_list is defined in stdarg.h. fixes build on OpenBSD. --- include/mruby.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/mruby.h b/include/mruby.h index f2c800eec..d891d0f5c 100644 --- a/include/mruby.h +++ b/include/mruby.h @@ -34,6 +34,7 @@ #define __STDC_FORMAT_MACROS #endif +#include #include #include #include -- cgit v1.2.3 From 4e9c90ed47cfdd6a955602415636eb79da5015b9 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Sat, 30 Mar 2019 13:19:31 +0900 Subject: Add `pass` and `flunk` to `test/assert.rb` --- test/assert.rb | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/test/assert.rb b/test/assert.rb index 33d9285ce..d20b83b18 100644 --- a/test/assert.rb +++ b/test/assert.rb @@ -151,11 +151,11 @@ def assert_float(exp, act, msg = nil) e, a = exp.to_f, act.to_f if (e.infinite? || a.infinite?) && e != a || e.nan? && !a.nan? || !e.nan? && a.nan? - assert_true(false, msg, " Expected #{act} to be #{exp}.") + flunk(msg, " Expected #{act} to be #{exp}.") elsif (n = (e - a).abs) > Mrbtest::FLOAT_TOLERANCE - assert_true(false, msg, " Expected |#{exp} - #{act}| (#{n}) to be <= #{Mrbtest::FLOAT_TOLERANCE}.") + flunk(msg, " Expected |#{exp} - #{act}| (#{n}) to be <= #{Mrbtest::FLOAT_TOLERANCE}.") else - assert_true(true) + pass end end @@ -165,15 +165,15 @@ def assert_raise(*exc) begin yield rescue *exc - assert_true(true) + pass rescue Exception => e diff = " #{exc} exception expected, not\n" \ " Class: <#{e.class}>\n" \ " Message: <#{e}>" - assert_true(false, msg, diff) + flunk(msg, diff) else diff = " #{exc} expected but nothing was raised." - assert_true(false, msg, diff) + flunk(msg, diff) end end @@ -184,12 +184,20 @@ def assert_nothing_raised(msg = nil) diff = " Exception raised:\n" \ " Class: <#{e.class}>\n" \ " Message: <#{e}>" - assert_true(false, msg, diff) + flunk(msg, diff) else - assert_true(true) + pass end end +def pass + assert_true(true) +end + +def flunk(msg = nil, diff = "Epic Fail!") + assert_true(false, msg, diff) +end + ## # Report the test result and print all assertions # which were reported broken. -- cgit v1.2.3 From 9b024dcf7a4228dbafc4bfa99d976468cde2ef94 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Sun, 31 Mar 2019 14:52:18 +0900 Subject: Fix warning: '*' interpreted as argument prefix --- test/assert.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/assert.rb b/test/assert.rb index d20b83b18..c57b04c12 100644 --- a/test/assert.rb +++ b/test/assert.rb @@ -8,7 +8,7 @@ $test_start = Time.now if Object.const_defined?(:Time) unless RUBY_ENGINE == "mruby" # For bintest on Ruby def t_print(*args) - print *args + print(*args) $stdout.flush nil end -- cgit v1.2.3 From 2871d0cdc5e5ef952d27187b5488888bbd18c5b0 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Mon, 1 Apr 2019 14:13:06 +0900 Subject: Avoid keeping pointers from `mrb_sym2name_len()`; fix #4342 The addresses for packed inline symbols reference `mrb->symbuf` that could be overridden by the later call of `mrb_sym2name_len`. Since file names in call stack information are kept as symbols, keeping the address in the C structures could cause problems like #4342. This changes small incompatible changes in function prototypes: * `mrb_parser_get_filename`: return value changed to `mrb_sym`. * `mrb_debug_get_filename`: add `mrb_state*` as a first argument. * `mrb_debug_get_line`: ditto. I believe above functions are almost internal, and no third-party mrbgem use them. --- include/mruby/compile.h | 4 ++-- include/mruby/debug.h | 5 ++--- mrbgems/mruby-bin-debugger/tools/mrdb/apibreak.c | 16 ++++++++------- mrbgems/mruby-bin-debugger/tools/mrdb/apilist.c | 2 +- mrbgems/mruby-bin-debugger/tools/mrdb/cmdbreak.c | 6 +++--- mrbgems/mruby-bin-debugger/tools/mrdb/mrdb.c | 4 ++-- mrbgems/mruby-compiler/core/codegen.c | 25 +++++++++++++----------- mrbgems/mruby-compiler/core/parse.y | 20 ++++++++++--------- mrbgems/mruby-proc-ext/src/proc.c | 8 ++++---- src/backtrace.c | 4 ++-- src/class.c | 14 +++---------- src/codedump.c | 14 ++++++------- src/debug.c | 15 +++++++------- src/error.c | 4 ++-- src/load.c | 3 --- src/symbol.c | 9 ++++++++- 16 files changed, 77 insertions(+), 76 deletions(-) diff --git a/include/mruby/compile.h b/include/mruby/compile.h index fd735be88..f19d9b0b3 100644 --- a/include/mruby/compile.h +++ b/include/mruby/compile.h @@ -118,7 +118,7 @@ struct mrb_parser_state { FILE *f; #endif mrbc_context *cxt; - char const *filename; + mrb_sym filename_sym; int lineno; int column; @@ -168,7 +168,7 @@ MRB_API void mrb_parser_free(struct mrb_parser_state*); MRB_API void mrb_parser_parse(struct mrb_parser_state*,mrbc_context*); MRB_API void mrb_parser_set_filename(struct mrb_parser_state*, char const*); -MRB_API char const* mrb_parser_get_filename(struct mrb_parser_state*, uint16_t idx); +MRB_API mrb_sym mrb_parser_get_filename(struct mrb_parser_state*, uint16_t idx); /* utility functions */ #ifndef MRB_DISABLE_STDIO diff --git a/include/mruby/debug.h b/include/mruby/debug.h index f0a40dfcf..e08c47cfc 100644 --- a/include/mruby/debug.h +++ b/include/mruby/debug.h @@ -26,7 +26,6 @@ typedef struct mrb_irep_debug_info_line { typedef struct mrb_irep_debug_info_file { uint32_t start_pos; - const char *filename; mrb_sym filename_sym; uint32_t line_entry_count; mrb_debug_line_type line_type; @@ -47,13 +46,13 @@ typedef struct mrb_irep_debug_info { * get line from irep's debug info and program counter * @return returns NULL if not found */ -MRB_API const char *mrb_debug_get_filename(mrb_irep *irep, ptrdiff_t pc); +MRB_API const char *mrb_debug_get_filename(mrb_state *mrb, mrb_irep *irep, ptrdiff_t pc); /* * get line from irep's debug info and program counter * @return returns -1 if not found */ -MRB_API int32_t mrb_debug_get_line(mrb_irep *irep, ptrdiff_t pc); +MRB_API int32_t mrb_debug_get_line(mrb_state *mrb, mrb_irep *irep, ptrdiff_t pc); MRB_API mrb_irep_debug_info *mrb_debug_info_alloc(mrb_state *mrb, mrb_irep *irep); MRB_API mrb_irep_debug_info_file *mrb_debug_info_append_file( diff --git a/mrbgems/mruby-bin-debugger/tools/mrdb/apibreak.c b/mrbgems/mruby-bin-debugger/tools/mrdb/apibreak.c index d3ccf08ae..513db4ded 100644 --- a/mrbgems/mruby-bin-debugger/tools/mrdb/apibreak.c +++ b/mrbgems/mruby-bin-debugger/tools/mrdb/apibreak.c @@ -84,7 +84,7 @@ free_breakpoint(mrb_state *mrb, mrb_debug_breakpoint *bp) } static uint16_t -check_file_lineno(struct mrb_irep *irep, const char *file, uint16_t lineno) +check_file_lineno(mrb_state *mrb, struct mrb_irep *irep, const char *file, uint16_t lineno) { mrb_irep_debug_info_file *info_file; uint16_t result = 0; @@ -93,8 +93,10 @@ check_file_lineno(struct mrb_irep *irep, const char *file, uint16_t lineno) uint16_t i; for (f_idx = 0; f_idx < irep->debug_info->flen; ++f_idx) { + const char *filename; info_file = irep->debug_info->files[f_idx]; - if (!strcmp(info_file->filename, file)) { + filename = mrb_sym2name_len(mrb, info_file->filename_sym, NULL); + if (!strcmp(filename, file)) { result = MRB_DEBUG_BP_FILE_OK; fix_lineno = check_lineno(info_file, lineno); @@ -103,7 +105,7 @@ check_file_lineno(struct mrb_irep *irep, const char *file, uint16_t lineno) } } for (i=0; i < irep->rlen; ++i) { - result |= check_file_lineno(irep->reps[i], file, lineno); + result |= check_file_lineno(mrb, irep->reps[i], file, lineno); if (result == (MRB_DEBUG_BP_FILE_OK | MRB_DEBUG_BP_LINENO_OK)) { return result; } @@ -185,7 +187,7 @@ mrb_debug_set_break_line(mrb_state *mrb, mrb_debug_context *dbg, const char *fil } /* file and lineno check (line type mrb_debug_line_ary only.) */ - result = check_file_lineno(dbg->root_irep, file, lineno); + result = check_file_lineno(mrb, dbg->root_irep, file, lineno); if (result == 0) { return MRB_DEBUG_BREAK_INVALID_FILE; } @@ -426,10 +428,10 @@ mrb_debug_disable_break_all(mrb_state *mrb, mrb_debug_context *dbg) } static mrb_bool -check_start_pc_for_line(mrb_irep *irep, mrb_code *pc, uint16_t line) +check_start_pc_for_line(mrb_state *mrb, mrb_irep *irep, mrb_code *pc, uint16_t line) { if (pc > irep->iseq) { - if (line == mrb_debug_get_line(irep, pc - irep->iseq - 1)) { + if (line == mrb_debug_get_line(mrb, irep, pc - irep->iseq - 1)) { return FALSE; } } @@ -447,7 +449,7 @@ mrb_debug_check_breakpoint_line(mrb_state *mrb, mrb_debug_context *dbg, const ch return MRB_DEBUG_INVALID_ARGUMENT; } - if (!check_start_pc_for_line(dbg->irep, dbg->pc, line)) { + if (!check_start_pc_for_line(mrb, dbg->irep, dbg->pc, line)) { return MRB_DEBUG_OK; } diff --git a/mrbgems/mruby-bin-debugger/tools/mrdb/apilist.c b/mrbgems/mruby-bin-debugger/tools/mrdb/apilist.c index 21fe64127..66ddfa783 100644 --- a/mrbgems/mruby-bin-debugger/tools/mrdb/apilist.c +++ b/mrbgems/mruby-bin-debugger/tools/mrdb/apilist.c @@ -181,7 +181,7 @@ mrb_debug_get_source(mrb_state *mrb, mrdb_state *mrdb, const char *srcpath, cons else srcname = filename; search_path[0] = srcpath; - search_path[1] = dirname(mrb, mrb_debug_get_filename(mrdb->dbg->irep, 0)); + search_path[1] = dirname(mrb, mrb_debug_get_filename(mrb, mrdb->dbg->irep, 0)); search_path[2] = "."; for (i = 0; i < 3; i++) { diff --git a/mrbgems/mruby-bin-debugger/tools/mrdb/cmdbreak.c b/mrbgems/mruby-bin-debugger/tools/mrdb/cmdbreak.c index 8e5901754..bc9937e94 100644 --- a/mrbgems/mruby-bin-debugger/tools/mrdb/cmdbreak.c +++ b/mrbgems/mruby-bin-debugger/tools/mrdb/cmdbreak.c @@ -242,7 +242,7 @@ info_break_select(mrb_state *mrb, mrdb_state *mrdb) } mrb_debug_bptype -parse_breakcommand(mrdb_state *mrdb, const char **file, uint32_t *line, char **cname, char **method) +parse_breakcommand(mrb_state *mrb, mrdb_state *mrdb, const char **file, uint32_t *line, char **cname, char **method) { mrb_debug_context *dbg = mrdb->dbg; char *args; @@ -274,7 +274,7 @@ parse_breakcommand(mrdb_state *mrdb, const char **file, uint32_t *line, char **c STRTOUL(l, body); if (l <= 65535) { *line = l; - *file = (body == args)? mrb_debug_get_filename(dbg->irep, dbg->pc - dbg->irep->iseq): args; + *file = (body == args)? mrb_debug_get_filename(mrb, dbg->irep, dbg->pc - dbg->irep->iseq): args; } else { puts(BREAK_ERR_MSG_RANGEOVER); @@ -332,7 +332,7 @@ dbgcmd_break(mrb_state *mrb, mrdb_state *mrdb) char *method = NULL; int32_t ret; - type = parse_breakcommand(mrdb, &file, &line, &cname, &method); + type = parse_breakcommand(mrb, mrdb, &file, &line, &cname, &method); switch (type) { case MRB_DEBUG_BPTYPE_LINE: ret = mrb_debug_set_break_line(mrb, dbg, file, line); diff --git a/mrbgems/mruby-bin-debugger/tools/mrdb/mrdb.c b/mrbgems/mruby-bin-debugger/tools/mrdb/mrdb.c index 5256ac5e3..003406172 100644 --- a/mrbgems/mruby-bin-debugger/tools/mrdb/mrdb.c +++ b/mrbgems/mruby-bin-debugger/tools/mrdb/mrdb.c @@ -569,8 +569,8 @@ mrb_code_fetch_hook(mrb_state *mrb, mrb_irep *irep, mrb_code *pc, mrb_value *reg dbg->xphase = DBG_PHASE_RUNNING; } - file = mrb_debug_get_filename(irep, pc - irep->iseq); - line = mrb_debug_get_line(irep, pc - irep->iseq); + file = mrb_debug_get_filename(mrb, irep, pc - irep->iseq); + line = mrb_debug_get_line(mrb, irep, pc - irep->iseq); switch (dbg->xm) { case DBG_STEP: diff --git a/mrbgems/mruby-compiler/core/codegen.c b/mrbgems/mruby-compiler/core/codegen.c index a2d790e32..927cc3a0f 100644 --- a/mrbgems/mruby-compiler/core/codegen.c +++ b/mrbgems/mruby-compiler/core/codegen.c @@ -62,7 +62,7 @@ typedef struct scope { struct loopinfo *loop; int ensure_level; - char const *filename; + mrb_sym filename_sym; uint16_t lineno; mrb_code *iseq; @@ -106,8 +106,9 @@ codegen_error(codegen_scope *s, const char *message) s = tmp; } #ifndef MRB_DISABLE_STDIO - if (s->filename && s->lineno) { - fprintf(stderr, "codegen error:%s:%d: %s\n", s->filename, s->lineno, message); + if (s->filename_sym && s->lineno) { + const char *filename = mrb_sym2name_len(s->mrb, s->filename_sym, NULL); + fprintf(stderr, "codegen error:%s:%d: %s\n", filename, s->lineno, message); } else { fprintf(stderr, "codegen error: %s\n", message); @@ -1399,13 +1400,14 @@ codegen(codegen_scope *s, node *tree, int val) codegen_error(s, "too complex expression"); } if (s->irep && s->filename_index != tree->filename_index) { - const char *filename = mrb_parser_get_filename(s->parser, s->filename_index); + mrb_sym fname = mrb_parser_get_filename(s->parser, s->filename_index); + const char *filename = mrb_sym2name_len(s->mrb, fname, NULL); mrb_debug_info_append_file(s->mrb, s->irep->debug_info, filename, s->lines, s->debug_start_pos, s->pc); s->debug_start_pos = s->pc; s->filename_index = tree->filename_index; - s->filename = mrb_parser_get_filename(s->parser, tree->filename_index); + s->filename_sym = mrb_parser_get_filename(s->parser, tree->filename_index); } nt = nint(tree->car); @@ -2990,15 +2992,15 @@ scope_new(mrb_state *mrb, codegen_scope *prev, node *lv) } p->ai = mrb_gc_arena_save(mrb); - p->filename = prev->filename; - if (p->filename) { + p->filename_sym = prev->filename_sym; + if (p->filename_sym) { p->lines = (uint16_t*)mrb_malloc(mrb, sizeof(short)*p->icapa); } p->lineno = prev->lineno; /* debug setting */ p->debug_start_pos = 0; - if (p->filename) { + if (p->filename_sym) { mrb_debug_info_alloc(mrb, p->irep); } else { @@ -3026,8 +3028,9 @@ scope_finish(codegen_scope *s) irep->pool = (mrb_value*)codegen_realloc(s, irep->pool, sizeof(mrb_value)*irep->plen); irep->syms = (mrb_sym*)codegen_realloc(s, irep->syms, sizeof(mrb_sym)*irep->slen); irep->reps = (mrb_irep**)codegen_realloc(s, irep->reps, sizeof(mrb_irep*)*irep->rlen); - if (s->filename) { - const char *filename = mrb_parser_get_filename(s->parser, s->filename_index); + if (s->filename_sym) { + mrb_sym fname = mrb_parser_get_filename(s->parser, s->filename_index); + const char *filename = mrb_sym2name_len(s->mrb, fname, NULL); mrb_debug_info_append_file(s->mrb, s->irep->debug_info, filename, s->lines, s->debug_start_pos, s->pc); @@ -3136,7 +3139,7 @@ generate_code(mrb_state *mrb, parser_state *p, int val) } scope->mrb = mrb; scope->parser = p; - scope->filename = p->filename; + scope->filename_sym = p->filename_sym; scope->filename_index = p->current_filename_index; MRB_TRY(&scope->jmp) { diff --git a/mrbgems/mruby-compiler/core/parse.y b/mrbgems/mruby-compiler/core/parse.y index 90f01e3a8..88d9ea4ee 100644 --- a/mrbgems/mruby-compiler/core/parse.y +++ b/mrbgems/mruby-compiler/core/parse.y @@ -3162,7 +3162,7 @@ var_ref : variable } | keyword__FILE__ { - const char *fn = p->filename; + const char *fn = mrb_sym2name_len(p->mrb, p->filename_sym, NULL); if (!fn) { fn = "(null)"; } @@ -3671,8 +3671,9 @@ yyerror(parser_state *p, const char *s) if (! p->capture_errors) { #ifndef MRB_DISABLE_STDIO - if (p->filename) { - fprintf(stderr, "%s:%d:%d: %s\n", p->filename, p->lineno, p->column, s); + if (p->filename_sym) { + const char *filename = mrb_sym2name_len(p->mrb, p->filename_sym, NULL); + fprintf(stderr, "%s:%d:%d: %s\n", filename, p->lineno, p->column, s); } else { fprintf(stderr, "line %d:%d: %s\n", p->lineno, p->column, s); @@ -3707,8 +3708,9 @@ yywarn(parser_state *p, const char *s) if (! p->capture_errors) { #ifndef MRB_DISABLE_STDIO - if (p->filename) { - fprintf(stderr, "%s:%d:%d: warning: %s\n", p->filename, p->lineno, p->column, s); + if (p->filename_sym) { + const char *filename = mrb_sym2name_len(p->mrb, p->filename_sym, NULL); + fprintf(stderr, "%s:%d:%d: warning: %s\n", filename, p->lineno, p->column, s); } else { fprintf(stderr, "line %d:%d: warning: %s\n", p->lineno, p->column, s); @@ -6012,7 +6014,7 @@ mrb_parser_set_filename(struct mrb_parser_state *p, const char *f) mrb_sym* new_table; sym = mrb_intern_cstr(p->mrb, f); - p->filename = mrb_sym2name_len(p->mrb, sym, NULL); + p->filename_sym = sym; p->lineno = (p->filename_table_length > 0)? 0 : 1; for (i = 0; i < p->filename_table_length; ++i) { @@ -6036,11 +6038,11 @@ mrb_parser_set_filename(struct mrb_parser_state *p, const char *f) p->filename_table[p->filename_table_length - 1] = sym; } -MRB_API char const* +MRB_API mrb_sym mrb_parser_get_filename(struct mrb_parser_state* p, uint16_t idx) { - if (idx >= p->filename_table_length) return NULL; + if (idx >= p->filename_table_length) return 0; else { - return mrb_sym2name_len(p->mrb, p->filename_table[idx], NULL); + return p->filename_table[idx]; } } diff --git a/mrbgems/mruby-proc-ext/src/proc.c b/mrbgems/mruby-proc-ext/src/proc.c index 4b85c245d..17884e3c6 100644 --- a/mrbgems/mruby-proc-ext/src/proc.c +++ b/mrbgems/mruby-proc-ext/src/proc.c @@ -25,8 +25,8 @@ mrb_proc_source_location(mrb_state *mrb, mrb_value self) int32_t line; const char *filename; - filename = mrb_debug_get_filename(irep, 0); - line = mrb_debug_get_line(irep, 0); + filename = mrb_debug_get_filename(mrb, irep, 0); + line = mrb_debug_get_line(mrb, irep, 0); return (!filename && line == -1)? mrb_nil_value() : mrb_assoc_new(mrb, mrb_str_new_cstr(mrb, filename), mrb_fixnum_value(line)); @@ -46,11 +46,11 @@ mrb_proc_inspect(mrb_state *mrb, mrb_value self) int32_t line; mrb_str_cat_lit(mrb, str, "@"); - filename = mrb_debug_get_filename(irep, 0); + filename = mrb_debug_get_filename(mrb, irep, 0); mrb_str_cat_cstr(mrb, str, filename ? filename : "-"); mrb_str_cat_lit(mrb, str, ":"); - line = mrb_debug_get_line(irep, 0); + line = mrb_debug_get_line(mrb, irep, 0); if (line != -1) { str = mrb_format(mrb, "%S:%S", str, mrb_fixnum_value(line)); } diff --git a/src/backtrace.c b/src/backtrace.c index efca2562f..e4f5a3064 100644 --- a/src/backtrace.c +++ b/src/backtrace.c @@ -58,10 +58,10 @@ each_backtrace(mrb_state *mrb, ptrdiff_t ciidx, mrb_code *pc0, each_backtrace_fu pc = pc0; } - loc.lineno = mrb_debug_get_line(irep, pc - irep->iseq); + loc.lineno = mrb_debug_get_line(mrb, irep, pc - irep->iseq); if (loc.lineno == -1) continue; - loc.filename = mrb_debug_get_filename(irep, pc - irep->iseq); + loc.filename = mrb_debug_get_filename(mrb, irep, pc - irep->iseq); if (!loc.filename) { loc.filename = "(unknown)"; } diff --git a/src/class.c b/src/class.c index 3354617bb..5c5ee9d17 100644 --- a/src/class.c +++ b/src/class.c @@ -484,15 +484,11 @@ mrb_define_method(mrb_state *mrb, struct RClass *c, const char *name, mrb_func_t MRB_API void mrb_notimplement(mrb_state *mrb) { - const char *str; - mrb_int len; mrb_callinfo *ci = mrb->c->ci; if (ci->mid) { - str = mrb_sym2name_len(mrb, ci->mid, &len); - mrb_raisef(mrb, E_NOTIMP_ERROR, - "%S() function is unimplemented on this machine", - mrb_str_new_static(mrb, str, (size_t)len)); + mrb_value str = mrb_sym2str(mrb, ci->mid); + mrb_raisef(mrb, E_NOTIMP_ERROR, "%S() function is unimplemented on this machine", str); } } @@ -1686,11 +1682,7 @@ mrb_class_path(mrb_state *mrb, struct RClass *c) } else if (mrb_symbol_p(path)) { /* toplevel class/module */ - const char *str; - mrb_int len; - - str = mrb_sym2name_len(mrb, mrb_symbol(path), &len); - return mrb_str_new(mrb, str, len); + return mrb_sym2str(mrb, mrb_symbol(path)); } return mrb_str_dup(mrb, path); } diff --git a/src/codedump.c b/src/codedump.c index c9c3b25ef..5bffefddb 100644 --- a/src/codedump.c +++ b/src/codedump.c @@ -48,11 +48,11 @@ print_lv_ab(mrb_state *mrb, mrb_irep *irep, uint16_t a, uint16_t b) } static void -print_header(mrb_irep *irep, ptrdiff_t i) +print_header(mrb_state *mrb, mrb_irep *irep, ptrdiff_t i) { int32_t line; - line = mrb_debug_get_line(irep, i); + line = mrb_debug_get_line(mrb, irep, i); if (line < 0) { printf(" "); } @@ -99,12 +99,12 @@ codedump(mrb_state *mrb, mrb_irep *irep) ai = mrb_gc_arena_save(mrb); i = pc - irep->iseq; - next_file = mrb_debug_get_filename(irep, i); + next_file = mrb_debug_get_filename(mrb, irep, i); if (next_file && file != next_file) { printf("file: %s\n", next_file); file = next_file; } - print_header(irep, i); + print_header(mrb, irep, i); ins = READ_B(); switch (ins) { CASE(OP_NOP, Z): @@ -491,7 +491,7 @@ codedump(mrb_state *mrb, mrb_irep *irep) CASE(OP_EXT1, Z): ins = READ_B(); printf("OP_EXT1\n"); - print_header(irep, pc-irep->iseq-2); + print_header(mrb, irep, pc-irep->iseq-2); switch (ins) { #define OPCODE(i,x) case OP_ ## i: FETCH_ ## x ## _1 (); goto L_OP_ ## i; #include "mruby/ops.h" @@ -501,7 +501,7 @@ codedump(mrb_state *mrb, mrb_irep *irep) CASE(OP_EXT2, Z): ins = READ_B(); printf("OP_EXT2\n"); - print_header(irep, pc-irep->iseq-2); + print_header(mrb, irep, pc-irep->iseq-2); switch (ins) { #define OPCODE(i,x) case OP_ ## i: FETCH_ ## x ## _2 (); goto L_OP_ ## i; #include "mruby/ops.h" @@ -511,7 +511,7 @@ codedump(mrb_state *mrb, mrb_irep *irep) CASE(OP_EXT3, Z): ins = READ_B(); printf("OP_EXT3\n"); - print_header(irep, pc-irep->iseq-2); + print_header(mrb, irep, pc-irep->iseq-2); switch (ins) { #define OPCODE(i,x) case OP_ ## i: FETCH_ ## x ## _3 (); goto L_OP_ ## i; #include "mruby/ops.h" diff --git a/src/debug.c b/src/debug.c index 2949131e4..0dc02a1e3 100644 --- a/src/debug.c +++ b/src/debug.c @@ -51,20 +51,20 @@ select_line_type(const uint16_t *lines, size_t lines_len) } MRB_API char const* -mrb_debug_get_filename(mrb_irep *irep, ptrdiff_t pc) +mrb_debug_get_filename(mrb_state *mrb, mrb_irep *irep, ptrdiff_t pc) { if (irep && pc >= 0 && pc < irep->ilen) { mrb_irep_debug_info_file* f = NULL; if (!irep->debug_info) return NULL; else if ((f = get_file(irep->debug_info, (uint32_t)pc))) { - return f->filename; + return mrb_sym2name_len(mrb, f->filename_sym, NULL); } } return NULL; } MRB_API int32_t -mrb_debug_get_line(mrb_irep *irep, ptrdiff_t pc) +mrb_debug_get_line(mrb_state *mrb, mrb_irep *irep, ptrdiff_t pc) { if (irep && pc >= 0 && pc < irep->ilen) { mrb_irep_debug_info_file* f = NULL; @@ -129,7 +129,6 @@ mrb_debug_info_append_file(mrb_state *mrb, mrb_irep_debug_info *d, mrb_irep_debug_info_file *f; uint32_t file_pc_count; size_t fn_len; - mrb_int len; uint32_t i; if (!d) return NULL; @@ -138,8 +137,10 @@ mrb_debug_info_append_file(mrb_state *mrb, mrb_irep_debug_info *d, mrb_assert(filename); mrb_assert(lines); - if (d->flen > 0 && strcmp(filename, d->files[d->flen - 1]->filename) == 0) { - return NULL; + if (d->flen > 0) { + const char *fn = mrb_sym2name_len(mrb, d->files[d->flen - 1]->filename_sym, NULL); + if (strcmp(filename, fn) == 0) + return NULL; } f = (mrb_irep_debug_info_file*)mrb_malloc(mrb, sizeof(*f)); @@ -156,8 +157,6 @@ mrb_debug_info_append_file(mrb_state *mrb, mrb_irep_debug_info *d, fn_len = strlen(filename); f->filename_sym = mrb_intern(mrb, filename, fn_len); - len = 0; - f->filename = mrb_sym2name_len(mrb, f->filename_sym, &len); f->line_type = select_line_type(lines + start_pos, end_pos - start_pos); f->lines.ptr = NULL; diff --git a/src/error.c b/src/error.c index 50d1ab6f9..e69812dda 100644 --- a/src/error.c +++ b/src/error.c @@ -208,8 +208,8 @@ exc_debug_info(mrb_state *mrb, struct RObject *exc) if (err && ci->proc && !MRB_PROC_CFUNC_P(ci->proc)) { mrb_irep *irep = ci->proc->body.irep; - int32_t const line = mrb_debug_get_line(irep, err - irep->iseq); - char const* file = mrb_debug_get_filename(irep, err - irep->iseq); + int32_t const line = mrb_debug_get_line(mrb, irep, err - irep->iseq); + char const* file = mrb_debug_get_filename(mrb, irep, err - irep->iseq); if (line != -1 && file) { mrb_obj_iv_set(mrb, exc, mrb_intern_lit(mrb, "file"), mrb_str_new_cstr(mrb, file)); mrb_obj_iv_set(mrb, exc, mrb_intern_lit(mrb, "line"), mrb_fixnum_value(line)); diff --git a/src/load.c b/src/load.c index 55e0845f3..ab0346750 100644 --- a/src/load.c +++ b/src/load.c @@ -317,7 +317,6 @@ read_debug_record(mrb_state *mrb, const uint8_t *start, mrb_irep* irep, size_t * for (f_idx = 0; f_idx < irep->debug_info->flen; ++f_idx) { mrb_irep_debug_info_file *file; uint16_t filename_idx; - mrb_int len; file = (mrb_irep_debug_info_file *)mrb_malloc(mrb, sizeof(*file)); irep->debug_info->files[f_idx] = file; @@ -330,8 +329,6 @@ read_debug_record(mrb_state *mrb, const uint8_t *start, mrb_irep* irep, size_t * bin += sizeof(uint16_t); mrb_assert(filename_idx < filenames_len); file->filename_sym = filenames[filename_idx]; - len = 0; - file->filename = mrb_sym2name_len(mrb, file->filename_sym, &len); file->line_entry_count = bin_to_uint32(bin); bin += sizeof(uint32_t); diff --git a/src/symbol.c b/src/symbol.c index 8ca03344c..96ca9dd17 100644 --- a/src/symbol.c +++ b/src/symbol.c @@ -520,7 +520,14 @@ mrb_sym2name(mrb_state *mrb, mrb_sym sym) return name; } else { - mrb_value str = mrb_str_dump(mrb, mrb_str_new_static(mrb, name, len)); + mrb_value str; + if (sym&1) { /* inline symbol */ + str = mrb_str_new(mrb, name, len); + } + else { + str = mrb_str_new_static(mrb, name, len); + } + str = mrb_str_dump(mrb, str); return RSTRING_PTR(str); } } -- cgit v1.2.3 From 55cb625808ab9b498d42d13442f5ce5115d606a5 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Mon, 1 Apr 2019 19:49:30 +0900 Subject: Fix modifiable class name Fix the following example: Object.const_set :A, Module.new{const_set :B, Class.new} ab = A::B.to_s p ab #=> "A::B" # Good ab[0] = "x" p A::B.to_s #=> "x::B" # Bad --- src/variable.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/variable.c b/src/variable.c index 724b153fe..9edfb32bd 100644 --- a/src/variable.c +++ b/src/variable.c @@ -1106,6 +1106,7 @@ mrb_class_find_path(mrb_state *mrb, struct RClass *c) iv_del(mrb, c->iv, mrb_intern_lit(mrb, "__outer__"), NULL); iv_put(mrb, c->iv, mrb_intern_lit(mrb, "__classname__"), path); mrb_field_write_barrier_value(mrb, (struct RBasic*)c, path); + path = mrb_str_dup(mrb, path); } return path; } -- cgit v1.2.3 From 9b7e9addcdd517d66f9dca7506027ff05ecce206 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Tue, 2 Apr 2019 16:24:07 +0900 Subject: Pad leading zero to month and day in `MRUBY_RELEASE_DATE` For Ruby compatibility. --- include/mruby/version.h | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/include/mruby/version.h b/include/mruby/version.h index 680533ab4..da7a2eb9d 100644 --- a/include/mruby/version.h +++ b/include/mruby/version.h @@ -77,7 +77,21 @@ MRB_BEGIN_DECL /* * Release date as a string. */ -#define MRUBY_RELEASE_DATE MRB_STRINGIZE(MRUBY_RELEASE_YEAR) "-" MRB_STRINGIZE(MRUBY_RELEASE_MONTH) "-" MRB_STRINGIZE(MRUBY_RELEASE_DAY) +#define MRUBY_RELEASE_DATE \ + MRUBY_RELEASE_YEAR_STR "-" \ + MRUBY_RELEASE_MONTH_STR "-" \ + MRUBY_RELEASE_DAY_STR +#define MRUBY_RELEASE_YEAR_STR MRB_STRINGIZE(MRUBY_RELEASE_YEAR) +#if MRUBY_RELEASE_MONTH < 10 +#define MRUBY_RELEASE_MONTH_STR "0" MRB_STRINGIZE(MRUBY_RELEASE_MONTH) +#else +#define MRUBY_RELEASE_MONTH_STR MRB_STRINGIZE(MRUBY_RELEASE_MONTH) +#endif +#if MRUBY_RELEASE_DAY < 10 +#define MRUBY_RELEASE_DAY_STR "0" MRB_STRINGIZE(MRUBY_RELEASE_DAY) +#else +#define MRUBY_RELEASE_DAY_STR MRB_STRINGIZE(MRUBY_RELEASE_DAY) +#endif /* * The year mruby was first created. -- cgit v1.2.3 From abc6c990a636058f41f9d34f12451036cb9c89fd Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Wed, 3 Apr 2019 18:54:25 +0900 Subject: Remove unnecessary `_set_output_format` call Three-digit exponent issue was fixed via another workaround (63b8f5c). --- src/state.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/state.c b/src/state.c index c3ce1dc33..08d7ba906 100644 --- a/src/state.c +++ b/src/state.c @@ -42,10 +42,6 @@ mrb_open_core(mrb_allocf f, void *ud) mrb_init_core(mrb); -#if !defined(MRB_DISABLE_STDIO) && defined(_MSC_VER) && _MSC_VER < 1900 - _set_output_format(_TWO_DIGIT_EXPONENT); -#endif - return mrb; } -- cgit v1.2.3 From 5e0caefa58bb0fae4174858abb3ba8cd7ccf7058 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Wed, 3 Apr 2019 19:25:06 +0900 Subject: Modify `#else` and `#endif` annotations in `src/fmt_fp.c` [ci skip] --- src/fmt_fp.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/fmt_fp.c b/src/fmt_fp.c index 14c74ef9e..1f1af6764 100644 --- a/src/fmt_fp.c +++ b/src/fmt_fp.c @@ -372,7 +372,7 @@ mrb_float_to_str(mrb_state *mrb, mrb_value flo, const char *fmt) } return f.str; } -#else /* MRB_DISABLE_STDIO */ +#else /* MRB_DISABLE_STDIO || _WIN32 || _WIN64 */ #include #include @@ -384,5 +384,5 @@ mrb_float_to_str(mrb_state *mrb, mrb_value flo, const char *fmt) snprintf(buf, sizeof(buf), fmt, mrb_float(flo)); return mrb_str_new_cstr(mrb, buf); } -#endif /* MRB_DISABLE_STDIO */ +#endif /* MRB_DISABLE_STDIO || _WIN32 || _WIN64 */ #endif -- cgit v1.2.3 From 7c91efc1ffda769a5f1a872c646c82b00698f1b8 Mon Sep 17 00:00:00 2001 From: Hiroshi Mimaki Date: Thu, 4 Apr 2019 09:26:40 +0900 Subject: Update version and release date. `mruby 2.0.1 (2019-4-4)` --- README.md | 2 +- doc/guides/debugger.md | 2 +- doc/limitations.md | 18 +++++++++--------- include/mruby.h | 2 +- include/mruby/version.h | 8 ++++---- 5 files changed, 16 insertions(+), 16 deletions(-) diff --git a/README.md b/README.md index c3e9ae10a..3e71ef7ca 100644 --- a/README.md +++ b/README.md @@ -17,7 +17,7 @@ of the Ministry of Economy, Trade and Industry of Japan. ## How to get mruby -The stable version 2.0.0 of mruby can be downloaded via the following URL: [https://github.com/mruby/mruby/archive/2.0.0.zip](https://github.com/mruby/mruby/archive/2.0.0.zip) +The stable version 2.0.1 of mruby can be downloaded via the following URL: [https://github.com/mruby/mruby/archive/2.0.1.zip](https://github.com/mruby/mruby/archive/2.0.1.zip) The latest development version of mruby can be downloaded via the following URL: [https://github.com/mruby/mruby/zipball/master](https://github.com/mruby/mruby/zipball/master) diff --git a/doc/guides/debugger.md b/doc/guides/debugger.md index b433a5ac5..81c0e9d63 100644 --- a/doc/guides/debugger.md +++ b/doc/guides/debugger.md @@ -38,7 +38,7 @@ To confirm mrdb was installed properly, run mrdb with the `--version` option: ```bash $ mrdb --version -mruby 2.0.0 (2018-12-11) +mruby 2.0.1 (2019-4-4) ``` ## 2.2 Basic Operation diff --git a/doc/limitations.md b/doc/limitations.md index 23017ccbe..9b4ed9c6f 100644 --- a/doc/limitations.md +++ b/doc/limitations.md @@ -38,7 +38,7 @@ puts [1,2,3] 3 ``` -#### mruby [2.0.0 (2018-12-11)] +#### mruby [2.0.1 (2019-4-4)] ``` [1, 2, 3] @@ -61,7 +61,7 @@ end ```ZeroDivisionError``` is raised. -#### mruby [2.0.0 (2018-12-11)] +#### mruby [2.0.1 (2019-4-4)] No exception is raised. @@ -89,7 +89,7 @@ p Liste.new "foobar" ``` [] ``` -#### mruby [1.4.1 (2018-4-27)] +#### mruby [2.0.1 (2019-4-4)] ```ArgumentError``` is raised. @@ -119,7 +119,7 @@ false true ``` -#### mruby [2.0.0 (2018-12-11)] +#### mruby [2.0.1 (2019-4-4)] ``` true @@ -142,7 +142,7 @@ defined?(Foo) nil ``` -#### mruby [2.0.0 (2018-12-11)] +#### mruby [2.0.1 (2019-4-4)] ```NameError``` is raised. @@ -159,7 +159,7 @@ alias $a $__a__ ``` nil ``` -#### mruby [2.0.0 (2018-12-11)] +#### mruby [2.0.1 (2019-4-4)] Syntax error @@ -181,7 +181,7 @@ end ```ArgumentError``` is raised. The re-defined ```+``` operator does not accept any arguments. -#### mruby [2.0.0 (2018-12-11)] +#### mruby [2.0.1 (2019-4-4)] ``` 'ab' ``` Behavior of the operator wasn't changed. @@ -197,7 +197,7 @@ $ ruby -e 'puts Proc.new {}.binding' # ``` -#### mruby [2.0.0 (2018-12-11)] +#### mruby [2.0.1 (2019-4-4)] ``` $ ./bin/mruby -e 'puts Proc.new {}.binding' @@ -219,7 +219,7 @@ $ ruby -e 'def m(*r,**k) p [r,k] end; m("a"=>1,:b=>2)' [[{"a"=>1}], {:b=>2}] ``` -#### mruby [mruby 2.0.0] +#### mruby [mruby 2.0.1] ``` $ ./bin/mruby -e 'def m(*r,**k) p [r,k] end; m("a"=>1,:b=>2)' diff --git a/include/mruby.h b/include/mruby.h index d891d0f5c..5b0d84cd3 100644 --- a/include/mruby.h +++ b/include/mruby.h @@ -1,7 +1,7 @@ /* ** mruby - An embeddable Ruby implementation ** -** Copyright (c) mruby developers 2010-2018 +** Copyright (c) mruby developers 2010-2019 ** ** Permission is hereby granted, free of charge, to any person obtaining ** a copy of this software and associated documentation files (the diff --git a/include/mruby/version.h b/include/mruby/version.h index 680533ab4..e7763732c 100644 --- a/include/mruby/version.h +++ b/include/mruby/version.h @@ -47,7 +47,7 @@ MRB_BEGIN_DECL /* * Tiny release version number. */ -#define MRUBY_RELEASE_TEENY 0 +#define MRUBY_RELEASE_TEENY 1 /* * The mruby version. @@ -62,17 +62,17 @@ MRB_BEGIN_DECL /* * Release year. */ -#define MRUBY_RELEASE_YEAR 2018 +#define MRUBY_RELEASE_YEAR 2019 /* * Release month. */ -#define MRUBY_RELEASE_MONTH 12 +#define MRUBY_RELEASE_MONTH 4 /* * Release day. */ -#define MRUBY_RELEASE_DAY 11 +#define MRUBY_RELEASE_DAY 4 /* * Release date as a string. -- cgit v1.2.3 From ed41bbb199fb614bb68423d19d26c09c5027319a Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Thu, 4 Apr 2019 22:17:26 +0900 Subject: Use `mrb_proc_arity` instead of `Proc#arity` call in `Method#arity` --- include/mruby/proc.h | 1 + mrbgems/mruby-method/src/method.c | 15 ++------- src/proc.c | 69 +++++++++++++++++++++------------------ 3 files changed, 40 insertions(+), 45 deletions(-) diff --git a/include/mruby/proc.h b/include/mruby/proc.h index 021f9c117..a8b16db1d 100644 --- a/include/mruby/proc.h +++ b/include/mruby/proc.h @@ -86,6 +86,7 @@ struct RProc *mrb_closure_new(mrb_state*, mrb_irep*); MRB_API struct RProc *mrb_proc_new_cfunc(mrb_state*, mrb_func_t); MRB_API struct RProc *mrb_closure_new_cfunc(mrb_state *mrb, mrb_func_t func, int nlocals); void mrb_proc_copy(struct RProc *a, struct RProc *b); +mrb_int mrb_proc_arity(const struct RProc *p); /* implementation of #send method */ mrb_value mrb_f_send(mrb_state *mrb, mrb_value self); diff --git a/mrbgems/mruby-method/src/method.c b/mrbgems/mruby-method/src/method.c index fa8985694..9f1134227 100644 --- a/mrbgems/mruby-method/src/method.c +++ b/mrbgems/mruby-method/src/method.c @@ -212,19 +212,8 @@ static mrb_value method_arity(mrb_state *mrb, mrb_value self) { mrb_value proc = mrb_iv_get(mrb, self, mrb_intern_lit(mrb, "proc")); - struct RProc *rproc; - struct RClass *orig; - mrb_value ret; - - if (mrb_nil_p(proc)) - return mrb_fixnum_value(-1); - - rproc = mrb_proc_ptr(proc); - orig = rproc->c; - rproc->c = mrb->proc_class; - ret = mrb_funcall(mrb, proc, "arity", 0); - rproc->c = orig; - return ret; + mrb_int arity = mrb_nil_p(proc) ? -1 : mrb_proc_arity(mrb_proc_ptr(proc)); + return mrb_fixnum_value(arity); } static mrb_value diff --git a/src/proc.c b/src/proc.c index dab95e465..bf3f01504 100644 --- a/src/proc.c +++ b/src/proc.c @@ -221,38 +221,9 @@ mrb_proc_cfunc_p(struct RProc *p) /* 15.2.17.4.2 */ static mrb_value -mrb_proc_arity(mrb_state *mrb, mrb_value self) +proc_arity(mrb_state *mrb, mrb_value self) { - struct RProc *p = mrb_proc_ptr(self); - struct mrb_irep *irep; - mrb_code *pc; - mrb_aspec aspec; - int ma, op, ra, pa, arity; - - if (MRB_PROC_CFUNC_P(p)) { - /* TODO cfunc aspec not implemented yet */ - return mrb_fixnum_value(-1); - } - - irep = p->body.irep; - if (!irep) { - return mrb_fixnum_value(0); - } - - pc = irep->iseq; - /* arity is depend on OP_ENTER */ - if (*pc != OP_ENTER) { - return mrb_fixnum_value(0); - } - - aspec = PEEK_W(pc+1); - ma = MRB_ASPEC_REQ(aspec); - op = MRB_ASPEC_OPT(aspec); - ra = MRB_ASPEC_REST(aspec); - pa = MRB_ASPEC_POST(aspec); - arity = ra || (MRB_PROC_STRICT_P(p) && op) ? -(ma + pa + 1) : ma + pa; - - return mrb_fixnum_value(arity); + return mrb_fixnum_value(mrb_proc_arity(mrb_proc_ptr(self))); } /* 15.3.1.2.6 */ @@ -287,6 +258,40 @@ proc_lambda(mrb_state *mrb, mrb_value self) return blk; } +mrb_int +mrb_proc_arity(const struct RProc *p) +{ + struct mrb_irep *irep; + mrb_code *pc; + mrb_aspec aspec; + int ma, op, ra, pa, arity; + + if (MRB_PROC_CFUNC_P(p)) { + /* TODO cfunc aspec not implemented yet */ + return -1; + } + + irep = p->body.irep; + if (!irep) { + return 0; + } + + pc = irep->iseq; + /* arity is depend on OP_ENTER */ + if (*pc != OP_ENTER) { + return 0; + } + + aspec = PEEK_W(pc+1); + ma = MRB_ASPEC_REQ(aspec); + op = MRB_ASPEC_OPT(aspec); + ra = MRB_ASPEC_REST(aspec); + pa = MRB_ASPEC_POST(aspec); + arity = ra || (MRB_PROC_STRICT_P(p) && op) ? -(ma + pa + 1) : ma + pa; + + return arity; +} + void mrb_init_proc(mrb_state *mrb) { @@ -303,7 +308,7 @@ mrb_init_proc(mrb_state *mrb) mrb_define_class_method(mrb, mrb->proc_class, "new", mrb_proc_s_new, MRB_ARGS_NONE()|MRB_ARGS_BLOCK()); mrb_define_method(mrb, mrb->proc_class, "initialize_copy", mrb_proc_init_copy, MRB_ARGS_REQ(1)); - mrb_define_method(mrb, mrb->proc_class, "arity", mrb_proc_arity, MRB_ARGS_NONE()); + mrb_define_method(mrb, mrb->proc_class, "arity", proc_arity, MRB_ARGS_NONE()); p = mrb_proc_new(mrb, call_irep); MRB_METHOD_FROM_PROC(m, p); -- cgit v1.2.3 From 623e15936a6c8b8ecaf9dca341be80c9316fd8be Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Fri, 5 Apr 2019 19:03:46 +0900 Subject: `Module#alias_method` should return `self` in ISO standard --- src/class.c | 2 +- test/t/module.rb | 11 +++++++++++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/src/class.c b/src/class.c index 5c5ee9d17..eaef787f7 100644 --- a/src/class.c +++ b/src/class.c @@ -1843,7 +1843,7 @@ mrb_mod_alias(mrb_state *mrb, mrb_value mod) mrb_get_args(mrb, "nn", &new_name, &old_name); mrb_alias_method(mrb, c, new_name, old_name); - return mrb_nil_value(); + return mod; } void diff --git a/test/t/module.rb b/test/t/module.rb index ec36855e8..da0f78fad 100644 --- a/test/t/module.rb +++ b/test/t/module.rb @@ -25,6 +25,17 @@ assert('Module', '15.2.2') do assert_equal Class, Module.class end +assert('Module#alias_method', '15.2.2.4.8') do + cls = Class.new do + def foo + "FOO" + end + end + + assert_same(cls, cls.alias_method(:bar, :foo)) + assert_equal("FOO", cls.new.bar) +end + # TODO not implemented ATM assert('Module.constants', '15.2.2.3.1') do assert('Module#ancestors', '15.2.2.4.9') do -- cgit v1.2.3 From 271a91c64815900338f0f9c152f9f3dabab8246d Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Sat, 6 Apr 2019 16:32:27 +0900 Subject: Remove unused `mrb_proc_cfunc_p()` --- src/proc.c | 6 ------ src/vm.c | 2 +- 2 files changed, 1 insertion(+), 7 deletions(-) diff --git a/src/proc.c b/src/proc.c index bf3f01504..094fff816 100644 --- a/src/proc.c +++ b/src/proc.c @@ -213,12 +213,6 @@ mrb_proc_init_copy(mrb_state *mrb, mrb_value self) return self; } -int -mrb_proc_cfunc_p(struct RProc *p) -{ - return MRB_PROC_CFUNC_P(p); -} - /* 15.2.17.4.2 */ static mrb_value proc_arity(mrb_state *mrb, mrb_value self) diff --git a/src/vm.c b/src/vm.c index a381de21f..60d5dee14 100644 --- a/src/vm.c +++ b/src/vm.c @@ -1004,7 +1004,7 @@ void mrb_hash_check_kdict(mrb_state *mrb, mrb_value self); MRB_API mrb_value mrb_vm_exec(mrb_state *mrb, struct RProc *proc, mrb_code *pc) { - /* mrb_assert(mrb_proc_cfunc_p(proc)) */ + /* mrb_assert(MRB_PROC_CFUNC_P(proc)) */ mrb_code *pc0 = pc; mrb_irep *irep = proc->body.irep; mrb_value *pool = irep->pool; -- cgit v1.2.3 From 5adef8ba44b92ca01692451e21af5c3f47e8853c Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Sat, 6 Apr 2019 17:40:51 +0900 Subject: Move `Array#(append|prepend)` from core to `mruby-ary-ext` They are not included in ISO standard. --- mrbgems/mruby-array-ext/mrblib/array.rb | 3 +++ src/array.c | 2 -- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/mrbgems/mruby-array-ext/mrblib/array.rb b/mrbgems/mruby-array-ext/mrblib/array.rb index 387bd6c90..59b6087d2 100644 --- a/mrbgems/mruby-array-ext/mrblib/array.rb +++ b/mrbgems/mruby-array-ext/mrblib/array.rb @@ -936,4 +936,7 @@ class Array end h end + + alias append push + alias prepend unshift end diff --git a/src/array.c b/src/array.c index 707820ab9..43f4c98b5 100644 --- a/src/array.c +++ b/src/array.c @@ -1286,7 +1286,6 @@ mrb_init_array(mrb_state *mrb) mrb_define_method(mrb, a, "length", mrb_ary_size, MRB_ARGS_NONE()); /* 15.2.12.5.19 */ mrb_define_method(mrb, a, "pop", mrb_ary_pop, MRB_ARGS_NONE()); /* 15.2.12.5.21 */ mrb_define_method(mrb, a, "push", mrb_ary_push_m, MRB_ARGS_ANY()); /* 15.2.12.5.22 */ - mrb_define_method(mrb, a, "append", mrb_ary_push_m, MRB_ARGS_ANY()); mrb_define_method(mrb, a, "replace", mrb_ary_replace_m, MRB_ARGS_REQ(1)); /* 15.2.12.5.23 */ mrb_define_method(mrb, a, "reverse", mrb_ary_reverse, MRB_ARGS_NONE()); /* 15.2.12.5.24 */ mrb_define_method(mrb, a, "reverse!", mrb_ary_reverse_bang, MRB_ARGS_NONE()); /* 15.2.12.5.25 */ @@ -1295,7 +1294,6 @@ mrb_init_array(mrb_state *mrb) mrb_define_method(mrb, a, "size", mrb_ary_size, MRB_ARGS_NONE()); /* 15.2.12.5.28 */ mrb_define_method(mrb, a, "slice", mrb_ary_aget, MRB_ARGS_ANY()); /* 15.2.12.5.29 */ mrb_define_method(mrb, a, "unshift", mrb_ary_unshift_m, MRB_ARGS_ANY()); /* 15.2.12.5.30 */ - mrb_define_method(mrb, a, "prepend", mrb_ary_unshift_m, MRB_ARGS_ANY()); mrb_define_method(mrb, a, "__ary_eq", mrb_ary_eq, MRB_ARGS_REQ(1)); mrb_define_method(mrb, a, "__ary_cmp", mrb_ary_cmp, MRB_ARGS_REQ(1)); -- cgit v1.2.3 From f65b35dc9f5428e7d07b304c01c7836d5be7ec52 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Sun, 7 Apr 2019 21:31:12 +0900 Subject: Fix test for `Array#slice` --- test/t/array.rb | 37 ++++++++++++++++++++++++++++++++----- 1 file changed, 32 insertions(+), 5 deletions(-) diff --git a/test/t/array.rb b/test/t/array.rb index 2b19fe0d4..3df99056f 100644 --- a/test/t/array.rb +++ b/test/t/array.rb @@ -298,11 +298,38 @@ assert('Array#size', '15.2.12.5.28') do end assert('Array#slice', '15.2.12.5.29') do - a = "12345".slice(1, 3) - b = a.slice(0) - - assert_equal("2:", "#{b}:") - assert_equal(2, [1,2,3].[](1)) + a = [*(1..100)] + b = a.dup + + assert_equal(1, a.slice(0)) + assert_equal(100, a.slice(99)) + assert_nil(a.slice(100)) + assert_equal(100, a.slice(-1)) + assert_equal(99, a.slice(-2)) + assert_equal(1, a.slice(-100)) + assert_nil(a.slice(-101)) + assert_equal([1], a.slice(0,1)) + assert_equal([100], a.slice(99,1)) + assert_equal([], a.slice(100,1)) + assert_equal([100], a.slice(99,100)) + assert_equal([100], a.slice(-1,1)) + assert_equal([99], a.slice(-2,1)) + assert_equal([10, 11, 12], a.slice(9, 3)) + assert_equal([10, 11, 12], a.slice(-91, 3)) + assert_nil(a.slice(-101, 2)) + assert_equal([1], a.slice(0..0)) + assert_equal([100], a.slice(99..99)) + assert_equal([], a.slice(100..100)) + assert_equal([100], a.slice(99..200)) + assert_equal([100], a.slice(-1..-1)) + assert_equal([99], a.slice(-2..-2)) + assert_equal([10, 11, 12], a.slice(9..11)) + assert_equal([10, 11, 12], a.slice(-91..-89)) + assert_equal([10, 11, 12], a.slice(-91..-89)) + assert_nil(a.slice(-101..-1)) + assert_nil(a.slice(10, -3)) + assert_equal([], a.slice(10..7)) + assert_equal(b, a) end assert('Array#unshift', '15.2.12.5.30') do -- cgit v1.2.3 From 6cec0c9f62c176e9bd926d12551b384315e98388 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Mon, 8 Apr 2019 19:02:45 +0900 Subject: Fix C99 style inline declaration; fix #4365 --- src/numeric.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/numeric.c b/src/numeric.c index 4128ea3a6..742df7b76 100644 --- a/src/numeric.c +++ b/src/numeric.c @@ -207,12 +207,12 @@ flo_to_s(mrb_state *mrb, mrb_value flt) char fmt[] = "%." MRB_STRINGIZE(FLO_TO_STR_PREC) "g"; mrb_value str = mrb_float_to_str(mrb, flt, fmt); mrb_int len; - char *begp; + char *begp, *p, *endp; insert_dot_zero: begp = RSTRING_PTR(str); len = RSTRING_LEN(str); - for (char *p = begp, *endp = p + len; p < endp; ++p) { + for (p = begp, endp = p + len; p < endp; ++p) { if (*p == '.') { return str; } -- cgit v1.2.3 From ec1688807ef301483321919778b2ccb578822767 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Mon, 8 Apr 2019 19:04:56 +0900 Subject: Avoid using `snprintf` when `MRB_DISABLE_STDIO` is set; fix #4173 --- mrbgems/mruby-compiler/core/parse.y | 90 ++++++++++++++++++++++++++++--------- 1 file changed, 68 insertions(+), 22 deletions(-) diff --git a/mrbgems/mruby-compiler/core/parse.y b/mrbgems/mruby-compiler/core/parse.y index 88d9ea4ee..f6c77859a 100644 --- a/mrbgems/mruby-compiler/core/parse.y +++ b/mrbgems/mruby-compiler/core/parse.y @@ -220,6 +220,25 @@ parser_strdup(parser_state *p, const char *s) #undef strdup #define strdup(s) parser_strdup(p, s) +static void +itoa(short i, char *s) +{ + char *p = s; + char *t = s; + + while (i > 0) { + *p++ = (i % 10)+'0'; + i /= 10; + } + if (p == s) *p++ = '0'; + *p = 0; + p--; /* point the last char */ + while (t < p) { + char c = *t; + *t++ = *p; + *p-- = c; + } +} /* xxx ----------------------------- */ static node* @@ -3172,7 +3191,7 @@ var_ref : variable { char buf[16]; - snprintf(buf, sizeof(buf), "%d", p->lineno); + itoa(p->lineno, buf); $$ = new_int(p, buf, 10); } | keyword__ENCODING__ @@ -3692,11 +3711,12 @@ yyerror(parser_state *p, const char *s) } static void -yyerror_i(parser_state *p, const char *fmt, int i) +yyerror_c(parser_state *p, const char *msg, char c) { char buf[256]; - snprintf(buf, sizeof(buf), fmt, i); + strcpy(buf, msg); + strcat(buf, &c); yyerror(p, buf); } @@ -3735,11 +3755,13 @@ yywarning(parser_state *p, const char *s) } static void -yywarning_s(parser_state *p, const char *fmt, const char *s) +yywarning_s(parser_state *p, const char *msg, const char *s) { char buf[256]; - snprintf(buf, sizeof(buf), fmt, s); + strcpy(buf, msg); + strcat(buf, ": "); + strcat(buf, s); yywarning(p, buf); } @@ -3751,10 +3773,10 @@ backref_error(parser_state *p, node *n) c = intn(n->car); if (c == NODE_NTH_REF) { - yyerror_i(p, "can't set variable $%" MRB_PRId, intn(n->cdr)); + yyerror_c(p, "can't set variable $", (char)intn(n->cdr)+'0'); } else if (c == NODE_BACK_REF) { - yyerror_i(p, "can't set variable $%c", intn(n->cdr)); + yyerror_c(p, "can't set variable $", (char)intn(n->cdr)); } else { mrb_bug(p->mrb, "Internal error in backref_error() : n=>car == %S", mrb_fixnum_value(c)); @@ -4298,7 +4320,15 @@ parse_string(parser_state *p) } if (c < 0) { char buf[256]; - snprintf(buf, sizeof(buf), "can't find heredoc delimiter \"%s\" anywhere before EOF", hinf->term); + const char s1[] = "can't find heredoc delimiter \""; + const char s2[] = "\" anywhere before EOF"; + + if (sizeof(s1)+sizeof(s2)+strlen(hinf->term)+1 >= sizeof(buf)) { + yyerror(p, "can't find heredoc delimiter anywhere before EOF"); + } + strcpy(buf, s1); + strcat(buf, hinf->term); + strcat(buf, s2); yyerror(p, buf); return 0; } @@ -4449,9 +4479,14 @@ parse_string(parser_state *p) pushback(p, re_opt); if (toklen(p)) { char msg[128]; + + strcpy(msg, "unknown regexp option"); tokfix(p); - snprintf(msg, sizeof(msg), "unknown regexp option%s - %s", - toklen(p) > 1 ? "s" : "", tok(p)); + if (toklen(p) > 1) { + strcat(msg, "s"); + } + strcat(msg, " - "); + strcat(msg, tok(p)); yyerror(p, msg); } if (f != 0) { @@ -4879,7 +4914,10 @@ parser_yylex(parser_state *p) } if (c2) { char buf[256]; - snprintf(buf, sizeof(buf), "invalid character syntax; use ?\\%c", c2); + char cc = (char)c2; + + strcpy(buf, "invalid character syntax; use ?\\"); + strcat(buf, &cc); yyerror(p, buf); } } @@ -5252,7 +5290,7 @@ parser_yylex(parser_state *p) pushback(p, c); if (nondigit) { trailing_uc: - yyerror_i(p, "trailing '%c' in number", nondigit); + yyerror_c(p, "trailing non digit in number: ", (char)nondigit); } tokfix(p); if (is_float) { @@ -5267,10 +5305,10 @@ parser_yylex(parser_state *p) errno = 0; d = mrb_float_read(tok(p), &endp); if (d == 0 && endp == tok(p)) { - yywarning_s(p, "corrupted float value %s", tok(p)); + yywarning_s(p, "corrupted float value", tok(p)); } else if (errno == ERANGE) { - yywarning_s(p, "float %s out of range", tok(p)); + yywarning_s(p, "float out of range", tok(p)); errno = 0; } pylval.nd = new_float(p, tok(p)); @@ -5612,7 +5650,7 @@ parser_yylex(parser_state *p) { unsigned long n = strtoul(tok(p), NULL, 10); if (n > INT_MAX) { - yyerror_i(p, "capture group index must be <= %d", INT_MAX); + yyerror(p, "capture group index must be <= " MRB_STRINGIZE(INT_MAX)); return 0; } pylval.nd = new_nth_ref(p, (int)n); @@ -5649,10 +5687,10 @@ parser_yylex(parser_state *p) } else if (ISDIGIT(c)) { if (p->tidx == 1) { - yyerror_i(p, "'@%c' is not allowed as an instance variable name", c); + yyerror_c(p, "wrong instance variable name: @", c); } else { - yyerror_i(p, "'@@%c' is not allowed as a class variable name", c); + yyerror_c(p, "wrong class variable name: @@", c); } return 0; } @@ -5668,7 +5706,14 @@ parser_yylex(parser_state *p) default: if (!identchar(c)) { - yyerror_i(p, "Invalid char '\\x%02X' in expression", c); + char buf[36]; + const char s[] = "Invalid char in expression: 0x"; + + strcpy(buf, s); + buf[sizeof(s)] = (c & 0xff00) >> 8; + buf[sizeof(s)+1] = (c & 0xff); + buf[sizeof(s)+2] = 0; + yyerror(p, buf); goto retry; } @@ -6097,11 +6142,12 @@ mrb_load_exec(mrb_state *mrb, struct mrb_parser_state *p, mrbc_context *c) if (c) c->parser_nerr = p->nerr; if (p->capture_errors) { char buf[256]; - int n; - n = snprintf(buf, sizeof(buf), "line %d: %s\n", - p->error_buffer[0].lineno, p->error_buffer[0].message); - mrb->exc = mrb_obj_ptr(mrb_exc_new(mrb, E_SYNTAX_ERROR, buf, n)); + strcpy(buf, "line "); + itoa(p->error_buffer[0].lineno, buf+5); + strcat(buf, ": "); + strcat(buf, p->error_buffer[0].message); + mrb->exc = mrb_obj_ptr(mrb_exc_new(mrb, E_SYNTAX_ERROR, buf, strlen(buf))); mrb_parser_free(p); return mrb_undef_value(); } -- cgit v1.2.3 From 292bffb32e7434b4725f39924adf0e9f8af5d1cf Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Mon, 8 Apr 2019 20:27:28 +0900 Subject: Avoid infinite loop when no `Regexp` class is available; fix #4363 --- mrblib/string.rb | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/mrblib/string.rb b/mrblib/string.rb index 64e85c5b6..62c925885 100644 --- a/mrblib/string.rb +++ b/mrblib/string.rb @@ -242,25 +242,27 @@ class String end end + def _regexp(re, mid) + if String === re + if Object.const_defined?(:Regexp) + return Regexp.new(re) + else + raise NotImplementedError, "String##{mid} needs Regexp class" + end + end + re + end + ## # ISO 15.2.10.5.3 def =~(re) - re =~ self + _regexp(re, :=~) =~ self end ## # ISO 15.2.10.5.27 def match(re, &block) - if String === re - if Object.const_defined?(:Regexp) - r = Regexp.new(re) - r.match(self, &block) - else - raise NotImplementedError, "String#match needs Regexp class" - end - else - re.match(self, &block) - end + _regexp(re, :match).match(self, &block) end end -- cgit v1.2.3 From f89fe04d546a0c18ae45a3b2045343143feab19c Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Mon, 8 Apr 2019 22:34:49 +0900 Subject: Remove unneeded function prototypes --- include/mruby.h | 3 --- 1 file changed, 3 deletions(-) diff --git a/include/mruby.h b/include/mruby.h index 5b0d84cd3..df26cdbc2 100644 --- a/include/mruby.h +++ b/include/mruby.h @@ -1083,9 +1083,6 @@ MRB_API mrb_value mrb_Float(mrb_state *mrb, mrb_value val); MRB_API mrb_value mrb_inspect(mrb_state *mrb, mrb_value obj); MRB_API mrb_bool mrb_eql(mrb_state *mrb, mrb_value obj1, mrb_value obj2); -static inline int mrb_gc_arena_save(mrb_state*); -static inline void mrb_gc_arena_restore(mrb_state*,int); - static inline int mrb_gc_arena_save(mrb_state *mrb) { -- cgit v1.2.3 From e3beef065c2de80a843f329599b424676d83086c Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Tue, 9 Apr 2019 18:23:11 +0900 Subject: Extract frozen checking to function --- include/mruby.h | 6 ++++++ mrbgems/mruby-struct/src/struct.c | 5 +---- src/array.c | 4 +--- src/class.c | 7 +------ src/error.c | 7 +++++++ src/hash.c | 5 +---- src/string.c | 12 ++---------- src/variable.c | 4 +--- 8 files changed, 20 insertions(+), 30 deletions(-) diff --git a/include/mruby.h b/include/mruby.h index 5b0d84cd3..939601b4d 100644 --- a/include/mruby.h +++ b/include/mruby.h @@ -1143,6 +1143,7 @@ MRB_API mrb_noreturn void mrb_exc_raise(mrb_state *mrb, mrb_value exc); MRB_API mrb_noreturn void mrb_raise(mrb_state *mrb, struct RClass *c, const char *msg); MRB_API mrb_noreturn void mrb_raisef(mrb_state *mrb, struct RClass *c, const char *fmt, ...); MRB_API mrb_noreturn void mrb_name_error(mrb_state *mrb, mrb_sym id, const char *fmt, ...); +MRB_API mrb_noreturn void mrb_frozen_error(mrb_state *mrb, void *frozen_obj); MRB_API void mrb_warn(mrb_state *mrb, const char *fmt, ...); MRB_API mrb_noreturn void mrb_bug(mrb_state *mrb, const char *fmt, ...); MRB_API void mrb_print_backtrace(mrb_state *mrb); @@ -1196,6 +1197,11 @@ MRB_API mrb_value mrb_to_int(mrb_state *mrb, mrb_value val); MRB_API mrb_value mrb_to_str(mrb_state *mrb, mrb_value val); MRB_API void mrb_check_type(mrb_state *mrb, mrb_value x, enum mrb_vtype t); +static inline void mrb_check_frozen(mrb_state *mrb, void *o) +{ + if (MRB_FROZEN_P((struct RBasic*)o)) mrb_frozen_error(mrb, o); +} + typedef enum call_type { CALL_PUBLIC, CALL_FCALL, diff --git a/mrbgems/mruby-struct/src/struct.c b/mrbgems/mruby-struct/src/struct.c index c0ce71219..1df135a9f 100644 --- a/mrbgems/mruby-struct/src/struct.c +++ b/mrbgems/mruby-struct/src/struct.c @@ -87,10 +87,7 @@ mrb_struct_s_members_m(mrb_state *mrb, mrb_value klass) static void mrb_struct_modify(mrb_state *mrb, mrb_value strct) { - if (MRB_FROZEN_P(mrb_basic_ptr(strct))) { - mrb_raise(mrb, E_FROZEN_ERROR, "can't modify frozen struct"); - } - + mrb_check_frozen(mrb, mrb_basic_ptr(strct)); mrb_write_barrier(mrb, mrb_basic_ptr(strct)); } diff --git a/src/array.c b/src/array.c index 43f4c98b5..d4302cb22 100644 --- a/src/array.c +++ b/src/array.c @@ -120,9 +120,7 @@ ary_fill_with_nil(mrb_value *ptr, mrb_int size) static void ary_modify_check(mrb_state *mrb, struct RArray *a) { - if (MRB_FROZEN_P(a)) { - mrb_raise(mrb, E_FROZEN_ERROR, "can't modify frozen array"); - } + mrb_check_frozen(mrb, a); } static void diff --git a/src/class.c b/src/class.c index eaef787f7..fd56fa399 100644 --- a/src/class.c +++ b/src/class.c @@ -441,12 +441,7 @@ mrb_define_method_raw(mrb_state *mrb, struct RClass *c, mrb_sym mid, mrb_method_ MRB_CLASS_ORIGIN(c); h = c->mt; - if (MRB_FROZEN_P(c)) { - if (c->tt == MRB_TT_MODULE) - mrb_raise(mrb, E_FROZEN_ERROR, "can't modify frozen module"); - else - mrb_raise(mrb, E_FROZEN_ERROR, "can't modify frozen class"); - } + mrb_check_frozen(mrb, c); if (!h) h = c->mt = kh_init(mt, mrb); k = kh_put(mt, mrb, h, mid); kh_value(h, k) = m; diff --git a/src/error.c b/src/error.c index e69812dda..4c1b67c99 100644 --- a/src/error.c +++ b/src/error.c @@ -484,6 +484,13 @@ mrb_no_method_error(mrb_state *mrb, mrb_sym id, mrb_value args, char const* fmt, mrb_exc_raise(mrb, exc); } +MRB_API mrb_noreturn void +mrb_frozen_error(mrb_state *mrb, void *frozen_obj) +{ + mrb_raisef(mrb, E_FROZEN_ERROR, "can't modify frozen %S", + mrb_obj_value(mrb_class(mrb, mrb_obj_value(frozen_obj)))); +} + void mrb_init_exception(mrb_state *mrb) { diff --git a/src/hash.c b/src/hash.c index fd963c3de..c4820513b 100644 --- a/src/hash.c +++ b/src/hash.c @@ -746,10 +746,7 @@ mrb_hash_set(mrb_state *mrb, mrb_value hash, mrb_value key, mrb_value val) static void mrb_hash_modify(mrb_state *mrb, mrb_value hash) { - if (MRB_FROZEN_P(mrb_hash_ptr(hash))) { - mrb_raise(mrb, E_FROZEN_ERROR, "can't modify frozen hash"); - } - + mrb_check_frozen(mrb, mrb_hash_ptr(hash)); if (!RHASH_TBL(hash)) { RHASH_TBL(hash) = ht_new(mrb); } diff --git a/src/string.c b/src/string.c index 63c592d59..f7a805a94 100644 --- a/src/string.c +++ b/src/string.c @@ -493,20 +493,12 @@ str_index_str(mrb_state *mrb, mrb_value str, mrb_value str2, mrb_int offset) return mrb_str_index(mrb, str, ptr, len, offset); } -static void -check_frozen(mrb_state *mrb, struct RString *s) -{ - if (MRB_FROZEN_P(s)) { - mrb_raise(mrb, E_FROZEN_ERROR, "can't modify frozen string"); - } -} - static mrb_value str_replace(mrb_state *mrb, struct RString *s1, struct RString *s2) { mrb_int len; - check_frozen(mrb, s1); + mrb_check_frozen(mrb, s1); if (s1 == s2) return mrb_obj_value(s1); s1->flags &= ~MRB_STR_NO_UTF; s1->flags |= s2->flags&MRB_STR_NO_UTF; @@ -646,7 +638,7 @@ mrb_locale_from_utf8(const char *utf8, int len) MRB_API void mrb_str_modify(mrb_state *mrb, struct RString *s) { - check_frozen(mrb, s); + mrb_check_frozen(mrb, s); s->flags &= ~MRB_STR_NO_UTF; if (RSTR_SHARED_P(s)) { mrb_shared_string *shared = s->as.heap.aux.shared; diff --git a/src/variable.c b/src/variable.c index 9edfb32bd..cf89a4a02 100644 --- a/src/variable.c +++ b/src/variable.c @@ -346,9 +346,7 @@ mrb_obj_iv_set(mrb_state *mrb, struct RObject *obj, mrb_sym sym, mrb_value v) { iv_tbl *t; - if (MRB_FROZEN_P(obj)) { - mrb_raisef(mrb, E_FROZEN_ERROR, "can't modify frozen %S", mrb_obj_value(obj)); - } + mrb_check_frozen(mrb, obj); assign_class_name(mrb, obj, sym, v); if (!obj->iv) { obj->iv = iv_new(mrb); -- cgit v1.2.3 From 16f86f8ede2f0d33fdd642d734c796b9435a57bf Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Wed, 10 Apr 2019 05:42:36 +0900 Subject: Use the old style declaration; ref #4365 --- src/variable.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/variable.c b/src/variable.c index 9edfb32bd..02e4f38a1 100644 --- a/src/variable.c +++ b/src/variable.c @@ -1116,7 +1116,9 @@ mrb_class_find_path(mrb_state *mrb, struct RClass *c) mrb_bool mrb_ident_p(const char *s, mrb_int len) { - for (mrb_int i = 0; i < len; i++) { + mrb_int i; + + for (i = 0; i < len; i++) { if (!identchar(s[i])) return FALSE; } return TRUE; -- cgit v1.2.3 From d529501cbfd2331c530ca37efa7295d9e627af97 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Wed, 10 Apr 2019 05:55:40 +0900 Subject: Rename `itoa` to `dump_int` to avoid name crash; ref #4173 --- mrbgems/mruby-compiler/core/parse.y | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/mrbgems/mruby-compiler/core/parse.y b/mrbgems/mruby-compiler/core/parse.y index f6c77859a..cb62ec3f2 100644 --- a/mrbgems/mruby-compiler/core/parse.y +++ b/mrbgems/mruby-compiler/core/parse.y @@ -221,7 +221,7 @@ parser_strdup(parser_state *p, const char *s) #define strdup(s) parser_strdup(p, s) static void -itoa(short i, char *s) +dump_int(short i, char *s) { char *p = s; char *t = s; @@ -239,6 +239,7 @@ itoa(short i, char *s) *p-- = c; } } + /* xxx ----------------------------- */ static node* @@ -3191,7 +3192,7 @@ var_ref : variable { char buf[16]; - itoa(p->lineno, buf); + dump_int(p->lineno, buf); $$ = new_int(p, buf, 10); } | keyword__ENCODING__ @@ -6144,7 +6145,7 @@ mrb_load_exec(mrb_state *mrb, struct mrb_parser_state *p, mrbc_context *c) char buf[256]; strcpy(buf, "line "); - itoa(p->error_buffer[0].lineno, buf+5); + dump_int(p->error_buffer[0].lineno, buf+5); strcat(buf, ": "); strcat(buf, p->error_buffer[0].message); mrb->exc = mrb_obj_ptr(mrb_exc_new(mrb, E_SYNTAX_ERROR, buf, strlen(buf))); -- cgit v1.2.3 From b351bdb8d53ef2ff2d91c51e2179103e3c76e9a4 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Wed, 10 Apr 2019 06:00:38 +0900 Subject: Fixed old style declaration; ref #4365 --- mrbgems/mruby-test/driver.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/mrbgems/mruby-test/driver.c b/mrbgems/mruby-test/driver.c index fd180b1bb..fcbe15a56 100644 --- a/mrbgems/mruby-test/driver.c +++ b/mrbgems/mruby-test/driver.c @@ -51,9 +51,10 @@ t_print(mrb_state *mrb, mrb_value self) { mrb_value *argv; mrb_int argc; + mrb_int i; mrb_get_args(mrb, "*!", &argv, &argc); - for (mrb_int i = 0; i < argc; ++i) { + for (i = 0; i < argc; ++i) { mrb_value s = mrb_obj_as_string(mrb, argv[i]); fwrite(RSTRING_PTR(s), RSTRING_LEN(s), 1, stdout); } -- cgit v1.2.3 From 88ac7549c08411b8d96a7ed0ed8ab2299228f28f Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Wed, 10 Apr 2019 17:14:08 +0900 Subject: Remove `MRB_API` from `mrb_instance_new`. --- include/mruby.h | 2 -- include/mruby/class.h | 1 + src/class.c | 2 +- 3 files changed, 2 insertions(+), 3 deletions(-) diff --git a/include/mruby.h b/include/mruby.h index e567e1da4..7026c1f5e 100644 --- a/include/mruby.h +++ b/include/mruby.h @@ -570,8 +570,6 @@ MRB_INLINE mrb_value mrb_class_new_instance(mrb_state *mrb, mrb_int argc, const return mrb_obj_new(mrb,c,argc,argv); } -MRB_API mrb_value mrb_instance_new(mrb_state *mrb, mrb_value cv); - /** * Creates a new instance of Class, Class. * diff --git a/include/mruby/class.h b/include/mruby/class.h index b667e2051..5ac6e5c40 100644 --- a/include/mruby/class.h +++ b/include/mruby/class.h @@ -85,6 +85,7 @@ MRB_API mrb_method_t mrb_method_search_vm(mrb_state*, struct RClass**, mrb_sym); MRB_API mrb_method_t mrb_method_search(mrb_state*, struct RClass*, mrb_sym); MRB_API struct RClass* mrb_class_real(struct RClass* cl); +mrb_value mrb_instance_new(mrb_state *mrb, mrb_value cv); void mrb_class_name_class(mrb_state*, struct RClass*, struct RClass*, mrb_sym); mrb_value mrb_class_find_path(mrb_state*, struct RClass*); diff --git a/src/class.c b/src/class.c index fd56fa399..6f6b3feda 100644 --- a/src/class.c +++ b/src/class.c @@ -1498,7 +1498,7 @@ mrb_instance_alloc(mrb_state *mrb, mrb_value cv) * */ -MRB_API mrb_value +mrb_value mrb_instance_new(mrb_state *mrb, mrb_value cv) { mrb_value obj, blk; -- cgit v1.2.3 From 4776ac50ed39652e56a084475a5d79c1bbccc6c0 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Wed, 10 Apr 2019 19:07:22 +0900 Subject: Remove too aggressive `initialize` call in `mrb_instance_new`. --- src/class.c | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/src/class.c b/src/class.c index 6f6b3feda..d6efdbdc4 100644 --- a/src/class.c +++ b/src/class.c @@ -1505,22 +1505,13 @@ mrb_instance_new(mrb_state *mrb, mrb_value cv) mrb_value *argv; mrb_int argc; mrb_sym init; - mrb_method_t m; mrb_get_args(mrb, "*&", &argv, &argc, &blk); obj = mrb_instance_alloc(mrb, cv); init = mrb_intern_lit(mrb, "initialize"); - m = mrb_method_search(mrb, mrb_class(mrb, obj), init); - if (MRB_METHOD_CFUNC_P(m)) { - mrb_func_t f = MRB_METHOD_CFUNC(m); - if (f != mrb_bob_init) { - f(mrb, obj); - } - } - else { + if (!mrb_func_basic_p(mrb, obj, init, mrb_bob_init)) { mrb_funcall_with_block(mrb, obj, init, argc, argv, blk); } - return obj; } -- cgit v1.2.3 From 7b0ebed033777cd8bdb8e3668e5c49cfe1b69c5d Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Wed, 10 Apr 2019 19:17:00 +0900 Subject: Use `mrb_immediate_p()` in `mrb_obj_freeze()` and `mrb_obj_frozen()` --- src/etc.c | 2 ++ src/kernel.c | 44 ++++++-------------------------------------- test/t/kernel.rb | 17 +++++++++++++++++ 3 files changed, 25 insertions(+), 38 deletions(-) diff --git a/src/etc.c b/src/etc.c index 12d948a55..6c5fb7480 100644 --- a/src/etc.c +++ b/src/etc.c @@ -167,6 +167,7 @@ mrb_word_boxing_float_value(mrb_state *mrb, mrb_float f) v.value.p = mrb_obj_alloc(mrb, MRB_TT_FLOAT, mrb->float_class); v.value.fp->f = f; + MRB_SET_FROZEN_FLAG(v.value.bp); return v; } @@ -177,6 +178,7 @@ mrb_word_boxing_float_pool(mrb_state *mrb, mrb_float f) nf->tt = MRB_TT_FLOAT; nf->c = mrb->float_class; nf->f = f; + MRB_SET_FROZEN_FLAG(nf); return mrb_obj_value(nf); } #endif /* MRB_WITHOUT_FLOAT */ diff --git a/src/kernel.c b/src/kernel.c index 7890e3dac..d9a1d36ce 100644 --- a/src/kernel.c +++ b/src/kernel.c @@ -434,24 +434,11 @@ mrb_obj_extend_m(mrb_state *mrb, mrb_value self) static mrb_value mrb_obj_freeze(mrb_state *mrb, mrb_value self) { - struct RBasic *b; - - switch (mrb_type(self)) { - case MRB_TT_FALSE: - case MRB_TT_TRUE: - case MRB_TT_FIXNUM: - case MRB_TT_SYMBOL: -#ifndef MRB_WITHOUT_FLOAT - case MRB_TT_FLOAT: -#endif - return self; - default: - break; - } - - b = mrb_basic_ptr(self); - if (!MRB_FROZEN_P(b)) { - MRB_SET_FROZEN_FLAG(b); + if (!mrb_immediate_p(self)) { + struct RBasic *b = mrb_basic_ptr(self); + if (!MRB_FROZEN_P(b)) { + MRB_SET_FROZEN_FLAG(b); + } } return self; } @@ -459,26 +446,7 @@ mrb_obj_freeze(mrb_state *mrb, mrb_value self) static mrb_value mrb_obj_frozen(mrb_state *mrb, mrb_value self) { - struct RBasic *b; - - switch (mrb_type(self)) { - case MRB_TT_FALSE: - case MRB_TT_TRUE: - case MRB_TT_FIXNUM: - case MRB_TT_SYMBOL: -#ifndef MRB_WITHOUT_FLOAT - case MRB_TT_FLOAT: -#endif - return mrb_true_value(); - default: - break; - } - - b = mrb_basic_ptr(self); - if (!MRB_FROZEN_P(b)) { - return mrb_false_value(); - } - return mrb_true_value(); + return mrb_bool_value(mrb_immediate_p(self) || MRB_FROZEN_P(mrb_basic_ptr(self))); } /* 15.3.1.3.15 */ diff --git a/test/t/kernel.rb b/test/t/kernel.rb index d99358c0c..bf7dbe94c 100644 --- a/test/t/kernel.rb +++ b/test/t/kernel.rb @@ -247,6 +247,23 @@ assert('Kernel#freeze') do assert_equal obj, obj.freeze assert_equal 0, 0.freeze assert_equal :a, :a.freeze + assert_equal true, true.freeze + assert_equal false, false.freeze + assert_equal nil, nil.freeze + skip unless Object.const_defined?(:Float) + assert_equal 0.0, 0.0.freeze +end + +assert('Kernel#frozen?') do + assert_false "".frozen? + assert_true "".freeze.frozen? + assert_true 0.frozen? + assert_true :a.frozen? + assert_true true.frozen? + assert_true false.frozen? + assert_true nil.frozen? + skip unless Object.const_defined?(:Float) + assert_true 0.0.frozen? end assert('Kernel#global_variables', '15.3.1.3.14') do -- cgit v1.2.3 From 0c9c3f08ee2c62f6f1b4ce9968a4d12e2ea60276 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Thu, 11 Apr 2019 21:42:18 +0900 Subject: Remove incorrect flags updating in `mrb_regexp_p()` --- src/etc.c | 1 - 1 file changed, 1 deletion(-) diff --git a/src/etc.c b/src/etc.c index 6c5fb7480..d15b398dd 100644 --- a/src/etc.c +++ b/src/etc.c @@ -205,7 +205,6 @@ mrb_regexp_p(mrb_state *mrb, mrb_value v) return mrb_obj_is_kind_of(mrb, v, mrb_class_get(mrb, REGEXP_CLASS)); } else { - mrb->flags |= MRB_STATE_REGEXP; mrb->flags |= MRB_STATE_NO_REGEXP; } return FALSE; -- cgit v1.2.3 From 57e617620a4fa8b144dd87e94dc22ae2acd87679 Mon Sep 17 00:00:00 2001 From: Clayton Smith Date: Thu, 11 Apr 2019 20:07:43 -0400 Subject: Fix buffer overflows in parser. --- mrbgems/mruby-compiler/core/parse.y | 27 +++++++++++++++------------ 1 file changed, 15 insertions(+), 12 deletions(-) diff --git a/mrbgems/mruby-compiler/core/parse.y b/mrbgems/mruby-compiler/core/parse.y index cb62ec3f2..ca4c90770 100644 --- a/mrbgems/mruby-compiler/core/parse.y +++ b/mrbgems/mruby-compiler/core/parse.y @@ -3716,8 +3716,9 @@ yyerror_c(parser_state *p, const char *msg, char c) { char buf[256]; - strcpy(buf, msg); - strcat(buf, &c); + strncpy(buf, msg, sizeof(buf) - 2); + buf[sizeof(buf) - 2] = '\0'; + strncat(buf, &c, 1); yyerror(p, buf); } @@ -3760,9 +3761,10 @@ yywarning_s(parser_state *p, const char *msg, const char *s) { char buf[256]; - strcpy(buf, msg); - strcat(buf, ": "); - strcat(buf, s); + strncpy(buf, msg, sizeof(buf) - 1); + buf[sizeof(buf) - 1] = '\0'; + strncat(buf, ": ", sizeof(buf) - strlen(buf) - 1); + strncat(buf, s, sizeof(buf) - strlen(buf) - 1); yywarning(p, buf); } @@ -4326,11 +4328,12 @@ parse_string(parser_state *p) if (sizeof(s1)+sizeof(s2)+strlen(hinf->term)+1 >= sizeof(buf)) { yyerror(p, "can't find heredoc delimiter anywhere before EOF"); + } else { + strcpy(buf, s1); + strcat(buf, hinf->term); + strcat(buf, s2); + yyerror(p, buf); } - strcpy(buf, s1); - strcat(buf, hinf->term); - strcat(buf, s2); - yyerror(p, buf); return 0; } pylval.nd = new_str(p, tok(p), toklen(p)); @@ -4487,7 +4490,7 @@ parse_string(parser_state *p) strcat(msg, "s"); } strcat(msg, " - "); - strcat(msg, tok(p)); + strncat(msg, tok(p), sizeof(msg) - strlen(msg) - 1); yyerror(p, msg); } if (f != 0) { @@ -4918,7 +4921,7 @@ parser_yylex(parser_state *p) char cc = (char)c2; strcpy(buf, "invalid character syntax; use ?\\"); - strcat(buf, &cc); + strncat(buf, &cc, 1); yyerror(p, buf); } } @@ -6147,7 +6150,7 @@ mrb_load_exec(mrb_state *mrb, struct mrb_parser_state *p, mrbc_context *c) strcpy(buf, "line "); dump_int(p->error_buffer[0].lineno, buf+5); strcat(buf, ": "); - strcat(buf, p->error_buffer[0].message); + strncat(buf, p->error_buffer[0].message, sizeof(buf) - strlen(buf) - 1); mrb->exc = mrb_obj_ptr(mrb_exc_new(mrb, E_SYNTAX_ERROR, buf, strlen(buf))); mrb_parser_free(p); return mrb_undef_value(); -- cgit v1.2.3 From 6626fbc5006d662f8fc69a51660ae7c1e998a1f0 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Fri, 12 Apr 2019 22:27:07 +0900 Subject: Refine `assert_float` Avoid arithmetic operations when `exp` and/or `act` are infinity or NaN. --- test/assert.rb | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/test/assert.rb b/test/assert.rb index c57b04c12..e0fac4d90 100644 --- a/test/assert.rb +++ b/test/assert.rb @@ -149,11 +149,11 @@ end # Fails unless +exp+ is equal to +act+ in terms of a Float def assert_float(exp, act, msg = nil) e, a = exp.to_f, act.to_f - if (e.infinite? || a.infinite?) && e != a || + if e.finite? && a.finite? && (n = (e - a).abs) > Mrbtest::FLOAT_TOLERANCE + flunk(msg, " Expected |#{exp} - #{act}| (#{n}) to be <= #{Mrbtest::FLOAT_TOLERANCE}.") + elsif (e.infinite? || a.infinite?) && e != a || e.nan? && !a.nan? || !e.nan? && a.nan? flunk(msg, " Expected #{act} to be #{exp}.") - elsif (n = (e - a).abs) > Mrbtest::FLOAT_TOLERANCE - flunk(msg, " Expected |#{exp} - #{act}| (#{n}) to be <= #{Mrbtest::FLOAT_TOLERANCE}.") else pass end -- cgit v1.2.3 From 00545fc51d33a9c71d610cc8da5e779cf29487af Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Fri, 12 Apr 2019 22:52:26 +0900 Subject: The number of local variables should be less than 1024; fix #4370 The `env` stores stack length in a 10 bit field. See `MRB_ENV_STACK_LEN()` macro. --- mrbgems/mruby-compiler/core/codegen.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/mrbgems/mruby-compiler/core/codegen.c b/mrbgems/mruby-compiler/core/codegen.c index 927cc3a0f..4bb81f415 100644 --- a/mrbgems/mruby-compiler/core/codegen.c +++ b/mrbgems/mruby-compiler/core/codegen.c @@ -3020,6 +3020,9 @@ scope_finish(codegen_scope *s) mrb_state *mrb = s->mrb; mrb_irep *irep = s->irep; + if (s->nlocals >= 0x3ff) { + codegen_error(s, "too many local variables"); + } irep->flags = 0; if (s->iseq) { irep->iseq = (mrb_code *)codegen_realloc(s, s->iseq, sizeof(mrb_code)*s->pc); -- cgit v1.2.3 From befdf59e610b43e7043b83074a2cc34070ae4e5f Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Fri, 12 Apr 2019 22:54:25 +0900 Subject: Deallocate `s->lines` in `codegen_error`; ref #4370 --- mrbgems/mruby-compiler/core/codegen.c | 1 + 1 file changed, 1 insertion(+) diff --git a/mrbgems/mruby-compiler/core/codegen.c b/mrbgems/mruby-compiler/core/codegen.c index 4bb81f415..b6d35f363 100644 --- a/mrbgems/mruby-compiler/core/codegen.c +++ b/mrbgems/mruby-compiler/core/codegen.c @@ -102,6 +102,7 @@ codegen_error(codegen_scope *s, const char *message) while (s->prev) { codegen_scope *tmp = s->prev; mrb_free(s->mrb, s->iseq); + mrb_free(s->mrb, s->lines); mrb_pool_close(s->mpool); s = tmp; } -- cgit v1.2.3 From 79fd986bcb2c6bc056a08669664c0024d77725f9 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Fri, 12 Apr 2019 23:03:38 +0900 Subject: Small refactoring in `mrb_funcall_with_block`. --- src/vm.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/src/vm.c b/src/vm.c index 60d5dee14..6bd9d53f9 100644 --- a/src/vm.c +++ b/src/vm.c @@ -486,6 +486,7 @@ mrb_funcall_with_block(mrb_state *mrb, mrb_value self, mrb_sym mid, mrb_int argc ci->argc = (int)argc; ci->target_class = c; mrb->c->stack = mrb->c->stack + n; + if (argc < 0) argc = 1; if (mrb->c->stbase <= argv && argv < mrb->c->stend) { voff = argv - mrb->c->stbase; } @@ -500,11 +501,10 @@ mrb_funcall_with_block(mrb_state *mrb, mrb_value self, mrb_sym mid, mrb_int argc ci->argc = -1; argc = 1; } - else { + else if (MRB_METHOD_PROC_P(m)) { struct RProc *p = MRB_METHOD_PROC(m); ci->proc = p; - if (argc < 0) argc = 1; mrb_stack_extend(mrb, p->body.irep->nregs + argc); } if (voff >= 0) { @@ -520,9 +520,6 @@ mrb_funcall_with_block(mrb_state *mrb, mrb_value self, mrb_sym mid, mrb_int argc int ai = mrb_gc_arena_save(mrb); ci->acc = CI_ACC_DIRECT; - if (MRB_METHOD_PROC_P(m)) { - ci->proc = MRB_METHOD_PROC(m); - } val = MRB_METHOD_CFUNC(m)(mrb, self); mrb->c->stack = mrb->c->ci->stackent; cipop(mrb); -- cgit v1.2.3 From f639da0f1c32c20255c32821191697d35350c1ad Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Sat, 13 Apr 2019 18:16:28 +0900 Subject: Fix broken NaN with `MRB_NAN_BOXING` Example: $ bin/mruby -e '(Float::INFINITY - Float::INFINITY).nan?' zsh: segmentation fault Cause: `SET_FLOAT_VALUE` is not used. It is needed for normalizing NaN. Treatment: In my environment, this issue could be reproduced only when `infinity - infinity`, however `SET_FLOAT_VALUE` should be used in all arithmetic operations (regardless of boxing setting), I think. So I fixed all similar codes by extracting to macro. --- src/vm.c | 96 +++++++++++----------------------------------------------------- 1 file changed, 16 insertions(+), 80 deletions(-) diff --git a/src/vm.c b/src/vm.c index 6bd9d53f9..712d39b66 100644 --- a/src/vm.c +++ b/src/vm.c @@ -2214,9 +2214,13 @@ RETRY_TRY_BLOCK: } #define TYPES2(a,b) ((((uint16_t)(a))<<8)|(((uint16_t)(b))&0xff)) -#define OP_MATH_BODY(op,v1,v2) do {\ - v1(regs[a]) = v1(regs[a]) op v2(regs[a+1]);\ -} while(0) +#define OP_MATH_FLOAT_BODY(op,t1,t2) do { \ + RETURN_TYPE_OF_##t1 x = t1(regs[a]); \ + RETURN_TYPE_OF_##t2 y = t2(regs[a+1]); \ + SET_FLOAT_VALUE(mrb, regs[a], x op y); \ +} while (0) +#define RETURN_TYPE_OF_mrb_fixnum mrb_int +#define RETURN_TYPE_OF_mrb_float mrb_float CASE(OP_ADD, B) { /* need to check if op is overridden */ @@ -2239,33 +2243,13 @@ RETRY_TRY_BLOCK: break; #ifndef MRB_WITHOUT_FLOAT case TYPES2(MRB_TT_FIXNUM,MRB_TT_FLOAT): - { - mrb_int x = mrb_fixnum(regs[a]); - mrb_float y = mrb_float(regs[a+1]); - SET_FLOAT_VALUE(mrb, regs[a], (mrb_float)x + y); - } + OP_MATH_FLOAT_BODY(+,mrb_fixnum,mrb_float); break; case TYPES2(MRB_TT_FLOAT,MRB_TT_FIXNUM): -#ifdef MRB_WORD_BOXING - { - mrb_float x = mrb_float(regs[a]); - mrb_int y = mrb_fixnum(regs[a+1]); - SET_FLOAT_VALUE(mrb, regs[a], x + y); - } -#else - OP_MATH_BODY(+,mrb_float,mrb_fixnum); -#endif + OP_MATH_FLOAT_BODY(+,mrb_float,mrb_fixnum); break; case TYPES2(MRB_TT_FLOAT,MRB_TT_FLOAT): -#ifdef MRB_WORD_BOXING - { - mrb_float x = mrb_float(regs[a]); - mrb_float y = mrb_float(regs[a+1]); - SET_FLOAT_VALUE(mrb, regs[a], x + y); - } -#else - OP_MATH_BODY(+,mrb_float,mrb_float); -#endif + OP_MATH_FLOAT_BODY(+,mrb_float,mrb_float); break; #endif case TYPES2(MRB_TT_STRING,MRB_TT_STRING): @@ -2300,33 +2284,13 @@ RETRY_TRY_BLOCK: break; #ifndef MRB_WITHOUT_FLOAT case TYPES2(MRB_TT_FIXNUM,MRB_TT_FLOAT): - { - mrb_int x = mrb_fixnum(regs[a]); - mrb_float y = mrb_float(regs[a+1]); - SET_FLOAT_VALUE(mrb, regs[a], (mrb_float)x - y); - } + OP_MATH_FLOAT_BODY(-,mrb_fixnum,mrb_float); break; case TYPES2(MRB_TT_FLOAT,MRB_TT_FIXNUM): -#ifdef MRB_WORD_BOXING - { - mrb_float x = mrb_float(regs[a]); - mrb_int y = mrb_fixnum(regs[a+1]); - SET_FLOAT_VALUE(mrb, regs[a], x - y); - } -#else - OP_MATH_BODY(-,mrb_float,mrb_fixnum); -#endif + OP_MATH_FLOAT_BODY(-,mrb_float,mrb_fixnum); break; case TYPES2(MRB_TT_FLOAT,MRB_TT_FLOAT): -#ifdef MRB_WORD_BOXING - { - mrb_float x = mrb_float(regs[a]); - mrb_float y = mrb_float(regs[a+1]); - SET_FLOAT_VALUE(mrb, regs[a], x - y); - } -#else - OP_MATH_BODY(-,mrb_float,mrb_float); -#endif + OP_MATH_FLOAT_BODY(-,mrb_float,mrb_float); break; #endif default: @@ -2357,33 +2321,13 @@ RETRY_TRY_BLOCK: break; #ifndef MRB_WITHOUT_FLOAT case TYPES2(MRB_TT_FIXNUM,MRB_TT_FLOAT): - { - mrb_int x = mrb_fixnum(regs[a]); - mrb_float y = mrb_float(regs[a+1]); - SET_FLOAT_VALUE(mrb, regs[a], (mrb_float)x * y); - } + OP_MATH_FLOAT_BODY(*,mrb_fixnum,mrb_float); break; case TYPES2(MRB_TT_FLOAT,MRB_TT_FIXNUM): -#ifdef MRB_WORD_BOXING - { - mrb_float x = mrb_float(regs[a]); - mrb_int y = mrb_fixnum(regs[a+1]); - SET_FLOAT_VALUE(mrb, regs[a], x * y); - } -#else - OP_MATH_BODY(*,mrb_float,mrb_fixnum); -#endif + OP_MATH_FLOAT_BODY(*,mrb_float,mrb_fixnum); break; case TYPES2(MRB_TT_FLOAT,MRB_TT_FLOAT): -#ifdef MRB_WORD_BOXING - { - mrb_float x = mrb_float(regs[a]); - mrb_float y = mrb_float(regs[a+1]); - SET_FLOAT_VALUE(mrb, regs[a], x * y); - } -#else - OP_MATH_BODY(*,mrb_float,mrb_float); -#endif + OP_MATH_FLOAT_BODY(*,mrb_float,mrb_float); break; #endif default: @@ -2466,14 +2410,10 @@ RETRY_TRY_BLOCK: break; #ifndef MRB_WITHOUT_FLOAT case MRB_TT_FLOAT: -#ifdef MRB_WORD_BOXING { mrb_float x = mrb_float(regs[a]); SET_FLOAT_VALUE(mrb, regs[a], x + b); } -#else - mrb_float(regs[a]) += b; -#endif break; #endif default: @@ -2507,14 +2447,10 @@ RETRY_TRY_BLOCK: break; #ifndef MRB_WITHOUT_FLOAT case MRB_TT_FLOAT: -#ifdef MRB_WORD_BOXING { mrb_float x = mrb_float(regs[a]); SET_FLOAT_VALUE(mrb, regs[a], (mrb_float)x - (mrb_float)b); } -#else - mrb_float(regs_a[0]) -= b; -#endif break; #endif default: -- cgit v1.2.3 From 0ebbc491a1ce45b85934be04e5824d69463ca593 Mon Sep 17 00:00:00 2001 From: dearblue Date: Sun, 14 Apr 2019 15:35:51 +0900 Subject: Include `RFiber` and `RIstruct` as a part of `RVALUE` --- src/gc.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/gc.c b/src/gc.c index ec52787e8..798e2c00a 100644 --- a/src/gc.c +++ b/src/gc.c @@ -10,6 +10,7 @@ #include #include #include +#include #include #include #include @@ -109,8 +110,10 @@ typedef struct { struct RHash hash; struct RRange range; struct RData data; + struct RIstruct istruct; struct RProc proc; struct REnv env; + struct RFiber fiber; struct RException exc; struct RBreak brk; #ifdef MRB_WORD_BOXING -- cgit v1.2.3 From c2fa935fee31c201ba4b07e72690e78a3094cf68 Mon Sep 17 00:00:00 2001 From: dearblue Date: Sun, 14 Apr 2019 16:11:21 +0900 Subject: Fix hexdigits convertion --- mrbgems/mruby-compiler/core/parse.y | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/mrbgems/mruby-compiler/core/parse.y b/mrbgems/mruby-compiler/core/parse.y index ca4c90770..f6b883b9e 100644 --- a/mrbgems/mruby-compiler/core/parse.y +++ b/mrbgems/mruby-compiler/core/parse.y @@ -5712,10 +5712,11 @@ parser_yylex(parser_state *p) if (!identchar(c)) { char buf[36]; const char s[] = "Invalid char in expression: 0x"; + const char hexdigits[] = "0123456789ABCDEF"; strcpy(buf, s); - buf[sizeof(s)] = (c & 0xff00) >> 8; - buf[sizeof(s)+1] = (c & 0xff); + buf[sizeof(s)] = hexdigits[(c & 0xf0) >> 4]; + buf[sizeof(s)+1] = hexdigits[(c & 0x0f)]; buf[sizeof(s)+2] = 0; yyerror(p, buf); goto retry; -- cgit v1.2.3 From dac0f3f5e85d067b15c44a933b151acefb2d5598 Mon Sep 17 00:00:00 2001 From: dearblue Date: Sun, 14 Apr 2019 16:16:05 +0900 Subject: Fix string index for appending `sizeof(string-literal)` is included `'\0'` character --- mrbgems/mruby-compiler/core/parse.y | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/mrbgems/mruby-compiler/core/parse.y b/mrbgems/mruby-compiler/core/parse.y index f6b883b9e..7838b6dfb 100644 --- a/mrbgems/mruby-compiler/core/parse.y +++ b/mrbgems/mruby-compiler/core/parse.y @@ -5715,9 +5715,9 @@ parser_yylex(parser_state *p) const char hexdigits[] = "0123456789ABCDEF"; strcpy(buf, s); - buf[sizeof(s)] = hexdigits[(c & 0xf0) >> 4]; - buf[sizeof(s)+1] = hexdigits[(c & 0x0f)]; - buf[sizeof(s)+2] = 0; + buf[sizeof(s)-1] = hexdigits[(c & 0xf0) >> 4]; + buf[sizeof(s)] = hexdigits[(c & 0x0f)]; + buf[sizeof(s)+1] = 0; yyerror(p, buf); goto retry; } -- cgit v1.2.3 From 3f3e4754d931004838278c1483e047a3635ebeb0 Mon Sep 17 00:00:00 2001 From: dearblue Date: Sun, 14 Apr 2019 15:58:11 +0900 Subject: Fix leaked function symbols - `free_heap()` in src/gc.c - `symhash()` in src/symbol.c - `no_optimize()` in mrbgems/mruby-compiler/core/codegen.c --- mrbgems/mruby-compiler/core/codegen.c | 3 +-- src/gc.c | 2 +- src/symbol.c | 2 +- 3 files changed, 3 insertions(+), 4 deletions(-) diff --git a/mrbgems/mruby-compiler/core/codegen.c b/mrbgems/mruby-compiler/core/codegen.c index b6d35f363..ed8fc3150 100644 --- a/mrbgems/mruby-compiler/core/codegen.c +++ b/mrbgems/mruby-compiler/core/codegen.c @@ -273,8 +273,7 @@ genop_W(codegen_scope *s, mrb_code i, uint32_t a) #define NOVAL 0 #define VAL 1 -//static -mrb_bool +static mrb_bool no_optimize(codegen_scope *s) { if (s && s->parser && s->parser->no_optimize) diff --git a/src/gc.c b/src/gc.c index ec52787e8..d07335eca 100644 --- a/src/gc.c +++ b/src/gc.c @@ -396,7 +396,7 @@ mrb_gc_init(mrb_state *mrb, mrb_gc *gc) static void obj_free(mrb_state *mrb, struct RBasic *obj, int end); -void +static void free_heap(mrb_state *mrb, mrb_gc *gc) { mrb_heap_page *page = gc->heaps; diff --git a/src/symbol.c b/src/symbol.c index 96ca9dd17..b26f2b1fd 100644 --- a/src/symbol.c +++ b/src/symbol.c @@ -91,7 +91,7 @@ sym_inline_unpack(mrb_sym sym, char *buf, mrb_int *lenp) } #endif -uint8_t +static uint8_t symhash(const char *key, size_t len) { uint32_t hash, i; -- cgit v1.2.3 From d557f977324bc55ae99205608099a788038712d6 Mon Sep 17 00:00:00 2001 From: dearblue Date: Sun, 14 Apr 2019 17:39:50 +0900 Subject: Remove pointer check after `mrb_malloc()` --- src/variable.c | 1 - 1 file changed, 1 deletion(-) diff --git a/src/variable.c b/src/variable.c index f97b09c52..6899d7475 100644 --- a/src/variable.c +++ b/src/variable.c @@ -87,7 +87,6 @@ iv_put(mrb_state *mrb, iv_tbl *t, mrb_sym sym, mrb_value val) } seg = (segment*)mrb_malloc(mrb, sizeof(segment)); - if (!seg) return; seg->next = NULL; seg->key[0] = sym; seg->val[0] = val; -- cgit v1.2.3 From d8527d17ea504aebcdbd3970127899e0216d46dc Mon Sep 17 00:00:00 2001 From: dearblue Date: Sun, 14 Apr 2019 17:42:35 +0900 Subject: Fix wrong size of instance variable if occur out of memory --- src/variable.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/variable.c b/src/variable.c index 6899d7475..983fe52f7 100644 --- a/src/variable.c +++ b/src/variable.c @@ -79,10 +79,10 @@ iv_put(mrb_state *mrb, iv_tbl *t, mrb_sym sym, mrb_value val) } /* Not found */ - t->size++; if (matched_seg) { matched_seg->key[matched_idx] = sym; matched_seg->val[matched_idx] = val; + t->size++; return; } @@ -91,6 +91,7 @@ iv_put(mrb_state *mrb, iv_tbl *t, mrb_sym sym, mrb_value val) seg->key[0] = sym; seg->val[0] = val; t->last_len = 1; + t->size++; if (prev) { prev->next = seg; } -- cgit v1.2.3 From d328808892bf866f9ad72ba476fcee00edd06293 Mon Sep 17 00:00:00 2001 From: dearblue Date: Sun, 14 Apr 2019 17:55:20 +0900 Subject: Fix memory leak for hash table index if occur out of memory --- src/hash.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hash.c b/src/hash.c index c4820513b..a9367a426 100644 --- a/src/hash.c +++ b/src/hash.c @@ -182,7 +182,7 @@ ht_index(mrb_state *mrb, htable *t) if (!index || index->capa < size) { index = (segindex*)mrb_realloc_simple(mrb, index, sizeof(segindex)+sizeof(struct segkv*)*size); if (index == NULL) { - mrb_free(mrb, index); + mrb_free(mrb, t->index); t->index = NULL; return; } -- cgit v1.2.3 From 716a99b069461b11c2b46099119f8578cd2c8f3f Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Wed, 3 Apr 2019 21:38:47 +0900 Subject: Add `assert_match` and `assert_not_match` --- mrbgems/mruby-test/driver.c | 146 ++++++++++++++++++++++++++++++++++++++++++++ test/assert.rb | 33 ++++++++++ test/t/module.rb | 7 +-- 3 files changed, 181 insertions(+), 5 deletions(-) diff --git a/mrbgems/mruby-test/driver.c b/mrbgems/mruby-test/driver.c index fd180b1bb..9e3dbea9d 100644 --- a/mrbgems/mruby-test/driver.c +++ b/mrbgems/mruby-test/driver.c @@ -62,6 +62,151 @@ t_print(mrb_state *mrb, mrb_value self) return mrb_nil_value(); } +#define UNESCAPE(p, endp) ((p) != (endp) && *(p) == '\\' ? (p)+1 : (p)) +#define CHAR_CMP(c1, c2) ((unsigned char)(c1) - (unsigned char)(c2)) + +static const char * +str_match_bracket(const char *p, const char *pat_end, + const char *s, const char *str_end) +{ + mrb_bool ok = FALSE, negated = FALSE; + + if (p == pat_end) return NULL; + if (*p == '!' || *p == '^') { + negated = TRUE; + ++p; + } + + while (*p != ']') { + const char *t1 = p; + if ((t1 = UNESCAPE(t1, pat_end)) == pat_end) return NULL; + if ((p = t1 + 1) == pat_end) return NULL; + if (p[0] == '-' && p[1] != ']') { + const char *t2 = p + 1; + if ((t2 = UNESCAPE(t2, pat_end)) == pat_end) return NULL; + p = t2 + 1; + if (!ok && CHAR_CMP(*t1, *s) <= 0 && CHAR_CMP(*s, *t2) <= 0) ok = TRUE; + } + else { + if (!ok && CHAR_CMP(*t1, *s) == 0) ok = TRUE; + } + } + + return ok == negated ? NULL : p + 1; +} + +static mrb_bool +str_match_no_brace_p(const char *pat, mrb_int pat_len, + const char *str, mrb_int str_len) +{ + const char *p = pat, *s = str; + const char *pat_end = pat + pat_len, *str_end = str + str_len; + const char *p_tmp = NULL, *s_tmp = NULL; + + for (;;) { + if (p == pat_end) return s == str_end; + switch (*p) { + case '*': + do { ++p; } while (p != pat_end && *p == '*'); + if (UNESCAPE(p, pat_end) == pat_end) return TRUE; + if (s == str_end) return FALSE; + p_tmp = p; + s_tmp = s; + continue; + case '?': + if (s == str_end) return FALSE; + ++p; + ++s; + continue; + case '[': { + const char *t; + if (s == str_end) return FALSE; + if ((t = str_match_bracket(p+1, pat_end, s, str_end))) { + p = t; + ++s; + continue; + } + goto L_failed; + } + } + + /* ordinary */ + p = UNESCAPE(p, pat_end); + if (s == str_end) return p == pat_end; + if (p == pat_end) goto L_failed; + if (*p++ != *s++) goto L_failed; + continue; + + L_failed: + if (p_tmp && s_tmp) { + /* try next '*' position */ + p = p_tmp; + s = ++s_tmp; + continue; + } + + return FALSE; + } +} + +#define COPY_AND_INC(dst, src, len) \ + do { memcpy(dst, src, len); dst += len; } while (0) + +static mrb_bool +str_match_p(mrb_state *mrb, + const char *pat, mrb_int pat_len, + const char *str, mrb_int str_len) +{ + const char *p = pat, *pat_end = pat + pat_len; + const char *lbrace = NULL, *rbrace = NULL; + int nest = 0; + mrb_bool ret = FALSE; + + for (; p != pat_end; ++p) { + if (*p == '{' && nest++ == 0) lbrace = p; + else if (*p == '}' && lbrace && --nest == 0) { rbrace = p; break; } + else if (*p == '\\' && ++p == pat_end) break; + } + + if (lbrace && rbrace) { + /* expand brace */ + char *ex_pat = (char *)mrb_malloc(mrb, pat_len-2); /* expanded pattern */ + char *ex_p = ex_pat; + + COPY_AND_INC(ex_p, pat, lbrace-pat); + p = lbrace; + while (p < rbrace) { + char *orig_ex_p = ex_p; + const char *t = ++p; + for (nest = 0; p < rbrace && !(*p == ',' && nest == 0); ++p) { + if (*p == '{') ++nest; + else if (*p == '}') --nest; + else if (*p == '\\' && ++p == rbrace) break; + } + COPY_AND_INC(ex_p, t, p-t); + COPY_AND_INC(ex_p, rbrace+1, pat_end-rbrace-1); + if ((ret = str_match_p(mrb, ex_pat, ex_p-ex_pat, str, str_len))) break; + ex_p = orig_ex_p; + } + mrb_free(mrb, ex_pat); + } + else if (!lbrace && !rbrace) { + ret = str_match_no_brace_p(pat, pat_len, str, str_len); + } + + return ret; +} + +static mrb_value +m_str_match_p(mrb_state *mrb, mrb_value self) +{ + const char *pat, *str; + mrb_int pat_len, str_len; + + mrb_get_args(mrb, "ss", &pat, &pat_len, &str, &str_len); + return mrb_bool_value(str_match_p(mrb, pat, pat_len, str, str_len)); +} + void mrb_init_test_driver(mrb_state *mrb, mrb_bool verbose) { @@ -69,6 +214,7 @@ mrb_init_test_driver(mrb_state *mrb, mrb_bool verbose) krn = mrb->kernel_module; mrb_define_method(mrb, krn, "t_print", t_print, MRB_ARGS_ANY()); + mrb_define_method(mrb, krn, "_str_match?", m_str_match_p, MRB_ARGS_REQ(2)); mrbtest = mrb_define_module(mrb, "Mrbtest"); diff --git a/test/assert.rb b/test/assert.rb index c57b04c12..4b01bd450 100644 --- a/test/assert.rb +++ b/test/assert.rb @@ -136,6 +136,39 @@ def _assert_include(affirmed, collection, obj, msg = nil) assert_true(ret, msg, diff) end +## +# Fail unless +str+ matches against +pattern+. +# +# +pattern+ is interpreted as pattern for File.fnmatch?. It may contain the +# following metacharacters: +# +# * :: +# Matches any string. +# +# ? :: +# Matches any one character. +# +# [_SET_], [^_SET_] ([!_SET_]) :: +# Matches any one character in _SET_. Behaves like character sets in +# Regexp, including set negation ([^a-z]). +# +# {_A_,_B_} :: +# Matches pattern _A_ or pattern _B_. +# +# \ :: +# Escapes the next character. +def assert_match(*args); _assert_match(true, *args) end +def assert_not_match(*args); _assert_match(false, *args) end +def _assert_match(affirmed, pattern, str, msg = nil) + receiver, *args = RUBY_ENGINE == "mruby" ? + [self, :_str_match?, pattern, str] : + [File, :fnmatch?, pattern, str, File::FNM_EXTGLOB|File::FNM_DOTMATCH] + unless ret = !receiver.__send__(*args) == !affirmed + diff = " Expected #{pattern.inspect} to #{'not ' unless affirmed}match #{str.inspect}." + end + assert_true(ret, msg, diff) +end + ## # Fails unless +obj+ is a kind of +cls+. def assert_kind_of(cls, obj, msg = nil) diff --git a/test/t/module.rb b/test/t/module.rb index ec36855e8..1694ef577 100644 --- a/test/t/module.rb +++ b/test/t/module.rb @@ -640,11 +640,8 @@ assert('Module#to_s') do assert_equal 'SetOuter', SetOuter.to_s assert_equal 'SetOuter::SetInner', SetOuter::SetInner.to_s - mod = Module.new - cls = Class.new - - assert_equal "#", Module.new.to_s + assert_match "#", Class.new.to_s end assert('Module#inspect') do -- cgit v1.2.3 From 30c880bea9ace559ccef50d5ed1a5dbf75659bbf Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Sun, 14 Apr 2019 22:40:17 +0900 Subject: Extract similar codes to macros for math opcode in `mrb_vm_exec` --- src/vm.c | 269 +++++++++++++++++++++------------------------------------------ 1 file changed, 89 insertions(+), 180 deletions(-) diff --git a/src/vm.c b/src/vm.c index 712d39b66..a7ecc575d 100644 --- a/src/vm.c +++ b/src/vm.c @@ -2214,128 +2214,67 @@ RETRY_TRY_BLOCK: } #define TYPES2(a,b) ((((uint16_t)(a))<<8)|(((uint16_t)(b))&0xff)) -#define OP_MATH_FLOAT_BODY(op,t1,t2) do { \ - RETURN_TYPE_OF_##t1 x = t1(regs[a]); \ - RETURN_TYPE_OF_##t2 y = t2(regs[a+1]); \ - SET_FLOAT_VALUE(mrb, regs[a], x op y); \ -} while (0) -#define RETURN_TYPE_OF_mrb_fixnum mrb_int -#define RETURN_TYPE_OF_mrb_float mrb_float +#define OP_MATH(op_name) \ + /* need to check if op is overridden */ \ + switch (TYPES2(mrb_type(regs[a]),mrb_type(regs[a+1]))) { \ + OP_MATH_CASE_FIXNUM(op_name); \ + OP_MATH_CASE_FLOAT(op_name, fixnum, float); \ + OP_MATH_CASE_FLOAT(op_name, float, fixnum); \ + OP_MATH_CASE_FLOAT(op_name, float, float); \ + OP_MATH_CASE_STRING_##op_name(); \ + default: \ + c = 1; \ + mid = mrb_intern_lit(mrb, MRB_STRINGIZE(OP_MATH_OP_##op_name)); \ + goto L_SEND_SYM; \ + } \ + NEXT; +#define OP_MATH_CASE_FIXNUM(op_name) \ + case TYPES2(MRB_TT_FIXNUM, MRB_TT_FIXNUM): \ + { \ + mrb_int x = mrb_fixnum(regs[a]), y = mrb_fixnum(regs[a+1]), z; \ + if (mrb_int_##op_name##_overflow(x, y, &z)) \ + OP_MATH_OVERFLOW_INT(op_name, x, y, z); \ + else \ + SET_INT_VALUE(regs[a], z); \ + } \ + break +#ifdef MRB_WITHOUT_FLOAT +#define OP_MATH_CASE_FLOAT(op_name, t1, t2) (void)0 +#define OP_MATH_OVERFLOW_INT(op_name, x, y, z) SET_INT_VALUE(regs[a], z) +#else +#define OP_MATH_CASE_FLOAT(op_name, t1, t2) \ + case TYPES2(OP_MATH_TT_##t1, OP_MATH_TT_##t2): \ + { \ + mrb_float z = mrb_##t1(regs[a]) OP_MATH_OP_##op_name mrb_##t2(regs[a+1]); \ + SET_FLOAT_VALUE(mrb, regs[a], z); \ + } \ + break +#define OP_MATH_OVERFLOW_INT(op_name, x, y, z) \ + SET_FLOAT_VALUE(mrb, regs[a], (mrb_float)x OP_MATH_OP_##op_name (mrb_float)y) +#endif +#define OP_MATH_CASE_STRING_add() \ + case TYPES2(MRB_TT_STRING, MRB_TT_STRING): \ + regs[a] = mrb_str_plus(mrb, regs[a], regs[a+1]); \ + mrb_gc_arena_restore(mrb, ai); \ + break +#define OP_MATH_CASE_STRING_sub() (void)0 +#define OP_MATH_CASE_STRING_mul() (void)0 +#define OP_MATH_OP_add + +#define OP_MATH_OP_sub - +#define OP_MATH_OP_mul * +#define OP_MATH_TT_fixnum MRB_TT_FIXNUM +#define OP_MATH_TT_float MRB_TT_FLOAT CASE(OP_ADD, B) { - /* need to check if op is overridden */ - switch (TYPES2(mrb_type(regs[a]),mrb_type(regs[a+1]))) { - case TYPES2(MRB_TT_FIXNUM,MRB_TT_FIXNUM): - { - mrb_int x, y, z; - mrb_value *regs_a = regs + a; - - x = mrb_fixnum(regs_a[0]); - y = mrb_fixnum(regs_a[1]); - if (mrb_int_add_overflow(x, y, &z)) { -#ifndef MRB_WITHOUT_FLOAT - SET_FLOAT_VALUE(mrb, regs_a[0], (mrb_float)x + (mrb_float)y); - break; -#endif - } - SET_INT_VALUE(regs[a], z); - } - break; -#ifndef MRB_WITHOUT_FLOAT - case TYPES2(MRB_TT_FIXNUM,MRB_TT_FLOAT): - OP_MATH_FLOAT_BODY(+,mrb_fixnum,mrb_float); - break; - case TYPES2(MRB_TT_FLOAT,MRB_TT_FIXNUM): - OP_MATH_FLOAT_BODY(+,mrb_float,mrb_fixnum); - break; - case TYPES2(MRB_TT_FLOAT,MRB_TT_FLOAT): - OP_MATH_FLOAT_BODY(+,mrb_float,mrb_float); - break; -#endif - case TYPES2(MRB_TT_STRING,MRB_TT_STRING): - regs[a] = mrb_str_plus(mrb, regs[a], regs[a+1]); - break; - default: - c = 1; - mid = mrb_intern_lit(mrb, "+"); - goto L_SEND_SYM; - } - mrb_gc_arena_restore(mrb, ai); - NEXT; + OP_MATH(add); } CASE(OP_SUB, B) { - /* need to check if op is overridden */ - switch (TYPES2(mrb_type(regs[a]),mrb_type(regs[a+1]))) { - case TYPES2(MRB_TT_FIXNUM,MRB_TT_FIXNUM): - { - mrb_int x, y, z; - - x = mrb_fixnum(regs[a]); - y = mrb_fixnum(regs[a+1]); - if (mrb_int_sub_overflow(x, y, &z)) { -#ifndef MRB_WITHOUT_FLOAT - SET_FLOAT_VALUE(mrb, regs[a], (mrb_float)x - (mrb_float)y); - break; -#endif - } - SET_INT_VALUE(regs[a], z); - } - break; -#ifndef MRB_WITHOUT_FLOAT - case TYPES2(MRB_TT_FIXNUM,MRB_TT_FLOAT): - OP_MATH_FLOAT_BODY(-,mrb_fixnum,mrb_float); - break; - case TYPES2(MRB_TT_FLOAT,MRB_TT_FIXNUM): - OP_MATH_FLOAT_BODY(-,mrb_float,mrb_fixnum); - break; - case TYPES2(MRB_TT_FLOAT,MRB_TT_FLOAT): - OP_MATH_FLOAT_BODY(-,mrb_float,mrb_float); - break; -#endif - default: - c = 1; - mid = mrb_intern_lit(mrb, "-"); - goto L_SEND_SYM; - } - NEXT; + OP_MATH(sub); } CASE(OP_MUL, B) { - /* need to check if op is overridden */ - switch (TYPES2(mrb_type(regs[a]),mrb_type(regs[a+1]))) { - case TYPES2(MRB_TT_FIXNUM,MRB_TT_FIXNUM): - { - mrb_int x, y, z; - - x = mrb_fixnum(regs[a]); - y = mrb_fixnum(regs[a+1]); - if (mrb_int_mul_overflow(x, y, &z)) { -#ifndef MRB_WITHOUT_FLOAT - SET_FLOAT_VALUE(mrb, regs[a], (mrb_float)x * (mrb_float)y); - break; -#endif - } - SET_INT_VALUE(regs[a], z); - } - break; -#ifndef MRB_WITHOUT_FLOAT - case TYPES2(MRB_TT_FIXNUM,MRB_TT_FLOAT): - OP_MATH_FLOAT_BODY(*,mrb_fixnum,mrb_float); - break; - case TYPES2(MRB_TT_FLOAT,MRB_TT_FIXNUM): - OP_MATH_FLOAT_BODY(*,mrb_float,mrb_fixnum); - break; - case TYPES2(MRB_TT_FLOAT,MRB_TT_FLOAT): - OP_MATH_FLOAT_BODY(*,mrb_float,mrb_float); - break; -#endif - default: - c = 1; - mid = mrb_intern_lit(mrb, "*"); - goto L_SEND_SYM; - } - NEXT; + OP_MATH(mul); } CASE(OP_DIV, B) { @@ -2390,76 +2329,46 @@ RETRY_TRY_BLOCK: NEXT; } - CASE(OP_ADDI, BB) { - /* need to check if + is overridden */ - switch (mrb_type(regs[a])) { - case MRB_TT_FIXNUM: - { - mrb_int x = mrb_fixnum(regs[a]); - mrb_int y = (mrb_int)b; - mrb_int z; - - if (mrb_int_add_overflow(x, y, &z)) { -#ifndef MRB_WITHOUT_FLOAT - SET_FLOAT_VALUE(mrb, regs[a], (mrb_float)x + (mrb_float)y); - break; -#endif - } - SET_INT_VALUE(regs[a], z); - } - break; -#ifndef MRB_WITHOUT_FLOAT - case MRB_TT_FLOAT: - { - mrb_float x = mrb_float(regs[a]); - SET_FLOAT_VALUE(mrb, regs[a], x + b); - } - break; +#define OP_MATHI(op_name) \ + /* need to check if op is overridden */ \ + switch (mrb_type(regs[a])) { \ + OP_MATHI_CASE_FIXNUM(op_name); \ + OP_MATHI_CASE_FLOAT(op_name); \ + default: \ + SET_INT_VALUE(regs[a+1], b); \ + c = 1; \ + mid = mrb_intern_lit(mrb, MRB_STRINGIZE(OP_MATH_OP_##op_name)); \ + goto L_SEND_SYM; \ + } \ + NEXT; +#define OP_MATHI_CASE_FIXNUM(op_name) \ + case MRB_TT_FIXNUM: \ + { \ + mrb_int x = mrb_fixnum(regs[a]), y = (mrb_int)b, z; \ + if (mrb_int_##op_name##_overflow(x, y, &z)) \ + OP_MATH_OVERFLOW_INT(op_name, x, y, z); \ + else \ + SET_INT_VALUE(regs[a], z); \ + } \ + break +#ifdef MRB_WITHOUT_FLOAT +#define OP_MATHI_CASE_FLOAT(op_name) (void)0 +#else +#define OP_MATHI_CASE_FLOAT(op_name) \ + case MRB_TT_FLOAT: \ + { \ + mrb_float z = mrb_float(regs[a]) OP_MATH_OP_##op_name b; \ + SET_FLOAT_VALUE(mrb, regs[a], z); \ + } \ + break #endif - default: - SET_INT_VALUE(regs[a+1], b); - c = 1; - mid = mrb_intern_lit(mrb, "+"); - goto L_SEND_SYM; - } - NEXT; + + CASE(OP_ADDI, BB) { + OP_MATHI(add); } CASE(OP_SUBI, BB) { - mrb_value *regs_a = regs + a; - - /* need to check if + is overridden */ - switch (mrb_type(regs_a[0])) { - case MRB_TT_FIXNUM: - { - mrb_int x = mrb_fixnum(regs_a[0]); - mrb_int y = (mrb_int)b; - mrb_int z; - - if (mrb_int_sub_overflow(x, y, &z)) { -#ifndef MRB_WITHOUT_FLOAT - SET_FLOAT_VALUE(mrb, regs_a[0], (mrb_float)x - (mrb_float)y); - break; -#endif - } - SET_INT_VALUE(regs_a[0], z); - } - break; -#ifndef MRB_WITHOUT_FLOAT - case MRB_TT_FLOAT: - { - mrb_float x = mrb_float(regs[a]); - SET_FLOAT_VALUE(mrb, regs[a], (mrb_float)x - (mrb_float)b); - } - break; -#endif - default: - SET_INT_VALUE(regs_a[1], b); - c = 1; - mid = mrb_intern_lit(mrb, "-"); - goto L_SEND_SYM; - } - NEXT; + OP_MATHI(sub); } #define OP_CMP_BODY(op,v1,v2) (v1(regs[a]) op v2(regs[a+1])) -- cgit v1.2.3 From 6b8d3c70702948e630536e7c42400e928ed9d773 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Mon, 15 Apr 2019 07:13:19 +0900 Subject: Fixed wrong function names; fix #4380 --- src/numeric.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/numeric.c b/src/numeric.c index 742df7b76..8205e41f6 100644 --- a/src/numeric.c +++ b/src/numeric.c @@ -510,7 +510,7 @@ flo_shift(mrb_state *mrb, mrb_value x, mrb_int width) } static mrb_value -flo_lshift(mrb_state *mrb, mrb_value x) +flo_rshift(mrb_state *mrb, mrb_value x) { mrb_int width; @@ -519,7 +519,7 @@ flo_lshift(mrb_state *mrb, mrb_value x) } static mrb_value -flo_rshift(mrb_state *mrb, mrb_value x) +flo_lshift(mrb_state *mrb, mrb_value x) { mrb_int width; @@ -1608,8 +1608,8 @@ mrb_init_numeric(mrb_state *mrb) mrb_define_method(mrb, fl, "&", flo_and, MRB_ARGS_REQ(1)); mrb_define_method(mrb, fl, "|", flo_or, MRB_ARGS_REQ(1)); mrb_define_method(mrb, fl, "^", flo_xor, MRB_ARGS_REQ(1)); - mrb_define_method(mrb, fl, ">>", flo_lshift, MRB_ARGS_REQ(1)); - mrb_define_method(mrb, fl, "<<", flo_rshift, MRB_ARGS_REQ(1)); + mrb_define_method(mrb, fl, ">>", flo_rshift, MRB_ARGS_REQ(1)); + mrb_define_method(mrb, fl, "<<", flo_lshift, MRB_ARGS_REQ(1)); mrb_define_method(mrb, fl, "ceil", flo_ceil, MRB_ARGS_NONE()); /* 15.2.9.3.8 */ mrb_define_method(mrb, fl, "finite?", flo_finite_p, MRB_ARGS_NONE()); /* 15.2.9.3.9 */ mrb_define_method(mrb, fl, "floor", flo_floor, MRB_ARGS_NONE()); /* 15.2.9.3.10 */ -- cgit v1.2.3 From 164985881b6d7d96218ec5cd986ca1bb4c919698 Mon Sep 17 00:00:00 2001 From: Shouji Kuboyama Date: Mon, 15 Apr 2019 17:16:08 +0900 Subject: Fix test, popen and cmd in mruby-io --- mrbgems/mruby-io/test/io.rb | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/mrbgems/mruby-io/test/io.rb b/mrbgems/mruby-io/test/io.rb index 85852c179..44eaca6be 100644 --- a/mrbgems/mruby-io/test/io.rb +++ b/mrbgems/mruby-io/test/io.rb @@ -3,7 +3,7 @@ assert('IO TEST SETUP') do MRubyIOTestUtil.io_test_setup - $cr = MRubyIOTestUtil.win? ? 1 : 0 # "\n" include CR or not + $cr, $crlf, $cmd = MRubyIOTestUtil.win? ? [1, "\r\n", "cmd /c "] : [0, "\n", ""] end assert('IO', '15.2.20') do @@ -419,7 +419,7 @@ end assert('IO.popen') do begin $? = nil - io = IO.popen("echo mruby-io") + io = IO.popen("#{$cmd}echo mruby-io") assert_true io.close_on_exec? assert_equal Fixnum, io.pid.class @@ -598,7 +598,7 @@ end assert('`cmd`') do begin - assert_equal `echo foo`, "foo\n" + assert_equal `#{$cmd}echo foo`, "foo#{$crlf}" rescue NotImplementedError => e skip e.message end -- cgit v1.2.3 From d53eb8a3779735dc5df8a57f11f150cddf96e877 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Mon, 15 Apr 2019 19:03:39 +0900 Subject: Fix missing assertions in `mruby-random` test --- mrbgems/mruby-random/test/random.rb | 70 ++++++++++++++++++++++++------------- 1 file changed, 45 insertions(+), 25 deletions(-) diff --git a/mrbgems/mruby-random/test/random.rb b/mrbgems/mruby-random/test/random.rb index 1653ae4a6..813e23968 100644 --- a/mrbgems/mruby-random/test/random.rb +++ b/mrbgems/mruby-random/test/random.rb @@ -1,48 +1,66 @@ ## # Random Test -assert("Random#srand") do +assert("Random.new") do r1 = Random.new(123) r2 = Random.new(123) - r1.rand == r2.rand + r3 = Random.new(124) + assert_equal(r1.rand, r2.rand) + assert_not_equal(r1.rand, r3.rand) end -assert("Kernel::srand") do +assert("Kernel.srand") do srand(234) r1 = rand srand(234) r2 = rand - r1 == r2 + srand(235) + r3 = rand + assert_equal(r1, r2) + assert_not_equal(r1, r3) end -assert("Random::srand") do +assert("Random.srand") do Random.srand(345) r1 = rand srand(345) r2 = Random.rand - r1 == r2 + Random.srand(346) + r3 = rand + assert_equal(r1, r2) + assert_not_equal(r1, r3) end -assert("fixnum") do - rand(3).class == Fixnum -end - -assert("float") do - rand.class == Float +assert("return class of Kernel.rand") do + assert_kind_of(Fixnum, rand(3)) + assert_kind_of(Fixnum, rand(1.5)) + assert_kind_of(Float, rand) + assert_kind_of(Float, rand(0.5)) end assert("Array#shuffle") do ary = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] + orig = ary.dup shuffled = ary.shuffle - - ary == [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] and shuffled != ary and 10.times { |x| ary.include? x } + assert_equal(orig, ary) + assert_not_equal(ary, shuffled) + assert_equal(ary.size, shuffled.size) + shuffled.each do |x| + assert_include(ary, x) + ary.delete(x) + end end assert('Array#shuffle!') do ary = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] - ary.shuffle! - - ary != [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] and 10.times { |x| ary.include? x } + orig = ary.dup + assert_same(ary, ary.shuffle!) + assert_not_equal(orig, ary) + assert_equal(orig.size, ary.size) + ary.each do |x| + assert_include(orig, x) + orig.delete(x) + end end assert("Array#shuffle(random)") do @@ -52,12 +70,12 @@ assert("Array#shuffle(random)") do end # verify that the same seed causes the same results - ary1 = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] - shuffle1 = ary1.shuffle Random.new 345 - ary2 = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] - shuffle2 = ary2.shuffle Random.new 345 - - ary1 != shuffle1 and 10.times { |x| shuffle1.include? x } and shuffle1 == shuffle2 + ary = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] + shuffled1 = ary.shuffle Random.new 345 + shuffled2 = ary.shuffle Random.new 345 + shuffled3 = ary.shuffle Random.new 346 + assert_equal(shuffled1, shuffled2) + assert_not_equal(shuffled1, shuffled3) end assert('Array#shuffle!(random)') do @@ -71,6 +89,8 @@ assert('Array#shuffle!(random)') do ary1.shuffle! Random.new 345 ary2 = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] ary2.shuffle! Random.new 345 - - ary1 != [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] and 10.times { |x| ary1.include? x } and ary1 == ary2 + ary3 = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] + ary3.shuffle! Random.new 346 + assert_equal(ary1, ary2) + assert_not_equal(ary1, ary3) end -- cgit v1.2.3 From 4e45e320b05afb500a9acedc5b7a2c19b2b7158d Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Tue, 16 Apr 2019 18:47:46 +0900 Subject: Fixed a bug in recursive `mrb_top_run` calls; fix #4384 --- src/vm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vm.c b/src/vm.c index a7ecc575d..9c07b8caa 100644 --- a/src/vm.c +++ b/src/vm.c @@ -2863,11 +2863,11 @@ mrb_top_run(mrb_state *mrb, struct RProc *proc, mrb_value self, unsigned int sta return mrb_vm_run(mrb, proc, self, stack_keep); } ci = cipush(mrb); + ci->stackent = mrb->c->stack; ci->mid = 0; ci->acc = CI_ACC_SKIP; ci->target_class = mrb->object_class; v = mrb_vm_run(mrb, proc, self, stack_keep); - cipop(mrb); return v; } -- cgit v1.2.3 From 79a7f181507674a6e56846d1dc82fa97341ec544 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Tue, 16 Apr 2019 19:23:30 +0900 Subject: Avoid potential zero size array declaration; fix #4382 --- include/mruby/array.h | 3 +-- tasks/toolchains/clang.rake | 2 ++ 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/include/mruby/array.h b/include/mruby/array.h index 2e6951c0d..0c0a002f5 100644 --- a/include/mruby/array.h +++ b/include/mruby/array.h @@ -33,7 +33,6 @@ struct RArray { } aux; mrb_value *ptr; } heap; - mrb_value embed[MRB_ARY_EMBED_LEN_MAX]; } as; }; @@ -46,7 +45,7 @@ struct RArray { #define ARY_UNSET_EMBED_FLAG(a) ((a)->flags &= ~(MRB_ARY_EMBED_MASK)) #define ARY_EMBED_LEN(a) ((mrb_int)(((a)->flags & MRB_ARY_EMBED_MASK) - 1)) #define ARY_SET_EMBED_LEN(a,len) ((a)->flags = ((a)->flags&~MRB_ARY_EMBED_MASK) | ((uint32_t)(len) + 1)) -#define ARY_EMBED_PTR(a) (&((a)->as.embed[0])) +#define ARY_EMBED_PTR(a) ((mrb_value*)&(a)->as) #define ARY_LEN(a) (ARY_EMBED_P(a)?ARY_EMBED_LEN(a):(a)->as.heap.len) #define ARY_PTR(a) (ARY_EMBED_P(a)?ARY_EMBED_PTR(a):(a)->as.heap.ptr) diff --git a/tasks/toolchains/clang.rake b/tasks/toolchains/clang.rake index 2832dad5f..7d0fe6a45 100644 --- a/tasks/toolchains/clang.rake +++ b/tasks/toolchains/clang.rake @@ -3,7 +3,9 @@ MRuby::Toolchain.new(:clang) do |conf, _params| [conf.cc, conf.objc, conf.asm].each do |cc| cc.command = ENV['CC'] || 'clang' + cc.flags << '-Wzero-length-array' unless ENV['CFLAGS'] end conf.cxx.command = ENV['CXX'] || 'clang++' + conf.cxx.flags << '-Wzero-length-array' unless ENV['CXXFLAGS'] || ENV['CFLAGS'] conf.linker.command = ENV['LD'] || ENV['CXX'] || ENV['CC'] || 'clang' end -- cgit v1.2.3 From 2ae727ac3aacd892f71f32ba4b3f343bd8705e54 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Wed, 17 Apr 2019 21:04:46 +0900 Subject: Add `Array#sample` test And simplify tests for `Array#shuffle` and `Array#shuffle!`. --- mrbgems/mruby-random/test/random.rb | 54 +++++++++++++++++++++++++++---------- 1 file changed, 40 insertions(+), 14 deletions(-) diff --git a/mrbgems/mruby-random/test/random.rb b/mrbgems/mruby-random/test/random.rb index 813e23968..cf4a55141 100644 --- a/mrbgems/mruby-random/test/random.rb +++ b/mrbgems/mruby-random/test/random.rb @@ -39,28 +39,20 @@ assert("return class of Kernel.rand") do end assert("Array#shuffle") do - ary = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] - orig = ary.dup + orig = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] + ary = orig.dup shuffled = ary.shuffle assert_equal(orig, ary) assert_not_equal(ary, shuffled) - assert_equal(ary.size, shuffled.size) - shuffled.each do |x| - assert_include(ary, x) - ary.delete(x) - end + assert_equal(orig, shuffled.sort) end assert('Array#shuffle!') do - ary = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] - orig = ary.dup + orig = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] + ary = orig.dup assert_same(ary, ary.shuffle!) assert_not_equal(orig, ary) - assert_equal(orig.size, ary.size) - ary.each do |x| - assert_include(orig, x) - orig.delete(x) - end + assert_equal(orig, ary.sort) end assert("Array#shuffle(random)") do @@ -94,3 +86,37 @@ assert('Array#shuffle!(random)') do assert_equal(ary1, ary2) assert_not_equal(ary1, ary3) end + +assert('Array#sample') do + 100.times do + assert_include([0, 1, 2], [2, 1, 0].sample) + [2, 1, 0].sample(2).each { |sample| assert_include([0, 1, 2], sample) } + h = {} + (1..10).to_a.sample(7).each do |sample| + assert_not_include(h, sample) + h[sample] = true + end + end + + assert_nil([].sample) + assert_equal([], [].sample(1)) + assert_equal([], [2, 1].sample(0)) + assert_raise(TypeError) { [2, 1].sample(true) } + assert_raise(ArgumentError) { [2, 1].sample(-1) } +end + +assert('Array#sample(random)') do + assert_raise(TypeError) do + # this will cause an exception due to the wrong argument + [1, 2].sample(2, "Not a Random instance") + end + + # verify that the same seed causes the same results + ary = (1..10).to_a + srand(15) + samples1 = ary.sample(4) + samples2 = ary.sample(4, Random.new(15)) + samples3 = ary.sample(4, Random.new(16)) + assert_equal(samples1, samples2) + assert_not_equal(samples1, samples3) +end -- cgit v1.2.3 From 916045921e629b59264a6f1e00e2347e64ef85cb Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Thu, 18 Apr 2019 19:58:05 +0900 Subject: Remove duplicated `include Comparable` in `mrblib/string.rb` --- mrblib/string.rb | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/mrblib/string.rb b/mrblib/string.rb index 62c925885..9ad8e8e73 100644 --- a/mrblib/string.rb +++ b/mrblib/string.rb @@ -3,7 +3,9 @@ # # ISO 15.2.10 class String + # ISO 15.2.10.3 include Comparable + ## # Calls the given block for each line # and pass the respective line. @@ -265,12 +267,3 @@ class String _regexp(re, :match).match(self, &block) end end - -## -# String is comparable -# -# ISO 15.2.10.3 -module Comparable; end -class String - include Comparable -end -- cgit v1.2.3 From 4a8b88f7757f71d7d88b89764b533dd5ba59fd44 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Fri, 19 Apr 2019 20:14:23 +0900 Subject: Add type check (conversion) in `String#[]=` Before this patch: 'a'[0] = 1 #=> 1 'a'[:a] = '1' #=> ArgumentError 'a'[:a, 0] = '1' #=> ArgumentError 'a'[0, :a] = '1' #=> ArgumentError 'a'[0, 1] = 1 #=> 1 After this patch / Ruby: 'a'[0] = 1 #=> TypeError 'a'[:a] = '1' #=> TypeError 'a'[:a, 0] = '1' #=> TypeError 'a'[0, :a] = '1' #=> TypeError 'a'[0, 1] = 1 #=> TypeError --- mrblib/string.rb | 11 ++++++----- test/t/string.rb | 7 +++++++ 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/mrblib/string.rb b/mrblib/string.rb index 9ad8e8e73..e9eb2be1d 100644 --- a/mrblib/string.rb +++ b/mrblib/string.rb @@ -197,12 +197,12 @@ class String def []=(*args) anum = args.size if anum == 2 - pos, value = args + pos, value = args[0], args[1].__to_str case pos when String posnum = self.index(pos) if posnum - b = self[0, posnum.to_i] + b = self[0, posnum] a = self[(posnum + pos.length)..-1] self.replace([b, value, a].join('')) else @@ -217,17 +217,18 @@ class String end return self[head, tail-head]=value else + pos = pos.__to_int pos += self.length if pos < 0 if pos < 0 || pos > self.length raise IndexError, "index #{args[0]} out of string" end - b = self[0, pos.to_i] + b = self[0, pos] a = self[pos + 1..-1] self.replace([b, value, a].join('')) end return value elsif anum == 3 - pos, len, value = args + pos, len, value = args[0].__to_int, args[1].__to_int, args[2].__to_str pos += self.length if pos < 0 if pos < 0 || pos > self.length raise IndexError, "index #{args[0]} out of string" @@ -235,7 +236,7 @@ class String if len < 0 raise IndexError, "negative length #{len}" end - b = self[0, pos.to_i] + b = self[0, pos] a = self[pos + len..-1] self.replace([b, value, a].join('')) return value diff --git a/test/t/string.rb b/test/t/string.rb index cf3702cbe..404cf03e1 100644 --- a/test/t/string.rb +++ b/test/t/string.rb @@ -161,6 +161,9 @@ assert('String#[]=') do assert_equal 'aXc', e end + assert_raise(TypeError) { 'a'[0] = 1 } + assert_raise(TypeError) { 'a'[:a] = '1' } + # length of args is 2 a1 = 'abc' assert_raise(IndexError) do @@ -197,6 +200,10 @@ assert('String#[]=') do assert_raise(IndexError) do b3['XX'] = 'Y' end + + assert_raise(TypeError) { 'a'[:a, 0] = '1' } + assert_raise(TypeError) { 'a'[0, :a] = '1' } + assert_raise(TypeError) { 'a'[0, 1] = 1 } end assert('String#capitalize', '15.2.10.5.7') do -- cgit v1.2.3 From 6907e97fa16507018a3c082fe5621d2662e59e08 Mon Sep 17 00:00:00 2001 From: dearblue Date: Fri, 19 Apr 2019 22:24:22 +0900 Subject: Change modifier to `MRB_INLINE` from `static inline` --- include/mruby.h | 8 ++++---- include/mruby/boxing_word.h | 2 +- include/mruby/class.h | 2 +- include/mruby/data.h | 2 +- include/mruby/value.h | 10 +++++----- 5 files changed, 12 insertions(+), 12 deletions(-) diff --git a/include/mruby.h b/include/mruby.h index 7026c1f5e..de6a803ef 100644 --- a/include/mruby.h +++ b/include/mruby.h @@ -868,7 +868,7 @@ typedef const char *mrb_args_format; */ MRB_API mrb_int mrb_get_args(mrb_state *mrb, mrb_args_format format, ...); -static inline mrb_sym +MRB_INLINE mrb_sym mrb_get_mid(mrb_state *mrb) /* get method symbol */ { return mrb->c->ci->mid; @@ -1081,13 +1081,13 @@ MRB_API mrb_value mrb_Float(mrb_state *mrb, mrb_value val); MRB_API mrb_value mrb_inspect(mrb_state *mrb, mrb_value obj); MRB_API mrb_bool mrb_eql(mrb_state *mrb, mrb_value obj1, mrb_value obj2); -static inline int +MRB_INLINE int mrb_gc_arena_save(mrb_state *mrb) { return mrb->gc.arena_idx; } -static inline void +MRB_INLINE void mrb_gc_arena_restore(mrb_state *mrb, int idx) { mrb->gc.arena_idx = idx; @@ -1192,7 +1192,7 @@ MRB_API mrb_value mrb_to_int(mrb_state *mrb, mrb_value val); MRB_API mrb_value mrb_to_str(mrb_state *mrb, mrb_value val); MRB_API void mrb_check_type(mrb_state *mrb, mrb_value x, enum mrb_vtype t); -static inline void mrb_check_frozen(mrb_state *mrb, void *o) +MRB_INLINE void mrb_check_frozen(mrb_state *mrb, void *o) { if (MRB_FROZEN_P((struct RBasic*)o)) mrb_frozen_error(mrb, o); } diff --git a/include/mruby/boxing_word.h b/include/mruby/boxing_word.h index 3b7167b28..a8eb7da9b 100644 --- a/include/mruby/boxing_word.h +++ b/include/mruby/boxing_word.h @@ -91,7 +91,7 @@ MRB_API mrb_value mrb_word_boxing_float_pool(struct mrb_state*, mrb_float); #define mrb_fixnum(o) ((mrb_int)(o).value.i) #define mrb_symbol(o) (o).value.sym -static inline enum mrb_vtype +MRB_INLINE enum mrb_vtype mrb_type(mrb_value o) { switch (o.w) { diff --git a/include/mruby/class.h b/include/mruby/class.h index 5ac6e5c40..a68724538 100644 --- a/include/mruby/class.h +++ b/include/mruby/class.h @@ -23,7 +23,7 @@ struct RClass { #define mrb_class_ptr(v) ((struct RClass*)(mrb_ptr(v))) -static inline struct RClass* +MRB_INLINE struct RClass* mrb_class(mrb_state *mrb, mrb_value v) { switch (mrb_type(v)) { diff --git a/include/mruby/data.h b/include/mruby/data.h index 415684342..d85edeb3a 100644 --- a/include/mruby/data.h +++ b/include/mruby/data.h @@ -63,7 +63,7 @@ MRB_API void *mrb_data_check_get_ptr(mrb_state *mrb, mrb_value, const mrb_data_t *(void**)&sval = mrb_data_get_ptr(mrb, obj, type); \ } while (0) -static inline void +MRB_INLINE void mrb_data_init(mrb_value v, void *ptr, const mrb_data_type *type) { mrb_assert(mrb_type(v) == MRB_TT_DATA); diff --git a/include/mruby/value.h b/include/mruby/value.h index 1ed20858f..14e342d14 100644 --- a/include/mruby/value.h +++ b/include/mruby/value.h @@ -189,7 +189,7 @@ MRB_INLINE mrb_value mrb_float_value(struct mrb_state *mrb, mrb_float f) } #endif -static inline mrb_value +MRB_INLINE mrb_value mrb_cptr_value(struct mrb_state *mrb, void *p) { mrb_value v; @@ -208,7 +208,7 @@ MRB_INLINE mrb_value mrb_fixnum_value(mrb_int i) return v; } -static inline mrb_value +MRB_INLINE mrb_value mrb_symbol_value(mrb_sym i) { mrb_value v; @@ -216,7 +216,7 @@ mrb_symbol_value(mrb_sym i) return v; } -static inline mrb_value +MRB_INLINE mrb_value mrb_obj_value(void *p) { mrb_value v; @@ -260,7 +260,7 @@ MRB_INLINE mrb_value mrb_true_value(void) return v; } -static inline mrb_value +MRB_INLINE mrb_value mrb_bool_value(mrb_bool boolean) { mrb_value v; @@ -268,7 +268,7 @@ mrb_bool_value(mrb_bool boolean) return v; } -static inline mrb_value +MRB_INLINE mrb_value mrb_undef_value(void) { mrb_value v; -- cgit v1.2.3 From 125c3bef19c364c958173ea27d35ffd683045ee2 Mon Sep 17 00:00:00 2001 From: dearblue Date: Fri, 19 Apr 2019 22:50:05 +0900 Subject: Add `mrb_true_p()` and `mrb_false_p()` macro functions --- include/mruby/boxing_word.h | 2 ++ include/mruby/value.h | 6 ++++++ 2 files changed, 8 insertions(+) diff --git a/include/mruby/boxing_word.h b/include/mruby/boxing_word.h index 3b7167b28..59fdb730d 100644 --- a/include/mruby/boxing_word.h +++ b/include/mruby/boxing_word.h @@ -116,6 +116,8 @@ mrb_type(mrb_value o) #define mrb_fixnum_p(o) ((o).value.i_flag == MRB_FIXNUM_FLAG) #define mrb_undef_p(o) ((o).w == MRB_Qundef) #define mrb_nil_p(o) ((o).w == MRB_Qnil) +#define mrb_false_p(o) ((o).w == MRB_Qfalse) +#define mrb_true_p(o) ((o).w == MRB_Qtrue) #define BOXWORD_SET_VALUE(o, ttt, attr, v) do { \ switch (ttt) {\ diff --git a/include/mruby/value.h b/include/mruby/value.h index 1ed20858f..8530950a9 100644 --- a/include/mruby/value.h +++ b/include/mruby/value.h @@ -157,6 +157,12 @@ typedef void mrb_value; #ifndef mrb_nil_p #define mrb_nil_p(o) (mrb_type(o) == MRB_TT_FALSE && !mrb_fixnum(o)) #endif +#ifndef mrb_false_p +#define mrb_false_p(o) (mrb_type(o) == MRB_TT_FALSE && !!mrb_fixnum(o)) +#endif +#ifndef mrb_true_p +#define mrb_true_p(o) (mrb_type(o) == MRB_TT_TRUE) +#endif #ifndef mrb_bool #define mrb_bool(o) (mrb_type(o) != MRB_TT_FALSE) #endif -- cgit v1.2.3 From 73bb144ef0dcf1f3dc4e721e0fd2d557f18cfe07 Mon Sep 17 00:00:00 2001 From: Rob Date: Fri, 19 Apr 2019 14:27:12 -0400 Subject: Fixes the twiddle wakka comparison algorithm to support passing only a major number --- lib/mruby/gem.rb | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/lib/mruby/gem.rb b/lib/mruby/gem.rb index ce2e01ab1..95c1d4bc3 100644 --- a/lib/mruby/gem.rb +++ b/lib/mruby/gem.rb @@ -267,16 +267,18 @@ module MRuby # ~> compare algorithm # # Example: + # ~> 2 means >= 2.0.0 and < 3.0.0 # ~> 2.2 means >= 2.2.0 and < 3.0.0 - # ~> 2.2.0 means >= 2.2.0 and < 2.3.0 + # ~> 2.2.2 means >= 2.2.2 and < 2.3.0 def twiddle_wakka_ok?(other) gr_or_eql = (self <=> other) >= 0 - still_minor = (self <=> other.skip_minor) < 0 - gr_or_eql and still_minor + still_major_or_minor = (self <=> other.skip_major_or_minor) < 0 + gr_or_eql and still_major_or_minor end - def skip_minor + def skip_major_or_minor a = @ary.dup + a << 0 if a.size == 1 # ~> 2 can also be represented as ~> 2.0 a.slice!(-1) a[-1] = a[-1].succ a -- cgit v1.2.3 From b2120500266c710a130bd17a5e1c7215445c884d Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Sat, 20 Apr 2019 21:23:58 +0900 Subject: Expand `BOXWORD_SET_VALUE()` macro in `include/mruby/boxing_word.h` In `SET_OBJ_VALUE()`, branch isn't removed because `switch` condition isn't constant expression. --- include/mruby/boxing_word.h | 39 ++++++++++++++++++++------------------- 1 file changed, 20 insertions(+), 19 deletions(-) diff --git a/include/mruby/boxing_word.h b/include/mruby/boxing_word.h index 59fdb730d..21ba9962a 100644 --- a/include/mruby/boxing_word.h +++ b/include/mruby/boxing_word.h @@ -119,28 +119,29 @@ mrb_type(mrb_value o) #define mrb_false_p(o) ((o).w == MRB_Qfalse) #define mrb_true_p(o) ((o).w == MRB_Qtrue) -#define BOXWORD_SET_VALUE(o, ttt, attr, v) do { \ - switch (ttt) {\ - case MRB_TT_FALSE: (o).w = (v) ? MRB_Qfalse : MRB_Qnil; break;\ - case MRB_TT_TRUE: (o).w = MRB_Qtrue; break;\ - case MRB_TT_UNDEF: (o).w = MRB_Qundef; break;\ - case MRB_TT_FIXNUM: (o).w = 0;(o).value.i_flag = MRB_FIXNUM_FLAG; (o).attr = (v); break;\ - case MRB_TT_SYMBOL: (o).w = 0;(o).value.sym_flag = MRB_SYMBOL_FLAG; (o).attr = (v); break;\ - default: (o).w = 0; (o).attr = (v); if ((o).value.bp) (o).value.bp->tt = ttt; break;\ - }\ -} while (0) - #ifndef MRB_WITHOUT_FLOAT #define SET_FLOAT_VALUE(mrb,r,v) ((r) = mrb_word_boxing_float_value(mrb, v)) #endif #define SET_CPTR_VALUE(mrb,r,v) ((r) = mrb_word_boxing_cptr_value(mrb, v)) -#define SET_NIL_VALUE(r) BOXWORD_SET_VALUE(r, MRB_TT_FALSE, value.i, 0) -#define SET_FALSE_VALUE(r) BOXWORD_SET_VALUE(r, MRB_TT_FALSE, value.i, 1) -#define SET_TRUE_VALUE(r) BOXWORD_SET_VALUE(r, MRB_TT_TRUE, value.i, 1) -#define SET_BOOL_VALUE(r,b) BOXWORD_SET_VALUE(r, (b) ? MRB_TT_TRUE : MRB_TT_FALSE, value.i, 1) -#define SET_INT_VALUE(r,n) BOXWORD_SET_VALUE(r, MRB_TT_FIXNUM, value.i, (n)) -#define SET_SYM_VALUE(r,v) BOXWORD_SET_VALUE(r, MRB_TT_SYMBOL, value.sym, (v)) -#define SET_OBJ_VALUE(r,v) BOXWORD_SET_VALUE(r, (((struct RObject*)(v))->tt), value.p, (v)) -#define SET_UNDEF_VALUE(r) BOXWORD_SET_VALUE(r, MRB_TT_UNDEF, value.i, 0) +#define SET_UNDEF_VALUE(r) ((r).w = MRB_Qundef) +#define SET_NIL_VALUE(r) ((r).w = MRB_Qnil) +#define SET_FALSE_VALUE(r) ((r).w = MRB_Qfalse) +#define SET_TRUE_VALUE(r) ((r).w = MRB_Qtrue) +#define SET_BOOL_VALUE(r,b) ((b) ? SET_TRUE_VALUE(r) : SET_FALSE_VALUE(r)) +#define SET_INT_VALUE(r,n) do { \ + (r).w = 0; \ + (r).value.i_flag = MRB_FIXNUM_FLAG; \ + (r).value.i = (n); \ +} while (0) +#define SET_SYM_VALUE(r,v) do { \ + (r).w = 0; \ + (r).value.sym_flag = MRB_SYMBOL_FLAG; \ + (r).value.sym = (v); \ +} while (0) +#define SET_OBJ_VALUE(r,v) do { \ + (r).w = 0; \ + (r).value.p = (v); \ + if ((r).value.bp) (r).value.bp->tt = ((struct RObject*)(v))->tt; \ +} while (0) #endif /* MRUBY_BOXING_WORD_H */ -- cgit v1.2.3 From cdb458ed4e07698ecb028bfe397fa273ed454e13 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Sun, 21 Apr 2019 20:34:39 +0900 Subject: Commented out `String#scan` because it is not implemented yet --- mrbgems/mruby-enumerator/mrblib/enumerator.rb | 7 ++++--- mrblib/string.rb | 21 +++++++++------------ test/t/string.rb | 4 +++- 3 files changed, 16 insertions(+), 16 deletions(-) diff --git a/mrbgems/mruby-enumerator/mrblib/enumerator.rb b/mrbgems/mruby-enumerator/mrblib/enumerator.rb index 457687268..89472ef01 100644 --- a/mrbgems/mruby-enumerator/mrblib/enumerator.rb +++ b/mrbgems/mruby-enumerator/mrblib/enumerator.rb @@ -244,9 +244,10 @@ class Enumerator # # === Examples # - # "Hello, world!".scan(/\w+/) #=> ["Hello", "world"] - # "Hello, world!".to_enum(:scan, /\w+/).to_a #=> ["Hello", "world"] - # "Hello, world!".to_enum(:scan).each(/\w+/).to_a #=> ["Hello", "world"] + # Array.new(3) #=> [nil, nil, nil] + # Array.new(3) { |i| i } #=> [0, 1, 2] + # Array.to_enum(:new, 3).to_a #=> [0, 1, 2] + # Array.to_enum(:new).each(3).to_a #=> [0, 1, 2] # # obj = Object.new # diff --git a/mrblib/string.rb b/mrblib/string.rb index e9eb2be1d..c92a9e7be 100644 --- a/mrblib/string.rb +++ b/mrblib/string.rb @@ -105,18 +105,15 @@ class String self.replace(str) end - ## - # Calls the given block for each match of +pattern+ - # If no block is given return an array with all - # matches of +pattern+. - # - # ISO 15.2.10.5.32 - def scan(reg, &block) - ### *** TODO *** ### - unless Object.const_defined?(:Regexp) - raise NotImplementedError, "scan not available (yet)" - end - end +# ## +# # Calls the given block for each match of +pattern+ +# # If no block is given return an array with all +# # matches of +pattern+. +# # +# # ISO 15.2.10.5.32 +# def scan(pattern, &block) +# # TODO: String#scan is not implemented yet +# end ## # Replace only the first match of +pattern+ with diff --git a/test/t/string.rb b/test/t/string.rb index 404cf03e1..e563db55a 100644 --- a/test/t/string.rb +++ b/test/t/string.rb @@ -509,7 +509,9 @@ assert('String#rindex(UTF-8)', '15.2.10.5.31') do assert_equal nil, str.index("さ") end if UTF8STRING -# 'String#scan', '15.2.10.5.32' will be tested in mrbgems. +# assert('String#scan', '15.2.10.5.32') do +# # Not implemented yet +# end assert('String#size', '15.2.10.5.33') do assert_equal 3, 'abc'.size -- cgit v1.2.3 From 0e6a93a9ca9b207ce26073597e2abe26bbbb2c0d Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Mon, 22 Apr 2019 19:09:29 +0900 Subject: Use `MRB_ASPEC_XXX()` macro in `codedump()` --- src/codedump.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/codedump.c b/src/codedump.c index 5bffefddb..12d609075 100644 --- a/src/codedump.c +++ b/src/codedump.c @@ -266,13 +266,13 @@ codedump(mrb_state *mrb, mrb_irep *irep) break; CASE(OP_ENTER, W): printf("OP_ENTER\t%d:%d:%d:%d:%d:%d:%d\n", - (a>>18)&0x1f, - (a>>13)&0x1f, - (a>>12)&0x1, - (a>>7)&0x1f, - (a>>2)&0x1f, - (a>>1)&0x1, - a & 0x1); + MRB_ASPEC_REQ(a), + MRB_ASPEC_OPT(a), + MRB_ASPEC_REST(a), + MRB_ASPEC_POST(a), + MRB_ASPEC_KEY(a), + MRB_ASPEC_KDICT(a), + MRB_ASPEC_BLOCK(a)); break; CASE(OP_KEY_P, BB): printf("OP_KEY_P\tR%d\t:%s\t", a, mrb_sym2name(mrb, irep->syms[b])); -- cgit v1.2.3 From 0debf154ee9aa4c4f9aa0190a54a810801c3d31d Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Mon, 22 Apr 2019 17:35:49 +0900 Subject: Add `assert_predicate` and `assert_operator` --- test/assert.rb | 20 ++++++++++++++++++++ test/t/float.rb | 20 ++++++++++---------- 2 files changed, 30 insertions(+), 10 deletions(-) diff --git a/test/assert.rb b/test/assert.rb index e0fac4d90..385de49bd 100644 --- a/test/assert.rb +++ b/test/assert.rb @@ -1,3 +1,4 @@ +$undefined = Object.new $ok_test = 0 $ko_test = 0 $kill_test = 0 @@ -136,6 +137,25 @@ def _assert_include(affirmed, collection, obj, msg = nil) assert_true(ret, msg, diff) end +def assert_predicate(*args); _assert_predicate(true, *args) end +def assert_not_predicate(*args); _assert_predicate(false, *args) end +def _assert_predicate(affirmed, obj, op, msg = nil) + unless ret = obj.__send__(op) == affirmed + diff = " Expected #{obj.inspect} to #{'not ' unless affirmed}be #{op}." + end + assert_true(ret, msg, diff) +end + +def assert_operator(*args); _assert_operator(true, *args) end +def assert_not_operator(*args); _assert_operator(false, *args) end +def _assert_operator(affirmed, obj1, op, obj2 = $undefined, msg = nil) + return _assert_predicate(affirmed, obj1, op, msg) if obj2 == $undefined + unless ret = obj1.__send__(op, obj2) == affirmed + diff = " Expected #{obj1.inspect} to #{'not ' unless affirmed}be #{op} #{obj2.inspect}." + end + assert_true(ret, msg, diff) +end + ## # Fails unless +obj+ is a kind of +cls+. def assert_kind_of(cls, obj, msg = nil) diff --git a/test/t/float.rb b/test/t/float.rb index 4e9d347b8..b4eb0bfd6 100644 --- a/test/t/float.rb +++ b/test/t/float.rb @@ -82,8 +82,8 @@ assert('Float#ceil', '15.2.9.3.8') do end assert('Float#finite?', '15.2.9.3.9') do - assert_true 3.123456789.finite? - assert_false (1.0 / 0.0).finite? + assert_predicate 3.123456789, :finite? + assert_not_predicate 1.0 / 0.0, :finite? end assert('Float#floor', '15.2.9.3.10') do @@ -139,7 +139,7 @@ assert('Float#round', '15.2.9.3.12') do nan = 0.0/0.0 assert_raise(FloatDomainError){ nan.round } assert_raise(FloatDomainError){ nan.round(-1) } - assert_true(nan.round(1).nan?) + assert_predicate(nan.round(1), :nan?) end assert('Float#to_f', '15.2.9.3.13') do @@ -178,10 +178,10 @@ assert('Float#divmod') do end assert('Float#nan?') do - assert_true (0.0/0.0).nan? - assert_false 0.0.nan? - assert_false (1.0/0.0).nan? - assert_false (-1.0/0.0).nan? + assert_predicate 0.0/0.0, :nan? + assert_not_predicate 0.0, :nan? + assert_not_predicate 1.0/0.0, :nan? + assert_not_predicate -1.0/0.0, :nan? end assert('Float#<<') do @@ -240,9 +240,9 @@ assert('Float#to_s') do end assert('Float#eql?') do - assert_true(5.0.eql?(5.0)) - assert_false(5.0.eql?(5)) - assert_false(5.0.eql?("5.0")) + assert_operator(5.0, :eql?, 5.0) + assert_not_operator(5.0, :eql?, 5) + assert_not_operator(5.0, :eql?, "5.0") end end # const_defined?(:Float) -- cgit v1.2.3 From e9f3902ab5544de31fc91459e1846650aa228142 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Tue, 23 Apr 2019 15:30:10 +0900 Subject: Fixed the condition in `mrb_funcall_with_block`; fix #4389 --- src/vm.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/src/vm.c b/src/vm.c index 9c07b8caa..8dc6623d1 100644 --- a/src/vm.c +++ b/src/vm.c @@ -490,22 +490,21 @@ mrb_funcall_with_block(mrb_state *mrb, mrb_value self, mrb_sym mid, mrb_int argc if (mrb->c->stbase <= argv && argv < mrb->c->stend) { voff = argv - mrb->c->stbase; } - if (MRB_METHOD_CFUNC_P(m)) { - mrb_stack_extend(mrb, argc + 2); - } - else if (argc >= CALL_MAXARGS) { + if (argc >= CALL_MAXARGS) { mrb_value args = mrb_ary_new_from_values(mrb, argc, argv); - mrb_stack_extend(mrb, 3); mrb->c->stack[1] = args; ci->argc = -1; argc = 1; } - else if (MRB_METHOD_PROC_P(m)) { + mrb_stack_extend(mrb, argc + 2); + if (MRB_METHOD_PROC_P(m)) { struct RProc *p = MRB_METHOD_PROC(m); ci->proc = p; - mrb_stack_extend(mrb, p->body.irep->nregs + argc); + if (!MRB_PROC_CFUNC_P(p)) { + mrb_stack_extend(mrb, p->body.irep->nregs + argc); + } } if (voff >= 0) { argv = mrb->c->stbase + voff; -- cgit v1.2.3 From cc7f9190ba93ef45bf85a7278dffe6326cf620a3 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Tue, 23 Apr 2019 20:45:38 +0900 Subject: Fix name assignment to frozen anonymous class/module Fix the following issues: A = Class.new.freeze #=> FrozenError Module.new::B = Class.new.freeze #=> FrozenError String::B = Module.new.freeze #=> FrozenError --- include/mruby/variable.h | 1 + src/class.c | 6 +++--- src/variable.c | 21 ++++++++++++--------- test/t/module.rb | 4 ++++ 4 files changed, 20 insertions(+), 12 deletions(-) diff --git a/include/mruby/variable.h b/include/mruby/variable.h index ba6037959..ff01e5cc8 100644 --- a/include/mruby/variable.h +++ b/include/mruby/variable.h @@ -117,6 +117,7 @@ MRB_API void mrb_mod_cv_set(mrb_state *mrb, struct RClass * c, mrb_sym sym, mrb_ MRB_API void mrb_cv_set(mrb_state *mrb, mrb_value mod, mrb_sym sym, mrb_value v); MRB_API mrb_bool mrb_cv_defined(mrb_state *mrb, mrb_value mod, mrb_sym sym); mrb_value mrb_obj_iv_inspect(mrb_state*, struct RObject*); +void mrb_obj_iv_set_force(mrb_state *mrb, struct RObject *obj, mrb_sym sym, mrb_value v); mrb_value mrb_mod_constants(mrb_state *mrb, mrb_value mod); mrb_value mrb_f_global_variables(mrb_state *mrb, mrb_value self); mrb_value mrb_obj_instance_variables(mrb_state*, mrb_value); diff --git a/src/class.c b/src/class.c index d6efdbdc4..77ff04437 100644 --- a/src/class.c +++ b/src/class.c @@ -66,15 +66,15 @@ mrb_class_name_class(mrb_state *mrb, struct RClass *outer, struct RClass *c, mrb name = mrb_class_path(mrb, outer); if (mrb_nil_p(name)) { /* unnamed outer class */ if (outer != mrb->object_class && outer != c) { - mrb_obj_iv_set(mrb, (struct RObject*)c, mrb_intern_lit(mrb, "__outer__"), - mrb_obj_value(outer)); + mrb_obj_iv_set_force(mrb, (struct RObject*)c, mrb_intern_lit(mrb, "__outer__"), + mrb_obj_value(outer)); } return; } mrb_str_cat_cstr(mrb, name, "::"); mrb_str_cat_cstr(mrb, name, mrb_sym2name(mrb, id)); } - mrb_obj_iv_set(mrb, (struct RObject*)c, nsym, name); + mrb_obj_iv_set_force(mrb, (struct RObject*)c, nsym, name); } static void diff --git a/src/variable.c b/src/variable.c index 983fe52f7..e859f02bf 100644 --- a/src/variable.c +++ b/src/variable.c @@ -341,21 +341,24 @@ mrb_iv_get(mrb_state *mrb, mrb_value obj, mrb_sym sym) static inline void assign_class_name(mrb_state *mrb, struct RObject *obj, mrb_sym sym, mrb_value v); -MRB_API void -mrb_obj_iv_set(mrb_state *mrb, struct RObject *obj, mrb_sym sym, mrb_value v) +void +mrb_obj_iv_set_force(mrb_state *mrb, struct RObject *obj, mrb_sym sym, mrb_value v) { - iv_tbl *t; - - mrb_check_frozen(mrb, obj); assign_class_name(mrb, obj, sym, v); if (!obj->iv) { obj->iv = iv_new(mrb); } - t = obj->iv; - iv_put(mrb, t, sym, v); + iv_put(mrb, obj->iv, sym, v); mrb_write_barrier(mrb, (struct RBasic*)obj); } +MRB_API void +mrb_obj_iv_set(mrb_state *mrb, struct RObject *obj, mrb_sym sym, mrb_value v) +{ + mrb_check_frozen(mrb, obj); + mrb_obj_iv_set_force(mrb, obj, sym, v); +} + /* Iterates over the instance variable table. */ MRB_API void mrb_iv_foreach(mrb_state *mrb, mrb_value obj, mrb_iv_foreach_func *func, void *p) @@ -385,10 +388,10 @@ assign_class_name(mrb_state *mrb, struct RObject *obj, mrb_sym sym, mrb_value v) if (mrb_nil_p(o)) { if ((struct RClass *)obj == mrb->object_class) { - mrb_obj_iv_set(mrb, c, id_classname, mrb_symbol_value(sym)); + mrb_obj_iv_set_force(mrb, c, id_classname, mrb_symbol_value(sym)); } else { - mrb_obj_iv_set(mrb, c, id_outer, mrb_obj_value(obj)); + mrb_obj_iv_set_force(mrb, c, id_outer, mrb_obj_value(obj)); } } } diff --git a/test/t/module.rb b/test/t/module.rb index 09613e1bc..f4999019a 100644 --- a/test/t/module.rb +++ b/test/t/module.rb @@ -653,6 +653,10 @@ assert('Module#to_s') do assert_match "#", Module.new.to_s assert_match "#", Class.new.to_s + + assert_equal "FrozenClassToS", (FrozenClassToS = Class.new.freeze).to_s + assert_equal "Outer::A", (Outer::A = Module.new.freeze).to_s + assert_match "#::A", (Module.new::A = Class.new.freeze).to_s end assert('Module#inspect') do -- cgit v1.2.3 From 9f4147f28e9319a55ff7e865355fd7e70ff0aa73 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Tue, 23 Apr 2019 21:02:42 +0900 Subject: Fix "ambiguous first argument" warning in `test/t/float.rb` --- test/t/float.rb | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/test/t/float.rb b/test/t/float.rb index b4eb0bfd6..63bf83f40 100644 --- a/test/t/float.rb +++ b/test/t/float.rb @@ -178,10 +178,10 @@ assert('Float#divmod') do end assert('Float#nan?') do - assert_predicate 0.0/0.0, :nan? - assert_not_predicate 0.0, :nan? - assert_not_predicate 1.0/0.0, :nan? - assert_not_predicate -1.0/0.0, :nan? + assert_predicate(0.0/0.0, :nan?) + assert_not_predicate(0.0, :nan?) + assert_not_predicate(1.0/0.0, :nan?) + assert_not_predicate(-1.0/0.0, :nan?) end assert('Float#<<') do -- cgit v1.2.3 From 0c5f26e0ffc30bdc88b857daed1c9fe18c4b8f0c Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Wed, 24 Apr 2019 09:43:12 +0900 Subject: Remove unnecessary `mrb_regexp_check()` and related functions. --- include/mruby.h | 4 ---- include/mruby/string.h | 3 --- include/mruby/value.h | 1 - src/etc.c | 16 ---------------- src/string.c | 39 ++++++--------------------------------- 5 files changed, 6 insertions(+), 57 deletions(-) diff --git a/include/mruby.h b/include/mruby.h index de6a803ef..dcd64b2d8 100644 --- a/include/mruby.h +++ b/include/mruby.h @@ -196,13 +196,9 @@ struct mrb_jmpbuf; typedef void (*mrb_atexit_func)(struct mrb_state*); -#define MRB_STATE_NO_REGEXP 1 -#define MRB_STATE_REGEXP 2 - typedef struct mrb_state { struct mrb_jmpbuf *jmp; - uint32_t flags; mrb_allocf allocf; /* memory allocation function */ void *allocf_ud; /* auxiliary data of allocf */ diff --git a/include/mruby/string.h b/include/mruby/string.h index 0b90debec..22445f654 100644 --- a/include/mruby/string.h +++ b/include/mruby/string.h @@ -433,9 +433,6 @@ mrb_value mrb_str_dump(mrb_state *mrb, mrb_value str); */ mrb_value mrb_str_inspect(mrb_state *mrb, mrb_value str); -void mrb_noregexp(mrb_state *mrb, mrb_value self); -void mrb_regexp_check(mrb_state *mrb, mrb_value obj); - /* For backward compatibility */ #define mrb_str_cat2(mrb, str, ptr) mrb_str_cat_cstr(mrb, str, ptr) #define mrb_str_buf_cat(mrb, str, ptr, len) mrb_str_cat(mrb, str, ptr, len) diff --git a/include/mruby/value.h b/include/mruby/value.h index 0446e772c..4d47d30ff 100644 --- a/include/mruby/value.h +++ b/include/mruby/value.h @@ -180,7 +180,6 @@ typedef void mrb_value; #define mrb_cptr_p(o) (mrb_type(o) == MRB_TT_CPTR) #define mrb_exception_p(o) (mrb_type(o) == MRB_TT_EXCEPTION) #define mrb_test(o) mrb_bool(o) -MRB_API mrb_bool mrb_regexp_p(struct mrb_state*, mrb_value); /* * Returns a float in Ruby. diff --git a/src/etc.c b/src/etc.c index d15b398dd..ac1540f92 100644 --- a/src/etc.c +++ b/src/etc.c @@ -194,22 +194,6 @@ mrb_word_boxing_cptr_value(mrb_state *mrb, void *p) } #endif /* MRB_WORD_BOXING */ -MRB_API mrb_bool -mrb_regexp_p(mrb_state *mrb, mrb_value v) -{ - if (mrb->flags & MRB_STATE_NO_REGEXP) { - return FALSE; - } - if ((mrb->flags & MRB_STATE_REGEXP) || mrb_class_defined(mrb, REGEXP_CLASS)) { - mrb->flags |= MRB_STATE_REGEXP; - return mrb_obj_is_kind_of(mrb, v, mrb_class_get(mrb, REGEXP_CLASS)); - } - else { - mrb->flags |= MRB_STATE_NO_REGEXP; - } - return FALSE; -} - #if defined _MSC_VER && _MSC_VER < 1900 #ifndef va_copy diff --git a/src/string.c b/src/string.c index f7a805a94..89ab59d4b 100644 --- a/src/string.c +++ b/src/string.c @@ -997,20 +997,6 @@ mrb_string_value_len(mrb_state *mrb, mrb_value ptr) return RSTRING_LEN(ptr); } -void -mrb_noregexp(mrb_state *mrb, mrb_value self) -{ - mrb_raise(mrb, E_NOTIMP_ERROR, "Regexp class not implemented"); -} - -void -mrb_regexp_check(mrb_state *mrb, mrb_value obj) -{ - if (mrb_regexp_p(mrb, obj)) { - mrb_noregexp(mrb, obj); - } -} - MRB_API mrb_value mrb_str_dup(mrb_state *mrb, mrb_value str) { @@ -1026,7 +1012,6 @@ mrb_str_aref(mrb_state *mrb, mrb_value str, mrb_value indx) { mrb_int idx; - mrb_regexp_check(mrb, indx); switch (mrb_type(indx)) { case MRB_TT_FIXNUM: idx = mrb_fixnum(indx); @@ -1119,7 +1104,6 @@ mrb_str_aref_m(mrb_state *mrb, mrb_value str) if (argc == 2) { mrb_int n1, n2; - mrb_regexp_check(mrb, a1); mrb_get_args(mrb, "ii", &n1, &n2); return str_substr(mrb, str, n1, n2); } @@ -1549,7 +1533,6 @@ mrb_str_index_m(mrb_state *mrb, mrb_value str) else sub = mrb_nil_value(); } - mrb_regexp_check(mrb, sub); clen = RSTRING_CHAR_LEN(str); if (pos < 0) { pos += clen; @@ -1801,7 +1784,6 @@ mrb_str_rindex(mrb_state *mrb, mrb_value str) if (pos < 0) { pos += len; if (pos < 0) { - mrb_regexp_check(mrb, sub); return mrb_nil_value(); } } @@ -1815,7 +1797,6 @@ mrb_str_rindex(mrb_state *mrb, mrb_value str) sub = mrb_nil_value(); } pos = chars2bytes(str, 0, pos); - mrb_regexp_check(mrb, sub); switch (mrb_type(sub)) { default: { @@ -1909,16 +1890,11 @@ mrb_str_split_m(mrb_state *mrb, mrb_value str) if (argc == 0 || mrb_nil_p(spat)) { split_type = awk; } - else { - if (mrb_string_p(spat)) { - split_type = string; - if (RSTRING_LEN(spat) == 1 && RSTRING_PTR(spat)[0] == ' ') { - split_type = awk; - } - } - else { - mrb_noregexp(mrb, str); - } + else if (!mrb_string_p(spat)) { + mrb_raise(mrb, E_TYPE_ERROR, "expected String"); + } + else if (RSTRING_LEN(spat) == 1 && RSTRING_PTR(spat)[0] == ' ') { + split_type = awk; } result = mrb_ary_new(mrb); @@ -1955,7 +1931,7 @@ mrb_str_split_m(mrb_state *mrb, mrb_value str) } } } - else if (split_type == string) { + else { /* split_type == string */ mrb_int str_len = RSTRING_LEN(str); mrb_int pat_len = RSTRING_LEN(spat); mrb_int idx = 0; @@ -1976,9 +1952,6 @@ mrb_str_split_m(mrb_state *mrb, mrb_value str) } beg = idx; } - else { - mrb_noregexp(mrb, str); - } if (RSTRING_LEN(str) > 0 && (lim_p || RSTRING_LEN(str) > beg || lim < 0)) { if (RSTRING_LEN(str) == beg) { tmp = mrb_str_new_empty(mrb, str); -- cgit v1.2.3 From 163a6d01e035f16b15d3b08c0dfddd2caec09f9b Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Wed, 24 Apr 2019 12:09:16 +0900 Subject: Reorganize defines related to `MRB_INLINE`; ref #4391 --- include/mruby/common.h | 10 +++++----- include/mruby/value.h | 3 --- 2 files changed, 5 insertions(+), 8 deletions(-) diff --git a/include/mruby/common.h b/include/mruby/common.h index 4eaac9af7..dc9e3acc5 100644 --- a/include/mruby/common.h +++ b/include/mruby/common.h @@ -54,12 +54,12 @@ MRB_BEGIN_DECL #endif /** Declare a function as always inlined. */ -#if defined(_MSC_VER) -# define MRB_INLINE static __inline -#else -# define MRB_INLINE static inline +#if defined _MSC_VER && _MSC_VER < 1900 +# ifndef __cplusplus +# define inline __inline +# endif #endif - +#define MRB_INLINE static inline /** Declare a public MRuby API function. */ #if defined(MRB_BUILD_AS_DLL) diff --git a/include/mruby/value.h b/include/mruby/value.h index 4d47d30ff..6838daaa5 100644 --- a/include/mruby/value.h +++ b/include/mruby/value.h @@ -73,9 +73,6 @@ MRB_API double mrb_float_read(const char*, char**); #endif #if defined _MSC_VER && _MSC_VER < 1900 -# ifndef __cplusplus -# define inline __inline -# endif # include MRB_API int mrb_msvc_vsnprintf(char *s, size_t n, const char *format, va_list arg); MRB_API int mrb_msvc_snprintf(char *s, size_t n, const char *format, ...); -- cgit v1.2.3 From 4720648137f2698cceb635c251475dec645cd598 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Wed, 24 Apr 2019 21:05:44 +0900 Subject: Fix modiying class variable to frozen class/module --- mrbgems/mruby-metaprog/test/metaprog.rb | 8 +++++++- src/variable.c | 2 ++ test/t/class.rb | 19 +++++++++++++++++++ 3 files changed, 28 insertions(+), 1 deletion(-) diff --git a/mrbgems/mruby-metaprog/test/metaprog.rb b/mrbgems/mruby-metaprog/test/metaprog.rb index 1262c9945..0abeb90a6 100644 --- a/mrbgems/mruby-metaprog/test/metaprog.rb +++ b/mrbgems/mruby-metaprog/test/metaprog.rb @@ -171,7 +171,6 @@ assert('Module#class_variable_set', '15.2.2.4.18') do @@foo end end - assert_equal 99, Test4ClassVariableSet.class_variable_set(:@@cv, 99) assert_equal 101, Test4ClassVariableSet.class_variable_set(:@@foo, 101) assert_true Test4ClassVariableSet.class_variables.include? :@@cv @@ -180,6 +179,13 @@ assert('Module#class_variable_set', '15.2.2.4.18') do %w[@@ @@1 @@x= @x @ x 1].each do |n| assert_raise(NameError) { Test4ClassVariableSet.class_variable_set(n, 1) } end + + m = Module.new.freeze + assert_raise(FrozenError) { m.class_variable_set(:@@cv, 1) } + + parent = Class.new{ class_variable_set(:@@a, nil) }.freeze + child = Class.new(parent) + assert_raise(FrozenError) { child.class_variable_set(:@@a, 1) } end assert('Module#class_variables', '15.2.2.4.19') do diff --git a/src/variable.c b/src/variable.c index 983fe52f7..c4c9d369f 100644 --- a/src/variable.c +++ b/src/variable.c @@ -671,6 +671,7 @@ mrb_mod_cv_set(mrb_state *mrb, struct RClass *c, mrb_sym sym, mrb_value v) iv_tbl *t = c->iv; if (iv_get(mrb, t, sym, NULL)) { + mrb_check_frozen(mrb, c); iv_put(mrb, t, sym, v); mrb_write_barrier(mrb, (struct RBasic*)c); return; @@ -698,6 +699,7 @@ mrb_mod_cv_set(mrb_state *mrb, struct RClass *c, mrb_sym sym, mrb_value v) c = cls; } + mrb_check_frozen(mrb, c); if (!c->iv) { c->iv = iv_new(mrb); } diff --git a/test/t/class.rb b/test/t/class.rb index 290ecf74a..0c95677fc 100644 --- a/test/t/class.rb +++ b/test/t/class.rb @@ -433,6 +433,25 @@ assert('overriding class variable with a module (#3235)') do end end +assert('class variable for frozen class/module') do + module CVarForFrozenModule + freeze + assert_raise(FrozenError) { @@cv = 1 } + end + + class CVarForFrozenClassA + @@a = nil + freeze + end + class CVarForFrozenClassB < CVarForFrozenClassA + def a=(v) + @@a = v + end + end + b = CVarForFrozenClassB.new + assert_raise(FrozenError) { b.a = 1 } +end + assert('class with non-class/module outer raises TypeError') do assert_raise(TypeError) { class 0::C1; end } assert_raise(TypeError) { class []::C2; end } -- cgit v1.2.3 From 4d85019e4cc3748a75d7c542fba80fcbf8554d5c Mon Sep 17 00:00:00 2001 From: dearblue Date: Wed, 24 Apr 2019 22:14:12 +0900 Subject: Check mruby binary version --- src/load.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/load.c b/src/load.c index ab0346750..01c97b926 100644 --- a/src/load.c +++ b/src/load.c @@ -539,6 +539,10 @@ read_binary_header(const uint8_t *bin, size_t *bin_size, uint16_t *crc, uint8_t return MRB_DUMP_INVALID_FILE_HEADER; } + if (memcmp(header->binary_version, RITE_BINARY_FORMAT_VER, sizeof(header->binary_version)) != 0) { + return MRB_DUMP_INVALID_FILE_HEADER; + } + if (crc) { *crc = bin_to_uint16(header->binary_crc); } -- cgit v1.2.3 From 58d525c9fafcc78af25d22f984821eda19d0913c Mon Sep 17 00:00:00 2001 From: dearblue Date: Sat, 6 Apr 2019 14:25:26 +0900 Subject: Check mruby binary size --- src/load.c | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/src/load.c b/src/load.c index 01c97b926..cc011fba7 100644 --- a/src/load.c +++ b/src/load.c @@ -519,10 +519,14 @@ lv_exit: } static int -read_binary_header(const uint8_t *bin, size_t *bin_size, uint16_t *crc, uint8_t *flags) +read_binary_header(const uint8_t *bin, size_t bufsize, size_t *bin_size, uint16_t *crc, uint8_t *flags) { const struct rite_binary_header *header = (const struct rite_binary_header *)bin; + if (bufsize < sizeof(struct rite_binary_header)) { + return MRB_DUMP_READ_FAULT; + } + if (memcmp(header->binary_ident, RITE_BINARY_IDENT, sizeof(header->binary_ident)) == 0) { if (bigendian_p()) *flags |= FLAG_BYTEORDER_NATIVE; @@ -548,11 +552,15 @@ read_binary_header(const uint8_t *bin, size_t *bin_size, uint16_t *crc, uint8_t } *bin_size = (size_t)bin_to_uint32(header->binary_size); + if (bufsize < *bin_size) { + return MRB_DUMP_READ_FAULT; + } + return MRB_DUMP_OK; } static mrb_irep* -read_irep(mrb_state *mrb, const uint8_t *bin, uint8_t flags) +read_irep(mrb_state *mrb, const uint8_t *bin, size_t bufsize, uint8_t flags) { int result; mrb_irep *irep = NULL; @@ -565,7 +573,7 @@ read_irep(mrb_state *mrb, const uint8_t *bin, uint8_t flags) return NULL; } - result = read_binary_header(bin, &bin_size, &crc, &flags); + result = read_binary_header(bin, bufsize, &bin_size, &crc, &flags); if (result != MRB_DUMP_OK) { return NULL; } @@ -618,7 +626,7 @@ mrb_read_irep(mrb_state *mrb, const uint8_t *bin) uint8_t flags = FLAG_SRC_STATIC; #endif - return read_irep(mrb, bin, flags); + return read_irep(mrb, bin, (size_t)-1, flags); } void mrb_exc_set(mrb_state *mrb, mrb_value exc); @@ -680,7 +688,7 @@ mrb_read_irep_file(mrb_state *mrb, FILE* fp) if (fread(buf, header_size, 1, fp) == 0) { goto irep_exit; } - result = read_binary_header(buf, &buf_size, NULL, &flags); + result = read_binary_header(buf, (size_t)-1, &buf_size, NULL, &flags); if (result != MRB_DUMP_OK || buf_size <= header_size) { goto irep_exit; } @@ -689,7 +697,7 @@ mrb_read_irep_file(mrb_state *mrb, FILE* fp) if (fread(buf+header_size, buf_size-header_size, 1, fp) == 0) { goto irep_exit; } - irep = read_irep(mrb, buf, FLAG_SRC_MALLOC); + irep = read_irep(mrb, buf, (size_t)-1, FLAG_SRC_MALLOC); irep_exit: mrb_free(mrb, buf); -- cgit v1.2.3 From 8f6f36f6540408d3b1b5a0dddf440d53b43e53e4 Mon Sep 17 00:00:00 2001 From: dearblue Date: Sat, 6 Apr 2019 14:37:25 +0900 Subject: Add mruby binary loader functions from buffer memory Add new functions (with `MRB_API`): - `mrb_read_irep_buf()` - `mrb_load_irep_buf()` - `mrb_load_irep_buf_cxt()` --- include/mruby/dump.h | 1 + include/mruby/irep.h | 12 ++++++++++++ src/load.c | 18 ++++++++++++++++++ 3 files changed, 31 insertions(+) diff --git a/include/mruby/dump.h b/include/mruby/dump.h index 0234a362b..201d7ef61 100644 --- a/include/mruby/dump.h +++ b/include/mruby/dump.h @@ -31,6 +31,7 @@ MRB_API mrb_value mrb_load_irep_file(mrb_state*,FILE*); MRB_API mrb_value mrb_load_irep_file_cxt(mrb_state*, FILE*, mrbc_context*); #endif MRB_API mrb_irep *mrb_read_irep(mrb_state*, const uint8_t*); +MRB_API mrb_irep *mrb_read_irep_buf(mrb_state*, const void*, size_t); /* dump/load error code * diff --git a/include/mruby/irep.h b/include/mruby/irep.h index 027a294d5..d42fd0fb8 100644 --- a/include/mruby/irep.h +++ b/include/mruby/irep.h @@ -52,9 +52,21 @@ MRB_API mrb_irep *mrb_add_irep(mrb_state *mrb); /* @param [const uint8_t*] irep code, expected as a literal */ MRB_API mrb_value mrb_load_irep(mrb_state*, const uint8_t*); +/* + * @param [const void*] irep code + * @param [size_t] size of irep buffer. If -1 is given, it is considered unrestricted. + */ +MRB_API mrb_value mrb_load_irep_buf(mrb_state*, const void*, size_t); + /* @param [const uint8_t*] irep code, expected as a literal */ MRB_API mrb_value mrb_load_irep_cxt(mrb_state*, const uint8_t*, mrbc_context*); +/* + * @param [const void*] irep code + * @param [size_t] size of irep buffer. If -1 is given, it is considered unrestricted. + */ +MRB_API mrb_value mrb_load_irep_buf_cxt(mrb_state*, const void*, size_t, mrbc_context*); + void mrb_irep_free(mrb_state*, struct mrb_irep*); void mrb_irep_incref(mrb_state*, struct mrb_irep*); void mrb_irep_decref(mrb_state*, struct mrb_irep*); diff --git a/src/load.c b/src/load.c index cc011fba7..0274f30d4 100644 --- a/src/load.c +++ b/src/load.c @@ -629,6 +629,12 @@ mrb_read_irep(mrb_state *mrb, const uint8_t *bin) return read_irep(mrb, bin, (size_t)-1, flags); } +MRB_API mrb_irep* +mrb_read_irep_buf(mrb_state *mrb, const void *buf, size_t bufsize) +{ + return read_irep(mrb, (const uint8_t *)buf, bufsize, FLAG_SRC_MALLOC); +} + void mrb_exc_set(mrb_state *mrb, mrb_value exc); static void @@ -662,12 +668,24 @@ mrb_load_irep_cxt(mrb_state *mrb, const uint8_t *bin, mrbc_context *c) return load_irep(mrb, mrb_read_irep(mrb, bin), c); } +MRB_API mrb_value +mrb_load_irep_buf_cxt(mrb_state *mrb, const void *buf, size_t bufsize, mrbc_context *c) +{ + return load_irep(mrb, mrb_read_irep_buf(mrb, buf, bufsize), c); +} + MRB_API mrb_value mrb_load_irep(mrb_state *mrb, const uint8_t *bin) { return mrb_load_irep_cxt(mrb, bin, NULL); } +MRB_API mrb_value +mrb_load_irep_buf(mrb_state *mrb, const void *buf, size_t bufsize) +{ + return mrb_load_irep_buf_cxt(mrb, buf, bufsize, NULL); +} + #ifndef MRB_DISABLE_STDIO mrb_irep* -- cgit v1.2.3 From 8fa3995a1a02e9014ce01351e0260bec20ceefd7 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Thu, 25 Apr 2019 19:48:40 +0900 Subject: Singleton class of frozen object should be frozen Before this patch: p (class << Object.new.freeze; self end).frozen? #=> false sc = class << (o=Object.new); self end; o.freeze; p sc.frozen? #=> false After this patch / Ruby: p (class << Object.new.freeze; self end).frozen? #=> true sc = class << (o=Object.new); self end; o.freeze; p sc.frozen? #=> true --- mrbgems/mruby-metaprog/test/metaprog.rb | 16 ++++++++++++++++ src/class.c | 1 + src/kernel.c | 1 + test/t/class.rb | 7 +++++++ 4 files changed, 25 insertions(+) diff --git a/mrbgems/mruby-metaprog/test/metaprog.rb b/mrbgems/mruby-metaprog/test/metaprog.rb index 0abeb90a6..3aa1d8732 100644 --- a/mrbgems/mruby-metaprog/test/metaprog.rb +++ b/mrbgems/mruby-metaprog/test/metaprog.rb @@ -122,6 +122,22 @@ assert('Kernel#define_singleton_method') do assert_equal :singleton_method_ok, o.test_method end +assert('Kernel#singleton_class') do + o1 = Object.new + assert_same(o1.singleton_class, class << o1; self end) + + o2 = Object.new + sc2 = class << o2; self end + assert_same(o2.singleton_class, sc2) + + o3 = Object.new + sc3 = o3.singleton_class + o3.freeze + assert_predicate(sc3, :frozen?) + + assert_predicate(Object.new.freeze.singleton_class, :frozen?) +end + def labeled_module(name, &block) Module.new do (class <flags |= o->flags & MRB_FL_OBJ_IS_FROZEN; } static mrb_value diff --git a/src/kernel.c b/src/kernel.c index d9a1d36ce..45bca7558 100644 --- a/src/kernel.c +++ b/src/kernel.c @@ -438,6 +438,7 @@ mrb_obj_freeze(mrb_state *mrb, mrb_value self) struct RBasic *b = mrb_basic_ptr(self); if (!MRB_FROZEN_P(b)) { MRB_SET_FROZEN_FLAG(b); + if (b->c->tt == MRB_TT_SCLASS) MRB_SET_FROZEN_FLAG(b->c); } } return self; diff --git a/test/t/class.rb b/test/t/class.rb index 0c95677fc..e2839111c 100644 --- a/test/t/class.rb +++ b/test/t/class.rb @@ -356,6 +356,13 @@ assert('singleton tests') do end end end if Object.const_defined?(:Float) + + o = Object.new + sc = class << o; self end + o.freeze + assert_predicate(sc, :frozen?) + + assert_predicate(class << Object.new.freeze; self end, :frozen?) end assert('clone Class') do -- cgit v1.2.3 From 302ad847a35f6bf3395ff8605c2007dc9698cea5 Mon Sep 17 00:00:00 2001 From: dearblue Date: Fri, 26 Apr 2019 21:28:57 +0900 Subject: Add customized `mrb_ro_data_p()` User definable `mrb_ro_data_p()` functions are available by defining `MRB_USE_CUSTOM_RO_DATA_P`. (Limitation) It can not be defined as an inline function. --- include/mruby/value.h | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/include/mruby/value.h b/include/mruby/value.h index 6838daaa5..be3dd397f 100644 --- a/include/mruby/value.h +++ b/include/mruby/value.h @@ -278,7 +278,10 @@ mrb_undef_value(void) return v; } -#ifdef MRB_USE_ETEXT_EDATA +#if defined(MRB_USE_CUSTOM_RO_DATA_P) +/* If you define `MRB_USE_CUSTOM_RO_DATA_P`, you must implement `mrb_ro_data_p()`. */ +mrb_bool mrb_ro_data_p(const char *p); +#elif defined(MRB_USE_ETEXT_EDATA) #if (defined(__APPLE__) && defined(__MACH__)) #include static inline mrb_bool -- cgit v1.2.3 From 270131253f62d806ea480ef4793e0b39cd068ee4 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Sat, 27 Apr 2019 12:50:02 +0900 Subject: Remove duplicated `String#each_char` --- mrbgems/mruby-io/test/io.rb | 4 ++-- mrbgems/mruby-method/test/method.rb | 2 +- mrbgems/mruby-string-ext/mrblib/string.rb | 10 +++++++--- mrbgems/mruby-string-ext/test/string.rb | 12 ++++++------ mrblib/string.rb | 12 ------------ 5 files changed, 16 insertions(+), 24 deletions(-) diff --git a/mrbgems/mruby-io/test/io.rb b/mrbgems/mruby-io/test/io.rb index 44eaca6be..2b3f9cf13 100644 --- a/mrbgems/mruby-io/test/io.rb +++ b/mrbgems/mruby-io/test/io.rb @@ -84,7 +84,7 @@ end assert('IO#getc', '15.2.20.5.8') do io = IO.new(IO.sysopen($mrbtest_io_rfname)) - $mrbtest_io_msg.each_char { |ch| + $mrbtest_io_msg.split("").each { |ch| assert_equal ch, io.getc } assert_equal nil, io.getc @@ -127,7 +127,7 @@ end assert('IO#readchar', '15.2.20.5.15') do # almost same as IO#getc IO.open(IO.sysopen($mrbtest_io_rfname)) do |io| - $mrbtest_io_msg.each_char { |ch| + $mrbtest_io_msg.split("").each { |ch| assert_equal ch, io.readchar } assert_raise(EOFError) do diff --git a/mrbgems/mruby-method/test/method.rb b/mrbgems/mruby-method/test/method.rb index dfddde9cc..0b67d3e61 100644 --- a/mrbgems/mruby-method/test/method.rb +++ b/mrbgems/mruby-method/test/method.rb @@ -21,7 +21,7 @@ class Interpreter } def interpret(string) @ret = "" - string.each_char {|b| Dispatcher[b].bind(self).call } + string.split("").each {|b| Dispatcher[b].bind(self).call } end end diff --git a/mrbgems/mruby-string-ext/mrblib/string.rb b/mrbgems/mruby-string-ext/mrblib/string.rb index 311803ea2..fdaf2f960 100644 --- a/mrbgems/mruby-string-ext/mrblib/string.rb +++ b/mrbgems/mruby-string-ext/mrblib/string.rb @@ -310,11 +310,15 @@ class String end end + ## + # Call the given block for each character of + # +self+. def each_char(&block) return to_enum :each_char unless block - - split('').each do |i| - block.call(i) + pos = 0 + while pos < self.size + block.call(self[pos]) + pos += 1 end self end diff --git a/mrbgems/mruby-string-ext/test/string.rb b/mrbgems/mruby-string-ext/test/string.rb index 44ca1fde2..02777e594 100644 --- a/mrbgems/mruby-string-ext/test/string.rb +++ b/mrbgems/mruby-string-ext/test/string.rb @@ -657,19 +657,19 @@ assert('String#chars(UTF-8)') do end if UTF8STRING assert('String#each_char') do - s = "" + chars = [] "hello!".each_char do |x| - s += x + chars << x end - assert_equal "hello!", s + assert_equal ["h", "e", "l", "l", "o", "!"], chars end assert('String#each_char(UTF-8)') do - s = "" + chars = [] "こんにちは世界!".each_char do |x| - s += x + chars << x end - assert_equal "こんにちは世界!", s + assert_equal ["こ", "ん", "に", "ち", "は", "世", "界", "!"], chars end if UTF8STRING assert('String#codepoints') do diff --git a/mrblib/string.rb b/mrblib/string.rb index c92a9e7be..506f23c83 100644 --- a/mrblib/string.rb +++ b/mrblib/string.rb @@ -164,18 +164,6 @@ class String self.replace(str) end - ## - # Call the given block for each character of - # +self+. - def each_char(&block) - pos = 0 - while pos < self.size - block.call(self[pos]) - pos += 1 - end - self - end - ## # Call the given block for each byte of +self+. def each_byte(&block) -- cgit v1.2.3 From b57f61ac95254cdd9becf8aab1e4e15bae404564 Mon Sep 17 00:00:00 2001 From: dearblue Date: Sat, 27 Apr 2019 22:28:54 +0900 Subject: Update document for any configurations - (Modify) `MRB_INT16` - (Add) `MRB_INT32` - (Modify) `MRB_INT64` - (Add) `MRB_USE_ETEXT_EDATA` - (Add) `MRB_NO_INIT_ARRAY_START - (Add) `MRB_WITHOUT_FLOAT` - (Add) `MRB_METHOD_CACHE` - (Add) `MRB_METHOD_CACHE_SIZE` - (Add) `MRB_METHOD_TABLE_INLINE - (Add) `MRB_ENABLE_ALL_SYMBOLS` --- doc/guides/mrbconf.md | 49 +++++++++++++++++++++++++++++++++++++++++++------ include/mrbconf.h | 9 +++++++-- 2 files changed, 50 insertions(+), 8 deletions(-) diff --git a/doc/guides/mrbconf.md b/doc/guides/mrbconf.md index f957f8ce2..4e3a81aa3 100644 --- a/doc/guides/mrbconf.md +++ b/doc/guides/mrbconf.md @@ -50,15 +50,21 @@ You can use mrbconfs with following ways: * When defined single precision floating point type(C type `float`) is used as `mrb_float`. * Else double precision floating point type(C type `double`) is used as `mrb_float`. +`MRB_WITHOUT_FLOAT` +* When defined removes floating point numbers from mruby. +* It makes mruby easier to handle in "Microcontroller without FPU" and "Kernel Space". + `MRB_INT16` * When defined `int16_t` will be defined as `mrb_int`. -* Conflicts with `MRB_INT64`. +* Conflicts with `MRB_INT32` and `MRB_INT64`. + +`MRB_INT32` +* When defined, or both `MRB_INT16` and `MRB_INT64` are not defined on 32-bit CPU mode, `int32_t` will be defined as `mrb_int`. +* Conflicts with `MRB_INT16` and `MRB_INT64`. `MRB_INT64` -* When defined `int64_t` will be defined as `mrb_int`. -* Conflicts with `MRB_INT16`. -* When `MRB_INT16` or `MRB_INT64` isn't defined `int`(most of the times 32-bit integer) -will be defined as `mrb_int`. +* When defined, or both `MRB_INT16` and `MRB_INT32` are not defined on 64-bit CPU mode, `int64_t` will be defined as `mrb_int`. +* Conflicts with `MRB_INT16` and `MRB_INT32`. ## Garbage collector configuration. @@ -115,7 +121,7 @@ largest value of required alignment. `MRB_NAN_BOXING` * If defined represent `mrb_value` in boxed `double`. -* Conflicts with `MRB_USE_FLOAT`. +* Conflicts with `MRB_USE_FLOAT` and `MRB_WITHOUT_FLOAT`. `MRB_WORD_BOXING` * If defined represent `mrb_value` as a word. @@ -126,6 +132,20 @@ largest value of required alignment. * Default value is `4`. * Specifies size of each segment in segment list. +## Reduce heap memory configuration. + +`MRB_USE_ETEXT_EDATA` +* If you specify the address of a read-only section when creating a symbol or string, that string will be used as it is. +* Heap memory can be saved. +* Uses `_etext` and `__init_array_start`. +* It must be `_etext < data_addr < &__init_array_start`. + +`MRB_NO_INIT_ARRAY_START` +* Ignored if `MRB_USE_ETEXT_EDATA` is not defined. +* Please try if `__init_array_start` is not available. +* Uses `_etext` and `_edata`. +* It must be `_etext < data_addr < _edata`. + ## Other configuration. `MRB_UTF8_STRING` * Adds UTF-8 encoding support to character-oriented String instance methods. @@ -144,3 +164,20 @@ largest value of required alignment. `MRB_STR_BUF_MIN_SIZE` * Default value is `128`. * Specifies initial capacity of `RString` created by `mrb_str_buf_new` function.. + +`MRB_METHOD_CACHE` +* Improve performance for method dispatch. + +`MRB_METHOD_CACHE_SIZE` +* Default value is `128`. +* Ignored if `MRB_METHOD_CACHE` is not defined. +* Need to be the power of 2. + +`MRB_METHOD_TABLE_INLINE` +* Reduce the size of method table. +* Requires LSB of function pointers to be zero. +* For example, you might need to specify `--falign-functions=n` (where `n > 1`) for GCC. + +`MRB_ENABLE_ALL_SYMBOLS` +* Make it available `Symbols.all_symbols` in `mrbgems/mruby-symbol-ext` +* Increase heap memory usage. diff --git a/include/mrbconf.h b/include/mrbconf.h index 08e69d3aa..caae08d7c 100644 --- a/include/mrbconf.h +++ b/include/mrbconf.h @@ -41,10 +41,15 @@ /* you might need to specify --falign-functions=n (where n>1) */ //#define MRB_METHOD_TABLE_INLINE -/* add -DMRB_INT16 to use 16bit integer for mrb_int; conflict with MRB_INT64 */ +/* add -DMRB_INT16 to use 16bit integer for mrb_int; conflict with MRB_INT32 and MRB_INT64 */ //#define MRB_INT16 -/* add -DMRB_INT64 to use 64bit integer for mrb_int; conflict with MRB_INT16 */ +/* add -DMRB_INT32 to use 32bit integer for mrb_int; conflict with MRB_INT16 and MRB_INT64; + Default for 32-bit CPU mode. */ +//#define MRB_INT32 + +/* add -DMRB_INT64 to use 64bit integer for mrb_int; conflict with MRB_INT16 and MRB_INT32; + Default for 64-bit CPU mode. */ //#define MRB_INT64 /* if no specific integer type is chosen */ -- cgit v1.2.3 From 828a99894179e858b4ddda4ba686413b56f986de Mon Sep 17 00:00:00 2001 From: dearblue Date: Sat, 27 Apr 2019 22:29:20 +0900 Subject: Update document for `MRB_USE_CUSTOM_RO_DATA_P` --- doc/guides/mrbconf.md | 7 +++++++ include/mrbconf.h | 5 +++++ 2 files changed, 12 insertions(+) diff --git a/doc/guides/mrbconf.md b/doc/guides/mrbconf.md index 4e3a81aa3..3c20b3388 100644 --- a/doc/guides/mrbconf.md +++ b/doc/guides/mrbconf.md @@ -146,6 +146,13 @@ largest value of required alignment. * Uses `_etext` and `_edata`. * It must be `_etext < data_addr < _edata`. +`MRB_USE_CUSTOM_RO_DATA_P` +* Takes precedence over `MRB_USE_ETEXT_EDATA`. +* Please try if both `MRB_USE_ETEXT_EDATA` and `MRB_NO_INIT_ARRAY_START` are not available. +* The `mrb_ro_data_p()` function is implemented by the user in an arbitrary file. +* The prototype declaration is `mrb_bool mrb_ro_data_p(const char *ptr)`. +* Return `TRUE` if `ptr` is in read-only section, otherwise return `FALSE`. + ## Other configuration. `MRB_UTF8_STRING` * Adds UTF-8 encoding support to character-oriented String instance methods. diff --git a/include/mrbconf.h b/include/mrbconf.h index caae08d7c..6b0b9e37e 100644 --- a/include/mrbconf.h +++ b/include/mrbconf.h @@ -93,6 +93,11 @@ effective only when MRB_USE_ETEXT_EDATA is defined */ //#define MRB_NO_INIT_ARRAY_START +/* if do not works both MRB_USE_ETEXT_EDATA and MRB_NO_INIT_ARRAY_START, + you can try mrb_ro_data_p() that you have implemented yourself in any file; + prototype is `mrb_bool mrb_ro_data_p(const char *ptr)` */ +//#define MRB_USE_CUSTOM_RO_DATA_P + /* turn off generational GC by default */ //#define MRB_GC_TURN_OFF_GENERATIONAL -- cgit v1.2.3 From 5969ed1afb0f28a2a3ce9504b4f1cb2f7c14ea57 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Sun, 28 Apr 2019 18:42:23 +0900 Subject: Commented out "Struct.new removes existing constant" test Because this test is always skipped. --- mrbgems/mruby-struct/test/struct.rb | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/mrbgems/mruby-struct/test/struct.rb b/mrbgems/mruby-struct/test/struct.rb index c298fef9f..91e8cecc6 100644 --- a/mrbgems/mruby-struct/test/struct.rb +++ b/mrbgems/mruby-struct/test/struct.rb @@ -152,14 +152,14 @@ assert("Struct#dig") do assert_equal 1, a.dig(1, 0) end -assert("Struct.new removes existing constant") do - skip "redefining Struct with same name cause warnings" - begin - assert_not_equal Struct.new("Test", :a), Struct.new("Test", :a, :b) - ensure - Struct.remove_const :Test - end -end +# TODO: suppress redefining Struct warning during test +# assert("Struct.new removes existing constant") do +# begin +# assert_not_equal Struct.new("Test", :a), Struct.new("Test", :a, :b) +# ensure +# Struct.remove_const :Test +# end +# end assert("Struct#initialize_copy requires struct to be the same type") do begin -- cgit v1.2.3 From 8cc2ad3348d00825d5daa6aed63a952ac6cec845 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Mon, 29 Apr 2019 11:09:35 +0900 Subject: Fix missing assertions in `mruby-io` test --- mrbgems/mruby-io/test/file.rb | 12 +++----- mrbgems/mruby-io/test/file_test.rb | 8 ++---- mrbgems/mruby-io/test/io.rb | 57 ++++++++++++++++++++------------------ 3 files changed, 36 insertions(+), 41 deletions(-) diff --git a/mrbgems/mruby-io/test/file.rb b/mrbgems/mruby-io/test/file.rb index ba4100492..88ced31a6 100644 --- a/mrbgems/mruby-io/test/file.rb +++ b/mrbgems/mruby-io/test/file.rb @@ -1,15 +1,13 @@ ## # File Test -assert('File TEST SETUP') do - MRubyIOTestUtil.io_test_setup -end +MRubyIOTestUtil.io_test_setup -assert('File', '15.2.21') do +assert('File.class', '15.2.21') do assert_equal Class, File.class end -assert('File', '15.2.21.2') do +assert('File.superclass', '15.2.21.2') do assert_equal IO, File.superclass end @@ -204,6 +202,4 @@ assert('File.chmod') do end end -assert('File TEST CLEANUP') do - assert_nil MRubyIOTestUtil.io_test_cleanup -end +MRubyIOTestUtil.io_test_cleanup diff --git a/mrbgems/mruby-io/test/file_test.rb b/mrbgems/mruby-io/test/file_test.rb index 04e10e0c8..72e921ce9 100644 --- a/mrbgems/mruby-io/test/file_test.rb +++ b/mrbgems/mruby-io/test/file_test.rb @@ -1,9 +1,7 @@ ## # FileTest -assert('FileTest TEST SETUP') do - MRubyIOTestUtil.io_test_setup -end +MRubyIOTestUtil.io_test_setup assert("FileTest.directory?") do dir = MRubyIOTestUtil.mkdtemp("mruby-io-test.XXXXXX") @@ -112,6 +110,4 @@ assert("FileTest.zero?") do assert_true fp2.closed? end -assert('FileTest TEST CLEANUP') do - assert_nil MRubyIOTestUtil.io_test_cleanup -end +MRubyIOTestUtil.io_test_cleanup diff --git a/mrbgems/mruby-io/test/io.rb b/mrbgems/mruby-io/test/io.rb index 2b3f9cf13..5004d0042 100644 --- a/mrbgems/mruby-io/test/io.rb +++ b/mrbgems/mruby-io/test/io.rb @@ -1,35 +1,44 @@ ## # IO Test -assert('IO TEST SETUP') do - MRubyIOTestUtil.io_test_setup - $cr, $crlf, $cmd = MRubyIOTestUtil.win? ? [1, "\r\n", "cmd /c "] : [0, "\n", ""] +MRubyIOTestUtil.io_test_setup +$cr, $crlf, $cmd = MRubyIOTestUtil.win? ? [1, "\r\n", "cmd /c "] : [0, "\n", ""] + +assert_io_open = ->(meth) do + fd = IO.sysopen($mrbtest_io_rfname) + assert_equal Fixnum, fd.class + io1 = IO.__send__(meth, fd) + begin + assert_equal IO, io1.class + assert_equal $mrbtest_io_msg, io1.read + ensure + io1.close + end + + io2 = IO.__send__(meth, IO.sysopen($mrbtest_io_rfname))do |io| + if meth == :open + assert_equal $mrbtest_io_msg, io.read + else + flunk "IO.#{meth} does not take block" + end + end + io2.close unless meth == :open end -assert('IO', '15.2.20') do +assert('IO.class', '15.2.20') do assert_equal(Class, IO.class) end -assert('IO', '15.2.20.2') do +assert('IO.superclass', '15.2.20.2') do assert_equal(Object, IO.superclass) end -assert('IO', '15.2.20.3') do +assert('IO.ancestors', '15.2.20.3') do assert_include(IO.ancestors, Enumerable) end assert('IO.open', '15.2.20.4.1') do - fd = IO.sysopen $mrbtest_io_rfname - assert_equal Fixnum, fd.class - io = IO.open fd - assert_equal IO, io.class - assert_equal $mrbtest_io_msg, io.read - io.close - - fd = IO.sysopen $mrbtest_io_rfname - IO.open(fd) do |io| - assert_equal $mrbtest_io_msg, io.read - end + assert_io_open.(:open) end assert('IO#close', '15.2.20.5.1') do @@ -215,19 +224,15 @@ assert('IO#dup for writable') do end assert('IO.for_fd') do - fd = IO.sysopen($mrbtest_io_rfname) - io = IO.for_fd(fd) - assert_equal $mrbtest_io_msg, io.read - io.close + assert_io_open.(:for_fd) end assert('IO.new') do - io = IO.new(0) - io.close + assert_io_open.(:new) end assert('IO gc check') do - 100.times { IO.new(0) } + assert_nothing_raised { 100.times { IO.new(0) } } end assert('IO.sysopen("./nonexistent")') do @@ -604,6 +609,4 @@ assert('`cmd`') do end end -assert('IO TEST CLEANUP') do - assert_nil MRubyIOTestUtil.io_test_cleanup -end +MRubyIOTestUtil.io_test_cleanup -- cgit v1.2.3 From 4bf6b8c136ecd6b4bf78e9a66c21943f3f8ab506 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Mon, 29 Apr 2019 11:34:41 +0900 Subject: Refine the default values of `flunk` The default message for the second argument should be set to the first argument because only one argument is normally specified. --- test/assert.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/assert.rb b/test/assert.rb index 121bd0a8e..a9bbc9a05 100644 --- a/test/assert.rb +++ b/test/assert.rb @@ -247,7 +247,7 @@ def pass assert_true(true) end -def flunk(msg = nil, diff = "Epic Fail!") +def flunk(msg = "Epic Fail!", diff = "") assert_true(false, msg, diff) end -- cgit v1.2.3 From 9bd17226d5cc9e36937497664886d05d527bfd19 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Tue, 30 Apr 2019 16:35:47 +0900 Subject: Refine error message output for `mruby` command - Write message to stderr instead of stdout. - Avoid duplicate message output (`SyntaxError`, `ScriptError` etc). - Refine invalid option message. - Suppress redundant usage output. - Fix some incorrect exit code. --- mrbgems/mruby-bin-mruby/bintest/mruby.rb | 51 ++++++++++++++++++++++++++--- mrbgems/mruby-bin-mruby/tools/mruby/mruby.c | 39 ++++++++-------------- 2 files changed, 60 insertions(+), 30 deletions(-) diff --git a/mrbgems/mruby-bin-mruby/bintest/mruby.rb b/mrbgems/mruby-bin-mruby/bintest/mruby.rb index e8d1510f7..1dced07f9 100644 --- a/mrbgems/mruby-bin-mruby/bintest/mruby.rb +++ b/mrbgems/mruby-bin-mruby/bintest/mruby.rb @@ -1,10 +1,16 @@ require 'tempfile' +require 'open3' + +assert_mruby = ->(exp_out_pattern, exp_err_pattern, exp_success, args) do + out, err, stat = Open3.capture3(cmd("mruby"), *args) + assert_match(exp_out_pattern, out, "standard output") + assert_match(exp_err_pattern, err, "standard error") + assert_equal(exp_success, stat.success?, "exit success?") +end assert('regression for #1564') do - o = `#{cmd('mruby')} -e #{shellquote('<<')} 2>&1` - assert_include o, "-e:1:2: syntax error" - o = `#{cmd('mruby')} -e #{shellquote('<<-')} 2>&1` - assert_include o, "-e:1:3: syntax error" + assert_mruby.("", "-e:1:2: syntax error, *", false, %w[-e <<]) + assert_mruby.("", "-e:1:3: syntax error, *", false, %w[-e <<-]) end assert('regression for #1572') do @@ -66,6 +72,11 @@ RUBY assert_equal 0, $?.exitstatus end +assert('mruby -c option') do + assert_mruby.("Syntax OK\n", "", true, ["-c", "-e", "p 1"]) + assert_mruby.("", "-e:1:7: syntax error, *", false, ["-c", "-e", "p 1; 1."]) +end + assert('mruby -d option') do o = `#{cmd('mruby')} -e #{shellquote('p $DEBUG')}` assert_equal "false\n", o @@ -73,6 +84,14 @@ assert('mruby -d option') do assert_equal "true\n", o end +assert('mruby -e option (no code specified)') do + assert_mruby.("", "* No code specified for -e\n", false, %w[-e]) +end + +assert('mruby -h option') do + assert_mruby.("Usage: *mruby*", "", true, %w[-h]) +end + assert('mruby -r option') do lib = Tempfile.new('lib.rb') lib.write < #include -#ifdef MRB_DISABLE_STDIO -static void -p(mrb_state *mrb, mrb_value obj) -{ - mrb_value val = mrb_inspect(mrb, obj); - - fwrite(RSTRING_PTR(val), RSTRING_LEN(val), 1, stdout); - putc('\n', stdout); -} -#else -#define p(mrb,obj) mrb_p(mrb,obj) -#endif - struct _args { FILE *rfp; char* cmdline; @@ -119,14 +106,17 @@ append_cmdline: } } else { - printf("%s: No code specified for -e\n", *origargv); - return EXIT_SUCCESS; + fprintf(stderr, "%s: No code specified for -e\n", *origargv); + return EXIT_FAILURE; } break; + case 'h': + usage(*origargv); + exit(EXIT_SUCCESS); case 'r': if (!item[0]) { if (argc <= 1) { - printf("%s: No library specified for -r\n", *origargv); + fprintf(stderr, "%s: No library specified for -r\n", *origargv); return EXIT_FAILURE; } argc--; argv++; @@ -158,6 +148,7 @@ append_cmdline: exit(EXIT_SUCCESS); } default: + fprintf(stderr, "%s: invalid option %s (-h will show valid options)\n", *origargv, *argv); return EXIT_FAILURE; } } @@ -167,7 +158,7 @@ append_cmdline: else { args->rfp = fopen(argv[0], args->mrbfile ? "rb" : "r"); if (args->rfp == NULL) { - printf("%s: Cannot open program file. (%s)\n", *origargv, *argv); + fprintf(stderr, "%s: Cannot open program file. (%s)\n", *origargv, *argv); return EXIT_FAILURE; } args->fname = TRUE; @@ -212,14 +203,13 @@ main(int argc, char **argv) mrb_sym zero_sym; if (mrb == NULL) { - fputs("Invalid mrb_state, exiting mruby\n", stderr); + fprintf(stderr, "%s: Invalid mrb_state, exiting mruby\n", *argv); return EXIT_FAILURE; } n = parse_args(mrb, argc, argv, &args); if (n == EXIT_FAILURE || (args.cmdline == NULL && args.rfp == NULL)) { cleanup(mrb, &args); - usage(argv[0]); return n; } else { @@ -258,7 +248,7 @@ main(int argc, char **argv) for (i = 0; i < args.libc; i++) { FILE *lfp = fopen(args.libv[i], args.mrbfile ? "rb" : "r"); if (lfp == NULL) { - printf("Cannot open library file: %s\n", args.libv[i]); + fprintf(stderr, "%s: Cannot open library file: %s\n", *argv, args.libv[i]); mrbc_context_free(mrb, c); cleanup(mrb, &args); return EXIT_FAILURE; @@ -289,13 +279,10 @@ main(int argc, char **argv) mrb_gc_arena_restore(mrb, ai); mrbc_context_free(mrb, c); if (mrb->exc) { - if (mrb_undef_p(v)) { - mrb_p(mrb, mrb_obj_value(mrb->exc)); - } - else { + if (!mrb_undef_p(v)) { mrb_print_error(mrb); } - n = -1; + n = EXIT_FAILURE; } else if (args.check_syntax) { printf("Syntax OK\n"); @@ -303,5 +290,5 @@ main(int argc, char **argv) } cleanup(mrb, &args); - return n == 0 ? EXIT_SUCCESS : EXIT_FAILURE; + return n; } -- cgit v1.2.3 From 1a8f6e70b5e91dcbdf92a3b671e00cd7410c3cc1 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Wed, 1 May 2019 15:04:08 +0900 Subject: Remove unneeded `argc` check in `mrb_str_aref_m()` --- src/string.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/string.c b/src/string.c index 89ab59d4b..90e609992 100644 --- a/src/string.c +++ b/src/string.c @@ -1107,9 +1107,6 @@ mrb_str_aref_m(mrb_state *mrb, mrb_value str) mrb_get_args(mrb, "ii", &n1, &n2); return str_substr(mrb, str, n1, n2); } - if (argc != 1) { - mrb_raisef(mrb, E_ARGUMENT_ERROR, "wrong number of arguments (%S for 1)", mrb_fixnum_value(argc)); - } return mrb_str_aref(mrb, str, a1); } -- cgit v1.2.3 From 2a94bf8fbd9afb49e1c2b83126f5952b2864d781 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Wed, 1 May 2019 16:49:56 +0900 Subject: Small fix in `mruby-bin-mruby` - Modify some error messages for consistency. - Add test for codegen error. - Use regular expression for error message matching in test. --- mrbgems/mruby-bin-mruby/bintest/mruby.rb | 33 +++++++++++++++++------------ mrbgems/mruby-bin-mruby/tools/mruby/mruby.c | 4 ++-- 2 files changed, 21 insertions(+), 16 deletions(-) diff --git a/mrbgems/mruby-bin-mruby/bintest/mruby.rb b/mrbgems/mruby-bin-mruby/bintest/mruby.rb index 1dced07f9..d1262254b 100644 --- a/mrbgems/mruby-bin-mruby/bintest/mruby.rb +++ b/mrbgems/mruby-bin-mruby/bintest/mruby.rb @@ -1,16 +1,16 @@ require 'tempfile' require 'open3' -assert_mruby = ->(exp_out_pattern, exp_err_pattern, exp_success, args) do +assert_mruby = ->(exp_out, exp_err, exp_success, args) do out, err, stat = Open3.capture3(cmd("mruby"), *args) - assert_match(exp_out_pattern, out, "standard output") - assert_match(exp_err_pattern, err, "standard error") + assert_operator(exp_out, :===, out, "standard output") + assert_operator(exp_err, :===, err, "standard error") assert_equal(exp_success, stat.success?, "exit success?") end assert('regression for #1564') do - assert_mruby.("", "-e:1:2: syntax error, *", false, %w[-e <<]) - assert_mruby.("", "-e:1:3: syntax error, *", false, %w[-e <<-]) + assert_mruby.("", /\A-e:1:2: syntax error, .*\n\z/, false, %w[-e <<]) + assert_mruby.("", /\A-e:1:3: syntax error, .*\n\z/, false, %w[-e <<-]) end assert('regression for #1572') do @@ -74,7 +74,7 @@ end assert('mruby -c option') do assert_mruby.("Syntax OK\n", "", true, ["-c", "-e", "p 1"]) - assert_mruby.("", "-e:1:7: syntax error, *", false, ["-c", "-e", "p 1; 1."]) + assert_mruby.("", /\A-e:1:7: syntax error, .*\n\z/, false, ["-c", "-e", "p 1; 1."]) end assert('mruby -d option') do @@ -85,11 +85,11 @@ assert('mruby -d option') do end assert('mruby -e option (no code specified)') do - assert_mruby.("", "* No code specified for -e\n", false, %w[-e]) + assert_mruby.("", /\A.*: No code specified for -e\n\z/, false, %w[-e]) end assert('mruby -h option') do - assert_mruby.("Usage: *mruby*", "", true, %w[-h]) + assert_mruby.(/\AUsage: #{Regexp.escape cmd("mruby")} .*/m, "", true, %w[-h]) end assert('mruby -r option') do @@ -116,25 +116,30 @@ EOS end assert('mruby -r option (no library specified)') do - assert_mruby.("", "*: No library specified for -r\n", false, %w[-r]) + assert_mruby.("", /\A.*: No library specified for -r\n\z/, false, %w[-r]) end assert('mruby -r option (file not found)') do - assert_mruby.("", "*: Cannot open library file: *", false, %w[-r _no_exists_]) + assert_mruby.("", /\A.*: Cannot open library file: .*\n\z/, false, %w[-r _no_exists_]) end assert('mruby invalid short option') do - assert_mruby.("", "*: invalid option -1 *", false, %w[-1]) + assert_mruby.("", /\A.*: invalid option -1 .*\n\z/, false, %w[-1]) end assert('mruby invalid long option') do - assert_mruby.("", "*: invalid option --longopt *", false, %w[--longopt]) + assert_mruby.("", /\A.*: invalid option --longopt .*\n\z/, false, %w[--longopt]) end assert('unhandled exception') do - assert_mruby.("", "* EXCEPTION!*", false, %w[-e raise("EXCEPTION!")]) + assert_mruby.("", /\bEXCEPTION\b.*\n\z/, false, %w[-e raise("EXCEPTION")]) end assert('program file not found') do - assert_mruby.("", "*: Cannot open program file*", false, %w[_no_exists_]) + assert_mruby.("", /\A.*: Cannot open program file: .*\n\z/, false, %w[_no_exists_]) +end + +assert('codegen error') do + code = "def f(#{(1..100).map{|n| "a#{n}"} * ","}); end" + assert_mruby.("", /\Acodegen error:.*\n\z/, false, ["-e", code]) end diff --git a/mrbgems/mruby-bin-mruby/tools/mruby/mruby.c b/mrbgems/mruby-bin-mruby/tools/mruby/mruby.c index c96365c9f..29ab4c17c 100644 --- a/mrbgems/mruby-bin-mruby/tools/mruby/mruby.c +++ b/mrbgems/mruby-bin-mruby/tools/mruby/mruby.c @@ -158,7 +158,7 @@ append_cmdline: else { args->rfp = fopen(argv[0], args->mrbfile ? "rb" : "r"); if (args->rfp == NULL) { - fprintf(stderr, "%s: Cannot open program file. (%s)\n", *origargv, *argv); + fprintf(stderr, "%s: Cannot open program file: %s\n", *origargv, *argv); return EXIT_FAILURE; } args->fname = TRUE; @@ -285,7 +285,7 @@ main(int argc, char **argv) n = EXIT_FAILURE; } else if (args.check_syntax) { - printf("Syntax OK\n"); + puts("Syntax OK"); } } cleanup(mrb, &args); -- cgit v1.2.3 From 95a92d35c89ec9c39c97c5f948255389a129029e Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Thu, 2 May 2019 20:45:31 +0900 Subject: Unify overflow error class for conversion to integer to `RangeError` --- src/numeric.c | 2 +- src/string.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/numeric.c b/src/numeric.c index 8205e41f6..101b338de 100644 --- a/src/numeric.c +++ b/src/numeric.c @@ -1230,7 +1230,7 @@ mrb_flo_to_fixnum(mrb_state *mrb, mrb_value x) z = (mrb_int)d; } else { - mrb_raisef(mrb, E_ARGUMENT_ERROR, "number (%S) too big for integer", x); + mrb_raisef(mrb, E_RANGE_ERROR, "number (%S) too big for integer", x); } } return mrb_fixnum_value(z); diff --git a/src/string.c b/src/string.c index 89ab59d4b..955ad57ce 100644 --- a/src/string.c +++ b/src/string.c @@ -2115,7 +2115,7 @@ mrb_str_len_to_inum(mrb_state *mrb, const char *str, mrb_int len, mrb_int base, else #endif { - mrb_raisef(mrb, E_ARGUMENT_ERROR, "string (%S) too big for integer", + mrb_raisef(mrb, E_RANGE_ERROR, "string (%S) too big for integer", mrb_str_new(mrb, str, pend-str)); } } -- cgit v1.2.3 From f83112cea21ba37ad9e3a1b27a0066e4dd6c6ae4 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Wed, 24 Apr 2019 12:43:19 +0900 Subject: Fixed include specifier format for `mruby/common.h`. --- include/mruby.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/mruby.h b/include/mruby.h index dcd64b2d8..20cdc1b83 100644 --- a/include/mruby.h +++ b/include/mruby.h @@ -84,7 +84,7 @@ #endif #endif -#include "mruby/common.h" +#include #include #include #include -- cgit v1.2.3 From 35319bed01d58c785f73ce03e67d4e58be30f4b5 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Thu, 2 May 2019 23:03:38 +0900 Subject: Use a normal method instead of a lambda in bintest/mruby; ref #4416 --- mrbgems/mruby-bin-mruby/bintest/mruby.rb | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/mrbgems/mruby-bin-mruby/bintest/mruby.rb b/mrbgems/mruby-bin-mruby/bintest/mruby.rb index d1262254b..09350ff49 100644 --- a/mrbgems/mruby-bin-mruby/bintest/mruby.rb +++ b/mrbgems/mruby-bin-mruby/bintest/mruby.rb @@ -1,7 +1,7 @@ require 'tempfile' require 'open3' -assert_mruby = ->(exp_out, exp_err, exp_success, args) do +def assert_mruby(exp_out, exp_err, exp_success, args) out, err, stat = Open3.capture3(cmd("mruby"), *args) assert_operator(exp_out, :===, out, "standard output") assert_operator(exp_err, :===, err, "standard error") @@ -9,8 +9,8 @@ assert_mruby = ->(exp_out, exp_err, exp_success, args) do end assert('regression for #1564') do - assert_mruby.("", /\A-e:1:2: syntax error, .*\n\z/, false, %w[-e <<]) - assert_mruby.("", /\A-e:1:3: syntax error, .*\n\z/, false, %w[-e <<-]) + assert_mruby("", /\A-e:1:2: syntax error, .*\n\z/, false, %w[-e <<]) + assert_mruby("", /\A-e:1:3: syntax error, .*\n\z/, false, %w[-e <<-]) end assert('regression for #1572') do @@ -73,8 +73,8 @@ RUBY end assert('mruby -c option') do - assert_mruby.("Syntax OK\n", "", true, ["-c", "-e", "p 1"]) - assert_mruby.("", /\A-e:1:7: syntax error, .*\n\z/, false, ["-c", "-e", "p 1; 1."]) + assert_mruby("Syntax OK\n", "", true, ["-c", "-e", "p 1"]) + assert_mruby("", /\A-e:1:7: syntax error, .*\n\z/, false, ["-c", "-e", "p 1; 1."]) end assert('mruby -d option') do @@ -85,11 +85,11 @@ assert('mruby -d option') do end assert('mruby -e option (no code specified)') do - assert_mruby.("", /\A.*: No code specified for -e\n\z/, false, %w[-e]) + assert_mruby("", /\A.*: No code specified for -e\n\z/, false, %w[-e]) end assert('mruby -h option') do - assert_mruby.(/\AUsage: #{Regexp.escape cmd("mruby")} .*/m, "", true, %w[-h]) + assert_mruby(/\AUsage: #{Regexp.escape cmd("mruby")} .*/m, "", true, %w[-h]) end assert('mruby -r option') do @@ -116,30 +116,30 @@ EOS end assert('mruby -r option (no library specified)') do - assert_mruby.("", /\A.*: No library specified for -r\n\z/, false, %w[-r]) + assert_mruby("", /\A.*: No library specified for -r\n\z/, false, %w[-r]) end assert('mruby -r option (file not found)') do - assert_mruby.("", /\A.*: Cannot open library file: .*\n\z/, false, %w[-r _no_exists_]) + assert_mruby("", /\A.*: Cannot open library file: .*\n\z/, false, %w[-r _no_exists_]) end assert('mruby invalid short option') do - assert_mruby.("", /\A.*: invalid option -1 .*\n\z/, false, %w[-1]) + assert_mruby("", /\A.*: invalid option -1 .*\n\z/, false, %w[-1]) end assert('mruby invalid long option') do - assert_mruby.("", /\A.*: invalid option --longopt .*\n\z/, false, %w[--longopt]) + assert_mruby("", /\A.*: invalid option --longopt .*\n\z/, false, %w[--longopt]) end assert('unhandled exception') do - assert_mruby.("", /\bEXCEPTION\b.*\n\z/, false, %w[-e raise("EXCEPTION")]) + assert_mruby("", /\bEXCEPTION\b.*\n\z/, false, %w[-e raise("EXCEPTION")]) end assert('program file not found') do - assert_mruby.("", /\A.*: Cannot open program file: .*\n\z/, false, %w[_no_exists_]) + assert_mruby("", /\A.*: Cannot open program file: .*\n\z/, false, %w[_no_exists_]) end assert('codegen error') do code = "def f(#{(1..100).map{|n| "a#{n}"} * ","}); end" - assert_mruby.("", /\Acodegen error:.*\n\z/, false, ["-e", code]) + assert_mruby("", /\Acodegen error:.*\n\z/, false, ["-e", code]) end -- cgit v1.2.3 From f5d5caaf82f68f5146594050d833cc1ceda6c72b Mon Sep 17 00:00:00 2001 From: dearblue Date: Fri, 3 May 2019 11:36:31 +0900 Subject: Clean duplicate code Removed duplicates in the code entered for "Concatenate string literal". --- mrbgems/mruby-compiler/core/parse.y | 55 ++++++++++++++++++------------------- 1 file changed, 27 insertions(+), 28 deletions(-) diff --git a/mrbgems/mruby-compiler/core/parse.y b/mrbgems/mruby-compiler/core/parse.y index 7838b6dfb..b7d47118f 100644 --- a/mrbgems/mruby-compiler/core/parse.y +++ b/mrbgems/mruby-compiler/core/parse.y @@ -913,40 +913,39 @@ concat_string(parser_state *p, node *a, node *b) } } } - else if (string_node_p(b)) { - /* a == NODE_DSTR && b == NODE_STR */ - - node *c; + else { + node *c; /* last node of a */ for (c = a; c->cdr != NULL; c = c->cdr) ; - if (string_node_p(c->car)) { - /* a->[..., NODE_STR] && b == NODE_STR */ - composite_string_node(p, c->car->cdr, b->cdr); - cons_free(b); - return a; - } - push(a, b); - return a; - } - else { - /* a == NODE_DSTR && b == NODE_DSTR */ + if (string_node_p(b)) { + /* a == NODE_DSTR && b == NODE_STR */ + if (string_node_p(c->car)) { + /* a->[..., NODE_STR] && b == NODE_STR */ + composite_string_node(p, c->car->cdr, b->cdr); + cons_free(b); + return a; + } - node *c, *d; - for (c = a; c->cdr != NULL; c = c->cdr) ; - if (string_node_p(c->car) && string_node_p(b->cdr->car)) { - /* a->[..., NODE_STR] && b->[NODE_STR, ...] */ - d = b->cdr; - cons_free(b); - composite_string_node(p, c->car->cdr, d->car->cdr); - cons_free(d->car); - c->cdr = d->cdr; - cons_free(d); + push(a, b); return a; } else { - c->cdr = b->cdr; - cons_free(b); - return a; + /* a == NODE_DSTR && b == NODE_DSTR */ + if (string_node_p(c->car) && string_node_p(b->cdr->car)) { + /* a->[..., NODE_STR] && b->[NODE_STR, ...] */ + node *d = b->cdr; + cons_free(b); + composite_string_node(p, c->car->cdr, d->car->cdr); + cons_free(d->car); + c->cdr = d->cdr; + cons_free(d); + return a; + } + else { + c->cdr = b->cdr; + cons_free(b); + return a; + } } } -- cgit v1.2.3 From e86e360b360029a432af42dbb414b7df21eb0c2b Mon Sep 17 00:00:00 2001 From: dearblue Date: Fri, 3 May 2019 11:42:14 +0900 Subject: Fix `FLAG_SRC_STATIC` always set in `mrb_read_irep()` with `MRB_USE_CUSTOM_RO_DATA_P` --- src/load.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/load.c b/src/load.c index ab0346750..70f18da31 100644 --- a/src/load.c +++ b/src/load.c @@ -608,7 +608,7 @@ read_irep(mrb_state *mrb, const uint8_t *bin, uint8_t flags) mrb_irep* mrb_read_irep(mrb_state *mrb, const uint8_t *bin) { -#ifdef MRB_USE_ETEXT_EDATA +#if defined(MRB_USE_ETEXT_EDATA) || defined(MRB_USE_CUSTOM_RO_DATA_P) uint8_t flags = mrb_ro_data_p((char*)bin) ? FLAG_SRC_STATIC : FLAG_SRC_MALLOC; #else uint8_t flags = FLAG_SRC_STATIC; -- cgit v1.2.3 From 0692f7916cc9865e276a58812186cac7f02dc042 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Fri, 3 May 2019 13:39:19 +0900 Subject: Simplify conversion process for `i` in `mrb_get_args()` --- src/class.c | 24 +----------------------- test/t/string.rb | 11 +++++++---- 2 files changed, 8 insertions(+), 27 deletions(-) diff --git a/src/class.c b/src/class.c index 254f5b005..2cabc820e 100644 --- a/src/class.c +++ b/src/class.c @@ -838,29 +838,7 @@ mrb_get_args(mrb_state *mrb, const char *format, ...) p = va_arg(ap, mrb_int*); if (i < argc) { - switch (mrb_type(ARGV[arg_i])) { - case MRB_TT_FIXNUM: - *p = mrb_fixnum(ARGV[arg_i]); - break; -#ifndef MRB_WITHOUT_FLOAT - case MRB_TT_FLOAT: - { - mrb_float f = mrb_float(ARGV[arg_i]); - - if (!FIXABLE_FLOAT(f)) { - mrb_raise(mrb, E_RANGE_ERROR, "float too big for int"); - } - *p = (mrb_int)f; - } - break; -#endif - case MRB_TT_STRING: - mrb_raise(mrb, E_TYPE_ERROR, "no implicit conversion of String into Integer"); - break; - default: - *p = mrb_fixnum(mrb_Integer(mrb, ARGV[arg_i])); - break; - } + *p = mrb_fixnum(mrb_to_int(mrb, ARGV[arg_i])); arg_i++; i++; } diff --git a/test/t/string.rb b/test/t/string.rb index e563db55a..e5b001366 100644 --- a/test/t/string.rb +++ b/test/t/string.rb @@ -37,11 +37,14 @@ end assert('String#*', '15.2.10.5.5') do assert_equal 'aaaaa', 'a' * 5 assert_equal '', 'a' * 0 - assert_raise(ArgumentError) do - 'a' * -1 - end + assert_equal 'aa', 'a' * 2.1 + assert_raise(ArgumentError) { 'a' * -1 } + assert_raise(RangeError) { '' * 1e30 } + assert_raise(RangeError) { '' * Float::INFINITY } + assert_raise(RangeError) { '' * Float::NAN } + assert_raise(TypeError) { 'a' * '1' } + assert_raise(TypeError) { 'a' * nil } end - assert('String#[]', '15.2.10.5.6') do # length of args is 1 a = 'abc'[0] -- cgit v1.2.3 From a5bda13fb76ba50c3742b24b854fb2e86c50b31d Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Sat, 4 May 2019 16:38:07 +0900 Subject: Check whether object is immediate in `mrb_gc_(register|unregister)` --- src/gc.c | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/src/gc.c b/src/gc.c index 27f3716ec..5e7440d50 100644 --- a/src/gc.c +++ b/src/gc.c @@ -466,9 +466,12 @@ mrb_gc_protect(mrb_state *mrb, mrb_value obj) MRB_API void mrb_gc_register(mrb_state *mrb, mrb_value obj) { - mrb_sym root = mrb_intern_lit(mrb, GC_ROOT_NAME); - mrb_value table = mrb_gv_get(mrb, root); + mrb_sym root; + mrb_value table; + if (mrb_immediate_p(obj)) return; + root = mrb_intern_lit(mrb, GC_ROOT_NAME); + table = mrb_gv_get(mrb, root); if (mrb_nil_p(table) || mrb_type(table) != MRB_TT_ARRAY) { table = mrb_ary_new(mrb); mrb_gv_set(mrb, root, table); @@ -480,11 +483,14 @@ mrb_gc_register(mrb_state *mrb, mrb_value obj) MRB_API void mrb_gc_unregister(mrb_state *mrb, mrb_value obj) { - mrb_sym root = mrb_intern_lit(mrb, GC_ROOT_NAME); - mrb_value table = mrb_gv_get(mrb, root); + mrb_sym root; + mrb_value table; struct RArray *a; mrb_int i; + if (mrb_immediate_p(obj)) return; + root = mrb_intern_lit(mrb, GC_ROOT_NAME); + table = mrb_gv_get(mrb, root); if (mrb_nil_p(table)) return; if (mrb_type(table) != MRB_TT_ARRAY) { mrb_gv_set(mrb, root, mrb_nil_value()); -- cgit v1.2.3 From 0ccb058b90e5b3f50c185f8e642cd358a6edca87 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Sun, 5 May 2019 20:31:12 +0900 Subject: Use `mrb_fixnum_to_str()` instead of `Fixnum#to_s` --- mrbgems/mruby-socket/src/socket.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/mrbgems/mruby-socket/src/socket.c b/mrbgems/mruby-socket/src/socket.c index dff176778..2a8ae1b2c 100644 --- a/mrbgems/mruby-socket/src/socket.c +++ b/mrbgems/mruby-socket/src/socket.c @@ -38,6 +38,7 @@ #include "mruby/array.h" #include "mruby/class.h" #include "mruby/data.h" +#include "mruby/numeric.h" #include "mruby/string.h" #include "mruby/variable.h" #include "error.h" @@ -140,7 +141,7 @@ mrb_addrinfo_getaddrinfo(mrb_state *mrb, mrb_value klass) if (mrb_string_p(service)) { servname = mrb_str_to_cstr(mrb, service); } else if (mrb_fixnum_p(service)) { - servname = mrb_str_to_cstr(mrb, mrb_funcall(mrb, service, "to_s", 0)); + servname = RSTRING_PTR(mrb_fixnum_to_str(mrb, service, 10)); } else if (mrb_nil_p(service)) { servname = NULL; } else { -- cgit v1.2.3 From e2604c1550562b6fa507570e817cadf9981e1c82 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Mon, 6 May 2019 23:16:03 +0900 Subject: Avoid using `mrb_str_to_cstr` if possible Because it always allocate new string. Replace with the followings: - Use `RSRING_PTR` if string is guaranteed to be null-terminated. - Use `mrb_string_value_cstr` or `mrb_get_args("z")` if return value isn't modified. --- mrbgems/mruby-io/src/file.c | 21 ++++++++++----------- mrbgems/mruby-io/src/file_test.c | 2 +- mrbgems/mruby-io/test/mruby_io_test.c | 6 ++---- mrbgems/mruby-socket/src/socket.c | 4 ++-- 4 files changed, 15 insertions(+), 18 deletions(-) diff --git a/mrbgems/mruby-io/src/file.c b/mrbgems/mruby-io/src/file.c index c00663481..b17b95e24 100644 --- a/mrbgems/mruby-io/src/file.c +++ b/mrbgems/mruby-io/src/file.c @@ -146,7 +146,7 @@ mrb_file_s_rename(mrb_state *mrb, mrb_value obj) #endif mrb_locale_free(src); mrb_locale_free(dst); - mrb_sys_fail(mrb, mrb_str_to_cstr(mrb, mrb_format(mrb, "(%S, %S)", from, to))); + mrb_sys_fail(mrb, RSTRING_PTR(mrb_format(mrb, "(%S, %S)", from, to))); } mrb_locale_free(src); mrb_locale_free(dst); @@ -159,12 +159,12 @@ mrb_file_dirname(mrb_state *mrb, mrb_value klass) #if defined(_WIN32) || defined(_WIN64) char dname[_MAX_DIR], vname[_MAX_DRIVE]; char buffer[_MAX_DRIVE + _MAX_DIR]; + const char *utf8_path; char *path; size_t ridx; - mrb_value s; - mrb_get_args(mrb, "S", &s); - path = mrb_locale_from_utf8(mrb_str_to_cstr(mrb, s), -1); - _splitpath((const char*)path, vname, dname, NULL, NULL); + mrb_get_args(mrb, "z", &utf8_path); + path = mrb_locale_from_utf8(utf8_path, -1); + _splitpath(path, vname, dname, NULL, NULL); snprintf(buffer, _MAX_DRIVE + _MAX_DIR, "%s%s", vname, dname); mrb_locale_free(path); ridx = strlen(buffer); @@ -248,7 +248,7 @@ mrb_file_realpath(mrb_state *mrb, mrb_value klass) s = mrb_str_append(mrb, s, pathname); pathname = s; } - cpath = mrb_locale_from_utf8(mrb_str_to_cstr(mrb, pathname), -1); + cpath = mrb_locale_from_utf8(mrb_string_value_cstr(mrb, &pathname), -1); result = mrb_str_buf_new(mrb, PATH_MAX); if (realpath(cpath, RSTRING_PTR(result)) == NULL) { mrb_locale_free(cpath); @@ -300,7 +300,7 @@ mrb_file__gethome(mrb_state *mrb, mrb_value klass) mrb_raise(mrb, E_ARGUMENT_ERROR, "non-absolute home"); } } else { - const char *cuser = mrb_str_to_cstr(mrb, username); + const char *cuser = mrb_string_value_cstr(mrb, &username); struct passwd *pwd = getpwnam(cuser); if (pwd == NULL) { return mrb_nil_value(); @@ -393,9 +393,8 @@ mrb_file_s_symlink(mrb_state *mrb, mrb_value klass) int ai = mrb_gc_arena_save(mrb); mrb_get_args(mrb, "SS", &from, &to); - src = mrb_locale_from_utf8(mrb_str_to_cstr(mrb, from), -1); - dst = mrb_locale_from_utf8(mrb_str_to_cstr(mrb, to), -1); - + src = mrb_locale_from_utf8(mrb_string_value_cstr(mrb, &from), -1); + dst = mrb_locale_from_utf8(mrb_string_value_cstr(mrb, &to), -1); if (symlink(src, dst) == -1) { mrb_locale_free(src); mrb_locale_free(dst); @@ -417,7 +416,7 @@ mrb_file_s_chmod(mrb_state *mrb, mrb_value klass) { mrb_get_args(mrb, "i*", &mode, &filenames, &argc); for (i = 0; i < argc; i++) { - const char *utf8_path = mrb_str_to_cstr(mrb, filenames[i]); + const char *utf8_path = mrb_string_value_cstr(mrb, &filenames[i]); char *path = mrb_locale_from_utf8(utf8_path, -1); if (CHMOD(path, mode) == -1) { mrb_locale_free(path); diff --git a/mrbgems/mruby-io/src/file_test.c b/mrbgems/mruby-io/src/file_test.c index e429b06b3..7d36f79b3 100644 --- a/mrbgems/mruby-io/src/file_test.c +++ b/mrbgems/mruby-io/src/file_test.c @@ -63,7 +63,7 @@ mrb_stat0(mrb_state *mrb, mrb_value obj, struct stat *st, int do_lstat) tmp = mrb_funcall(mrb, obj, "is_a?", 1, str_klass); if (mrb_test(tmp)) { - char *path = mrb_locale_from_utf8(mrb_str_to_cstr(mrb, obj), -1); + char *path = mrb_locale_from_utf8(mrb_string_value_cstr(mrb, &obj), -1); int ret; if (do_lstat) { ret = LSTAT(path, st); diff --git a/mrbgems/mruby-io/test/mruby_io_test.c b/mrbgems/mruby-io/test/mruby_io_test.c index 71239a827..3312d6c7e 100644 --- a/mrbgems/mruby-io/test/mruby_io_test.c +++ b/mrbgems/mruby-io/test/mruby_io_test.c @@ -215,11 +215,9 @@ mrb_io_test_mkdtemp(mrb_state *mrb, mrb_value klass) static mrb_value mrb_io_test_rmdir(mrb_state *mrb, mrb_value klass) { - mrb_value str; - char *cp; + const char *cp; - mrb_get_args(mrb, "S", &str); - cp = mrb_str_to_cstr(mrb, str); + mrb_get_args(mrb, "z", &cp); if (rmdir(cp) == -1) { mrb_sys_fail(mrb, "rmdir"); } diff --git a/mrbgems/mruby-socket/src/socket.c b/mrbgems/mruby-socket/src/socket.c index 2a8ae1b2c..8515a6057 100644 --- a/mrbgems/mruby-socket/src/socket.c +++ b/mrbgems/mruby-socket/src/socket.c @@ -131,7 +131,7 @@ mrb_addrinfo_getaddrinfo(mrb_state *mrb, mrb_value klass) mrb_get_args(mrb, "oo|oooi", &nodename, &service, &family, &socktype, &protocol, &flags); if (mrb_string_p(nodename)) { - hostname = mrb_str_to_cstr(mrb, nodename); + hostname = mrb_string_value_cstr(mrb, &nodename); } else if (mrb_nil_p(nodename)) { hostname = NULL; } else { @@ -139,7 +139,7 @@ mrb_addrinfo_getaddrinfo(mrb_state *mrb, mrb_value klass) } if (mrb_string_p(service)) { - servname = mrb_str_to_cstr(mrb, service); + servname = mrb_string_value_cstr(mrb, &service); } else if (mrb_fixnum_p(service)) { servname = RSTRING_PTR(mrb_fixnum_to_str(mrb, service, 10)); } else if (mrb_nil_p(service)) { -- cgit v1.2.3 From 35943e7beb0e4fd22f2096b56817e0cf22b8cf42 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Tue, 7 May 2019 23:01:13 +0900 Subject: Refactor `mrb_str_to_cstr` and `mrb_string_value_cstr` - Extract null byte check to function. - Avoid string allocation if null byte is included. - Use `str_new` instead of `mrb_str_dup` + `mrb_str_modify` --- mrbgems/mruby-io/test/file.rb | 3 +++ src/string.c | 42 ++++++++++++++++++++++++++---------------- 2 files changed, 29 insertions(+), 16 deletions(-) diff --git a/mrbgems/mruby-io/test/file.rb b/mrbgems/mruby-io/test/file.rb index 88ced31a6..1535ebb44 100644 --- a/mrbgems/mruby-io/test/file.rb +++ b/mrbgems/mruby-io/test/file.rb @@ -33,6 +33,7 @@ assert('File.basename') do assert_equal 'a', File.basename('/a/') assert_equal 'b', File.basename('/a/b') assert_equal 'b', File.basename('../a/b') + assert_raise(ArgumentError) { File.basename("/a/b\0") } end assert('File.dirname') do @@ -106,6 +107,8 @@ assert('File.realpath') do MRubyIOTestUtil.rmdir dir end end + + assert_raise(ArgumentError) { File.realpath("TO\0DO") } end assert("File.readlink") do diff --git a/src/string.c b/src/string.c index f043bfd5a..7fc405a2b 100644 --- a/src/string.c +++ b/src/string.c @@ -194,6 +194,15 @@ str_decref(mrb_state *mrb, mrb_shared_string *shared) } } +static void +check_null_byte(mrb_state *mrb, mrb_value str) +{ + mrb_to_str(mrb, str); + if (memchr(RSTRING_PTR(str), '\0', RSTRING_LEN(str))) { + mrb_raise(mrb, E_ARGUMENT_ERROR, "string contains null byte"); + } +} + void mrb_gc_free_str(mrb_state *mrb, struct RString *str) { @@ -723,14 +732,8 @@ mrb_str_to_cstr(mrb_state *mrb, mrb_value str0) { struct RString *s; - if (!mrb_string_p(str0)) { - mrb_raise(mrb, E_TYPE_ERROR, "expected String"); - } - + check_null_byte(mrb, str0); s = str_new(mrb, RSTRING_PTR(str0), RSTRING_LEN(str0)); - if ((strlen(RSTR_PTR(s)) ^ RSTR_LEN(s)) != 0) { - mrb_raise(mrb, E_ARGUMENT_ERROR, "string contains null byte"); - } return RSTR_PTR(s); } @@ -2144,20 +2147,27 @@ mrb_cstr_to_inum(mrb_state *mrb, const char *str, mrb_int base, mrb_bool badchec MRB_API const char* mrb_string_value_cstr(mrb_state *mrb, mrb_value *ptr) { - mrb_value str = mrb_to_str(mrb, *ptr); - struct RString *ps = mrb_str_ptr(str); - mrb_int len = mrb_str_strlen(mrb, ps); - char *p = RSTR_PTR(ps); + struct RString *ps; + const char *p; + mrb_int len; - if (!p || p[len] != '\0') { + check_null_byte(mrb, *ptr); + ps = mrb_str_ptr(*ptr); + p = RSTR_PTR(ps); + len = RSTR_LEN(ps); + if (p[len] == '\0') { + return p; + } + else { if (MRB_FROZEN_P(ps)) { - *ptr = str = mrb_str_dup(mrb, str); - ps = mrb_str_ptr(str); + ps = str_new(mrb, p, len); + *ptr = mrb_obj_value(ps); + } + else { + mrb_str_modify(mrb, ps); } - mrb_str_modify(mrb, ps); return RSTR_PTR(ps); } - return p; } MRB_API mrb_value -- cgit v1.2.3 From 1975dedb214b9d181630c337374702a1b4725288 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Wed, 8 May 2019 20:35:03 +0900 Subject: Use `mrb_string_value_cstr` in `mrb_str_to_dbl` --- mrbgems/mruby-kernel-ext/test/kernel.rb | 2 ++ src/string.c | 17 +---------------- 2 files changed, 3 insertions(+), 16 deletions(-) diff --git a/mrbgems/mruby-kernel-ext/test/kernel.rb b/mrbgems/mruby-kernel-ext/test/kernel.rb index 28f089007..ad9177165 100644 --- a/mrbgems/mruby-kernel-ext/test/kernel.rb +++ b/mrbgems/mruby-kernel-ext/test/kernel.rb @@ -65,6 +65,8 @@ assert('Kernel#Float') do assert_equal(123.456, Float(123.456)) assert_equal(123.456, Float("123.456")) assert_raise(TypeError) { Float(nil) } + assert_raise(ArgumentError) { Float("1.5a") } + assert_raise(ArgumentError) { Float("1.5\0") } end assert('Kernel#String') do diff --git a/src/string.c b/src/string.c index 7fc405a2b..578e3bdcc 100644 --- a/src/string.c +++ b/src/string.c @@ -2281,22 +2281,7 @@ bad: MRB_API double mrb_str_to_dbl(mrb_state *mrb, mrb_value str, mrb_bool badcheck) { - char *s; - mrb_int len; - - mrb_to_str(mrb, str); - s = RSTRING_PTR(str); - len = RSTRING_LEN(str); - if (s) { - if (badcheck && memchr(s, '\0', len)) { - mrb_raise(mrb, E_ARGUMENT_ERROR, "string for Float contains null byte"); - } - if (s[len]) { /* no sentinel somehow */ - struct RString *temp_str = str_new(mrb, s, len); - s = RSTR_PTR(temp_str); - } - } - return mrb_cstr_to_dbl(mrb, s, badcheck); + return mrb_cstr_to_dbl(mrb, mrb_string_value_cstr(mrb, &str), badcheck); } /* 15.2.10.5.39 */ -- cgit v1.2.3 From 9a4f3029d98f50f2142af99ba3dea4c504849593 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Sat, 4 May 2019 21:56:55 +0900 Subject: Update `README.md`; mruby is now Ruby 2.x compatible. --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 3e71ef7ca..2acc8de1a 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@ ## What is mruby mruby is the lightweight implementation of the Ruby language complying to (part -of) the [ISO standard][ISO-standard]. Its syntax is Ruby 1.9 compatible. +of) the [ISO standard][ISO-standard]. Its syntax is Ruby 2.x compatible. mruby can be linked and embedded within your application. We provide the interpreter program "mruby" and the interactive mruby shell "mirb" as examples. -- cgit v1.2.3 From 0d94a2e3a917b39ffcf4ed930edeacf9fabcff5b Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Thu, 9 May 2019 23:26:40 +0900 Subject: Raise `TypeError` if the argument type is unsupported in `mrb_stat0` --- mrbgems/mruby-io/src/file_test.c | 15 ++------------- mrbgems/mruby-io/test/file_test.rb | 5 ++--- 2 files changed, 4 insertions(+), 16 deletions(-) diff --git a/mrbgems/mruby-io/src/file_test.c b/mrbgems/mruby-io/src/file_test.c index 7d36f79b3..ec731b094 100644 --- a/mrbgems/mruby-io/src/file_test.c +++ b/mrbgems/mruby-io/src/file_test.c @@ -42,14 +42,7 @@ extern struct mrb_data_type mrb_io_type; static int mrb_stat0(mrb_state *mrb, mrb_value obj, struct stat *st, int do_lstat) { - mrb_value tmp; - mrb_value io_klass, str_klass; - - io_klass = mrb_obj_value(mrb_class_get(mrb, "IO")); - str_klass = mrb_obj_value(mrb_class_get(mrb, "String")); - - tmp = mrb_funcall(mrb, obj, "is_a?", 1, io_klass); - if (mrb_test(tmp)) { + if (mrb_obj_is_kind_of(mrb, obj, mrb_class_get(mrb, "IO"))) { struct mrb_io *fptr; fptr = (struct mrb_io *)mrb_get_datatype(mrb, obj, &mrb_io_type); @@ -60,9 +53,7 @@ mrb_stat0(mrb_state *mrb, mrb_value obj, struct stat *st, int do_lstat) mrb_raise(mrb, E_IO_ERROR, "closed stream"); return -1; } - - tmp = mrb_funcall(mrb, obj, "is_a?", 1, str_klass); - if (mrb_test(tmp)) { + else { char *path = mrb_locale_from_utf8(mrb_string_value_cstr(mrb, &obj), -1); int ret; if (do_lstat) { @@ -73,8 +64,6 @@ mrb_stat0(mrb_state *mrb, mrb_value obj, struct stat *st, int do_lstat) mrb_locale_free(path); return ret; } - - return -1; } static int diff --git a/mrbgems/mruby-io/test/file_test.rb b/mrbgems/mruby-io/test/file_test.rb index 72e921ce9..2134c6a75 100644 --- a/mrbgems/mruby-io/test/file_test.rb +++ b/mrbgems/mruby-io/test/file_test.rb @@ -20,9 +20,8 @@ assert("FileTest.exist?") do assert_equal true, FileTest.exist?(io), "io obj - exist" io.close assert_equal true, io.closed? - assert_raise IOError do - FileTest.exist?(io) - end + assert_raise(IOError) { FileTest.exist?(io) } + assert_raise(TypeError) { File.exist?($mrbtest_io_rfname.to_sym) } end assert("FileTest.file?") do -- cgit v1.2.3 From f2719e903aef90bc1e8c45f866abb3471c2d6e52 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Fri, 10 May 2019 20:52:15 +0900 Subject: Move `mrb_gc_arena_restore` to inside the loop in `mrb_file_s_chmod` --- mrbgems/mruby-io/src/file.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mrbgems/mruby-io/src/file.c b/mrbgems/mruby-io/src/file.c index b17b95e24..243f634b4 100644 --- a/mrbgems/mruby-io/src/file.c +++ b/mrbgems/mruby-io/src/file.c @@ -423,9 +423,9 @@ mrb_file_s_chmod(mrb_state *mrb, mrb_value klass) { mrb_sys_fail(mrb, utf8_path); } mrb_locale_free(path); + mrb_gc_arena_restore(mrb, ai); } - mrb_gc_arena_restore(mrb, ai); return mrb_fixnum_value(argc); } -- cgit v1.2.3 From 1e2983bd043d91a21d2594dea8460194afad489b Mon Sep 17 00:00:00 2001 From: Bhargava Shastry Date: Fri, 10 May 2019 16:13:05 +0200 Subject: Update ossfuzz options --- oss-fuzz/config/mruby_fuzzer.options | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/oss-fuzz/config/mruby_fuzzer.options b/oss-fuzz/config/mruby_fuzzer.options index 5d1c8d2da..132affcae 100644 --- a/oss-fuzz/config/mruby_fuzzer.options +++ b/oss-fuzz/config/mruby_fuzzer.options @@ -1,3 +1,5 @@ [libfuzzer] -close_fd_mask=3 -dict=mruby.dict +close_fd_mask = 3 +dict = mruby.dict +fork = 8 +only_ascii = 1 -- cgit v1.2.3 From fa317fabbd400204dfb11171155c30feb92a2293 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Sat, 11 May 2019 18:40:33 +0900 Subject: Use `mrb_ensure_string_type` in `mrb_to_str` --- src/object.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/object.c b/src/object.c index d45ab27c7..7c1879019 100644 --- a/src/object.c +++ b/src/object.c @@ -584,11 +584,7 @@ mrb_Float(mrb_state *mrb, mrb_value val) MRB_API mrb_value mrb_to_str(mrb_state *mrb, mrb_value val) { - if (!mrb_string_p(val)) { - mrb_value type = inspect_type(mrb, val); - mrb_raisef(mrb, E_TYPE_ERROR, "can't convert %S to String", type); - } - return val; + return mrb_ensure_string_type(mrb, val); } /* obsolete: use mrb_ensure_string_type() instead */ -- cgit v1.2.3 From 2c2584138a28de2cffeed8f2b2171e4415cad480 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Sun, 12 May 2019 20:25:11 +0900 Subject: Fix missing assertions in `mruby-time` test --- mrbgems/mruby-time/test/time.rb | 122 +++++++++++++++++++++++++--------------- 1 file changed, 78 insertions(+), 44 deletions(-) diff --git a/mrbgems/mruby-time/test/time.rb b/mrbgems/mruby-time/test/time.rb index 54c446ca3..8a93b4938 100644 --- a/mrbgems/mruby-time/test/time.rb +++ b/mrbgems/mruby-time/test/time.rb @@ -2,11 +2,11 @@ # Time ISO Test assert('Time.new', '15.2.3.3.3') do - Time.new.class == Time + assert_equal(Time, Time.new.class) end assert('Time', '15.2.19') do - Time.class == Class + assert_equal(Class, Time.class) end assert('Time.at', '15.2.19.6.1') do @@ -21,23 +21,51 @@ assert('Time.at', '15.2.19.6.1') do end assert('Time.gm', '15.2.19.6.2') do - Time.gm(2012, 12, 23) + t = Time.gm(2012, 9, 23) + assert_operator(2012, :eql?, t.year) + assert_operator( 9, :eql?, t.month) + assert_operator( 23, :eql?, t.day) + assert_operator( 0, :eql?, t.hour) + assert_operator( 0, :eql?, t.min) + assert_operator( 0, :eql?, t.sec) + assert_operator( 0, :eql?, t.usec) end assert('Time.local', '15.2.19.6.3') do - Time.local(2012, 12, 23) + t = Time.local(2014, 12, 27, 18) + assert_operator(2014, :eql?, t.year) + assert_operator( 12, :eql?, t.month) + assert_operator( 27, :eql?, t.day) + assert_operator( 18, :eql?, t.hour) + assert_operator( 0, :eql?, t.min) + assert_operator( 0, :eql?, t.sec) + assert_operator( 0, :eql?, t.usec) end assert('Time.mktime', '15.2.19.6.4') do - Time.mktime(2012, 12, 23) + t = Time.mktime(2013, 10, 4, 6, 15, 58, 3485) + assert_operator(2013, :eql?, t.year) + assert_operator( 10, :eql?, t.month) + assert_operator( 4, :eql?, t.day) + assert_operator( 6, :eql?, t.hour) + assert_operator( 15, :eql?, t.min) + assert_operator( 58, :eql?, t.sec) + assert_operator(3485, :eql?, t.usec) end assert('Time.now', '15.2.19.6.5') do - Time.now.class == Time + assert_equal(Time, Time.now.class) end assert('Time.utc', '15.2.19.6.6') do - Time.utc(2012, 12, 23) + t = Time.utc(2134) + assert_operator(2134, :eql?, t.year) + assert_operator( 1, :eql?, t.month) + assert_operator( 1, :eql?, t.day) + assert_operator( 0, :eql?, t.hour) + assert_operator( 0, :eql?, t.min) + assert_operator( 0, :eql?, t.sec) + assert_operator( 0, :eql?, t.usec) end assert('Time#+', '15.2.19.7.1') do @@ -67,30 +95,30 @@ assert('Time#<=>', '15.2.19.7.3') do t2 = Time.at(1400000000.0) t3 = Time.at(1500000000.0) - t2.<=>(t1) == 1 and - t2.<=>(t2) == 0 and - t2.<=>(t3) == -1 and - t2.<=>(nil) == nil + assert_equal(1, t2 <=> t1) + assert_equal(0, t2 <=> t2) + assert_equal(-1, t2 <=> t3) + assert_nil(t2 <=> nil) end assert('Time#asctime', '15.2.19.7.4') do - Time.at(1300000000.0).utc.asctime == "Sun Mar 13 07:06:40 UTC 2011" + assert_equal("Sun Mar 13 07:06:40 UTC 2011", Time.at(1300000000.0).utc.asctime) end assert('Time#ctime', '15.2.19.7.5') do - Time.at(1300000000.0).utc.ctime == "Sun Mar 13 07:06:40 UTC 2011" + assert_equal("Sun Mar 13 07:06:40 UTC 2011", Time.at(1300000000.0).utc.ctime) end assert('Time#day', '15.2.19.7.6') do - Time.gm(2012, 12, 23).day == 23 + assert_equal(23, Time.gm(2012, 12, 23).day) end assert('Time#dst?', '15.2.19.7.7') do - not Time.gm(2012, 12, 23).utc.dst? + assert_not_predicate(Time.gm(2012, 12, 23).utc, :dst?) end assert('Time#getgm', '15.2.19.7.8') do - Time.at(1300000000.0).getgm.asctime == "Sun Mar 13 07:06:40 UTC 2011" + assert_equal("Sun Mar 13 07:06:40 UTC 2011", Time.at(1300000000.0).getgm.asctime) end assert('Time#getlocal', '15.2.19.7.9') do @@ -98,114 +126,120 @@ assert('Time#getlocal', '15.2.19.7.9') do t2 = Time.at(1300000000.0) t3 = t1.getlocal - t1 == t3 and t3 == t2.getlocal + assert_equal(t1, t3) + assert_equal(t3, t2.getlocal) end assert('Time#getutc', '15.2.19.7.10') do - Time.at(1300000000.0).getutc.asctime == "Sun Mar 13 07:06:40 UTC 2011" + assert_equal("Sun Mar 13 07:06:40 UTC 2011", Time.at(1300000000.0).getutc.asctime) end assert('Time#gmt?', '15.2.19.7.11') do - Time.at(1300000000.0).utc.gmt? + assert_predicate(Time.at(1300000000.0).utc, :gmt?) end # ATM not implemented # assert('Time#gmt_offset', '15.2.19.7.12') do assert('Time#gmtime', '15.2.19.7.13') do - Time.at(1300000000.0).gmtime + t = Time.now + assert_predicate(t.gmtime, :gmt?) + assert_predicate(t, :gmt?) end # ATM not implemented # assert('Time#gmtoff', '15.2.19.7.14') do assert('Time#hour', '15.2.19.7.15') do - Time.gm(2012, 12, 23, 7, 6).hour == 7 + assert_equal(7, Time.gm(2012, 12, 23, 7, 6).hour) end # ATM doesn't really work # assert('Time#initialize', '15.2.19.7.16') do assert('Time#initialize_copy', '15.2.19.7.17') do - time_tmp_2 = Time.at(7.0e6) - time_tmp_2.clone == time_tmp_2 + t = Time.at(7.0e6) + assert_equal(t, t.clone) end assert('Time#localtime', '15.2.19.7.18') do - t1 = Time.at(1300000000.0) - t2 = Time.at(1300000000.0) + t1 = Time.utc(2014, 5 ,6) + t2 = Time.utc(2014, 5 ,6) + t3 = t2.getlocal - t1.localtime - t1 == t2.getlocal + assert_equal(t3, t1.localtime) + assert_equal(t3, t1) end assert('Time#mday', '15.2.19.7.19') do - Time.gm(2012, 12, 23).mday == 23 + assert_equal(23, Time.gm(2012, 12, 23).mday) end assert('Time#min', '15.2.19.7.20') do - Time.gm(2012, 12, 23, 7, 6).min == 6 + assert_equal(6, Time.gm(2012, 12, 23, 7, 6).min) end assert('Time#mon', '15.2.19.7.21') do - Time.gm(2012, 12, 23).mon == 12 + assert_equal(12, Time.gm(2012, 12, 23).mon) end assert('Time#month', '15.2.19.7.22') do - Time.gm(2012, 12, 23).month == 12 + assert_equal(12, Time.gm(2012, 12, 23).month) end assert('Times#sec', '15.2.19.7.23') do - Time.gm(2012, 12, 23, 7, 6, 40).sec == 40 + assert_equal(40, Time.gm(2012, 12, 23, 7, 6, 40).sec) end assert('Time#to_f', '15.2.19.7.24') do - Time.at(1300000000.0).to_f == 1300000000.0 + assert_operator(2.0, :eql?, Time.at(2).to_f) end assert('Time#to_i', '15.2.19.7.25') do - Time.at(1300000000.0).to_i == 1300000000 + assert_operator(2, :eql?, Time.at(2.0).to_i) end assert('Time#usec', '15.2.19.7.26') do - Time.at(1300000000.0).usec == 0 + assert_equal(0, Time.at(1300000000.0).usec) end assert('Time#utc', '15.2.19.7.27') do - Time.at(1300000000.0).utc + t = Time.now + assert_predicate(t.utc, :gmt?) + assert_predicate(t, :gmt?) end assert('Time#utc?', '15.2.19.7.28') do - Time.at(1300000000.0).utc.utc? + assert_predicate(Time.at(1300000000.0).utc, :utc?) end # ATM not implemented # assert('Time#utc_offset', '15.2.19.7.29') do assert('Time#wday', '15.2.19.7.30') do - Time.gm(2012, 12, 23).wday == 0 + assert_equal(0, Time.gm(2012, 12, 23).wday) end assert('Time#yday', '15.2.19.7.31') do - Time.gm(2012, 12, 23).yday == 358 + assert_equal(358, Time.gm(2012, 12, 23).yday) end assert('Time#year', '15.2.19.7.32') do - Time.gm(2012, 12, 23).year == 2012 + assert_equal(2012, Time.gm(2012, 12, 23).year) end assert('Time#zone', '15.2.19.7.33') do - Time.at(1300000000.0).utc.zone == 'UTC' + assert_equal('UTC', Time.at(1300000000.0).utc.zone) end # Not ISO specified assert('Time#to_s') do - Time.at(1300000000.0).utc.to_s == "Sun Mar 13 07:06:40 UTC 2011" + assert_equal("Sun Mar 13 07:06:40 UTC 2011", Time.at(1300000000.0).utc.to_s) end assert('Time#inspect') do - Time.at(1300000000.0).utc.inspect == "Sun Mar 13 07:06:40 UTC 2011" + assert_equal("Sun Mar 13 07:06:40 UTC 2011", Time.at(1300000000.0).utc.inspect) end assert('day of week methods') do @@ -224,7 +258,7 @@ assert('2000 times 500us make a second') do 2000.times do t += 0.0005 end - t.usec == 0 + assert_equal(0, t.usec) end assert('Time.gm with Dec 31 23:59:59 1969 raise ArgumentError') do -- cgit v1.2.3 From a2616db4dc810aa44d90d768a627c62d2a67886c Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Mon, 13 May 2019 19:46:26 +0900 Subject: Fix `Time#(asctime|ctime)` according to ISO Ruby - A leading charactor for day is space. - Time zone does not included. Before this patch: Time.gm(1982,3,4,5,6,7).asctime #=> "Thu Mar 04 05:06:07 UTC 1982" After this patch: Time.gm(1982,3,4,5,6,7).asctime #=> "Thu Mar 4 05:06:07 1982" --- mrbgems/mruby-time/src/time.c | 3 +-- mrbgems/mruby-time/test/time.rb | 20 ++++++++++---------- 2 files changed, 11 insertions(+), 12 deletions(-) diff --git a/mrbgems/mruby-time/src/time.c b/mrbgems/mruby-time/src/time.c index 7f6c3004d..bc8abc7ae 100644 --- a/mrbgems/mruby-time/src/time.c +++ b/mrbgems/mruby-time/src/time.c @@ -576,10 +576,9 @@ mrb_time_asctime(mrb_state *mrb, mrb_value self) #else char buf[256]; - len = snprintf(buf, sizeof(buf), "%s %s %02d %02d:%02d:%02d %s%d", + len = snprintf(buf, sizeof(buf), "%s %s %2d %02d:%02d:%02d %.4d", wday_names[d->tm_wday], mon_names[d->tm_mon], d->tm_mday, d->tm_hour, d->tm_min, d->tm_sec, - tm->timezone == MRB_TIMEZONE_UTC ? "UTC " : "", d->tm_year + 1900); #endif return mrb_str_new(mrb, buf, len); diff --git a/mrbgems/mruby-time/test/time.rb b/mrbgems/mruby-time/test/time.rb index 8a93b4938..c7ad35ab2 100644 --- a/mrbgems/mruby-time/test/time.rb +++ b/mrbgems/mruby-time/test/time.rb @@ -58,8 +58,8 @@ assert('Time.now', '15.2.19.6.5') do end assert('Time.utc', '15.2.19.6.6') do - t = Time.utc(2134) - assert_operator(2134, :eql?, t.year) + t = Time.utc(2034) + assert_operator(2034, :eql?, t.year) assert_operator( 1, :eql?, t.month) assert_operator( 1, :eql?, t.day) assert_operator( 0, :eql?, t.hour) @@ -72,7 +72,7 @@ assert('Time#+', '15.2.19.7.1') do t1 = Time.at(1300000000.0) t2 = t1.+(60) - assert_equal(t2.utc.asctime, "Sun Mar 13 07:07:40 UTC 2011") + assert_equal(t2.utc.asctime, "Sun Mar 13 07:07:40 2011") assert_raise(FloatDomainError) { Time.at(0) + Float::NAN } assert_raise(FloatDomainError) { Time.at(0) + Float::INFINITY } @@ -83,7 +83,7 @@ assert('Time#-', '15.2.19.7.2') do t1 = Time.at(1300000000.0) t2 = t1.-(60) - assert_equal(t2.utc.asctime, "Sun Mar 13 07:05:40 UTC 2011") + assert_equal(t2.utc.asctime, "Sun Mar 13 07:05:40 2011") assert_raise(FloatDomainError) { Time.at(0) - Float::NAN } assert_raise(FloatDomainError) { Time.at(0) - Float::INFINITY } @@ -102,11 +102,11 @@ assert('Time#<=>', '15.2.19.7.3') do end assert('Time#asctime', '15.2.19.7.4') do - assert_equal("Sun Mar 13 07:06:40 UTC 2011", Time.at(1300000000.0).utc.asctime) + assert_equal("Thu Mar 4 05:06:07 1982", Time.gm(1982,3,4,5,6,7).asctime) end assert('Time#ctime', '15.2.19.7.5') do - assert_equal("Sun Mar 13 07:06:40 UTC 2011", Time.at(1300000000.0).utc.ctime) + assert_equal("Thu Oct 24 15:26:47 2013", Time.gm(2013,10,24,15,26,47).ctime) end assert('Time#day', '15.2.19.7.6') do @@ -118,7 +118,7 @@ assert('Time#dst?', '15.2.19.7.7') do end assert('Time#getgm', '15.2.19.7.8') do - assert_equal("Sun Mar 13 07:06:40 UTC 2011", Time.at(1300000000.0).getgm.asctime) + assert_equal("Sun Mar 13 07:06:40 2011", Time.at(1300000000.0).getgm.asctime) end assert('Time#getlocal', '15.2.19.7.9') do @@ -131,7 +131,7 @@ assert('Time#getlocal', '15.2.19.7.9') do end assert('Time#getutc', '15.2.19.7.10') do - assert_equal("Sun Mar 13 07:06:40 UTC 2011", Time.at(1300000000.0).getutc.asctime) + assert_equal("Sun Mar 13 07:06:40 2011", Time.at(1300000000.0).getutc.asctime) end assert('Time#gmt?', '15.2.19.7.11') do @@ -235,11 +235,11 @@ end # Not ISO specified assert('Time#to_s') do - assert_equal("Sun Mar 13 07:06:40 UTC 2011", Time.at(1300000000.0).utc.to_s) + assert_equal("Sun Mar 13 07:06:40 2011", Time.at(1300000000.0).utc.to_s) end assert('Time#inspect') do - assert_equal("Sun Mar 13 07:06:40 UTC 2011", Time.at(1300000000.0).utc.inspect) + assert_equal("Sun Mar 13 07:06:40 2011", Time.at(1300000000.0).utc.inspect) end assert('day of week methods') do -- cgit v1.2.3 From edf4b33c61d04148ef11406d37256feda5fe78fb Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Tue, 14 May 2019 22:05:45 +0900 Subject: Refine `Time#(to_s|inspect)` For the following reasons: - Ruby compatibility. - Add UTC offset (time zone informations was not included by #4433). - More readable. Example: Before this patch: p Time.gm(2003,4,5,6,7,8,9) #=> Sat Apr 5 06:07:08 2003 p Time.local(2013,10,28,16,27,48) #=> Mon Oct 28 16:27:48 2013 After this patch: p Time.gm(2003,4,5,6,7,8,9) #=> 2003-04-05 06:07:08 UTC p Time.local(2013,10,28,16,27,48) #=> 2013-10-28 16:27:48 +0900 Implementation: I use `strftime(3)` because UTC offset can be added and program size become smaller than the other implementations (using `sprintf(3)`, self conversion etc) in my environment. --- mrbgems/mruby-time/src/time.c | 15 ++++++++++++--- mrbgems/mruby-time/test/time.rb | 4 ++-- 2 files changed, 14 insertions(+), 5 deletions(-) diff --git a/mrbgems/mruby-time/src/time.c b/mrbgems/mruby-time/src/time.c index bc8abc7ae..b5a540d09 100644 --- a/mrbgems/mruby-time/src/time.c +++ b/mrbgems/mruby-time/src/time.c @@ -18,6 +18,7 @@ #endif #define NDIV(x,y) (-(-((x)+1)/(y))-1) +#define TO_S_FMT "%Y-%m-%d %H:%M:%S " #if defined(_MSC_VER) && _MSC_VER < 1800 double round(double x) { @@ -760,7 +761,6 @@ mrb_time_sec(mrb_state *mrb, mrb_value self) return mrb_fixnum_value(tm->datetime.tm_sec); } - /* 15.2.19.7.24 */ /* Returns a Float with the time since the epoch in seconds. */ static mrb_value @@ -824,6 +824,15 @@ mrb_time_utc_p(mrb_state *mrb, mrb_value self) return mrb_bool_value(tm->timezone == MRB_TIMEZONE_UTC); } +static mrb_value +mrb_time_to_s(mrb_state *mrb, mrb_value self) +{ + char buf[64]; + struct mrb_time *tm = time_get_ptr(mrb, self); + const char *fmt = tm->timezone == MRB_TIMEZONE_UTC ? TO_S_FMT "UTC" : TO_S_FMT "%z"; + size_t len = strftime(buf, sizeof(buf), fmt, &tm->datetime); + return mrb_str_new(mrb, buf, len); +} void mrb_mruby_time_gem_init(mrb_state* mrb) @@ -844,8 +853,8 @@ mrb_mruby_time_gem_init(mrb_state* mrb) mrb_define_method(mrb, tc, "<=>" , mrb_time_cmp , MRB_ARGS_REQ(1)); /* 15.2.19.7.1 */ mrb_define_method(mrb, tc, "+" , mrb_time_plus , MRB_ARGS_REQ(1)); /* 15.2.19.7.2 */ mrb_define_method(mrb, tc, "-" , mrb_time_minus , MRB_ARGS_REQ(1)); /* 15.2.19.7.3 */ - mrb_define_method(mrb, tc, "to_s" , mrb_time_asctime, MRB_ARGS_NONE()); - mrb_define_method(mrb, tc, "inspect", mrb_time_asctime, MRB_ARGS_NONE()); + mrb_define_method(mrb, tc, "to_s" , mrb_time_to_s , MRB_ARGS_NONE()); + mrb_define_method(mrb, tc, "inspect", mrb_time_to_s , MRB_ARGS_NONE()); mrb_define_method(mrb, tc, "asctime", mrb_time_asctime, MRB_ARGS_NONE()); /* 15.2.19.7.4 */ mrb_define_method(mrb, tc, "ctime" , mrb_time_asctime, MRB_ARGS_NONE()); /* 15.2.19.7.5 */ mrb_define_method(mrb, tc, "day" , mrb_time_day , MRB_ARGS_NONE()); /* 15.2.19.7.6 */ diff --git a/mrbgems/mruby-time/test/time.rb b/mrbgems/mruby-time/test/time.rb index c7ad35ab2..ce7b39928 100644 --- a/mrbgems/mruby-time/test/time.rb +++ b/mrbgems/mruby-time/test/time.rb @@ -235,11 +235,11 @@ end # Not ISO specified assert('Time#to_s') do - assert_equal("Sun Mar 13 07:06:40 2011", Time.at(1300000000.0).utc.to_s) + assert_equal("2003-04-05 06:07:08 UTC", Time.gm(2003,4,5,6,7,8,9).to_s) end assert('Time#inspect') do - assert_equal("Sun Mar 13 07:06:40 2011", Time.at(1300000000.0).utc.inspect) + assert_match("2013-10-28 16:27:48 [^U]*", Time.local(2013,10,28,16,27,48).inspect) end assert('day of week methods') do -- cgit v1.2.3 From fd37bc53deb2d52fe3134838eab002dfb9ac35ab Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Wed, 15 May 2019 09:55:21 +0900 Subject: Remove `String#=~` and `String#match` that requires `Regexp`. --- mrblib/string.rb | 24 +++++++----------------- 1 file changed, 7 insertions(+), 17 deletions(-) diff --git a/mrblib/string.rb b/mrblib/string.rb index 506f23c83..42d594055 100644 --- a/mrblib/string.rb +++ b/mrblib/string.rb @@ -230,26 +230,16 @@ class String end end - def _regexp(re, mid) - if String === re - if Object.const_defined?(:Regexp) - return Regexp.new(re) - else - raise NotImplementedError, "String##{mid} needs Regexp class" - end - end - re - end - + # those two methods requires Regexp that is optional in mruby ## # ISO 15.2.10.5.3 - def =~(re) - _regexp(re, :=~) =~ self - end + #def =~(re) + # re =~ self + #end ## # ISO 15.2.10.5.27 - def match(re, &block) - _regexp(re, :match).match(self, &block) - end + #def match(re, &block) + # re.match(self, &block) + #end end -- cgit v1.2.3 From 780342eddb880a1c0a457311b005398ce36d0c9f Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Wed, 15 May 2019 14:59:48 +0900 Subject: Add Enumerator support to `String#each_byte`. `String#each_byte` is not defined in ISO Ruby but it is implemented in the core mruby because it's useful. --- mrblib/string.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/mrblib/string.rb b/mrblib/string.rb index 42d594055..b0fe4033e 100644 --- a/mrblib/string.rb +++ b/mrblib/string.rb @@ -167,6 +167,7 @@ class String ## # Call the given block for each byte of +self+. def each_byte(&block) + return to_enum(:each_byte, &block) unless block bytes = self.bytes pos = 0 while pos < bytes.size -- cgit v1.2.3 From 5f664fb6f890e9c3a6c8e56cf1d173fa46dd39e9 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Wed, 15 May 2019 16:27:08 +0900 Subject: Fix typo in `mrbgems/mruby-io/src/file_test.c` [ci skip] --- mrbgems/mruby-io/src/file_test.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mrbgems/mruby-io/src/file_test.c b/mrbgems/mruby-io/src/file_test.c index ec731b094..5d5ecb93f 100644 --- a/mrbgems/mruby-io/src/file_test.c +++ b/mrbgems/mruby-io/src/file_test.c @@ -1,5 +1,5 @@ /* -** file.c - File class +** file_test.c - FileTest class */ #include "mruby.h" -- cgit v1.2.3 From 8808219e6d51673e6fa582819703e6e5912439b0 Mon Sep 17 00:00:00 2001 From: Ukrainskiy Sergey Date: Thu, 9 Aug 2018 17:09:02 +0900 Subject: Initial suffix support --- include/mrbconf.h | 3 + mrbgems/default.gembox | 6 ++ mrbgems/mruby-compiler/core/parse.y | 148 +++++++++++++++++++++++++++--- mrbgems/mruby-complex/mrbgem.rake | 5 + mrbgems/mruby-complex/mrblib/complex.rb | 95 +++++++++++++++++++ mrbgems/mruby-complex/test/complex.rb | 3 + mrbgems/mruby-rational/mrbgem.rake | 5 + mrbgems/mruby-rational/mrblib/rational.rb | 46 ++++++++++ mrbgems/mruby-rational/test/rational.rb | 3 + 9 files changed, 301 insertions(+), 13 deletions(-) create mode 100644 mrbgems/mruby-complex/mrbgem.rake create mode 100644 mrbgems/mruby-complex/mrblib/complex.rb create mode 100644 mrbgems/mruby-complex/test/complex.rb create mode 100644 mrbgems/mruby-rational/mrbgem.rake create mode 100644 mrbgems/mruby-rational/mrblib/rational.rb create mode 100644 mrbgems/mruby-rational/test/rational.rb diff --git a/include/mrbconf.h b/include/mrbconf.h index 6b0b9e37e..ee816e322 100644 --- a/include/mrbconf.h +++ b/include/mrbconf.h @@ -63,6 +63,9 @@ # endif #endif +#define MRB_COMPLEX_NUMBERS +#define MRB_RATIONAL_NUMBERS + /* define on big endian machines; used by MRB_NAN_BOXING, etc. */ #ifndef MRB_ENDIAN_BIG # if (defined(BYTE_ORDER) && defined(BIG_ENDIAN) && BYTE_ORDER == BIG_ENDIAN) || \ diff --git a/mrbgems/default.gembox b/mrbgems/default.gembox index 23e65fcee..501aee146 100644 --- a/mrbgems/default.gembox +++ b/mrbgems/default.gembox @@ -68,6 +68,12 @@ MRuby::GemBox.new do |conf| # Use Enumerator::Lazy class (require mruby-enumerator) conf.gem :core => "mruby-enum-lazy" + # Use Complex class + #conf.gem :core => "mruby-complex" + + # Use Rational class + #conf.gem :core => "mruby-rational" + # Use toplevel object (main) methods extension conf.gem :core => "mruby-toplevel-ext" diff --git a/mrbgems/mruby-compiler/core/parse.y b/mrbgems/mruby-compiler/core/parse.y index b7d47118f..b18906ed3 100644 --- a/mrbgems/mruby-compiler/core/parse.y +++ b/mrbgems/mruby-compiler/core/parse.y @@ -76,6 +76,24 @@ typedef unsigned int stack_type; #define nint(x) ((node*)(intptr_t)(x)) #define intn(x) ((int)(intptr_t)(x)) +#if defined(MRB_COMPLEX_NUMBERS) || defined(MRB_RATIONAL_NUMBERS) + #define MRB_SUFFIX_SUPPORT + + #ifdef MRB_RATIONAL_NUMBERS + #define NUM_SUFFIX_R (1<<0) + #else + #define NUM_SUFFIX_R 0 + #endif + + #ifdef MRB_COMPLEX_NUMBERS + #define NUM_SUFFIX_I (1<<1) + #else + #define NUM_SUFFIX_I 0 + #endif + + #define NUM_SUFFIX_ALL (NUM_SUFFIX_R | NUM_SUFFIX_I) +#endif + static inline mrb_sym intern_cstr_gen(parser_state *p, const char *s) { @@ -842,19 +860,62 @@ new_op_asgn(parser_state *p, node *a, mrb_sym op, node *b) return list4((node*)NODE_OP_ASGN, a, nsym(op), b); } +#ifdef MRB_COMPLEX_NUMBERS +static node* +new_imaginary(parser_state *p, node *imaginary); +#endif + +#ifdef MRB_RATIONAL_NUMBERS +static node* +new_rational(parser_state *p, node *rational) +{ + return new_call(p, new_const(p, intern_cstr("Rational")), intern_cstr("new"), list1(list1(rational)), 1); +} +#endif + /* (:int . i) */ static node* -new_int(parser_state *p, const char *s, int base) +new_int(parser_state *p, const char *s, int base, int suffix) { - return list3((node*)NODE_INT, (node*)strdup(s), nint(base)); + node* result = list3((node*)NODE_INT, (node*)strdup(s), nint(base)); +#ifdef MRB_RATIONAL_NUMBERS + if (suffix & NUM_SUFFIX_R) { + result = new_rational(p, result); + } +#endif +#ifdef MRB_COMPLEX_NUMBERS + if (suffix & NUM_SUFFIX_I) { + result = new_imaginary(p, result); + } +#endif + return result; } #ifndef MRB_WITHOUT_FLOAT /* (:float . i) */ static node* -new_float(parser_state *p, const char *s) +new_float(parser_state *p, const char *s, int suffix) +{ + node* result = cons((node*)NODE_FLOAT, (node*)strdup(s)); +#ifdef MRB_RATIONAL_NUMBERS + if (suffix & NUM_SUFFIX_R) { + result = new_rational(p, result); + } +#endif +#ifdef MRB_COMPLEX_NUMBERS + if (suffix & NUM_SUFFIX_I) { + result = new_imaginary(p, result); + } +#endif + return result; +} +#endif + +#ifdef MRB_COMPLEX_NUMBERS +static node* +new_imaginary(parser_state *p, node *imaginary) { - return cons((node*)NODE_FLOAT, (node*)strdup(s)); + return new_call(p, new_const(p, intern_cstr("Complex")), intern_cstr("new"), list1(list2(new_int(p, "0", 10, 0), imaginary)), 1); } #endif @@ -3192,7 +3253,7 @@ var_ref : variable char buf[16]; dump_int(p->lineno, buf); - $$ = new_int(p, buf, 10); + $$ = new_int(p, buf, 10, 0); } | keyword__ENCODING__ { @@ -4520,6 +4581,45 @@ parse_string(parser_state *p) return tSTRING; } +#ifdef MRB_SUFFIX_SUPPORT +static int +number_literal_suffix(parser_state *p, int mask) +{ + int c, result = 0; + node *list = 0; + int column = p->column; + + while ((c = nextc(p)) != -1) { + list = push(list, (node*)(intptr_t)c); + + if ((mask & NUM_SUFFIX_I) && c == 'i') { + result |= (mask & NUM_SUFFIX_I); + mask &= ~NUM_SUFFIX_I; + /* r after i, rational of complex is disallowed */ + mask &= ~NUM_SUFFIX_R; + continue; + } + if ((mask & NUM_SUFFIX_R) && c == 'r') { + result |= (mask & NUM_SUFFIX_R); + mask &= ~NUM_SUFFIX_R; + continue; + } + if (!ISASCII(c) || ISALPHA(c) || c == '_') { + p->column = column; + if (p->pb) { + p->pb = append((node*)list, p->pb); + } + else { + p->pb = list; + } + return 0; + } + pushback(p, c); + break; + } + return result; +} +#endif static int heredoc_identifier(parser_state *p) @@ -5094,6 +5194,7 @@ parser_yylex(parser_state *p) case '5': case '6': case '7': case '8': case '9': { int is_float, seen_point, seen_e, nondigit; + int suffix; is_float = seen_point = seen_e = nondigit = 0; p->lstate = EXPR_ENDARG; @@ -5127,7 +5228,10 @@ parser_yylex(parser_state *p) no_digits(); } else if (nondigit) goto trailing_uc; - pylval.nd = new_int(p, tok(p), 16); + #ifdef MRB_SUFFIX_SUPPORT + suffix = number_literal_suffix(p, NUM_SUFFIX_ALL); + #endif + pylval.nd = new_int(p, tok(p), 16, suffix); return tINTEGER; } if (c == 'b' || c == 'B') { @@ -5151,7 +5255,10 @@ parser_yylex(parser_state *p) no_digits(); } else if (nondigit) goto trailing_uc; - pylval.nd = new_int(p, tok(p), 2); + #ifdef MRB_SUFFIX_SUPPORT + suffix = number_literal_suffix(p, NUM_SUFFIX_ALL); + #endif + pylval.nd = new_int(p, tok(p), 2, suffix); return tINTEGER; } if (c == 'd' || c == 'D') { @@ -5175,7 +5282,10 @@ parser_yylex(parser_state *p) no_digits(); } else if (nondigit) goto trailing_uc; - pylval.nd = new_int(p, tok(p), 10); + #ifdef MRB_SUFFIX_SUPPORT + suffix = number_literal_suffix(p, NUM_SUFFIX_ALL); + #endif + pylval.nd = new_int(p, tok(p), 10, suffix); return tINTEGER; } if (c == '_') { @@ -5208,7 +5318,10 @@ parser_yylex(parser_state *p) pushback(p, c); tokfix(p); if (nondigit) goto trailing_uc; - pylval.nd = new_int(p, tok(p), 8); + #ifdef MRB_SUFFIX_SUPPORT + suffix = number_literal_suffix(p, NUM_SUFFIX_ALL); + #endif + pylval.nd = new_int(p, tok(p), 8, suffix); return tINTEGER; } if (nondigit) { @@ -5225,7 +5338,10 @@ parser_yylex(parser_state *p) } else { pushback(p, c); - pylval.nd = new_int(p, "0", 10); + #ifdef MRB_SUFFIX_SUPPORT + suffix = number_literal_suffix(p, NUM_SUFFIX_ALL); + #endif + pylval.nd = new_int(p, "0", 10, suffix); return tINTEGER; } } @@ -5299,7 +5415,7 @@ parser_yylex(parser_state *p) if (is_float) { #ifdef MRB_WITHOUT_FLOAT yywarning(p, "floating point numbers are not supported"); - pylval.nd = new_int(p, "0", 10); + pylval.nd = new_int(p, "0", 10, 0); return tINTEGER; #else double d; @@ -5314,11 +5430,17 @@ parser_yylex(parser_state *p) yywarning_s(p, "float out of range", tok(p)); errno = 0; } - pylval.nd = new_float(p, tok(p)); + #ifdef MRB_SUFFIX_SUPPORT + suffix = number_literal_suffix(p, NUM_SUFFIX_ALL); + #endif + pylval.nd = new_float(p, tok(p), suffix); return tFLOAT; #endif } - pylval.nd = new_int(p, tok(p), 10); + #ifdef MRB_SUFFIX_SUPPORT + suffix = number_literal_suffix(p, NUM_SUFFIX_ALL); + #endif + pylval.nd = new_int(p, tok(p), 10, suffix); return tINTEGER; } diff --git a/mrbgems/mruby-complex/mrbgem.rake b/mrbgems/mruby-complex/mrbgem.rake new file mode 100644 index 000000000..f8f04d0b8 --- /dev/null +++ b/mrbgems/mruby-complex/mrbgem.rake @@ -0,0 +1,5 @@ +MRuby::Gem::Specification.new('mruby-complex') do |spec| + spec.license = 'MIT' + spec.author = 'mruby developers' + spec.summary = 'Complex class' +end diff --git a/mrbgems/mruby-complex/mrblib/complex.rb b/mrbgems/mruby-complex/mrblib/complex.rb new file mode 100644 index 000000000..0815c9a71 --- /dev/null +++ b/mrbgems/mruby-complex/mrblib/complex.rb @@ -0,0 +1,95 @@ +class Complex < Numeric + def initialize(real = 0, imaginary = 0) + @real = real + @imaginary = imaginary + end + + def inspect + "(#{to_s})" + end + + def to_s + "#{real}#{'+'}#{imaginary}i" + end + + def +@ + Complex.new(real, imaginary) + end + + def -@ + Complex.new(-real, -imaginary) + end + + def +(rhs) + if rhs.is_a? Complex + Complex.new(real + rhs.real, imaginary + rhs.imaginary) + elsif rhs.is_a? Numeric + Complex.new(real + rhs, imaginary) + end + end + + def -(rhs) + if rhs.is_a? Complex + Complex.new(real - rhs.real, imaginary - rhs.imaginary) + elsif rhs.is_a? Numeric + Complex.new(real - rhs, imaginary) + end + end + + def *(rhs) + if rhs.is_a? Complex + Complex.new(real * rhs.real - imaginary * rhs.imaginary, real * rhs.imaginary + rhs.real * imaginary) + elsif rhs.is_a? Numeric + Complex.new(real * rhs, imaginary * rhs) + end + end + + def /(rhs) + if rhs.is_a? Complex + div = rhs.real * rhs.real + rhs.imaginary * rhs.imaginary + Complex.new((real * rhs.real + imaginary * rhs.imaginary) / div, (rhs.real * imaginary - real * rhs.imaginary) / div) + elsif rhs.is_a? Numeric + Complex.new(real / rhs, imaginary / rhs) + end + end + + attr_reader :real, :imaginary +end + +def Complex(real = 0, imaginary = 0) + Complex.new(real, imaginary) +end + +module ForwardOperatorToComplex + def __forward_operator_to_complex(op, &b) + original_operator_name = "__original_operator_#{op}_complex" + alias_method original_operator_name, op + define_method op do |rhs| + if rhs.is_a? Complex + Complex.new(self).send(op, rhs) + else + send(original_operator_name, rhs) + end + end + end + + def __forward_operators_to_complex + __forward_operator_to_complex :+ + __forward_operator_to_complex :- + __forward_operator_to_complex :* + __forward_operator_to_complex :/ + + singleton_class.undef_method :__forward_operator_to_complex + singleton_class.undef_method :__forward_operators_to_complex + end +end + +class Fixnum + extend ForwardOperatorToComplex + __forward_operators_to_complex +end + +class Float + extend ForwardOperatorToComplex + __forward_operators_to_complex +end \ No newline at end of file diff --git a/mrbgems/mruby-complex/test/complex.rb b/mrbgems/mruby-complex/test/complex.rb new file mode 100644 index 000000000..890dd4ff1 --- /dev/null +++ b/mrbgems/mruby-complex/test/complex.rb @@ -0,0 +1,3 @@ +assert 'Complex' do + assert_equal Complex, 0i.class +end \ No newline at end of file diff --git a/mrbgems/mruby-rational/mrbgem.rake b/mrbgems/mruby-rational/mrbgem.rake new file mode 100644 index 000000000..4b540dec4 --- /dev/null +++ b/mrbgems/mruby-rational/mrbgem.rake @@ -0,0 +1,5 @@ +MRuby::Gem::Specification.new('mruby-rational') do |spec| + spec.license = 'MIT' + spec.author = 'mruby developers' + spec.summary = 'Rational class' +end diff --git a/mrbgems/mruby-rational/mrblib/rational.rb b/mrbgems/mruby-rational/mrblib/rational.rb new file mode 100644 index 000000000..457c0488a --- /dev/null +++ b/mrbgems/mruby-rational/mrblib/rational.rb @@ -0,0 +1,46 @@ +class Rational < Numeric + def initialize(numerator = 0, denominator = 1) + @numerator = numerator + @denominator = denominator + end + + attr_reader :numerator, :denominator +end + +def Rational(numerator = 0, denominator = 1) + Rational.new(numerator, denominator) +end + +module ForwardOperatorToRational + def __forward_operator_to_rational(op, &b) + original_operator_name = "__original_operator_#{op}_rational" + alias_method original_operator_name, op + define_method op do |rhs| + if rhs.is_a? Rational + Rational.new(self).send(op, rhs) + else + send(original_operator_name, rhs) + end + end + end + + def __forward_operators_to_rational + __forward_operator_to_rational :+ + __forward_operator_to_rational :- + __forward_operator_to_rational :* + __forward_operator_to_rational :/ + + singleton_class.undef_method :__forward_operator_to_rational + singleton_class.undef_method :__forward_operators_to_rational + end +end + +class Fixnum + extend ForwardOperatorToRational + __forward_operators_to_rational +end + +class Float + extend ForwardOperatorToRational + __forward_operators_to_rational +end \ No newline at end of file diff --git a/mrbgems/mruby-rational/test/rational.rb b/mrbgems/mruby-rational/test/rational.rb new file mode 100644 index 000000000..6f20a6cd4 --- /dev/null +++ b/mrbgems/mruby-rational/test/rational.rb @@ -0,0 +1,3 @@ +assert 'Rational' do + assert_equal Rational, 0r.class +end \ No newline at end of file -- cgit v1.2.3 From 79c3335e8d22ec76340b3028a7bbc658d631b17c Mon Sep 17 00:00:00 2001 From: Ukrainskiy Sergey Date: Sun, 9 Sep 2018 11:55:21 +0900 Subject: Small refactoring --- mrbgems/mruby-compiler/core/parse.y | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/mrbgems/mruby-compiler/core/parse.y b/mrbgems/mruby-compiler/core/parse.y index b18906ed3..2c5e0c991 100644 --- a/mrbgems/mruby-compiler/core/parse.y +++ b/mrbgems/mruby-compiler/core/parse.y @@ -862,14 +862,17 @@ new_op_asgn(parser_state *p, node *a, mrb_sym op, node *b) #ifdef MRB_COMPLEX_NUMBERS static node* -new_imaginary(parser_state *p, node *imaginary); +new_imaginary(parser_state *p, node *imaginary) +{ + return new_call(p, new_const(p, intern_cstr("Kernel")), intern_cstr("Complex"), list1(list2(list3((node*)NODE_INT, (node*)strdup("0"), nint(10)), imaginary)), 1); +} #endif #ifdef MRB_RATIONAL_NUMBERS static node* new_rational(parser_state *p, node *rational) { - return new_call(p, new_const(p, intern_cstr("Rational")), intern_cstr("new"), list1(list1(rational)), 1); + return new_call(p, new_const(p, intern_cstr("Kernel")), intern_cstr("Rational"), list1(list1(rational)), 1); } #endif @@ -911,14 +914,6 @@ new_float(parser_state *p, const char *s, int suffix) } #endif -#ifdef MRB_COMPLEX_NUMBERS -static node* -new_imaginary(parser_state *p, node *imaginary) -{ - return new_call(p, new_const(p, intern_cstr("Complex")), intern_cstr("new"), list1(list2(new_int(p, "0", 10, 0), imaginary)), 1); -} -#endif - /* (:str . (s . len)) */ static node* new_str(parser_state *p, const char *s, size_t len) -- cgit v1.2.3 From d67d2ae8e88b93536e71dfa41a90721ce351da7c Mon Sep 17 00:00:00 2001 From: Ukrainskiy Sergey Date: Sun, 9 Sep 2018 11:57:16 +0900 Subject: Basic implementation of Complex and Rational classes --- mrbgems/default.gembox | 4 +- mrbgems/mruby-complex/mrbgem.rake | 4 + mrbgems/mruby-complex/mrblib/complex.rb | 155 ++++++++++++++++++++++-------- mrbgems/mruby-complex/test/complex.rb | 129 ++++++++++++++++++++++++- mrbgems/mruby-rational/mrbgem.rake | 3 + mrbgems/mruby-rational/mrblib/rational.rb | 100 +++++++++++++------ mrbgems/mruby-rational/test/rational.rb | 41 +++++++- 7 files changed, 363 insertions(+), 73 deletions(-) diff --git a/mrbgems/default.gembox b/mrbgems/default.gembox index 501aee146..ae085309c 100644 --- a/mrbgems/default.gembox +++ b/mrbgems/default.gembox @@ -69,10 +69,10 @@ MRuby::GemBox.new do |conf| conf.gem :core => "mruby-enum-lazy" # Use Complex class - #conf.gem :core => "mruby-complex" + # conf.gem :core => "mruby-complex" # Use Rational class - #conf.gem :core => "mruby-rational" + # conf.gem :core => "mruby-rational" # Use toplevel object (main) methods extension conf.gem :core => "mruby-toplevel-ext" diff --git a/mrbgems/mruby-complex/mrbgem.rake b/mrbgems/mruby-complex/mrbgem.rake index f8f04d0b8..25b8966da 100644 --- a/mrbgems/mruby-complex/mrbgem.rake +++ b/mrbgems/mruby-complex/mrbgem.rake @@ -2,4 +2,8 @@ MRuby::Gem::Specification.new('mruby-complex') do |spec| spec.license = 'MIT' spec.author = 'mruby developers' spec.summary = 'Complex class' + + spec.add_dependency 'mruby-object-ext', core: 'mruby-object-ext' + spec.add_dependency 'mruby-numeric-ext', core: 'mruby-numeric-ext' + spec.add_dependency 'mruby-math', core: 'mruby-math' end diff --git a/mrbgems/mruby-complex/mrblib/complex.rb b/mrbgems/mruby-complex/mrblib/complex.rb index 0815c9a71..266c00c36 100644 --- a/mrbgems/mruby-complex/mrblib/complex.rb +++ b/mrbgems/mruby-complex/mrblib/complex.rb @@ -1,95 +1,168 @@ class Complex < Numeric - def initialize(real = 0, imaginary = 0) + def initialize(real, imaginary) + real = real.to_f unless real.is_a? Numeric + imaginary = imaginary.to_f unless imaginary.is_a? Numeric @real = real @imaginary = imaginary end + def self.polar(abs, arg = 0) + Complex(abs * Math.cos(arg), abs * Math.sin(arg)) + end + + def self.rectangular(real, imaginary = 0) + _new(real, imaginary) + end + def inspect "(#{to_s})" end def to_s - "#{real}#{'+'}#{imaginary}i" + "#{real}#{'+' unless imaginary.negative?}#{imaginary}i" end def +@ - Complex.new(real, imaginary) + Complex(real, imaginary) end def -@ - Complex.new(-real, -imaginary) + Complex(-real, -imaginary) end def +(rhs) if rhs.is_a? Complex - Complex.new(real + rhs.real, imaginary + rhs.imaginary) + Complex(real + rhs.real, imaginary + rhs.imaginary) elsif rhs.is_a? Numeric - Complex.new(real + rhs, imaginary) + Complex(real + rhs, imaginary) end end def -(rhs) if rhs.is_a? Complex - Complex.new(real - rhs.real, imaginary - rhs.imaginary) + Complex(real - rhs.real, imaginary - rhs.imaginary) elsif rhs.is_a? Numeric - Complex.new(real - rhs, imaginary) + Complex(real - rhs, imaginary) end end def *(rhs) if rhs.is_a? Complex - Complex.new(real * rhs.real - imaginary * rhs.imaginary, real * rhs.imaginary + rhs.real * imaginary) + Complex(real * rhs.real - imaginary * rhs.imaginary, real * rhs.imaginary + rhs.real * imaginary) elsif rhs.is_a? Numeric - Complex.new(real * rhs, imaginary * rhs) + Complex(real * rhs, imaginary * rhs) end end def /(rhs) if rhs.is_a? Complex div = rhs.real * rhs.real + rhs.imaginary * rhs.imaginary - Complex.new((real * rhs.real + imaginary * rhs.imaginary) / div, (rhs.real * imaginary - real * rhs.imaginary) / div) + Complex((real * rhs.real + imaginary * rhs.imaginary) / div, (rhs.real * imaginary - real * rhs.imaginary) / div) elsif rhs.is_a? Numeric - Complex.new(real / rhs, imaginary / rhs) + Complex(real / rhs, imaginary / rhs) end end + alias_method :quo, :/ - attr_reader :real, :imaginary -end + def ==(rhs) + if rhs.is_a? Complex + real == rhs.real && imaginary == rhs.imaginary + elsif rhs.is_a? Numeric + imaginary.zero? && real == rhs + end + end -def Complex(real = 0, imaginary = 0) - Complex.new(real, imaginary) -end + def abs + Math.sqrt(abs2) + end + alias_method :magnitude, :abs -module ForwardOperatorToComplex - def __forward_operator_to_complex(op, &b) - original_operator_name = "__original_operator_#{op}_complex" - alias_method original_operator_name, op - define_method op do |rhs| - if rhs.is_a? Complex - Complex.new(self).send(op, rhs) - else - send(original_operator_name, rhs) - end - end + def abs2 + real * real + imaginary * imaginary + end + + def arg + Math.atan2 imaginary, real + end + alias_method :angle, :arg + alias_method :phase, :arg + + def conjugate + Complex(real, -imaginary) + end + alias_method :conj, :conjugate + + def numerator + self + end + + def denominator + 1 + end + + def fdiv(numeric) + Complex(real.to_f / numeric, imaginary.to_f / numeric) + end + + def polar + [abs, arg] + end + + def real? + false end - def __forward_operators_to_complex - __forward_operator_to_complex :+ - __forward_operator_to_complex :- - __forward_operator_to_complex :* - __forward_operator_to_complex :/ + def rectangular + [real, imaginary] + end + alias_method :rect, :rectangular + + def to_c + self + end + + def to_f + raise RangeError.new "can't convert #{to_s} into Float" unless imaginary.zero? + real.to_f + end - singleton_class.undef_method :__forward_operator_to_complex - singleton_class.undef_method :__forward_operators_to_complex + def to_i + raise RangeError.new "can't convert #{to_s} into Integer" unless imaginary.zero? + real.to_i end + + def to_r + raise RangeError.new "can't convert #{to_s} into Rational" unless imaginary.zero? + Rational(real, 1) + end + + attr_reader :real, :imaginary + alias_method :imag, :imaginary +end + +class << Complex + alias_method :_new, :new + undef_method :new + + alias_method :rect, :rectangular end -class Fixnum - extend ForwardOperatorToComplex - __forward_operators_to_complex +def Complex(real, imaginary = 0) + Complex.rectangular(real, imaginary) end -class Float - extend ForwardOperatorToComplex - __forward_operators_to_complex +[Fixnum, Float].each do |cls| + [:+, :-, :*, :/, :==].each do |op| + cls.instance_exec do + original_operator_name = "__original_operator_#{op}_complex" + alias_method original_operator_name, op + define_method op do |rhs| + if rhs.is_a? Complex + Complex(self).send(op, rhs) + else + send(original_operator_name, rhs) + end + end + end + end end \ No newline at end of file diff --git a/mrbgems/mruby-complex/test/complex.rb b/mrbgems/mruby-complex/test/complex.rb index 890dd4ff1..ca58202c2 100644 --- a/mrbgems/mruby-complex/test/complex.rb +++ b/mrbgems/mruby-complex/test/complex.rb @@ -1,3 +1,130 @@ +def assert_complex(real, exp) + assert_float real.real, exp.real + assert_float real.imaginary, exp.imaginary +end + assert 'Complex' do - assert_equal Complex, 0i.class + c = 123i + assert_equal Complex, c.class + assert_equal [c.real, c.imaginary], [0, 123] + c = 123 + -1.23i + assert_equal Complex, c.class + assert_equal [c.real, c.imaginary], [123, -1.23] +end + +assert 'Complex::polar' do + assert_complex Complex.polar(3, 0), (3 + 0i) + assert_complex Complex.polar(3, Math::PI/2), (0 + 3i) + assert_complex Complex.polar(3, Math::PI), (-3 + 0i) + assert_complex Complex.polar(3, -Math::PI/2), (0 + -3i) +end + +assert 'Complex::rectangular' do + assert_complex Complex.rectangular(1, 2), (1 + 2i) +end + +assert 'Complex#*' do + assert_complex Complex(2, 3) * Complex(2, 3), (-5 + 12i) + assert_complex Complex(900) * Complex(1), (900 + 0i) + assert_complex Complex(-2, 9) * Complex(-9, 2), (0 - 85i) + assert_complex Complex(9, 8) * 4, (36 + 32i) + assert_complex Complex(20, 9) * 9.8, (196.0 + 88.2i) +end + +assert 'Complex#+' do + assert_complex Complex(2, 3) + Complex(2, 3) , (4 + 6i) + assert_complex Complex(900) + Complex(1) , (901 + 0i) + assert_complex Complex(-2, 9) + Complex(-9, 2), (-11 + 11i) + assert_complex Complex(9, 8) + 4 , (13 + 8i) + assert_complex Complex(20, 9) + 9.8 , (29.8 + 9i) +end + +assert 'Complex#-' do + assert_complex Complex(2, 3) - Complex(2, 3) , (0 + 0i) + assert_complex Complex(900) - Complex(1) , (899 + 0i) + assert_complex Complex(-2, 9) - Complex(-9, 2), (7 + 7i) + assert_complex Complex(9, 8) - 4 , (5 + 8i) + assert_complex Complex(20, 9) - 9.8 , (10.2 + 9i) +end + +assert 'Complex#-@' do + assert_complex -Complex(1, 2), (-1 - 2i) +end + +assert 'Complex#/' do + assert_complex Complex(2, 3) / Complex(2, 3) , (1 + 0i) + assert_complex Complex(900) / Complex(1) , (900 + 0i) + assert_complex Complex(-2, 9) / Complex(-9, 2), ((36 / 85) - (77i / 85)) + assert_complex Complex(9, 8) / 4 , ((9 / 4) + 2i) + assert_complex Complex(20, 9) / 9.8 , (2.0408163265306123 + 0.9183673469387754i) +end + +assert 'Complex#==' do + assert_true Complex(2, 3) == Complex(2, 3) + assert_true Complex(5) == 5 + assert_true Complex(0) == 0.0 + assert_false Complex('1/3') == 0.33 + assert_false Complex('1/2') == '1/2' +end + +assert 'Complex#abs' do + assert_float Complex(-1).abs, 1 + assert_float Complex(3.0, -4.0).abs, 5.0 +end + +assert 'Complex#abs2' do + assert_float Complex(-1).abs2, 1 + assert_float Complex(3.0, -4.0).abs2, 25.0 +end + +assert 'Complex#arg' do + assert_float Complex.polar(3, Math::PI/2).arg, 1.5707963267948966 +end + +assert 'Complex#conjugate' do + assert_complex Complex(1, 2).conjugate, (1 - 2i) +end + +assert 'Complex#fdiv' do + assert_complex Complex(11, 22).fdiv(3), (3.6666666666666665 + 7.333333333333333i) +end + +assert 'Complex#imaginary' do + assert_float Complex(7).imaginary , 0 + assert_float Complex(9, -4).imaginary, -4 +end + +assert 'Complex#polar' do + assert_equal Complex(1, 2).polar, [2.23606797749979, 1.1071487177940904] +end + +assert 'Complex#real' do + assert_float Complex(7).real, 7 + assert_float Complex(9, -4).real, 9 +end + +assert 'Complex#real?' do + assert_false Complex(1).real? +end + +assert 'Complex::rectangular' do + assert_equal Complex(1, 2).rectangular, [1, 2] +end + +assert 'Complex::to_c' do + assert_equal Complex(1, 2).to_c, Complex(1, 2) +end + +assert 'Complex::to_f' do + assert_float Complex(1, 0).to_f, 1.0 + assert_raise(RangeError) do + Complex(1, 2).to_f + end +end + +assert 'Complex::to_i' do + assert_equal Complex(1, 0).to_i, 1 + assert_raise(RangeError) do + Complex(1, 2).to_i + end end \ No newline at end of file diff --git a/mrbgems/mruby-rational/mrbgem.rake b/mrbgems/mruby-rational/mrbgem.rake index 4b540dec4..496082709 100644 --- a/mrbgems/mruby-rational/mrbgem.rake +++ b/mrbgems/mruby-rational/mrbgem.rake @@ -2,4 +2,7 @@ MRuby::Gem::Specification.new('mruby-rational') do |spec| spec.license = 'MIT' spec.author = 'mruby developers' spec.summary = 'Rational class' + + spec.add_dependency 'mruby-object-ext', core: 'mruby-object-ext' + spec.add_dependency 'mruby-numeric-ext', core: 'mruby-numeric-ext' end diff --git a/mrbgems/mruby-rational/mrblib/rational.rb b/mrbgems/mruby-rational/mrblib/rational.rb index 457c0488a..ffadd55eb 100644 --- a/mrbgems/mruby-rational/mrblib/rational.rb +++ b/mrbgems/mruby-rational/mrblib/rational.rb @@ -2,45 +2,89 @@ class Rational < Numeric def initialize(numerator = 0, denominator = 1) @numerator = numerator @denominator = denominator + + _simplify end - attr_reader :numerator, :denominator -end + def inspect + "(#{to_s})" + end -def Rational(numerator = 0, denominator = 1) - Rational.new(numerator, denominator) -end + def to_s + "#{numerator}/#{denominator}" + end -module ForwardOperatorToRational - def __forward_operator_to_rational(op, &b) - original_operator_name = "__original_operator_#{op}_rational" - alias_method original_operator_name, op - define_method op do |rhs| - if rhs.is_a? Rational - Rational.new(self).send(op, rhs) - else - send(original_operator_name, rhs) - end + def *(rhs) + if rhs.is_a? Rational + Rational(numerator * rhs.numerator, denominator * rhs.denominator) + elsif rhs.is_a? Integer + Rational(numerator * rhs, denominator) + elsif rhs.is_a? Numeric + numerator * rhs / denominator + end + end + + def +(rhs) + if rhs.is_a? Rational + Rational(numerator * rhs.denominator + rhs.numerator * denominator, denominator * rhs.denominator) + elsif rhs.is_a? Integer + Rational(numerator + rhs * denominator, denominator) + elsif rhs.is_a? Numeric + (numerator + rhs * denominator) / denominator + end + end + + def -(rhs) + if rhs.is_a? Rational + Rational(numerator * rhs.denominator - rhs.numerator * denominator, denominator * rhs.denominator) + elsif rhs.is_a? Integer + Rational(numerator - rhs * denominator, denominator) + elsif rhs.is_a? Numeric + (numerator - rhs * denominator) / denominator end end - def __forward_operators_to_rational - __forward_operator_to_rational :+ - __forward_operator_to_rational :- - __forward_operator_to_rational :* - __forward_operator_to_rational :/ + def /(rhs) + if rhs.is_a? Rational + Rational(numerator * rhs.denominator, denominator * rhs.numerator) + elsif rhs.is_a? Integer + Rational(numerator, denominator * rhs) + elsif rhs.is_a? Numeric + numerator / rhs / denominator + end + end - singleton_class.undef_method :__forward_operator_to_rational - singleton_class.undef_method :__forward_operators_to_rational + def negative? + numerator.negative? end + + def _simplify + a = numerator + b = denominator + a, b = b, a % b while !b.zero? + @numerator /= a + @denominator /= a + end + + attr_reader :numerator, :denominator end -class Fixnum - extend ForwardOperatorToRational - __forward_operators_to_rational +def Rational(numerator = 0, denominator = 1) + Rational.new(numerator, denominator) end -class Float - extend ForwardOperatorToRational - __forward_operators_to_rational +[Fixnum, Float].each do |cls| + [:+, :-, :*, :/, :==].each do |op| + cls.instance_exec do + original_operator_name = "__original_operator_#{op}_rational" + alias_method original_operator_name, op + define_method op do |rhs| + if rhs.is_a? Rational + Rational(self).send(op, rhs) + else + send(original_operator_name, rhs) + end + end + end + end end \ No newline at end of file diff --git a/mrbgems/mruby-rational/test/rational.rb b/mrbgems/mruby-rational/test/rational.rb index 6f20a6cd4..a86f00690 100644 --- a/mrbgems/mruby-rational/test/rational.rb +++ b/mrbgems/mruby-rational/test/rational.rb @@ -1,3 +1,42 @@ +def assert_rational(real, exp) + assert_float real.numerator, exp.numerator + assert_float real.denominator, exp.denominator +end + assert 'Rational' do - assert_equal Rational, 0r.class + r = 5r + assert_equal Rational, r.class + assert_equal [r.numerator, r.denominator], [5, 1] +end + +assert 'Rational#*' do + assert_rational Rational(2, 3) * Rational(2, 3), Rational(4, 9) + assert_rational Rational(900) * Rational(1), Rational(900, 1) + assert_rational Rational(-2, 9) * Rational(-9, 2), Rational(1, 1) + assert_rational Rational(9, 8) * 4, Rational(9, 2) + assert_float Rational(20, 9) * 9.8, 21.77777777777778 +end + +assert 'Rational#+' do + assert_rational Rational(2, 3) + Rational(2, 3), Rational(4, 3) + assert_rational Rational(900) + Rational(1), Rational(901, 1) + assert_rational Rational(-2, 9) + Rational(-9, 2), Rational(-85, 18) + assert_rational Rational(9, 8) + 4, Rational(41, 8) + assert_float Rational(20, 9) + 9.8, 12.022222222222222 +end + +assert 'Rational#-' do + assert_rational Rational(2, 3) - Rational(2, 3), Rational(0, 1) + assert_rational Rational(900) - Rational(1), Rational(899, 1) + assert_rational Rational(-2, 9) - Rational(-9, 2), Rational(77, 18) + assert_rational Rational(9, 8) - 4, Rational(-23, 8) + assert_float Rational(20, 9) - 9.8, -7.577777777777778 +end + +assert 'Rational#/' do + assert_rational Rational(2, 3) / Rational(2, 3), Rational(1, 1) + assert_rational Rational(900) / Rational(1), Rational(900, 1) + assert_rational Rational(-2, 9) / Rational(-9, 2), Rational(4, 81) + assert_rational Rational(9, 8) / 4, Rational(9, 32) + assert_float Rational(20, 9) / 9.8, 0.22675736961451246 end \ No newline at end of file -- cgit v1.2.3 From fa45cc42726720b89732bf43d1bf433970007c89 Mon Sep 17 00:00:00 2001 From: Ukrainskiy Sergey Date: Sat, 22 Sep 2018 16:53:56 +0900 Subject: Fix dependencies --- mrbgems/default.gembox | 6 ------ mrbgems/mruby-complex/mrbgem.rake | 1 + mrbgems/mruby-rational/mrbgem.rake | 1 + mrbgems/mruby-rational/mrblib/rational.rb | 12 ++++++++++++ mrbgems/mruby-rational/test/rational.rb | 15 +++++++++++++++ 5 files changed, 29 insertions(+), 6 deletions(-) diff --git a/mrbgems/default.gembox b/mrbgems/default.gembox index ae085309c..23e65fcee 100644 --- a/mrbgems/default.gembox +++ b/mrbgems/default.gembox @@ -68,12 +68,6 @@ MRuby::GemBox.new do |conf| # Use Enumerator::Lazy class (require mruby-enumerator) conf.gem :core => "mruby-enum-lazy" - # Use Complex class - # conf.gem :core => "mruby-complex" - - # Use Rational class - # conf.gem :core => "mruby-rational" - # Use toplevel object (main) methods extension conf.gem :core => "mruby-toplevel-ext" diff --git a/mrbgems/mruby-complex/mrbgem.rake b/mrbgems/mruby-complex/mrbgem.rake index 25b8966da..19612e74d 100644 --- a/mrbgems/mruby-complex/mrbgem.rake +++ b/mrbgems/mruby-complex/mrbgem.rake @@ -3,6 +3,7 @@ MRuby::Gem::Specification.new('mruby-complex') do |spec| spec.author = 'mruby developers' spec.summary = 'Complex class' + spec.add_dependency 'mruby-metaprog', core: 'mruby-metaprog' spec.add_dependency 'mruby-object-ext', core: 'mruby-object-ext' spec.add_dependency 'mruby-numeric-ext', core: 'mruby-numeric-ext' spec.add_dependency 'mruby-math', core: 'mruby-math' diff --git a/mrbgems/mruby-rational/mrbgem.rake b/mrbgems/mruby-rational/mrbgem.rake index 496082709..93f5b601c 100644 --- a/mrbgems/mruby-rational/mrbgem.rake +++ b/mrbgems/mruby-rational/mrbgem.rake @@ -3,6 +3,7 @@ MRuby::Gem::Specification.new('mruby-rational') do |spec| spec.author = 'mruby developers' spec.summary = 'Rational class' + spec.add_dependency 'mruby-metaprog', core: 'mruby-metaprog' spec.add_dependency 'mruby-object-ext', core: 'mruby-object-ext' spec.add_dependency 'mruby-numeric-ext', core: 'mruby-numeric-ext' end diff --git a/mrbgems/mruby-rational/mrblib/rational.rb b/mrbgems/mruby-rational/mrblib/rational.rb index ffadd55eb..7d5b87362 100644 --- a/mrbgems/mruby-rational/mrblib/rational.rb +++ b/mrbgems/mruby-rational/mrblib/rational.rb @@ -10,6 +10,18 @@ class Rational < Numeric "(#{to_s})" end + def to_f + @numerator.to_f / @denominator.to_f + end + + def to_i + to_f.to_i + end + + def to_r + self + end + def to_s "#{numerator}/#{denominator}" end diff --git a/mrbgems/mruby-rational/test/rational.rb b/mrbgems/mruby-rational/test/rational.rb index a86f00690..85cebc316 100644 --- a/mrbgems/mruby-rational/test/rational.rb +++ b/mrbgems/mruby-rational/test/rational.rb @@ -9,6 +9,21 @@ assert 'Rational' do assert_equal [r.numerator, r.denominator], [5, 1] end +assert 'Rational#to_f' do + assert_float Rational(2).to_f, 2.0 + assert_float Rational(9, 4).to_f, 2.25 + assert_float Rational(-3, 4).to_f, -0.75 + assert_float Rational(20, 3).to_f, 6.666666666666667 +end + +assert 'Rational#to_i' do + assert_equal Rational(2, 3).to_i, 0 + assert_equal Rational(3).to_i, 3 + assert_equal Rational(300.6).to_i, 300 + assert_equal Rational(98, 71).to_i, 1 + assert_equal Rational(-30, 2).to_i, -15 +end + assert 'Rational#*' do assert_rational Rational(2, 3) * Rational(2, 3), Rational(4, 9) assert_rational Rational(900) * Rational(1), Rational(900, 1) -- cgit v1.2.3 From 31bfc5586615a759b3c415ec8550ee67827bd296 Mon Sep 17 00:00:00 2001 From: Ukrainskiy Sergey Date: Sat, 22 Sep 2018 17:23:03 +0900 Subject: Fix --- mrbgems/mruby-compiler/core/parse.y | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mrbgems/mruby-compiler/core/parse.y b/mrbgems/mruby-compiler/core/parse.y index 2c5e0c991..3ad11f406 100644 --- a/mrbgems/mruby-compiler/core/parse.y +++ b/mrbgems/mruby-compiler/core/parse.y @@ -5189,7 +5189,7 @@ parser_yylex(parser_state *p) case '5': case '6': case '7': case '8': case '9': { int is_float, seen_point, seen_e, nondigit; - int suffix; + int suffix = 0; is_float = seen_point = seen_e = nondigit = 0; p->lstate = EXPR_ENDARG; -- cgit v1.2.3 From 936f72fdd239e37474b51e2af6d2041a9f018693 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Wed, 15 May 2019 16:58:35 +0900 Subject: Do not overwrite `conf.cc.defines`. --- appveyor_config.rb | 2 +- travis_config.rb | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/appveyor_config.rb b/appveyor_config.rb index 2555b2f62..b50a9e4ef 100644 --- a/appveyor_config.rb +++ b/appveyor_config.rb @@ -17,7 +17,7 @@ MRuby::Build.new('full-debug') do |conf| # include all core GEMs conf.gembox 'full-core' - conf.cc.defines = %w(MRB_ENABLE_DEBUG_HOOK) + conf.cc.defines += %w(MRB_ENABLE_DEBUG_HOOK) conf.enable_test end diff --git a/travis_config.rb b/travis_config.rb index e12bae648..7a13ced72 100644 --- a/travis_config.rb +++ b/travis_config.rb @@ -18,7 +18,7 @@ MRuby::Build.new('full-debug') do |conf| # include all core GEMs conf.gembox 'full-core' - conf.cc.defines = %w(MRB_ENABLE_DEBUG_HOOK) + conf.cc.defines += %w(MRB_ENABLE_DEBUG_HOOK) conf.enable_test end -- cgit v1.2.3 From 752edf413f09fb3e78d79ca7d752ae5dc2e25c02 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Thu, 16 May 2019 09:51:27 +0900 Subject: Terminate float right shift if shift value is too big. --- src/numeric.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/numeric.c b/src/numeric.c index 101b338de..5dbf9df22 100644 --- a/src/numeric.c +++ b/src/numeric.c @@ -484,6 +484,10 @@ flo_shift(mrb_state *mrb, mrb_value x, mrb_int width) if (width < 0) { while (width++) { val /= 2; + if (val < 1.0) { + val = 0; + break; + } } #if defined(_ISOC99_SOURCE) val = trunc(val); -- cgit v1.2.3 From 2f1425414226f4ff6698de99b0d1b743368cdb39 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Thu, 16 May 2019 10:13:52 +0900 Subject: Avoid potential integer overflow. --- mrbgems/mruby-pack/src/pack.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/mrbgems/mruby-pack/src/pack.c b/mrbgems/mruby-pack/src/pack.c index ac29fdbf3..0c4f0d965 100644 --- a/mrbgems/mruby-pack/src/pack.c +++ b/mrbgems/mruby-pack/src/pack.c @@ -1075,10 +1075,11 @@ alias: if (ISDIGIT(ch)) { count = ch - '0'; while (tmpl->idx < tlen && ISDIGIT(tptr[tmpl->idx])) { - count = count * 10 + (tptr[tmpl->idx++] - '0'); - if (count < 0) { + int ch = tptr[tmpl->idx++] - '0'; + if (count+ch > INT_MAX/10) { mrb_raise(mrb, E_RUNTIME_ERROR, "too big template length"); } + count = count * 10 + ch; } continue; /* special case */ } else if (ch == '*') { -- cgit v1.2.3 From 7aff5507dddf63dab578165471205b674e28524c Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Thu, 16 May 2019 10:15:11 +0900 Subject: Avoid potential type mismatch warnings in `pack.c`. --- mrbgems/mruby-pack/src/pack.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/mrbgems/mruby-pack/src/pack.c b/mrbgems/mruby-pack/src/pack.c index 0c4f0d965..75a447d6c 100644 --- a/mrbgems/mruby-pack/src/pack.c +++ b/mrbgems/mruby-pack/src/pack.c @@ -118,9 +118,9 @@ make_base64_dec_tab(void) base64_dec_tab['a' + i] = i + 26; for (i = 0; i < 10; i++) base64_dec_tab['0' + i] = i + 52; - base64_dec_tab['+'] = 62; - base64_dec_tab['/'] = 63; - base64_dec_tab['='] = PACK_BASE64_PADDING; + base64_dec_tab['+'+0] = 62; + base64_dec_tab['/'+0] = 63; + base64_dec_tab['='+0] = PACK_BASE64_PADDING; } static mrb_value -- cgit v1.2.3 From 304b52fabe1c9672adac79dcc7777b07a468b6a4 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Thu, 16 May 2019 11:44:51 +0900 Subject: Set maximum string (and symbol) size to 65534 (`UINT16_MAX-1`). The previous value (`UINT16_MAX`) was too long for symbols, so it raises an exception after the length check. --- include/mruby/compile.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/mruby/compile.h b/include/mruby/compile.h index f19d9b0b3..8f8f2ebd7 100644 --- a/include/mruby/compile.h +++ b/include/mruby/compile.h @@ -105,7 +105,7 @@ struct mrb_parser_heredoc_info { mrb_ast_node *doc; }; -#define MRB_PARSER_TOKBUF_MAX 65536 +#define MRB_PARSER_TOKBUF_MAX (UINT16_MAX-1) #define MRB_PARSER_TOKBUF_SIZE 256 /* parser structure */ -- cgit v1.2.3 From 9b604abc8300d378bb32fb0e88d6f0831ed7e0d9 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Thu, 16 May 2019 11:46:37 +0900 Subject: Enable `YYSTACK_USE_ALLOCA`. It used heap allocated memory for the parser stack, but there's possibility of parser termination by exceptions. In that case, the parser stack memory is leaked. We were afraid of stack consumption, but parser stack size is only 4KB, so we don't have to worry about it (at least for the parser). --- mrbgems/mruby-compiler/core/parse.y | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/mrbgems/mruby-compiler/core/parse.y b/mrbgems/mruby-compiler/core/parse.y index 3ad11f406..37d4d1bf1 100644 --- a/mrbgems/mruby-compiler/core/parse.y +++ b/mrbgems/mruby-compiler/core/parse.y @@ -10,13 +10,7 @@ # define YYDEBUG 1 #endif #define YYERROR_VERBOSE 1 -/* - * Force yacc to use our memory management. This is a little evil because - * the macros assume that "parser_state *p" is in scope - */ -#define YYMALLOC(n) mrb_malloc(p->mrb, (n)) -#define YYFREE(o) mrb_free(p->mrb, (o)) -#define YYSTACK_USE_ALLOCA 0 +#define YYSTACK_USE_ALLOCA 1 #include #include -- cgit v1.2.3 From f5fb1307b017fb972c12b4ec4b1866d789b0ca09 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Thu, 16 May 2019 22:09:56 +0900 Subject: Fix `Rational#==` --- mrbgems/mruby-rational/mrbgem.rake | 1 - mrbgems/mruby-rational/mrblib/rational.rb | 29 +++++++++++++++--- mrbgems/mruby-rational/test/rational.rb | 49 +++++++++++++++++++++++++++++-- 3 files changed, 72 insertions(+), 7 deletions(-) diff --git a/mrbgems/mruby-rational/mrbgem.rake b/mrbgems/mruby-rational/mrbgem.rake index 93f5b601c..496082709 100644 --- a/mrbgems/mruby-rational/mrbgem.rake +++ b/mrbgems/mruby-rational/mrbgem.rake @@ -3,7 +3,6 @@ MRuby::Gem::Specification.new('mruby-rational') do |spec| spec.author = 'mruby developers' spec.summary = 'Rational class' - spec.add_dependency 'mruby-metaprog', core: 'mruby-metaprog' spec.add_dependency 'mruby-object-ext', core: 'mruby-object-ext' spec.add_dependency 'mruby-numeric-ext', core: 'mruby-numeric-ext' end diff --git a/mrbgems/mruby-rational/mrblib/rational.rb b/mrbgems/mruby-rational/mrblib/rational.rb index 7d5b87362..dbc855af0 100644 --- a/mrbgems/mruby-rational/mrblib/rational.rb +++ b/mrbgems/mruby-rational/mrblib/rational.rb @@ -1,4 +1,7 @@ class Rational < Numeric + # Override #<, #<=, #>, #>= in Numeric + prepend Comparable + def initialize(numerator = 0, denominator = 1) @numerator = numerator @denominator = denominator @@ -66,6 +69,24 @@ class Rational < Numeric end end + def <=>(rhs) + case rhs + when Fixnum + return @numerator <=> rhs if @denominator == 1 + rhs = Rational(rhs) + when Float + return to_f <=> rhs + end + case rhs + when Rational + (@numerator * rhs.denominator - @denominator * rhs.numerator) <=> 0 + when Numeric + return rhs <=> self + else + nil + end + end + def negative? numerator.negative? end @@ -86,17 +107,17 @@ def Rational(numerator = 0, denominator = 1) end [Fixnum, Float].each do |cls| - [:+, :-, :*, :/, :==].each do |op| + [:+, :-, :*, :/, :<=>, :==, :<, :<=, :>, :>=].each do |op| cls.instance_exec do original_operator_name = "__original_operator_#{op}_rational" alias_method original_operator_name, op define_method op do |rhs| if rhs.is_a? Rational - Rational(self).send(op, rhs) + Rational(self).__send__(op, rhs) else - send(original_operator_name, rhs) + __send__(original_operator_name, rhs) end end end end -end \ No newline at end of file +end diff --git a/mrbgems/mruby-rational/test/rational.rb b/mrbgems/mruby-rational/test/rational.rb index 85cebc316..4d3d36ccc 100644 --- a/mrbgems/mruby-rational/test/rational.rb +++ b/mrbgems/mruby-rational/test/rational.rb @@ -1,8 +1,18 @@ def assert_rational(real, exp) - assert_float real.numerator, exp.numerator + assert_float real.numerator, exp.numerator assert_float real.denominator, exp.denominator end +def assert_equal_rational(exp, r1, r2) + if exp + assert_operator(r1, :==, r2) + assert_not_operator(r1, :!=, r2) + else + assert_not_operator(r1, :==, r2) + assert_operator(r1, :!=, r2) + end +end + assert 'Rational' do r = 5r assert_equal Rational, r.class @@ -54,4 +64,39 @@ assert 'Rational#/' do assert_rational Rational(-2, 9) / Rational(-9, 2), Rational(4, 81) assert_rational Rational(9, 8) / 4, Rational(9, 32) assert_float Rational(20, 9) / 9.8, 0.22675736961451246 -end \ No newline at end of file +end + +assert 'Rational#==, Rational#!=' do + assert_equal_rational(true, Rational(1,1), Rational(1)) + assert_equal_rational(true, Rational(-1,1), -1r) + assert_equal_rational(true, Rational(13,4), 3.25) + assert_equal_rational(true, Rational(13,3.25), Rational(4,1)) + assert_equal_rational(true, Rational(-3,-4), Rational(3,4)) + assert_equal_rational(true, Rational(-4,5), Rational(4,-5)) + assert_equal_rational(true, Rational(4,2), 2) + assert_equal_rational(true, Rational(-4,2), -2) + assert_equal_rational(true, Rational(4,-2), -2) + assert_equal_rational(true, Rational(4,2), 2.0) + assert_equal_rational(true, Rational(-4,2), -2.0) + assert_equal_rational(true, Rational(4,-2), -2.0) + assert_equal_rational(true, Rational(8,6), Rational(4,3)) + assert_equal_rational(false, Rational(13,4), 3) + assert_equal_rational(false, Rational(13,4), 3.3) + assert_equal_rational(false, Rational(2,1), 1r) + assert_equal_rational(false, Rational(1), nil) + assert_equal_rational(false, Rational(1), '') +end + +assert 'Fixnum#==(Rational), Fixnum#!=(Rational)' do + assert_equal_rational(true, 2, Rational(4,2)) + assert_equal_rational(true, -2, Rational(-4,2)) + assert_equal_rational(true, -2, Rational(4,-2)) + assert_equal_rational(false, 3, Rational(13,4)) +end + +assert 'Float#==(Rational), Float#!=(Rational)' do + assert_equal_rational(true, 2.0, Rational(4,2)) + assert_equal_rational(true, -2.0, Rational(-4,2)) + assert_equal_rational(true, -2.0, Rational(4,-2)) + assert_equal_rational(false, 3.3, Rational(13,4)) +end -- cgit v1.2.3 From 4bc48d0b76924f936dc389406c68ed1a8e144e9c Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Thu, 16 May 2019 13:37:36 +0900 Subject: Refactor `time.c` regarding memory allocation. --- mrbgems/mruby-time/src/time.c | 28 ++++++++++++++++------------ 1 file changed, 16 insertions(+), 12 deletions(-) diff --git a/mrbgems/mruby-time/src/time.c b/mrbgems/mruby-time/src/time.c index b5a540d09..34376c286 100644 --- a/mrbgems/mruby-time/src/time.c +++ b/mrbgems/mruby-time/src/time.c @@ -205,17 +205,18 @@ static struct mrb_time* time_update_datetime(mrb_state *mrb, struct mrb_time *self, int dealloc) { struct tm *aid; + time_t t = self->sec; if (self->timezone == MRB_TIMEZONE_UTC) { - aid = gmtime_r(&self->sec, &self->datetime); + aid = gmtime_r(&t, &self->datetime); } else { - aid = localtime_r(&self->sec, &self->datetime); + aid = localtime_r(&t, &self->datetime); } if (!aid) { - mrb_float sec = (mrb_float)self->sec; + mrb_float sec = (mrb_float)t; - mrb_free(mrb, self); + if (dealloc) mrb_free(mrb, self); mrb_raisef(mrb, E_ARGUMENT_ERROR, "%S out of Time range", mrb_float_value(mrb, sec)); /* not reached */ return NULL; @@ -292,24 +293,24 @@ mrb_time_make(mrb_state *mrb, struct RClass *c, double sec, double usec, enum mr static struct mrb_time* current_mrb_time(mrb_state *mrb) { + struct mrb_time tmzero = {0}; struct mrb_time *tm; + time_t sec, usec; - tm = (struct mrb_time *)mrb_malloc(mrb, sizeof(*tm)); #if defined(TIME_UTC) && !defined(__ANDROID__) { struct timespec ts; if (timespec_get(&ts, TIME_UTC) == 0) { - mrb_free(mrb, tm); mrb_raise(mrb, E_RUNTIME_ERROR, "timespec_get() failed for unknown reasons"); } - tm->sec = ts.tv_sec; - tm->usec = ts.tv_nsec / 1000; + sec = ts.tv_sec; + usec = ts.tv_nsec / 1000; } #elif defined(NO_GETTIMEOFDAY) { static time_t last_sec = 0, last_usec = 0; - tm->sec = time(NULL); + sec = time(NULL); if (tm->sec != last_sec) { last_sec = tm->sec; last_usec = 0; @@ -318,17 +319,20 @@ current_mrb_time(mrb_state *mrb) /* add 1 usec to differentiate two times */ last_usec += 1; } - tm->usec = last_usec; + usec = last_usec; } #else { struct timeval tv; gettimeofday(&tv, NULL); - tm->sec = tv.tv_sec; - tm->usec = tv.tv_usec; + sec = tv.tv_sec; + usec = tv.tv_usec; } #endif + tm = (struct mrb_time *)mrb_malloc(mrb, sizeof(*tm)); + *tm = tmzero; + tm->sec = sec; tm->usec = usec; tm->timezone = MRB_TIMEZONE_LOCAL; time_update_datetime(mrb, tm, TRUE); -- cgit v1.2.3 From 283530b19b4140301a395d34c49f3188373dd69d Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Fri, 17 May 2019 10:37:49 +0900 Subject: Use `mrb_float` instead of `double` in `FIXABLE_FLOAT`. --- include/mruby/numeric.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/mruby/numeric.h b/include/mruby/numeric.h index da9225aaa..9a04631d6 100644 --- a/include/mruby/numeric.h +++ b/include/mruby/numeric.h @@ -23,7 +23,7 @@ MRB_BEGIN_DECL #define NEGFIXABLE(f) TYPED_NEGFIXABLE(f,mrb_int) #define FIXABLE(f) TYPED_FIXABLE(f,mrb_int) #ifndef MRB_WITHOUT_FLOAT -#define FIXABLE_FLOAT(f) TYPED_FIXABLE(f,double) +#define FIXABLE_FLOAT(f) TYPED_FIXABLE(f,mrb_float) #endif #ifndef MRB_WITHOUT_FLOAT -- cgit v1.2.3 From 80c789b3941160312ac7ffed202abe8c23bc0628 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Fri, 17 May 2019 10:40:19 +0900 Subject: Use `int64_t` instead of `mrb_int` in `int64_value`. --- src/numeric.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/numeric.c b/src/numeric.c index 5dbf9df22..113413502 100644 --- a/src/numeric.c +++ b/src/numeric.c @@ -421,7 +421,7 @@ value_int64(mrb_state *mrb, mrb_value x) static mrb_value int64_value(mrb_state *mrb, int64_t v) { - if (FIXABLE(v)) { + if (TYPED_FIXABLE(v,int64_t)) { return mrb_fixnum_value((mrb_int)v); } return mrb_float_value(mrb, (mrb_float)v); -- cgit v1.2.3 From 8a9f984eb8771a3d4956783116f972d4f5f70dfd Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Fri, 17 May 2019 10:42:16 +0900 Subject: Add a new function `mrb_int_value`. This function returns `Fixnum` if the value fits in `mrb_int`, otherwise it returns `Float` value (mruby behavior of handling integers). --- src/numeric.c | 29 +++++++++++++---------------- 1 file changed, 13 insertions(+), 16 deletions(-) diff --git a/src/numeric.c b/src/numeric.c index 113413502..30b6b230e 100644 --- a/src/numeric.c +++ b/src/numeric.c @@ -44,6 +44,15 @@ mrb_to_flo(mrb_state *mrb, mrb_value val) } return mrb_float(val); } + +static mrb_value +mrb_int_value(mrb_state *mrb, mrb_float f) +{ + if (FIXABLE_FLOAT(f)) { + return mrb_fixnum_value((mrb_int)f); + } + return mrb_float_value(mrb, f); +} #endif /* @@ -507,10 +516,7 @@ flo_shift(mrb_state *mrb, mrb_value x, mrb_int width) val *= 2; } } - if (FIXABLE_FLOAT(val)) { - return mrb_fixnum_value((mrb_int)val); - } - return mrb_float_value(mrb, val); + return mrb_int_value(mrb, val); } static mrb_value @@ -616,10 +622,7 @@ flo_floor(mrb_state *mrb, mrb_value num) mrb_float f = floor(mrb_float(num)); mrb_check_num_exact(mrb, f); - if (!FIXABLE_FLOAT(f)) { - return mrb_float_value(mrb, f); - } - return mrb_fixnum_value((mrb_int)f); + return mrb_int_value(mrb, f); } /* 15.2.9.3.8 */ @@ -642,10 +645,7 @@ flo_ceil(mrb_state *mrb, mrb_value num) mrb_float f = ceil(mrb_float(num)); mrb_check_num_exact(mrb, f); - if (!FIXABLE_FLOAT(f)) { - return mrb_float_value(mrb, f); - } - return mrb_fixnum_value((mrb_int)f); + return mrb_int_value(mrb, f); } /* 15.2.9.3.12 */ @@ -748,10 +748,7 @@ flo_truncate(mrb_state *mrb, mrb_value num) if (f < 0.0) f = ceil(f); mrb_check_num_exact(mrb, f); - if (!FIXABLE_FLOAT(f)) { - return mrb_float_value(mrb, f); - } - return mrb_fixnum_value((mrb_int)f); + return mrb_int_value(mrb, f); } static mrb_value -- cgit v1.2.3 From bc18060149fae9121fe744544521ca58989010ae Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Fri, 17 May 2019 10:44:56 +0900 Subject: Change the `num.divmod(float)` to return `[int,num]`. --- src/numeric.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/numeric.c b/src/numeric.c index 30b6b230e..ab8771e1a 100644 --- a/src/numeric.c +++ b/src/numeric.c @@ -934,7 +934,7 @@ fix_divmod(mrb_state *mrb, mrb_value x) mrb_value a, b; flodivmod(mrb, (mrb_float)mrb_fixnum(x), mrb_to_flo(mrb, y), &div, &mod); - a = mrb_float_value(mrb, div); + a = mrb_int_value(mrb, div); b = mrb_float_value(mrb, mod); return mrb_assoc_new(mrb, a, b); } @@ -952,7 +952,7 @@ flo_divmod(mrb_state *mrb, mrb_value x) mrb_get_args(mrb, "o", &y); flodivmod(mrb, mrb_float(x), mrb_to_flo(mrb, y), &div, &mod); - a = mrb_float_value(mrb, div); + a = mrb_int_value(mrb, div); b = mrb_float_value(mrb, mod); return mrb_assoc_new(mrb, a, b); } -- cgit v1.2.3 From 3734c53eb8e5fd34f572b62e2f85ed43b4f6d921 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Fri, 17 May 2019 11:13:12 +0900 Subject: Make `flo_rount` to return `Integeral`. --- src/numeric.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/numeric.c b/src/numeric.c index ab8771e1a..954e91019 100644 --- a/src/numeric.c +++ b/src/numeric.c @@ -726,7 +726,7 @@ flo_round(mrb_state *mrb, mrb_value num) if (!isfinite(number)) return num; return mrb_float_value(mrb, number); } - return mrb_fixnum_value((mrb_int)number); + return mrb_int_value(mrb, number); } /* 15.2.9.3.14 */ -- cgit v1.2.3 From 223defd62ae511786a2b50c68ed97b73bfc05d59 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Fri, 17 May 2019 11:26:16 +0900 Subject: Move `Numeric#div` to the core. --- mrbgems/mruby-numeric-ext/mrblib/numeric_ext.rb | 4 ---- src/numeric.c | 20 ++++++++++++++++++++ 2 files changed, 20 insertions(+), 4 deletions(-) diff --git a/mrbgems/mruby-numeric-ext/mrblib/numeric_ext.rb b/mrbgems/mruby-numeric-ext/mrblib/numeric_ext.rb index f250538fe..e86e8b283 100644 --- a/mrbgems/mruby-numeric-ext/mrblib/numeric_ext.rb +++ b/mrbgems/mruby-numeric-ext/mrblib/numeric_ext.rb @@ -1,8 +1,4 @@ module Integral - def div(other) - self.divmod(other)[0] - end - def zero? self == 0 end diff --git a/src/numeric.c b/src/numeric.c index 954e91019..8c17635a2 100644 --- a/src/numeric.c +++ b/src/numeric.c @@ -136,6 +136,25 @@ mrb_num_div(mrb_state *mrb, mrb_value x, mrb_value y) #endif } +static mrb_value +num_idiv(mrb_state *mrb, mrb_value x) +{ +#ifdef MRB_WITHOUT_FLOAT + mrb_value y; + + mrb_get_args(mrb, "o", &y); + if (!mrb_fixnum_p(y)) { + mrb_raise(mrb, E_TYPE_ERROR, "non fixnum value"); + } + return mrb_fixnum_value(mrb_fixnum(x) / mrb_fixnum(y)); +#else + mrb_float y; + + mrb_get_args(mrb, "f", &y); + return mrb_int_value(mrb, mrb_to_flo(mrb, x) / y); +#endif +} + /* 15.2.9.3.19(x) */ /* * call-seq: @@ -1552,6 +1571,7 @@ mrb_init_numeric(mrb_state *mrb) mrb_define_method(mrb, numeric, "**", num_pow, MRB_ARGS_REQ(1)); mrb_define_method(mrb, numeric, "/", num_div, MRB_ARGS_REQ(1)); /* 15.2.8.3.4 */ mrb_define_method(mrb, numeric, "quo", num_div, MRB_ARGS_REQ(1)); /* 15.2.7.4.5 (x) */ + mrb_define_method(mrb, numeric, "div", num_idiv, MRB_ARGS_REQ(1)); mrb_define_method(mrb, numeric, "<=>", num_cmp, MRB_ARGS_REQ(1)); /* 15.2.9.3.6 */ mrb_define_method(mrb, numeric, "<", num_lt, MRB_ARGS_REQ(1)); mrb_define_method(mrb, numeric, "<=", num_le, MRB_ARGS_REQ(1)); -- cgit v1.2.3 From 0c91da257bf64769d85a709852cfa2da313a4185 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Fri, 17 May 2019 11:27:21 +0900 Subject: Remove unused `mrb_num_div()` function. --- include/mruby/numeric.h | 1 - src/numeric.c | 35 +++++++++++------------------------ 2 files changed, 11 insertions(+), 25 deletions(-) diff --git a/include/mruby/numeric.h b/include/mruby/numeric.h index 9a04631d6..2fae3142d 100644 --- a/include/mruby/numeric.h +++ b/include/mruby/numeric.h @@ -39,7 +39,6 @@ MRB_API mrb_float mrb_to_flo(mrb_state *mrb, mrb_value x); mrb_value mrb_fixnum_plus(mrb_state *mrb, mrb_value x, mrb_value y); mrb_value mrb_fixnum_minus(mrb_state *mrb, mrb_value x, mrb_value y); mrb_value mrb_fixnum_mul(mrb_state *mrb, mrb_value x, mrb_value y); -mrb_value mrb_num_div(mrb_state *mrb, mrb_value x, mrb_value y); #ifndef __has_builtin #define __has_builtin(x) 0 diff --git a/src/numeric.c b/src/numeric.c index 8c17635a2..8e5fefa04 100644 --- a/src/numeric.c +++ b/src/numeric.c @@ -112,30 +112,6 @@ num_pow(mrb_state *mrb, mrb_value x) #endif } -/* 15.2.8.3.4 */ -/* 15.2.9.3.4 */ -/* - * call-seq: - * num / other -> num - * - * Performs division: the class of the resulting object depends on - * the class of num and on the magnitude of the - * result. - */ - -mrb_value -mrb_num_div(mrb_state *mrb, mrb_value x, mrb_value y) -{ -#ifdef MRB_WITHOUT_FLOAT - if (!mrb_fixnum_p(y)) { - mrb_raise(mrb, E_TYPE_ERROR, "non fixnum value"); - } - return mrb_fixnum_value(mrb_fixnum(x) / mrb_fixnum(y)); -#else - return mrb_float_value(mrb, mrb_to_flo(mrb, x) / mrb_to_flo(mrb, y)); -#endif -} - static mrb_value num_idiv(mrb_state *mrb, mrb_value x) { @@ -155,6 +131,17 @@ num_idiv(mrb_state *mrb, mrb_value x) #endif } +/* 15.2.8.3.4 */ +/* 15.2.9.3.4 */ +/* + * call-seq: + * num / other -> num + * + * Performs division: the class of the resulting object depends on + * the class of num and on the magnitude of the + * result. + */ + /* 15.2.9.3.19(x) */ /* * call-seq: -- cgit v1.2.3 From 0d61bcd823df74c65d8d5a3f8e36661780f92914 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Fri, 17 May 2019 11:27:52 +0900 Subject: Use `div` (integer divition) instead of `/` for rational numbers. --- mrbgems/mruby-rational/mrblib/rational.rb | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/mrbgems/mruby-rational/mrblib/rational.rb b/mrbgems/mruby-rational/mrblib/rational.rb index dbc855af0..30aaef915 100644 --- a/mrbgems/mruby-rational/mrblib/rational.rb +++ b/mrbgems/mruby-rational/mrblib/rational.rb @@ -94,9 +94,9 @@ class Rational < Numeric def _simplify a = numerator b = denominator - a, b = b, a % b while !b.zero? - @numerator /= a - @denominator /= a + a, b = b, a % b until b.zero? + @numerator = @numerator.div(a) + @denominator = @denominator.div(a) end attr_reader :numerator, :denominator -- cgit v1.2.3 From 237a57bbe831c57d3ebb0f9cc69768dbc8dda589 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Fri, 17 May 2019 11:30:38 +0900 Subject: Make unused functions private. * mrb_fixnum_plus() * mrb_fixnum_minus() * mrb_fixnum_mul() --- include/mruby/numeric.h | 4 ---- src/numeric.c | 6 +++--- 2 files changed, 3 insertions(+), 7 deletions(-) diff --git a/include/mruby/numeric.h b/include/mruby/numeric.h index 2fae3142d..9d87ca5c4 100644 --- a/include/mruby/numeric.h +++ b/include/mruby/numeric.h @@ -36,10 +36,6 @@ MRB_API mrb_value mrb_float_to_str(mrb_state *mrb, mrb_value x, const char *fmt) MRB_API mrb_float mrb_to_flo(mrb_state *mrb, mrb_value x); #endif -mrb_value mrb_fixnum_plus(mrb_state *mrb, mrb_value x, mrb_value y); -mrb_value mrb_fixnum_minus(mrb_state *mrb, mrb_value x, mrb_value y); -mrb_value mrb_fixnum_mul(mrb_state *mrb, mrb_value x, mrb_value y); - #ifndef __has_builtin #define __has_builtin(x) 0 #endif diff --git a/src/numeric.c b/src/numeric.c index 8e5fefa04..6622a46e9 100644 --- a/src/numeric.c +++ b/src/numeric.c @@ -787,7 +787,7 @@ int_to_i(mrb_state *mrb, mrb_value num) return num; } -mrb_value +static mrb_value mrb_fixnum_mul(mrb_state *mrb, mrb_value x, mrb_value y) { mrb_int a; @@ -1244,7 +1244,7 @@ mrb_flo_to_fixnum(mrb_state *mrb, mrb_value x) } #endif -mrb_value +static mrb_value mrb_fixnum_plus(mrb_state *mrb, mrb_value x, mrb_value y) { mrb_int a; @@ -1287,7 +1287,7 @@ fix_plus(mrb_state *mrb, mrb_value self) return mrb_fixnum_plus(mrb, self, other); } -mrb_value +static mrb_value mrb_fixnum_minus(mrb_state *mrb, mrb_value x, mrb_value y) { mrb_int a; -- cgit v1.2.3 From 912d23634d60def0c6a370b059f69999fe363c9b Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Fri, 17 May 2019 16:18:46 +0900 Subject: Fixed wrong overloading. `float op rational` should return `float`, since float is an inexact value. --- mrbgems/mruby-rational/mrblib/rational.rb | 30 +++++++++++++++++++----------- 1 file changed, 19 insertions(+), 11 deletions(-) diff --git a/mrbgems/mruby-rational/mrblib/rational.rb b/mrbgems/mruby-rational/mrblib/rational.rb index 30aaef915..82ae98425 100644 --- a/mrbgems/mruby-rational/mrblib/rational.rb +++ b/mrbgems/mruby-rational/mrblib/rational.rb @@ -106,18 +106,26 @@ def Rational(numerator = 0, denominator = 1) Rational.new(numerator, denominator) end -[Fixnum, Float].each do |cls| - [:+, :-, :*, :/, :<=>, :==, :<, :<=, :>, :>=].each do |op| - cls.instance_exec do - original_operator_name = "__original_operator_#{op}_rational" - alias_method original_operator_name, op - define_method op do |rhs| - if rhs.is_a? Rational - Rational(self).__send__(op, rhs) - else - __send__(original_operator_name, rhs) - end +[:+, :-, :*, :/, :<=>, :==, :<, :<=, :>, :>=].each do |op| + Fixnum.instance_exec do + original_operator_name = "__original_operator_#{op}_rational" + alias_method original_operator_name, op + define_method op do |rhs| + if rhs.is_a? Rational + Rational(self).__send__(op, rhs) + else + __send__(original_operator_name, rhs) end end end + Float.instance_exec do + original_operator_name = "__original_operator_#{op}_rational" + alias_method original_operator_name, op + define_method op do |rhs| + if rhs.is_a? Rational + rhs = rhs.to_f + end + __send__(original_operator_name, rhs) + end + end end -- cgit v1.2.3 From cec92673ae9e24d73a6feb2d69602b5fa60dcddd Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Fri, 17 May 2019 16:22:23 +0900 Subject: Avoid direct access to instance variables in `rational.rb`. --- mrbgems/mruby-rational/mrblib/rational.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mrbgems/mruby-rational/mrblib/rational.rb b/mrbgems/mruby-rational/mrblib/rational.rb index 82ae98425..a38f71407 100644 --- a/mrbgems/mruby-rational/mrblib/rational.rb +++ b/mrbgems/mruby-rational/mrblib/rational.rb @@ -72,14 +72,14 @@ class Rational < Numeric def <=>(rhs) case rhs when Fixnum - return @numerator <=> rhs if @denominator == 1 + return numerator <=> rhs if denominator == 1 rhs = Rational(rhs) when Float return to_f <=> rhs end case rhs when Rational - (@numerator * rhs.denominator - @denominator * rhs.numerator) <=> 0 + (numerator * rhs.denominator - denominator * rhs.numerator) <=> 0 when Numeric return rhs <=> self else -- cgit v1.2.3 From b6e9fab64949b91f00d07c890935642f44147615 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Fri, 17 May 2019 16:37:34 +0900 Subject: Implement part of `Rational` in C. --- mrbgems/mruby-rational/mrblib/rational.rb | 43 +++++---------- mrbgems/mruby-rational/src/rational.c | 90 +++++++++++++++++++++++++++++++ 2 files changed, 102 insertions(+), 31 deletions(-) create mode 100644 mrbgems/mruby-rational/src/rational.c diff --git a/mrbgems/mruby-rational/mrblib/rational.rb b/mrbgems/mruby-rational/mrblib/rational.rb index a38f71407..54324b05f 100644 --- a/mrbgems/mruby-rational/mrblib/rational.rb +++ b/mrbgems/mruby-rational/mrblib/rational.rb @@ -2,29 +2,10 @@ class Rational < Numeric # Override #<, #<=, #>, #>= in Numeric prepend Comparable - def initialize(numerator = 0, denominator = 1) - @numerator = numerator - @denominator = denominator - - _simplify - end - def inspect "(#{to_s})" end - def to_f - @numerator.to_f / @denominator.to_f - end - - def to_i - to_f.to_i - end - - def to_r - self - end - def to_s "#{numerator}/#{denominator}" end @@ -86,24 +67,24 @@ class Rational < Numeric nil end end +end - def negative? - numerator.negative? - end - - def _simplify - a = numerator - b = denominator - a, b = b, a % b until b.zero? - @numerator = @numerator.div(a) - @denominator = @denominator.div(a) +class << Numeric + def to_r + Rational(self, 1) end +end - attr_reader :numerator, :denominator +class << Rational + alias_method :_new, :new + undef_method :new end def Rational(numerator = 0, denominator = 1) - Rational.new(numerator, denominator) + a = numerator + b = denominator + a, b = b, a % b until b.zero? + Rational._new(numerator.div(a), denominator.div(a)) end [:+, :-, :*, :/, :<=>, :==, :<, :<=, :>, :>=].each do |op| diff --git a/mrbgems/mruby-rational/src/rational.c b/mrbgems/mruby-rational/src/rational.c new file mode 100644 index 000000000..14a9b045d --- /dev/null +++ b/mrbgems/mruby-rational/src/rational.c @@ -0,0 +1,90 @@ +#include +#include +#include +#include + +struct mrb_rational { + mrb_int numerator; + mrb_int denominator; +}; + +static struct mrb_rational* +rational_ptr(mrb_value v) +{ + return (struct mrb_rational*)mrb_istruct_ptr(v); +} + +static mrb_value +rational_numerator(mrb_state *mrb, mrb_value self) +{ + struct mrb_rational *p = rational_ptr(self); + return mrb_fixnum_value(p->numerator); +} + +static mrb_value +rational_denominator(mrb_state *mrb, mrb_value self) +{ + struct mrb_rational *p = rational_ptr(self); + return mrb_fixnum_value(p->denominator); +} + +static mrb_value +rational_initialize(mrb_state *mrb, mrb_value self) +{ + struct mrb_rational *p = rational_ptr(self); + mrb_get_args(mrb, "ii", &p->numerator, &p->denominator); + return self; +} + +static mrb_value +rational_to_f(mrb_state *mrb, mrb_value self) +{ + struct mrb_rational *p = rational_ptr(self); + mrb_float f = (mrb_float)p->numerator / (mrb_float)p->denominator; + + return mrb_float_value(mrb, f); +} + +static mrb_value +rational_to_i(mrb_state *mrb, mrb_value self) +{ + struct mrb_rational *p = rational_ptr(self); + return mrb_fixnum_value(p->numerator / p->denominator); +} + +static mrb_value +rational_to_r(mrb_state *mrb, mrb_value self) +{ + return self; +} + +static mrb_value +rational_negative_p(mrb_state *mrb, mrb_value self) +{ + struct mrb_rational *p = rational_ptr(self); + if (p->numerator < 0) { + return mrb_true_value(); + } + return mrb_false_value(); +} + +void mrb_mruby_rational_gem_init(mrb_state *mrb) +{ + struct RClass *rat; + + mrb_assert(sizeof(struct mrb_rational) < ISTRUCT_DATA_SIZE); + rat = mrb_define_class(mrb, "Rational", mrb_class_get(mrb, "Numeric")); + MRB_SET_INSTANCE_TT(rat, MRB_TT_ISTRUCT); + mrb_define_method(mrb, rat, "numerator", rational_numerator, MRB_ARGS_NONE()); + mrb_define_method(mrb, rat, "denominator", rational_denominator, MRB_ARGS_NONE()); + mrb_define_method(mrb, rat, "initialize", rational_initialize, MRB_ARGS_REQ(2)); + mrb_define_method(mrb, rat, "to_f", rational_to_f, MRB_ARGS_NONE()); + mrb_define_method(mrb, rat, "to_i", rational_to_i, MRB_ARGS_NONE()); + mrb_define_method(mrb, rat, "to_r", rational_to_r, MRB_ARGS_NONE()); + mrb_define_method(mrb, rat, "negative?", rational_negative_p, MRB_ARGS_NONE()); +} + +void +mrb_mruby_rational_gem_final(mrb_state* mrb) +{ +} -- cgit v1.2.3 From d5c8868346b49e2b2228cb8733398d88f744985b Mon Sep 17 00:00:00 2001 From: Kouhei Sutou Date: Fri, 17 May 2019 17:59:24 +0900 Subject: Add support for CC="gcc --option ..." again If $rake_root_fiber is used, sh runs command in another Fiber. If command is ran in another Fiber, "rescue RuntimEerror" can't rescue exception for system(...) failure. How to reproduce: $ CC="gcc -std=gnu99" ./minirake (in /home/kou/work/ruby/mruby.kou) CC mrbgems/mruby-compiler/core/codegen.c -> build/test/mrbgems/mruby-compiler/core/codegen.o sh: 1: gcc -std=gnu99: not found rake aborted! Command Failed: ["gcc -std=gnu99" -g -std=gnu99 ...] --- lib/mruby/build/command.rb | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lib/mruby/build/command.rb b/lib/mruby/build/command.rb index 0f18e0e62..0fa4746da 100644 --- a/lib/mruby/build/command.rb +++ b/lib/mruby/build/command.rb @@ -30,10 +30,13 @@ module MRuby def _run(options, params={}) return sh command + ' ' + ( options % params ) if NotFoundCommands.key? @command begin + fiber, $rake_root_fiber = $rake_root_fiber, nil sh build.filename(command) + ' ' + ( options % params ) rescue RuntimeError NotFoundCommands[@command] = true _run options, params + ensure + $rake_root_fiber = fiber end end end -- cgit v1.2.3 From eeb95e058a579a45207079369b19869cb48a39de Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Fri, 17 May 2019 19:53:31 +0900 Subject: Fix `Numeric#to_r` --- mrbgems/mruby-rational/mrblib/rational.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mrbgems/mruby-rational/mrblib/rational.rb b/mrbgems/mruby-rational/mrblib/rational.rb index 54324b05f..37dcfc2a0 100644 --- a/mrbgems/mruby-rational/mrblib/rational.rb +++ b/mrbgems/mruby-rational/mrblib/rational.rb @@ -69,7 +69,7 @@ class Rational < Numeric end end -class << Numeric +class Numeric def to_r Rational(self, 1) end -- cgit v1.2.3 From aa41a5c9af4d8ee61867d4f0bfdaeab4deb7cf0e Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Fri, 17 May 2019 20:44:48 +0900 Subject: Drop dependency from `mruby-rational` to `mruby-numeric-ext` --- mrbgems/mruby-rational/mrbgem.rake | 1 - mrbgems/mruby-rational/mrblib/rational.rb | 2 +- mrbgems/mruby-rational/test/rational.rb | 7 +++++++ 3 files changed, 8 insertions(+), 2 deletions(-) diff --git a/mrbgems/mruby-rational/mrbgem.rake b/mrbgems/mruby-rational/mrbgem.rake index 496082709..15c3429f2 100644 --- a/mrbgems/mruby-rational/mrbgem.rake +++ b/mrbgems/mruby-rational/mrbgem.rake @@ -4,5 +4,4 @@ MRuby::Gem::Specification.new('mruby-rational') do |spec| spec.summary = 'Rational class' spec.add_dependency 'mruby-object-ext', core: 'mruby-object-ext' - spec.add_dependency 'mruby-numeric-ext', core: 'mruby-numeric-ext' end diff --git a/mrbgems/mruby-rational/mrblib/rational.rb b/mrbgems/mruby-rational/mrblib/rational.rb index 54324b05f..ccb67541f 100644 --- a/mrbgems/mruby-rational/mrblib/rational.rb +++ b/mrbgems/mruby-rational/mrblib/rational.rb @@ -83,7 +83,7 @@ end def Rational(numerator = 0, denominator = 1) a = numerator b = denominator - a, b = b, a % b until b.zero? + a, b = b, a % b until b == 0 Rational._new(numerator.div(a), denominator.div(a)) end diff --git a/mrbgems/mruby-rational/test/rational.rb b/mrbgems/mruby-rational/test/rational.rb index 4d3d36ccc..a65926bfb 100644 --- a/mrbgems/mruby-rational/test/rational.rb +++ b/mrbgems/mruby-rational/test/rational.rb @@ -100,3 +100,10 @@ assert 'Float#==(Rational), Float#!=(Rational)' do assert_equal_rational(true, -2.0, Rational(4,-2)) assert_equal_rational(false, 3.3, Rational(13,4)) end + +assert 'Rational#negative?' do + assert_predicate(Rational(-2,3), :negative?) + assert_predicate(Rational(2,-3), :negative?) + assert_not_predicate(Rational(2,3), :negative?) + assert_not_predicate(Rational(0), :negative?) +end -- cgit v1.2.3 From c5c39f585b48ef9cede6059ae5bc16b00f160db8 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Fri, 17 May 2019 21:13:31 +0900 Subject: Move `Integral#(zero|nonzero|positive|negative)?` to `Numeric` Because these methods work if object is `Comparable`, and `Numeric` is `Comparable`. --- mrbgems/mruby-numeric-ext/mrblib/numeric_ext.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mrbgems/mruby-numeric-ext/mrblib/numeric_ext.rb b/mrbgems/mruby-numeric-ext/mrblib/numeric_ext.rb index e86e8b283..576605cb1 100644 --- a/mrbgems/mruby-numeric-ext/mrblib/numeric_ext.rb +++ b/mrbgems/mruby-numeric-ext/mrblib/numeric_ext.rb @@ -1,4 +1,4 @@ -module Integral +class Numeric def zero? self == 0 end -- cgit v1.2.3 From 647569bfe84799c7452da278b64fa72338e48246 Mon Sep 17 00:00:00 2001 From: Bhargava Shastry Date: Fri, 17 May 2019 14:26:41 +0200 Subject: Add/Edit ossfuzz config options --- oss-fuzz/config/mruby_fuzzer.options | 2 +- oss-fuzz/config/mruby_proto_fuzzer.options | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) create mode 100644 oss-fuzz/config/mruby_proto_fuzzer.options diff --git a/oss-fuzz/config/mruby_fuzzer.options b/oss-fuzz/config/mruby_fuzzer.options index 132affcae..8658e71b2 100644 --- a/oss-fuzz/config/mruby_fuzzer.options +++ b/oss-fuzz/config/mruby_fuzzer.options @@ -1,5 +1,5 @@ [libfuzzer] close_fd_mask = 3 dict = mruby.dict -fork = 8 +fork = 1 only_ascii = 1 diff --git a/oss-fuzz/config/mruby_proto_fuzzer.options b/oss-fuzz/config/mruby_proto_fuzzer.options new file mode 100644 index 000000000..4ced8516c --- /dev/null +++ b/oss-fuzz/config/mruby_proto_fuzzer.options @@ -0,0 +1,4 @@ +[libfuzzer] +close_fd_mask = 3 +dict = mruby.dict +fork = 1 -- cgit v1.2.3 From 1f3ece9631d3b52911ff7b5fff88fa8fccbbc3f9 Mon Sep 17 00:00:00 2001 From: Bhargava Shastry Date: Fri, 17 May 2019 14:22:43 +0200 Subject: proto fuzzer: Add source files necessary to compile proto fuzzer --- oss-fuzz/mruby_proto_fuzzer.cpp | 44 ++++ oss-fuzz/proto_to_ruby.cpp | 455 ++++++++++++++++++++++++++++++++++++++++ oss-fuzz/proto_to_ruby.h | 55 +++++ oss-fuzz/ruby.proto | 201 ++++++++++++++++++ 4 files changed, 755 insertions(+) create mode 100644 oss-fuzz/mruby_proto_fuzzer.cpp create mode 100644 oss-fuzz/proto_to_ruby.cpp create mode 100644 oss-fuzz/proto_to_ruby.h create mode 100644 oss-fuzz/ruby.proto diff --git a/oss-fuzz/mruby_proto_fuzzer.cpp b/oss-fuzz/mruby_proto_fuzzer.cpp new file mode 100644 index 000000000..2999c5470 --- /dev/null +++ b/oss-fuzz/mruby_proto_fuzzer.cpp @@ -0,0 +1,44 @@ +#include +#include +#include + +#include +#include + +#include "libprotobuf-mutator/src/libfuzzer/libfuzzer_macro.h" +#include "ruby.pb.h" +#include "proto_to_ruby.h" + +using namespace ruby_fuzzer; +using namespace std; + +int FuzzRB(const uint8_t *Data, size_t size) { + mrb_value v; + mrb_state *mrb = mrb_open(); + if (!mrb) + return 0; + + char *code = (char *)malloc(size+1); + if (!code) + return 0; + memcpy(code, Data, size); + code[size] = '\0'; + + if (const char *dump_path = getenv("PROTO_FUZZER_DUMP_PATH")) { + // With libFuzzer binary run this to generate an RB file x.rb: + // PROTO_FUZZER_DUMP_PATH=x.rb ./a.out proto-input + std::ofstream of(dump_path); + of.write(code, size); + } + v = mrb_load_string(mrb, code); + mrb_close(mrb); + + free(code); + return 0; +} + +DEFINE_PROTO_FUZZER(const Function &function) { + protoConverter converter; + auto s = converter.FunctionToString(function); + (void)FuzzRB((const uint8_t*)s.data(), s.size()); +} diff --git a/oss-fuzz/proto_to_ruby.cpp b/oss-fuzz/proto_to_ruby.cpp new file mode 100644 index 000000000..92ad039e2 --- /dev/null +++ b/oss-fuzz/proto_to_ruby.cpp @@ -0,0 +1,455 @@ +#include "proto_to_ruby.h" + +using namespace ruby_fuzzer; + +std::string protoConverter::removeSpecial(const std::string &x) +{ + std::string tmp(x); + if (!tmp.empty()) + tmp.erase(std::remove_if(tmp.begin(), tmp.end(), + [](char c) { return !(std::isalpha(c) || std::isdigit(c)); } ), tmp.end()); + return tmp; +} + +void protoConverter::visit(ArrType const& x) +{ + if (x.elements_size() > 0) { + int i = x.elements_size(); + m_output << "["; + for (auto &e : x.elements()) { + i--; + if (i == 0) { + visit(e); + } else { + visit(e); + m_output << ", "; + } + } + m_output << "]"; + } else { + m_output << "[1]"; + } +} + +void protoConverter::visit(Array const& x) +{ + switch (x.arr_func()) { + case Array::FLATTEN: + visit(x.arr_arg()); + m_output << ".flatten"; + break; + case Array::COMPACT: + visit(x.arr_arg()); + m_output << ".compact"; + break; + case Array::FETCH: + visit(x.arr_arg()); + m_output << ".fetch"; + break; + case Array::FILL: + visit(x.arr_arg()); + m_output << ".fill"; + break; + case Array::ROTATE: + visit(x.arr_arg()); + m_output << ".rotate"; + break; + case Array::ROTATE_E: + visit(x.arr_arg()); + m_output << ".rotate!"; + break; + case Array::DELETEIF: + visit(x.arr_arg()); + m_output << ".delete_if"; + break; + case Array::INSERT: + visit(x.arr_arg()); + m_output << ".insert"; + break; + case Array::BSEARCH: + visit(x.arr_arg()); + m_output << ".bsearch"; + break; + case Array::KEEPIF: + visit(x.arr_arg()); + m_output << ".keep_if"; + break; + case Array::SELECT: + visit(x.arr_arg()); + m_output << ".select"; + break; + case Array::VALUES_AT: + visit(x.arr_arg()); + m_output << ".values_at"; + break; + case Array::BLOCK: + visit(x.arr_arg()); + m_output << ".index"; + break; + case Array::DIG: + visit(x.arr_arg()); + m_output << ".dig"; + break; + case Array::SLICE: + visit(x.arr_arg()); + m_output << ".slice"; + break; + case Array::PERM: + visit(x.arr_arg()); + m_output << ".permutation"; + break; + case Array::COMB: + visit(x.arr_arg()); + m_output << ".combination"; + break; + case Array::ASSOC: + visit(x.arr_arg()); + m_output << ".assoc"; + break; + case Array::RASSOC: + visit(x.arr_arg()); + m_output << ".rassoc"; + break; + } + m_output << "("; + visit(x.val_arg()); + m_output << ")"; +} + +void protoConverter::visit(AssignmentStatement const& x) +{ + m_output << "var_" << m_numLiveVars << " = "; + visit(x.rvalue()); + m_numVarsPerScope.top()++; + m_numLiveVars++; + m_output << "\n"; +} + +void protoConverter::visit(BinaryOp const& x) +{ + m_output << "("; + visit(x.left()); + switch (x.op()) { + case BinaryOp::ADD: m_output << " + "; break; + case BinaryOp::SUB: m_output << " - "; break; + case BinaryOp::MUL: m_output << " * "; break; + case BinaryOp::DIV: m_output << " / "; break; + case BinaryOp::MOD: m_output << " % "; break; + case BinaryOp::XOR: m_output << " ^ "; break; + case BinaryOp::AND: m_output << " and "; break; + case BinaryOp::OR: m_output << " or "; break; + case BinaryOp::EQ: m_output << " == "; break; + case BinaryOp::NE: m_output << " != "; break; + case BinaryOp::LE: m_output << " <= "; break; + case BinaryOp::GE: m_output << " >= "; break; + case BinaryOp::LT: m_output << " < "; break; + case BinaryOp::GT: m_output << " > "; break; + case BinaryOp::RS: m_output << " >> "; break; + } + visit(x.right()); + m_output << ")"; +} + +void protoConverter::visit(BuiltinFuncs const& x) +{ + switch (x.bifunc_oneof_case()) { + case BuiltinFuncs::kOs: + visit(x.os()); + break; + case BuiltinFuncs::kTime: + visit(x.time()); + break; + case BuiltinFuncs::kArr: + visit(x.arr()); + break; + case BuiltinFuncs::kMops: + visit(x.mops()); + break; + case BuiltinFuncs::BIFUNC_ONEOF_NOT_SET: + m_output << "1"; + break; + } + m_output << "\n"; +} + +void protoConverter::visit(Const const& x) +{ + switch (x.const_oneof_case()) { + case Const::kIntLit: + m_output << "(" << (x.int_lit() % 13) << ")"; + break; + case Const::kBoolVal: + m_output << "(" << x.bool_val() << ")"; + break; + case Const::CONST_ONEOF_NOT_SET: + m_output << "1"; + break; + } +} + +void protoConverter::visit(Function const& x) +{ + m_output << "def foo()\nvar_0 = 1\n"; + visit(x.statements()); + m_output << "end\n"; + m_output << "foo\n"; +} + +void protoConverter::visit(HashType const& x) +{ + if (x.keyval_size() > 0) { + int i = x.keyval_size(); + m_output << "{"; + for (auto &e : x.keyval()) { + i--; + if (i == 0) { + visit(e); + } + else { + visit(e); + m_output << ", "; + } + } + m_output << "}"; + } +} + +void protoConverter::visit(IfElse const& x) +{ + m_output << "if "; + visit(x.cond()); + m_output << "\n"; + visit(x.if_body()); + m_output << "\nelse\n"; + visit(x.else_body()); + m_output << "\nend\n"; +} + +void protoConverter::visit(KVPair const& x) +{ + m_output << "\"" << removeSpecial(x.key()) << "\""; + m_output << " => "; + m_output << "\"" << removeSpecial(x.val()) << "\""; +} + +void protoConverter::visit(MathConst const& x) +{ + switch (x.math_const()) { + case MathConst::PI: + m_output << "Math::PI"; + break; + case MathConst::E: + m_output << "Math::E"; + break; + } +} + +void protoConverter::visit(MathOps const& x) +{ + switch (x.math_op()) { + case MathOps::CBRT: + m_output << "Math.cbrt("; + visit(x.math_arg()); + m_output << ")"; + break; + case MathOps::COS: + m_output << "Math.cos("; + visit(x.math_arg()); + m_output << ")"; + break; + case MathOps::ERF: + m_output << "Math.erf("; + visit(x.math_arg()); + m_output << ")"; + break; + case MathOps::ERFC: + m_output << "Math.erfc("; + visit(x.math_arg()); + m_output << ")"; + break; + case MathOps::LOG: + m_output << "Math.log("; + visit(x.math_arg()); + m_output << ")"; + break; + case MathOps::LOG10: + m_output << "Math.log10("; + visit(x.math_arg()); + m_output << ")"; + break; + case MathOps::LOG2: + m_output << "Math.log2("; + visit(x.math_arg()); + m_output << ")"; + break; + case MathOps::SIN: + m_output << "Math.sin("; + visit(x.math_arg()); + m_output << ")"; + break; + case MathOps::SQRT: + m_output << "Math.sqrt("; + visit(x.math_arg()); + m_output << ")"; + break; + case MathOps::TAN: + m_output << "Math.tan("; + visit(x.math_arg()); + m_output << ")"; + break; + } +} + +void protoConverter::visit(MathType const& x) +{ + switch (x.math_arg_oneof_case()) { + case MathType::kMathRval: + visit(x.math_rval()); + break; + case MathType::kMathConst: + visit(x.math_const()); + break; + case MathType::MATH_ARG_ONEOF_NOT_SET: + m_output << "1"; + break; + } +} + +void protoConverter::visit(ObjectSpace const& x) +{ + switch (x.os_func()) { + case ObjectSpace::COUNT: + m_output << "ObjectSpace.count_objects"; + break; + } + m_output << "("; + visit(x.os_arg()); + m_output << ")" << "\n"; +} + +void protoConverter::visit(Rvalue const& x) +{ + switch (x.rvalue_oneof_case()) { + case Rvalue::kVarref: + visit(x.varref()); + break; + case Rvalue::kCons: + visit(x.cons()); + break; + case Rvalue::kBinop: + visit(x.binop()); + break; + case Rvalue::RVALUE_ONEOF_NOT_SET: + m_output << "1"; + break; + } +} + +void protoConverter::visit(Statement const& x) +{ + switch (x.stmt_oneof_case()) { + case Statement::kAssignment: + visit(x.assignment()); + break; + case Statement::kIfelse: + visit(x.ifelse()); + break; + case Statement::kTernaryStmt: + visit(x.ternary_stmt()); + break; + case Statement::kBuiltins: + visit(x.builtins()); + break; + case Statement::kBlockstmt: + visit(x.blockstmt()); + break; + case Statement::STMT_ONEOF_NOT_SET: + break; + } + m_output << "\n"; +} + +void protoConverter::visit(StatementSeq const& x) +{ + if (x.statements_size() > 0) { + m_numVarsPerScope.push(0); + m_output << "@scope ||= begin\n"; + for (auto &st : x.statements()) + visit(st); + m_output << "end\n"; + m_numLiveVars -= m_numVarsPerScope.top(); + m_numVarsPerScope.pop(); + } +} + +void protoConverter::visit(StringExtNoArg const& x) +{ + m_output << "\"" << removeSpecial(x.str_arg()) << "\""; + switch (x.str_op()) { + case StringExtNoArg::DUMP: + m_output << ".dump"; + break; + case StringExtNoArg::STRIP: + m_output << ".strip"; + break; + case StringExtNoArg::LSTRIP: + m_output << ".lstrip"; + break; + case StringExtNoArg::RSTRIP: + m_output << ".rstrip"; + break; + case StringExtNoArg::STRIPE: + m_output << ".strip!"; + break; + case StringExtNoArg::LSTRIPE: + m_output << ".lstrip!"; + break; + case StringExtNoArg::RSTRIPE: + m_output << ".rstrip!"; + break; + case StringExtNoArg::SWAPCASE: + m_output << ".swapcase"; + break; + case StringExtNoArg::SWAPCASEE: + m_output << ".swapcase!"; + break; + case StringExtNoArg::SQUEEZE: + m_output << ".squeeze"; + break; + } +} + +void protoConverter::visit(Ternary const& x) +{ + m_output << "("; + visit(x.tern_cond()); + m_output << " ? "; + visit(x.t_branch()); + m_output << " : "; + visit(x.f_branch()); + m_output << ")\n"; +} + +void protoConverter::visit(Time const& x) +{ + switch (x.t_func()) { + case Time::AT: + m_output << "Time.at"; + break; + case Time::GM: + m_output << "Time.gm"; + break; + } + m_output << "(" << (x.t_arg()% 13) << ")" << "\n"; +} + +void protoConverter::visit(VarRef const& x) +{ + m_output << "var_" << (static_cast(x.varnum()) % m_numLiveVars); +} + +std::string protoConverter::FunctionToString(Function const& input) +{ + visit(input); + return m_output.str(); +} diff --git a/oss-fuzz/proto_to_ruby.h b/oss-fuzz/proto_to_ruby.h new file mode 100644 index 000000000..01f9d68bb --- /dev/null +++ b/oss-fuzz/proto_to_ruby.h @@ -0,0 +1,55 @@ +#include +#include +#include +#include +#include +#include +#include "ruby.pb.h" + +namespace ruby_fuzzer { + class protoConverter + { + public: + protoConverter() { + m_numLiveVars = 1; + m_numVarsPerScope.push(m_numLiveVars); + } + protoConverter(protoConverter const& x) { + m_numLiveVars = x.m_numLiveVars; + m_numVarsPerScope = x.m_numVarsPerScope; + } + ~protoConverter() {} + std::string FunctionToString(Function const& _input); + + private: + void visit(ArrType const&); + void visit(Array const&); + void visit(AssignmentStatement const&); + void visit(BinaryOp const&); + void visit(BuiltinFuncs const&); + void visit(Const const&); + void visit(Function const&); + void visit(HashType const&); + void visit(IfElse const&); + void visit(KVPair const&); + void visit(MathConst const&); + void visit(MathOps const&); + void visit(MathType const&); + void visit(ObjectSpace const&); + void visit(Rvalue const&); + void visit(Statement const&); + void visit(StatementSeq const&); + void visit(StringExtNoArg const&); + void visit(Ternary const&); + void visit(Time const&); + void visit(VarRef const&); + template + void visit(google::protobuf::RepeatedPtrField const& _repeated_field); + + std::string removeSpecial(const std::string &x); + + std::ostringstream m_output; + std::stack m_numVarsPerScope; + int32_t m_numLiveVars; + }; +} diff --git a/oss-fuzz/ruby.proto b/oss-fuzz/ruby.proto new file mode 100644 index 000000000..d9b0804c8 --- /dev/null +++ b/oss-fuzz/ruby.proto @@ -0,0 +1,201 @@ +syntax = "proto2"; + +message VarRef { + required int32 varnum = 1; +} + +message ArrType { + repeated Const elements = 1; +} + +message KVPair { + required string key = 1; + required string val = 2; +} + +message HashType { + repeated KVPair keyval = 1; +} + +message StringExtNoArg { + enum StrExtOp { + DUMP = 0; + STRIP = 1; + LSTRIP = 2; + RSTRIP = 3; + STRIPE = 4; + LSTRIPE = 5; + RSTRIPE = 6; + SWAPCASE = 7; + SWAPCASEE = 8; + SQUEEZE = 9; + } + required StrExtOp str_op = 1; + required string str_arg = 2; +} + +message MathConst { + enum MathConstLit { + PI = 0; + E = 1; + } + required MathConstLit math_const = 1; +} + +message Const { + oneof const_oneof { + uint32 int_lit = 1; + bool bool_val = 4; + } +} + +message BinaryOp { + enum Op { + ADD = 0; + SUB = 1; + MUL = 2; + DIV = 3; + MOD = 4; + XOR = 5; + AND = 6; + OR = 7; + EQ = 8; + NE = 9; + LE = 10; + GE = 11; + LT = 12; + GT = 13; + RS = 14; + }; + required Op op = 1; + required Rvalue left = 2; + required Rvalue right = 3; +} + +message Rvalue { + oneof rvalue_oneof { + VarRef varref = 1; + Const cons = 2; + BinaryOp binop = 3; + } +} + +message AssignmentStatement { + required Rvalue rvalue = 2; +} + + +message IfElse { + required Rvalue cond = 1; + required StatementSeq if_body = 2; + required StatementSeq else_body = 3; +} + +//TODO: Add Switch statement +//message Switch { +// required Rvalue switch_var = 1; +// repeated Rvalue cond = 2; +//} + +message Ternary { + required Rvalue tern_cond = 1; + required Rvalue t_branch = 2; + required Rvalue f_branch = 3; +} + +message ObjectSpace { + enum OS_methods { + COUNT = 1; + } + required OS_methods os_func = 1; + required HashType os_arg = 2; +} + +message Time { + enum T_methods { + AT = 1; + GM = 2; + } + required T_methods t_func = 1; + required uint32 t_arg = 2; +} + +message Array { + enum Arr_methods { + FLATTEN = 1; + COMPACT = 2; + FETCH = 3; + FILL = 4; + ROTATE = 5; + ROTATE_E = 6; + DELETEIF = 7; + INSERT = 8; + BSEARCH = 9; + KEEPIF = 10; + SELECT = 11; + VALUES_AT = 12; + BLOCK = 13; + DIG = 14; + SLICE = 15; + PERM = 16; + COMB = 17; + ASSOC = 18; + RASSOC = 19; + } + required Arr_methods arr_func = 1; + required ArrType arr_arg = 2; + required Rvalue val_arg = 3; +} + +message MathType { + oneof math_arg_oneof { + Rvalue math_rval = 2; + MathConst math_const = 3; + } +} + +message MathOps { + enum Mops { + CBRT = 1; + COS = 2; + ERF = 3; + ERFC = 4; + LOG = 5; + LOG10 = 6; + LOG2 = 7; + SIN = 8; + SQRT = 9; + TAN = 10; + } + required Mops math_op = 1; + required MathType math_arg = 2; +} + +message BuiltinFuncs { + oneof bifunc_oneof { + ObjectSpace os = 1; + Time time = 2; + Array arr = 3; + MathOps mops = 4; + } +} + +message Statement { + oneof stmt_oneof { + AssignmentStatement assignment = 1; + IfElse ifelse = 2; + Ternary ternary_stmt = 3; + BuiltinFuncs builtins = 4; + StatementSeq blockstmt = 5; + } +} + +message StatementSeq { + repeated Statement statements = 1; +} + +message Function { + required StatementSeq statements = 1; +} + +package ruby_fuzzer; -- cgit v1.2.3 From a14ae801022291bfa7ffcc15d1acbc0fea3407a6 Mon Sep 17 00:00:00 2001 From: dearblue Date: Fri, 17 May 2019 22:04:25 +0900 Subject: (Proof of Concept) mruby tuning profiles [ci skip] Not only mruby, it is one of the difficult things to adjust the performance vs. memory efficiency of the software. If the approximate target device is divided and the adjustment value for it is prepared by default, it is a good indicator to do fine adjustment. This PR divides into four profiles. ***Caution: There is no basis for the definitions in the patch.*** - `MRB_CONSTRAINED_BASELINE_PROFILE` - for microprocessors. Reduce memory consumption. - `MRB_BASELINE_PROFILE` - Default value of mruby. - `MRB_MAIN_PROFILE` - For desktop computers. Assume that a huge amount of RAM, 10 MiB or more, is on board. - `MRB_HIGH_PROFILE` - for servers. Assume that mruby VM has a long life. As you can see the profile name has been ~~stolen~~ imitated from H.264. --- include/mrbconf.h | 66 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 66 insertions(+) diff --git a/include/mrbconf.h b/include/mrbconf.h index ee816e322..f5e8858ce 100644 --- a/include/mrbconf.h +++ b/include/mrbconf.h @@ -159,4 +159,70 @@ # define TRUE 1 #endif +/* +** mruby tuning profiles +**/ + +/* A profile for micro controllers */ +#if defined(MRB_CONSTRAINED_BASELINE_PROFILE) +# ifndef KHASH_DEFAULT_SIZE +# define KHASH_DEFAULT_SIZE 16 +# endif + +# ifndef MRB_STR_BUF_MIN_SIZE +# define MRB_STR_BUF_MIN_SIZE 32 +# endif + +# ifndef MRB_HEAP_PAGE_SIZE +# define MRB_HEAP_PAGE_SIZE 256 +# endif + +/* A profile for default mruby */ +#elif defined(MRB_BASELINE_PROFILE) + +/* A profile for desktop computers or workstations; rich memory! */ +#elif defined(MRB_MAIN_PROFILE) +# ifndef MRB_METHOD_CACHE +# define MRB_METHOD_CACHE +# endif + +# ifndef MRB_METHOD_CACHE_SIZE +# define MRB_METHOD_CACHE_SIZE (1<<10) +# endif + +# ifndef MRB_METHOD_TABLE_INLINE +# define MRB_METHOD_TABLE_INLINE +# endif + +# ifndef MRB_IV_SEGMENT_SIZE +# define MRB_IV_SEGMENT_SIZE 32 +# endif + +# ifndef MRB_HEAP_PAGE_SIZE +# define MRB_HEAP_PAGE_SIZE 4096 +# endif + +/* A profile for server; mruby vm is long life */ +#elif defined(MRB_HIGH_PROFILE) +# ifndef MRB_METHOD_CACHE +# define MRB_METHOD_CACHE +# endif + +# ifndef MRB_METHOD_CACHE_SIZE +# define MRB_METHOD_CACHE_SIZE (1<<12) +# endif + +# ifndef MRB_METHOD_TABLE_INLINE +# define MRB_METHOD_TABLE_INLINE +# endif + +# ifndef MRB_IV_SEGMENT_SIZE +# define MRB_IV_SEGMENT_SIZE 64 +# endif + +# ifndef MRB_HEAP_PAGE_SIZE +# define MRB_HEAP_PAGE_SIZE 4096 +# endif +#endif + #endif /* MRUBYCONF_H */ -- cgit v1.2.3 From 8d37a3575b9d6e7648967c675395bd176b360b77 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Fri, 17 May 2019 22:37:45 +0900 Subject: Revert "Add support for CC="gcc --option ..." again" This reverts commit d5c8868346b49e2b2228cb8733398d88f744985b. --- lib/mruby/build/command.rb | 3 --- 1 file changed, 3 deletions(-) diff --git a/lib/mruby/build/command.rb b/lib/mruby/build/command.rb index 0fa4746da..0f18e0e62 100644 --- a/lib/mruby/build/command.rb +++ b/lib/mruby/build/command.rb @@ -30,13 +30,10 @@ module MRuby def _run(options, params={}) return sh command + ' ' + ( options % params ) if NotFoundCommands.key? @command begin - fiber, $rake_root_fiber = $rake_root_fiber, nil sh build.filename(command) + ' ' + ( options % params ) rescue RuntimeError NotFoundCommands[@command] = true _run options, params - ensure - $rake_root_fiber = fiber end end end -- cgit v1.2.3 From b7bc03aa18f3cc5eac0bbd6690e24062df9fe837 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Fri, 17 May 2019 22:38:07 +0900 Subject: Stop wrapping the filename by double quotes; ref #4440 --- lib/mruby/build.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/mruby/build.rb b/lib/mruby/build.rb index 016b32b3e..887a5518e 100644 --- a/lib/mruby/build.rb +++ b/lib/mruby/build.rb @@ -255,7 +255,7 @@ EOS if name.is_a?(Array) name.flatten.map { |n| filename(n) } else - '"%s"' % name.gsub('/', file_separator) + name.gsub('/', file_separator) end end @@ -263,7 +263,7 @@ EOS if name.is_a?(Array) name.flatten.map { |n| cygwin_filename(n) } else - '"%s"' % `cygpath -w "#{filename(name)}"`.strip + `cygpath -w "#{filename(name)}"`.strip end end -- cgit v1.2.3 From ace0d3949b62b3541a5ab210706f939890890cc0 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Sat, 18 May 2019 08:38:45 +0900 Subject: Support `MRB_WITHOUT_FLOAT`. I assume there's no realistic usage of `Rational` with `MRB_WITHOUT_FLOAT`. But just for consistency. --- mrbgems/mruby-rational/src/rational.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/mrbgems/mruby-rational/src/rational.c b/mrbgems/mruby-rational/src/rational.c index 14a9b045d..03f373490 100644 --- a/mrbgems/mruby-rational/src/rational.c +++ b/mrbgems/mruby-rational/src/rational.c @@ -36,6 +36,7 @@ rational_initialize(mrb_state *mrb, mrb_value self) return self; } +#ifndef MRB_WITHOUT_FLOAT static mrb_value rational_to_f(mrb_state *mrb, mrb_value self) { @@ -44,6 +45,7 @@ rational_to_f(mrb_state *mrb, mrb_value self) return mrb_float_value(mrb, f); } +#endif static mrb_value rational_to_i(mrb_state *mrb, mrb_value self) @@ -78,7 +80,9 @@ void mrb_mruby_rational_gem_init(mrb_state *mrb) mrb_define_method(mrb, rat, "numerator", rational_numerator, MRB_ARGS_NONE()); mrb_define_method(mrb, rat, "denominator", rational_denominator, MRB_ARGS_NONE()); mrb_define_method(mrb, rat, "initialize", rational_initialize, MRB_ARGS_REQ(2)); +#ifndef MRB_WITHOUT_FLOAT mrb_define_method(mrb, rat, "to_f", rational_to_f, MRB_ARGS_NONE()); +#endif mrb_define_method(mrb, rat, "to_i", rational_to_i, MRB_ARGS_NONE()); mrb_define_method(mrb, rat, "to_r", rational_to_r, MRB_ARGS_NONE()); mrb_define_method(mrb, rat, "negative?", rational_negative_p, MRB_ARGS_NONE()); -- cgit v1.2.3 From e41f15747eea34ea45e0258f0755145fcd10293b Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Sat, 18 May 2019 11:10:20 +0900 Subject: Rename `struct RIstruct` to `struct RIStruct`. --- include/mruby/istruct.h | 4 ++-- src/gc.c | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/include/mruby/istruct.h b/include/mruby/istruct.h index 4d2393ccd..23c9bfa36 100644 --- a/include/mruby/istruct.h +++ b/include/mruby/istruct.h @@ -19,12 +19,12 @@ MRB_BEGIN_DECL #define ISTRUCT_DATA_SIZE (sizeof(void*) * 3) -struct RIstruct { +struct RIStruct { MRB_OBJECT_HEADER; char inline_data[ISTRUCT_DATA_SIZE]; }; -#define RISTRUCT(obj) ((struct RIstruct*)(mrb_ptr(obj))) +#define RISTRUCT(obj) ((struct RIStruct*)(mrb_ptr(obj))) #define ISTRUCT_PTR(obj) (RISTRUCT(obj)->inline_data) MRB_INLINE mrb_int mrb_istruct_size() diff --git a/src/gc.c b/src/gc.c index 5e7440d50..6dc8e373b 100644 --- a/src/gc.c +++ b/src/gc.c @@ -110,7 +110,7 @@ typedef struct { struct RHash hash; struct RRange range; struct RData data; - struct RIstruct istruct; + struct RIStruct istruct; struct RProc proc; struct REnv env; struct RFiber fiber; -- cgit v1.2.3 From bd7328f5e606a59db25c6c17534f7db6c21fc13c Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Sat, 18 May 2019 11:23:59 +0900 Subject: Implement `Rational._new` in C. --- mrbgems/mruby-rational/mrblib/rational.rb | 5 ----- mrbgems/mruby-rational/src/rational.c | 31 ++++++++++++++++++++++++++----- 2 files changed, 26 insertions(+), 10 deletions(-) diff --git a/mrbgems/mruby-rational/mrblib/rational.rb b/mrbgems/mruby-rational/mrblib/rational.rb index 37e9d8c0f..870c12242 100644 --- a/mrbgems/mruby-rational/mrblib/rational.rb +++ b/mrbgems/mruby-rational/mrblib/rational.rb @@ -75,11 +75,6 @@ class Numeric end end -class << Rational - alias_method :_new, :new - undef_method :new -end - def Rational(numerator = 0, denominator = 1) a = numerator b = denominator diff --git a/mrbgems/mruby-rational/src/rational.c b/mrbgems/mruby-rational/src/rational.c index 03f373490..549715e7d 100644 --- a/mrbgems/mruby-rational/src/rational.c +++ b/mrbgems/mruby-rational/src/rational.c @@ -29,11 +29,24 @@ rational_denominator(mrb_state *mrb, mrb_value self) } static mrb_value -rational_initialize(mrb_state *mrb, mrb_value self) +rational_new(mrb_state *mrb, mrb_int numerator, mrb_int denominator) { - struct mrb_rational *p = rational_ptr(self); - mrb_get_args(mrb, "ii", &p->numerator, &p->denominator); - return self; + struct RClass *c = mrb_class_get(mrb, "Rational"); + struct RIStruct *s = (struct RIStruct*)mrb_obj_alloc(mrb, MRB_TT_ISTRUCT, c); + mrb_value rat = mrb_obj_value(s); + struct mrb_rational *p = rational_ptr(rat); + p->numerator = numerator; + p->denominator = denominator; + return mrb_obj_value(s); +} + +static mrb_value +rational_s_new(mrb_state *mrb, mrb_value self) +{ + mrb_int numerator, denominator; + + mrb_get_args(mrb, "ii", &numerator, &denominator); + return rational_new(mrb, numerator, denominator); } #ifndef MRB_WITHOUT_FLOAT @@ -70,6 +83,12 @@ rational_negative_p(mrb_state *mrb, mrb_value self) return mrb_false_value(); } +static mrb_value +fix_to_r(mrb_state *mrb, mrb_value self) +{ + return rational_new(mrb, mrb_fixnum(self), 1); +} + void mrb_mruby_rational_gem_init(mrb_state *mrb) { struct RClass *rat; @@ -77,15 +96,17 @@ void mrb_mruby_rational_gem_init(mrb_state *mrb) mrb_assert(sizeof(struct mrb_rational) < ISTRUCT_DATA_SIZE); rat = mrb_define_class(mrb, "Rational", mrb_class_get(mrb, "Numeric")); MRB_SET_INSTANCE_TT(rat, MRB_TT_ISTRUCT); + mrb_undef_class_method(mrb, rat, "new"); + mrb_define_class_method(mrb, rat, "_new", rational_s_new, MRB_ARGS_REQ(2)); mrb_define_method(mrb, rat, "numerator", rational_numerator, MRB_ARGS_NONE()); mrb_define_method(mrb, rat, "denominator", rational_denominator, MRB_ARGS_NONE()); - mrb_define_method(mrb, rat, "initialize", rational_initialize, MRB_ARGS_REQ(2)); #ifndef MRB_WITHOUT_FLOAT mrb_define_method(mrb, rat, "to_f", rational_to_f, MRB_ARGS_NONE()); #endif mrb_define_method(mrb, rat, "to_i", rational_to_i, MRB_ARGS_NONE()); mrb_define_method(mrb, rat, "to_r", rational_to_r, MRB_ARGS_NONE()); mrb_define_method(mrb, rat, "negative?", rational_negative_p, MRB_ARGS_NONE()); + mrb_define_method(mrb, mrb->fixnum_class, "to_r", fix_to_r, MRB_ARGS_NONE()); } void -- cgit v1.2.3 From 89d29264158946a62af8874b4f04e553b0528630 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Sat, 18 May 2019 11:48:59 +0900 Subject: Add ISO section number to `Module#===`. --- src/class.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/class.c b/src/class.c index 9d26851b9..4cc60ab67 100644 --- a/src/class.c +++ b/src/class.c @@ -2191,7 +2191,7 @@ mrb_init_class(mrb_state *mrb) mrb_define_method(mrb, mod, "const_missing", mrb_mod_const_missing, MRB_ARGS_REQ(1)); mrb_define_method(mrb, mod, "method_defined?", mrb_mod_method_defined, MRB_ARGS_REQ(1)); /* 15.2.2.4.34 */ mrb_define_method(mrb, mod, "define_method", mod_define_method, MRB_ARGS_ARG(1,1)); - mrb_define_method(mrb, mod, "===", mrb_mod_eqq, MRB_ARGS_REQ(1)); + mrb_define_method(mrb, mod, "===", mrb_mod_eqq, MRB_ARGS_REQ(1)); /* 15.2.2.4.7 */ mrb_undef_method(mrb, cls, "append_features"); mrb_undef_method(mrb, cls, "extend_object"); -- cgit v1.2.3 From 4f71e9eebe2a4dc17092768aeabf75af0bbae1ce Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Sat, 18 May 2019 18:22:56 +0900 Subject: Move `Numeric#__coerce_step_counter` to `Integral` This method is only used in `Integral#step` --- src/numeric.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/numeric.c b/src/numeric.c index 6622a46e9..e73bdaca2 100644 --- a/src/numeric.c +++ b/src/numeric.c @@ -170,7 +170,7 @@ num_div(mrb_state *mrb, mrb_value x) } static mrb_value -num_coerce_step_counter(mrb_state *mrb, mrb_value self) +integral_coerce_step_counter(mrb_state *mrb, mrb_value self) { mrb_value counter = self, num, step; @@ -1551,6 +1551,7 @@ mrb_init_numeric(mrb_state *mrb) #endif integral = mrb_define_module(mrb, "Integral"); + mrb_define_method(mrb, integral, "__coerce_step_counter", integral_coerce_step_counter, MRB_ARGS_REQ(2)); /* Numeric Class */ numeric = mrb_define_class(mrb, "Numeric", mrb->object_class); /* 15.2.7 */ @@ -1566,7 +1567,6 @@ mrb_init_numeric(mrb_state *mrb) mrb_define_method(mrb, numeric, ">=", num_ge, MRB_ARGS_REQ(1)); mrb_define_method(mrb, numeric, "finite?", num_finite_p, MRB_ARGS_NONE()); mrb_define_method(mrb, numeric, "infinite?",num_infinite_p, MRB_ARGS_NONE()); - mrb_define_method(mrb, numeric, "__coerce_step_counter", num_coerce_step_counter, MRB_ARGS_REQ(2)); /* Integer Class */ integer = mrb_define_class(mrb, "Integer", numeric); /* 15.2.8 */ -- cgit v1.2.3 From 6c9c189e4b9b5a340e220b333bc5f975fdb65adc Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Sat, 18 May 2019 18:31:55 +0900 Subject: Move `Object#(Rational|Complex)` to `Kernel` --- mrbgems/mruby-complex/mrblib/complex.rb | 10 ++++++---- mrbgems/mruby-rational/mrblib/rational.rb | 12 +++++++----- 2 files changed, 13 insertions(+), 9 deletions(-) diff --git a/mrbgems/mruby-complex/mrblib/complex.rb b/mrbgems/mruby-complex/mrblib/complex.rb index 266c00c36..8ae743e77 100644 --- a/mrbgems/mruby-complex/mrblib/complex.rb +++ b/mrbgems/mruby-complex/mrblib/complex.rb @@ -107,7 +107,7 @@ class Complex < Numeric def polar [abs, arg] end - + def real? false end @@ -147,8 +147,10 @@ class << Complex alias_method :rect, :rectangular end -def Complex(real, imaginary = 0) - Complex.rectangular(real, imaginary) +module Kernel + def Complex(real, imaginary = 0) + Complex.rectangular(real, imaginary) + end end [Fixnum, Float].each do |cls| @@ -165,4 +167,4 @@ end end end end -end \ No newline at end of file +end diff --git a/mrbgems/mruby-rational/mrblib/rational.rb b/mrbgems/mruby-rational/mrblib/rational.rb index 870c12242..19c6da9e7 100644 --- a/mrbgems/mruby-rational/mrblib/rational.rb +++ b/mrbgems/mruby-rational/mrblib/rational.rb @@ -75,11 +75,13 @@ class Numeric end end -def Rational(numerator = 0, denominator = 1) - a = numerator - b = denominator - a, b = b, a % b until b == 0 - Rational._new(numerator.div(a), denominator.div(a)) +module Kernel + def Rational(numerator = 0, denominator = 1) + a = numerator + b = denominator + a, b = b, a % b until b == 0 + Rational._new(numerator.div(a), denominator.div(a)) + end end [:+, :-, :*, :/, :<=>, :==, :<, :<=, :>, :>=].each do |op| -- cgit v1.2.3 From ef5dd5d31d76d575350f06a823a23b94cb14524a Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Sat, 18 May 2019 19:19:52 +0900 Subject: Move `Kernel#instance_exec` to `BasicObject` --- mrbgems/mruby-object-ext/src/object.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mrbgems/mruby-object-ext/src/object.c b/mrbgems/mruby-object-ext/src/object.c index b076b3ec0..ac26cdc94 100644 --- a/mrbgems/mruby-object-ext/src/object.c +++ b/mrbgems/mruby-object-ext/src/object.c @@ -103,7 +103,7 @@ mrb_mruby_object_ext_gem_init(mrb_state* mrb) #endif mrb_define_method(mrb, n, "to_i", nil_to_i, MRB_ARGS_NONE()); - mrb_define_method(mrb, mrb->kernel_module, "instance_exec", mrb_obj_instance_exec, MRB_ARGS_ANY() | MRB_ARGS_BLOCK()); + mrb_define_method(mrb, mrb_class_get(mrb, "BasicObject"), "instance_exec", mrb_obj_instance_exec, MRB_ARGS_ANY() | MRB_ARGS_BLOCK()); } void -- cgit v1.2.3 From 6fb5979d29217386425044b8170acb7a9363ce0c Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Sat, 18 May 2019 20:57:54 +0900 Subject: Move `Kernel#equal? to `BasicObject` --- src/class.c | 1 + src/kernel.c | 1 - 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/src/class.c b/src/class.c index 4cc60ab67..6ceaa0cfa 100644 --- a/src/class.c +++ b/src/class.c @@ -2154,6 +2154,7 @@ mrb_init_class(mrb_state *mrb) mrb_define_method(mrb, bob, "!=", mrb_obj_not_equal_m, MRB_ARGS_REQ(1)); mrb_define_method(mrb, bob, "__id__", mrb_obj_id_m, MRB_ARGS_NONE()); /* 15.3.1.3.4 */ mrb_define_method(mrb, bob, "__send__", mrb_f_send, MRB_ARGS_ANY()); /* 15.3.1.3.5 */ + mrb_define_method(mrb, bob, "equal?", mrb_obj_equal_m, MRB_ARGS_REQ(1)); /* 15.3.1.3.11 */ mrb_define_method(mrb, bob, "instance_eval", mrb_obj_instance_eval, MRB_ARGS_ANY()); /* 15.3.1.3.18 */ mrb_define_class_method(mrb, cls, "new", mrb_class_new_class, MRB_ARGS_OPT(1)); diff --git a/src/kernel.c b/src/kernel.c index 45bca7558..349e71cb8 100644 --- a/src/kernel.c +++ b/src/kernel.c @@ -780,7 +780,6 @@ mrb_init_kernel(mrb_state *mrb) mrb_define_method(mrb, krn, "clone", mrb_obj_clone, MRB_ARGS_NONE()); /* 15.3.1.3.8 */ mrb_define_method(mrb, krn, "dup", mrb_obj_dup, MRB_ARGS_NONE()); /* 15.3.1.3.9 */ mrb_define_method(mrb, krn, "eql?", mrb_obj_equal_m, MRB_ARGS_REQ(1)); /* 15.3.1.3.10 */ - mrb_define_method(mrb, krn, "equal?", mrb_obj_equal_m, MRB_ARGS_REQ(1)); /* 15.3.1.3.11 */ mrb_define_method(mrb, krn, "extend", mrb_obj_extend_m, MRB_ARGS_ANY()); /* 15.3.1.3.13 */ mrb_define_method(mrb, krn, "freeze", mrb_obj_freeze, MRB_ARGS_NONE()); mrb_define_method(mrb, krn, "frozen?", mrb_obj_frozen, MRB_ARGS_NONE()); -- cgit v1.2.3 From 9c79c28604fe0e6cd66ba11d1e5d8d7d29ead6c2 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Sat, 18 May 2019 21:17:47 +0900 Subject: Move `Kernel#instance_eval` to `BasicObject` --- mrbgems/mruby-eval/src/eval.c | 2 +- mrbgems/mruby-eval/test/eval.rb | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/mrbgems/mruby-eval/src/eval.c b/mrbgems/mruby-eval/src/eval.c index fa687d624..a3b211ba2 100644 --- a/mrbgems/mruby-eval/src/eval.c +++ b/mrbgems/mruby-eval/src/eval.c @@ -387,7 +387,7 @@ void mrb_mruby_eval_gem_init(mrb_state* mrb) { mrb_define_module_function(mrb, mrb->kernel_module, "eval", f_eval, MRB_ARGS_ARG(1, 3)); - mrb_define_method(mrb, mrb->kernel_module, "instance_eval", f_instance_eval, MRB_ARGS_ARG(1, 2)); + mrb_define_method(mrb, mrb_class_get(mrb, "BasicObject"), "instance_eval", f_instance_eval, MRB_ARGS_ARG(1, 2)); } void diff --git a/mrbgems/mruby-eval/test/eval.rb b/mrbgems/mruby-eval/test/eval.rb index 4d7dd4606..4930259c1 100644 --- a/mrbgems/mruby-eval/test/eval.rb +++ b/mrbgems/mruby-eval/test/eval.rb @@ -80,7 +80,7 @@ assert('Kernel.#eval(string) context') do assert_equal('class') { obj.const_string } end -assert('Object#instance_eval with begin-rescue-ensure execution order') do +assert('BasicObject#instance_eval with begin-rescue-ensure execution order') do class HellRaiser def raise_hell order = [:enter_raise_hell] @@ -100,7 +100,7 @@ assert('Object#instance_eval with begin-rescue-ensure execution order') do assert_equal([:enter_raise_hell, :begin, :rescue, :ensure], hell_raiser.raise_hell) end -assert('Kernel#instance_eval() to define singleton methods Issue #3141') do +assert('BasicObject#instance_eval to define singleton methods Issue #3141') do foo_class = Class.new do def bar(x) instance_eval "def baz; #{x}; end" -- cgit v1.2.3 From 67fc3428cb6c0fae2c08c5de36adc7bd0990c4c0 Mon Sep 17 00:00:00 2001 From: dearblue Date: Mon, 6 May 2019 16:28:27 +0900 Subject: Remove "LINE" section reader Because it is not currently output by `mrbc`. --- include/mruby/dump.h | 5 ---- src/load.c | 67 ---------------------------------------------------- 2 files changed, 72 deletions(-) diff --git a/include/mruby/dump.h b/include/mruby/dump.h index 0234a362b..4c7d08253 100644 --- a/include/mruby/dump.h +++ b/include/mruby/dump.h @@ -60,7 +60,6 @@ MRB_API mrb_irep *mrb_read_irep(mrb_state*, const uint8_t*); #define RITE_BINARY_EOF "END\0" #define RITE_SECTION_IREP_IDENT "IREP" -#define RITE_SECTION_LINENO_IDENT "LINE" #define RITE_SECTION_DEBUG_IDENT "DBG\0" #define RITE_SECTION_LV_IDENT "LVAR" @@ -92,10 +91,6 @@ struct rite_section_irep_header { uint8_t rite_version[4]; /* Rite Instruction Specification Version */ }; -struct rite_section_lineno_header { - RITE_SECTION_HEADER; -}; - struct rite_section_debug_header { RITE_SECTION_HEADER; }; diff --git a/src/load.c b/src/load.c index 70f18da31..9af752a15 100644 --- a/src/load.c +++ b/src/load.c @@ -233,66 +233,6 @@ read_section_irep(mrb_state *mrb, const uint8_t *bin, uint8_t flags) return read_irep_record(mrb, bin, &len, flags); } -/* ignore lineno record */ -static int -read_lineno_record_1(mrb_state *mrb, const uint8_t *bin, mrb_irep *irep, size_t *len) -{ - size_t i, fname_len, niseq; - - *len = 0; - bin += sizeof(uint32_t); /* record size */ - *len += sizeof(uint32_t); - fname_len = bin_to_uint16(bin); - bin += sizeof(uint16_t); - *len += sizeof(uint16_t); - bin += fname_len; - *len += fname_len; - - niseq = (size_t)bin_to_uint32(bin); - bin += sizeof(uint32_t); /* niseq */ - *len += sizeof(uint32_t); - - if (SIZE_ERROR_MUL(niseq, sizeof(uint16_t))) { - return MRB_DUMP_GENERAL_FAILURE; - } - for (i = 0; i < niseq; i++) { - bin += sizeof(uint16_t); /* niseq */ - *len += sizeof(uint16_t); - } - - return MRB_DUMP_OK; -} - -static int -read_lineno_record(mrb_state *mrb, const uint8_t *bin, mrb_irep *irep, size_t *lenp) -{ - int result = read_lineno_record_1(mrb, bin, irep, lenp); - int i; - - if (result != MRB_DUMP_OK) return result; - for (i = 0; i < irep->rlen; i++) { - size_t len; - - result = read_lineno_record(mrb, bin, irep->reps[i], &len); - if (result != MRB_DUMP_OK) break; - bin += len; - *lenp += len; - } - return result; -} - -static int -read_section_lineno(mrb_state *mrb, const uint8_t *bin, mrb_irep *irep) -{ - size_t len; - - len = 0; - bin += sizeof(struct rite_section_lineno_header); - - /* Read Binary Data Section */ - return read_lineno_record(mrb, bin, irep, &len); -} - static int read_debug_record(mrb_state *mrb, const uint8_t *start, mrb_irep* irep, size_t *record_len, const mrb_sym *filenames, size_t filenames_len) { @@ -578,13 +518,6 @@ read_irep(mrb_state *mrb, const uint8_t *bin, uint8_t flags) irep = read_section_irep(mrb, bin, flags); if (!irep) return NULL; } - else if (memcmp(section_header->section_ident, RITE_SECTION_LINENO_IDENT, sizeof(section_header->section_ident)) == 0) { - if (!irep) return NULL; /* corrupted data */ - result = read_section_lineno(mrb, bin, irep); - if (result < MRB_DUMP_OK) { - return NULL; - } - } else if (memcmp(section_header->section_ident, RITE_SECTION_DEBUG_IDENT, sizeof(section_header->section_ident)) == 0) { if (!irep) return NULL; /* corrupted data */ result = read_section_debug(mrb, bin, irep, flags); -- cgit v1.2.3 From a6eb01837b5d18d0a9b6fd5e22ab7d99241a1e2a Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Sun, 19 May 2019 13:52:18 +0900 Subject: Fix `Rational#<=>(Numeric)` Reported by Sergey Ukrainskiy: https://github.com/mruby/mruby/commit/f5fb1307b017fb972c12b4ec4b1866d789b0ca09#r33590698 --- mrbgems/mruby-rational/mrblib/rational.rb | 3 +- mrbgems/mruby-rational/test/rational.rb | 168 +++++++++++++++++++++++++++++- 2 files changed, 165 insertions(+), 6 deletions(-) diff --git a/mrbgems/mruby-rational/mrblib/rational.rb b/mrbgems/mruby-rational/mrblib/rational.rb index 19c6da9e7..ad1f3ab0f 100644 --- a/mrbgems/mruby-rational/mrblib/rational.rb +++ b/mrbgems/mruby-rational/mrblib/rational.rb @@ -58,11 +58,12 @@ class Rational < Numeric when Float return to_f <=> rhs end + case rhs when Rational (numerator * rhs.denominator - denominator * rhs.numerator) <=> 0 when Numeric - return rhs <=> self + (rhs <=> self)&.-@ else nil end diff --git a/mrbgems/mruby-rational/test/rational.rb b/mrbgems/mruby-rational/test/rational.rb index a65926bfb..1ff819090 100644 --- a/mrbgems/mruby-rational/test/rational.rb +++ b/mrbgems/mruby-rational/test/rational.rb @@ -3,13 +3,21 @@ def assert_rational(real, exp) assert_float real.denominator, exp.denominator end -def assert_equal_rational(exp, r1, r2) +def assert_equal_rational(exp, o1, o2) if exp - assert_operator(r1, :==, r2) - assert_not_operator(r1, :!=, r2) + assert_operator(o1, :==, o2) + assert_not_operator(o1, :!=, o2) else - assert_not_operator(r1, :==, r2) - assert_operator(r1, :!=, r2) + assert_not_operator(o1, :==, o2) + assert_operator(o1, :!=, o2) + end +end + +def assert_cmp(exp, o1, o2) + if exp == (o1 <=> o2) + pass + else + flunk "", " Expected #{o1.inspect} <=> #{o2.inspect} to be #{exp}" end end @@ -101,6 +109,156 @@ assert 'Float#==(Rational), Float#!=(Rational)' do assert_equal_rational(false, 3.3, Rational(13,4)) end +assert 'Rational#<=>' do + num = Class.new(Numeric) do + def initialize(n) + @n = n + end + + def <=>(rhs) + rhs = rhs.to_i + rhs < 0 ? nil : @n <=> rhs + end + + def inspect + "num(#{@n})" + end + end + + assert_cmp(-1, Rational(-1), Rational(0)) + assert_cmp(0, Rational(0), Rational(0)) + assert_cmp(1, Rational(1), Rational(0)) + assert_cmp(-1, Rational(-1), 0) + assert_cmp(0, Rational(0), 0) + assert_cmp(1, Rational(1), 0) + assert_cmp(-1, Rational(-1), 0.0) + assert_cmp(0, Rational(0), 0.0) + assert_cmp(1, Rational(1), 0.0) + assert_cmp(-1, Rational(1,2), Rational(2,3)) + assert_cmp(0, Rational(2,3), Rational(2,3)) + assert_cmp(1, Rational(2,3), Rational(1,2)) + assert_cmp(1, Rational(2,3), Rational(1,2)) + assert_cmp(1, Rational(0), Rational(-1)) + assert_cmp(-1, Rational(0), Rational(1)) + assert_cmp(1, Rational(2,3), Rational(1,2)) + assert_cmp(0, Rational(2,3), Rational(2,3)) + assert_cmp(-1, Rational(1,2), Rational(2,3)) + assert_cmp(-1, Rational(1,2), Rational(2,3)) + assert_cmp(nil, 3r, "3") + assert_cmp(1, 3r, num.new(2)) + assert_cmp(0, 3r, num.new(3)) + assert_cmp(-1, 3r, num.new(4)) + assert_cmp(nil, Rational(-3), num.new(5)) +end + +assert 'Fixnum#<=>(Rational)' do + assert_cmp(-1, -2, Rational(-9,5)) + assert_cmp(0, 5, 5r) + assert_cmp(1, 3, Rational(8,3)) +end + +assert 'Float#<=>(Rational)' do + assert_cmp(-1, -2.1, Rational(-9,5)) + assert_cmp(0, 5.0, 5r) + assert_cmp(1, 2.7, Rational(8,3)) +end + +assert 'Rational#<' do + assert_operator(Rational(1,2), :<, Rational(2,3)) + assert_not_operator(Rational(2,3), :<, Rational(2,3)) + assert_operator(Rational(2,3), :<, 1) + assert_not_operator(2r, :<, 2) + assert_not_operator(Rational(2,3), :<, -3) + assert_operator(Rational(-4,3), :<, -0.3) + assert_not_operator(Rational(13,4), :<, 3.25) + assert_not_operator(Rational(2,3), :<, 0.6) + assert_raise(ArgumentError) { 1r < "2" } +end + +assert 'Fixnum#<(Rational)' do + assert_not_operator(1, :<, Rational(2,3)) + assert_not_operator(2, :<, 2r) + assert_operator(-3, :<, Rational(2,3)) +end + +assert 'Float#<(Rational)' do + assert_not_operator(-0.3, :<, Rational(-4,3)) + assert_not_operator(3.25, :<, Rational(13,4)) + assert_operator(0.6, :<, Rational(2,3)) +end + +assert 'Rational#<=' do + assert_operator(Rational(1,2), :<=, Rational(2,3)) + assert_operator(Rational(2,3), :<=, Rational(2,3)) + assert_operator(Rational(2,3), :<=, 1) + assert_operator(2r, :<=, 2) + assert_not_operator(Rational(2,3), :<=, -3) + assert_operator(Rational(-4,3), :<=, -0.3) + assert_operator(Rational(13,4), :<=, 3.25) + assert_not_operator(Rational(2,3), :<=, 0.6) + assert_raise(ArgumentError) { 1r <= "2" } +end + +assert 'Fixnum#<=(Rational)' do + assert_not_operator(1, :<=, Rational(2,3)) + assert_operator(2, :<=, 2r) + assert_operator(-3, :<=, Rational(2,3)) +end + +assert 'Float#<=(Rational)' do + assert_not_operator(-0.3, :<=, Rational(-4,3)) + assert_operator(3.25, :<=, Rational(13,4)) + assert_operator(0.6, :<=, Rational(2,3)) +end + +assert 'Rational#>' do + assert_not_operator(Rational(1,2), :>, Rational(2,3)) + assert_not_operator(Rational(2,3), :>, Rational(2,3)) + assert_not_operator(Rational(2,3), :>, 1) + assert_not_operator(2r, :>, 2) + assert_operator(Rational(2,3), :>, -3) + assert_not_operator(Rational(-4,3), :>, -0.3) + assert_not_operator(Rational(13,4), :>, 3.25) + assert_operator(Rational(2,3), :>, 0.6) + assert_raise(ArgumentError) { 1r > "2" } +end + +assert 'Fixnum#>(Rational)' do + assert_operator(1, :>, Rational(2,3)) + assert_not_operator(2, :>, 2r) + assert_not_operator(-3, :>, Rational(2,3)) +end + +assert 'Float#>(Rational)' do + assert_operator(-0.3, :>, Rational(-4,3)) + assert_not_operator(3.25, :>, Rational(13,4)) + assert_not_operator(0.6, :>, Rational(2,3)) +end + +assert 'Rational#>=' do + assert_not_operator(Rational(1,2), :>=, Rational(2,3)) + assert_operator(Rational(2,3), :>=, Rational(2,3)) + assert_not_operator(Rational(2,3), :>=, 1) + assert_operator(2r, :>=, 2) + assert_operator(Rational(2,3), :>=, -3) + assert_not_operator(Rational(-4,3), :>=, -0.3) + assert_operator(Rational(13,4), :>=, 3.25) + assert_operator(Rational(2,3), :>=, 0.6) + assert_raise(ArgumentError) { 1r >= "2" } +end + +assert 'Fixnum#>=(Rational)' do + assert_operator(1, :>=, Rational(2,3)) + assert_operator(2, :>=, 2r) + assert_not_operator(-3, :>=, Rational(2,3)) +end + +assert 'Float#>=(Rational)' do + assert_operator(-0.3, :>=, Rational(-4,3)) + assert_operator(3.25, :>=, Rational(13,4)) + assert_not_operator(0.6, :>=, Rational(2,3)) +end + assert 'Rational#negative?' do assert_predicate(Rational(-2,3), :negative?) assert_predicate(Rational(2,-3), :negative?) -- cgit v1.2.3 From 8e637bdd83505e8c1723f87a8d267e00ee209787 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Sun, 19 May 2019 22:15:27 +0900 Subject: Should clarify the role of `mruby-kernel-ext` and `mruby-object-ext`; close #4449 The former should contain function like methods, and the latter should contain methods shared by all objects. --- mrbgems/mruby-kernel-ext/mrblib/kernel.rb | 15 --------------- mrbgems/mruby-kernel-ext/src/kernel.c | 17 ----------------- mrbgems/mruby-object-ext/mrblib/object.rb | 16 +++++++++++++++- mrbgems/mruby-object-ext/src/object.c | 17 +++++++++++++++++ 4 files changed, 32 insertions(+), 33 deletions(-) delete mode 100644 mrbgems/mruby-kernel-ext/mrblib/kernel.rb diff --git a/mrbgems/mruby-kernel-ext/mrblib/kernel.rb b/mrbgems/mruby-kernel-ext/mrblib/kernel.rb deleted file mode 100644 index bf739ed1a..000000000 --- a/mrbgems/mruby-kernel-ext/mrblib/kernel.rb +++ /dev/null @@ -1,15 +0,0 @@ -module Kernel - # call-seq: - # obj.yield_self {|_obj|...} -> an_object - # obj.then {|_obj|...} -> an_object - # - # Yields obj and returns the result. - # - # 'my string'.yield_self {|s|s.upcase} #=> "MY STRING" - # - def yield_self(&block) - return to_enum :yield_self unless block - block.call(self) - end - alias then yield_self -end diff --git a/mrbgems/mruby-kernel-ext/src/kernel.c b/mrbgems/mruby-kernel-ext/src/kernel.c index 99affbfa4..9288b0e6f 100644 --- a/mrbgems/mruby-kernel-ext/src/kernel.c +++ b/mrbgems/mruby-kernel-ext/src/kernel.c @@ -206,22 +206,6 @@ mrb_f_hash(mrb_state *mrb, mrb_value self) return mrb_ensure_hash_type(mrb, arg); } -/* - * call-seq: - * obj.itself -> an_object - * - * Returns obj. - * - * string = 'my string' #=> "my string" - * string.itself.object_id == string.object_id #=> true - * - */ -static mrb_value -mrb_f_itself(mrb_state *mrb, mrb_value self) -{ - return self; -} - void mrb_mruby_kernel_ext_gem_init(mrb_state *mrb) { @@ -237,7 +221,6 @@ mrb_mruby_kernel_ext_gem_init(mrb_state *mrb) mrb_define_module_function(mrb, krn, "String", mrb_f_string, MRB_ARGS_REQ(1)); mrb_define_module_function(mrb, krn, "Array", mrb_f_array, MRB_ARGS_REQ(1)); mrb_define_module_function(mrb, krn, "Hash", mrb_f_hash, MRB_ARGS_REQ(1)); - mrb_define_module_function(mrb, krn, "itself", mrb_f_itself, MRB_ARGS_NONE()); } void diff --git a/mrbgems/mruby-object-ext/mrblib/object.rb b/mrbgems/mruby-object-ext/mrblib/object.rb index 581156cb0..f014df469 100644 --- a/mrbgems/mruby-object-ext/mrblib/object.rb +++ b/mrbgems/mruby-object-ext/mrblib/object.rb @@ -1,4 +1,18 @@ -class Object +module Kernel + # call-seq: + # obj.yield_self {|_obj|...} -> an_object + # obj.then {|_obj|...} -> an_object + # + # Yields obj and returns the result. + # + # 'my string'.yield_self {|s|s.upcase} #=> "MY STRING" + # + def yield_self(&block) + return to_enum :yield_self unless block + block.call(self) + end + alias then yield_self + ## # call-seq: # obj.tap{|x|...} -> obj diff --git a/mrbgems/mruby-object-ext/src/object.c b/mrbgems/mruby-object-ext/src/object.c index b076b3ec0..dce97132c 100644 --- a/mrbgems/mruby-object-ext/src/object.c +++ b/mrbgems/mruby-object-ext/src/object.c @@ -44,6 +44,22 @@ nil_to_i(mrb_state *mrb, mrb_value obj) return mrb_fixnum_value(0); } +/* + * call-seq: + * obj.itself -> an_object + * + * Returns obj. + * + * string = 'my string' #=> "my string" + * string.itself.object_id == string.object_id #=> true + * + */ +static mrb_value +mrb_f_itself(mrb_state *mrb, mrb_value self) +{ + return self; +} + /* * call-seq: * obj.instance_exec(arg...) {|var...| block } -> obj @@ -102,6 +118,7 @@ mrb_mruby_object_ext_gem_init(mrb_state* mrb) mrb_define_method(mrb, n, "to_f", nil_to_f, MRB_ARGS_NONE()); #endif mrb_define_method(mrb, n, "to_i", nil_to_i, MRB_ARGS_NONE()); + mrb_define_module_function(mrb, mrb->kernel_module, "itself", mrb_f_itself, MRB_ARGS_NONE()); mrb_define_method(mrb, mrb->kernel_module, "instance_exec", mrb_obj_instance_exec, MRB_ARGS_ANY() | MRB_ARGS_BLOCK()); } -- cgit v1.2.3 From 8b8bf9f3f696f28836138b8106147d9d3e6071a2 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Mon, 20 May 2019 14:59:25 +0900 Subject: Add new functions for numerical operation; ref 237a57b New functions: * mrb_num_plus(mrb, x, y) * mrb_num_minus(mrb, x, y) * num_num_mul(mrb, x, y) --- include/mruby/numeric.h | 4 ++++ src/numeric.c | 54 +++++++++++++++++++++++++++++++++++++++++++------ 2 files changed, 52 insertions(+), 6 deletions(-) diff --git a/include/mruby/numeric.h b/include/mruby/numeric.h index 9d87ca5c4..d670504c2 100644 --- a/include/mruby/numeric.h +++ b/include/mruby/numeric.h @@ -36,6 +36,10 @@ MRB_API mrb_value mrb_float_to_str(mrb_state *mrb, mrb_value x, const char *fmt) MRB_API mrb_float mrb_to_flo(mrb_state *mrb, mrb_value x); #endif +MRB_API mrb_value mrb_num_plus(mrb_state *mrb, mrb_value x, mrb_value y); +MRB_API mrb_value mrb_num_minus(mrb_state *mrb, mrb_value x, mrb_value y); +MRB_API mrb_value mrb_num_mul(mrb_state *mrb, mrb_value x, mrb_value y); + #ifndef __has_builtin #define __has_builtin(x) 0 #endif diff --git a/src/numeric.c b/src/numeric.c index e73bdaca2..3ad5721ef 100644 --- a/src/numeric.c +++ b/src/numeric.c @@ -788,7 +788,7 @@ int_to_i(mrb_state *mrb, mrb_value num) } static mrb_value -mrb_fixnum_mul(mrb_state *mrb, mrb_value x, mrb_value y) +fixnum_mul(mrb_state *mrb, mrb_value x, mrb_value y) { mrb_int a; @@ -812,6 +812,20 @@ mrb_fixnum_mul(mrb_state *mrb, mrb_value x, mrb_value y) #endif } +MRB_API mrb_value +mrb_num_mul(mrb_state *mrb, mrb_value x, mrb_value y) +{ + if (mrb_fixnum_p(x)) { + return fixnum_mul(mrb, x, y); + } +#ifndef MRB_WITHOUT_FLOAT + if (mrb_float_p(x)) { + return mrb_float_value(mrb, mrb_float(x) * mrb_to_flo(mrb, y)); + } +#endif + mrb_raise(mrb, E_TYPE_ERROR, "no number multiply"); +} + /* 15.2.8.3.3 */ /* * call-seq: @@ -828,7 +842,7 @@ fix_mul(mrb_state *mrb, mrb_value x) mrb_value y; mrb_get_args(mrb, "o", &y); - return mrb_fixnum_mul(mrb, x, y); + return fixnum_mul(mrb, x, y); } static void @@ -1245,7 +1259,7 @@ mrb_flo_to_fixnum(mrb_state *mrb, mrb_value x) #endif static mrb_value -mrb_fixnum_plus(mrb_state *mrb, mrb_value x, mrb_value y) +fixnum_plus(mrb_state *mrb, mrb_value x, mrb_value y) { mrb_int a; @@ -1269,6 +1283,20 @@ mrb_fixnum_plus(mrb_state *mrb, mrb_value x, mrb_value y) #endif } +MRB_API mrb_value +mrb_num_plus(mrb_state *mrb, mrb_value x, mrb_value y) +{ + if (mrb_fixnum_p(x)) { + return fixnum_plus(mrb, x, y); + } +#ifndef MRB_WITHOUT_FLOAT + if (mrb_float_p(x)) { + return mrb_float_value(mrb, mrb_float(x) + mrb_to_flo(mrb, y)); + } +#endif + mrb_raise(mrb, E_TYPE_ERROR, "no number addition"); +} + /* 15.2.8.3.1 */ /* * call-seq: @@ -1284,11 +1312,11 @@ fix_plus(mrb_state *mrb, mrb_value self) mrb_value other; mrb_get_args(mrb, "o", &other); - return mrb_fixnum_plus(mrb, self, other); + return fixnum_plus(mrb, self, other); } static mrb_value -mrb_fixnum_minus(mrb_state *mrb, mrb_value x, mrb_value y) +fixnum_minus(mrb_state *mrb, mrb_value x, mrb_value y) { mrb_int a; @@ -1311,6 +1339,20 @@ mrb_fixnum_minus(mrb_state *mrb, mrb_value x, mrb_value y) #endif } +MRB_API mrb_value +mrb_num_minus(mrb_state *mrb, mrb_value x, mrb_value y) +{ + if (mrb_fixnum_p(x)) { + return fixnum_minus(mrb, x, y); + } +#ifdef MRB_WITHOUT_FLOAT + if (mrb_float_p(x)) { + return mrb_float_value(mrb, mrb_float(x) - mrb_to_flo(mrb, y)); + } +#endif + mrb_raise(mrb, E_TYPE_ERROR, "no number subtraction"); +} + /* 15.2.8.3.2 */ /* 15.2.8.3.16 */ /* @@ -1327,7 +1369,7 @@ fix_minus(mrb_state *mrb, mrb_value self) mrb_value other; mrb_get_args(mrb, "o", &other); - return mrb_fixnum_minus(mrb, self, other); + return fixnum_minus(mrb, self, other); } -- cgit v1.2.3 From 97600ded8d7717f327a3bf00e904a7ebb38dbd64 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Mon, 20 May 2019 18:24:18 +0900 Subject: Change the order of "expected" and "actual" in `mruby-rational` test --- mrbgems/mruby-rational/test/rational.rb | 68 ++++++++++++++++----------------- 1 file changed, 34 insertions(+), 34 deletions(-) diff --git a/mrbgems/mruby-rational/test/rational.rb b/mrbgems/mruby-rational/test/rational.rb index 1ff819090..5a1055ee7 100644 --- a/mrbgems/mruby-rational/test/rational.rb +++ b/mrbgems/mruby-rational/test/rational.rb @@ -1,6 +1,6 @@ -def assert_rational(real, exp) - assert_float real.numerator, exp.numerator - assert_float real.denominator, exp.denominator +def assert_rational(exp, real) + assert_float exp.numerator, real.numerator + assert_float exp.denominator, real.denominator end def assert_equal_rational(exp, o1, o2) @@ -23,55 +23,55 @@ end assert 'Rational' do r = 5r - assert_equal Rational, r.class - assert_equal [r.numerator, r.denominator], [5, 1] + assert_equal(r.class, Rational) + assert_equal([5, 1], [r.numerator, r.denominator]) end assert 'Rational#to_f' do - assert_float Rational(2).to_f, 2.0 - assert_float Rational(9, 4).to_f, 2.25 - assert_float Rational(-3, 4).to_f, -0.75 - assert_float Rational(20, 3).to_f, 6.666666666666667 + assert_float(2.0, Rational(2).to_f) + assert_float(2.25, Rational(9, 4).to_f) + assert_float(-0.75, Rational(-3, 4).to_f) + assert_float(6.666666666666667, Rational(20, 3).to_f) end assert 'Rational#to_i' do - assert_equal Rational(2, 3).to_i, 0 - assert_equal Rational(3).to_i, 3 - assert_equal Rational(300.6).to_i, 300 - assert_equal Rational(98, 71).to_i, 1 - assert_equal Rational(-30, 2).to_i, -15 + assert_equal(0, Rational(2, 3).to_i) + assert_equal(3, Rational(3).to_i) + assert_equal(300, Rational(300.6).to_i) + assert_equal(1, Rational(98, 71).to_i) + assert_equal(-15, Rational(-30, 2).to_i) end assert 'Rational#*' do - assert_rational Rational(2, 3) * Rational(2, 3), Rational(4, 9) - assert_rational Rational(900) * Rational(1), Rational(900, 1) - assert_rational Rational(-2, 9) * Rational(-9, 2), Rational(1, 1) - assert_rational Rational(9, 8) * 4, Rational(9, 2) - assert_float Rational(20, 9) * 9.8, 21.77777777777778 + assert_rational(Rational(4, 9), Rational(2, 3) * Rational(2, 3)) + assert_rational(Rational(900, 1), Rational(900) * Rational(1)) + assert_rational(Rational(1, 1), Rational(-2, 9) * Rational(-9, 2)) + assert_rational(Rational(9, 2), Rational(9, 8) * 4) + assert_float( 21.77777777777778, Rational(20, 9) * 9.8) end assert 'Rational#+' do - assert_rational Rational(2, 3) + Rational(2, 3), Rational(4, 3) - assert_rational Rational(900) + Rational(1), Rational(901, 1) - assert_rational Rational(-2, 9) + Rational(-9, 2), Rational(-85, 18) - assert_rational Rational(9, 8) + 4, Rational(41, 8) - assert_float Rational(20, 9) + 9.8, 12.022222222222222 + assert_rational(Rational(4, 3), Rational(2, 3) + Rational(2, 3)) + assert_rational(Rational(901, 1), Rational(900) + Rational(1)) + assert_rational(Rational(-85, 18), Rational(-2, 9) + Rational(-9, 2)) + assert_rational(Rational(41, 8), Rational(9, 8) + 4) + assert_float( 12.022222222222222, Rational(20, 9) + 9.8) end assert 'Rational#-' do - assert_rational Rational(2, 3) - Rational(2, 3), Rational(0, 1) - assert_rational Rational(900) - Rational(1), Rational(899, 1) - assert_rational Rational(-2, 9) - Rational(-9, 2), Rational(77, 18) - assert_rational Rational(9, 8) - 4, Rational(-23, 8) - assert_float Rational(20, 9) - 9.8, -7.577777777777778 + assert_rational(Rational(0, 1), Rational(2, 3) - Rational(2, 3)) + assert_rational(Rational(899, 1), Rational(900) - Rational(1)) + assert_rational(Rational(77, 18), Rational(-2, 9) - Rational(-9, 2)) + assert_rational(Rational(-23, 8), Rational(9, 8) - 4) + assert_float( -7.577777777777778, Rational(20, 9) - 9.8) end assert 'Rational#/' do - assert_rational Rational(2, 3) / Rational(2, 3), Rational(1, 1) - assert_rational Rational(900) / Rational(1), Rational(900, 1) - assert_rational Rational(-2, 9) / Rational(-9, 2), Rational(4, 81) - assert_rational Rational(9, 8) / 4, Rational(9, 32) - assert_float Rational(20, 9) / 9.8, 0.22675736961451246 + assert_rational(Rational(1, 1), Rational(2, 3) / Rational(2, 3)) + assert_rational(Rational(900, 1), Rational(900) / Rational(1)) + assert_rational(Rational(4, 81), Rational(-2, 9) / Rational(-9, 2)) + assert_rational(Rational(9, 32), Rational(9, 8) / 4) + assert_float( 0.22675736961451246, Rational(20, 9) / 9.8) end assert 'Rational#==, Rational#!=' do -- cgit v1.2.3 From 3db5d7fe3d91c17719ab69a2161d1a0581e5ed2c Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Mon, 20 May 2019 18:36:13 +0900 Subject: Drop dependency from `mruby-rational` to `mruby-object-ext` --- mrbgems/mruby-rational/mrbgem.rake | 2 -- mrbgems/mruby-rational/mrblib/rational.rb | 4 ++-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/mrbgems/mruby-rational/mrbgem.rake b/mrbgems/mruby-rational/mrbgem.rake index 15c3429f2..4b540dec4 100644 --- a/mrbgems/mruby-rational/mrbgem.rake +++ b/mrbgems/mruby-rational/mrbgem.rake @@ -2,6 +2,4 @@ MRuby::Gem::Specification.new('mruby-rational') do |spec| spec.license = 'MIT' spec.author = 'mruby developers' spec.summary = 'Rational class' - - spec.add_dependency 'mruby-object-ext', core: 'mruby-object-ext' end diff --git a/mrbgems/mruby-rational/mrblib/rational.rb b/mrbgems/mruby-rational/mrblib/rational.rb index ad1f3ab0f..28c96c69f 100644 --- a/mrbgems/mruby-rational/mrblib/rational.rb +++ b/mrbgems/mruby-rational/mrblib/rational.rb @@ -86,7 +86,7 @@ module Kernel end [:+, :-, :*, :/, :<=>, :==, :<, :<=, :>, :>=].each do |op| - Fixnum.instance_exec do + Fixnum.instance_eval do original_operator_name = "__original_operator_#{op}_rational" alias_method original_operator_name, op define_method op do |rhs| @@ -97,7 +97,7 @@ end end end end - Float.instance_exec do + Float.instance_eval do original_operator_name = "__original_operator_#{op}_rational" alias_method original_operator_name, op define_method op do |rhs| -- cgit v1.2.3 From 5d6c1794ad8620279514f45770ab4e8eeb16c734 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Tue, 21 May 2019 09:31:06 +0900 Subject: Revert part of #4457 --- mrbgems/mruby-rational/test/rational.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mrbgems/mruby-rational/test/rational.rb b/mrbgems/mruby-rational/test/rational.rb index 5a1055ee7..ea55880fe 100644 --- a/mrbgems/mruby-rational/test/rational.rb +++ b/mrbgems/mruby-rational/test/rational.rb @@ -23,7 +23,7 @@ end assert 'Rational' do r = 5r - assert_equal(r.class, Rational) + assert_equal(Rational, r.class) assert_equal([5, 1], [r.numerator, r.denominator]) end -- cgit v1.2.3 From 3b46831da83b4d5d5355c60261fb3ebe2a885513 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Tue, 21 May 2019 20:26:53 +0900 Subject: Move `**`,`/`,`quo`,`div` and comparison methods to Integral from Numeric Having these methods in Numeric can get in the way of creating subclasses of Numeric because they only support Fixnum and Float. --- mrbgems/mruby-rational/mrblib/rational.rb | 3 --- src/numeric.c | 37 +++++++++++++++---------------- 2 files changed, 18 insertions(+), 22 deletions(-) diff --git a/mrbgems/mruby-rational/mrblib/rational.rb b/mrbgems/mruby-rational/mrblib/rational.rb index 28c96c69f..cecede48a 100644 --- a/mrbgems/mruby-rational/mrblib/rational.rb +++ b/mrbgems/mruby-rational/mrblib/rational.rb @@ -1,7 +1,4 @@ class Rational < Numeric - # Override #<, #<=, #>, #>= in Numeric - prepend Comparable - def inspect "(#{to_s})" end diff --git a/src/numeric.c b/src/numeric.c index 3ad5721ef..c740a32e3 100644 --- a/src/numeric.c +++ b/src/numeric.c @@ -65,7 +65,7 @@ mrb_int_value(mrb_state *mrb, mrb_float f) * 2.0**3 #=> 8.0 */ static mrb_value -num_pow(mrb_state *mrb, mrb_value x) +integral_pow(mrb_state *mrb, mrb_value x) { mrb_value y; #ifndef MRB_WITHOUT_FLOAT @@ -113,7 +113,7 @@ num_pow(mrb_state *mrb, mrb_value x) } static mrb_value -num_idiv(mrb_state *mrb, mrb_value x) +integral_idiv(mrb_state *mrb, mrb_value x) { #ifdef MRB_WITHOUT_FLOAT mrb_value y; @@ -151,7 +151,7 @@ num_idiv(mrb_state *mrb, mrb_value x) */ static mrb_value -num_div(mrb_state *mrb, mrb_value x) +integral_div(mrb_state *mrb, mrb_value x) { #ifdef MRB_WITHOUT_FLOAT mrb_value y; @@ -1479,7 +1479,7 @@ cmpnum(mrb_state *mrb, mrb_value v1, mrb_value v2) * basis for the tests in Comparable. */ static mrb_value -num_cmp(mrb_state *mrb, mrb_value self) +integral_cmp(mrb_state *mrb, mrb_value self) { mrb_value other; mrb_int n; @@ -1499,7 +1499,7 @@ cmperr(mrb_state *mrb, mrb_value v1, mrb_value v2) } static mrb_value -num_lt(mrb_state *mrb, mrb_value self) +integral_lt(mrb_state *mrb, mrb_value self) { mrb_value other; mrb_int n; @@ -1512,7 +1512,7 @@ num_lt(mrb_state *mrb, mrb_value self) } static mrb_value -num_le(mrb_state *mrb, mrb_value self) +integral_le(mrb_state *mrb, mrb_value self) { mrb_value other; mrb_int n; @@ -1525,7 +1525,7 @@ num_le(mrb_state *mrb, mrb_value self) } static mrb_value -num_gt(mrb_state *mrb, mrb_value self) +integral_gt(mrb_state *mrb, mrb_value self) { mrb_value other; mrb_int n; @@ -1538,7 +1538,7 @@ num_gt(mrb_state *mrb, mrb_value self) } static mrb_value -num_ge(mrb_state *mrb, mrb_value self) +integral_ge(mrb_state *mrb, mrb_value self) { mrb_value other; mrb_int n; @@ -1593,20 +1593,19 @@ mrb_init_numeric(mrb_state *mrb) #endif integral = mrb_define_module(mrb, "Integral"); - mrb_define_method(mrb, integral, "__coerce_step_counter", integral_coerce_step_counter, MRB_ARGS_REQ(2)); + mrb_define_method(mrb, integral,"**", integral_pow, MRB_ARGS_REQ(1)); + mrb_define_method(mrb, integral,"/", integral_div, MRB_ARGS_REQ(1)); /* 15.2.8.3.4 */ + mrb_define_method(mrb, integral,"quo", integral_div, MRB_ARGS_REQ(1)); /* 15.2.7.4.5 (x) */ + mrb_define_method(mrb, integral,"div", integral_idiv, MRB_ARGS_REQ(1)); + mrb_define_method(mrb, integral,"<=>", integral_cmp, MRB_ARGS_REQ(1)); /* 15.2.9.3.6 */ + mrb_define_method(mrb, integral,"<", integral_lt, MRB_ARGS_REQ(1)); + mrb_define_method(mrb, integral,"<=", integral_le, MRB_ARGS_REQ(1)); + mrb_define_method(mrb, integral,">", integral_gt, MRB_ARGS_REQ(1)); + mrb_define_method(mrb, integral,">=", integral_ge, MRB_ARGS_REQ(1)); + mrb_define_method(mrb, integral,"__coerce_step_counter", integral_coerce_step_counter, MRB_ARGS_REQ(2)); /* Numeric Class */ numeric = mrb_define_class(mrb, "Numeric", mrb->object_class); /* 15.2.7 */ - - mrb_define_method(mrb, numeric, "**", num_pow, MRB_ARGS_REQ(1)); - mrb_define_method(mrb, numeric, "/", num_div, MRB_ARGS_REQ(1)); /* 15.2.8.3.4 */ - mrb_define_method(mrb, numeric, "quo", num_div, MRB_ARGS_REQ(1)); /* 15.2.7.4.5 (x) */ - mrb_define_method(mrb, numeric, "div", num_idiv, MRB_ARGS_REQ(1)); - mrb_define_method(mrb, numeric, "<=>", num_cmp, MRB_ARGS_REQ(1)); /* 15.2.9.3.6 */ - mrb_define_method(mrb, numeric, "<", num_lt, MRB_ARGS_REQ(1)); - mrb_define_method(mrb, numeric, "<=", num_le, MRB_ARGS_REQ(1)); - mrb_define_method(mrb, numeric, ">", num_gt, MRB_ARGS_REQ(1)); - mrb_define_method(mrb, numeric, ">=", num_ge, MRB_ARGS_REQ(1)); mrb_define_method(mrb, numeric, "finite?", num_finite_p, MRB_ARGS_NONE()); mrb_define_method(mrb, numeric, "infinite?",num_infinite_p, MRB_ARGS_NONE()); -- cgit v1.2.3 From 5d30309e9826fe1a392fa7a7a33e11ad58857b3f Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Mon, 20 May 2019 16:32:00 +0900 Subject: Silence the return value warnings from gcc; ref 237a57b --- src/numeric.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/numeric.c b/src/numeric.c index c740a32e3..140cd0101 100644 --- a/src/numeric.c +++ b/src/numeric.c @@ -824,6 +824,7 @@ mrb_num_mul(mrb_state *mrb, mrb_value x, mrb_value y) } #endif mrb_raise(mrb, E_TYPE_ERROR, "no number multiply"); + return mrb_nil_value(); /* not reached */ } /* 15.2.8.3.3 */ @@ -1295,6 +1296,7 @@ mrb_num_plus(mrb_state *mrb, mrb_value x, mrb_value y) } #endif mrb_raise(mrb, E_TYPE_ERROR, "no number addition"); + return mrb_nil_value(); /* not reached */ } /* 15.2.8.3.1 */ @@ -1351,6 +1353,7 @@ mrb_num_minus(mrb_state *mrb, mrb_value x, mrb_value y) } #endif mrb_raise(mrb, E_TYPE_ERROR, "no number subtraction"); + return mrb_nil_value(); /* not reached */ } /* 15.2.8.3.2 */ -- cgit v1.2.3 From b7f85b9df91168f8c6338354bc50a621ca0e098b Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Mon, 20 May 2019 16:35:06 +0900 Subject: Should not refer `Float` class in case of `MRB_WITHOUT_FLOAT`. This commit removes `Float` from `rational.c`. --- mrbgems/mruby-rational/mrblib/rational.rb | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/mrbgems/mruby-rational/mrblib/rational.rb b/mrbgems/mruby-rational/mrblib/rational.rb index cecede48a..c8614ecea 100644 --- a/mrbgems/mruby-rational/mrblib/rational.rb +++ b/mrbgems/mruby-rational/mrblib/rational.rb @@ -48,12 +48,9 @@ class Rational < Numeric end def <=>(rhs) - case rhs - when Fixnum + if rhs.is_a?(Integral) return numerator <=> rhs if denominator == 1 rhs = Rational(rhs) - when Float - return to_f <=> rhs end case rhs @@ -103,5 +100,5 @@ end end __send__(original_operator_name, rhs) end - end + end if Object.const_defined?(:Float) end -- cgit v1.2.3 From f6e4145ad960d9bc748f9c91fd4c5db5afeebbd0 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Tue, 21 May 2019 16:06:37 +0900 Subject: Remove `Complex(string)` complex generation. It should raise an error. --- mrbgems/mruby-complex/test/complex.rb | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/mrbgems/mruby-complex/test/complex.rb b/mrbgems/mruby-complex/test/complex.rb index ca58202c2..e7fcc7322 100644 --- a/mrbgems/mruby-complex/test/complex.rb +++ b/mrbgems/mruby-complex/test/complex.rb @@ -63,8 +63,6 @@ assert 'Complex#==' do assert_true Complex(2, 3) == Complex(2, 3) assert_true Complex(5) == 5 assert_true Complex(0) == 0.0 - assert_false Complex('1/3') == 0.33 - assert_false Complex('1/2') == '1/2' end assert 'Complex#abs' do @@ -127,4 +125,4 @@ assert 'Complex::to_i' do assert_raise(RangeError) do Complex(1, 2).to_i end -end \ No newline at end of file +end -- cgit v1.2.3 From e941cf06a3e0351107d36d49d540562fdf49f9b4 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Tue, 21 May 2019 16:08:02 +0900 Subject: Export `mrb_int_value` that converts `mrb_float` to `Fixnum`. Or `Float` if `mrb_float` value is too big (or too small) to fit in `mrb_int`. The `_int_` in `mrb_int_value` means `Integral` module, which represents integer-like values in mruby. --- include/mruby/numeric.h | 1 + src/numeric.c | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/include/mruby/numeric.h b/include/mruby/numeric.h index d670504c2..34707e441 100644 --- a/include/mruby/numeric.h +++ b/include/mruby/numeric.h @@ -34,6 +34,7 @@ MRB_API mrb_value mrb_fixnum_to_str(mrb_state *mrb, mrb_value x, mrb_int base); #ifndef MRB_WITHOUT_FLOAT MRB_API mrb_value mrb_float_to_str(mrb_state *mrb, mrb_value x, const char *fmt); MRB_API mrb_float mrb_to_flo(mrb_state *mrb, mrb_value x); +MRB_API mrb_value mrb_int_value(mrb_state *mrb, mrb_float f); #endif MRB_API mrb_value mrb_num_plus(mrb_state *mrb, mrb_value x, mrb_value y); diff --git a/src/numeric.c b/src/numeric.c index 140cd0101..e15b7f671 100644 --- a/src/numeric.c +++ b/src/numeric.c @@ -45,7 +45,7 @@ mrb_to_flo(mrb_state *mrb, mrb_value val) return mrb_float(val); } -static mrb_value +MRB_API mrb_value mrb_int_value(mrb_state *mrb, mrb_float f) { if (FIXABLE_FLOAT(f)) { -- cgit v1.2.3 From fccec8964a1b30cef8ff9d97e0e01f3a348e318b Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Tue, 21 May 2019 16:11:25 +0900 Subject: Implements part of `Complex` class in C. --- mrbgems/mruby-complex/mrblib/complex.rb | 50 +++----------- mrbgems/mruby-complex/src/complex.c | 116 ++++++++++++++++++++++++++++++++ mrbgems/mruby-rational/src/rational.c | 2 +- 3 files changed, 127 insertions(+), 41 deletions(-) create mode 100644 mrbgems/mruby-complex/src/complex.c diff --git a/mrbgems/mruby-complex/mrblib/complex.rb b/mrbgems/mruby-complex/mrblib/complex.rb index 8ae743e77..4c0c19c70 100644 --- a/mrbgems/mruby-complex/mrblib/complex.rb +++ b/mrbgems/mruby-complex/mrblib/complex.rb @@ -23,43 +23,43 @@ class Complex < Numeric end def +@ - Complex(real, imaginary) + Complex._new(real, imaginary) end def -@ - Complex(-real, -imaginary) + Complex._new(-real, -imaginary) end def +(rhs) if rhs.is_a? Complex - Complex(real + rhs.real, imaginary + rhs.imaginary) + Complex._new(real + rhs.real, imaginary + rhs.imaginary) elsif rhs.is_a? Numeric - Complex(real + rhs, imaginary) + Complex._new(real + rhs, imaginary) end end def -(rhs) if rhs.is_a? Complex - Complex(real - rhs.real, imaginary - rhs.imaginary) + Complex._new(real - rhs.real, imaginary - rhs.imaginary) elsif rhs.is_a? Numeric - Complex(real - rhs, imaginary) + Complex._new(real - rhs, imaginary) end end def *(rhs) if rhs.is_a? Complex - Complex(real * rhs.real - imaginary * rhs.imaginary, real * rhs.imaginary + rhs.real * imaginary) + Complex._new(real * rhs.real - imaginary * rhs.imaginary, real * rhs.imaginary + rhs.real * imaginary) elsif rhs.is_a? Numeric - Complex(real * rhs, imaginary * rhs) + Complex._new(real * rhs, imaginary * rhs) end end def /(rhs) if rhs.is_a? Complex div = rhs.real * rhs.real + rhs.imaginary * rhs.imaginary - Complex((real * rhs.real + imaginary * rhs.imaginary) / div, (rhs.real * imaginary - real * rhs.imaginary) / div) + Complex._new((real * rhs.real + imaginary * rhs.imaginary) / div, (rhs.real * imaginary - real * rhs.imaginary) / div) elsif rhs.is_a? Numeric - Complex(real / rhs, imaginary / rhs) + Complex._new(real / rhs, imaginary / rhs) end end alias_method :quo, :/ @@ -92,14 +92,6 @@ class Complex < Numeric end alias_method :conj, :conjugate - def numerator - self - end - - def denominator - 1 - end - def fdiv(numeric) Complex(real.to_f / numeric, imaginary.to_f / numeric) end @@ -117,36 +109,14 @@ class Complex < Numeric end alias_method :rect, :rectangular - def to_c - self - end - - def to_f - raise RangeError.new "can't convert #{to_s} into Float" unless imaginary.zero? - real.to_f - end - - def to_i - raise RangeError.new "can't convert #{to_s} into Integer" unless imaginary.zero? - real.to_i - end - def to_r raise RangeError.new "can't convert #{to_s} into Rational" unless imaginary.zero? Rational(real, 1) end - attr_reader :real, :imaginary alias_method :imag, :imaginary end -class << Complex - alias_method :_new, :new - undef_method :new - - alias_method :rect, :rectangular -end - module Kernel def Complex(real, imaginary = 0) Complex.rectangular(real, imaginary) diff --git a/mrbgems/mruby-complex/src/complex.c b/mrbgems/mruby-complex/src/complex.c new file mode 100644 index 000000000..5de0ae9a4 --- /dev/null +++ b/mrbgems/mruby-complex/src/complex.c @@ -0,0 +1,116 @@ +#include +#include +#include + +struct mrb_complex { + mrb_float real; + mrb_float imaginary; +}; + +#include + +static const struct mrb_data_type mrb_complex_type = {"Complex", mrb_free}; + +static mrb_value +complex_new(mrb_state *mrb, mrb_float real, mrb_float imaginary) +{ + struct RClass *c = mrb_class_get(mrb, "Complex"); + struct mrb_complex *p; + + p = (struct mrb_complex*)mrb_malloc(mrb, sizeof(struct mrb_complex)); + p->real = real; + p->imaginary = imaginary; + + return mrb_obj_value(Data_Wrap_Struct(mrb, c, &mrb_complex_type, p)); +} + +static struct mrb_complex* +complex_ptr(mrb_state *mrb, mrb_value v) +{ + struct mrb_complex *p; + + p = DATA_GET_PTR(mrb, v, &mrb_complex_type, struct mrb_complex); + if (!p) { + mrb_raise(mrb, E_ARGUMENT_ERROR, "uninitialized complex"); + } + return p; +} + +static mrb_value +complex_real(mrb_state *mrb, mrb_value self) +{ + struct mrb_complex *p = complex_ptr(mrb, self); + return mrb_float_value(mrb, p->real); +} + +static mrb_value +complex_imaginary(mrb_state *mrb, mrb_value self) +{ + struct mrb_complex *p = complex_ptr(mrb, self); + return mrb_float_value(mrb, p->imaginary); +} + +static mrb_value +complex_s_new(mrb_state *mrb, mrb_value self) +{ + mrb_float real, imaginary; + + mrb_get_args(mrb, "ff", &real, &imaginary); + return complex_new(mrb, real, imaginary); +} + +#ifndef MRB_WITHOUT_FLOAT +static mrb_value +complex_to_f(mrb_state *mrb, mrb_value self) +{ + struct mrb_complex *p = complex_ptr(mrb, self); + + if (p->imaginary != 0) { + mrb_raisef(mrb, E_RANGE_ERROR, "can't convert %S into Float", self); + } + + return mrb_float_value(mrb, p->real); +} +#endif + +static mrb_value +complex_to_i(mrb_state *mrb, mrb_value self) +{ + struct mrb_complex *p = complex_ptr(mrb, self); + + if (p->imaginary != 0) { + mrb_raisef(mrb, E_RANGE_ERROR, "can't convert %S into Float", self); + } + return mrb_int_value(mrb, p->real); +} + +static mrb_value +complex_to_c(mrb_state *mrb, mrb_value self) +{ + return self; +} + +void mrb_mruby_complex_gem_init(mrb_state *mrb) +{ + struct RClass *comp; + +#ifdef COMPLEX_USE_ISTRUCT + mrb_assert(sizeof(struct mrb_complex) < ISTRUCT_DATA_SIZE); +#endif + comp = mrb_define_class(mrb, "Complex", mrb_class_get(mrb, "Numeric")); + //MRB_SET_INSTANCE_TT(comp, MRB_TT_ISTRUCT); + mrb_undef_class_method(mrb, comp, "new"); + mrb_define_class_method(mrb, comp, "_new", complex_s_new, MRB_ARGS_REQ(2)); + mrb_define_method(mrb, comp, "real", complex_real, MRB_ARGS_NONE()); + mrb_define_method(mrb, comp, "imaginary", complex_imaginary, MRB_ARGS_NONE()); +#ifndef MRB_WITHOUT_FLOAT + mrb_define_method(mrb, comp, "to_f", complex_to_f, MRB_ARGS_NONE()); +#endif + mrb_define_method(mrb, comp, "to_i", complex_to_i, MRB_ARGS_NONE()); + mrb_define_method(mrb, comp, "to_c", complex_to_c, MRB_ARGS_NONE()); +} + +void +mrb_mruby_complex_gem_final(mrb_state* mrb) +{ +} diff --git a/mrbgems/mruby-rational/src/rational.c b/mrbgems/mruby-rational/src/rational.c index 549715e7d..2a3f6df09 100644 --- a/mrbgems/mruby-rational/src/rational.c +++ b/mrbgems/mruby-rational/src/rational.c @@ -37,7 +37,7 @@ rational_new(mrb_state *mrb, mrb_int numerator, mrb_int denominator) struct mrb_rational *p = rational_ptr(rat); p->numerator = numerator; p->denominator = denominator; - return mrb_obj_value(s); + return rat; } static mrb_value -- cgit v1.2.3 From c02e63eb77b68377239287acccf371516177a8b9 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Tue, 21 May 2019 16:17:21 +0900 Subject: Use `MRB_TT_ISTRUCT` for `Complex` numbers if possible. --- mrbgems/mruby-complex/src/complex.c | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/mrbgems/mruby-complex/src/complex.c b/mrbgems/mruby-complex/src/complex.c index 5de0ae9a4..c6fb7a829 100644 --- a/mrbgems/mruby-complex/src/complex.c +++ b/mrbgems/mruby-complex/src/complex.c @@ -7,6 +7,29 @@ struct mrb_complex { mrb_float imaginary; }; +#if defined(MRB_64BIT) || defined(MRB_USE_FLOAT) + +#define COMPLEX_USE_ISTRUCT +/* use TT_ISTRUCT */ +#include + +#define complex_ptr(mrb, v) (struct mrb_complex*)mrb_istruct_ptr(v) + +static mrb_value +complex_new(mrb_state *mrb, mrb_float real, mrb_float imaginary) +{ + struct RClass *c = mrb_class_get(mrb, "Complex"); + struct RIStruct *s = (struct RIStruct*)mrb_obj_alloc(mrb, MRB_TT_ISTRUCT, c); + mrb_value comp = mrb_obj_value(s); + struct mrb_complex *p = complex_ptr(mrb, comp); + p->real = real; + p->imaginary = imaginary; + + return comp; +} + +#else +/* use TT_DATA */ #include static const struct mrb_data_type mrb_complex_type = {"Complex", mrb_free}; @@ -35,6 +58,7 @@ complex_ptr(mrb_state *mrb, mrb_value v) } return p; } +#endif static mrb_value complex_real(mrb_state *mrb, mrb_value self) -- cgit v1.2.3 From 38f8edbdd7463ee5e3331d09b2d031d55f2fd05e Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Tue, 21 May 2019 21:12:33 +0900 Subject: Update ISO section number for some Numeric methods. --- src/numeric.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/numeric.c b/src/numeric.c index e15b7f671..608b4f289 100644 --- a/src/numeric.c +++ b/src/numeric.c @@ -1597,10 +1597,10 @@ mrb_init_numeric(mrb_state *mrb) integral = mrb_define_module(mrb, "Integral"); mrb_define_method(mrb, integral,"**", integral_pow, MRB_ARGS_REQ(1)); - mrb_define_method(mrb, integral,"/", integral_div, MRB_ARGS_REQ(1)); /* 15.2.8.3.4 */ + mrb_define_method(mrb, integral,"/", integral_div, MRB_ARGS_REQ(1)); /* 15.2.{8,9}.3.6 */ mrb_define_method(mrb, integral,"quo", integral_div, MRB_ARGS_REQ(1)); /* 15.2.7.4.5 (x) */ mrb_define_method(mrb, integral,"div", integral_idiv, MRB_ARGS_REQ(1)); - mrb_define_method(mrb, integral,"<=>", integral_cmp, MRB_ARGS_REQ(1)); /* 15.2.9.3.6 */ + mrb_define_method(mrb, integral,"<=>", integral_cmp, MRB_ARGS_REQ(1)); /* 15.2.{8,9}.3.1 */ mrb_define_method(mrb, integral,"<", integral_lt, MRB_ARGS_REQ(1)); mrb_define_method(mrb, integral,"<=", integral_le, MRB_ARGS_REQ(1)); mrb_define_method(mrb, integral,">", integral_gt, MRB_ARGS_REQ(1)); -- cgit v1.2.3 From 8513abd40404ef8cb8340da906f2d15101536de1 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Wed, 22 May 2019 19:57:35 +0900 Subject: `Kernel#Rational` requires numerator --- mrbgems/mruby-rational/mrblib/rational.rb | 2 +- mrbgems/mruby-rational/test/rational.rb | 13 +++++++++++++ 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/mrbgems/mruby-rational/mrblib/rational.rb b/mrbgems/mruby-rational/mrblib/rational.rb index c8614ecea..4936b1123 100644 --- a/mrbgems/mruby-rational/mrblib/rational.rb +++ b/mrbgems/mruby-rational/mrblib/rational.rb @@ -71,7 +71,7 @@ class Numeric end module Kernel - def Rational(numerator = 0, denominator = 1) + def Rational(numerator, denominator = 1) a = numerator b = denominator a, b = b, a % b until b == 0 diff --git a/mrbgems/mruby-rational/test/rational.rb b/mrbgems/mruby-rational/test/rational.rb index ea55880fe..914f8505e 100644 --- a/mrbgems/mruby-rational/test/rational.rb +++ b/mrbgems/mruby-rational/test/rational.rb @@ -27,6 +27,19 @@ assert 'Rational' do assert_equal([5, 1], [r.numerator, r.denominator]) end +assert 'Kernel#Rational' do + r = Rational(4,10) + assert_equal(2, r.numerator) + assert_equal(5, r.denominator) + + r = Rational(3) + assert_equal(3, r.numerator) + assert_equal(1, r.denominator) + + assert_raise(ArgumentError) { Rational() } + assert_raise(ArgumentError) { Rational(1,2,3) } +end + assert 'Rational#to_f' do assert_float(2.0, Rational(2).to_f) assert_float(2.25, Rational(9, 4).to_f) -- cgit v1.2.3 From 48903850e9041e74c526fef5e63857007d2cac38 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Thu, 23 May 2019 13:40:49 +0900 Subject: Freeze `Rational` and `Complex` objects --- mrbgems/mruby-complex/src/complex.c | 1 + mrbgems/mruby-complex/test/complex.rb | 8 +++++++- mrbgems/mruby-rational/src/rational.c | 1 + mrbgems/mruby-rational/test/rational.rb | 6 ++++++ 4 files changed, 15 insertions(+), 1 deletion(-) diff --git a/mrbgems/mruby-complex/src/complex.c b/mrbgems/mruby-complex/src/complex.c index c6fb7a829..1b030c317 100644 --- a/mrbgems/mruby-complex/src/complex.c +++ b/mrbgems/mruby-complex/src/complex.c @@ -24,6 +24,7 @@ complex_new(mrb_state *mrb, mrb_float real, mrb_float imaginary) struct mrb_complex *p = complex_ptr(mrb, comp); p->real = real; p->imaginary = imaginary; + MRB_SET_FROZEN_FLAG(s); return comp; } diff --git a/mrbgems/mruby-complex/test/complex.rb b/mrbgems/mruby-complex/test/complex.rb index e7fcc7322..6996eb214 100644 --- a/mrbgems/mruby-complex/test/complex.rb +++ b/mrbgems/mruby-complex/test/complex.rb @@ -1,5 +1,5 @@ def assert_complex(real, exp) - assert_float real.real, exp.real + assert_float real.real, exp.real assert_float real.imaginary, exp.imaginary end @@ -126,3 +126,9 @@ assert 'Complex::to_i' do Complex(1, 2).to_i end end + +assert 'Complex#frozen?' do + assert_predicate(1i, :frozen?) + assert_predicate(Complex(2,3), :frozen?) + assert_predicate(4+5i, :frozen?) +end diff --git a/mrbgems/mruby-rational/src/rational.c b/mrbgems/mruby-rational/src/rational.c index 2a3f6df09..fa061c0b8 100644 --- a/mrbgems/mruby-rational/src/rational.c +++ b/mrbgems/mruby-rational/src/rational.c @@ -37,6 +37,7 @@ rational_new(mrb_state *mrb, mrb_int numerator, mrb_int denominator) struct mrb_rational *p = rational_ptr(rat); p->numerator = numerator; p->denominator = denominator; + MRB_SET_FROZEN_FLAG(s); return rat; } diff --git a/mrbgems/mruby-rational/test/rational.rb b/mrbgems/mruby-rational/test/rational.rb index 914f8505e..1ed3b3a07 100644 --- a/mrbgems/mruby-rational/test/rational.rb +++ b/mrbgems/mruby-rational/test/rational.rb @@ -278,3 +278,9 @@ assert 'Rational#negative?' do assert_not_predicate(Rational(2,3), :negative?) assert_not_predicate(Rational(0), :negative?) end + +assert 'Rational#frozen?' do + assert_predicate(1r, :frozen?) + assert_predicate(Rational(2,3), :frozen?) + assert_predicate(4/5r, :frozen?) +end -- cgit v1.2.3 From 240bbc39e11e317a902e30b2cf790509c2e75464 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Fri, 24 May 2019 21:02:22 +0900 Subject: Fix the order of "expected" and "actual" in `mruby-time` test --- mrbgems/mruby-time/test/time.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mrbgems/mruby-time/test/time.rb b/mrbgems/mruby-time/test/time.rb index ce7b39928..f59e27bc1 100644 --- a/mrbgems/mruby-time/test/time.rb +++ b/mrbgems/mruby-time/test/time.rb @@ -72,7 +72,7 @@ assert('Time#+', '15.2.19.7.1') do t1 = Time.at(1300000000.0) t2 = t1.+(60) - assert_equal(t2.utc.asctime, "Sun Mar 13 07:07:40 2011") + assert_equal("Sun Mar 13 07:07:40 2011", t2.utc.asctime) assert_raise(FloatDomainError) { Time.at(0) + Float::NAN } assert_raise(FloatDomainError) { Time.at(0) + Float::INFINITY } @@ -83,7 +83,7 @@ assert('Time#-', '15.2.19.7.2') do t1 = Time.at(1300000000.0) t2 = t1.-(60) - assert_equal(t2.utc.asctime, "Sun Mar 13 07:05:40 2011") + assert_equal("Sun Mar 13 07:05:40 2011", t2.utc.asctime) assert_raise(FloatDomainError) { Time.at(0) - Float::NAN } assert_raise(FloatDomainError) { Time.at(0) - Float::INFINITY } -- cgit v1.2.3 From 56e0e1934d4ec751d83f9f54ce93ca74b0e21194 Mon Sep 17 00:00:00 2001 From: dearblue Date: Sat, 25 May 2019 12:12:21 +0900 Subject: Name the return value of `mrb_range_beg_len()` --- include/mruby/range.h | 8 +++++++- mrbgems/mruby-array-ext/src/array.c | 2 +- mrbgems/mruby-kernel-ext/src/kernel.c | 2 +- mrbgems/mruby-string-ext/src/string.c | 6 +++--- src/array.c | 8 ++++---- src/range.c | 12 ++++++------ src/string.c | 4 ++-- 7 files changed, 24 insertions(+), 18 deletions(-) diff --git a/include/mruby/range.h b/include/mruby/range.h index b5626993a..ee6eb8d1d 100644 --- a/include/mruby/range.h +++ b/include/mruby/range.h @@ -64,7 +64,13 @@ MRB_API struct RRange* mrb_range_ptr(mrb_state *mrb, mrb_value range); */ MRB_API mrb_value mrb_range_new(mrb_state *mrb, mrb_value start, mrb_value end, mrb_bool exclude); -MRB_API mrb_int mrb_range_beg_len(mrb_state *mrb, mrb_value range, mrb_int *begp, mrb_int *lenp, mrb_int len, mrb_bool trunc); +enum mrb_range_beg_len { + MRB_RANGE_TYPE_MISMATCH = 0, /* (failure) not range */ + MRB_RANGE_OK = 1, /* (success) range */ + MRB_RANGE_OUT = 2 /* (failure) out of range */ +}; + +MRB_API enum mrb_range_beg_len mrb_range_beg_len(mrb_state *mrb, mrb_value range, mrb_int *begp, mrb_int *lenp, mrb_int len, mrb_bool trunc); mrb_value mrb_get_values_at(mrb_state *mrb, mrb_value obj, mrb_int olen, mrb_int argc, const mrb_value *argv, mrb_value (*func)(mrb_state*, mrb_value, mrb_int)); void mrb_gc_mark_range(mrb_state *mrb, struct RRange *r); diff --git a/mrbgems/mruby-array-ext/src/array.c b/mrbgems/mruby-array-ext/src/array.c index b6d9c9c80..20c771a97 100644 --- a/mrbgems/mruby-array-ext/src/array.c +++ b/mrbgems/mruby-array-ext/src/array.c @@ -145,7 +145,7 @@ mrb_ary_slice_bang(mrb_state *mrb, mrb_value self) mrb_get_args(mrb, "o|i", &index, &len); switch (mrb_type(index)) { case MRB_TT_RANGE: - if (mrb_range_beg_len(mrb, index, &i, &len, ARY_LEN(a), TRUE) == 1) { + if (mrb_range_beg_len(mrb, index, &i, &len, ARY_LEN(a), TRUE) == MRB_RANGE_OK) { goto delete_pos_len; } else { diff --git a/mrbgems/mruby-kernel-ext/src/kernel.c b/mrbgems/mruby-kernel-ext/src/kernel.c index 9288b0e6f..8e7e03c56 100644 --- a/mrbgems/mruby-kernel-ext/src/kernel.c +++ b/mrbgems/mruby-kernel-ext/src/kernel.c @@ -22,7 +22,7 @@ mrb_f_caller(mrb_state *mrb, mrb_value self) case 1: if (mrb_type(v) == MRB_TT_RANGE) { mrb_int beg, len; - if (mrb_range_beg_len(mrb, v, &beg, &len, bt_len, TRUE) == 1) { + if (mrb_range_beg_len(mrb, v, &beg, &len, bt_len, TRUE) == MRB_RANGE_OK) { lev = beg; n = len; } diff --git a/mrbgems/mruby-string-ext/src/string.c b/mrbgems/mruby-string-ext/src/string.c index ba7e3c610..85180516c 100644 --- a/mrbgems/mruby-string-ext/src/string.c +++ b/mrbgems/mruby-string-ext/src/string.c @@ -58,11 +58,11 @@ mrb_str_byteslice(mrb_state *mrb, mrb_value str) len = RSTRING_LEN(str); switch (mrb_range_beg_len(mrb, a1, &beg, &len, len, TRUE)) { - case 0: /* not range */ + case MRB_RANGE_TYPE_MISMATCH: break; - case 1: /* range */ + case MRB_RANGE_OK: return mrb_str_substr(mrb, str, beg, len); - case 2: /* out of range */ + case MRB_RANGE_OUT: mrb_raisef(mrb, E_RANGE_ERROR, "%S out of range", a1); break; } diff --git a/src/array.c b/src/array.c index d4302cb22..bd9b4d358 100644 --- a/src/array.c +++ b/src/array.c @@ -858,7 +858,7 @@ mrb_ary_aget(mrb_state *mrb, mrb_value self) switch (mrb_type(index)) { /* a[n..m] */ case MRB_TT_RANGE: - if (mrb_range_beg_len(mrb, index, &i, &len, ARY_LEN(a), TRUE) == 1) { + if (mrb_range_beg_len(mrb, index, &i, &len, ARY_LEN(a), TRUE) == MRB_RANGE_OK) { return ary_subseq(mrb, a, i, len); } else { @@ -927,13 +927,13 @@ mrb_ary_aset(mrb_state *mrb, mrb_value self) if (mrb_get_args(mrb, "oo|o", &v1, &v2, &v3) == 2) { /* a[n..m] = v */ switch (mrb_range_beg_len(mrb, v1, &i, &len, RARRAY_LEN(self), FALSE)) { - case 0: /* not range */ + case MRB_RANGE_TYPE_MISMATCH: mrb_ary_set(mrb, self, aget_index(mrb, v1), v2); break; - case 1: /* range */ + case MRB_RANGE_OK: mrb_ary_splice(mrb, self, i, len, v2); break; - case 2: /* out of range */ + case MRB_RANGE_OUT: mrb_raisef(mrb, E_RANGE_ERROR, "%S out of range", v1); break; } diff --git a/src/range.c b/src/range.c index 21771c8ec..9036ef093 100644 --- a/src/range.c +++ b/src/range.c @@ -352,7 +352,7 @@ mrb_get_values_at(mrb_state *mrb, mrb_value obj, mrb_int olen, mrb_int argc, con if (mrb_fixnum_p(argv[i])) { mrb_ary_push(mrb, result, func(mrb, obj, mrb_fixnum(argv[i]))); } - else if (mrb_range_beg_len(mrb, argv[i], &beg, &len, olen, FALSE) == 1) { + else if (mrb_range_beg_len(mrb, argv[i], &beg, &len, olen, FALSE) == MRB_RANGE_OK) { mrb_int const end = olen < beg + len ? olen : beg + len; for (j = beg; j < end; ++j) { mrb_ary_push(mrb, result, func(mrb, obj, j)); @@ -398,13 +398,13 @@ mrb_range_new(mrb_state *mrb, mrb_value beg, mrb_value end, mrb_bool excl) return mrb_range_value(r); } -MRB_API mrb_int +MRB_API enum mrb_range_beg_len mrb_range_beg_len(mrb_state *mrb, mrb_value range, mrb_int *begp, mrb_int *lenp, mrb_int len, mrb_bool trunc) { mrb_int beg, end; struct RRange *r; - if (mrb_type(range) != MRB_TT_RANGE) return 0; + if (mrb_type(range) != MRB_TT_RANGE) return MRB_RANGE_TYPE_MISMATCH; r = mrb_range_ptr(mrb, range); beg = mrb_int(mrb, RANGE_BEG(r)); @@ -412,11 +412,11 @@ mrb_range_beg_len(mrb_state *mrb, mrb_value range, mrb_int *begp, mrb_int *lenp, if (beg < 0) { beg += len; - if (beg < 0) return 2; + if (beg < 0) return MRB_RANGE_OUT; } if (trunc) { - if (beg > len) return 2; + if (beg > len) return MRB_RANGE_OUT; if (end > len) end = len; } @@ -427,7 +427,7 @@ mrb_range_beg_len(mrb_state *mrb, mrb_value range, mrb_int *begp, mrb_int *lenp, *begp = beg; *lenp = len; - return 1; + return MRB_RANGE_OK; } void diff --git a/src/string.c b/src/string.c index 578e3bdcc..db2d73e32 100644 --- a/src/string.c +++ b/src/string.c @@ -1041,9 +1041,9 @@ num_index: len = RSTRING_CHAR_LEN(str); switch (mrb_range_beg_len(mrb, indx, &beg, &len, len, TRUE)) { - case 1: + case MRB_RANGE_OK: return str_subseq(mrb, str, beg, len); - case 2: + case MRB_RANGE_OUT: return mrb_nil_value(); default: break; -- cgit v1.2.3 From ecfca8def78043f891bcbe6bc1eb036048996169 Mon Sep 17 00:00:00 2001 From: dearblue Date: Sat, 25 May 2019 22:24:08 +0900 Subject: Fix double rounded by negative index - Before patched: ``` $ mruby -e 'p (-12..-1).map { |i| "Hello"[i] }.join' "HelloHello" ``` - After patched: ``` $ mruby -e 'p (-12..-1).map { |i| "Hello"[i] }.join' "Hello" ``` --- src/string.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/string.c b/src/string.c index db2d73e32..bfe73b359 100644 --- a/src/string.c +++ b/src/string.c @@ -449,9 +449,6 @@ str_substr(mrb_state *mrb, mrb_value str, mrb_int beg, mrb_int len) if (clen == 0) { len = 0; } - else if (beg < 0) { - beg = clen + beg; - } if (beg > clen) return mrb_nil_value(); if (beg < 0) { beg += clen; -- cgit v1.2.3 From d1e1bb0d5b45d9f1c5de943a036c86542698af49 Mon Sep 17 00:00:00 2001 From: dearblue Date: Sat, 25 May 2019 23:59:43 +0900 Subject: Remove `mrb_alloca()` function When I found this function, I expected it to behave the same as the `alloca(3)` function, but it is accually the `mrb_alloca()` function does not free the heap until the `mrb_close()` function is called. Also, even if it is deleted, it can be replaced with the combination of the `MRB_TT_DATA` object and the `mrb_gv_set()` function if it is sure necessary. --- include/mruby.h | 2 -- src/state.c | 33 --------------------------------- 2 files changed, 35 deletions(-) diff --git a/include/mruby.h b/include/mruby.h index 20cdc1b83..5d5c759dd 100644 --- a/include/mruby.h +++ b/include/mruby.h @@ -228,7 +228,6 @@ typedef struct mrb_state { struct RClass *symbol_class; struct RClass *kernel_module; - struct alloca_header *mems; mrb_gc gc; #ifdef MRB_METHOD_CACHE @@ -1247,7 +1246,6 @@ MRB_API void mrb_pool_close(struct mrb_pool*); MRB_API void* mrb_pool_alloc(struct mrb_pool*, size_t); MRB_API void* mrb_pool_realloc(struct mrb_pool*, void*, size_t oldlen, size_t newlen); MRB_API mrb_bool mrb_pool_can_realloc(struct mrb_pool*, void*, size_t); -MRB_API void* mrb_alloca(mrb_state *mrb, size_t); MRB_API void mrb_state_atexit(mrb_state *mrb, mrb_atexit_func func); diff --git a/src/state.c b/src/state.c index 08d7ba906..c42df71ba 100644 --- a/src/state.c +++ b/src/state.c @@ -57,38 +57,6 @@ mrb_default_allocf(mrb_state *mrb, void *p, size_t size, void *ud) } } -struct alloca_header { - struct alloca_header *next; - char buf[1]; -}; - -MRB_API void* -mrb_alloca(mrb_state *mrb, size_t size) -{ - struct alloca_header *p; - - p = (struct alloca_header*) mrb_malloc(mrb, sizeof(struct alloca_header)+size); - p->next = mrb->mems; - mrb->mems = p; - return (void*)p->buf; -} - -static void -mrb_alloca_free(mrb_state *mrb) -{ - struct alloca_header *p; - struct alloca_header *tmp; - - if (mrb == NULL) return; - p = mrb->mems; - - while (p) { - tmp = p; - p = p->next; - mrb_free(mrb, tmp); - } -} - MRB_API mrb_state* mrb_open(void) { @@ -256,7 +224,6 @@ mrb_close(mrb_state *mrb) mrb_gc_free_gv(mrb); mrb_free_context(mrb, mrb->root_c); mrb_free_symtbl(mrb); - mrb_alloca_free(mrb); mrb_gc_destroy(mrb, &mrb->gc); mrb_free(mrb, mrb); } -- cgit v1.2.3 From 4261ba944330f27dcb80e5e4580f73bd6b3a7106 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Fri, 24 May 2019 13:15:26 +0900 Subject: Remove some overhead from methods defined in Ruby in Complex. --- mrbgems/mruby-complex/mrblib/complex.rb | 37 +++++++++------------------------ mrbgems/mruby-complex/src/complex.c | 9 ++++---- 2 files changed, 15 insertions(+), 31 deletions(-) diff --git a/mrbgems/mruby-complex/mrblib/complex.rb b/mrbgems/mruby-complex/mrblib/complex.rb index 4c0c19c70..0299e7675 100644 --- a/mrbgems/mruby-complex/mrblib/complex.rb +++ b/mrbgems/mruby-complex/mrblib/complex.rb @@ -1,19 +1,8 @@ class Complex < Numeric - def initialize(real, imaginary) - real = real.to_f unless real.is_a? Numeric - imaginary = imaginary.to_f unless imaginary.is_a? Numeric - @real = real - @imaginary = imaginary - end - def self.polar(abs, arg = 0) Complex(abs * Math.cos(arg), abs * Math.sin(arg)) end - def self.rectangular(real, imaginary = 0) - _new(real, imaginary) - end - def inspect "(#{to_s})" end @@ -23,43 +12,43 @@ class Complex < Numeric end def +@ - Complex._new(real, imaginary) + Complex(real, imaginary) end def -@ - Complex._new(-real, -imaginary) + Complex(-real, -imaginary) end def +(rhs) if rhs.is_a? Complex - Complex._new(real + rhs.real, imaginary + rhs.imaginary) + Complex(real + rhs.real, imaginary + rhs.imaginary) elsif rhs.is_a? Numeric - Complex._new(real + rhs, imaginary) + Complex(real + rhs, imaginary) end end def -(rhs) if rhs.is_a? Complex - Complex._new(real - rhs.real, imaginary - rhs.imaginary) + Complex(real - rhs.real, imaginary - rhs.imaginary) elsif rhs.is_a? Numeric - Complex._new(real - rhs, imaginary) + Complex(real - rhs, imaginary) end end def *(rhs) if rhs.is_a? Complex - Complex._new(real * rhs.real - imaginary * rhs.imaginary, real * rhs.imaginary + rhs.real * imaginary) + Complex(real * rhs.real - imaginary * rhs.imaginary, real * rhs.imaginary + rhs.real * imaginary) elsif rhs.is_a? Numeric - Complex._new(real * rhs, imaginary * rhs) + Complex(real * rhs, imaginary * rhs) end end def /(rhs) if rhs.is_a? Complex div = rhs.real * rhs.real + rhs.imaginary * rhs.imaginary - Complex._new((real * rhs.real + imaginary * rhs.imaginary) / div, (rhs.real * imaginary - real * rhs.imaginary) / div) + Complex((real * rhs.real + imaginary * rhs.imaginary) / div, (rhs.real * imaginary - real * rhs.imaginary) / div) elsif rhs.is_a? Numeric - Complex._new(real / rhs, imaginary / rhs) + Complex(real / rhs, imaginary / rhs) end end alias_method :quo, :/ @@ -117,12 +106,6 @@ class Complex < Numeric alias_method :imag, :imaginary end -module Kernel - def Complex(real, imaginary = 0) - Complex.rectangular(real, imaginary) - end -end - [Fixnum, Float].each do |cls| [:+, :-, :*, :/, :==].each do |op| cls.instance_exec do diff --git a/mrbgems/mruby-complex/src/complex.c b/mrbgems/mruby-complex/src/complex.c index 1b030c317..0678d4b26 100644 --- a/mrbgems/mruby-complex/src/complex.c +++ b/mrbgems/mruby-complex/src/complex.c @@ -76,11 +76,11 @@ complex_imaginary(mrb_state *mrb, mrb_value self) } static mrb_value -complex_s_new(mrb_state *mrb, mrb_value self) +complex_s_rect(mrb_state *mrb, mrb_value self) { - mrb_float real, imaginary; + mrb_float real, imaginary = 0.0; - mrb_get_args(mrb, "ff", &real, &imaginary); + mrb_get_args(mrb, "f|f", &real, &imaginary); return complex_new(mrb, real, imaginary); } @@ -125,7 +125,8 @@ void mrb_mruby_complex_gem_init(mrb_state *mrb) comp = mrb_define_class(mrb, "Complex", mrb_class_get(mrb, "Numeric")); //MRB_SET_INSTANCE_TT(comp, MRB_TT_ISTRUCT); mrb_undef_class_method(mrb, comp, "new"); - mrb_define_class_method(mrb, comp, "_new", complex_s_new, MRB_ARGS_REQ(2)); + mrb_define_class_method(mrb, comp, "rectangular", complex_s_rect, MRB_ARGS_REQ(1)|MRB_ARGS_OPT(1)); + mrb_define_method(mrb, mrb->kernel_module, "Complex", complex_s_rect, MRB_ARGS_REQ(1)|MRB_ARGS_OPT(1)); mrb_define_method(mrb, comp, "real", complex_real, MRB_ARGS_NONE()); mrb_define_method(mrb, comp, "imaginary", complex_imaginary, MRB_ARGS_NONE()); #ifndef MRB_WITHOUT_FLOAT -- cgit v1.2.3 From 0bdb185a6fc1a6440b90b015bdb9d137db57ab77 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Sun, 26 May 2019 20:17:03 +0900 Subject: Add `Complex.rect` --- mrbgems/mruby-complex/src/complex.c | 1 + 1 file changed, 1 insertion(+) diff --git a/mrbgems/mruby-complex/src/complex.c b/mrbgems/mruby-complex/src/complex.c index 0678d4b26..5371332cd 100644 --- a/mrbgems/mruby-complex/src/complex.c +++ b/mrbgems/mruby-complex/src/complex.c @@ -126,6 +126,7 @@ void mrb_mruby_complex_gem_init(mrb_state *mrb) //MRB_SET_INSTANCE_TT(comp, MRB_TT_ISTRUCT); mrb_undef_class_method(mrb, comp, "new"); mrb_define_class_method(mrb, comp, "rectangular", complex_s_rect, MRB_ARGS_REQ(1)|MRB_ARGS_OPT(1)); + mrb_define_class_method(mrb, comp, "rect", complex_s_rect, MRB_ARGS_REQ(1)|MRB_ARGS_OPT(1)); mrb_define_method(mrb, mrb->kernel_module, "Complex", complex_s_rect, MRB_ARGS_REQ(1)|MRB_ARGS_OPT(1)); mrb_define_method(mrb, comp, "real", complex_real, MRB_ARGS_NONE()); mrb_define_method(mrb, comp, "imaginary", complex_imaginary, MRB_ARGS_NONE()); -- cgit v1.2.3 From 779251de64bdf63f71b02927db511fb8633c5d60 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Sun, 26 May 2019 20:32:04 +0900 Subject: Move `mrb_mod_s_nesting()` to `mruby-metaprog` gem from the core --- mrbgems/mruby-metaprog/src/metaprog.c | 26 ++++++++++++++++++++++++-- src/vm.c | 25 ------------------------- 2 files changed, 24 insertions(+), 27 deletions(-) diff --git a/mrbgems/mruby-metaprog/src/metaprog.c b/mrbgems/mruby-metaprog/src/metaprog.c index 0aafb4c34..38f75d460 100644 --- a/mrbgems/mruby-metaprog/src/metaprog.c +++ b/mrbgems/mruby-metaprog/src/metaprog.c @@ -657,8 +657,30 @@ mrb_mod_s_constants(mrb_state *mrb, mrb_value mod) return mrb_nil_value(); /* not reached */ } -/* implementation of Module.nesting */ -mrb_value mrb_mod_s_nesting(mrb_state*, mrb_value); +mrb_value +mrb_mod_s_nesting(mrb_state *mrb, mrb_value mod) +{ + struct RProc *proc; + mrb_value ary; + struct RClass *c = NULL; + + mrb_get_args(mrb, ""); + ary = mrb_ary_new(mrb); + proc = mrb->c->ci[-1].proc; /* callee proc */ + mrb_assert(!MRB_PROC_CFUNC_P(proc)); + while (proc) { + if (MRB_PROC_SCOPE_P(proc)) { + struct RClass *c2 = MRB_PROC_TARGET_CLASS(proc); + + if (c2 != c) { + c = c2; + mrb_ary_push(mrb, ary, mrb_obj_value(c)); + } + } + proc = proc->upper; + } + return ary; +} void mrb_mruby_metaprog_gem_init(mrb_state* mrb) diff --git a/src/vm.c b/src/vm.c index 8dc6623d1..0a6d4af8d 100644 --- a/src/vm.c +++ b/src/vm.c @@ -830,31 +830,6 @@ mrb_yield_cont(mrb_state *mrb, mrb_value b, mrb_value self, mrb_int argc, const return mrb_exec_irep(mrb, self, p); } -mrb_value -mrb_mod_s_nesting(mrb_state *mrb, mrb_value mod) -{ - struct RProc *proc; - mrb_value ary; - struct RClass *c = NULL; - - mrb_get_args(mrb, ""); - ary = mrb_ary_new(mrb); - proc = mrb->c->ci[-1].proc; /* callee proc */ - mrb_assert(!MRB_PROC_CFUNC_P(proc)); - while (proc) { - if (MRB_PROC_SCOPE_P(proc)) { - struct RClass *c2 = MRB_PROC_TARGET_CLASS(proc); - - if (c2 != c) { - c = c2; - mrb_ary_push(mrb, ary, mrb_obj_value(c)); - } - } - proc = proc->upper; - } - return ary; -} - static struct RBreak* break_new(mrb_state *mrb, struct RProc *p, mrb_value val) { -- cgit v1.2.3 From 534b578da7ae3742a67b1e950b5aea2ad97b8b9b Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Mon, 27 May 2019 18:26:54 +0900 Subject: Make some functions static in `mrbgems/mruby-metaprog/src/metaprog.c` --- mrbgems/mruby-metaprog/src/metaprog.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/mrbgems/mruby-metaprog/src/metaprog.c b/mrbgems/mruby-metaprog/src/metaprog.c index 38f75d460..e57d10d8d 100644 --- a/mrbgems/mruby-metaprog/src/metaprog.c +++ b/mrbgems/mruby-metaprog/src/metaprog.c @@ -186,7 +186,7 @@ method_entry_loop(mrb_state *mrb, struct RClass* klass, khash_t(st)* set) } } -mrb_value +static mrb_value mrb_class_instance_method_list(mrb_state *mrb, mrb_bool recur, struct RClass* klass, int obj) { khint_t i; @@ -565,8 +565,6 @@ mrb_mod_included_modules(mrb_state *mrb, mrb_value self) return result; } -mrb_value mrb_class_instance_method_list(mrb_state*, mrb_bool, struct RClass*, int); - /* 15.2.2.4.33 */ /* * call-seq: @@ -657,7 +655,7 @@ mrb_mod_s_constants(mrb_state *mrb, mrb_value mod) return mrb_nil_value(); /* not reached */ } -mrb_value +static mrb_value mrb_mod_s_nesting(mrb_state *mrb, mrb_value mod) { struct RProc *proc; -- cgit v1.2.3 From 902b2ce3c669d4e3b5c20b2c90a3b3982f17d820 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Mon, 27 May 2019 21:29:49 +0900 Subject: Fix `Rational#==(Complex)` Consider a Numreic class like `Complex` that does not have `<=>` but `==` works (`0i == 0r` is `true`). --- mrbgems/mruby-rational/mrblib/rational.rb | 13 +++++++ mrbgems/mruby-rational/test/rational.rb | 58 ++++++++++++++++++++----------- 2 files changed, 51 insertions(+), 20 deletions(-) diff --git a/mrbgems/mruby-rational/mrblib/rational.rb b/mrbgems/mruby-rational/mrblib/rational.rb index 4936b1123..54d9a955f 100644 --- a/mrbgems/mruby-rational/mrblib/rational.rb +++ b/mrbgems/mruby-rational/mrblib/rational.rb @@ -62,6 +62,19 @@ class Rational < Numeric nil end end + + def ==(rhs) + if rhs.is_a?(Integral) + return numerator == rhs if denominator == 1 + rhs = Rational(rhs) + end + + if rhs.is_a?(Rational) + numerator * rhs.denominator == denominator * rhs.numerator + else + rhs == self + end + end end class Numeric diff --git a/mrbgems/mruby-rational/test/rational.rb b/mrbgems/mruby-rational/test/rational.rb index 1ed3b3a07..5e9d9ea48 100644 --- a/mrbgems/mruby-rational/test/rational.rb +++ b/mrbgems/mruby-rational/test/rational.rb @@ -1,3 +1,27 @@ +class UserDefinedNumeric < Numeric + def initialize(n) + @n = n + end + + def <=>(rhs) + return nil unless rhs.respond_to?(:to_i) + rhs = rhs.to_i + rhs < 0 ? nil : @n <=> rhs + end + + def inspect + "#{self.class}(#{@n})" + end +end + +class ComplexLikeNumeric < UserDefinedNumeric + def ==(rhs) + @n == 0 && rhs == 0 + end + + undef <=> +end + def assert_rational(exp, real) assert_float exp.numerator, real.numerator assert_float exp.denominator, real.denominator @@ -17,7 +41,7 @@ def assert_cmp(exp, o1, o2) if exp == (o1 <=> o2) pass else - flunk "", " Expected #{o1.inspect} <=> #{o2.inspect} to be #{exp}" + flunk "", " Expected #{o1.inspect} <=> #{o2.inspect} to be #{exp}." end end @@ -106,6 +130,13 @@ assert 'Rational#==, Rational#!=' do assert_equal_rational(false, Rational(2,1), 1r) assert_equal_rational(false, Rational(1), nil) assert_equal_rational(false, Rational(1), '') + assert_equal_rational(true, 0r, UserDefinedNumeric.new(0)) + assert_equal_rational(true, 1r, UserDefinedNumeric.new(1)) + assert_equal_rational(false, 1r, UserDefinedNumeric.new(2)) + assert_equal_rational(false, -1r, UserDefinedNumeric.new(-1)) + assert_equal_rational(true, 0r, ComplexLikeNumeric.new(0)) + assert_equal_rational(false, 1r, ComplexLikeNumeric.new(1)) + assert_equal_rational(false, 1r, ComplexLikeNumeric.new(2)) end assert 'Fixnum#==(Rational), Fixnum#!=(Rational)' do @@ -123,21 +154,6 @@ assert 'Float#==(Rational), Float#!=(Rational)' do end assert 'Rational#<=>' do - num = Class.new(Numeric) do - def initialize(n) - @n = n - end - - def <=>(rhs) - rhs = rhs.to_i - rhs < 0 ? nil : @n <=> rhs - end - - def inspect - "num(#{@n})" - end - end - assert_cmp(-1, Rational(-1), Rational(0)) assert_cmp(0, Rational(0), Rational(0)) assert_cmp(1, Rational(1), Rational(0)) @@ -158,10 +174,12 @@ assert 'Rational#<=>' do assert_cmp(-1, Rational(1,2), Rational(2,3)) assert_cmp(-1, Rational(1,2), Rational(2,3)) assert_cmp(nil, 3r, "3") - assert_cmp(1, 3r, num.new(2)) - assert_cmp(0, 3r, num.new(3)) - assert_cmp(-1, 3r, num.new(4)) - assert_cmp(nil, Rational(-3), num.new(5)) + assert_cmp(1, 3r, UserDefinedNumeric.new(2)) + assert_cmp(0, 3r, UserDefinedNumeric.new(3)) + assert_cmp(-1, 3r, UserDefinedNumeric.new(4)) + assert_cmp(nil, Rational(-3), UserDefinedNumeric.new(5)) + assert_raise(NoMethodError) { 0r <=> ComplexLikeNumeric.new(0) } + assert_raise(NoMethodError) { 1r <=> ComplexLikeNumeric.new(2) } end assert 'Fixnum#<=>(Rational)' do -- cgit v1.2.3 From a97a455c031c77f01eaae85ce683e9c1346eb8c9 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Mon, 27 May 2019 20:51:47 +0900 Subject: Use `$undefined.equal?(obj2)` instead of `obj2 == $undefined` in `assert.rb` In case `obj2.==` is broken. --- test/assert.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/assert.rb b/test/assert.rb index a9bbc9a05..5e2e104b3 100644 --- a/test/assert.rb +++ b/test/assert.rb @@ -149,7 +149,7 @@ end def assert_operator(*args); _assert_operator(true, *args) end def assert_not_operator(*args); _assert_operator(false, *args) end def _assert_operator(affirmed, obj1, op, obj2 = $undefined, msg = nil) - return _assert_predicate(affirmed, obj1, op, msg) if obj2 == $undefined + return _assert_predicate(affirmed, obj1, op, msg) if $undefined.equal?(obj2) unless ret = obj1.__send__(op, obj2) == affirmed diff = " Expected #{obj1.inspect} to #{'not ' unless affirmed}be #{op} #{obj2.inspect}." end -- cgit v1.2.3 From ffc915fdee4407a7ff757d02795863524a74bce9 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Tue, 28 May 2019 18:26:01 +0900 Subject: Fix missing assertions in `mruby-pack` test --- mrbgems/mruby-pack/test/pack.rb | 79 ++++++++++++++++------------------------- 1 file changed, 30 insertions(+), 49 deletions(-) diff --git a/mrbgems/mruby-pack/test/pack.rb b/mrbgems/mruby-pack/test/pack.rb index 1788c2b72..110aee5db 100644 --- a/mrbgems/mruby-pack/test/pack.rb +++ b/mrbgems/mruby-pack/test/pack.rb @@ -1,101 +1,82 @@ +PACK_IS_LITTLE_ENDIAN = "\x01\00".unpack('S')[0] == 0x01 + +def assert_pack tmpl, packed, unpacked + t = tmpl.inspect + assert_equal packed, unpacked.pack(tmpl), "#{unpacked.inspect}.pack(#{t})" + assert_equal unpacked, packed.unpack(tmpl), "#{packed.inspect}.unpack(#{t})" +end + # pack & unpack 'm' (base64) assert('[""].pack("m")') do - ary = "" - str = "" - [ary].pack("m") == str and - str.unpack("m") == [ary] + assert_pack "m", "", [""] end assert('["\0"].pack("m")') do - ary = "\0" - str = "AA==\n" - [ary].pack("m") == str and - str.unpack("m") == [ary] + assert_pack "m", "AA==\n", ["\0"] end assert('["\0\0"].pack("m")') do - ary = "\0\0" - str = "AAA=\n" - [ary].pack("m") == str and - str.unpack("m") == [ary] + assert_pack "m", "AAA=\n", ["\0\0"] end assert('["\0\0\0"].pack("m")') do - ary = "\0\0\0" - str = "AAAA\n" - [ary].pack("m") == str and - str.unpack("m") == [ary] + assert_pack "m", "AAAA\n", ["\0\0\0"] end assert('["abc..xyzABC..XYZ"].pack("m")') do - ["abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"].pack("m") == "YWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXpBQkNERUZHSElKS0xNTk9QUVJT\nVFVWV1hZWg==\n" + assert_pack "m", "YWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXpBQkNERUZHSElKS0xNTk9QUVJT\nVFVWV1hZWg==\n", ["abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"] end assert('"YWJ...".unpack("m") should "abc..xyzABC..XYZ"') do - str = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" - "YWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXpBQkNERUZHSElKS0xNTk9QUVJT\nVFVWV1hZWg==\n".unpack("m") == [str] and - "YWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXpBQkNERUZHSElKS0xNTk9QUVJTVFVWV1hZWg==\n".unpack("m") == [str] + ary = ["abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"] + assert_equal ary, "YWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXpBQkNERUZHSElKS0xNTk9QUVJT\nVFVWV1hZWg==\n".unpack("m") + assert_equal ary, "YWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXpBQkNERUZHSElKS0xNTk9QUVJTVFVWV1hZWg==\n".unpack("m") end # pack & unpack 'H' assert('["3031"].pack("H*")') do - ary = "3031" - str = "01" - [ary].pack("H*") == str and - str.unpack("H*") == [ary] + assert_pack "H*", "01", ["3031"] end assert('["10"].pack("H*")') do - ary = "10" - str = "\020" - [ary].pack("H*") == str and - str.unpack("H*") == [ary] + assert_pack "H*", "\020", ["10"] end assert('[0,1,127,128,255].pack("C*")') do - ary = [ 0, 1, 127, 128, 255 ] - str = "\x00\x01\x7F\x80\xFF" - ary.pack("C*") == str and str.unpack("C*") == ary + assert_pack "C*", "\x00\x01\x7F\x80\xFF", [0, 1, 127, 128, 255] end # pack "a" assert('["abc"].pack("a")') do - ["abc"].pack("a") == "a" and - ["abc"].pack("a*") == "abc" and - ["abc"].pack("a4") == "abc\0" + assert_equal "a", ["abc"].pack("a") + assert_equal "abc", ["abc"].pack("a*") + assert_equal "abc\0", ["abc"].pack("a4") end # upack "a" assert('["abc"].pack("a")') do - "abc\0".unpack("a4") == ["abc\0"] and - "abc ".unpack("a4") == ["abc "] + assert_equal ["abc\0"], "abc\0".unpack("a4") + assert_equal ["abc "], "abc ".unpack("a4") end # pack "A" assert('["abc"].pack("A")') do - ["abc"].pack("A") == "a" and - ["abc"].pack("A*") == "abc" and - ["abc"].pack("A4") == "abc " + assert_equal "a", ["abc"].pack("A") + assert_equal "abc", ["abc"].pack("A*") + assert_equal "abc ", ["abc"].pack("A4") end # upack "A" assert('["abc"].pack("A")') do - "abc\0".unpack("A4") == ["abc"] and - "abc ".unpack("A4") == ["abc"] + assert_equal ["abc"], "abc\0".unpack("A4") + assert_equal ["abc"], "abc ".unpack("A4") end # regression tests assert('issue #1') do - [1, 2].pack("nn") == "\000\001\000\002" + assert_equal "\000\001\000\002", [1, 2].pack("nn") end -def assert_pack tmpl, packed, unpacked - assert_equal packed, unpacked.pack(tmpl) - assert_equal unpacked, packed.unpack(tmpl) -end - -PACK_IS_LITTLE_ENDIAN = "\x01\00".unpack('S')[0] == 0x01 - assert 'pack float' do assert_pack 'e', "\x00\x00@@", [3.0] assert_pack 'g', "@@\x00\x00", [3.0] -- cgit v1.2.3 From 2b81ea7ec1c7645b13b097e5b249cbc99f374da7 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Tue, 28 May 2019 10:44:18 +0900 Subject: Add `mrb_alloca` again; ref #4470 This time, the allocated memory comes from the string object, which is referenced from GC arena. The memory region will be reclaimed when the C function called from VM is terminated, or the GC arena is restored. --- include/mruby.h | 2 ++ src/gc.c | 7 +++++++ 2 files changed, 9 insertions(+) diff --git a/include/mruby.h b/include/mruby.h index 5d5c759dd..3ef399716 100644 --- a/include/mruby.h +++ b/include/mruby.h @@ -1246,6 +1246,8 @@ MRB_API void mrb_pool_close(struct mrb_pool*); MRB_API void* mrb_pool_alloc(struct mrb_pool*, size_t); MRB_API void* mrb_pool_realloc(struct mrb_pool*, void*, size_t oldlen, size_t newlen); MRB_API mrb_bool mrb_pool_can_realloc(struct mrb_pool*, void*, size_t); +/* temporary memory allocation, only effective while GC arena is kept */ +MRB_API void* mrb_alloca(mrb_state *mrb, size_t); MRB_API void mrb_state_atexit(mrb_state *mrb, mrb_atexit_func func); diff --git a/src/gc.c b/src/gc.c index 6dc8e373b..94068c0f9 100644 --- a/src/gc.c +++ b/src/gc.c @@ -277,6 +277,13 @@ mrb_free(mrb_state *mrb, void *p) (mrb->allocf)(mrb, p, 0, mrb->allocf_ud); } +MRB_API void* +mrb_alloca(mrb_state *mrb, size_t size) +{ + mrb_value str = mrb_str_new(mrb, NULL, size); + return RSTRING_PTR(str); +} + static mrb_bool heap_p(mrb_gc *gc, struct RBasic *object) { -- cgit v1.2.3 From 855f2cdeea5c305e71721ef3c146eaa6472815b8 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Wed, 29 May 2019 11:49:21 +0900 Subject: Slightly simplify `Rational#==`; ref #4475 --- mrbgems/mruby-rational/mrblib/rational.rb | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/mrbgems/mruby-rational/mrblib/rational.rb b/mrbgems/mruby-rational/mrblib/rational.rb index 54d9a955f..93af72b96 100644 --- a/mrbgems/mruby-rational/mrblib/rational.rb +++ b/mrbgems/mruby-rational/mrblib/rational.rb @@ -64,11 +64,10 @@ class Rational < Numeric end def ==(rhs) - if rhs.is_a?(Integral) - return numerator == rhs if denominator == 1 - rhs = Rational(rhs) + return true if self.equal?(rhs) + if rhs.is_a?(Integral) && denominator == 1 + return numerator == rhs end - if rhs.is_a?(Rational) numerator * rhs.denominator == denominator * rhs.numerator else -- cgit v1.2.3 From 03fce2e206128d6ae7fc5b7e3c66826446a5bad1 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Wed, 29 May 2019 15:57:18 +0900 Subject: `Kernel#itself` should not be a module function --- mrbgems/mruby-object-ext/src/object.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/mrbgems/mruby-object-ext/src/object.c b/mrbgems/mruby-object-ext/src/object.c index d3e7a9c50..85db75b28 100644 --- a/mrbgems/mruby-object-ext/src/object.c +++ b/mrbgems/mruby-object-ext/src/object.c @@ -118,7 +118,8 @@ mrb_mruby_object_ext_gem_init(mrb_state* mrb) mrb_define_method(mrb, n, "to_f", nil_to_f, MRB_ARGS_NONE()); #endif mrb_define_method(mrb, n, "to_i", nil_to_i, MRB_ARGS_NONE()); - mrb_define_module_function(mrb, mrb->kernel_module, "itself", mrb_f_itself, MRB_ARGS_NONE()); + + mrb_define_method(mrb, mrb->kernel_module, "itself", mrb_f_itself, MRB_ARGS_NONE()); mrb_define_method(mrb, mrb_class_get(mrb, "BasicObject"), "instance_exec", mrb_obj_instance_exec, MRB_ARGS_ANY() | MRB_ARGS_BLOCK()); } -- cgit v1.2.3 From 729931a06c0eebb8c1eaa471f2a1d16192deca9f Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Thu, 30 May 2019 12:33:41 +0900 Subject: Fix inverted compilation condition; fix #4478 --- src/numeric.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/numeric.c b/src/numeric.c index 608b4f289..0d1c23589 100644 --- a/src/numeric.c +++ b/src/numeric.c @@ -1347,7 +1347,7 @@ mrb_num_minus(mrb_state *mrb, mrb_value x, mrb_value y) if (mrb_fixnum_p(x)) { return fixnum_minus(mrb, x, y); } -#ifdef MRB_WITHOUT_FLOAT +#ifndef MRB_WITHOUT_FLOAT if (mrb_float_p(x)) { return mrb_float_value(mrb, mrb_float(x) - mrb_to_flo(mrb, y)); } -- cgit v1.2.3 From 05056ddac4096d1500c975d32f545ff01b3ec5d6 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Thu, 30 May 2019 21:42:01 +0900 Subject: Fix missing assertions in `mruby-fiber` test --- mrbgems/mruby-fiber/test/fiber.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mrbgems/mruby-fiber/test/fiber.rb b/mrbgems/mruby-fiber/test/fiber.rb index d063a0a62..b6ecb798c 100644 --- a/mrbgems/mruby-fiber/test/fiber.rb +++ b/mrbgems/mruby-fiber/test/fiber.rb @@ -76,7 +76,7 @@ assert('Fiber iteration') do end assert('Fiber with splat in the block argument list') { - Fiber.new{|*x|x}.resume(1) == [1] + assert_equal([1], Fiber.new{|*x|x}.resume(1)) } assert('Fiber raises on resume when dead') do -- cgit v1.2.3 From c1e6f324c29d16014a8c6c27b9e27cf9af9fc1d5 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Fri, 31 May 2019 20:50:54 +0900 Subject: Comment out the empty `Array#bsearch_index` test --- mrbgems/mruby-array-ext/test/array.rb | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/mrbgems/mruby-array-ext/test/array.rb b/mrbgems/mruby-array-ext/test/array.rb index 853554bcc..82f09297a 100644 --- a/mrbgems/mruby-array-ext/test/array.rb +++ b/mrbgems/mruby-array-ext/test/array.rb @@ -268,9 +268,9 @@ assert("Array#bsearch") do end end -assert("Array#bsearch_index") do - # tested through Array#bsearch -end +# tested through Array#bsearch +#assert("Array#bsearch_index") do +#end assert("Array#delete_if") do a = [1, 2, 3, 4, 5] -- cgit v1.2.3 From 92f00d3e58e91d513a483f87e0ee9eb17147d516 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Sun, 2 Jun 2019 19:15:20 +0900 Subject: Fix missing assertions in `mruby-objectspace` test --- mrbgems/mruby-objectspace/test/objectspace.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mrbgems/mruby-objectspace/test/objectspace.rb b/mrbgems/mruby-objectspace/test/objectspace.rb index 8db89eeaf..9c44c2157 100644 --- a/mrbgems/mruby-objectspace/test/objectspace.rb +++ b/mrbgems/mruby-objectspace/test/objectspace.rb @@ -56,5 +56,5 @@ assert('ObjectSpace.each_object') do end assert 'Check class pointer of ObjectSpace.each_object.' do - ObjectSpace.each_object { |obj| !obj } + assert_nothing_raised { ObjectSpace.each_object { |obj| !obj } } end -- cgit v1.2.3 From c75402a57b0f06dcdb62fc176ffa533c6eb6e73d Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Tue, 4 Jun 2019 10:45:13 +0900 Subject: Fix typo in `mrblib/range.rb` [ci skip] --- mrblib/range.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mrblib/range.rb b/mrblib/range.rb index 5bd2521e8..392cc2274 100644 --- a/mrblib/range.rb +++ b/mrblib/range.rb @@ -26,7 +26,7 @@ class Range return self end - if val.kind_of?(String) && last.kind_of?(String) # fixnums are special + if val.kind_of?(String) && last.kind_of?(String) # strings are special if val.respond_to? :upto return val.upto(last, exclude_end?, &block) else -- cgit v1.2.3 From 81ea89f10ee60ef67284bd8d92adc4292d217c3f Mon Sep 17 00:00:00 2001 From: dearblue Date: Tue, 4 Jun 2019 21:41:40 +0900 Subject: Need explicit cast for C++ --- include/mruby/data.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/mruby/data.h b/include/mruby/data.h index d85edeb3a..54466dcd6 100644 --- a/include/mruby/data.h +++ b/include/mruby/data.h @@ -41,7 +41,7 @@ MRB_API struct RData *mrb_data_object_alloc(mrb_state *mrb, struct RClass* klass #define Data_Make_Struct(mrb,klass,strct,type,sval,data_obj) do { \ (data_obj) = Data_Wrap_Struct(mrb,klass,type,NULL);\ - (sval) = mrb_malloc(mrb, sizeof(strct)); \ + (sval) = (strct *)mrb_malloc(mrb, sizeof(strct)); \ { static const strct zero = { 0 }; *(sval) = zero; };\ (data_obj)->data = (sval);\ } while (0) -- cgit v1.2.3 From dc1905e1bd8af679c639a67a6787fc41a2612603 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Wed, 5 Jun 2019 18:59:48 +0900 Subject: Fix missing assertions in `test/t/module.rb` --- test/t/module.rb | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/test/t/module.rb b/test/t/module.rb index f4999019a..3bb9735df 100644 --- a/test/t/module.rb +++ b/test/t/module.rb @@ -684,8 +684,8 @@ assert('Issue 1467') do include M1 end - C1.new - C2.new + assert_kind_of(M1, C1.new) + assert_kind_of(M1, C2.new) end assert('clone Module') do @@ -699,7 +699,7 @@ assert('clone Module') do include M1.clone end - B.new.foo + assert_true(B.new.foo) end assert('Module#module_function') do -- cgit v1.2.3 From 97e999c409fbbe46fd4154e4be292f182f42b771 Mon Sep 17 00:00:00 2001 From: dearblue Date: Sun, 2 Jun 2019 10:43:54 +0900 Subject: Fix memory leak in `Complex` method by `RData` If `Data_Wrap_Struct()` raises a `NoMemoryError` exception, it will leak memory if it does `mrb_malloc()` first. --- mrbgems/mruby-complex/src/complex.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/mrbgems/mruby-complex/src/complex.c b/mrbgems/mruby-complex/src/complex.c index 5371332cd..a727eb604 100644 --- a/mrbgems/mruby-complex/src/complex.c +++ b/mrbgems/mruby-complex/src/complex.c @@ -40,12 +40,13 @@ complex_new(mrb_state *mrb, mrb_float real, mrb_float imaginary) { struct RClass *c = mrb_class_get(mrb, "Complex"); struct mrb_complex *p; + struct RData *d; - p = (struct mrb_complex*)mrb_malloc(mrb, sizeof(struct mrb_complex)); + Data_Make_Struct(mrb, c, struct mrb_complex, &mrb_complex_type, p, d); p->real = real; p->imaginary = imaginary; - return mrb_obj_value(Data_Wrap_Struct(mrb, c, &mrb_complex_type, p)); + return mrb_obj_value(d); } static struct mrb_complex* -- cgit v1.2.3 From 82831c6acd116852e918094e940266152897056e Mon Sep 17 00:00:00 2001 From: dearblue Date: Sun, 2 Jun 2019 11:05:53 +0900 Subject: Fix not frozen in `Complex` method by `RData` Object allocation was separated, and initialization was made common. --- mrbgems/mruby-complex/src/complex.c | 42 +++++++++++++++++++++---------------- 1 file changed, 24 insertions(+), 18 deletions(-) diff --git a/mrbgems/mruby-complex/src/complex.c b/mrbgems/mruby-complex/src/complex.c index a727eb604..8a0569d68 100644 --- a/mrbgems/mruby-complex/src/complex.c +++ b/mrbgems/mruby-complex/src/complex.c @@ -15,18 +15,15 @@ struct mrb_complex { #define complex_ptr(mrb, v) (struct mrb_complex*)mrb_istruct_ptr(v) -static mrb_value -complex_new(mrb_state *mrb, mrb_float real, mrb_float imaginary) +static struct RBasic* +complex_alloc(mrb_state *mrb, struct RClass *c, struct mrb_complex **p) { - struct RClass *c = mrb_class_get(mrb, "Complex"); - struct RIStruct *s = (struct RIStruct*)mrb_obj_alloc(mrb, MRB_TT_ISTRUCT, c); - mrb_value comp = mrb_obj_value(s); - struct mrb_complex *p = complex_ptr(mrb, comp); - p->real = real; - p->imaginary = imaginary; - MRB_SET_FROZEN_FLAG(s); + struct RIStruct *s; + + s = (struct RIStruct*)mrb_obj_alloc(mrb, MRB_TT_ISTRUCT, c); + *p = (struct mrb_complex*)s->inline_data; - return comp; + return (struct RBasic*)s; } #else @@ -35,18 +32,14 @@ complex_new(mrb_state *mrb, mrb_float real, mrb_float imaginary) static const struct mrb_data_type mrb_complex_type = {"Complex", mrb_free}; -static mrb_value -complex_new(mrb_state *mrb, mrb_float real, mrb_float imaginary) +static struct RBasic* +complex_alloc(mrb_state *mrb, struct RClass *c, struct mrb_complex **p) { - struct RClass *c = mrb_class_get(mrb, "Complex"); - struct mrb_complex *p; struct RData *d; - Data_Make_Struct(mrb, c, struct mrb_complex, &mrb_complex_type, p, d); - p->real = real; - p->imaginary = imaginary; + Data_Make_Struct(mrb, c, struct mrb_complex, &mrb_complex_type, *p, d); - return mrb_obj_value(d); + return (struct RBasic*)d; } static struct mrb_complex* @@ -62,6 +55,19 @@ complex_ptr(mrb_state *mrb, mrb_value v) } #endif +static mrb_value +complex_new(mrb_state *mrb, mrb_float real, mrb_float imaginary) +{ + struct RClass *c = mrb_class_get(mrb, "Complex"); + struct mrb_complex *p; + struct RBasic *comp = complex_alloc(mrb, c, &p); + p->real = real; + p->imaginary = imaginary; + MRB_SET_FROZEN_FLAG(comp); + + return mrb_obj_value(comp); +} + static mrb_value complex_real(mrb_state *mrb, mrb_value self) { -- cgit v1.2.3 From 5e69760d919dd468ea8c8285f0f24affb52d3045 Mon Sep 17 00:00:00 2001 From: dearblue Date: Sun, 2 Jun 2019 17:21:33 +0900 Subject: Fix build error if `struct mrb_rational` is bigger than `RIStruct` In that case, to be switched implementation with `RData`. It is based to "complex". --- mrbgems/mruby-rational/src/rational.c | 69 ++++++++++++++++++++++++++++------- 1 file changed, 55 insertions(+), 14 deletions(-) diff --git a/mrbgems/mruby-rational/src/rational.c b/mrbgems/mruby-rational/src/rational.c index fa061c0b8..db9a8fbb9 100644 --- a/mrbgems/mruby-rational/src/rational.c +++ b/mrbgems/mruby-rational/src/rational.c @@ -1,30 +1,71 @@ #include #include #include -#include struct mrb_rational { mrb_int numerator; mrb_int denominator; }; +#if MRB_INT_MAX <= INTPTR_MAX + +#define RATIONAL_USE_ISTRUCT +/* use TT_ISTRUCT */ +#include + +#define rational_ptr(mrb, v) (struct mrb_rational*)mrb_istruct_ptr(v) + +static struct RBasic* +rational_alloc(mrb_state *mrb, struct RClass *c, struct mrb_rational **p) +{ + struct RIStruct *s; + + s = (struct RIStruct*)mrb_obj_alloc(mrb, MRB_TT_ISTRUCT, c); + *p = (struct mrb_rational*)s->inline_data; + + return (struct RBasic*)s; +} + +#else +/* use TT_DATA */ +#include + +static const struct mrb_data_type mrb_rational_type = {"Rational", mrb_free}; + +static struct RBasic* +rational_alloc(mrb_state *mrb, struct RClass *c, struct mrb_rational **p) +{ + struct RData *d; + + Data_Make_Struct(mrb, c, struct mrb_rational, &mrb_rational_type, *p, d); + + return (struct RBasic*)d; +} + static struct mrb_rational* -rational_ptr(mrb_value v) +rational_ptr(mrb_state *mrb, mrb_value v) { - return (struct mrb_rational*)mrb_istruct_ptr(v); + struct mrb_rational *p; + + p = DATA_GET_PTR(mrb, v, &mrb_rational_type, struct mrb_rational); + if (!p) { + mrb_raise(mrb, E_ARGUMENT_ERROR, "uninitialized rational"); + } + return p; } +#endif static mrb_value rational_numerator(mrb_state *mrb, mrb_value self) { - struct mrb_rational *p = rational_ptr(self); + struct mrb_rational *p = rational_ptr(mrb, self); return mrb_fixnum_value(p->numerator); } static mrb_value rational_denominator(mrb_state *mrb, mrb_value self) { - struct mrb_rational *p = rational_ptr(self); + struct mrb_rational *p = rational_ptr(mrb, self); return mrb_fixnum_value(p->denominator); } @@ -32,13 +73,12 @@ static mrb_value rational_new(mrb_state *mrb, mrb_int numerator, mrb_int denominator) { struct RClass *c = mrb_class_get(mrb, "Rational"); - struct RIStruct *s = (struct RIStruct*)mrb_obj_alloc(mrb, MRB_TT_ISTRUCT, c); - mrb_value rat = mrb_obj_value(s); - struct mrb_rational *p = rational_ptr(rat); + struct mrb_rational *p; + struct RBasic *rat = rational_alloc(mrb, c, &p); p->numerator = numerator; p->denominator = denominator; - MRB_SET_FROZEN_FLAG(s); - return rat; + MRB_SET_FROZEN_FLAG(rat); + return mrb_obj_value(rat); } static mrb_value @@ -54,7 +94,7 @@ rational_s_new(mrb_state *mrb, mrb_value self) static mrb_value rational_to_f(mrb_state *mrb, mrb_value self) { - struct mrb_rational *p = rational_ptr(self); + struct mrb_rational *p = rational_ptr(mrb, self); mrb_float f = (mrb_float)p->numerator / (mrb_float)p->denominator; return mrb_float_value(mrb, f); @@ -64,7 +104,7 @@ rational_to_f(mrb_state *mrb, mrb_value self) static mrb_value rational_to_i(mrb_state *mrb, mrb_value self) { - struct mrb_rational *p = rational_ptr(self); + struct mrb_rational *p = rational_ptr(mrb, self); return mrb_fixnum_value(p->numerator / p->denominator); } @@ -77,7 +117,7 @@ rational_to_r(mrb_state *mrb, mrb_value self) static mrb_value rational_negative_p(mrb_state *mrb, mrb_value self) { - struct mrb_rational *p = rational_ptr(self); + struct mrb_rational *p = rational_ptr(mrb, self); if (p->numerator < 0) { return mrb_true_value(); } @@ -94,9 +134,10 @@ void mrb_mruby_rational_gem_init(mrb_state *mrb) { struct RClass *rat; +#ifdef COMPLEX_USE_RATIONAL mrb_assert(sizeof(struct mrb_rational) < ISTRUCT_DATA_SIZE); +#endif rat = mrb_define_class(mrb, "Rational", mrb_class_get(mrb, "Numeric")); - MRB_SET_INSTANCE_TT(rat, MRB_TT_ISTRUCT); mrb_undef_class_method(mrb, rat, "new"); mrb_define_class_method(mrb, rat, "_new", rational_s_new, MRB_ARGS_REQ(2)); mrb_define_method(mrb, rat, "numerator", rational_numerator, MRB_ARGS_NONE()); -- cgit v1.2.3 From 64b3d452ec1cc3d5547da9ca37179f0e4406cc92 Mon Sep 17 00:00:00 2001 From: dearblue Date: Sun, 2 Jun 2019 18:00:54 +0900 Subject: Drop precisions for rational when big numbers --- mrbgems/mruby-rational/src/rational.c | 49 +++++++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) diff --git a/mrbgems/mruby-rational/src/rational.c b/mrbgems/mruby-rational/src/rational.c index db9a8fbb9..31471e934 100644 --- a/mrbgems/mruby-rational/src/rational.c +++ b/mrbgems/mruby-rational/src/rational.c @@ -1,6 +1,7 @@ #include #include #include +#include struct mrb_rational { mrb_int numerator; @@ -86,7 +87,52 @@ rational_s_new(mrb_state *mrb, mrb_value self) { mrb_int numerator, denominator; +#ifdef MRB_WITHOUT_FLOAT mrb_get_args(mrb, "ii", &numerator, &denominator); +#else + +#define DROP_PRECISION(cond, num, denom) \ + do { \ + while (cond) { \ + num /= 2; \ + denom /= 2; \ + } \ + } while (0) + + mrb_value numv, denomv; + + mrb_get_args(mrb, "oo", &numv, &denomv); + if (mrb_fixnum_p(numv)) { + numerator = mrb_fixnum(numv); + + if (mrb_fixnum_p(denomv)) { + denominator = mrb_fixnum(denomv); + } + else { + mrb_float denomf = mrb_to_flo(mrb, denomv); + + DROP_PRECISION(denomf < MRB_INT_MIN || denomf > MRB_INT_MAX, numerator, denomf); + denominator = denomf; + } + } + else { + mrb_float numf = mrb_to_flo(mrb, numv); + + if (mrb_fixnum_p(denomv)) { + denominator = mrb_fixnum(denomv); + } + else { + mrb_float denomf = mrb_to_flo(mrb, denomv); + + DROP_PRECISION(denomf < MRB_INT_MIN || denomf > MRB_INT_MAX, numf, denomf); + denominator = denomf; + } + + DROP_PRECISION(numf < MRB_INT_MIN || numf > MRB_INT_MAX, numf, denominator); + numerator = numf; + } +#endif + return rational_new(mrb, numerator, denominator); } @@ -105,6 +151,9 @@ static mrb_value rational_to_i(mrb_state *mrb, mrb_value self) { struct mrb_rational *p = rational_ptr(mrb, self); + if (p->denominator == 0) { + mrb_raise(mrb, mrb_exc_get(mrb, "StandardError"), "divided by 0"); + } return mrb_fixnum_value(p->numerator / p->denominator); } -- cgit v1.2.3 From 05493e651db15dd5c870b47556b4f9b54dfccee3 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Thu, 6 Jun 2019 20:21:40 +0900 Subject: Clarify `mruby-(kernel|object)-ext` gem summary; ref 8e637bdd [ci skip] --- mrbgems/mruby-kernel-ext/mrbgem.rake | 2 +- mrbgems/mruby-object-ext/mrbgem.rake | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/mrbgems/mruby-kernel-ext/mrbgem.rake b/mrbgems/mruby-kernel-ext/mrbgem.rake index fcb3a83b0..e52c63a55 100644 --- a/mrbgems/mruby-kernel-ext/mrbgem.rake +++ b/mrbgems/mruby-kernel-ext/mrbgem.rake @@ -1,5 +1,5 @@ MRuby::Gem::Specification.new('mruby-kernel-ext') do |spec| spec.license = 'MIT' spec.author = 'mruby developers' - spec.summary = 'Kernel module extension' + spec.summary = 'extensional function-like methods' end diff --git a/mrbgems/mruby-object-ext/mrbgem.rake b/mrbgems/mruby-object-ext/mrbgem.rake index 6d14b4a51..1aea2c8cd 100644 --- a/mrbgems/mruby-object-ext/mrbgem.rake +++ b/mrbgems/mruby-object-ext/mrbgem.rake @@ -1,5 +1,5 @@ MRuby::Gem::Specification.new('mruby-object-ext') do |spec| spec.license = 'MIT' spec.author = 'mruby developers' - spec.summary = 'Object class extension' + spec.summary = 'extensional methods shared by all objects' end -- cgit v1.2.3 From 4b83fe8b04f61e62d851648c0fe95e8e575181d5 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Fri, 7 Jun 2019 22:02:43 +0900 Subject: Remove `Kernel#global_variables` from core This method is defined in `mruby-metaprog` gem. --- mrbgems/mruby-metaprog/src/metaprog.c | 2 +- mrbgems/mruby-metaprog/test/metaprog.rb | 12 ++++++++++++ src/kernel.c | 1 - test/t/kernel.rb | 15 --------------- 4 files changed, 13 insertions(+), 17 deletions(-) diff --git a/mrbgems/mruby-metaprog/src/metaprog.c b/mrbgems/mruby-metaprog/src/metaprog.c index e57d10d8d..43d27f4dc 100644 --- a/mrbgems/mruby-metaprog/src/metaprog.c +++ b/mrbgems/mruby-metaprog/src/metaprog.c @@ -686,7 +686,7 @@ mrb_mruby_metaprog_gem_init(mrb_state* mrb) struct RClass *krn = mrb->kernel_module; struct RClass *mod = mrb->module_class; - mrb_define_method(mrb, krn, "global_variables", mrb_f_global_variables, MRB_ARGS_NONE()); /* 15.3.1.2.4 */ + mrb_define_method(mrb, krn, "global_variables", mrb_f_global_variables, MRB_ARGS_NONE()); /* 15.3.1.3.14 (15.3.1.2.4) */ mrb_define_method(mrb, krn, "local_variables", mrb_local_variables, MRB_ARGS_NONE()); /* 15.3.1.3.28 */ mrb_define_method(mrb, krn, "singleton_class", mrb_singleton_class, MRB_ARGS_NONE()); diff --git a/mrbgems/mruby-metaprog/test/metaprog.rb b/mrbgems/mruby-metaprog/test/metaprog.rb index 3aa1d8732..329580abc 100644 --- a/mrbgems/mruby-metaprog/test/metaprog.rb +++ b/mrbgems/mruby-metaprog/test/metaprog.rb @@ -99,6 +99,18 @@ assert('Kernel#singleton_methods', '15.3.1.3.45') do assert_equal singleton_methods.class, Array end +assert('Kernel.global_variables', '15.3.1.2.4') do + assert_equal Array, Kernel.global_variables.class +end + +assert('Kernel#global_variables', '15.3.1.3.14') do + variables = global_variables + assert_equal Array, variables.class + 1.upto(9) do |i| + assert_equal variables.include?(:"$#{i}"), true + end +end + assert('Kernel.local_variables', '15.3.1.2.7') do a, b = 0, 1 a += b diff --git a/src/kernel.c b/src/kernel.c index 349e71cb8..a3c2d2ec6 100644 --- a/src/kernel.c +++ b/src/kernel.c @@ -783,7 +783,6 @@ mrb_init_kernel(mrb_state *mrb) mrb_define_method(mrb, krn, "extend", mrb_obj_extend_m, MRB_ARGS_ANY()); /* 15.3.1.3.13 */ mrb_define_method(mrb, krn, "freeze", mrb_obj_freeze, MRB_ARGS_NONE()); mrb_define_method(mrb, krn, "frozen?", mrb_obj_frozen, MRB_ARGS_NONE()); - mrb_define_method(mrb, krn, "global_variables", mrb_f_global_variables, MRB_ARGS_NONE()); /* 15.3.1.3.14 */ mrb_define_method(mrb, krn, "hash", mrb_obj_hash, MRB_ARGS_NONE()); /* 15.3.1.3.15 */ mrb_define_method(mrb, krn, "initialize_copy", mrb_obj_init_copy, MRB_ARGS_REQ(1)); /* 15.3.1.3.16 */ mrb_define_method(mrb, krn, "inspect", mrb_obj_inspect, MRB_ARGS_NONE()); /* 15.3.1.3.17 */ diff --git a/test/t/kernel.rb b/test/t/kernel.rb index bf7dbe94c..7f6e6c58d 100644 --- a/test/t/kernel.rb +++ b/test/t/kernel.rb @@ -31,10 +31,6 @@ end # Kernel.eval is provided by the mruby-gem mrbgem. '15.3.1.2.3' -assert('Kernel.global_variables', '15.3.1.2.4') do - assert_equal Array, Kernel.global_variables.class -end - assert('Kernel.iterator?', '15.3.1.2.5') do assert_false Kernel.iterator? end @@ -266,10 +262,6 @@ assert('Kernel#frozen?') do assert_true 0.0.frozen? end -assert('Kernel#global_variables', '15.3.1.3.14') do - assert_equal Array, global_variables.class -end - assert('Kernel#hash', '15.3.1.3.15') do assert_equal hash, hash end @@ -488,13 +480,6 @@ assert('Kernel#respond_to_missing?') do assert_false Test4RespondToMissing.new.respond_to?(:no_method) end -assert('Kernel#global_variables') do - variables = global_variables - 1.upto(9) do |i| - assert_equal variables.include?(:"$#{i}"), true - end -end - assert('stack extend') do def recurse(count, stop) return count if count > stop -- cgit v1.2.3 From f8f75fc9c66d834fa81632b113dad5713e2b42b4 Mon Sep 17 00:00:00 2001 From: dearblue Date: Fri, 7 Jun 2019 22:54:03 +0900 Subject: Replace obsolete macros --- mrbgems/mruby-io/src/file_test.c | 2 +- mrbgems/mruby-io/src/io.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/mrbgems/mruby-io/src/file_test.c b/mrbgems/mruby-io/src/file_test.c index 5d5ecb93f..85a221ff9 100644 --- a/mrbgems/mruby-io/src/file_test.c +++ b/mrbgems/mruby-io/src/file_test.c @@ -44,7 +44,7 @@ mrb_stat0(mrb_state *mrb, mrb_value obj, struct stat *st, int do_lstat) { if (mrb_obj_is_kind_of(mrb, obj, mrb_class_get(mrb, "IO"))) { struct mrb_io *fptr; - fptr = (struct mrb_io *)mrb_get_datatype(mrb, obj, &mrb_io_type); + fptr = (struct mrb_io *)mrb_data_get_ptr(mrb, obj, &mrb_io_type); if (fptr && fptr->fd >= 0) { return fstat(fptr->fd, st); diff --git a/mrbgems/mruby-io/src/io.c b/mrbgems/mruby-io/src/io.c index e5b83e923..99441f16b 100644 --- a/mrbgems/mruby-io/src/io.c +++ b/mrbgems/mruby-io/src/io.c @@ -79,7 +79,7 @@ io_get_open_fptr(mrb_state *mrb, mrb_value self) { struct mrb_io *fptr; - fptr = (struct mrb_io *)mrb_get_datatype(mrb, self, &mrb_io_type); + fptr = (struct mrb_io *)mrb_data_get_ptr(mrb, self, &mrb_io_type); if (fptr == NULL) { mrb_raise(mrb, E_IO_ERROR, "uninitialized stream."); } @@ -955,7 +955,7 @@ mrb_value mrb_io_closed(mrb_state *mrb, mrb_value io) { struct mrb_io *fptr; - fptr = (struct mrb_io *)mrb_get_datatype(mrb, io, &mrb_io_type); + fptr = (struct mrb_io *)mrb_data_get_ptr(mrb, io, &mrb_io_type); if (fptr == NULL || fptr->fd >= 0) { return mrb_false_value(); } -- cgit v1.2.3 From 2e160f53dbd69598ec6a3ee8a15f85b4cf5168cf Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Sat, 8 Jun 2019 22:32:19 +0900 Subject: Remove "Check the usage of a NUL character" test Because there is not assertion in this test and NUL character literal is used in other tests. --- test/t/string.rb | 4 ---- 1 file changed, 4 deletions(-) diff --git a/test/t/string.rb b/test/t/string.rb index e5b001366..9817dd188 100644 --- a/test/t/string.rb +++ b/test/t/string.rb @@ -694,10 +694,6 @@ assert('String interpolation (mrb_str_concat for shared strings)') do assert_equal "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA:", "#{a}:" end -assert('Check the usage of a NUL character') do - "qqq\0ppp" -end - assert('String#bytes') do str1 = "hello" bytes1 = [104, 101, 108, 108, 111] -- cgit v1.2.3 From ffb700dea0a23930e4f620cf5ff9855efa709f9c Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Sun, 9 Jun 2019 18:27:28 +0900 Subject: Fix missing assertions in `test/t/syntax.rb` --- test/t/syntax.rb | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/test/t/syntax.rb b/test/t/syntax.rb index 603547c7c..afb735e7f 100644 --- a/test/t/syntax.rb +++ b/test/t/syntax.rb @@ -423,10 +423,11 @@ assert('parenthesed do-block in cmdarg') do end assert('method definition in cmdarg') do - if false + result = class MethodDefinitionInCmdarg + def self.bar(arg); arg end bar def foo; self.each do end end end - true + assert_equal(:foo, result) end assert('optional argument in the rhs default expressions') do -- cgit v1.2.3 From 38f1da6f26bde5185612b66a1b1fc94f78654d78 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Mon, 10 Jun 2019 18:46:57 +0900 Subject: `Kernel#global_variables` should not include undefined `$1`-`$9` - They are not include in Ruby. - Appear in duplicate when `$1`-`$9` are defined. --- mrbgems/mruby-metaprog/test/metaprog.rb | 13 ++++++++----- src/variable.c | 8 -------- 2 files changed, 8 insertions(+), 13 deletions(-) diff --git a/mrbgems/mruby-metaprog/test/metaprog.rb b/mrbgems/mruby-metaprog/test/metaprog.rb index 329580abc..685fdf196 100644 --- a/mrbgems/mruby-metaprog/test/metaprog.rb +++ b/mrbgems/mruby-metaprog/test/metaprog.rb @@ -104,11 +104,14 @@ assert('Kernel.global_variables', '15.3.1.2.4') do end assert('Kernel#global_variables', '15.3.1.3.14') do - variables = global_variables - assert_equal Array, variables.class - 1.upto(9) do |i| - assert_equal variables.include?(:"$#{i}"), true - end + variables1 = global_variables + assert_equal Array, variables1.class + assert_not_include(variables1, :$kernel_global_variables_test) + + $kernel_global_variables_test = nil + variables2 = global_variables + assert_include(variables2, :$kernel_global_variables_test) + assert_equal(1, variables2.size - variables1.size) end assert('Kernel.local_variables', '15.3.1.2.7') do diff --git a/src/variable.c b/src/variable.c index ee21a3b96..779f206dc 100644 --- a/src/variable.c +++ b/src/variable.c @@ -965,16 +965,8 @@ mrb_f_global_variables(mrb_state *mrb, mrb_value self) { iv_tbl *t = mrb->globals; mrb_value ary = mrb_ary_new(mrb); - size_t i; - char buf[3]; iv_foreach(mrb, t, gv_i, &ary); - buf[0] = '$'; - buf[2] = 0; - for (i = 1; i <= 9; ++i) { - buf[1] = (char)(i + '0'); - mrb_ary_push(mrb, ary, mrb_symbol_value(mrb_intern(mrb, buf, 2))); - } return ary; } -- cgit v1.2.3 From 3b9b326d3ccd21e45f498272c8bb8d3f338ccd60 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Tue, 11 Jun 2019 18:55:39 +0900 Subject: Remove redundant colon in `Proc#inspect` (`mruby-proc-ext`) Before this patch: $ bin/mruby -e 'p proc{}' #=> # After this patch: $ bin/mruby -e 'p proc{}' #=> # --- mrbgems/mruby-proc-ext/src/proc.c | 4 ++-- mrbgems/mruby-proc-ext/test/proc.rb | 26 +++++++++++++++++++++----- 2 files changed, 23 insertions(+), 7 deletions(-) diff --git a/mrbgems/mruby-proc-ext/src/proc.c b/mrbgems/mruby-proc-ext/src/proc.c index 17884e3c6..c9041ec75 100644 --- a/mrbgems/mruby-proc-ext/src/proc.c +++ b/mrbgems/mruby-proc-ext/src/proc.c @@ -38,7 +38,7 @@ mrb_proc_inspect(mrb_state *mrb, mrb_value self) { struct RProc *p = mrb_proc_ptr(self); mrb_value str = mrb_str_new_lit(mrb, "#body.irep; @@ -52,7 +52,7 @@ mrb_proc_inspect(mrb_state *mrb, mrb_value self) line = mrb_debug_get_line(mrb, irep, 0); if (line != -1) { - str = mrb_format(mrb, "%S:%S", str, mrb_fixnum_value(line)); + mrb_str_concat(mrb, str, mrb_fixnum_value(line)); } else { mrb_str_cat_lit(mrb, str, "-"); diff --git a/mrbgems/mruby-proc-ext/test/proc.rb b/mrbgems/mruby-proc-ext/test/proc.rb index 1220841c8..a6321d371 100644 --- a/mrbgems/mruby-proc-ext/test/proc.rb +++ b/mrbgems/mruby-proc-ext/test/proc.rb @@ -1,16 +1,32 @@ ## # Proc(Ext) Test +def enable_debug_info? + return @enable_debug_info unless @enable_debug_info == nil + begin + raise + rescue => e + @enable_debug_info = !e.backtrace.empty? + end +end + assert('Proc#source_location') do - loc = Proc.new {}.source_location - next true if loc.nil? - assert_equal loc[0][-7, 7], 'proc.rb' - assert_equal loc[1], 5 + skip unless enable_debug_info? + file, line = Proc.new{}.source_location + assert_equal __FILE__, file + assert_equal __LINE__ - 2, line end assert('Proc#inspect') do ins = Proc.new{}.inspect - assert_kind_of String, ins + if enable_debug_info? + metas = %w(\\ * ? [ ] { }) + file = __FILE__.split("").map{|c| metas.include?(c) ? "\\#{c}" : c}.join + line = __LINE__ - 4 + else + file = line = "-" + end + assert_match "#", ins end assert('Proc#parameters') do -- cgit v1.2.3 From ee955b58f7818248626e3aa66a6bff17dbd6060f Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Wed, 12 Jun 2019 18:52:58 +0900 Subject: Adjust allocation size in `mrb_id_attrset()` (`mruby-struct`) --- mrbgems/mruby-struct/src/struct.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/mrbgems/mruby-struct/src/struct.c b/mrbgems/mruby-struct/src/struct.c index 1df135a9f..6edc5444b 100644 --- a/mrbgems/mruby-struct/src/struct.c +++ b/mrbgems/mruby-struct/src/struct.c @@ -129,10 +129,9 @@ mrb_id_attrset(mrb_state *mrb, mrb_sym id) mrb_sym mid; name = mrb_sym2name_len(mrb, id, &len); - buf = (char *)mrb_malloc(mrb, (size_t)len+2); + buf = (char *)mrb_malloc(mrb, (size_t)len+1); memcpy(buf, name, (size_t)len); buf[len] = '='; - buf[len+1] = '\0'; mid = mrb_intern(mrb, buf, len+1); mrb_free(mrb, buf); -- cgit v1.2.3 From db3e6f6ac66c258cb23ecbbbcaa7dc32bdfe4759 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Wed, 12 Jun 2019 20:45:27 +0900 Subject: Fix typo in `String#setbyte` error message --- mrbgems/mruby-string-ext/src/string.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mrbgems/mruby-string-ext/src/string.c b/mrbgems/mruby-string-ext/src/string.c index 85180516c..d9ebb7392 100644 --- a/mrbgems/mruby-string-ext/src/string.c +++ b/mrbgems/mruby-string-ext/src/string.c @@ -29,7 +29,7 @@ mrb_str_setbyte(mrb_state *mrb, mrb_value str) len = RSTRING_LEN(str); if (pos < -len || len <= pos) - mrb_raisef(mrb, E_INDEX_ERROR, "index %S is out of array", mrb_fixnum_value(pos)); + mrb_raisef(mrb, E_INDEX_ERROR, "index %S out of string", mrb_fixnum_value(pos)); if (pos < 0) pos += len; -- cgit v1.2.3 From 9bd692bc67ee302bcbc359d0841458339c440fb4 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Thu, 13 Jun 2019 21:24:48 +0900 Subject: Fix class name validation in `Struct.new` Before this patch: $ bin/mruby -e 'p Struct.new("A-")' #=> Struct::"A-" After this patch: $ bin/mruby -e 'p Struct.new("A-")' #=> NameError: identifier A- needs to be constant --- include/mruby/class.h | 1 + mrbgems/mruby-struct/src/struct.c | 2 +- mrbgems/mruby-struct/test/struct.rb | 4 ++++ src/class.c | 14 +++++++------- 4 files changed, 13 insertions(+), 8 deletions(-) diff --git a/include/mruby/class.h b/include/mruby/class.h index a68724538..c79a487b5 100644 --- a/include/mruby/class.h +++ b/include/mruby/class.h @@ -88,6 +88,7 @@ MRB_API struct RClass* mrb_class_real(struct RClass* cl); mrb_value mrb_instance_new(mrb_state *mrb, mrb_value cv); void mrb_class_name_class(mrb_state*, struct RClass*, struct RClass*, mrb_sym); +mrb_bool mrb_const_name_p(mrb_state*, const char*, mrb_int); mrb_value mrb_class_find_path(mrb_state*, struct RClass*); void mrb_gc_mark_mt(mrb_state*, struct RClass*); size_t mrb_gc_mark_mt_size(mrb_state*, struct RClass*); diff --git a/mrbgems/mruby-struct/src/struct.c b/mrbgems/mruby-struct/src/struct.c index 1df135a9f..539127bf8 100644 --- a/mrbgems/mruby-struct/src/struct.c +++ b/mrbgems/mruby-struct/src/struct.c @@ -212,7 +212,7 @@ make_struct(mrb_state *mrb, mrb_value name, mrb_value members, struct RClass *kl /* old style: should we warn? */ mrb_to_str(mrb, name); id = mrb_obj_to_sym(mrb, name); - if (!is_const_id(mrb, mrb_sym2name_len(mrb, id, NULL))) { + if (!mrb_const_name_p(mrb, RSTRING_PTR(name), RSTRING_LEN(name))) { mrb_name_error(mrb, id, "identifier %S needs to be constant", name); } if (mrb_const_defined_at(mrb, mrb_obj_value(klass), id)) { diff --git a/mrbgems/mruby-struct/test/struct.rb b/mrbgems/mruby-struct/test/struct.rb index 91e8cecc6..9f2ff1cdc 100644 --- a/mrbgems/mruby-struct/test/struct.rb +++ b/mrbgems/mruby-struct/test/struct.rb @@ -181,6 +181,10 @@ assert("Struct.new does not allow array") do end end +assert("Struct.new does not allow invalid class name") do + assert_raise(NameError) { Struct.new("Test-", :a) } +end + assert("Struct.new generates subclass of Struct") do begin original_struct = Struct diff --git a/src/class.c b/src/class.c index 6ceaa0cfa..373f2aec7 100644 --- a/src/class.c +++ b/src/class.c @@ -77,6 +77,12 @@ mrb_class_name_class(mrb_state *mrb, struct RClass *outer, struct RClass *c, mrb mrb_obj_iv_set_force(mrb, (struct RObject*)c, nsym, name); } +mrb_bool +mrb_const_name_p(mrb_state *mrb, const char *name, mrb_int len) +{ + return len > 0 && ISUPPER(name[0]) && mrb_ident_p(name+1, len-1); +} + static void setup_class(mrb_state *mrb, struct RClass *outer, struct RClass *c, mrb_sym id) { @@ -1852,18 +1858,12 @@ mrb_mod_undef(mrb_state *mrb, mrb_value mod) return mrb_nil_value(); } -static mrb_bool -const_name_p(mrb_state *mrb, const char *name, mrb_int len) -{ - return len > 0 && ISUPPER(name[0]) && mrb_ident_p(name+1, len-1); -} - static void check_const_name_sym(mrb_state *mrb, mrb_sym id) { mrb_int len; const char *name = mrb_sym2name_len(mrb, id, &len); - if (!const_name_p(mrb, name, len)) { + if (!mrb_const_name_p(mrb, name, len)) { mrb_name_error(mrb, id, "wrong constant name %S", mrb_sym2str(mrb, id)); } } -- cgit v1.2.3 From 6084048b28a3c256ceeaa2885d17fc42e238e4a6 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Fri, 14 Jun 2019 10:26:19 +0900 Subject: Remove a meaningless branch condition in `mruby-struct` The following branch condition is always true: // mrbgems/mruby-struct/src/struct.c:187 in make_struct_define_accessors() if (is_local_id(mrb, name) || is_const_id(mrb, name)) { --- mrbgems/mruby-struct/src/struct.c | 36 +++++++++--------------------------- 1 file changed, 9 insertions(+), 27 deletions(-) diff --git a/mrbgems/mruby-struct/src/struct.c b/mrbgems/mruby-struct/src/struct.c index 539127bf8..40914acc9 100644 --- a/mrbgems/mruby-struct/src/struct.c +++ b/mrbgems/mruby-struct/src/struct.c @@ -158,20 +158,6 @@ mrb_struct_set_m(mrb_state *mrb, mrb_value obj) return val; } -static mrb_bool -is_local_id(mrb_state *mrb, const char *name) -{ - if (!name) return FALSE; - return !ISUPPER(name[0]); -} - -static mrb_bool -is_const_id(mrb_state *mrb, const char *name) -{ - if (!name) return FALSE; - return ISUPPER(name[0]); -} - static void make_struct_define_accessors(mrb_state *mrb, mrb_value members, struct RClass *c) { @@ -182,19 +168,15 @@ make_struct_define_accessors(mrb_state *mrb, mrb_value members, struct RClass *c for (i=0; i Date: Sat, 15 Jun 2019 19:41:04 +0900 Subject: Fix index in error message of `Struct#[]` Before this patch: $ bin/mruby -e 'Struct.new(:a,:b).new[-3]' #=> offset -1 too small for struct(size:2) (IndexError) After this patch (same as Ruby): $ bin/mruby -e 'Struct.new(:a,:b).new[-3]' #=> offset -3 too small for struct(size:2) (IndexError) --- mrbgems/mruby-struct/src/struct.c | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/mrbgems/mruby-struct/src/struct.c b/mrbgems/mruby-struct/src/struct.c index 40914acc9..939033d74 100644 --- a/mrbgems/mruby-struct/src/struct.c +++ b/mrbgems/mruby-struct/src/struct.c @@ -385,16 +385,17 @@ struct_aref_sym(mrb_state *mrb, mrb_value obj, mrb_sym id) static mrb_value struct_aref_int(mrb_state *mrb, mrb_value s, mrb_int i) { - if (i < 0) i = RSTRUCT_LEN(s) + i; - if (i < 0) - mrb_raisef(mrb, E_INDEX_ERROR, - "offset %S too small for struct(size:%S)", - mrb_fixnum_value(i), mrb_fixnum_value(RSTRUCT_LEN(s))); - if (RSTRUCT_LEN(s) <= i) + mrb_int idx = i < 0 ? RSTRUCT_LEN(s) + i : i; + + if (idx < 0) + mrb_raisef(mrb, E_INDEX_ERROR, + "offset %S too small for struct(size:%S)", + mrb_fixnum_value(i), mrb_fixnum_value(RSTRUCT_LEN(s))); + if (RSTRUCT_LEN(s) <= idx) mrb_raisef(mrb, E_INDEX_ERROR, "offset %S too large for struct(size:%S)", mrb_fixnum_value(i), mrb_fixnum_value(RSTRUCT_LEN(s))); - return RSTRUCT_PTR(s)[i]; + return RSTRUCT_PTR(s)[idx]; } /* 15.2.18.4.2 */ -- cgit v1.2.3 From 030dd6655e47dad4af4b48a74646712c00684698 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Sun, 16 Jun 2019 20:43:23 +0900 Subject: Fix cvar, ivar, const and method can be removed to frozen object --- mrbgems/mruby-metaprog/src/metaprog.c | 1 + mrbgems/mruby-metaprog/test/metaprog.rb | 8 ++++++-- src/variable.c | 1 + test/t/kernel.rb | 1 + test/t/module.rb | 1 + 5 files changed, 10 insertions(+), 2 deletions(-) diff --git a/mrbgems/mruby-metaprog/src/metaprog.c b/mrbgems/mruby-metaprog/src/metaprog.c index 43d27f4dc..0d207ef41 100644 --- a/mrbgems/mruby-metaprog/src/metaprog.c +++ b/mrbgems/mruby-metaprog/src/metaprog.c @@ -641,6 +641,7 @@ mrb_mod_remove_method(mrb_state *mrb, mrb_value mod) mrb_value *argv; mrb_get_args(mrb, "*", &argv, &argc); + mrb_check_frozen(mrb, mrb_obj_ptr(mod)); while (argc--) { remove_method(mrb, mod, mrb_obj_to_sym(mrb, *argv)); argv++; diff --git a/mrbgems/mruby-metaprog/test/metaprog.rb b/mrbgems/mruby-metaprog/test/metaprog.rb index 685fdf196..46b98d0ed 100644 --- a/mrbgems/mruby-metaprog/test/metaprog.rb +++ b/mrbgems/mruby-metaprog/test/metaprog.rb @@ -298,6 +298,9 @@ assert('Module#remove_class_variable', '15.2.2.4.39') do assert_raise(NameError) do Test4RemoveClassVariable.remove_class_variable(:@v) end + assert_raise(FrozenError) do + Test4RemoveClassVariable.freeze.remove_class_variable(:@@cv) + end end assert('Module#remove_method', '15.2.2.4.41') do @@ -305,9 +308,9 @@ assert('Module#remove_method', '15.2.2.4.41') do class Parent def hello end - end + end - class Child < Parent + class Child < Parent def hello end end @@ -317,6 +320,7 @@ assert('Module#remove_method', '15.2.2.4.41') do assert_same klass, klass.class_eval{ remove_method :hello } assert_true klass.instance_methods.include? :hello assert_false klass.instance_methods(false).include? :hello + assert_raise(FrozenError) { klass.freeze.remove_method :m } end assert('Module.nesting', '15.2.2.2.2') do diff --git a/src/variable.c b/src/variable.c index 779f206dc..23d900b7d 100644 --- a/src/variable.c +++ b/src/variable.c @@ -521,6 +521,7 @@ mrb_obj_iv_inspect(mrb_state *mrb, struct RObject *obj) MRB_API mrb_value mrb_iv_remove(mrb_state *mrb, mrb_value obj, mrb_sym sym) { + mrb_check_frozen(mrb, mrb_obj_ptr(obj)); if (obj_iv_p(obj)) { iv_tbl *t = mrb_obj_ptr(obj)->iv; mrb_value val; diff --git a/test/t/kernel.rb b/test/t/kernel.rb index 7f6e6c58d..950442351 100644 --- a/test/t/kernel.rb +++ b/test/t/kernel.rb @@ -404,6 +404,7 @@ assert('Kernel#remove_instance_variable', '15.3.1.3.41') do assert_equal nil, tri.var assert_raise(NameError) { tri.remove } assert_raise(NameError) { tri.remove_instance_variable(:var) } + assert_raise(FrozenError) { tri.freeze.remove } end # Kernel#require is defined in mruby-require. '15.3.1.3.42' diff --git a/test/t/module.rb b/test/t/module.rb index 3bb9735df..571f4759d 100644 --- a/test/t/module.rb +++ b/test/t/module.rb @@ -262,6 +262,7 @@ assert('Module#remove_const', '15.2.2.4.40') do %i[x X!].each do |n| assert_raise(NameError) { Test4RemoveConst.remove_const(n) } end + assert_raise(FrozenError) { Test4RemoveConst.freeze.remove_const(:A) } end assert('Module#const_missing', '15.2.2.4.22') do -- cgit v1.2.3 From d895c5fe5aa8e65f7e98b79494602a0f0d442a30 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Sat, 15 Jun 2019 10:02:49 +0900 Subject: Fixed wrong behavior on `..` at the beginning of the line. --- mrbgems/mruby-compiler/core/parse.y | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/mrbgems/mruby-compiler/core/parse.y b/mrbgems/mruby-compiler/core/parse.y index 37d4d1bf1..baa69b556 100644 --- a/mrbgems/mruby-compiler/core/parse.y +++ b/mrbgems/mruby-compiler/core/parse.y @@ -4758,8 +4758,7 @@ parser_yylex(parser_state *p) space_seen = 1; break; case '.': - if ((c = nextc(p)) != '.') { - pushback(p, c); + if (!peek(p, '.')) { pushback(p, '.'); goto retry; } -- cgit v1.2.3 From 4124047ccec9c299002902750fcb4b6534bbbdca Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Sat, 15 Jun 2019 10:04:47 +0900 Subject: Support `&.` at the beginning of the line. --- mrbgems/mruby-compiler/core/parse.y | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/mrbgems/mruby-compiler/core/parse.y b/mrbgems/mruby-compiler/core/parse.y index baa69b556..ff4016d8b 100644 --- a/mrbgems/mruby-compiler/core/parse.y +++ b/mrbgems/mruby-compiler/core/parse.y @@ -4762,6 +4762,15 @@ parser_yylex(parser_state *p) pushback(p, '.'); goto retry; } + pushback(p, c); + goto normal_newline; + case '&': + if (peek(p, '.')) { + pushback(p, '&'); + goto retry; + } + pushback(p, c); + goto normal_newline; case -1: /* EOF */ case -2: /* end of a file */ goto normal_newline; -- cgit v1.2.3 From 4296c77e29b67e72399dde8295dd6fa4a10cc321 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Sat, 15 Jun 2019 12:52:57 +0900 Subject: Allow newlines and comments between method calls. --- mrbgems/mruby-compiler/core/parse.y | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/mrbgems/mruby-compiler/core/parse.y b/mrbgems/mruby-compiler/core/parse.y index ff4016d8b..6ab91ce91 100644 --- a/mrbgems/mruby-compiler/core/parse.y +++ b/mrbgems/mruby-compiler/core/parse.y @@ -4757,6 +4757,14 @@ parser_yylex(parser_state *p) case '\13': /* '\v' */ space_seen = 1; break; + case '#': /* comment as a whitespace */ + pushback(p, '#'); + goto retry; + case '\n': /* consecutive newlines */ + p->lineno++; + p->column = 0; + pushback(p, '\n'); + goto retry; case '.': if (!peek(p, '.')) { pushback(p, '.'); -- cgit v1.2.3 From 0fba50082642fa4a6e0468f4e41192de095258f4 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Sat, 15 Jun 2019 12:58:30 +0900 Subject: Fixed indentation in parse.y --- mrbgems/mruby-compiler/core/parse.y | 106 ++++++++++++++++++------------------ 1 file changed, 53 insertions(+), 53 deletions(-) diff --git a/mrbgems/mruby-compiler/core/parse.y b/mrbgems/mruby-compiler/core/parse.y index 6ab91ce91..96a9453b6 100644 --- a/mrbgems/mruby-compiler/core/parse.y +++ b/mrbgems/mruby-compiler/core/parse.y @@ -4729,68 +4729,68 @@ parser_yylex(parser_state *p) /* fall through */ case -2: /* end of a file */ case '\n': - maybe_heredoc: + maybe_heredoc: heredoc_treat_nextline(p); - switch (p->lstate) { - case EXPR_BEG: - case EXPR_FNAME: - case EXPR_DOT: - case EXPR_CLASS: - case EXPR_VALUE: - p->lineno++; - p->column = 0; - if (p->parsing_heredoc != NULL) { - if (p->lex_strterm) { - return parse_string(p); - } - } - goto retry; - default: - break; - } - if (p->parsing_heredoc != NULL) { - return '\n'; - } - while ((c = nextc(p))) { - switch (c) { - case ' ': case '\t': case '\f': case '\r': - case '\13': /* '\v' */ - space_seen = 1; - break; - case '#': /* comment as a whitespace */ - pushback(p, '#'); - goto retry; - case '\n': /* consecutive newlines */ + switch (p->lstate) { + case EXPR_BEG: + case EXPR_FNAME: + case EXPR_DOT: + case EXPR_CLASS: + case EXPR_VALUE: p->lineno++; p->column = 0; - pushback(p, '\n'); + if (p->parsing_heredoc != NULL) { + if (p->lex_strterm) { + return parse_string(p); + } + } goto retry; - case '.': - if (!peek(p, '.')) { - pushback(p, '.'); + default: + break; + } + if (p->parsing_heredoc != NULL) { + return '\n'; + } + while ((c = nextc(p))) { + switch (c) { + case ' ': case '\t': case '\f': case '\r': + case '\13': /* '\v' */ + space_seen = 1; + break; + case '#': /* comment as a whitespace */ + pushback(p, '#'); goto retry; - } - pushback(p, c); - goto normal_newline; - case '&': - if (peek(p, '.')) { - pushback(p, '&'); + case '\n': /* consecutive newlines */ + p->lineno++; + p->column = 0; + pushback(p, '\n'); goto retry; + case '.': + if (!peek(p, '.')) { + pushback(p, '.'); + goto retry; + } + pushback(p, c); + goto normal_newline; + case '&': + if (peek(p, '.')) { + pushback(p, '&'); + goto retry; + } + pushback(p, c); + goto normal_newline; + case -1: /* EOF */ + case -2: /* end of a file */ + goto normal_newline; + default: + pushback(p, c); + goto normal_newline; } - pushback(p, c); - goto normal_newline; - case -1: /* EOF */ - case -2: /* end of a file */ - goto normal_newline; - default: - pushback(p, c); - goto normal_newline; } - } normal_newline: - p->cmd_start = TRUE; - p->lstate = EXPR_BEG; - return '\n'; + p->cmd_start = TRUE; + p->lstate = EXPR_BEG; + return '\n'; case '*': if ((c = nextc(p)) == '*') { -- cgit v1.2.3 From faec8331b7805c810b83b94785323ed239a05cb7 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Mon, 17 Jun 2019 21:46:30 +0900 Subject: Remove unneeded `mrb_str_dup()` in `Module#name` `mrb_class_path()` always returns a new string or `nil`. --- mrbgems/mruby-class-ext/src/class.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/mrbgems/mruby-class-ext/src/class.c b/mrbgems/mruby-class-ext/src/class.c index 705db9949..fdd56bcc3 100644 --- a/mrbgems/mruby-class-ext/src/class.c +++ b/mrbgems/mruby-class-ext/src/class.c @@ -5,8 +5,7 @@ static mrb_value mrb_mod_name(mrb_state *mrb, mrb_value self) { - mrb_value name = mrb_class_path(mrb, mrb_class_ptr(self)); - return mrb_nil_p(name)? name : mrb_str_dup(mrb, name); + return mrb_class_path(mrb, mrb_class_ptr(self)); } static mrb_value -- cgit v1.2.3 From b630bf59ef9db340f727d18ac5d091790b88d6ce Mon Sep 17 00:00:00 2001 From: Hiroshi Mimaki Date: Tue, 18 Jun 2019 13:27:16 +0900 Subject: Fix path of `error.h`. --- mrbgems/mruby-pack/src/pack.c | 2 +- mrbgems/mruby-socket/src/socket.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/mrbgems/mruby-pack/src/pack.c b/mrbgems/mruby-pack/src/pack.c index 75a447d6c..46c0cc1fe 100644 --- a/mrbgems/mruby-pack/src/pack.c +++ b/mrbgems/mruby-pack/src/pack.c @@ -3,7 +3,7 @@ */ #include "mruby.h" -#include "error.h" +#include "mruby/error.h" #include "mruby/array.h" #include "mruby/class.h" #include "mruby/numeric.h" diff --git a/mrbgems/mruby-socket/src/socket.c b/mrbgems/mruby-socket/src/socket.c index 8515a6057..9b06274dc 100644 --- a/mrbgems/mruby-socket/src/socket.c +++ b/mrbgems/mruby-socket/src/socket.c @@ -41,7 +41,7 @@ #include "mruby/numeric.h" #include "mruby/string.h" #include "mruby/variable.h" -#include "error.h" +#include "mruby/error.h" #include "mruby/ext/io.h" -- cgit v1.2.3 From 81828f8b08aa79bb9ead5b846958a087ddcf5b1f Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Tue, 18 Jun 2019 18:17:03 +0900 Subject: Fix `struct RRange` overflow on 32-bit CPU with `MRB_NAN_BOXING` --- include/mruby/range.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/mruby/range.h b/include/mruby/range.h index ee6eb8d1d..500a941d5 100644 --- a/include/mruby/range.h +++ b/include/mruby/range.h @@ -14,7 +14,7 @@ */ MRB_BEGIN_DECL -#if defined(MRB_NAN_BOXING) || defined(MRB_WORD_BOXING) +#if defined(MRB_NAN_BOXING) && defined(MRB_64BIT) || defined(MRB_WORD_BOXING) # define MRB_RANGE_EMBED #endif -- cgit v1.2.3 From 4d9d6faf0d5890eca2b6407fe53531ea19450b3d Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Wed, 19 Jun 2019 17:50:20 +0900 Subject: Remove unneeded statement in `SET_OBJ_VALUE` with `boxing_word.h` `(r).value.bp` and `v` have the same value due to assignment of the line preceding the removed line. --- include/mruby/boxing_word.h | 1 - 1 file changed, 1 deletion(-) diff --git a/include/mruby/boxing_word.h b/include/mruby/boxing_word.h index 2fb84052a..f16968a1f 100644 --- a/include/mruby/boxing_word.h +++ b/include/mruby/boxing_word.h @@ -141,7 +141,6 @@ mrb_type(mrb_value o) #define SET_OBJ_VALUE(r,v) do { \ (r).w = 0; \ (r).value.p = (v); \ - if ((r).value.bp) (r).value.bp->tt = ((struct RObject*)(v))->tt; \ } while (0) #endif /* MRUBY_BOXING_WORD_H */ -- cgit v1.2.3 From 77996e6adc753e3e407fefa0d282ea66762d5699 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Thu, 20 Jun 2019 19:59:27 +0900 Subject: Add ISO section number to `Kernel.#local_variables` [ci skip] --- mrbgems/mruby-metaprog/src/metaprog.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/mrbgems/mruby-metaprog/src/metaprog.c b/mrbgems/mruby-metaprog/src/metaprog.c index 0d207ef41..62daa5227 100644 --- a/mrbgems/mruby-metaprog/src/metaprog.c +++ b/mrbgems/mruby-metaprog/src/metaprog.c @@ -117,6 +117,7 @@ mrb_obj_ivar_set(mrb_state *mrb, mrb_value self) } /* 15.3.1.2.7 */ +/* 15.3.1.3.28 */ /* * call-seq: * local_variables -> array @@ -688,7 +689,7 @@ mrb_mruby_metaprog_gem_init(mrb_state* mrb) struct RClass *mod = mrb->module_class; mrb_define_method(mrb, krn, "global_variables", mrb_f_global_variables, MRB_ARGS_NONE()); /* 15.3.1.3.14 (15.3.1.2.4) */ - mrb_define_method(mrb, krn, "local_variables", mrb_local_variables, MRB_ARGS_NONE()); /* 15.3.1.3.28 */ + mrb_define_method(mrb, krn, "local_variables", mrb_local_variables, MRB_ARGS_NONE()); /* 15.3.1.3.28 (15.3.1.2.7) */ mrb_define_method(mrb, krn, "singleton_class", mrb_singleton_class, MRB_ARGS_NONE()); mrb_define_method(mrb, krn, "instance_variable_defined?", mrb_obj_ivar_defined, MRB_ARGS_REQ(1)); /* 15.3.1.3.20 */ -- cgit v1.2.3 From c43ff6fa4063d22db391ab1818b121110ca520bf Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Fri, 21 Jun 2019 22:02:29 +0900 Subject: Move `Kernel#__send__` test to core from `mruby-metaprog` --- mrbgems/mruby-metaprog/test/metaprog.rb | 14 -------------- test/t/kernel.rb | 14 ++++++++++++++ 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/mrbgems/mruby-metaprog/test/metaprog.rb b/mrbgems/mruby-metaprog/test/metaprog.rb index 46b98d0ed..1e1d4ff26 100644 --- a/mrbgems/mruby-metaprog/test/metaprog.rb +++ b/mrbgems/mruby-metaprog/test/metaprog.rb @@ -1,17 +1,3 @@ -assert('Kernel#__send__', '15.3.1.3.4') do - # test with block - l = __send__(:lambda) do - true - end - - assert_true l.call - assert_equal Proc, l.class - # test with argument - assert_true __send__(:respond_to?, :nil?) - # test without argument and without block - assert_equal String, __send__(:to_s).class -end - assert('Kernel#send', '15.3.1.3.44') do # test with block l = send(:lambda) do diff --git a/test/t/kernel.rb b/test/t/kernel.rb index 950442351..103660f53 100644 --- a/test/t/kernel.rb +++ b/test/t/kernel.rb @@ -88,6 +88,20 @@ assert('Kernel#__id__', '15.3.1.3.3') do assert_equal Fixnum, __id__.class end +assert('Kernel#__send__', '15.3.1.3.4') do + # test with block + l = __send__(:lambda) do + true + end + + assert_true l.call + assert_equal Proc, l.class + # test with argument + assert_true __send__(:respond_to?, :nil?) + # test without argument and without block + assert_equal String, __send__(:to_s).class +end + assert('Kernel#block_given?', '15.3.1.3.6') do def bg_try(&b) if block_given? -- cgit v1.2.3 From a76da32567f9c6f8aea5c697f3ec68f31b99fb16 Mon Sep 17 00:00:00 2001 From: dearblue Date: Sat, 18 Aug 2018 11:44:44 +0900 Subject: Use stack memory for small name of Struct members --- mrbgems/mruby-struct/src/struct.c | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/mrbgems/mruby-struct/src/struct.c b/mrbgems/mruby-struct/src/struct.c index 44822a03e..e1f64df55 100644 --- a/mrbgems/mruby-struct/src/struct.c +++ b/mrbgems/mruby-struct/src/struct.c @@ -123,18 +123,29 @@ mrb_struct_ref(mrb_state *mrb, mrb_value obj) static mrb_sym mrb_id_attrset(mrb_state *mrb, mrb_sym id) { +#define STACKED_ALLOC_MAX 32 +#define STACKED_STRING_MAX (STACKED_ALLOC_MAX - 1) /* '=' character */ + const char *name; char *buf; mrb_int len; mrb_sym mid; + char stacked[STACKED_ALLOC_MAX]; name = mrb_sym2name_len(mrb, id, &len); - buf = (char *)mrb_malloc(mrb, (size_t)len+1); + if (len > STACKED_STRING_MAX) { + buf = (char *)mrb_malloc(mrb, (size_t)len+1); + } + else { + buf = stacked; + } memcpy(buf, name, (size_t)len); buf[len] = '='; mid = mrb_intern(mrb, buf, len+1); - mrb_free(mrb, buf); + if (buf != stacked) { + mrb_free(mrb, buf); + } return mid; } -- cgit v1.2.3 From 758353902940e43530dbbbab0d9ce6ded5884923 Mon Sep 17 00:00:00 2001 From: dearblue Date: Sat, 22 Jun 2019 16:48:22 +0900 Subject: Fix potential overflow in `utf8len()` For example on 32 bit mode, when `p = 0xfffffffd`, `e = 0xfffffffe` and `len = 4`, the sum of `p` and `len` can be to `1`, and comparison with `e` will to be false. As a result, a segmentation fault occurs by referring to address 0. --- src/string.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/string.c b/src/string.c index bfe73b359..ed58c484b 100644 --- a/src/string.c +++ b/src/string.c @@ -234,7 +234,7 @@ utf8len(const char* p, const char* e) mrb_int i; len = utf8len_codepage[(unsigned char)*p]; - if (p + len > e) return 1; + if (len > e - p) return 1; for (i = 1; i < len; ++i) if ((p[i] & 0xc0) != 0x80) return 1; -- cgit v1.2.3 From 28de6b0da195e1ebf8f6ce30de462f44fb761b8b Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Sat, 22 Jun 2019 19:05:42 +0900 Subject: Refine `Hash#rehash` example [ci skip] Previous example doesn't work because string key (frozen) can't be modified. --- src/hash.c | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/src/hash.c b/src/hash.c index a9367a426..b4d96251c 100644 --- a/src/hash.c +++ b/src/hash.c @@ -1378,10 +1378,21 @@ mrb_hash_merge(mrb_state *mrb, mrb_value hash1, mrb_value hash2) * values of key objects have changed since they were inserted, this * method will reindex hsh. * - * h = {"AAA" => "b"} - * h.keys[0].chop! - * h.rehash #=> {"AA"=>"b"} - * h["AA"] #=> "b" + * keys = (1..17).map{|n| [n]} + * k = keys[0] + * h = {} + * keys.each{|key| h[key] = key[0]} + * h #=> { [1]=> 1, [2]=> 2, [3]=> 3, [4]=> 4, [5]=> 5, [6]=> 6, [7]=> 7, + * [8]=> 8, [9]=> 9,[10]=>10,[11]=>11,[12]=>12,[13]=>13,[14]=>14, + * [15]=>15,[16]=>16,[17]=>17} + * h[k] #=> 1 + * k[0] = keys.size + 1 + * h #=> {[18]=> 1, [2]=> 2, [3]=> 3, [4]=> 4, [5]=> 5, [6]=> 6, [7]=> 7, + * [8]=> 8, [9]=> 9,[10]=>10,[11]=>11,[12]=>12,[13]=>13,[14]=>14, + * [15]=>15,[16]=>16,[17]=>17} + * h[k] #=> nil + * h.rehash + * h[k] #=> 1 */ static mrb_value mrb_hash_rehash(mrb_state *mrb, mrb_value self) -- cgit v1.2.3 From 7c6d6effaea6ec3cbac01cffc4f094744d53d8b9 Mon Sep 17 00:00:00 2001 From: dearblue Date: Sat, 22 Jun 2019 16:30:36 +0900 Subject: Replacement to function for string reversing --- src/string.c | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/src/string.c b/src/string.c index bfe73b359..282f8d776 100644 --- a/src/string.c +++ b/src/string.c @@ -1671,6 +1671,18 @@ mrb_ptr_to_str(mrb_state *mrb, void *p) return mrb_obj_value(p_str); } +static inline void +str_reverse(char *p, char *e) +{ + char c; + + while (p < e) { + c = *p; + *p++ = *e; + *e-- = c; + } +} + /* 15.2.10.5.30 */ /* * call-seq: @@ -1714,17 +1726,12 @@ mrb_str_reverse_bang(mrb_state *mrb, mrb_value str) { struct RString *s = mrb_str_ptr(str); char *p, *e; - char c; mrb_str_modify(mrb, s); if (RSTR_LEN(s) > 1) { p = RSTR_PTR(s); e = p + RSTR_LEN(s) - 1; - while (p < e) { - c = *p; - *p++ = *e; - *e-- = c; - } + str_reverse(p, e); } return str; } -- cgit v1.2.3 From bd2c93c2dfbb944f57b10b7b9c056caf852a5053 Mon Sep 17 00:00:00 2001 From: dearblue Date: Sat, 22 Jun 2019 16:32:17 +0900 Subject: Change to UTF-8 string reversing with in place MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reverses UTF-8 strings without allocated heap for working memory. 1. String before reversing: ``` "!yburmの界世" # byte unit [33, 121, 98, 117, 114, 109, 227, 129, 174, 231, 149, 140, 228, 184, 150] ``` 2. Reverse the byte order of each character: ``` [33, 121, 98, 117, 114, 109, 174, 129, 227, 140, 149, 231, 150, 184, 228] ``` 3. Reverse the whole byte order and complete: ``` [228, 184, 150, 231, 149, 140, 227, 129, 174, 109, 114, 117, 98, 121, 33] # string "世界のmruby!" ``` --- src/string.c | 28 ++++++++-------------------- 1 file changed, 8 insertions(+), 20 deletions(-) diff --git a/src/string.c b/src/string.c index 282f8d776..6d01b773c 100644 --- a/src/string.c +++ b/src/string.c @@ -1693,40 +1693,28 @@ str_reverse(char *p, char *e) static mrb_value mrb_str_reverse_bang(mrb_state *mrb, mrb_value str) { + struct RString *s = mrb_str_ptr(str); + char *p, *e; + #ifdef MRB_UTF8_STRING mrb_int utf8_len = RSTRING_CHAR_LEN(str); - mrb_int len = RSTRING_LEN(str); + mrb_int len = RSTR_LEN(s); if (utf8_len == len) goto bytes; if (utf8_len > 1) { - char *buf; - char *p, *e, *r; - - mrb_str_modify(mrb, mrb_str_ptr(str)); - len = RSTRING_LEN(str); - buf = (char*)mrb_malloc(mrb, (size_t)len); - p = buf; - e = buf + len; - - memcpy(buf, RSTRING_PTR(str), len); - r = RSTRING_PTR(str) + len; - + mrb_str_modify(mrb, s); + p = RSTR_PTR(s); + e = p + RSTR_LEN(s); while (p 1) { p = RSTR_PTR(s); -- cgit v1.2.3 From 5af8a9777be82838b65c5b84bb2758f5395df998 Mon Sep 17 00:00:00 2001 From: dearblue Date: Sat, 22 Jun 2019 22:58:08 +0900 Subject: Add test for one UTF-8 charactor --- test/t/string.rb | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/test/t/string.rb b/test/t/string.rb index 9817dd188..7ef236dbe 100644 --- a/test/t/string.rb +++ b/test/t/string.rb @@ -479,6 +479,7 @@ assert('String#reverse(UTF-8)', '15.2.10.5.29') do assert_equal 'こんにちは世界!', a assert_equal '!界世はちにんこ', 'こんにちは世界!'.reverse + assert_equal 'あ', 'あ'.reverse end if UTF8STRING assert('String#reverse!', '15.2.10.5.30') do @@ -495,6 +496,10 @@ assert('String#reverse!(UTF-8)', '15.2.10.5.30') do assert_equal '!界世はちにんこ', a assert_equal '!界世はちにんこ', 'こんにちは世界!'.reverse! + + b = 'あ' + b.reverse! + assert_equal 'あ', b end if UTF8STRING assert('String#rindex', '15.2.10.5.31') do -- cgit v1.2.3 From 567075aab939dd262e816832195cb11594abade9 Mon Sep 17 00:00:00 2001 From: dearblue Date: Sat, 22 Jun 2019 22:58:18 +0900 Subject: Fix string brakes for one UTF-8 charactor --- src/string.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/string.c b/src/string.c index 6d01b773c..a35262eb4 100644 --- a/src/string.c +++ b/src/string.c @@ -1700,8 +1700,8 @@ mrb_str_reverse_bang(mrb_state *mrb, mrb_value str) mrb_int utf8_len = RSTRING_CHAR_LEN(str); mrb_int len = RSTR_LEN(s); - if (utf8_len == len) goto bytes; - if (utf8_len > 1) { + if (utf8_len < 2) return str; + if (utf8_len < len) { mrb_str_modify(mrb, s); p = RSTR_PTR(s); e = p + RSTR_LEN(s); @@ -1711,8 +1711,6 @@ mrb_str_reverse_bang(mrb_state *mrb, mrb_value str) p += clen; } } - - bytes: #endif { mrb_str_modify(mrb, s); -- cgit v1.2.3 From ec03e3f54af55af8c461a19b2f7cf0a984282997 Mon Sep 17 00:00:00 2001 From: dearblue Date: Sat, 22 Jun 2019 23:02:29 +0900 Subject: Delete the unnecessary block brace in `mrb_str_reverse_bang` --- src/string.c | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/src/string.c b/src/string.c index a35262eb4..2cfdc337e 100644 --- a/src/string.c +++ b/src/string.c @@ -1712,15 +1712,14 @@ mrb_str_reverse_bang(mrb_state *mrb, mrb_value str) } } #endif - { - mrb_str_modify(mrb, s); - if (RSTR_LEN(s) > 1) { - p = RSTR_PTR(s); - e = p + RSTR_LEN(s) - 1; - str_reverse(p, e); - } - return str; + + mrb_str_modify(mrb, s); + if (RSTR_LEN(s) > 1) { + p = RSTR_PTR(s); + e = p + RSTR_LEN(s) - 1; + str_reverse(p, e); } + return str; } /* ---------------------------------- */ -- cgit v1.2.3 From 11e09dc5dbd6ddaabf145bbee62741f4191eca79 Mon Sep 17 00:00:00 2001 From: dearblue Date: Sat, 22 Jun 2019 23:09:36 +0900 Subject: Fix the unnecessary `mrb_str_modify()` call Now to be calls `mrb_str_modify()` only once when 2 or more characters. --- src/string.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/string.c b/src/string.c index 2cfdc337e..2d9d176d4 100644 --- a/src/string.c +++ b/src/string.c @@ -1710,11 +1710,13 @@ mrb_str_reverse_bang(mrb_state *mrb, mrb_value str) str_reverse(p, p + clen - 1); p += clen; } + goto bytes; } #endif - mrb_str_modify(mrb, s); if (RSTR_LEN(s) > 1) { + mrb_str_modify(mrb, s); + bytes: p = RSTR_PTR(s); e = p + RSTR_LEN(s) - 1; str_reverse(p, e); -- cgit v1.2.3 From 1fd08aee15942c3b3e3133f8cc92d4025df024a8 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Sun, 23 Jun 2019 20:01:33 +0900 Subject: Fix argument specs to `Array` --- mrbgems/mruby-array-ext/src/array.c | 2 +- src/array.c | 58 ++++++++++++++++++------------------- 2 files changed, 30 insertions(+), 30 deletions(-) diff --git a/mrbgems/mruby-array-ext/src/array.c b/mrbgems/mruby-array-ext/src/array.c index 20c771a97..cb4798d49 100644 --- a/mrbgems/mruby-array-ext/src/array.c +++ b/mrbgems/mruby-array-ext/src/array.c @@ -194,7 +194,7 @@ mrb_mruby_array_ext_gem_init(mrb_state* mrb) mrb_define_method(mrb, a, "at", mrb_ary_at, MRB_ARGS_REQ(1)); mrb_define_method(mrb, a, "rassoc", mrb_ary_rassoc, MRB_ARGS_REQ(1)); mrb_define_method(mrb, a, "values_at", mrb_ary_values_at, MRB_ARGS_ANY()); - mrb_define_method(mrb, a, "slice!", mrb_ary_slice_bang, MRB_ARGS_ANY()); + mrb_define_method(mrb, a, "slice!", mrb_ary_slice_bang, MRB_ARGS_ARG(1,1)); } void diff --git a/src/array.c b/src/array.c index bd9b4d358..8cf813743 100644 --- a/src/array.c +++ b/src/array.c @@ -1262,39 +1262,39 @@ mrb_init_array(mrb_state *mrb) { struct RClass *a; - mrb->array_class = a = mrb_define_class(mrb, "Array", mrb->object_class); /* 15.2.12 */ + mrb->array_class = a = mrb_define_class(mrb, "Array", mrb->object_class); /* 15.2.12 */ MRB_SET_INSTANCE_TT(a, MRB_TT_ARRAY); - mrb_define_class_method(mrb, a, "[]", mrb_ary_s_create, MRB_ARGS_ANY()); /* 15.2.12.4.1 */ - - mrb_define_method(mrb, a, "+", mrb_ary_plus, MRB_ARGS_REQ(1)); /* 15.2.12.5.1 */ - mrb_define_method(mrb, a, "*", mrb_ary_times, MRB_ARGS_REQ(1)); /* 15.2.12.5.2 */ - mrb_define_method(mrb, a, "<<", mrb_ary_push_m, MRB_ARGS_REQ(1)); /* 15.2.12.5.3 */ - mrb_define_method(mrb, a, "[]", mrb_ary_aget, MRB_ARGS_ANY()); /* 15.2.12.5.4 */ - mrb_define_method(mrb, a, "[]=", mrb_ary_aset, MRB_ARGS_ANY()); /* 15.2.12.5.5 */ - mrb_define_method(mrb, a, "clear", mrb_ary_clear_m, MRB_ARGS_NONE()); /* 15.2.12.5.6 */ - mrb_define_method(mrb, a, "concat", mrb_ary_concat_m, MRB_ARGS_REQ(1)); /* 15.2.12.5.8 */ - mrb_define_method(mrb, a, "delete_at", mrb_ary_delete_at, MRB_ARGS_REQ(1)); /* 15.2.12.5.9 */ - mrb_define_method(mrb, a, "empty?", mrb_ary_empty_p, MRB_ARGS_NONE()); /* 15.2.12.5.12 */ - mrb_define_method(mrb, a, "first", mrb_ary_first, MRB_ARGS_OPT(1)); /* 15.2.12.5.13 */ - mrb_define_method(mrb, a, "index", mrb_ary_index_m, MRB_ARGS_REQ(1)); /* 15.2.12.5.14 */ - mrb_define_method(mrb, a, "initialize_copy", mrb_ary_replace_m, MRB_ARGS_REQ(1)); /* 15.2.12.5.16 */ - mrb_define_method(mrb, a, "join", mrb_ary_join_m, MRB_ARGS_ANY()); /* 15.2.12.5.17 */ - mrb_define_method(mrb, a, "last", mrb_ary_last, MRB_ARGS_ANY()); /* 15.2.12.5.18 */ - mrb_define_method(mrb, a, "length", mrb_ary_size, MRB_ARGS_NONE()); /* 15.2.12.5.19 */ - mrb_define_method(mrb, a, "pop", mrb_ary_pop, MRB_ARGS_NONE()); /* 15.2.12.5.21 */ - mrb_define_method(mrb, a, "push", mrb_ary_push_m, MRB_ARGS_ANY()); /* 15.2.12.5.22 */ - mrb_define_method(mrb, a, "replace", mrb_ary_replace_m, MRB_ARGS_REQ(1)); /* 15.2.12.5.23 */ - mrb_define_method(mrb, a, "reverse", mrb_ary_reverse, MRB_ARGS_NONE()); /* 15.2.12.5.24 */ - mrb_define_method(mrb, a, "reverse!", mrb_ary_reverse_bang, MRB_ARGS_NONE()); /* 15.2.12.5.25 */ - mrb_define_method(mrb, a, "rindex", mrb_ary_rindex_m, MRB_ARGS_REQ(1)); /* 15.2.12.5.26 */ - mrb_define_method(mrb, a, "shift", mrb_ary_shift, MRB_ARGS_NONE()); /* 15.2.12.5.27 */ - mrb_define_method(mrb, a, "size", mrb_ary_size, MRB_ARGS_NONE()); /* 15.2.12.5.28 */ - mrb_define_method(mrb, a, "slice", mrb_ary_aget, MRB_ARGS_ANY()); /* 15.2.12.5.29 */ - mrb_define_method(mrb, a, "unshift", mrb_ary_unshift_m, MRB_ARGS_ANY()); /* 15.2.12.5.30 */ + mrb_define_class_method(mrb, a, "[]", mrb_ary_s_create, MRB_ARGS_ANY()); /* 15.2.12.4.1 */ + + mrb_define_method(mrb, a, "+", mrb_ary_plus, MRB_ARGS_REQ(1)); /* 15.2.12.5.1 */ + mrb_define_method(mrb, a, "*", mrb_ary_times, MRB_ARGS_REQ(1)); /* 15.2.12.5.2 */ + mrb_define_method(mrb, a, "<<", mrb_ary_push_m, MRB_ARGS_REQ(1)); /* 15.2.12.5.3 */ + mrb_define_method(mrb, a, "[]", mrb_ary_aget, MRB_ARGS_ARG(1,1)); /* 15.2.12.5.4 */ + mrb_define_method(mrb, a, "[]=", mrb_ary_aset, MRB_ARGS_ARG(2,1)); /* 15.2.12.5.5 */ + mrb_define_method(mrb, a, "clear", mrb_ary_clear_m, MRB_ARGS_NONE()); /* 15.2.12.5.6 */ + mrb_define_method(mrb, a, "concat", mrb_ary_concat_m, MRB_ARGS_REQ(1)); /* 15.2.12.5.8 */ + mrb_define_method(mrb, a, "delete_at", mrb_ary_delete_at, MRB_ARGS_REQ(1)); /* 15.2.12.5.9 */ + mrb_define_method(mrb, a, "empty?", mrb_ary_empty_p, MRB_ARGS_NONE()); /* 15.2.12.5.12 */ + mrb_define_method(mrb, a, "first", mrb_ary_first, MRB_ARGS_OPT(1)); /* 15.2.12.5.13 */ + mrb_define_method(mrb, a, "index", mrb_ary_index_m, MRB_ARGS_REQ(1)); /* 15.2.12.5.14 */ + mrb_define_method(mrb, a, "initialize_copy", mrb_ary_replace_m, MRB_ARGS_REQ(1)); /* 15.2.12.5.16 */ + mrb_define_method(mrb, a, "join", mrb_ary_join_m, MRB_ARGS_OPT(1)); /* 15.2.12.5.17 */ + mrb_define_method(mrb, a, "last", mrb_ary_last, MRB_ARGS_OPT(1)); /* 15.2.12.5.18 */ + mrb_define_method(mrb, a, "length", mrb_ary_size, MRB_ARGS_NONE()); /* 15.2.12.5.19 */ + mrb_define_method(mrb, a, "pop", mrb_ary_pop, MRB_ARGS_NONE()); /* 15.2.12.5.21 */ + mrb_define_method(mrb, a, "push", mrb_ary_push_m, MRB_ARGS_ANY()); /* 15.2.12.5.22 */ + mrb_define_method(mrb, a, "replace", mrb_ary_replace_m, MRB_ARGS_REQ(1)); /* 15.2.12.5.23 */ + mrb_define_method(mrb, a, "reverse", mrb_ary_reverse, MRB_ARGS_NONE()); /* 15.2.12.5.24 */ + mrb_define_method(mrb, a, "reverse!", mrb_ary_reverse_bang, MRB_ARGS_NONE()); /* 15.2.12.5.25 */ + mrb_define_method(mrb, a, "rindex", mrb_ary_rindex_m, MRB_ARGS_REQ(1)); /* 15.2.12.5.26 */ + mrb_define_method(mrb, a, "shift", mrb_ary_shift, MRB_ARGS_NONE()); /* 15.2.12.5.27 */ + mrb_define_method(mrb, a, "size", mrb_ary_size, MRB_ARGS_NONE()); /* 15.2.12.5.28 */ + mrb_define_method(mrb, a, "slice", mrb_ary_aget, MRB_ARGS_ARG(1,1)); /* 15.2.12.5.29 */ + mrb_define_method(mrb, a, "unshift", mrb_ary_unshift_m, MRB_ARGS_ANY()); /* 15.2.12.5.30 */ mrb_define_method(mrb, a, "__ary_eq", mrb_ary_eq, MRB_ARGS_REQ(1)); mrb_define_method(mrb, a, "__ary_cmp", mrb_ary_cmp, MRB_ARGS_REQ(1)); - mrb_define_method(mrb, a, "__ary_index", mrb_ary_index_m, MRB_ARGS_REQ(1)); /* kept for mruby-array-ext */ + mrb_define_method(mrb, a, "__ary_index", mrb_ary_index_m, MRB_ARGS_REQ(1)); /* kept for mruby-array-ext */ mrb_define_method(mrb, a, "__svalue", mrb_ary_svalue, MRB_ARGS_NONE()); } -- cgit v1.2.3 From f71270df7736e9cd53845c45d1eb369227c853ea Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Mon, 24 Jun 2019 18:55:05 +0900 Subject: Compare obj pointer directly instead of using mrb_obj_eq in mrb_gc_unregister Because immediate values are not registered. --- src/gc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gc.c b/src/gc.c index 94068c0f9..b05d929a1 100644 --- a/src/gc.c +++ b/src/gc.c @@ -506,7 +506,7 @@ mrb_gc_unregister(mrb_state *mrb, mrb_value obj) a = mrb_ary_ptr(table); mrb_ary_modify(mrb, a); for (i = 0; i < ARY_LEN(a); i++) { - if (mrb_obj_eq(mrb, ARY_PTR(a)[i], obj)) { + if (mrb_ptr(ARY_PTR(a)[i]) == mrb_ptr(obj)) { mrb_int len = ARY_LEN(a)-1; mrb_value *ptr = ARY_PTR(a); -- cgit v1.2.3 From ace0c76a69600816e583adac3a37df8cb4bb75ff Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Tue, 25 Jun 2019 18:05:03 +0900 Subject: Renamed `stacked` to `onstack`; ref #4523 --- mrbgems/mruby-struct/src/struct.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/mrbgems/mruby-struct/src/struct.c b/mrbgems/mruby-struct/src/struct.c index e1f64df55..e04fe13ad 100644 --- a/mrbgems/mruby-struct/src/struct.c +++ b/mrbgems/mruby-struct/src/struct.c @@ -123,27 +123,27 @@ mrb_struct_ref(mrb_state *mrb, mrb_value obj) static mrb_sym mrb_id_attrset(mrb_state *mrb, mrb_sym id) { -#define STACKED_ALLOC_MAX 32 -#define STACKED_STRING_MAX (STACKED_ALLOC_MAX - 1) /* '=' character */ +#define ONSTACK_ALLOC_MAX 32 +#define ONSTACK_STRLEN_MAX (ONSTACK_ALLOC_MAX - 1) /* '=' character */ const char *name; char *buf; mrb_int len; mrb_sym mid; - char stacked[STACKED_ALLOC_MAX]; + char onstack[ONSTACK_ALLOC_MAX]; name = mrb_sym2name_len(mrb, id, &len); - if (len > STACKED_STRING_MAX) { + if (len > ONSTACK_STRLEN_MAX) { buf = (char *)mrb_malloc(mrb, (size_t)len+1); } else { - buf = stacked; + buf = onstack; } memcpy(buf, name, (size_t)len); buf[len] = '='; mid = mrb_intern(mrb, buf, len+1); - if (buf != stacked) { + if (buf != onstack) { mrb_free(mrb, buf); } return mid; -- cgit v1.2.3 From dc21024ec795bcfcd3018825fa3c272731439a7e Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Tue, 25 Jun 2019 18:05:33 +0900 Subject: Fix `mrb_str_to_str()` to handle symbols. --- src/string.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/string.c b/src/string.c index ed58c484b..856e908af 100644 --- a/src/string.c +++ b/src/string.c @@ -973,6 +973,8 @@ mrb_str_to_str(mrb_state *mrb, mrb_value str) switch (mrb_type(str)) { case MRB_TT_STRING: return str; + case MRB_TT_SYMBOL: + return mrb_sym2str(mrb, mrb_symbol(str)); case MRB_TT_FIXNUM: return mrb_fixnum_to_str(mrb, str, 10); case MRB_TT_CLASS: -- cgit v1.2.3 From 6724416d5c6289a1e7bd8e0fd0be7d86b6166f93 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Tue, 25 Jun 2019 18:06:39 +0900 Subject: Fixed a bug caused by `to_s` that returns `nil`; fix 4504 --- mrbgems/mruby-method/src/method.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/mrbgems/mruby-method/src/method.c b/mrbgems/mruby-method/src/method.c index 9f1134227..d94db1cb2 100644 --- a/mrbgems/mruby-method/src/method.c +++ b/mrbgems/mruby-method/src/method.c @@ -270,16 +270,16 @@ method_to_s(mrb_state *mrb, mrb_value self) mrb_str_cat_lit(mrb, str, ": "); rklass = mrb_class_ptr(klass); if (mrb_class_ptr(owner) == rklass) { - mrb_str_cat_str(mrb, str, mrb_funcall(mrb, owner, "to_s", 0)); + mrb_str_cat_str(mrb, str, mrb_str_to_str(mrb, owner)); mrb_str_cat_lit(mrb, str, "#"); - mrb_str_cat_str(mrb, str, mrb_funcall(mrb, name, "to_s", 0)); + mrb_str_cat_str(mrb, str, mrb_str_to_str(mrb, name)); } else { mrb_str_cat_cstr(mrb, str, mrb_class_name(mrb, rklass)); mrb_str_cat_lit(mrb, str, "("); - mrb_str_cat_str(mrb, str, mrb_funcall(mrb, owner, "to_s", 0)); + mrb_str_cat_str(mrb, str, mrb_str_to_str(mrb, owner)); mrb_str_cat_lit(mrb, str, ")#"); - mrb_str_cat_str(mrb, str, mrb_funcall(mrb, name, "to_s", 0)); + mrb_str_cat_str(mrb, str, mrb_str_to_str(mrb, name)); } mrb_str_cat_lit(mrb, str, ">"); return str; -- cgit v1.2.3 From 63d8b5e1e32cbbeb2368b06b3efa7723bf0677d2 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Tue, 25 Jun 2019 18:41:17 +0900 Subject: Fixed `mrb_iv_remove` with immediate objects; fix #4519 The #4520 tried to address the issue, but it changes the type of `mrb_check_frozen` argument; close #4520 --- src/variable.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/variable.c b/src/variable.c index 23d900b7d..e6f2f397e 100644 --- a/src/variable.c +++ b/src/variable.c @@ -521,11 +521,11 @@ mrb_obj_iv_inspect(mrb_state *mrb, struct RObject *obj) MRB_API mrb_value mrb_iv_remove(mrb_state *mrb, mrb_value obj, mrb_sym sym) { - mrb_check_frozen(mrb, mrb_obj_ptr(obj)); if (obj_iv_p(obj)) { iv_tbl *t = mrb_obj_ptr(obj)->iv; mrb_value val; + mrb_check_frozen(mrb, mrb_obj_ptr(obj)); if (iv_del(mrb, t, sym, &val)) { return val; } -- cgit v1.2.3 From 75df13a97334c162b2cf743c3e37c4933a4b0d1c Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Tue, 25 Jun 2019 22:58:21 +0900 Subject: Fix `String#byteslice` with `MRB_UTF8_STRING` and some edge cases MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Example: $ bin/mruby -e ' p "あa".byteslice(1) p "bar".byteslice(3) p "bar".byteslice(4..0) ' Before this patch: "a" "" RangeError (4..0 out of range) After this patch (same as Ruby): "\x81" nil nil --- include/mruby/string.h | 3 ++ mrbgems/mruby-string-ext/src/string.c | 58 +++++++++++++-------------------- mrbgems/mruby-string-ext/test/string.rb | 51 +++++++++++++++++++++++++++++ src/string.c | 49 ++++++++++++++-------------- 4 files changed, 102 insertions(+), 59 deletions(-) diff --git a/include/mruby/string.h b/include/mruby/string.h index 22445f654..b563541cb 100644 --- a/include/mruby/string.h +++ b/include/mruby/string.h @@ -438,6 +438,9 @@ mrb_value mrb_str_inspect(mrb_state *mrb, mrb_value str); #define mrb_str_buf_cat(mrb, str, ptr, len) mrb_str_cat(mrb, str, ptr, len) #define mrb_str_buf_append(mrb, str, str2) mrb_str_cat_str(mrb, str, str2) +mrb_bool mrb_str_beg_len(mrb_int str_len, mrb_int *begp, mrb_int *lenp); +mrb_value mrb_str_byte_subseq(mrb_state *mrb, mrb_value str, mrb_int beg, mrb_int len); + #ifdef MRB_UTF8_STRING mrb_int mrb_utf8_len(const char *str, mrb_int byte_len); #endif diff --git a/mrbgems/mruby-string-ext/src/string.c b/mrbgems/mruby-string-ext/src/string.c index d9ebb7392..50a4e5582 100644 --- a/mrbgems/mruby-string-ext/src/string.c +++ b/mrbgems/mruby-string-ext/src/string.c @@ -42,44 +42,32 @@ mrb_str_setbyte(mrb_state *mrb, mrb_value str) static mrb_value mrb_str_byteslice(mrb_state *mrb, mrb_value str) { - mrb_value a1; - mrb_int len; - - if (mrb_get_argc(mrb) == 2) { - mrb_int pos; - mrb_get_args(mrb, "ii", &pos, &len); - return mrb_str_substr(mrb, str, pos, len); + mrb_value a1, a2; + mrb_int str_len = RSTRING_LEN(str), beg, len; + mrb_bool empty = TRUE; + + if (mrb_get_args(mrb, "o|o", &a1, &a2) == 2) { + beg = mrb_fixnum(mrb_to_int(mrb, a1)); + len = mrb_fixnum(mrb_to_int(mrb, a2)); + goto subseq; } - mrb_get_args(mrb, "o|i", &a1, &len); - switch (mrb_type(a1)) { - case MRB_TT_RANGE: - { - mrb_int beg; - - len = RSTRING_LEN(str); - switch (mrb_range_beg_len(mrb, a1, &beg, &len, len, TRUE)) { - case MRB_RANGE_TYPE_MISMATCH: - break; - case MRB_RANGE_OK: - return mrb_str_substr(mrb, str, beg, len); - case MRB_RANGE_OUT: - mrb_raisef(mrb, E_RANGE_ERROR, "%S out of range", a1); - break; - } - return mrb_nil_value(); + if (mrb_type(a1) == MRB_TT_RANGE) { + if (mrb_range_beg_len(mrb, a1, &beg, &len, str_len, TRUE) == MRB_RANGE_OK) { + goto subseq; } -#ifndef MRB_WITHOUT_FLOAT - case MRB_TT_FLOAT: - a1 = mrb_fixnum_value((mrb_int)mrb_float(a1)); - /* fall through */ -#endif - case MRB_TT_FIXNUM: - return mrb_str_substr(mrb, str, mrb_fixnum(a1), 1); - default: - mrb_raise(mrb, E_TYPE_ERROR, "wrong type of argument"); + return mrb_nil_value(); + } + + beg = mrb_fixnum(mrb_to_int(mrb, a1)); + len = 1; + empty = FALSE; +subseq: + if (mrb_str_beg_len(str_len, &beg, &len) && (empty || len != 0)) { + return mrb_str_byte_subseq(mrb, str, beg, len); + } + else { + return mrb_nil_value(); } - /* not reached */ - return mrb_nil_value(); } /* diff --git a/mrbgems/mruby-string-ext/test/string.rb b/mrbgems/mruby-string-ext/test/string.rb index 02777e594..bf633bcef 100644 --- a/mrbgems/mruby-string-ext/test/string.rb +++ b/mrbgems/mruby-string-ext/test/string.rb @@ -26,10 +26,61 @@ end assert('String#byteslice') do str1 = "hello" + str2 = "\u3042ab" # "\xE3\x81\x82ab" + + assert_equal("h", str1.byteslice(0)) assert_equal("e", str1.byteslice(1)) + assert_equal(nil, str1.byteslice(5)) assert_equal("o", str1.byteslice(-1)) + assert_equal(nil, str1.byteslice(-6)) + assert_equal("\xE3", str2.byteslice(0)) + assert_equal("\x81", str2.byteslice(1)) + assert_equal(nil, str2.byteslice(5)) + assert_equal("b", str2.byteslice(-1)) + assert_equal(nil, str2.byteslice(-6)) + + assert_equal("", str1.byteslice(0, 0)) + assert_equal(str1, str1.byteslice(0, 6)) + assert_equal("el", str1.byteslice(1, 2)) + assert_equal("", str1.byteslice(5, 1)) + assert_equal("o", str1.byteslice(-1, 6)) + assert_equal(nil, str1.byteslice(-6, 1)) + assert_equal(nil, str1.byteslice(0, -1)) + assert_equal("", str2.byteslice(0, 0)) + assert_equal(str2, str2.byteslice(0, 6)) + assert_equal("\x81\x82", str2.byteslice(1, 2)) + assert_equal("", str2.byteslice(5, 1)) + assert_equal("b", str2.byteslice(-1, 6)) + assert_equal(nil, str2.byteslice(-6, 1)) + assert_equal(nil, str2.byteslice(0, -1)) + assert_equal("ell", str1.byteslice(1..3)) assert_equal("el", str1.byteslice(1...3)) + assert_equal("h", str1.byteslice(0..0)) + assert_equal("", str1.byteslice(5..0)) + assert_equal("o", str1.byteslice(4..5)) + assert_equal(nil, str1.byteslice(6..0)) + assert_equal("", str1.byteslice(-1..0)) + assert_equal("llo", str1.byteslice(-3..5)) + assert_equal("\x81\x82a", str2.byteslice(1..3)) + assert_equal("\x81\x82", str2.byteslice(1...3)) + assert_equal("\xE3", str2.byteslice(0..0)) + assert_equal("", str2.byteslice(5..0)) + assert_equal("b", str2.byteslice(4..5)) + assert_equal(nil, str2.byteslice(6..0)) + assert_equal("", str2.byteslice(-1..0)) + assert_equal("\x82ab", str2.byteslice(-3..5)) + + assert_raise(ArgumentError) { str1.byteslice } + assert_raise(ArgumentError) { str1.byteslice(1, 2, 3) } + assert_raise(TypeError) { str1.byteslice("1") } + assert_raise(TypeError) { str1.byteslice("1", 2) } + assert_raise(TypeError) { str1.byteslice(1, "2") } + assert_raise(TypeError) { str1.byteslice(1..2, 3) } + + skip unless Object.const_defined?(:Float) + assert_equal("o", str1.byteslice(4.0)) + assert_equal("\x82ab", str2.byteslice(2.0, 3.0)) end assert('String#dump') do diff --git a/src/string.c b/src/string.c index ed58c484b..f5fb936a6 100644 --- a/src/string.c +++ b/src/string.c @@ -410,8 +410,8 @@ str_make_shared(mrb_state *mrb, struct RString *orig, struct RString *s) } } -static mrb_value -byte_subseq(mrb_state *mrb, mrb_value str, mrb_int beg, mrb_int len) +mrb_value +mrb_str_byte_subseq(mrb_state *mrb, mrb_value str, mrb_int beg, mrb_int len) { struct RString *orig, *s; @@ -434,32 +434,33 @@ str_subseq(mrb_state *mrb, mrb_value str, mrb_int beg, mrb_int len) beg = chars2bytes(str, 0, beg); len = chars2bytes(str, beg, len); - return byte_subseq(mrb, str, beg, len); + return mrb_str_byte_subseq(mrb, str, beg, len); } #else -#define str_subseq(mrb, str, beg, len) byte_subseq(mrb, str, beg, len) +#define str_subseq(mrb, str, beg, len) mrb_str_byte_subseq(mrb, str, beg, len) #endif -static mrb_value -str_substr(mrb_state *mrb, mrb_value str, mrb_int beg, mrb_int len) +mrb_bool +mrb_str_beg_len(mrb_int str_len, mrb_int *begp, mrb_int *lenp) { - mrb_int clen = RSTRING_CHAR_LEN(str); - - if (len < 0) return mrb_nil_value(); - if (clen == 0) { - len = 0; + if (str_len < *begp || *lenp < 0) return FALSE; + if (*begp < 0) { + *begp += str_len; + if (*begp < 0) return FALSE; } - if (beg > clen) return mrb_nil_value(); - if (beg < 0) { - beg += clen; - if (beg < 0) return mrb_nil_value(); + if (*lenp > str_len - *begp) + *lenp = str_len - *begp; + if (*lenp <= 0) { + *lenp = 0; } - if (len > clen - beg) - len = clen - beg; - if (len <= 0) { - len = 0; - } - return str_subseq(mrb, str, beg, len); + return TRUE; +} + +static mrb_value +str_substr(mrb_state *mrb, mrb_value str, mrb_int beg, mrb_int len) +{ + return mrb_str_beg_len(RSTRING_CHAR_LEN(str), &beg, &len) ? + str_subseq(mrb, str, beg, len) : mrb_nil_value(); } MRB_API mrb_int @@ -1917,7 +1918,7 @@ mrb_str_split_m(mrb_state *mrb, mrb_value str) } } else if (ISSPACE(c)) { - mrb_ary_push(mrb, result, byte_subseq(mrb, str, beg, end-beg)); + mrb_ary_push(mrb, result, mrb_str_byte_subseq(mrb, str, beg, end-beg)); mrb_gc_arena_restore(mrb, ai); skip = TRUE; beg = idx; @@ -1942,7 +1943,7 @@ mrb_str_split_m(mrb_state *mrb, mrb_value str) else { end = chars2bytes(str, idx, 1); } - mrb_ary_push(mrb, result, byte_subseq(mrb, str, idx, end)); + mrb_ary_push(mrb, result, mrb_str_byte_subseq(mrb, str, idx, end)); mrb_gc_arena_restore(mrb, ai); idx += end + pat_len; if (lim_p && lim <= ++i) break; @@ -1954,7 +1955,7 @@ mrb_str_split_m(mrb_state *mrb, mrb_value str) tmp = mrb_str_new_empty(mrb, str); } else { - tmp = byte_subseq(mrb, str, beg, RSTRING_LEN(str)-beg); + tmp = mrb_str_byte_subseq(mrb, str, beg, RSTRING_LEN(str)-beg); } mrb_ary_push(mrb, result, tmp); } -- cgit v1.2.3 From 28c510cf41767ee40dbea9b0b1f165a28da956d1 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Wed, 26 Jun 2019 15:38:20 +0900 Subject: Silence unused label warnings from gcc; ref #4524 mruby/mruby/src/string.c:1722:4: warning: label 'bytes' defined but not used [-Wunused-label] bytes: ^~~~~ --- src/string.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/string.c b/src/string.c index b980ee760..c8a9e61ec 100644 --- a/src/string.c +++ b/src/string.c @@ -1719,12 +1719,15 @@ mrb_str_reverse_bang(mrb_state *mrb, mrb_value str) if (RSTR_LEN(s) > 1) { mrb_str_modify(mrb, s); - bytes: - p = RSTR_PTR(s); - e = p + RSTR_LEN(s) - 1; - str_reverse(p, e); + goto bytes; } return str; + + bytes: + p = RSTR_PTR(s); + e = p + RSTR_LEN(s) - 1; + str_reverse(p, e); + return str; } /* ---------------------------------- */ -- cgit v1.2.3 From 23783a44300a39efbbc312a6ca22fe61d94db857 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Thu, 27 Jun 2019 09:34:40 +0900 Subject: Skip copying delete keys in a hash; fix #4534 --- src/hash.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/hash.c b/src/hash.c index b4d96251c..ac6a7cd56 100644 --- a/src/hash.c +++ b/src/hash.c @@ -240,7 +240,7 @@ ht_compact(mrb_state *mrb, htable *t) if (!seg->next && i >= t->last_len) { goto exit; } - if (mrb_undef_p(k)) { /* found delete key */ + if (mrb_undef_p(k)) { /* found deleted key */ if (seg2 == NULL) { seg2 = seg; i2 = i; @@ -543,6 +543,7 @@ ht_copy(mrb_state *mrb, htable *t) mrb_value key = seg->e[i].key; mrb_value val = seg->e[i].val; + if (mrb_undef_p(key)) continue; /* skip deleted key */ if ((seg->next == NULL) && (i >= t->last_len)) { return t2; } -- cgit v1.2.3 From ad8473bd66c0dd622146e226f281909248b47305 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Thu, 27 Jun 2019 18:47:48 +0900 Subject: Add modification tests for immediate value --- mrbgems/mruby-metaprog/test/metaprog.rb | 4 ++++ test/t/kernel.rb | 1 + 2 files changed, 5 insertions(+) diff --git a/mrbgems/mruby-metaprog/test/metaprog.rb b/mrbgems/mruby-metaprog/test/metaprog.rb index 1e1d4ff26..30b75bd60 100644 --- a/mrbgems/mruby-metaprog/test/metaprog.rb +++ b/mrbgems/mruby-metaprog/test/metaprog.rb @@ -44,6 +44,8 @@ assert('Kernel#instance_variable_set', '15.3.1.3.22') do %w[@6 @% @@a @ a].each do |n| assert_raise(NameError) { o.instance_variable_set(n, 1) } end + assert_raise(FrozenError) { o.freeze.instance_variable_set(:@a, 2) } + assert_raise(FrozenError, ArgumentError) { nil.instance_variable_set(:@a, 2) } end assert('Kernel#instance_variables', '15.3.1.3.23') do @@ -121,6 +123,8 @@ assert('Kernel#define_singleton_method') do end assert_equal :test_method, ret assert_equal :singleton_method_ok, o.test_method + assert_raise(TypeError) { 2.define_singleton_method(:f){} } + assert_raise(FrozenError) { [].freeze.define_singleton_method(:f){} } end assert('Kernel#singleton_class') do diff --git a/test/t/kernel.rb b/test/t/kernel.rb index 103660f53..1e48069f2 100644 --- a/test/t/kernel.rb +++ b/test/t/kernel.rb @@ -419,6 +419,7 @@ assert('Kernel#remove_instance_variable', '15.3.1.3.41') do assert_raise(NameError) { tri.remove } assert_raise(NameError) { tri.remove_instance_variable(:var) } assert_raise(FrozenError) { tri.freeze.remove } + assert_raise(FrozenError, NameError) { :a.remove_instance_variable(:@v) } end # Kernel#require is defined in mruby-require. '15.3.1.3.42' -- cgit v1.2.3 From 5727d3a30cd9fd39103e06186c12058cb8d3407b Mon Sep 17 00:00:00 2001 From: Yasuhiro Horimoto Date: Thu, 27 Jun 2019 22:31:25 +0900 Subject: Fix broken links for mruby.org A part of a fix for issue mruby/mruby.github.io#50 --- README.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 2acc8de1a..863560ebc 100644 --- a/README.md +++ b/README.md @@ -38,7 +38,7 @@ We don't have a mailing list, but you can use [GitHub issues](https://github.com ## How to compile and install (mruby and gems) -See the [doc/guides/compile.md](doc/guides/compile.md) file. +See the [compile.md](https://github.com/mruby/mruby/blob/master/doc/guides/compile.md) file. ## Running Tests @@ -54,12 +54,12 @@ Or mruby contains a package manager called *mrbgems*. To create extensions in C and/or Ruby you should create a *GEM*. For a documentation of how to -use mrbgems consult the file [doc/guides/mrbgems.md](doc/guides/mrbgems.md). For example code of -how to use mrbgems look into the folder *examples/mrbgems/*. +use mrbgems consult the file [mrbgems.md](https://github.com/mruby/mruby/blob/master/doc/guides/mrbgems.md). +For example code of how to use mrbgems look into the folder *examples/mrbgems/*. ## License -mruby is released under the [MIT License](LICENSE). +mruby is released under the [MIT License](https://github.com/mruby/mruby/blob/master/LICENSE). ## Note for License @@ -88,5 +88,5 @@ file in your pull request. [ISO-standard]: http://www.iso.org/iso/iso_catalogue/catalogue_tc/catalogue_detail.htm?csnumber=59579 [build-status-img]: https://travis-ci.org/mruby/mruby.svg?branch=master -[contribution-guidelines]: CONTRIBUTING.md +[contribution-guidelines]: https://github.com/mruby/mruby/blob/master/CONTRIBUTING.md [travis-ci]: https://travis-ci.org/mruby/mruby -- cgit v1.2.3 From bc3176da630e3e055d58aa065ff897aec66df280 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Fri, 28 Jun 2019 19:26:29 +0900 Subject: Use `__ENCODING__` in tests It cannot be used for `String#size` test if judging whether or not `MRB_UTF8_STRING` is defined by result of `String#size`. --- mrbgems/mruby-string-ext/test/string.rb | 2 +- mrbgems/mruby-symbol-ext/test/symbol.rb | 2 +- test/t/string.rb | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/mrbgems/mruby-string-ext/test/string.rb b/mrbgems/mruby-string-ext/test/string.rb index bf633bcef..9a324c46d 100644 --- a/mrbgems/mruby-string-ext/test/string.rb +++ b/mrbgems/mruby-string-ext/test/string.rb @@ -2,7 +2,7 @@ ## # String(Ext) Test -UTF8STRING = ("\343\201\202".size == 1) +UTF8STRING = __ENCODING__ == "UTF-8" assert('String#getbyte') do str1 = "hello" diff --git a/mrbgems/mruby-symbol-ext/test/symbol.rb b/mrbgems/mruby-symbol-ext/test/symbol.rb index 61ecad247..db686e5f4 100644 --- a/mrbgems/mruby-symbol-ext/test/symbol.rb +++ b/mrbgems/mruby-symbol-ext/test/symbol.rb @@ -14,7 +14,7 @@ end assert("Symbol##{n}") do assert_equal 5, :hello.__send__(n) assert_equal 4, :"aA\0b".__send__(n) - if "あ".size == 1 # enable MRB_UTF8_STRING? + if __ENCODING__ == "UTF-8" assert_equal 8, :"こんにちは世界!".__send__(n) assert_equal 4, :"aあ\0b".__send__(n) else diff --git a/test/t/string.rb b/test/t/string.rb index 7ef236dbe..81699f17e 100644 --- a/test/t/string.rb +++ b/test/t/string.rb @@ -2,7 +2,7 @@ ## # String ISO Test -UTF8STRING = ("\343\201\202".size == 1) +UTF8STRING = __ENCODING__ == "UTF-8" assert('String', '15.2.10') do assert_equal Class, String.class -- cgit v1.2.3 From c9a3867ff22a1158b88c1f9119ce3c9e08085e98 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Fri, 28 Jun 2019 19:27:58 +0900 Subject: Remove unnecessary backticks in `src/range.c`; ref #2858 --- src/range.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/range.c b/src/range.c index 9036ef093..c9dfb2b3c 100644 --- a/src/range.c +++ b/src/range.c @@ -92,7 +92,7 @@ range_ptr_init(mrb_state *mrb, struct RRange *r, mrb_value beg, mrb_value end, m if (r) { if (RANGE_INITIALIZED_P(r)) { /* Ranges are immutable, so that they should be initialized only once. */ - mrb_name_error(mrb, mrb_intern_lit(mrb, "initialize"), "`initialize' called twice"); + mrb_name_error(mrb, mrb_intern_lit(mrb, "initialize"), "'initialize' called twice"); } else { range_ptr_alloc_edges(mrb, r); -- cgit v1.2.3 From 5f9034e4283ccaa99c929a36e2cfbb465e8b31b4 Mon Sep 17 00:00:00 2001 From: dearblue Date: Thu, 6 Jun 2019 22:24:58 +0900 Subject: Nested `assert` for mrbtest When nesting `assert` used in test, it is indented and displayed. Assertion numbers are concatenated by `"-"` at this time. The purpose is to match the apparent numbers when failing with `assert_mruby` which is defined by `mrbgems/mruby-bin-mruby/bintest/mruby.rb` for example. Child assertions "skip" and "info" are reported as parent assertions "info" and `$ok_test += 1`. The child assertions "ko" and "crash" are reported as the parent assertion "ko" and `$ko_test += 1`. When child assertions are mixed, "ko" takes precedence. Incompatibility: - `$mrbtest_assert_idx` takes `nil` or an integer array object. So far it was `nil` or an integer. - `$asserts` points to the top of the internal stack in the `assert`. - `$mrbtest_assert` points to the top of the internal stack in `assert`. --- test/assert.rb | 93 +++++++++++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 82 insertions(+), 11 deletions(-) diff --git a/test/assert.rb b/test/assert.rb index 5e2e104b3..c493cbbc0 100644 --- a/test/assert.rb +++ b/test/assert.rb @@ -15,6 +15,36 @@ unless RUBY_ENGINE == "mruby" end end +class Array + def _assertion_join + join("-") + end +end + +class String + def _assertion_indent(indent) + indent = indent.to_s + off = 0 + str = self + while nl = index("\n", off) + nl += 1 + nl += 1 while slice(nl) == "\n" + break if nl >= size + str = indent.dup if off == 0 + str += slice(off, nl - off) + indent + off = nl + end + + if off == 0 + str = indent + self + else + str += slice(off..-1) + end + + str + end +end + ## # Create the assertion in a readable way def assertion_string(err, str, iso=nil, e=nil, bt=nil) @@ -22,14 +52,14 @@ def assertion_string(err, str, iso=nil, e=nil, bt=nil) msg += " [#{iso}]" if iso && !iso.empty? msg += " => #{e}" if e && !e.to_s.empty? msg += " (#{GEMNAME == 'mruby-test' ? 'core' : "mrbgems: #{GEMNAME}"})" - if $mrbtest_assert && $mrbtest_assert.size > 0 + if $mrbtest_assert $mrbtest_assert.each do |idx, assert_msg, diff| msg += "\n - Assertion[#{idx}]" msg += " #{assert_msg}." if assert_msg && !assert_msg.empty? msg += "\n#{diff}" if diff && !diff.empty? end end - msg += "\nbacktrace:\n\t#{bt.join("\n\t")}" if bt + msg += "\nbacktrace:\n #{bt.join("\n ")}" if bt msg end @@ -44,13 +74,35 @@ end def assert(str = 'Assertion failed', iso = '') t_print(str, (iso != '' ? " [#{iso}]" : ''), ' : ') if $mrbtest_verbose begin + $mrbtest_child_noassert ||= [0] + $mrbtest_child_noassert << 0 + parent_asserts = $asserts + $asserts = [] + parent_mrbtest_assert = $mrbtest_assert $mrbtest_assert = [] - $mrbtest_assert_idx = 0 + + if $mrbtest_assert_idx && !$mrbtest_assert_idx.empty? + $mrbtest_assert_idx[-1] += 1 + $mrbtest_assert_idx << 0 + else + $mrbtest_assert_idx = [0] + class << $mrbtest_assert_idx + alias to_s _assertion_join + end + end + yield - if($mrbtest_assert.size > 0) - $asserts.push(assertion_string('Fail: ', str, iso)) - $ko_test += 1 - t_print('F') + if $mrbtest_assert.size > 0 + if $mrbtest_assert.size == $mrbtest_child_noassert[-1] + $asserts.push(assertion_string('Info: ', str, iso)) + $mrbtest_child_noassert[-2] += 1 + $ok_test += 1 + t_print('.') + else + $asserts.push(assertion_string('Fail: ', str, iso)) + $ko_test += 1 + t_print('F') + end else $ok_test += 1 t_print('.') @@ -58,6 +110,7 @@ def assert(str = 'Assertion failed', iso = '') rescue MRubyTestSkip => e $asserts.push(assertion_string('Skip: ', str, iso, e)) $skip_test += 1 + $mrbtest_child_noassert[-2] += 1 t_print('?') rescue Exception => e bt = e.backtrace if $mrbtest_verbose @@ -65,7 +118,25 @@ def assert(str = 'Assertion failed', iso = '') $kill_test += 1 t_print('X') ensure - $mrbtest_assert = nil + if $mrbtest_assert_idx.size > 1 + $asserts.each do |mesg| + idx = $mrbtest_assert_idx[0..-2]._assertion_join + mesg = mesg._assertion_indent(" ") + + # Give `mesg` as a `diff` argument to avoid adding extra periods. + parent_mrbtest_assert << [idx, nil, mesg] + end + else + parent_asserts.concat $asserts + end + $asserts = parent_asserts + + $mrbtest_assert = parent_mrbtest_assert + $mrbtest_assert_idx.pop + $mrbtest_assert_idx = nil if $mrbtest_assert_idx.empty? + $mrbtest_child_noassert.pop + + nil end t_print("\n") if $mrbtest_verbose end @@ -76,11 +147,11 @@ def assertion_diff(exp, act) end def assert_true(obj, msg = nil, diff = nil) - if $mrbtest_assert - $mrbtest_assert_idx += 1 + if $mrbtest_assert_idx && $mrbtest_assert_idx.size > 0 + $mrbtest_assert_idx[-1] += 1 unless obj == true diff ||= " Expected #{obj.inspect} to be true." - $mrbtest_assert.push([$mrbtest_assert_idx, msg, diff]) + $mrbtest_assert.push([$mrbtest_assert_idx.to_s, msg, diff]) end end obj -- cgit v1.2.3 From 1b9f949f3662ffaf39145638e15d628e0e94661e Mon Sep 17 00:00:00 2001 From: dearblue Date: Fri, 28 Jun 2019 23:17:25 +0900 Subject: Use a normal method instead of a lambda Ref commit 35319bed01d58c785f73ce03e67d4e58be30f4b5 --- mrbgems/mruby-io/test/io.rb | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/mrbgems/mruby-io/test/io.rb b/mrbgems/mruby-io/test/io.rb index 5004d0042..ef0b49643 100644 --- a/mrbgems/mruby-io/test/io.rb +++ b/mrbgems/mruby-io/test/io.rb @@ -4,7 +4,7 @@ MRubyIOTestUtil.io_test_setup $cr, $crlf, $cmd = MRubyIOTestUtil.win? ? [1, "\r\n", "cmd /c "] : [0, "\n", ""] -assert_io_open = ->(meth) do +def assert_io_open(meth) fd = IO.sysopen($mrbtest_io_rfname) assert_equal Fixnum, fd.class io1 = IO.__send__(meth, fd) @@ -38,7 +38,7 @@ assert('IO.ancestors', '15.2.20.3') do end assert('IO.open', '15.2.20.4.1') do - assert_io_open.(:open) + assert_io_open(:open) end assert('IO#close', '15.2.20.5.1') do @@ -224,11 +224,11 @@ assert('IO#dup for writable') do end assert('IO.for_fd') do - assert_io_open.(:for_fd) + assert_io_open(:for_fd) end assert('IO.new') do - assert_io_open.(:new) + assert_io_open(:new) end assert('IO gc check') do -- cgit v1.2.3 From a215292b6ad4315a5a0edef49a1df65e3f27b46a Mon Sep 17 00:00:00 2001 From: dearblue Date: Fri, 28 Jun 2019 23:13:29 +0900 Subject: Use nested `assert` --- mrbgems/mruby-bin-mruby/bintest/mruby.rb | 8 +++++--- mrbgems/mruby-complex/test/complex.rb | 6 ++++-- mrbgems/mruby-io/test/io.rb | 32 +++++++++++++++++--------------- mrbgems/mruby-pack/test/pack.rb | 6 ++++-- mrbgems/mruby-rational/test/rational.rb | 20 ++++++++++++-------- 5 files changed, 42 insertions(+), 30 deletions(-) diff --git a/mrbgems/mruby-bin-mruby/bintest/mruby.rb b/mrbgems/mruby-bin-mruby/bintest/mruby.rb index 09350ff49..5dbbc5592 100644 --- a/mrbgems/mruby-bin-mruby/bintest/mruby.rb +++ b/mrbgems/mruby-bin-mruby/bintest/mruby.rb @@ -3,9 +3,11 @@ require 'open3' def assert_mruby(exp_out, exp_err, exp_success, args) out, err, stat = Open3.capture3(cmd("mruby"), *args) - assert_operator(exp_out, :===, out, "standard output") - assert_operator(exp_err, :===, err, "standard error") - assert_equal(exp_success, stat.success?, "exit success?") + assert do + assert_operator(exp_out, :===, out, "standard output") + assert_operator(exp_err, :===, err, "standard error") + assert_equal(exp_success, stat.success?, "exit success?") + end end assert('regression for #1564') do diff --git a/mrbgems/mruby-complex/test/complex.rb b/mrbgems/mruby-complex/test/complex.rb index 6996eb214..ab882664e 100644 --- a/mrbgems/mruby-complex/test/complex.rb +++ b/mrbgems/mruby-complex/test/complex.rb @@ -1,6 +1,8 @@ def assert_complex(real, exp) - assert_float real.real, exp.real - assert_float real.imaginary, exp.imaginary + assert do + assert_float real.real, exp.real + assert_float real.imaginary, exp.imaginary + end end assert 'Complex' do diff --git a/mrbgems/mruby-io/test/io.rb b/mrbgems/mruby-io/test/io.rb index ef0b49643..1491a4cfe 100644 --- a/mrbgems/mruby-io/test/io.rb +++ b/mrbgems/mruby-io/test/io.rb @@ -5,24 +5,26 @@ MRubyIOTestUtil.io_test_setup $cr, $crlf, $cmd = MRubyIOTestUtil.win? ? [1, "\r\n", "cmd /c "] : [0, "\n", ""] def assert_io_open(meth) - fd = IO.sysopen($mrbtest_io_rfname) - assert_equal Fixnum, fd.class - io1 = IO.__send__(meth, fd) - begin - assert_equal IO, io1.class - assert_equal $mrbtest_io_msg, io1.read - ensure - io1.close - end + assert do + fd = IO.sysopen($mrbtest_io_rfname) + assert_equal Fixnum, fd.class + io1 = IO.__send__(meth, fd) + begin + assert_equal IO, io1.class + assert_equal $mrbtest_io_msg, io1.read + ensure + io1.close + end - io2 = IO.__send__(meth, IO.sysopen($mrbtest_io_rfname))do |io| - if meth == :open - assert_equal $mrbtest_io_msg, io.read - else - flunk "IO.#{meth} does not take block" + io2 = IO.__send__(meth, IO.sysopen($mrbtest_io_rfname))do |io| + if meth == :open + assert_equal $mrbtest_io_msg, io.read + else + flunk "IO.#{meth} does not take block" + end end + io2.close unless meth == :open end - io2.close unless meth == :open end assert('IO.class', '15.2.20') do diff --git a/mrbgems/mruby-pack/test/pack.rb b/mrbgems/mruby-pack/test/pack.rb index 110aee5db..eb24e8d1f 100644 --- a/mrbgems/mruby-pack/test/pack.rb +++ b/mrbgems/mruby-pack/test/pack.rb @@ -2,8 +2,10 @@ PACK_IS_LITTLE_ENDIAN = "\x01\00".unpack('S')[0] == 0x01 def assert_pack tmpl, packed, unpacked t = tmpl.inspect - assert_equal packed, unpacked.pack(tmpl), "#{unpacked.inspect}.pack(#{t})" - assert_equal unpacked, packed.unpack(tmpl), "#{packed.inspect}.unpack(#{t})" + assert do + assert_equal packed, unpacked.pack(tmpl), "#{unpacked.inspect}.pack(#{t})" + assert_equal unpacked, packed.unpack(tmpl), "#{packed.inspect}.unpack(#{t})" + end end # pack & unpack 'm' (base64) diff --git a/mrbgems/mruby-rational/test/rational.rb b/mrbgems/mruby-rational/test/rational.rb index 5e9d9ea48..11737034b 100644 --- a/mrbgems/mruby-rational/test/rational.rb +++ b/mrbgems/mruby-rational/test/rational.rb @@ -23,17 +23,21 @@ class ComplexLikeNumeric < UserDefinedNumeric end def assert_rational(exp, real) - assert_float exp.numerator, real.numerator - assert_float exp.denominator, real.denominator + assert do + assert_float exp.numerator, real.numerator + assert_float exp.denominator, real.denominator + end end def assert_equal_rational(exp, o1, o2) - if exp - assert_operator(o1, :==, o2) - assert_not_operator(o1, :!=, o2) - else - assert_not_operator(o1, :==, o2) - assert_operator(o1, :!=, o2) + assert do + if exp + assert_operator(o1, :==, o2) + assert_not_operator(o1, :!=, o2) + else + assert_not_operator(o1, :==, o2) + assert_operator(o1, :!=, o2) + end end end -- cgit v1.2.3 From 40030a5dbc2b76bbd9563cdfc6389ab672312b70 Mon Sep 17 00:00:00 2001 From: dearblue Date: Tue, 21 May 2019 21:58:53 +0900 Subject: Add test for `String#[]=` --- test/t/string.rb | 50 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) diff --git a/test/t/string.rb b/test/t/string.rb index 81699f17e..87d60ed72 100644 --- a/test/t/string.rb +++ b/test/t/string.rb @@ -209,6 +209,56 @@ assert('String#[]=') do assert_raise(TypeError) { 'a'[0, 1] = 1 } end +assert('String[]=(UTF-8)') do + a = "➀➁➂➃➄" + a[3] = "⚃" + assert_equal "➀➁➂⚃➄", a + + b = "➀➁➂➃➄" + b[3, 0] = "⛄" + assert_equal "➀➁➂⛄➃➄", b + + c = "➀➁➂➃➄" + c[3, 2] = "⚃⚄" + assert_equal "➀➁➂⚃⚄", c + + d = "➀➁➂➃➄" + d[5] = "⛄" + assert_equal "➀➁➂➃➄⛄", d + + e = "➀➁➂➃➄" + e[5, 0] = "⛄" + assert_equal "➀➁➂➃➄⛄", e + + f = "➀➁➂➃➄" + f[5, 2] = "⛄" + assert_equal "➀➁➂➃➄⛄", f + + g = "➀➁➂➃➄" + assert_raise(IndexError) { g[6] = "⛄" } + + h = "➀➁➂➃➄" + assert_raise(IndexError) { h[6, 0] = "⛄" } + + i = "➀➁➂➃➄" + assert_raise(IndexError) { i[6, 2] = "⛄" } + + j = "➀➁➂➃➄" + j["➃"] = "⚃" + assert_equal "➀➁➂⚃➄", j + + k = "➀➁➂➃➄" + assert_raise(IndexError) { k["⛄"] = "⛇" } + + l = "➀➁➂➃➄" + assert_nothing_raised { l["➂"] = "" } + assert_equal "➀➁➃➄", l + + m = "➀➁➂➃➄" + assert_raise(TypeError) { m["➂"] = nil } + assert_equal "➀➁➂➃➄", m +end if UTF8STRING + assert('String#capitalize', '15.2.10.5.7') do a = 'abc' a.capitalize -- cgit v1.2.3 From 0d452073f46fc46496200db610ce785e514cdb65 Mon Sep 17 00:00:00 2001 From: dearblue Date: Tue, 21 May 2019 22:02:11 +0900 Subject: Replace `String#[]=` method by C implements The purpose is to eliminate string objects that are temporarily created during processing. --- mrblib/string.rb | 54 ----------------- src/string.c | 176 ++++++++++++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 173 insertions(+), 57 deletions(-) diff --git a/mrblib/string.rb b/mrblib/string.rb index b0fe4033e..c26cdb1e2 100644 --- a/mrblib/string.rb +++ b/mrblib/string.rb @@ -177,60 +177,6 @@ class String self end - ## - # Modify +self+ by replacing the content of +self+. - # The portion of the string affected is determined using the same criteria as +String#[]+. - def []=(*args) - anum = args.size - if anum == 2 - pos, value = args[0], args[1].__to_str - case pos - when String - posnum = self.index(pos) - if posnum - b = self[0, posnum] - a = self[(posnum + pos.length)..-1] - self.replace([b, value, a].join('')) - else - raise IndexError, "string not matched" - end - when Range - head = pos.begin - tail = pos.end - tail += self.length if tail < 0 - unless pos.exclude_end? - tail += 1 - end - return self[head, tail-head]=value - else - pos = pos.__to_int - pos += self.length if pos < 0 - if pos < 0 || pos > self.length - raise IndexError, "index #{args[0]} out of string" - end - b = self[0, pos] - a = self[pos + 1..-1] - self.replace([b, value, a].join('')) - end - return value - elsif anum == 3 - pos, len, value = args[0].__to_int, args[1].__to_int, args[2].__to_str - pos += self.length if pos < 0 - if pos < 0 || pos > self.length - raise IndexError, "index #{args[0]} out of string" - end - if len < 0 - raise IndexError, "negative length #{len}" - end - b = self[0, pos] - a = self[pos + len..-1] - self.replace([b, value, a].join('')) - return value - else - raise ArgumentError, "wrong number of arguments (#{anum} for 2..3)" - end - end - # those two methods requires Regexp that is optional in mruby ## # ISO 15.2.10.5.3 diff --git a/src/string.c b/src/string.c index c8a9e61ec..43bf8a841 100644 --- a/src/string.c +++ b/src/string.c @@ -427,13 +427,18 @@ mrb_str_byte_subseq(mrb_state *mrb, mrb_value str, mrb_int beg, mrb_int len) } return mrb_obj_value(s); } + +static void +str_range_to_bytes(mrb_value str, mrb_int *pos, mrb_int *len) +{ + *pos = chars2bytes(str, 0, *pos); + *len = chars2bytes(str, *pos, *len); +} #ifdef MRB_UTF8_STRING static inline mrb_value str_subseq(mrb_state *mrb, mrb_value str, mrb_int beg, mrb_int len) { - beg = chars2bytes(str, 0, beg); - len = chars2bytes(str, beg, len); - + str_range_to_bytes(str, &beg, &len); return mrb_str_byte_subseq(mrb, str, beg, len); } #else @@ -1010,6 +1015,68 @@ mrb_str_dup(mrb_state *mrb, mrb_value str) return str_replace(mrb, dup, s); } +enum str_convert_range { + /* `beg` and `len` are byte unit in `0 ... str.bytesize` */ + STR_BYTE_RANGE_CORRECTED = 1, + + /* `beg` and `len` are char unit in any range */ + STR_CHAR_RANGE = 2, + + /* `beg` and `len` are char unit in `0 ... str.size` */ + STR_CHAR_RANGE_CORRECTED = 3, + + /* `beg` is out of range */ + STR_OUT_OF_RANGE = -1 +}; + +static enum str_convert_range +str_convert_range(mrb_state *mrb, mrb_value str, mrb_value indx, mrb_value alen, mrb_int *beg, mrb_int *len) +{ + if (!mrb_undef_p(alen)) { + *beg = mrb_int(mrb, indx); + *len = mrb_int(mrb, alen); + return STR_CHAR_RANGE; + } + else { + switch (mrb_type(indx)) { + case MRB_TT_FIXNUM: + *beg = mrb_fixnum(indx); + *len = 1; + return STR_CHAR_RANGE; + + case MRB_TT_STRING: + *beg = str_index_str(mrb, str, indx, 0); + if (*beg < 0) { break; } + *len = RSTRING_LEN(indx); + return STR_BYTE_RANGE_CORRECTED; + + case MRB_TT_RANGE: + goto range_arg; + + default: + indx = mrb_to_int(mrb, indx); + if (mrb_fixnum_p(indx)) { + *beg = mrb_fixnum(indx); + *len = 1; + return STR_CHAR_RANGE; + } +range_arg: + *len = RSTRING_CHAR_LEN(str); + switch (mrb_range_beg_len(mrb, indx, beg, len, *len, TRUE)) { + case MRB_RANGE_OK: + return STR_CHAR_RANGE_CORRECTED; + case MRB_RANGE_OUT: + return STR_OUT_OF_RANGE; + default: + break; + } + + mrb_raise(mrb, E_TYPE_ERROR, "can't convert to Fixnum"); + } + } + return STR_OUT_OF_RANGE; +} + static mrb_value mrb_str_aref(mrb_state *mrb, mrb_value str, mrb_value indx) { @@ -1113,6 +1180,108 @@ mrb_str_aref_m(mrb_state *mrb, mrb_value str) return mrb_str_aref(mrb, str, a1); } +static mrb_noreturn void +str_out_of_index(mrb_state *mrb, mrb_value index) +{ + mrb_raisef(mrb, E_INDEX_ERROR, "index %S out of string", index); +} + +static mrb_value +str_replace_partial(mrb_state *mrb, mrb_value src, mrb_int pos, mrb_int end, mrb_value rep) +{ + const mrb_int shrink_threshold = 256; + struct RString *str = mrb_str_ptr(src); + mrb_int len = RSTR_LEN(str); + mrb_int replen, newlen; + char *strp; + + if (end > len) { end = len; } + + if (pos < 0 || pos > len) { + str_out_of_index(mrb, mrb_fixnum_value(pos)); + } + + replen = (mrb_nil_p(rep) ? 0 : RSTRING_LEN(rep)); + newlen = replen + len - (end - pos); + + if (newlen >= MRB_INT_MAX || newlen < replen /* overflowed */) { + mrb_raise(mrb, E_RUNTIME_ERROR, "string size too big"); + } + + mrb_str_modify(mrb, str); + + if (len < newlen || len - newlen >= shrink_threshold) { + resize_capa(mrb, str, newlen); + } + + strp = RSTR_PTR(str); + + memmove(strp + newlen - (len - end), strp + end, len - end); + if (!mrb_nil_p(rep)) { + memcpy(strp + pos, RSTRING_PTR(rep), replen); + } + RSTR_SET_LEN(str, newlen); + strp[newlen] = '\0'; + + return src; +} + +static void +mrb_str_aset(mrb_state *mrb, mrb_value str, mrb_value indx, mrb_value alen, mrb_value replace) +{ + mrb_int beg, len, charlen; + + replace = mrb_to_str(mrb, replace); + + switch (str_convert_range(mrb, str, indx, alen, &beg, &len)) { + case STR_OUT_OF_RANGE: + default: + mrb_raise(mrb, E_INDEX_ERROR, "string not matched"); + case STR_CHAR_RANGE: + if (len < 0) { + mrb_raisef(mrb, E_INDEX_ERROR, "negative length %S", alen); + } + charlen = RSTRING_CHAR_LEN(str); + if (beg < 0) { beg += charlen; } + if (beg < 0 || beg > charlen) { str_out_of_index(mrb, indx); } + /* fall through */ + case STR_CHAR_RANGE_CORRECTED: + str_range_to_bytes(str, &beg, &len); + /* fall through */ + case STR_BYTE_RANGE_CORRECTED: + str_replace_partial(mrb, str, beg, beg + len, replace); + } +} + +/* + * call-seq: + * str[fixnum] = replace + * str[fixnum, fixnum] = replace + * str[range] = replace + * str[regexp] = replace + * str[regexp, fixnum] = replace + * str[other_str] = replace + * + * Modify +self+ by replacing the content of +self+. + * The portion of the string affected is determined using the same criteria as +String#[]+. + */ +static mrb_value +mrb_str_aset_m(mrb_state *mrb, mrb_value str) +{ + mrb_value indx, alen, replace; + + switch (mrb_get_args(mrb, "oo|S!", &indx, &alen, &replace)) { + case 2: + replace = alen; + alen = mrb_undef_value(); + break; + case 3: + break; + } + mrb_str_aset(mrb, str, indx, alen, replace); + return str; +} + /* 15.2.10.5.8 */ /* * call-seq: @@ -2678,6 +2847,7 @@ mrb_init_string(mrb_state *mrb) mrb_define_method(mrb, s, "+", mrb_str_plus_m, MRB_ARGS_REQ(1)); /* 15.2.10.5.4 */ mrb_define_method(mrb, s, "*", mrb_str_times, MRB_ARGS_REQ(1)); /* 15.2.10.5.5 */ mrb_define_method(mrb, s, "[]", mrb_str_aref_m, MRB_ARGS_ANY()); /* 15.2.10.5.6 */ + mrb_define_method(mrb, s, "[]=", mrb_str_aset_m, MRB_ARGS_ANY()); mrb_define_method(mrb, s, "capitalize", mrb_str_capitalize, MRB_ARGS_NONE()); /* 15.2.10.5.7 */ mrb_define_method(mrb, s, "capitalize!", mrb_str_capitalize_bang, MRB_ARGS_NONE()); /* 15.2.10.5.8 */ mrb_define_method(mrb, s, "chomp", mrb_str_chomp, MRB_ARGS_ANY()); /* 15.2.10.5.9 */ -- cgit v1.2.3 From 0ad1cacff30c744fcf07869990cbab7bc51c4c68 Mon Sep 17 00:00:00 2001 From: dearblue Date: Thu, 27 Jun 2019 20:46:49 +0900 Subject: Simplify `mrb_str_aref_m()` and `mrb_str_aref()` It is integration with part of argument parsing used in `mrb_str_aset_m()`. --- src/string.c | 66 ++++++++++++++++++------------------------------------------ 1 file changed, 20 insertions(+), 46 deletions(-) diff --git a/src/string.c b/src/string.c index 43bf8a841..6938418fb 100644 --- a/src/string.c +++ b/src/string.c @@ -1078,50 +1078,28 @@ range_arg: } static mrb_value -mrb_str_aref(mrb_state *mrb, mrb_value str, mrb_value indx) +mrb_str_aref(mrb_state *mrb, mrb_value str, mrb_value indx, mrb_value alen) { - mrb_int idx; + mrb_int beg, len; - switch (mrb_type(indx)) { - case MRB_TT_FIXNUM: - idx = mrb_fixnum(indx); - -num_index: - str = str_substr(mrb, str, idx, 1); - if (!mrb_nil_p(str) && RSTRING_LEN(str) == 0) return mrb_nil_value(); + switch (str_convert_range(mrb, str, indx, alen, &beg, &len)) { + case STR_CHAR_RANGE_CORRECTED: + return str_subseq(mrb, str, beg, len); + case STR_CHAR_RANGE: + str = str_substr(mrb, str, beg, len); + if (mrb_undef_p(alen) && !mrb_nil_p(str) && RSTRING_LEN(str) == 0) return mrb_nil_value(); return str; - - case MRB_TT_STRING: - if (str_index_str(mrb, str, indx, 0) != -1) + case STR_BYTE_RANGE_CORRECTED: + if (mrb_string_p(indx)) { return mrb_str_dup(mrb, indx); - return mrb_nil_value(); - - case MRB_TT_RANGE: - goto range_arg; - - default: - indx = mrb_Integer(mrb, indx); - if (mrb_nil_p(indx)) { - range_arg: - { - mrb_int beg, len; - - len = RSTRING_CHAR_LEN(str); - switch (mrb_range_beg_len(mrb, indx, &beg, &len, len, TRUE)) { - case MRB_RANGE_OK: - return str_subseq(mrb, str, beg, len); - case MRB_RANGE_OUT: - return mrb_nil_value(); - default: - break; - } - } - mrb_raise(mrb, E_TYPE_ERROR, "can't convert to Fixnum"); } - idx = mrb_fixnum(indx); - goto num_index; + else { + return mrb_str_byte_subseq(mrb, str, beg, len); + } + case STR_OUT_OF_RANGE: + default: + return mrb_nil_value(); } - return mrb_nil_value(); /* not reached */ } /* 15.2.10.5.6 */ @@ -1168,16 +1146,12 @@ static mrb_value mrb_str_aref_m(mrb_state *mrb, mrb_value str) { mrb_value a1, a2; - mrb_int argc; - argc = mrb_get_args(mrb, "o|o", &a1, &a2); - if (argc == 2) { - mrb_int n1, n2; - - mrb_get_args(mrb, "ii", &n1, &n2); - return str_substr(mrb, str, n1, n2); + if (mrb_get_args(mrb, "o|o", &a1, &a2) == 1) { + a2 = mrb_undef_value(); } - return mrb_str_aref(mrb, str, a1); + + return mrb_str_aref(mrb, str, a1, a2); } static mrb_noreturn void -- cgit v1.2.3 From 97c9e6b00032cd8a7132b43911c05e44732a4c56 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Sun, 30 Jun 2019 14:46:38 +0900 Subject: Fix `include`, `prepend` and `extend` to frozen object --- src/class.c | 5 +++-- test/t/kernel.rb | 3 +++ test/t/module.rb | 27 +++++++++++++++++++++++++++ 3 files changed, 33 insertions(+), 2 deletions(-) diff --git a/src/class.c b/src/class.c index 373f2aec7..1064870a8 100644 --- a/src/class.c +++ b/src/class.c @@ -1070,8 +1070,8 @@ include_module_at(mrb_state *mrb, struct RClass *c, struct RClass *ins_pos, stru MRB_API void mrb_include_module(mrb_state *mrb, struct RClass *c, struct RClass *m) { - int changed = include_module_at(mrb, c, find_origin(c), m, 1); - if (changed < 0) { + mrb_check_frozen(mrb, c); + if (include_module_at(mrb, c, find_origin(c), m, 1) < 0) { mrb_raise(mrb, E_ARGUMENT_ERROR, "cyclic include detected"); } } @@ -1082,6 +1082,7 @@ mrb_prepend_module(mrb_state *mrb, struct RClass *c, struct RClass *m) struct RClass *origin; int changed = 0; + mrb_check_frozen(mrb, c); if (!(c->flags & MRB_FL_CLASS_IS_PREPENDED)) { origin = (struct RClass*)mrb_obj_alloc(mrb, MRB_TT_ICLASS, c); origin->flags |= MRB_FL_CLASS_IS_ORIGIN | MRB_FL_CLASS_IS_INHERITED; diff --git a/test/t/kernel.rb b/test/t/kernel.rb index 1e48069f2..ecfb863a8 100644 --- a/test/t/kernel.rb +++ b/test/t/kernel.rb @@ -240,6 +240,9 @@ assert('Kernel#extend', '15.3.1.3.13') do assert_true a.respond_to?(:test_method) assert_false b.respond_to?(:test_method) + + assert_raise(FrozenError) { Object.new.freeze.extend(Test4ExtendModule) } + assert_raise(FrozenError, TypeError) { :sym.extend(Test4ExtendModule) } end assert('Kernel#extend works on toplevel', '15.3.1.3.13') do diff --git a/test/t/module.rb b/test/t/module.rb index 571f4759d..7f869bf1f 100644 --- a/test/t/module.rb +++ b/test/t/module.rb @@ -59,6 +59,7 @@ assert('Module#append_features', '15.2.2.4.10') do end assert_equal Test4AppendFeatures2, Test4AppendFeatures2.const_get(:Const4AppendFeatures2) + assert_raise(FrozenError) { Module.new.append_features Class.new.freeze } end assert('Module#attr NameError') do @@ -275,6 +276,18 @@ assert('Module#const_missing', '15.2.2.4.22') do assert_equal 42, Test4ConstMissing.const_get(:ConstDoesntExist) end +assert('Module#extend_object', '15.2.2.4.25') do + cls = Class.new + mod = Module.new { def foo; end } + a = cls.new + b = cls.new + mod.extend_object(b) + assert_false a.respond_to?(:foo) + assert_true b.respond_to?(:foo) + assert_raise(FrozenError) { mod.extend_object(cls.new.freeze) } + assert_raise(FrozenError, TypeError) { mod.extend_object(1) } +end + assert('Module#include', '15.2.2.4.27') do module Test4Include Const4Include = 42 @@ -288,6 +301,7 @@ assert('Module#include', '15.2.2.4.27') do assert_equal 42, Test4Include2.const_get(:Const4Include) assert_equal Test4Include2, Test4Include2.include_result + assert_raise(FrozenError) { Module.new.freeze.include Test4Include } end assert('Module#include?', '15.2.2.4.28') do @@ -398,6 +412,15 @@ assert('Module#define_method') do end end +assert 'Module#prepend_features' do + mod = Module.new { def m; :mod end } + cls = Class.new { def m; :cls end } + assert_equal :cls, cls.new.m + mod.prepend_features(cls) + assert_equal :mod, cls.new.m + assert_raise(FrozenError) { Module.new.prepend_features(Class.new.freeze) } +end + # @!group prepend assert('Module#prepend') do module M0 @@ -632,6 +655,10 @@ end # end # end; #end + + assert 'Module#prepend to frozen class' do + assert_raise(FrozenError) { Class.new.freeze.prepend Module.new } + end # @!endgroup prepend assert('Module#to_s') do -- cgit v1.2.3 From 7e3a8b7a7520b101d8cc3453cf7ca5e3c7700772 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Mon, 1 Jul 2019 12:29:02 +0900 Subject: Remove unused C header file from `src/etc.c` --- src/etc.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/etc.c b/src/etc.c index ac1540f92..37717a6f2 100644 --- a/src/etc.c +++ b/src/etc.c @@ -1,5 +1,5 @@ /* -** etc.c - +** etc.c ** ** See Copyright Notice in mruby.h */ @@ -8,8 +8,6 @@ #include #include #include -#include -#include MRB_API struct RData* mrb_data_object_alloc(mrb_state *mrb, struct RClass *klass, void *ptr, const mrb_data_type *type) -- cgit v1.2.3 From 0d54dbb2644b468e255564cfdbb5c435e1e3686f Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Tue, 2 Jul 2019 19:41:40 +0900 Subject: Fix and refine error message in `mrb_obj_to_sym()` Before this patch: $ bin/mruby -e '1.respond_to?(2)' #=> nil is not a symbol After this patch (same as Ruby): $ bin/mruby -e '1.respond_to?(2)' #=> 2 is not a symbol nor a string --- src/etc.c | 22 ++++------------------ 1 file changed, 4 insertions(+), 18 deletions(-) diff --git a/src/etc.c b/src/etc.c index 37717a6f2..18d2839d9 100644 --- a/src/etc.c +++ b/src/etc.c @@ -65,24 +65,10 @@ mrb_data_get_ptr(mrb_state *mrb, mrb_value obj, const mrb_data_type *type) MRB_API mrb_sym mrb_obj_to_sym(mrb_state *mrb, mrb_value name) { - mrb_sym id; - - switch (mrb_type(name)) { - default: - name = mrb_check_string_type(mrb, name); - if (mrb_nil_p(name)) { - name = mrb_inspect(mrb, name); - mrb_raisef(mrb, E_TYPE_ERROR, "%S is not a symbol", name); - /* not reached */ - } - /* fall through */ - case MRB_TT_STRING: - name = mrb_str_intern(mrb, name); - /* fall through */ - case MRB_TT_SYMBOL: - id = mrb_symbol(name); - } - return id; + if (mrb_symbol_p(name)) return mrb_symbol(name); + if (mrb_string_p(name)) return mrb_intern_str(mrb, name); + mrb_raisef(mrb, E_TYPE_ERROR, "%S is not a symbol nor a string", mrb_inspect(mrb, name)); + return 0; /* not reached */ } MRB_API mrb_int -- cgit v1.2.3 From d915261590d646a8788b2200342228804cb1754f Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Wed, 3 Jul 2019 20:36:04 +0900 Subject: Refine document to mrb_get_args()` [ci skip] --- include/mruby.h | 12 +++++++----- src/class.c | 16 ++++++++-------- 2 files changed, 15 insertions(+), 13 deletions(-) diff --git a/include/mruby.h b/include/mruby.h index 3ef399716..7deb3cbe2 100644 --- a/include/mruby.h +++ b/include/mruby.h @@ -836,15 +836,17 @@ MRB_API struct RClass * mrb_define_module_under(mrb_state *mrb, struct RClass *o * | `S` | {String} | {mrb_value} | when `!` follows, the value may be `nil` | * | `A` | {Array} | {mrb_value} | when `!` follows, the value may be `nil` | * | `H` | {Hash} | {mrb_value} | when `!` follows, the value may be `nil` | - * | `s` | {String} | char *, {mrb_int} | Receive two arguments; `s!` gives (`NULL`,`0`) for `nil` | + * | `s` | {String} | char *, {mrb_int} | Receive two arguments; `s!` gives (`NULL`,`0`) for `nil` | * | `z` | {String} | char * | `NULL` terminated string; `z!` gives `NULL` for `nil` | * | `a` | {Array} | {mrb_value} *, {mrb_int} | Receive two arguments; `a!` gives (`NULL`,`0`) for `nil` | - * | `f` | {Float} | {mrb_float} | | - * | `i` | {Integer} | {mrb_int} | | + * | `f` | {Fixnum}/{Float} | {mrb_float} | | + * | `i` | {Fixnum}/{Float} | {mrb_int} | | * | `b` | boolean | {mrb_bool} | | - * | `n` | {Symbol} | {mrb_sym} | | + * | `n` | {String}/{Symbol} | {mrb_sym} | | + * | `d` | data | void *, {mrb_data_type} const | 2nd argument will be used to check data type so it won't be modified; when `!` follows, the value may be `nil` | + * | `I` | inline struct | void * | | * | `&` | block | {mrb_value} | &! raises exception if no block given. | - * | `*` | rest arguments | {mrb_value} *, {mrb_int} | Receive the rest of arguments as an array; *! avoid copy of the stack. | + * | `*` | rest arguments | {mrb_value} *, {mrb_int} | Receive the rest of arguments as an array; `*!` avoid copy of the stack. | * | | | optional | | After this spec following specs would be optional. | * | `?` | optional given | {mrb_bool} | `TRUE` if preceding argument is given. Used to check optional argument is given. | * diff --git a/src/class.c b/src/class.c index 1064870a8..edee95678 100644 --- a/src/class.c +++ b/src/class.c @@ -573,20 +573,20 @@ mrb_get_argv(mrb_state *mrb) string mruby type C type note ---------------------------------------------------------------------------------------------- o: Object [mrb_value] - C: class/module [mrb_value] + C: Class/Module [mrb_value] S: String [mrb_value] when ! follows, the value may be nil A: Array [mrb_value] when ! follows, the value may be nil H: Hash [mrb_value] when ! follows, the value may be nil s: String [char*,mrb_int] Receive two arguments; s! gives (NULL,0) for nil z: String [char*] NUL terminated string; z! gives NULL for nil a: Array [mrb_value*,mrb_int] Receive two arguments; a! gives (NULL,0) for nil - f: Float [mrb_float] - i: Integer [mrb_int] - b: Boolean [mrb_bool] - n: Symbol [mrb_sym] - d: Data [void*,mrb_data_type const] 2nd argument will be used to check data type so it won't be modified - I: Inline struct [void*] - &: Block [mrb_value] &! raises exception if no block given + f: Fixnum/Float [mrb_float] + i: Fixnum/Float [mrb_int] + b: boolean [mrb_bool] + n: String/Symbol [mrb_sym] + d: data [void*,mrb_data_type const] 2nd argument will be used to check data type so it won't be modified; when ! follows, the value may be nil + I: inline struct [void*] + &: block [mrb_value] &! raises exception if no block given *: rest argument [mrb_value*,mrb_int] The rest of the arguments as an array; *! avoid copy of the stack |: optional Following arguments are optional ?: optional given [mrb_bool] true if preceding argument (optional) is given -- cgit v1.2.3 From 2bb30481b6d6aed0f869dd089a56ebe24e8e2349 Mon Sep 17 00:00:00 2001 From: dearblue Date: Thu, 4 Jul 2019 21:49:07 +0900 Subject: Fix heap buffer overflow; ref #4549 This patch is showed in #4549. --- src/string.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/string.c b/src/string.c index 6938418fb..7a094b3a7 100644 --- a/src/string.c +++ b/src/string.c @@ -1184,7 +1184,7 @@ str_replace_partial(mrb_state *mrb, mrb_value src, mrb_int pos, mrb_int end, mrb mrb_str_modify(mrb, str); - if (len < newlen || len - newlen >= shrink_threshold) { + if (len < newlen) { resize_capa(mrb, str, newlen); } @@ -1197,6 +1197,10 @@ str_replace_partial(mrb_state *mrb, mrb_value src, mrb_int pos, mrb_int end, mrb RSTR_SET_LEN(str, newlen); strp[newlen] = '\0'; + if (len - newlen >= shrink_threshold) { + resize_capa(mrb, str, newlen); + } + return src; } -- cgit v1.2.3 From 991bdd4ed7b0aa6fd6bee4fa5c62283365dcf15d Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Thu, 4 Jul 2019 23:01:16 +0900 Subject: Rename `MRB_STR_NO_UTF` to 'MRB_STR_ASCII`; close #4550 In #4550, @shuuji proposed the name name `MRB_STR_NO_MULTI_BYTE` for more precise description. Although I agree that the name name is correct, but the flag means the string does not contain multi byte UTF-8 characters, i.e. all characters fit in the range of ASCII. --- include/mruby/string.h | 2 +- src/string.c | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/include/mruby/string.h b/include/mruby/string.h index b563541cb..9484e20d7 100644 --- a/include/mruby/string.h +++ b/include/mruby/string.h @@ -87,7 +87,7 @@ MRB_API mrb_int mrb_str_strlen(mrb_state*, struct RString*); #define MRB_STR_FSHARED 2 #define MRB_STR_NOFREE 4 #define MRB_STR_POOL 8 -#define MRB_STR_NO_UTF 16 +#define MRB_STR_ASCII 16 #define MRB_STR_EMBED 32 #define MRB_STR_EMBED_LEN_MASK 0x7c0 #define MRB_STR_EMBED_LEN_SHIFT 6 diff --git a/src/string.c b/src/string.c index 7a094b3a7..805cf01dc 100644 --- a/src/string.c +++ b/src/string.c @@ -260,12 +260,12 @@ utf8_strlen(mrb_value str) { mrb_int byte_len = RSTRING_LEN(str); - if (RSTRING(str)->flags & MRB_STR_NO_UTF) { + if (RSTRING(str)->flags & MRB_STR_ASCII) { return byte_len; } else { mrb_int utf8_len = mrb_utf8_len(RSTRING_PTR(str), byte_len); - if (byte_len == utf8_len) RSTRING(str)->flags |= MRB_STR_NO_UTF; + if (byte_len == utf8_len) RSTRING(str)->flags |= MRB_STR_ASCII; return utf8_len; } } @@ -512,8 +512,8 @@ str_replace(mrb_state *mrb, struct RString *s1, struct RString *s2) mrb_check_frozen(mrb, s1); if (s1 == s2) return mrb_obj_value(s1); - s1->flags &= ~MRB_STR_NO_UTF; - s1->flags |= s2->flags&MRB_STR_NO_UTF; + s1->flags &= ~MRB_STR_ASCII; + s1->flags |= s2->flags&MRB_STR_ASCII; len = RSTR_LEN(s2); if (RSTR_SHARED_P(s1)) { str_decref(mrb, s1->as.heap.aux.shared); @@ -651,7 +651,7 @@ MRB_API void mrb_str_modify(mrb_state *mrb, struct RString *s) { mrb_check_frozen(mrb, s); - s->flags &= ~MRB_STR_NO_UTF; + s->flags &= ~MRB_STR_ASCII; if (RSTR_SHARED_P(s)) { mrb_shared_string *shared = s->as.heap.aux.shared; -- cgit v1.2.3 From 8294ce9fd458a0a1acf8fcdcb6161b4a020866ad Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Thu, 4 Jul 2019 23:11:57 +0900 Subject: It was too early to check `key` for `undef`; ref #4534 --- src/hash.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hash.c b/src/hash.c index ac6a7cd56..2a0a19363 100644 --- a/src/hash.c +++ b/src/hash.c @@ -543,10 +543,10 @@ ht_copy(mrb_state *mrb, htable *t) mrb_value key = seg->e[i].key; mrb_value val = seg->e[i].val; - if (mrb_undef_p(key)) continue; /* skip deleted key */ if ((seg->next == NULL) && (i >= t->last_len)) { return t2; } + if (mrb_undef_p(key)) continue; /* skip deleted key */ ht_put(mrb, t2, key, val); } seg = seg->next; -- cgit v1.2.3 From f9bf2d9d8e2531b2bfebb5a80362b43ab559b56f Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Fri, 5 Jul 2019 20:37:59 +0900 Subject: Read/write `MRB_STR_ASCII` flag only when `MRB_UTF8_STRING` is defined --- include/mruby/string.h | 14 ++++++++++++++ src/string.c | 14 +++++++------- 2 files changed, 21 insertions(+), 7 deletions(-) diff --git a/include/mruby/string.h b/include/mruby/string.h index 9484e20d7..d648d856c 100644 --- a/include/mruby/string.h +++ b/include/mruby/string.h @@ -68,6 +68,20 @@ struct RString { #define RSTR_SET_NOFREE_FLAG(s) ((s)->flags |= MRB_STR_NOFREE) #define RSTR_UNSET_NOFREE_FLAG(s) ((s)->flags &= ~MRB_STR_NOFREE) +#ifdef MRB_UTF8_STRING +# define RSTR_ASCII_P(s) ((s)->flags & MRB_STR_ASCII) +# define RSTR_SET_ASCII_FLAG(s) ((s)->flags |= MRB_STR_ASCII) +# define RSTR_UNSET_ASCII_FLAG(s) ((s)->flags &= ~MRB_STR_ASCII) +# define RSTR_WRITE_ASCII_FLAG(s, v) (RSTR_UNSET_ASCII_FLAG(s), (s)->flags |= v) +# define RSTR_COPY_ASCII_FLAG(dst, src) RSTR_WRITE_ASCII_FLAG(dst, RSTR_ASCII_P(src)) +#else +# define RSTR_ASCII_P(s) (void)0 +# define RSTR_SET_ASCII_FLAG(s) (void)0 +# define RSTR_UNSET_ASCII_FLAG(s) (void)0 +# define RSTR_WRITE_ASCII_FLAG(s, v) (void)0 +# define RSTR_COPY_ASCII_FLAG(dst, src) (void)0 +#endif + #define RSTR_POOL_P(s) ((s)->flags & MRB_STR_POOL) #define RSTR_SET_POOL_FLAG(s) ((s)->flags |= MRB_STR_POOL) diff --git a/src/string.c b/src/string.c index 805cf01dc..078c028d8 100644 --- a/src/string.c +++ b/src/string.c @@ -258,14 +258,15 @@ mrb_utf8_len(const char *str, mrb_int byte_len) static mrb_int utf8_strlen(mrb_value str) { - mrb_int byte_len = RSTRING_LEN(str); + struct RString *s = mrb_str_ptr(str); + mrb_int byte_len = RSTR_LEN(s); - if (RSTRING(str)->flags & MRB_STR_ASCII) { + if (RSTR_ASCII_P(s)) { return byte_len; } else { - mrb_int utf8_len = mrb_utf8_len(RSTRING_PTR(str), byte_len); - if (byte_len == utf8_len) RSTRING(str)->flags |= MRB_STR_ASCII; + mrb_int utf8_len = mrb_utf8_len(RSTR_PTR(s), byte_len); + if (byte_len == utf8_len) RSTR_SET_ASCII_FLAG(s); return utf8_len; } } @@ -512,8 +513,7 @@ str_replace(mrb_state *mrb, struct RString *s1, struct RString *s2) mrb_check_frozen(mrb, s1); if (s1 == s2) return mrb_obj_value(s1); - s1->flags &= ~MRB_STR_ASCII; - s1->flags |= s2->flags&MRB_STR_ASCII; + RSTR_COPY_ASCII_FLAG(s1, s2); len = RSTR_LEN(s2); if (RSTR_SHARED_P(s1)) { str_decref(mrb, s1->as.heap.aux.shared); @@ -651,7 +651,7 @@ MRB_API void mrb_str_modify(mrb_state *mrb, struct RString *s) { mrb_check_frozen(mrb, s); - s->flags &= ~MRB_STR_ASCII; + RSTR_UNSET_ASCII_FLAG(s); if (RSTR_SHARED_P(s)) { mrb_shared_string *shared = s->as.heap.aux.shared; -- cgit v1.2.3 From df1f1002d9fe8466e0d621818febf465e03b9016 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Sat, 6 Jul 2019 19:55:37 +0900 Subject: Fix missing `#ifndef MRB_ENABLE_ALL_SYMBOLS` --- src/symbol.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/symbol.c b/src/symbol.c index b26f2b1fd..5eeb28045 100644 --- a/src/symbol.c +++ b/src/symbol.c @@ -503,9 +503,11 @@ mrb_sym2str(mrb_state *mrb, mrb_sym sym) const char *name = mrb_sym2name_len(mrb, sym, &len); if (!name) return mrb_undef_value(); /* can't happen */ +#ifndef MRB_ENABLE_ALL_SYMBOLS if (sym&1) { /* inline symbol */ return mrb_str_new(mrb, name, len); } +#endif return mrb_str_new_static(mrb, name, len); } @@ -521,12 +523,12 @@ mrb_sym2name(mrb_state *mrb, mrb_sym sym) } else { mrb_value str; - if (sym&1) { /* inline symbol */ +#ifndef MRB_ENABLE_ALL_SYMBOLS + if (sym&1) /* inline symbol */ str = mrb_str_new(mrb, name, len); - } - else { + else +#endif str = mrb_str_new_static(mrb, name, len); - } str = mrb_str_dump(mrb, str); return RSTRING_PTR(str); } -- cgit v1.2.3 From 32c2aa10c79e37c53411b1d693c6c8d010fba7bb Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Sun, 7 Jul 2019 22:10:32 +0900 Subject: Fix `Numeric#step` to infinity; ref. #4555 --- mrblib/numeric.rb | 8 ++--- test/t/numeric.rb | 88 ++++++++++++++++++++++++++++++++++++++++--------------- 2 files changed, 69 insertions(+), 27 deletions(-) diff --git a/mrblib/numeric.rb b/mrblib/numeric.rb index 5a3c5eb58..5926518d5 100644 --- a/mrblib/numeric.rb +++ b/mrblib/numeric.rb @@ -105,14 +105,14 @@ module Integral return to_enum(:step, num, step) unless block i = __coerce_step_counter(num, step) - if num == nil + if num == self || step.infinite? + block.call(i) if step > 0 && i <= (num||i) || step < 0 && i >= (num||-i) + elsif num == nil while true block.call(i) i += step end - return self - end - if step > 0 + elsif step > 0 while i <= num block.call(i) i += step diff --git a/test/t/numeric.rb b/test/t/numeric.rb index d73dfdb61..bb95f8ef3 100644 --- a/test/t/numeric.rb +++ b/test/t/numeric.rb @@ -1,6 +1,19 @@ ## # Numeric ISO Test +def assert_step(exp, receiver, args, inf: false) + act = [] + ret = receiver.step(*args) do |i| + act << i + break if inf && exp.size == act.size + end + expr = "#{receiver.inspect}.step(#{args.map(&:inspect).join(', ')})" + assert do + assert_true(exp.eql?(act), "#{expr}: counters", assertion_diff(exp, act)) + assert_same(receiver, ret, "#{expr}: return value") unless inf + end +end + assert('Numeric', '15.2.7') do assert_equal(Class, Numeric.class) end @@ -42,31 +55,60 @@ assert('Numeric#**') do end assert('Numeric#step') do - assert_step = ->(exp, receiver, args) do - inf = !args[0] - act = [] - ret = receiver.step(*args) do |i| - act << i - break if inf && exp.size == act.size - end - expr = "#{receiver.inspect}.step(#{args.map(&:inspect).join(', ')})" - assert_true(exp.eql?(act), "#{expr}: counters", assertion_diff(exp, act)) - assert_same(receiver, ret, "#{expr}: return value") unless inf - end - assert_raise(ArgumentError) { 1.step(2, 0) { break } } - assert_step.([2, 3, 4], 2, [4]) - assert_step.([10, 8, 6, 4, 2], 10, [1, -2]) - assert_step.([], 2, [1, 3]) - assert_step.([], -2, [-1, -3]) - assert_step.([10, 11, 12, 13], 10, []) - assert_step.([10, 7, 4], 10, [nil, -3]) + assert_step([2, 3, 4], 2, [4]) + assert_step([10, 8, 6, 4, 2], 10, [1, -2]) + assert_step([], 2, [1, 3]) + assert_step([], -2, [-1, -3]) + assert_step([10, 11, 12, 13], 10, [], inf: true) + assert_step([10, 7, 4], 10, [nil, -3], inf: true) skip unless Object.const_defined?(:Float) + inf = Float::INFINITY assert_raise(ArgumentError) { 1.step(2, 0.0) { break } } - assert_step.([2.0, 3.0, 4.0], 2, [4.0]) - assert_step.([7.0, 4.0, 1.0, -2.0], 7, [-4, -3.0]) - assert_step.([2.0, 3.0, 4.0], 2.0, [4]) - assert_step.([10.0, 11.0, 12.0, 13.0], 10.0, []) - assert_step.([10.0, 7.0, 4.0], 10, [nil, -3.0]) + assert_step([2.0, 3.0, 4.0], 2, [4.0]) + assert_step([7.0, 4.0, 1.0, -2.0], 7, [-4, -3.0]) + assert_step([2.0, 3.0, 4.0], 2.0, [4]) + assert_step([10.0, 11.0, 12.0, 13.0], 10.0, [], inf: true) + assert_step([10.0, 7.0, 4.0], 10, [nil, -3.0], inf: true) + assert_step([1.0], 1, [nil, inf]) + assert_step([1.0], 1, [nil, -inf]) + assert_step([1.0], 1, [3, inf]) + assert_step([], 1, [-3, inf]) + assert_step([], 1, [3, -inf]) + assert_step([1.0], 1, [-3, -inf]) + assert_step([1.0], 1, [inf, inf]) + assert_step([], 1, [inf, -inf]) + assert_step([], 1, [-inf, inf]) + assert_step([1.0], 1, [-inf, -inf]) + assert_step([], inf, [2]) + assert_step([], inf, [-2]) + assert_step([], inf, [2, 3]) + assert_step([inf, inf, inf], inf, [2, -3], inf: true) + assert_step([], inf, [2, inf]) + assert_step([inf], inf, [2, -inf]) + assert_step([], inf, [-2, inf]) + assert_step([inf], inf, [-2, -inf]) + assert_step([], inf, [-2, 3]) + assert_step([inf, inf, inf], inf, [-2, -3], inf: true) + assert_step([inf], inf, [inf]) + assert_step([], inf, [-inf]) + assert_step([inf], inf, [inf, inf]) + assert_step([inf], inf, [inf, -inf]) + assert_step([inf], inf, [-inf, -inf]) + assert_step([-inf, -inf, -inf], -inf, [2], inf: true) + assert_step([-inf, -inf, -inf], -inf, [-2], inf: true) + assert_step([-inf, -inf, -inf], -inf, [2, 3], inf: true) + assert_step([], -inf, [2, -3]) + assert_step([-inf], -inf, [2, inf]) + assert_step([], -inf, [2, -inf]) + assert_step([-inf], -inf, [-2, inf]) + assert_step([], -inf, [-2, -inf]) + assert_step([-inf, -inf, -inf], -inf, [-2, 3], inf: true) + assert_step([], -inf, [-2, -3]) + assert_step([-inf, -inf, -inf], -inf, [inf], inf: true) + assert_step([-inf], -inf, [-inf]) + assert_step([-inf], -inf, [inf, inf]) + assert_step([], -inf, [inf, -inf]) + assert_step([-inf], -inf, [-inf, -inf]) end -- cgit v1.2.3 From 0a79486380d6991cf6adc015de65d9758d1584e3 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Mon, 8 Jul 2019 22:14:23 +0900 Subject: Add macros for inline symbol for readability --- src/symbol.c | 65 ++++++++++++++++++++++++++++++------------------------------ 1 file changed, 33 insertions(+), 32 deletions(-) diff --git a/src/symbol.c b/src/symbol.c index 5eeb28045..38843c71f 100644 --- a/src/symbol.c +++ b/src/symbol.c @@ -20,6 +20,22 @@ typedef struct symbol_name { const char *name; } symbol_name; +#define SYMBOL_INLINE_BIT 1 +#define SYMBOL_INLINE_LOWER_BIT 2 +#define SYMBOL_INLINE (1 << (SYMBOL_INLINE_BIT - 1)) +#define SYMBOL_INLINE_LOWER (1 << (SYMBOL_INLINE_LOWER_BIT - 1)) +#define SYMBOL_NORMAL_SHIFT SYMBOL_INLINE_BIT +#define SYMBOL_INLINE_SHIFT SYMBOL_INLINE_LOWER_BIT +#ifdef MRB_ENABLE_ALL_SYMBOLS +# define SYMBOL_INLINE_P(sym) FALSE +# define SYMBOL_INLINE_LOWER_P(sym) FALSE +# define sym_inline_pack(name, len) 0 +# define sym_inline_unpack(sym, buf, lenp) NULL +#else +# define SYMBOL_INLINE_P(sym) ((sym) & SYMBOL_INLINE) +# define SYMBOL_INLINE_LOWER_P(sym) ((sym) & SYMBOL_INLINE_LOWER) +#endif + static void sym_validate_len(mrb_state *mrb, size_t len) { @@ -41,7 +57,7 @@ sym_inline_pack(const char *name, uint16_t len) const char *p; int i; mrb_sym sym = 0; - int lower = 1; + mrb_bool lower = TRUE; if (len > lower_length_max) return 0; /* too long */ for (i=0; i 27) lower = 0; + if (bits > 27) lower = FALSE; if (i >= mix_length_max) break; - sym |= bits<<(i*6+2); + sym |= bits<<(i*6+SYMBOL_INLINE_SHIFT); } if (lower) { sym = 0; @@ -64,24 +80,24 @@ sym_inline_pack(const char *name, uint16_t len) c = name[i]; p = strchr(pack_table, (int)c); bits = (uint32_t)(p - pack_table)+1; - sym |= bits<<(i*5+2); + sym |= bits<<(i*5+SYMBOL_INLINE_SHIFT); } - return sym | 3; + return sym | SYMBOL_INLINE | SYMBOL_INLINE_LOWER; } if (len > mix_length_max) return 0; - return sym | 1; + return sym | SYMBOL_INLINE; } static const char* sym_inline_unpack(mrb_sym sym, char *buf, mrb_int *lenp) { - int bit_per_char = sym&2 ? 5 : 6; /* all lower case if `sym&2` is true */ + int bit_per_char = SYMBOL_INLINE_LOWER_P(sym) ? 5 : 6; int i; - mrb_assert(sym&1); + mrb_assert(SYMBOL_INLINE_P(sym)); for (i=0; i<30/bit_per_char; i++) { - uint32_t bits = sym>>(i*bit_per_char+2) & ((1<>(i*bit_per_char+SYMBOL_INLINE_SHIFT) & ((1< 0) return i; -#endif i = mrb->symhash[hash]; if (i == 0) return 0; do { sname = &mrb->symtbl[i]; if (sname->len == len && memcmp(sname->name, name, len) == 0) { - return i<<1; + return i<prev == 0xff) { i -= 0xff; sname = &mrb->symtbl[i]; while (mrb->symtbl < sname) { if (sname->len == len && memcmp(sname->name, name, len) == 0) { - return (mrb_sym)(sname - mrb->symtbl)<<1; + return (mrb_sym)(sname - mrb->symtbl)<symhash[hash] = sym; - return sym<<1; + return sym<>= 1; + sym >>= SYMBOL_NORMAL_SHIFT; if (sym == 0 || mrb->symidx < sym) { if (lenp) *lenp = 0; return NULL; @@ -503,11 +513,7 @@ mrb_sym2str(mrb_state *mrb, mrb_sym sym) const char *name = mrb_sym2name_len(mrb, sym, &len); if (!name) return mrb_undef_value(); /* can't happen */ -#ifndef MRB_ENABLE_ALL_SYMBOLS - if (sym&1) { /* inline symbol */ - return mrb_str_new(mrb, name, len); - } -#endif + if (SYMBOL_INLINE_P(sym)) return mrb_str_new(mrb, name, len); return mrb_str_new_static(mrb, name, len); } @@ -522,13 +528,8 @@ mrb_sym2name(mrb_state *mrb, mrb_sym sym) return name; } else { - mrb_value str; -#ifndef MRB_ENABLE_ALL_SYMBOLS - if (sym&1) /* inline symbol */ - str = mrb_str_new(mrb, name, len); - else -#endif - str = mrb_str_new_static(mrb, name, len); + mrb_value str = SYMBOL_INLINE_P(sym) ? + mrb_str_new(mrb, name, len) : mrb_str_new_static(mrb, name, len); str = mrb_str_dump(mrb, str); return RSTRING_PTR(str); } -- cgit v1.2.3 From c8a7d0ab9541a4297d3885842c5fc1343fe5ea99 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Tue, 9 Jul 2019 13:13:13 +0900 Subject: Fix the order of "expected" and "actual" in `test/t/range.rb` --- test/t/range.rb | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/test/t/range.rb b/test/t/range.rb index d71fe8946..106c2866e 100644 --- a/test/t/range.rb +++ b/test/t/range.rb @@ -101,12 +101,12 @@ end assert('Range#dup') do r = (1..3).dup - assert_equal r.begin, 1 - assert_equal r.end, 3 + assert_equal 1, r.begin + assert_equal 3, r.end assert_false r.exclude_end? r = ("a"..."z").dup - assert_equal r.begin, "a" - assert_equal r.end, "z" + assert_equal "a", r.begin + assert_equal "z", r.end assert_true r.exclude_end? end -- cgit v1.2.3 From f7d59dfe23b6fed5a6dc0720144eeaebb407efbb Mon Sep 17 00:00:00 2001 From: Ryan Lopopolo Date: Mon, 8 Jul 2019 20:10:24 -0700 Subject: Add tests for Range#max and Range#min --- test/t/range.rb | 42 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/test/t/range.rb b/test/t/range.rb index d71fe8946..7ce4a7a94 100644 --- a/test/t/range.rb +++ b/test/t/range.rb @@ -110,3 +110,45 @@ assert('Range#dup') do assert_equal r.end, "z" assert_true r.exclude_end? end + +assert('Range#max') do + assert_equal 10, (1..10).max + assert_equal 9, (1...10).max + assert_equal nil, (10..1).max + assert_equal nil, (10...1).max + + # equal endpoints + assert_equal 5, (5..5).max + assert_equal nil, (5...5).max + + # block overrides comparison + assert_equal(10, (1..10).max { |a, b| a <=> b }) + assert_equal(9, (1...10).max { |a, b| a <=> b }) + assert_equal(nil, (10..1).max { |a, b| a <=> b }) + assert_equal(nil, (10...1).max { |a, b| a <=> b }) + assert_equal(1, (1..10).max { |a, b| b <=> a }) + assert_equal(1, (1...10).max { |a, b| b <=> a }) + assert_equal(nil, (10..1).max { |a, b| b <=> a }) + assert_equal(nil, (10...1).max { |a, b| b <=> a }) +end + +assert('Range#min') do + assert_equal 1, (1..10).min + assert_equal 1, (1...10).min + assert_equal nil, (10..1).min + assert_equal nil, (10...1).min + + # equal endpoints + assert_equal 7, (7..7).min + assert_equal nil, (7...7).min + + # block overrides comparison + assert_equal(1, (1..10).min { |a, b| a <=> b }) + assert_equal(1, (1...10).min { |a, b| a <=> b }) + assert_equal(nil, (10..1).min { |a, b| a <=> b }) + assert_equal(nil, (10...1).min { |a, b| a <=> b }) + assert_equal(10, (1..10).min { |a, b| b <=> a }) + assert_equal(9, (1...10).min { |a, b| b <=> a }) + assert_equal(nil, (10..1).min { |a, b| b <=> a }) + assert_equal(nil, (10...1).min { |a, b| b <=> a }) +end -- cgit v1.2.3 From 469c6261c69999aab9e0d19cea6ac8e03f7847e3 Mon Sep 17 00:00:00 2001 From: Ryan Lopopolo Date: Mon, 8 Jul 2019 22:35:12 -0700 Subject: Add tests for String Ranges Range#each depends on String#upto which is implemented in mruby-string-ext which is why these tests live there. --- mrbgems/mruby-string-ext/test/range.rb | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 mrbgems/mruby-string-ext/test/range.rb diff --git a/mrbgems/mruby-string-ext/test/range.rb b/mrbgems/mruby-string-ext/test/range.rb new file mode 100644 index 000000000..4b42cd3a6 --- /dev/null +++ b/mrbgems/mruby-string-ext/test/range.rb @@ -0,0 +1,12 @@ +assert('Range#max') do + # string Range depends on String#upto + assert_equal 'l', ('f'..'l').max + assert_equal 'e', ('a'...'f').max + assert_equal nil, ('z'..'l').max +end + +assert('Range#min') do + # string Range depends on String#upto + assert_equal 'f', ('f'..'l').min + assert_equal nil, ('z'..'l').min +end -- cgit v1.2.3 From 4085709ae1736fb755955d3d52b6b73c15853506 Mon Sep 17 00:00:00 2001 From: Ryan Lopopolo Date: Mon, 8 Jul 2019 19:23:24 -0700 Subject: Specialize Enumerable#max and Enumerable#min for Range This patch prevents a hang for pathalogical (large) Ranges when computing max and min. Range inherits its implementation of max and min from Enumerable. Enumerable implements max and min by calling each. For Range objects, this is unnecessary since we know the max and the min by the end and begin attributes. It is also very slow. This code hangs unnecessarily: (0..2**32).max # ... hang (0..2**32).min # ... hang This patch overrides max and min after including enumerable to yield based on the begin and end methods. --- mrblib/range.rb | 66 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 65 insertions(+), 1 deletion(-) diff --git a/mrblib/range.rb b/mrblib/range.rb index 392cc2274..746cb322c 100644 --- a/mrblib/range.rb +++ b/mrblib/range.rb @@ -15,7 +15,8 @@ class Range val = self.first last = self.last - if val.kind_of?(Fixnum) && last.kind_of?(Fixnum) # fixnums are special + # numerics are special + if (val.kind_of?(Fixnum) || val.kind_of?(Float)) && (last.kind_of?(Fixnum) || last.kind_of?(Float)) lim = last lim += 1 unless exclude_end? i = val @@ -64,4 +65,67 @@ end # ISO 15.2.14.3 class Range include Enumerable + + def max(&block) + val = self.first + last = self.last + # numerics are special + if (val.kind_of?(Fixnum) || val.kind_of?(Float)) && (last.kind_of?(Fixnum) || last.kind_of?(Float)) + return nil if val > last + return nil if val == last && exclude_end? + + max = last + max -= 1 if exclude_end? + max = val if block && block.call(val, last) > 0 + return max + end + + max = nil + each do |item| + max = + if max.nil? + item + elsif block && block.call(max, item) > 0 + item + elsif item > max + item + else + max + end + end + max + end + + def min(&block) + val = self.first + last = self.last + + # numerics are special + if (val.kind_of?(Fixnum) || val.kind_of?(Float)) && (last.kind_of?(Fixnum) || last.kind_of?(Float)) + return nil if val > last + return nil if val == last && exclude_end? + + min = val + if block && block.call(val, last) > 0 + min = last + min -= 1 if exclude_end? + end + return min + end + + min = nil + each do |item| + min = + if min.nil? + item + elsif block && block.call(min, item) < 0 + item + elsif item < min + item + else + min + end + end + min + end end -- cgit v1.2.3 From d9c530379343ef0dd0f314c982ddeedea8eb1a60 Mon Sep 17 00:00:00 2001 From: Ryan Lopopolo Date: Tue, 9 Jul 2019 01:40:44 -0700 Subject: Remove attempt at spec-compliant Range#max and Range#min from core --- mrblib/range.rb | 63 --------------------------------------------------------- test/t/range.rb | 42 -------------------------------------- 2 files changed, 105 deletions(-) diff --git a/mrblib/range.rb b/mrblib/range.rb index 746cb322c..3e6dbfb24 100644 --- a/mrblib/range.rb +++ b/mrblib/range.rb @@ -65,67 +65,4 @@ end # ISO 15.2.14.3 class Range include Enumerable - - def max(&block) - val = self.first - last = self.last - # numerics are special - if (val.kind_of?(Fixnum) || val.kind_of?(Float)) && (last.kind_of?(Fixnum) || last.kind_of?(Float)) - return nil if val > last - return nil if val == last && exclude_end? - - max = last - max -= 1 if exclude_end? - max = val if block && block.call(val, last) > 0 - return max - end - - max = nil - each do |item| - max = - if max.nil? - item - elsif block && block.call(max, item) > 0 - item - elsif item > max - item - else - max - end - end - max - end - - def min(&block) - val = self.first - last = self.last - - # numerics are special - if (val.kind_of?(Fixnum) || val.kind_of?(Float)) && (last.kind_of?(Fixnum) || last.kind_of?(Float)) - return nil if val > last - return nil if val == last && exclude_end? - - min = val - if block && block.call(val, last) > 0 - min = last - min -= 1 if exclude_end? - end - return min - end - - min = nil - each do |item| - min = - if min.nil? - item - elsif block && block.call(min, item) < 0 - item - elsif item < min - item - else - min - end - end - min - end end diff --git a/test/t/range.rb b/test/t/range.rb index 7ce4a7a94..d71fe8946 100644 --- a/test/t/range.rb +++ b/test/t/range.rb @@ -110,45 +110,3 @@ assert('Range#dup') do assert_equal r.end, "z" assert_true r.exclude_end? end - -assert('Range#max') do - assert_equal 10, (1..10).max - assert_equal 9, (1...10).max - assert_equal nil, (10..1).max - assert_equal nil, (10...1).max - - # equal endpoints - assert_equal 5, (5..5).max - assert_equal nil, (5...5).max - - # block overrides comparison - assert_equal(10, (1..10).max { |a, b| a <=> b }) - assert_equal(9, (1...10).max { |a, b| a <=> b }) - assert_equal(nil, (10..1).max { |a, b| a <=> b }) - assert_equal(nil, (10...1).max { |a, b| a <=> b }) - assert_equal(1, (1..10).max { |a, b| b <=> a }) - assert_equal(1, (1...10).max { |a, b| b <=> a }) - assert_equal(nil, (10..1).max { |a, b| b <=> a }) - assert_equal(nil, (10...1).max { |a, b| b <=> a }) -end - -assert('Range#min') do - assert_equal 1, (1..10).min - assert_equal 1, (1...10).min - assert_equal nil, (10..1).min - assert_equal nil, (10...1).min - - # equal endpoints - assert_equal 7, (7..7).min - assert_equal nil, (7...7).min - - # block overrides comparison - assert_equal(1, (1..10).min { |a, b| a <=> b }) - assert_equal(1, (1...10).min { |a, b| a <=> b }) - assert_equal(nil, (10..1).min { |a, b| a <=> b }) - assert_equal(nil, (10...1).min { |a, b| a <=> b }) - assert_equal(10, (1..10).min { |a, b| b <=> a }) - assert_equal(9, (1...10).min { |a, b| b <=> a }) - assert_equal(nil, (10..1).min { |a, b| b <=> a }) - assert_equal(nil, (10...1).min { |a, b| b <=> a }) -end -- cgit v1.2.3 From eab07daf92c9a8a2836923656d9e8f58583a52ba Mon Sep 17 00:00:00 2001 From: Ryan Lopopolo Date: Tue, 9 Jul 2019 01:41:10 -0700 Subject: Add Range#max and Range#min tests from Ruby Spec --- mrbgems/mruby-range-ext/test/range.rb | 101 +++++++++++++++++++++++++++++++++ mrbgems/mruby-string-ext/test/range.rb | 18 +++++- 2 files changed, 117 insertions(+), 2 deletions(-) diff --git a/mrbgems/mruby-range-ext/test/range.rb b/mrbgems/mruby-range-ext/test/range.rb index efcbdabe4..6b135aeff 100644 --- a/mrbgems/mruby-range-ext/test/range.rb +++ b/mrbgems/mruby-range-ext/test/range.rb @@ -30,3 +30,104 @@ assert('Range#size') do assert_equal Float::INFINITY, (0..Float::INFINITY).size assert_nil ('a'..'z').size end + +assert('Range#max') do + # returns the maximum value in the range when called with no arguments + assert_equal 10, (1..10).max + assert_equal 9, (1...10).max + assert_equal 4294967295, (0...2**32).max + + # returns the maximum value in the Float range when called with no arguments + assert_equal 908.1111, (303.20..908.1111).max + + # raises TypeError when called on an exclusive range and a non Integer value + assert_raise(TypeError) { (303.20...908.1111).max } + + # returns nil when the endpoint is less than the start point + assert_equal nil, (100..10).max + + # returns nil when the endpoint equals the start point and the range is exclusive + assert_equal nil, (5...5).max + + # returns the endpoint when the endpoint equals the start point and the range is inclusive + assert_equal 5, (5..5).max + + # returns nil when the endpoint is less than the start point in a Float range + assert_equal nil, (3003.20..908.1111).max +end + +assert('Range#max given a block') do + # passes each pair of values in the range to the block + acc = [] + (1..10).max do |a, b| + acc << a + acc << b + a + end + (1..10).each do |value| + assert_true acc.include?(value) + end + + # passes each pair of elements to the block in reversed order + acc = [] + (1..5).max do |a, b| + acc << [a, b] + a + end + assert_equal [[2, 1], [3, 2], [4, 3], [5, 4]], acc + + # returns the element the block determines to be the maximum + assert_equal 1, ((1..3).max { |_a, _b| -3 }) + + # returns nil when the endpoint is less than the start point + assert_equal nil, ((100..10).max { |x, y| x <=> y }) + assert_equal nil, ((5...5).max { |x, y| x <=> y }) +end + +assert('Range#min') do + # returns the minimum value in the range when called with no arguments + assert_equal 1, (1..10).min + + # returns the minimum value in the Float range when called with no arguments + assert_equal 303.20, (303.20..908.1111).min + + # returns nil when the start point is greater than the endpoint + assert_equal nil, (100..10).min + + # returns nil when the endpoint equals the start point and the range is exclusive + assert_equal nil, (5...5).max + + # returns the endpoint when the endpoint equals the start point and the range is inclusive + assert_equal 5, (5..5).max + + # returns nil when the start point is greater than the endpoint in a Float range + assert_equal nil, (3003.20..908.1111).max +end + +assert('Range#min given a block') do + # passes each pair of values in the range to the block + acc = [] + (1..10).min do |a, b| + acc << a + acc << b + a + end + (1..10).each do |value| + assert_true acc.include?(value) + end + + # passes each pair of elements to the block in reversed order + acc = [] + (1..5).min do |a, b| + acc << [a, b] + a + end + assert_equal [[2, 1], [3, 1], [4, 1], [5, 1]], acc + + # returns the element the block determines to be the minimum + assert_equal 3, ((1..3).min { |_a, _b| -3 }) + + # returns nil when the start point is greater than the endpoint + assert_equal nil, ((100..10).min { |x, y| x <=> y }) + assert_equal nil, ((5...5).min { |x, y| x <=> y }) +end diff --git a/mrbgems/mruby-string-ext/test/range.rb b/mrbgems/mruby-string-ext/test/range.rb index 4b42cd3a6..80c286850 100644 --- a/mrbgems/mruby-string-ext/test/range.rb +++ b/mrbgems/mruby-string-ext/test/range.rb @@ -1,12 +1,26 @@ assert('Range#max') do - # string Range depends on String#upto + # returns the maximum value in the range when called with no arguments assert_equal 'l', ('f'..'l').max assert_equal 'e', ('a'...'f').max + + # returns nil when the endpoint is less than the start point assert_equal nil, ('z'..'l').max end +assert('Range#max given a block') do + # returns nil when the endpoint is less than the start point + assert_equal nil, (('z'..'l').max { |x, y| x <=> y }) +end + assert('Range#min') do - # string Range depends on String#upto + # returns the minimum value in the range when called with no arguments assert_equal 'f', ('f'..'l').min + + # returns nil when the start point is greater than the endpoint assert_equal nil, ('z'..'l').min end + +assert('Range#min given a block') do + # returns nil when the start point is greater than the endpoint + assert_equal nil, (('z'..'l').min { |x, y| x <=> y }) +end -- cgit v1.2.3 From 0ad5ba7a0f819cff87460d9b6f5691656ea75ade Mon Sep 17 00:00:00 2001 From: Ryan Lopopolo Date: Tue, 9 Jul 2019 01:42:40 -0700 Subject: Add a fast path for Float and Fixnum ranges for Range#max and Range#min If no block is given and the Range has Fixnum or Float endpoints, do not iterate with each and instead compare the endpoints directly. This implementation passes all of the applicable specs from Ruby Spec. --- mrbgems/mruby-range-ext/mrblib/range.rb | 40 +++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/mrbgems/mruby-range-ext/mrblib/range.rb b/mrbgems/mruby-range-ext/mrblib/range.rb index de7925ba7..e09b2d096 100644 --- a/mrbgems/mruby-range-ext/mrblib/range.rb +++ b/mrbgems/mruby-range-ext/mrblib/range.rb @@ -25,4 +25,44 @@ class Range end ary end + + def max(&block) + val = self.first + last = self.last + return super if block + + # fast path for numerics + if (val.kind_of?(Fixnum) || val.kind_of?(Float)) && (last.kind_of?(Fixnum) || last.kind_of?(Float)) + raise TypeError if exclude_end? && !last.kind_of?(Fixnum) + return nil if val > last + return nil if val == last && exclude_end? + + max = last + max -= 1 if exclude_end? + return max + end + + # delegate to Enumerable + super + end + + def min(&block) + val = self.first + last = self.last + return super if block + + # fast path for numerics + if (val.kind_of?(Fixnum) || val.kind_of?(Float)) && (last.kind_of?(Fixnum) || last.kind_of?(Float)) + raise TypeError if exclude_end? && !last.kind_of?(Fixnum) + return nil if val > last + return nil if val == last && exclude_end? + + min = val + min -= 1 if exclude_end? + return min + end + + # delegate to Enumerable + super + end end -- cgit v1.2.3 From 56929362f58ba5ad3ebe4131a6cc4259e6479dc0 Mon Sep 17 00:00:00 2001 From: Ryan Lopopolo Date: Tue, 9 Jul 2019 01:48:15 -0700 Subject: Fix Range#min fast path with exclusive range --- mrbgems/mruby-range-ext/mrblib/range.rb | 1 - mrbgems/mruby-range-ext/test/range.rb | 1 + 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/mrbgems/mruby-range-ext/mrblib/range.rb b/mrbgems/mruby-range-ext/mrblib/range.rb index e09b2d096..a149a57dc 100644 --- a/mrbgems/mruby-range-ext/mrblib/range.rb +++ b/mrbgems/mruby-range-ext/mrblib/range.rb @@ -58,7 +58,6 @@ class Range return nil if val == last && exclude_end? min = val - min -= 1 if exclude_end? return min end diff --git a/mrbgems/mruby-range-ext/test/range.rb b/mrbgems/mruby-range-ext/test/range.rb index 6b135aeff..b56d6b58e 100644 --- a/mrbgems/mruby-range-ext/test/range.rb +++ b/mrbgems/mruby-range-ext/test/range.rb @@ -87,6 +87,7 @@ end assert('Range#min') do # returns the minimum value in the range when called with no arguments assert_equal 1, (1..10).min + assert_equal 1, (1...10).min # returns the minimum value in the Float range when called with no arguments assert_equal 303.20, (303.20..908.1111).min -- cgit v1.2.3 From 3b77b5fd394f9c9ba841e7bea8ea62dc6e8a3a1b Mon Sep 17 00:00:00 2001 From: Ryan Lopopolo Date: Tue, 9 Jul 2019 02:08:14 -0700 Subject: Revert Float dependency in Range#each --- mrblib/range.rb | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/mrblib/range.rb b/mrblib/range.rb index 3e6dbfb24..392cc2274 100644 --- a/mrblib/range.rb +++ b/mrblib/range.rb @@ -15,8 +15,7 @@ class Range val = self.first last = self.last - # numerics are special - if (val.kind_of?(Fixnum) || val.kind_of?(Float)) && (last.kind_of?(Fixnum) || last.kind_of?(Float)) + if val.kind_of?(Fixnum) && last.kind_of?(Fixnum) # fixnums are special lim = last lim += 1 unless exclude_end? i = val -- cgit v1.2.3 From 23fc3339eedf685e358c9389b4f6b8bd068bcad2 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Tue, 9 Jul 2019 18:59:00 +0900 Subject: Set `MRB_STR_ASCII` flag when an inline symbol is stringized --- src/symbol.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/symbol.c b/src/symbol.c index 38843c71f..53f4f6e1d 100644 --- a/src/symbol.c +++ b/src/symbol.c @@ -494,7 +494,7 @@ sym_inspect(mrb_state *mrb, mrb_value sym) name = mrb_sym2name_len(mrb, id, &len); str = mrb_str_new(mrb, 0, len+1); sp = RSTRING_PTR(str); - RSTRING_PTR(str)[0] = ':'; + sp[0] = ':'; memcpy(sp+1, name, len); mrb_assert_int_fit(mrb_int, len, size_t, SIZE_MAX); if (!symname_p(name) || strlen(name) != (size_t)len) { @@ -503,6 +503,9 @@ sym_inspect(mrb_state *mrb, mrb_value sym) sp[0] = ':'; sp[1] = '"'; } +#ifdef MRB_UTF8_STRING + if (SYMBOL_INLINE_P(id)) RSTR_SET_ASCII_FLAG(mrb_str_ptr(str)); +#endif return str; } @@ -513,7 +516,11 @@ mrb_sym2str(mrb_state *mrb, mrb_sym sym) const char *name = mrb_sym2name_len(mrb, sym, &len); if (!name) return mrb_undef_value(); /* can't happen */ - if (SYMBOL_INLINE_P(sym)) return mrb_str_new(mrb, name, len); + if (SYMBOL_INLINE_P(sym)) { + mrb_value str = mrb_str_new(mrb, name, len); + RSTR_SET_ASCII_FLAG(mrb_str_ptr(str)); + return str; + } return mrb_str_new_static(mrb, name, len); } -- cgit v1.2.3 From 80f78ca196790e2900b89f447c5ab83433d69d89 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Wed, 10 Jul 2019 21:53:17 +0900 Subject: Remove an unused argument of `str_with_class()` --- src/string.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/string.c b/src/string.c index 078c028d8..3ef86eb53 100644 --- a/src/string.c +++ b/src/string.c @@ -83,7 +83,7 @@ str_new(mrb_state *mrb, const char *p, size_t len) } static inline void -str_with_class(mrb_state *mrb, struct RString *s, mrb_value obj) +str_with_class(struct RString *s, mrb_value obj) { s->c = mrb_str_ptr(obj)->c; } @@ -93,7 +93,7 @@ mrb_str_new_empty(mrb_state *mrb, mrb_value str) { struct RString *s = str_new(mrb, 0, 0); - str_with_class(mrb, s, str); + str_with_class(s, str); return mrb_obj_value(s); } @@ -830,7 +830,7 @@ mrb_str_times(mrb_state *mrb, mrb_value self) len = RSTRING_LEN(self)*times; str2 = str_new(mrb, 0, len); - str_with_class(mrb, str2, self); + str_with_class(str2, self); p = RSTR_PTR(str2); if (len > 0) { n = RSTRING_LEN(self); @@ -1011,7 +1011,7 @@ mrb_str_dup(mrb_state *mrb, mrb_value str) struct RString *s = mrb_str_ptr(str); struct RString *dup = str_new(mrb, 0, 0); - str_with_class(mrb, dup, str); + str_with_class(dup, str); return str_replace(mrb, dup, s); } @@ -2561,7 +2561,7 @@ mrb_str_dump(mrb_state *mrb, mrb_value str) } result = str_new(mrb, 0, len); - str_with_class(mrb, result, str); + str_with_class(result, str); p = RSTRING_PTR(str); pend = p + RSTRING_LEN(str); q = RSTR_PTR(result); *q++ = '"'; -- cgit v1.2.3 From 8c0d9ba1a363683bbeab8cb7c22acdb07621352d Mon Sep 17 00:00:00 2001 From: dearblue Date: Thu, 11 Jul 2019 21:52:05 +0900 Subject: Improve performance `String#index` with UTF-8 Based on Boyer-Moore-Horspool algorithm (Quick Search algorithm). As a side effect, the correct position is returned even if an invalid UTF-8 string is given. ```console % ./mruby@master -e 'p ("\xd1" * 100 + "#").index("#")' 50 % ./mruby@improve-index -e 'p ("\xd1" * 100 + "#").index("#")' 100 ``` The other behavior should be the same as the current implementation. --- src/string.c | 68 +++++++++++++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 63 insertions(+), 5 deletions(-) diff --git a/src/string.c b/src/string.c index 3ef86eb53..0700f81fa 100644 --- a/src/string.c +++ b/src/string.c @@ -304,12 +304,73 @@ bytes2chars(char *p, mrb_int bi) return i; } +static mrb_int +str_index_str_by_char_search(mrb_state *mrb, const char *p, const char *pend, const char *s, const mrb_int slen, mrb_int off) +{ + /* Based on Quick Search algorithm (Boyer-Moore-Horspool algorithm) */ + + ptrdiff_t qstable[1 << CHAR_BIT]; + + /* Preprocessing */ + { + size_t i; + + for (i = 0; i < 1 << CHAR_BIT; i ++) { + qstable[i] = slen; + } + for (i = 0; i < slen; i ++) { + qstable[(unsigned char)s[i]] = slen - (i + 1); + } + } + + /* Searching */ + if (p < pend && pend - p >= slen) { + for (;;) { + const char *pivot; + + if (memcmp(p, s, slen) == 0) { + return off; + } + + pivot = p + qstable[(unsigned char)p[slen - 1]]; + if (pivot > pend || pivot < p /* overflowed */) { return -1; } + + do { + p += utf8len(p, pend); + off ++; + } while (p < pivot); + } + } + + return -1; +} + +static mrb_int +str_index_str_by_char(mrb_state *mrb, mrb_value str, mrb_value sub, mrb_int pos) +{ + const char *p = RSTRING_PTR(str); + const char *pend = p + RSTRING_LEN(str); + const char *s = RSTRING_PTR(sub); + const mrb_int slen = RSTRING_LEN(sub); + mrb_int off = pos; + + for (; pos > 0; pos --) { + if (pend - p < 1) { return -1; } + p += utf8len(p, pend); + } + + if (slen < 1) { return off; } + + return str_index_str_by_char_search(mrb, p, pend, s, slen, off); +} + #define BYTES_ALIGN_CHECK(pos) if (pos < 0) return mrb_nil_value(); #else #define RSTRING_CHAR_LEN(s) RSTRING_LEN(s) #define chars2bytes(p, off, ci) (ci) #define bytes2chars(p, bi) (bi) #define BYTES_ALIGN_CHECK(pos) +#define str_index_str_by_char(mrb, str, sub, pos) str_index_str(mrb, str, sub, pos) #endif static inline mrb_int @@ -1680,15 +1741,13 @@ mrb_str_index_m(mrb_state *mrb, mrb_value str) else sub = mrb_nil_value(); } - clen = RSTRING_CHAR_LEN(str); if (pos < 0) { + clen = RSTRING_CHAR_LEN(str); pos += clen; if (pos < 0) { return mrb_nil_value(); } } - if (pos > clen) return mrb_nil_value(); - pos = chars2bytes(str, 0, pos); switch (mrb_type(sub)) { default: { @@ -1702,12 +1761,11 @@ mrb_str_index_m(mrb_state *mrb, mrb_value str) } /* fall through */ case MRB_TT_STRING: - pos = str_index_str(mrb, str, sub, pos); + pos = str_index_str_by_char(mrb, str, sub, pos); break; } if (pos == -1) return mrb_nil_value(); - pos = bytes2chars(RSTRING_PTR(str), pos); BYTES_ALIGN_CHECK(pos); return mrb_fixnum_value(pos); } -- cgit v1.2.3 From e4249b1b9e1c568546865287bf367e4501c263de Mon Sep 17 00:00:00 2001 From: dearblue Date: Thu, 11 Jul 2019 22:00:01 +0900 Subject: Add UTF-8 test for `String#index` --- test/t/string.rb | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/test/t/string.rb b/test/t/string.rb index 87d60ed72..cf145f97e 100644 --- a/test/t/string.rb +++ b/test/t/string.rb @@ -468,6 +468,17 @@ assert('String#index', '15.2.10.5.22') do assert_equal nil, "hello".index("", 6) end +assert('String#index(UTF-8)', '15.2.10.5.22') do + assert_equal 0, '⓿➊➋➌➍➎'.index('⓿') + assert_nil '⓿➊➋➌➍➎'.index('➓') + assert_equal 6, '⓿➊➋➌➍➎⓿➊➋➌➍➎'.index('⓿', 1) + assert_equal 6, "⓿➊➋➌➍➎".index("", 6) + assert_equal nil, "⓿➊➋➌➍➎".index("", 7) + assert_equal 0, '⓿➊➋➌➍➎'.index("\xe2") + assert_equal nil, '⓿➊➋➌➍➎'.index("\xe3") + assert_equal 6, "\xd1\xd1\xd1\xd1\xd1\xd1⓿➊➋➌➍➎".index('⓿') +end if UTF8STRING + assert('String#initialize', '15.2.10.5.23') do a = '' a.initialize('abc') -- cgit v1.2.3 From 66909dfe8650e242ed96c26e576498d290ece347 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Thu, 11 Jul 2019 23:56:45 +0900 Subject: Consider `-MP` flag specified when parsing `.d` file `-MP` flag is used in `tasks/toolchains/android.rake`. --- lib/mruby/build/command.rb | 35 +++++++++++++++++++++++++++++++---- 1 file changed, 31 insertions(+), 4 deletions(-) diff --git a/lib/mruby/build/command.rb b/lib/mruby/build/command.rb index 0f18e0e62..d4354225e 100644 --- a/lib/mruby/build/command.rb +++ b/lib/mruby/build/command.rb @@ -127,13 +127,40 @@ module MRuby end private + + # + # === Example of +.d+ file + # + # ==== Without -MP compiler flag + # + # /build/host/src/array.o: \ + # /src/array.c \ + # /include/mruby/common.h \ + # /include/mruby/value.h \ + # /src/value_array.h + # + # ==== With -MP compiler flag + # + # /build/host/src/array.o: \ + # /src/array.c \ + # /include/mruby/common.h \ + # /include/mruby/value.h \ + # /src/value_array.h + # + # /include/mruby/common.h: + # + # /include/mruby/value.h: + # + # /src/value_array.h: + # def get_dependencies(file) file = file.ext('d') unless File.extname(file) == '.d' + deps = [] if File.exist?(file) - File.read(file).gsub("\\\n ", "").scan(/^\S+:\s+(.+)$/).flatten.map {|s| s.split(' ') }.flatten - else - [] - end + [ MRUBY_CONFIG ] + File.foreach(file){|line| deps << $1 if /^ +(.*?)(?: *\\)?$/ =~ line} + deps.uniq! + end + deps << MRUBY_CONFIG end end -- cgit v1.2.3 From 16e4657acdacfd99bd649d50b44a748d86a31861 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Fri, 12 Jul 2019 18:35:20 +0900 Subject: Lazy load `tasks/toolchains/*.rake` --- lib/mruby/build.rb | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/lib/mruby/build.rb b/lib/mruby/build.rb index 887a5518e..d9d52948b 100644 --- a/lib/mruby/build.rb +++ b/lib/mruby/build.rb @@ -22,7 +22,6 @@ module MRuby def initialize(name, &block) @name, @initializer = name.to_s, block - MRuby::Toolchain.toolchains ||= {} MRuby::Toolchain.toolchains[@name] = self end @@ -30,13 +29,8 @@ module MRuby conf.instance_exec(conf, params, &@initializer) end - def self.load - Dir.glob("#{MRUBY_ROOT}/tasks/toolchains/*.rake").each do |file| - Kernel.load file - end - end + self.toolchains = {} end - Toolchain.load class Build class << self @@ -196,10 +190,15 @@ EOS end def toolchain(name, params={}) - tc = Toolchain.toolchains[name.to_s] - fail "Unknown #{name} toolchain" unless tc + name = name.to_s + tc = Toolchain.toolchains[name] || begin + path = "#{MRUBY_ROOT}/tasks/toolchains/#{name}.rake" + fail "Unknown #{name} toolchain" unless File.exist?(path) + load path + Toolchain.toolchains[name] + end tc.setup(self, params) - @toolchains.unshift name.to_s + @toolchains.unshift name end def primary_toolchain -- cgit v1.2.3 From bde2f35a9f2d894ec88ad693633e89279b0560b9 Mon Sep 17 00:00:00 2001 From: dearblue Date: Fri, 12 Jul 2019 21:23:55 +0900 Subject: Fix heap buffer overflow; fix #4569 --- src/string.c | 24 +++++++++++------------- 1 file changed, 11 insertions(+), 13 deletions(-) diff --git a/src/string.c b/src/string.c index 0700f81fa..056348921 100644 --- a/src/string.c +++ b/src/string.c @@ -324,22 +324,20 @@ str_index_str_by_char_search(mrb_state *mrb, const char *p, const char *pend, co } /* Searching */ - if (p < pend && pend - p >= slen) { - for (;;) { - const char *pivot; + while (p < pend && pend - p >= slen) { + const char *pivot; - if (memcmp(p, s, slen) == 0) { - return off; - } + if (memcmp(p, s, slen) == 0) { + return off; + } - pivot = p + qstable[(unsigned char)p[slen - 1]]; - if (pivot > pend || pivot < p /* overflowed */) { return -1; } + pivot = p + qstable[(unsigned char)p[slen - 1]]; + if (pivot > pend || pivot < p /* overflowed */) { return -1; } - do { - p += utf8len(p, pend); - off ++; - } while (p < pivot); - } + do { + p += utf8len(p, pend); + off ++; + } while (p < pivot); } return -1; -- cgit v1.2.3 From 6b1cc6e2fe4eab30e265d8209a208e0bf942c54d Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Mon, 8 Jul 2019 18:40:13 +0900 Subject: Avoid `mrb_funcall()` if possible using `mrb_Float()`; ref #4555 --- src/numeric.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/numeric.c b/src/numeric.c index 0d1c23589..4288df44a 100644 --- a/src/numeric.c +++ b/src/numeric.c @@ -172,17 +172,17 @@ integral_div(mrb_state *mrb, mrb_value x) static mrb_value integral_coerce_step_counter(mrb_state *mrb, mrb_value self) { - mrb_value counter = self, num, step; + mrb_value num, step; mrb_get_args(mrb, "oo", &num, &step); #ifndef MRB_WITHOUT_FLOAT if (mrb_float_p(self) || mrb_float_p(num) || mrb_float_p(step)) { - counter = mrb_funcall(mrb, counter, "to_f", 0); + return mrb_Float(mrb, self); } #endif - return counter; + return self; } #ifndef MRB_WITHOUT_FLOAT -- cgit v1.2.3 From 9741df100bb84a858725dba58705a908e5bdca4c Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Sat, 13 Jul 2019 13:13:21 +0900 Subject: Change type of a variable for signedness mismatch; ref #4573 --- src/string.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/string.c b/src/string.c index 056348921..a6aa9d906 100644 --- a/src/string.c +++ b/src/string.c @@ -313,7 +313,7 @@ str_index_str_by_char_search(mrb_state *mrb, const char *p, const char *pend, co /* Preprocessing */ { - size_t i; + mrb_int i; for (i = 0; i < 1 << CHAR_BIT; i ++) { qstable[i] = slen; -- cgit v1.2.3 From a9fd2e646492699894d33eaf3de7336356ce6726 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Sat, 13 Jul 2019 13:16:30 +0900 Subject: Resolve ambiguous argument warning. --- mrbgems/mruby-complex/test/complex.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mrbgems/mruby-complex/test/complex.rb b/mrbgems/mruby-complex/test/complex.rb index ab882664e..5b7c3bfa4 100644 --- a/mrbgems/mruby-complex/test/complex.rb +++ b/mrbgems/mruby-complex/test/complex.rb @@ -50,7 +50,7 @@ assert 'Complex#-' do end assert 'Complex#-@' do - assert_complex -Complex(1, 2), (-1 - 2i) + assert_complex(-Complex(1, 2), (-1 - 2i)) end assert 'Complex#/' do -- cgit v1.2.3 From b4cdced22fe1f25d8cf6fc499a2e2c9875f17e9e Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Sat, 13 Jul 2019 18:05:01 +0900 Subject: `Enumerable#detect` {and `#find`} should call `ifnone`; fix #4484 It's an error in ISO specification; 15.3.2.2.4 and 15.3.2.2.7 --- mrblib/enum.rb | 16 +++++++--------- test/t/enumerable.rb | 4 ++-- 2 files changed, 9 insertions(+), 11 deletions(-) diff --git a/mrblib/enum.rb b/mrblib/enum.rb index 9bd74e1c4..fe40b4d27 100644 --- a/mrblib/enum.rb +++ b/mrblib/enum.rb @@ -65,22 +65,20 @@ module Enumerable end ## - # Call the given block for each element - # which is yield by +each+. Return - # +ifnone+ if no block value was true. - # Otherwise return the first block value - # which had was true. + # Return the first element for which + # value from the block is true. If no + # object matches, calls +ifnone+ and + # returns its result. Otherwise returns + # +nil+. # # ISO 15.3.2.2.4 def detect(ifnone=nil, &block) - ret = ifnone self.each{|*val| if block.call(*val) - ret = val.__svalue - break + return val.__svalue end } - ret + ifnone.call unless ifnone.nil? end ## diff --git a/test/t/enumerable.rb b/test/t/enumerable.rb index 652c304da..9e7602db7 100644 --- a/test/t/enumerable.rb +++ b/test/t/enumerable.rb @@ -45,7 +45,7 @@ end assert('Enumerable#detect', '15.3.2.2.4') do assert_equal 1, [1,2,3].detect() { true } - assert_equal 'a', [1,2,3].detect("a") { false } + assert_equal 'a', [1,2,3].detect(->{"a"}) { false } end assert('Array#each_with_index', '15.3.2.2.5') do @@ -64,7 +64,7 @@ end assert('Enumerable#find', '15.3.2.2.7') do assert_equal 1, [1,2,3].find() { true } - assert_equal 'a', [1,2,3].find("a") { false } + assert_equal 'a', [1,2,3].find(->{"a"}) { false } end assert('Enumerable#find_all', '15.3.2.2.8') do -- cgit v1.2.3 From e8a84d663f7ae76fc98920ae7e08882d129496bc Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Sat, 13 Jul 2019 20:41:56 +0900 Subject: Add `mruby-method` gem to `default.gembox` [ci skip] --- mrbgems/default.gembox | 3 +++ 1 file changed, 3 insertions(+) diff --git a/mrbgems/default.gembox b/mrbgems/default.gembox index 23e65fcee..9859c7d52 100644 --- a/mrbgems/default.gembox +++ b/mrbgems/default.gembox @@ -86,6 +86,9 @@ MRuby::GemBox.new do |conf| # Use class/module extension conf.gem :core => "mruby-class-ext" + # Use Method/UnboundMethod class + conf.gem :core => "mruby-method" + # Use mruby-compiler to build other mrbgems conf.gem :core => "mruby-compiler" end -- cgit v1.2.3 From c96b517ea28efe7f45a91873142d6449b2a4c59c Mon Sep 17 00:00:00 2001 From: dearblue Date: Sun, 14 Jul 2019 00:29:17 +0900 Subject: Error needed/conflicts configuration The purpose is to clarify the error if there is a needed/conflicts configuration at compile time. --- mrbgems/mruby-bin-debugger/tools/mrdb/mrdbconf.h | 4 ++++ mrbgems/mruby-math/src/math.c | 4 ++++ mrbgems/mruby-random/src/random.c | 4 ++++ mrbgems/mruby-range-ext/src/range.c | 4 ++++ mrbgems/mruby-time/src/time.c | 4 ++++ 5 files changed, 20 insertions(+) diff --git a/mrbgems/mruby-bin-debugger/tools/mrdb/mrdbconf.h b/mrbgems/mruby-bin-debugger/tools/mrdb/mrdbconf.h index f17f9c57d..de2f90144 100644 --- a/mrbgems/mruby-bin-debugger/tools/mrdb/mrdbconf.h +++ b/mrbgems/mruby-bin-debugger/tools/mrdb/mrdbconf.h @@ -6,6 +6,10 @@ #ifndef MRDBCONF_H #define MRDBCONF_H +#ifndef MRB_ENABLE_DEBUG_HOOK +# error Need 'MRB_ENABLE_DEBUG_HOOK' configuration in your 'build_config.rb' +#endif + /* configuration options: */ /* maximum size for command buffer */ #define MAX_COMMAND_LINE 1024 diff --git a/mrbgems/mruby-math/src/math.c b/mrbgems/mruby-math/src/math.c index caa16b789..35fcd0fa6 100644 --- a/mrbgems/mruby-math/src/math.c +++ b/mrbgems/mruby-math/src/math.c @@ -4,6 +4,10 @@ ** See Copyright Notice in mruby.h */ +#ifdef MRB_WITHOUT_FLOAT +# error Conflict 'MRB_WITHOUT_FLOAT' configuration in your 'build_config.rb' +#endif + #include #include diff --git a/mrbgems/mruby-random/src/random.c b/mrbgems/mruby-random/src/random.c index 68209840a..99f2b02e4 100644 --- a/mrbgems/mruby-random/src/random.c +++ b/mrbgems/mruby-random/src/random.c @@ -4,6 +4,10 @@ ** See Copyright Notice in mruby.h */ +#ifdef MRB_WITHOUT_FLOAT +# error Conflict 'MRB_WITHOUT_FLOAT' configuration in your 'build_config.rb' +#endif + #include #include #include diff --git a/mrbgems/mruby-range-ext/src/range.c b/mrbgems/mruby-range-ext/src/range.c index 1f6690904..fb76fe0d8 100644 --- a/mrbgems/mruby-range-ext/src/range.c +++ b/mrbgems/mruby-range-ext/src/range.c @@ -1,3 +1,7 @@ +#ifdef MRB_WITHOUT_FLOAT +# error Conflict 'MRB_WITHOUT_FLOAT' configuration in your 'build_config.rb' +#endif + #include #include #include diff --git a/mrbgems/mruby-time/src/time.c b/mrbgems/mruby-time/src/time.c index 34376c286..4f0afd6c6 100644 --- a/mrbgems/mruby-time/src/time.c +++ b/mrbgems/mruby-time/src/time.c @@ -4,6 +4,10 @@ ** See Copyright Notice in mruby.h */ +#ifdef MRB_WITHOUT_FLOAT +# error Conflict 'MRB_WITHOUT_FLOAT' configuration in your 'build_config.rb' +#endif + #include #include #include -- cgit v1.2.3 From 109d926e9ca2e1efc974b45b1ca25095a57c709d Mon Sep 17 00:00:00 2001 From: dearblue Date: Mon, 15 Jul 2019 10:41:32 +0900 Subject: Add pack/unpack test for base64 --- mrbgems/mruby-pack/test/pack.rb | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/mrbgems/mruby-pack/test/pack.rb b/mrbgems/mruby-pack/test/pack.rb index eb24e8d1f..68ef4165f 100644 --- a/mrbgems/mruby-pack/test/pack.rb +++ b/mrbgems/mruby-pack/test/pack.rb @@ -35,6 +35,17 @@ assert('"YWJ...".unpack("m") should "abc..xyzABC..XYZ"') do assert_equal ary, "YWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXpBQkNERUZHSElKS0xNTk9QUVJTVFVWV1hZWg==\n".unpack("m") end +assert('["A", "B"].pack') do + assert_equal "QQ==\n", ["A", "B"].pack("m50") + assert_equal ["A"], "QQ==\n".unpack("m50") + assert_equal "QQ==Qg==", ["A", "B"].pack("m0 m0") + assert_equal ["A", "B"], "QQ==Qg==".unpack("m10 m10") +end + +assert('["abc..xyzABC..XYZ"].pack("m0")') do + assert_pack "m0", "YWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXpBQkNERUZHSElKS0xNTk9QUVJTVFVWV1hZWg==", ["abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"] +end + # pack & unpack 'H' assert('["3031"].pack("H*")') do assert_pack "H*", "01", ["3031"] -- cgit v1.2.3 From 4861be1171e63d94d8924bc35a39949f691ec427 Mon Sep 17 00:00:00 2001 From: dearblue Date: Mon, 15 Jul 2019 11:19:22 +0900 Subject: Fix pack/unpack for base64; ref #4556 The pack/unpack "m" directive should be treated as a length rather than an element count. --- mrbgems/mruby-pack/src/pack.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/mrbgems/mruby-pack/src/pack.c b/mrbgems/mruby-pack/src/pack.c index 46c0cc1fe..894c4555f 100644 --- a/mrbgems/mruby-pack/src/pack.c +++ b/mrbgems/mruby-pack/src/pack.c @@ -1002,7 +1002,7 @@ alias: case 'm': dir = PACK_DIR_BASE64; type = PACK_TYPE_STRING; - flags |= PACK_FLAG_WIDTH; + flags |= PACK_FLAG_WIDTH | PACK_FLAG_COUNT2; break; case 'N': /* = "L>" */ dir = PACK_DIR_LONG; @@ -1196,7 +1196,7 @@ mrb_pack_pack(mrb_state *mrb, mrb_value ary) default: break; } - if (dir == PACK_DIR_STR) { /* always consumes 1 entry */ + if (dir == PACK_DIR_STR || dir == PACK_DIR_BASE64) { /* always consumes 1 entry */ aidx++; break; } @@ -1249,6 +1249,9 @@ pack_unpack(mrb_state *mrb, mrb_value str, int single) case PACK_DIR_STR: srcidx += unpack_a(mrb, sptr, srclen - srcidx, result, count, flags); break; + case PACK_DIR_BASE64: + srcidx += unpack_m(mrb, sptr, srclen - srcidx, result, flags); + break; } continue; } @@ -1275,9 +1278,6 @@ pack_unpack(mrb_state *mrb, mrb_value str, int single) case PACK_DIR_QUAD: srcidx += unpack_q(mrb, sptr, srclen - srcidx, result, flags); break; - case PACK_DIR_BASE64: - srcidx += unpack_m(mrb, sptr, srclen - srcidx, result, flags); - break; #ifndef MRB_WITHOUT_FLOAT case PACK_DIR_FLOAT: srcidx += unpack_float(mrb, sptr, srclen - srcidx, result, flags); -- cgit v1.2.3 From fd899481643feeed874c95060fa50cb75f9d993a Mon Sep 17 00:00:00 2001 From: dearblue Date: Mon, 15 Jul 2019 11:23:50 +0900 Subject: Fix empty array refers; ref #4556 For example, `"".unpack("")` evaluates to `[]`. --- mrbgems/mruby-pack/src/pack.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/mrbgems/mruby-pack/src/pack.c b/mrbgems/mruby-pack/src/pack.c index 894c4555f..9f091194b 100644 --- a/mrbgems/mruby-pack/src/pack.c +++ b/mrbgems/mruby-pack/src/pack.c @@ -1299,7 +1299,12 @@ pack_unpack(mrb_state *mrb, mrb_value str, int single) if (single) break; } - if (single) return RARRAY_PTR(result)[0]; + if (single) { + if (RARRAY_LEN(result) > 0) { + return RARRAY_PTR(result)[0]; + } + return mrb_nil_value(); + } return result; } -- cgit v1.2.3 From 7b260d9c2de4436d6e8b09ba4fd524782934153f Mon Sep 17 00:00:00 2001 From: dearblue Date: Sun, 14 Jul 2019 18:55:38 +0900 Subject: Improve `utf8len()` performance with UTF-8 --- src/string.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/string.c b/src/string.c index a6aa9d906..be623deda 100644 --- a/src/string.c +++ b/src/string.c @@ -233,7 +233,9 @@ utf8len(const char* p, const char* e) mrb_int len; mrb_int i; + if ((unsigned char)*p < 0x80) return 1; len = utf8len_codepage[(unsigned char)*p]; + if (len == 1) return 1; if (len > e - p) return 1; for (i = 1; i < len; ++i) if ((p[i] & 0xc0) != 0x80) -- cgit v1.2.3 From 380805ece257147275bbed3eb83277f374296d9a Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Sun, 14 Jul 2019 19:13:19 +0900 Subject: Keep `MRB_STR_ASCII` flag in some methods of `String` --- include/mruby/string.h | 9 ++++++++- src/string.c | 15 +++++++-------- 2 files changed, 15 insertions(+), 9 deletions(-) diff --git a/include/mruby/string.h b/include/mruby/string.h index d648d856c..4615b4384 100644 --- a/include/mruby/string.h +++ b/include/mruby/string.h @@ -107,7 +107,6 @@ MRB_API mrb_int mrb_str_strlen(mrb_state*, struct RString*); #define MRB_STR_EMBED_LEN_SHIFT 6 void mrb_gc_free_str(mrb_state*, struct RString*); -MRB_API void mrb_str_modify(mrb_state*, struct RString*); /* * Finds the index of a substring in a string @@ -454,6 +453,14 @@ mrb_value mrb_str_inspect(mrb_state *mrb, mrb_value str); mrb_bool mrb_str_beg_len(mrb_int str_len, mrb_int *begp, mrb_int *lenp); mrb_value mrb_str_byte_subseq(mrb_state *mrb, mrb_value str, mrb_int beg, mrb_int len); +void mrb_str_modify_keep_ascii(mrb_state *mrb, struct RString *s); + +MRB_INLINE void +mrb_str_modify(mrb_state *mrb, struct RString *s) +{ + mrb_str_modify_keep_ascii(mrb, s); + RSTR_UNSET_ASCII_FLAG(s); +} #ifdef MRB_UTF8_STRING mrb_int mrb_utf8_len(const char *str, mrb_int byte_len); diff --git a/src/string.c b/src/string.c index a6aa9d906..8706bfd1b 100644 --- a/src/string.c +++ b/src/string.c @@ -706,11 +706,10 @@ mrb_locale_from_utf8(const char *utf8, int len) } #endif -MRB_API void -mrb_str_modify(mrb_state *mrb, struct RString *s) +void +mrb_str_modify_keep_ascii(mrb_state *mrb, struct RString *s) { mrb_check_frozen(mrb, s); - RSTR_UNSET_ASCII_FLAG(s); if (RSTR_SHARED_P(s)) { mrb_shared_string *shared = s->as.heap.aux.shared; @@ -1339,7 +1338,7 @@ mrb_str_capitalize_bang(mrb_state *mrb, mrb_value str) mrb_bool modify = FALSE; struct RString *s = mrb_str_ptr(str); - mrb_str_modify(mrb, s); + mrb_str_modify_keep_ascii(mrb, s); if (RSTR_LEN(s) == 0 || !RSTR_PTR(s)) return mrb_nil_value(); p = RSTR_PTR(s); pend = RSTR_PTR(s) + RSTR_LEN(s); if (ISLOWER(*p)) { @@ -1398,7 +1397,7 @@ mrb_str_chomp_bang(mrb_state *mrb, mrb_value str) struct RString *s = mrb_str_ptr(str); argc = mrb_get_args(mrb, "|S", &rs); - mrb_str_modify(mrb, s); + mrb_str_modify_keep_ascii(mrb, s); len = RSTR_LEN(s); if (argc == 0) { if (len == 0) return mrb_nil_value(); @@ -1497,7 +1496,7 @@ mrb_str_chop_bang(mrb_state *mrb, mrb_value str) { struct RString *s = mrb_str_ptr(str); - mrb_str_modify(mrb, s); + mrb_str_modify_keep_ascii(mrb, s); if (RSTR_LEN(s) > 0) { mrb_int len; #ifdef MRB_UTF8_STRING @@ -1566,7 +1565,7 @@ mrb_str_downcase_bang(mrb_state *mrb, mrb_value str) mrb_bool modify = FALSE; struct RString *s = mrb_str_ptr(str); - mrb_str_modify(mrb, s); + mrb_str_modify_keep_ascii(mrb, s); p = RSTR_PTR(s); pend = RSTR_PTR(s) + RSTR_LEN(s); while (p < pend) { @@ -2536,7 +2535,7 @@ mrb_str_upcase_bang(mrb_state *mrb, mrb_value str) char *p, *pend; mrb_bool modify = FALSE; - mrb_str_modify(mrb, s); + mrb_str_modify_keep_ascii(mrb, s); p = RSTRING_PTR(str); pend = RSTRING_END(str); while (p < pend) { -- cgit v1.2.3 From 9093f3403f76b0a70d2b29b6c04ca7f203c242e6 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Mon, 15 Jul 2019 07:39:57 +0900 Subject: Add `MRB_API` to `mrb_str_modify_keep_ascii()` --- include/mruby/string.h | 3 ++- src/string.c | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/include/mruby/string.h b/include/mruby/string.h index 4615b4384..77f6becf6 100644 --- a/include/mruby/string.h +++ b/include/mruby/string.h @@ -108,6 +108,8 @@ MRB_API mrb_int mrb_str_strlen(mrb_state*, struct RString*); void mrb_gc_free_str(mrb_state*, struct RString*); +MRB_API void mrb_str_modify_keep_ascii(mrb_state *mrb, struct RString *s); + /* * Finds the index of a substring in a string */ @@ -453,7 +455,6 @@ mrb_value mrb_str_inspect(mrb_state *mrb, mrb_value str); mrb_bool mrb_str_beg_len(mrb_int str_len, mrb_int *begp, mrb_int *lenp); mrb_value mrb_str_byte_subseq(mrb_state *mrb, mrb_value str, mrb_int beg, mrb_int len); -void mrb_str_modify_keep_ascii(mrb_state *mrb, struct RString *s); MRB_INLINE void mrb_str_modify(mrb_state *mrb, struct RString *s) diff --git a/src/string.c b/src/string.c index 8706bfd1b..c1a001634 100644 --- a/src/string.c +++ b/src/string.c @@ -706,7 +706,7 @@ mrb_locale_from_utf8(const char *utf8, int len) } #endif -void +MRB_API void mrb_str_modify_keep_ascii(mrb_state *mrb, struct RString *s) { mrb_check_frozen(mrb, s); -- cgit v1.2.3 From acad9567c16317a86d7e246d6093a43d3a58c758 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Mon, 15 Jul 2019 23:03:41 +0900 Subject: Unify type of line number to `uint16_t` --- include/mruby/compile.h | 6 +++--- mrbgems/mruby-compiler/core/parse.y | 2 +- mrbgems/mruby-eval/src/eval.c | 2 +- src/backtrace.c | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/include/mruby/compile.h b/include/mruby/compile.h index 8f8f2ebd7..3b25ff526 100644 --- a/include/mruby/compile.h +++ b/include/mruby/compile.h @@ -24,7 +24,7 @@ typedef struct mrbc_context { mrb_sym *syms; int slen; char *filename; - short lineno; + uint16_t lineno; int (*partial_hook)(struct mrb_parser_state*); void *partial_data; struct RClass *target_class; @@ -67,7 +67,7 @@ enum mrb_lex_state_enum { /* saved error message */ struct mrb_parser_message { - int lineno; + uint16_t lineno; int column; char* message; }; @@ -119,7 +119,7 @@ struct mrb_parser_state { #endif mrbc_context *cxt; mrb_sym filename_sym; - int lineno; + uint16_t lineno; int column; enum mrb_lex_state_enum lstate; diff --git a/mrbgems/mruby-compiler/core/parse.y b/mrbgems/mruby-compiler/core/parse.y index 96a9453b6..ac59a8b0b 100644 --- a/mrbgems/mruby-compiler/core/parse.y +++ b/mrbgems/mruby-compiler/core/parse.y @@ -233,7 +233,7 @@ parser_strdup(parser_state *p, const char *s) #define strdup(s) parser_strdup(p, s) static void -dump_int(short i, char *s) +dump_int(uint16_t i, char *s) { char *p = s; char *t = s; diff --git a/mrbgems/mruby-eval/src/eval.c b/mrbgems/mruby-eval/src/eval.c index a3b211ba2..30534aaec 100644 --- a/mrbgems/mruby-eval/src/eval.c +++ b/mrbgems/mruby-eval/src/eval.c @@ -235,7 +235,7 @@ create_proc_from_string(mrb_state *mrb, char *s, mrb_int len, mrb_value binding, } cxt = mrbc_context_new(mrb); - cxt->lineno = (short)line; + cxt->lineno = (uint16_t)line; mrbc_filename(mrb, cxt, file ? file : "(eval)"); cxt->capture_errors = TRUE; diff --git a/src/backtrace.c b/src/backtrace.c index e4f5a3064..991a67d00 100644 --- a/src/backtrace.c +++ b/src/backtrace.c @@ -16,7 +16,7 @@ #include struct backtrace_location { - int lineno; + int32_t lineno; mrb_sym method_id; const char *filename; }; -- cgit v1.2.3 From 31492a177c34485e9bcc441e74c208366920f7b2 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Tue, 16 Jul 2019 21:56:58 +0900 Subject: Copy receiver's `MRB_STR_ASCII` flag in some methods of `String` --- src/string.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/string.c b/src/string.c index 39b3515a3..6b7cced13 100644 --- a/src/string.c +++ b/src/string.c @@ -487,6 +487,7 @@ mrb_str_byte_subseq(mrb_state *mrb, mrb_value str, mrb_int beg, mrb_int len) s->as.heap.ptr += beg; s->as.heap.len = len; } + RSTR_COPY_ASCII_FLAG(s, orig); return mrb_obj_value(s); } @@ -902,6 +903,7 @@ mrb_str_times(mrb_state *mrb, mrb_value self) memcpy(p + n, p, len-n); } p[RSTR_LEN(str2)] = '\0'; + RSTR_COPY_ASCII_FLAG(str2, mrb_str_ptr(self)); return mrb_obj_value(str2); } @@ -2837,6 +2839,7 @@ mrb_str_inspect(mrb_state *mrb, mrb_value str) } } mrb_str_cat_lit(mrb, result, "\""); + RSTR_COPY_ASCII_FLAG(mrb_str_ptr(result), mrb_str_ptr(str)); return result; } -- cgit v1.2.3