diff options
32 files changed, 374 insertions, 125 deletions
@@ -17,3 +17,5 @@ Original Authors "mruby developers" are: Jun Hiroe Narihiro Nakamura Yuichi Nishiwaki + Tatsuhiko Kubo + Takeshi Watanabe @@ -1,10 +1,3 @@ -# !!Notice!! - This is a preliminary release for internal team review. - The URLs and addresses described below are not available yet. - The official release will be announced later. - Any suggestions for modification are welcome. - Delays in replies are to be expected. Sorry in advance. - [](https://travis-ci.org/mruby/mruby) ## What's mruby diff --git a/include/mruby.h b/include/mruby.h index 30c2dbbb1..4f404fb8e 100644 --- a/include/mruby.h +++ b/include/mruby.h @@ -374,6 +374,9 @@ mrb_value mrb_attr_get(mrb_state *mrb, mrb_value obj, mrb_sym id); mrb_bool mrb_respond_to(mrb_state *mrb, mrb_value obj, mrb_sym mid); mrb_bool mrb_obj_is_instance_of(mrb_state *mrb, mrb_value obj, struct RClass* c); +/* fiber functions (you need to link mruby-fiber mrbgem to use) */ +mrb_value mrb_fiber_yield(mrb_state *mrb, int argc, mrb_value *argv); + /* memory pool implementation */ typedef struct mrb_pool mrb_pool; struct mrb_pool* mrb_pool_open(mrb_state*); diff --git a/include/mruby/error.h b/include/mruby/error.h index b04dc1082..96c4092b5 100644 --- a/include/mruby/error.h +++ b/include/mruby/error.h @@ -13,5 +13,8 @@ mrb_value mrb_make_exception(mrb_state *mrb, int argc, mrb_value *argv); mrb_value mrb_format(mrb_state *mrb, const char *format, ...); void mrb_exc_print(mrb_state *mrb, struct RObject *exc); void mrb_longjmp(mrb_state *mrb); +void mrb_print_backtrace(mrb_state *mrb); +mrb_value mrb_exc_backtrace(mrb_state *mrb, mrb_value exc); +mrb_value mrb_get_backtrace(mrb_state *mrb); #endif /* MRUBY_ERROR_H */ diff --git a/include/mruby/string.h b/include/mruby/string.h index 675dadb5c..966f0bf77 100644 --- a/include/mruby/string.h +++ b/include/mruby/string.h @@ -53,7 +53,6 @@ char *mrb_string_value_ptr(mrb_state *mrb, mrb_value ptr); int mrb_str_offset(mrb_state *mrb, mrb_value str, int pos); mrb_value mrb_str_dup(mrb_state *mrb, mrb_value str); mrb_value mrb_str_intern(mrb_state *mrb, mrb_value self); -mrb_value mrb_str_cat_cstr(mrb_state *, mrb_value, const char *); mrb_value mrb_str_to_inum(mrb_state *mrb, mrb_value str, int base, mrb_bool badcheck); double mrb_str_to_dbl(mrb_state *mrb, mrb_value str, mrb_bool badcheck); mrb_value mrb_str_to_str(mrb_state *mrb, mrb_value str); @@ -63,6 +62,8 @@ mrb_value mrb_str_inspect(mrb_state *mrb, mrb_value str); mrb_bool mrb_str_equal(mrb_state *mrb, mrb_value str1, mrb_value str2); mrb_value mrb_str_dump(mrb_state *mrb, mrb_value str); mrb_value mrb_str_cat(mrb_state *mrb, mrb_value str, const char *ptr, size_t len); +mrb_value mrb_str_cat_cstr(mrb_state *mrb, mrb_value str, const char *ptr); +#define mrb_str_cat_lit(mrb, str, lit) mrb_str_cat(mrb, str, (lit), sizeof(lit) - 1) mrb_value mrb_str_append(mrb_state *mrb, mrb_value str, mrb_value str2); int mrb_str_cmp(mrb_state *mrb, mrb_value str1, mrb_value str2); diff --git a/mrbgems/mruby-bin-strip/bintest/mruby-strip.rb b/mrbgems/mruby-bin-strip/bintest/mruby-strip.rb new file mode 100644 index 000000000..4f27d2fce --- /dev/null +++ b/mrbgems/mruby-bin-strip/bintest/mruby-strip.rb @@ -0,0 +1,53 @@ +require 'tempfile' + +assert('no files') do + o = `bin/mruby-strip 2>&1` + assert_equal 1, $?.exitstatus + assert_equal "no files to strip\n", o +end + +assert('file not found') do + o = `bin/mruby-strip not_found.mrb 2>&1` + assert_equal 1, $?.exitstatus + assert_equal "can't open file not_found.mrb\n", o +end + +assert('not irep file') do + t = Tempfile.new('script.rb') + t.write 'p test\n' + t.flush + o = `bin/mruby-strip #{t.path} 2>&1` + assert_equal 1, $?.exitstatus + assert_equal "can't read irep file #{t.path}\n", o +end + +assert('success') do + script_file, compiled1, compiled2 = + Tempfile.new('script.rb'), Tempfile.new('c1.mrb'), Tempfile.new('c2.mrb') + script_file.write "p 'test'\n" + script_file.flush + `bin/mrbc -g -o #{compiled1.path} #{script_file.path}` + `bin/mrbc -g -o #{compiled2.path} #{script_file.path}` + + o = `bin/mruby-strip #{compiled1.path}` + assert_equal 0, $?.exitstatus + assert_equal "", o + + o = `bin/mruby-strip #{compiled1.path} #{compiled2.path}` + assert_equal 0, $?.exitstatus + assert_equal "", o +end + +assert('check debug section') do + script_file, with_debug, without_debug = + Tempfile.new('script.rb'), Tempfile.new('c1.mrb'), Tempfile.new('c2.mrb') + script_file.write "p 'test'\n" + script_file.flush + `bin/mrbc -o #{without_debug.path} #{script_file.path}` + `bin/mrbc -g -o #{with_debug.path} #{script_file.path}` + + assert_true with_debug.size >= without_debug.size + + `bin/mruby-strip #{with_debug.path}` + assert_equal without_debug.size, with_debug.size +end diff --git a/mrbgems/mruby-bin-strip/mrbgem.rake b/mrbgems/mruby-bin-strip/mrbgem.rake new file mode 100644 index 000000000..47304b2a5 --- /dev/null +++ b/mrbgems/mruby-bin-strip/mrbgem.rake @@ -0,0 +1,5 @@ +MRuby::Gem::Specification.new('mruby-bin-strip') do |spec| + spec.license = 'MIT' + spec.author = 'mruby developers' + spec.bins = %w(mruby-strip) +end diff --git a/mrbgems/mruby-bin-strip/tools/mruby-strip/mruby-strip.c b/mrbgems/mruby-bin-strip/tools/mruby-strip/mruby-strip.c new file mode 100644 index 000000000..dee3e0cd6 --- /dev/null +++ b/mrbgems/mruby-bin-strip/tools/mruby-strip/mruby-strip.c @@ -0,0 +1,58 @@ +#include <stdio.h> +#include <stdlib.h> +#include "mruby.h" +#include "mruby/irep.h" +#include "mruby/dump.h" + +int +main(int argc, char **argv) +{ + int i, dump_result; + FILE **files; + mrb_irep **ireps; + mrb_state *mrb; + + if (argc <= 1) { + fprintf(stderr, "no files to strip\n"); + return EXIT_FAILURE; + } + + files = (FILE**)malloc(sizeof(FILE*) * argc); + for (i = 1; i < argc; ++i) { + files[i] = fopen(argv[i], "rb"); + + if (!files[i]) { + fprintf(stderr, "can't open file %s\n", argv[i]); + return EXIT_FAILURE; + } + } + + mrb = mrb_open(); + + ireps = (mrb_irep**)malloc(sizeof(mrb_irep*) * argc); + for (i = 1; i < argc; ++i) { + ireps[i] = mrb_read_irep_file(mrb, files[i]); + if (!ireps[i]) { + fprintf(stderr, "can't read irep file %s\n", argv[i]); + return EXIT_FAILURE; + } + fclose(files[i]); + files[i] = fopen(argv[i], "wb"); + if (!ireps[i]) { + fprintf(stderr, "can't reopen irep file %s\n", argv[i]); + return EXIT_FAILURE; + } + } + + for (i = 1; i < argc; ++i) { + /* debug flag must be alway false */ + dump_result = mrb_dump_irep_binary(mrb, ireps[i], FALSE, files[i]); + if (dump_result != MRB_DUMP_OK) { + fprintf(stderr, "error occur when dumping %s", argv[i]); + return EXIT_FAILURE; + } + } + + mrb_close(mrb); + return EXIT_SUCCESS; +} diff --git a/mrbgems/mruby-fiber/src/fiber.c b/mrbgems/mruby-fiber/src/fiber.c index 6ee22eded..0dbdad871 100644 --- a/mrbgems/mruby-fiber/src/fiber.c +++ b/mrbgems/mruby-fiber/src/fiber.c @@ -205,23 +205,11 @@ fiber_alive_p(mrb_state *mrb, mrb_value self) return mrb_bool_value(c->status != MRB_FIBER_TERMINATED); } -/* - * call-seq: - * Fiber.yield(args, ...) -> obj - * - * Yields control back to the context that resumed the fiber, passing - * along any arguments that were passed to it. The fiber will resume - * processing at this point when <code>resume</code> is called next. - * Any arguments passed to the next <code>resume</code> will be the - * value that this <code>Fiber.yield</code> expression evaluates to. - */ -static mrb_value -fiber_yield(mrb_state *mrb, mrb_value self) +mrb_value +mrb_fiber_yield(mrb_state *mrb, int len, mrb_value *a) { struct mrb_context *c = mrb->c; mrb_callinfo *ci; - mrb_value *a; - int len; for (ci = c->ci; ci >= c->cibase; ci--) { if (ci->acc < 0) { @@ -231,7 +219,7 @@ fiber_yield(mrb_state *mrb, mrb_value self) if (!c->prev) { mrb_raise(mrb, E_ARGUMENT_ERROR, "can't yield from root fiber"); } - mrb_get_args(mrb, "*", &a, &len); + c->prev->status = MRB_FIBER_RUNNING; mrb->c = c->prev; c->prev = NULL; @@ -241,6 +229,26 @@ fiber_yield(mrb_state *mrb, mrb_value self) /* * call-seq: + * Fiber.yield(args, ...) -> obj + * + * Yields control back to the context that resumed the fiber, passing + * along any arguments that were passed to it. The fiber will resume + * processing at this point when <code>resume</code> is called next. + * Any arguments passed to the next <code>resume</code> will be the + * value that this <code>Fiber.yield</code> expression evaluates to. + */ +static mrb_value +fiber_yield(mrb_state *mrb, mrb_value self) +{ + mrb_value *a; + int len; + + mrb_get_args(mrb, "*", &a, &len); + return mrb_fiber_yield(mrb, len, a); +} + +/* + * call-seq: * Fiber.current() -> fiber * * Returns the current fiber. You need to <code>require 'fiber'</code> diff --git a/mrbgems/mruby-numeric-ext/test/numeric.rb b/mrbgems/mruby-numeric-ext/test/numeric.rb index 7d85eaaa2..1ca01648e 100644 --- a/mrbgems/mruby-numeric-ext/test/numeric.rb +++ b/mrbgems/mruby-numeric-ext/test/numeric.rb @@ -5,6 +5,11 @@ assert('Integer#chr') do assert_equal("A", 65.chr) assert_equal("B", 0x42.chr) - # multibyte encoding (not support yet) - assert_raise(RangeError) { 12345.chr } + if "こんにちわ世界".size == 7 then + # UTF-8 gem is configured + assert_raise(RangeError) { 0x110000.chr } + else + # multibyte encoding (not support yet) + assert_raise(RangeError) { 256.chr } + end end diff --git a/mrbgems/mruby-proc-ext/src/proc.c b/mrbgems/mruby-proc-ext/src/proc.c index f27356bb7..3bb0d3570 100644 --- a/mrbgems/mruby-proc-ext/src/proc.c +++ b/mrbgems/mruby-proc-ext/src/proc.c @@ -39,29 +39,29 @@ mrb_proc_inspect(mrb_state *mrb, mrb_value self) if (!MRB_PROC_CFUNC_P(p)) { mrb_irep *irep = p->body.irep; - mrb_str_cat_cstr(mrb, str, "@"); + mrb_str_cat_lit(mrb, str, "@"); if (irep->filename) { mrb_str_cat_cstr(mrb, str, irep->filename); } else { - mrb_str_cat_cstr(mrb, str, "-"); + mrb_str_cat_lit(mrb, str, "-"); } - mrb_str_cat_cstr(mrb, str, ":"); + mrb_str_cat_lit(mrb, str, ":"); if (irep->lines) { mrb_str_append(mrb, str, mrb_fixnum_value(*irep->lines)); } else { - mrb_str_cat_cstr(mrb, str, "-"); + mrb_str_cat_lit(mrb, str, "-"); } } if (MRB_PROC_STRICT_P(p)) { - mrb_str_cat_cstr(mrb, str, " (lambda)"); + mrb_str_cat_lit(mrb, str, " (lambda)"); } - mrb_str_cat_cstr(mrb, str, ">"); + mrb_str_cat_lit(mrb, str, ">"); return str; } diff --git a/mrbgems/mruby-sprintf/src/sprintf.c b/mrbgems/mruby-sprintf/src/sprintf.c index 64b9f0787..ff9627437 100644 --- a/mrbgems/mruby-sprintf/src/sprintf.c +++ b/mrbgems/mruby-sprintf/src/sprintf.c @@ -654,7 +654,7 @@ retry: case '\n': case '\0': p--; - + /* fallthrough */ case '%': if (flags != FNONE) { mrb_raise(mrb, E_ARGUMENT_ERROR, "invalid format character - %"); @@ -665,38 +665,37 @@ retry: case 'c': { mrb_value val = GETARG(); mrb_value tmp; - unsigned int c; + char *c; tmp = mrb_check_string_type(mrb, val); if (!mrb_nil_p(tmp)) { - if (RSTRING_LEN(tmp) != 1 ) { + if (mrb_fixnum(mrb_funcall(mrb, tmp, "size", 0)) != 1 ) { mrb_raise(mrb, E_ARGUMENT_ERROR, "%c requires a character"); } - c = RSTRING_PTR(tmp)[0]; - n = 1; } - else { - c = mrb_fixnum(val); - n = 1; + else if (mrb_fixnum_p(val)) { + tmp = mrb_funcall(mrb, val, "chr", 0); } - if (n <= 0) { + else { mrb_raise(mrb, E_ARGUMENT_ERROR, "invalid character"); } + c = RSTRING_PTR(tmp); + n = RSTRING_LEN(tmp); if (!(flags & FWIDTH)) { CHECK(n); - buf[blen] = c; + memcpy(buf+blen, c, n); blen += n; } else if ((flags & FMINUS)) { CHECK(n); - buf[blen] = c; + memcpy(buf+blen, c, n); blen += n; FILL(' ', width-1); } else { FILL(' ', width-1); CHECK(n); - buf[blen] = c; + memcpy(buf+blen, c, n); blen += n; } } diff --git a/mrbgems/mruby-string-utf8/src/string.c b/mrbgems/mruby-string-utf8/src/string.c index 2dd848c86..4f3833944 100644 --- a/mrbgems/mruby-string-utf8/src/string.c +++ b/mrbgems/mruby-string-utf8/src/string.c @@ -279,6 +279,41 @@ mrb_str_reverse(mrb_state *mrb, mrb_value str) return mrb_str_reverse_bang(mrb, mrb_str_dup(mrb, str)); } +static mrb_value +mrb_fixnum_chr(mrb_state *mrb, mrb_value num) +{ + mrb_int cp = mrb_fixnum(num); + char utf8[4]; + int len; + + if (cp < 0 || 0x10FFFF < cp) { + mrb_raisef(mrb, E_RANGE_ERROR, "%S out of char range", num); + } + if (cp < 0x80) { + utf8[0] = (char)cp; + len = 1; + } + else if (cp < 0x800) { + utf8[0] = (char)(0xC0 | (cp >> 6)); + utf8[1] = (char)(0x80 | (cp & 0x3F)); + len = 2; + } + else if (cp < 0x10000) { + utf8[0] = (char)(0xE0 | (cp >> 12)); + utf8[1] = (char)(0x80 | ((cp >> 6) & 0x3F)); + utf8[2] = (char)(0x80 | ( cp & 0x3F)); + len = 3; + } + else { + utf8[0] = (char)(0xF0 | (cp >> 18)); + utf8[1] = (char)(0x80 | ((cp >> 12) & 0x3F)); + utf8[2] = (char)(0x80 | ((cp >> 6) & 0x3F)); + utf8[3] = (char)(0x80 | ( cp & 0x3F)); + len = 4; + } + return mrb_str_new(mrb, utf8, len); +} + void mrb_mruby_string_utf8_gem_init(mrb_state* mrb) { @@ -290,6 +325,8 @@ mrb_mruby_string_utf8_gem_init(mrb_state* mrb) mrb_define_method(mrb, s, "slice", mrb_str_aref_m, MRB_ARGS_ANY()); mrb_define_method(mrb, s, "reverse", mrb_str_reverse, MRB_ARGS_NONE()); mrb_define_method(mrb, s, "reverse!", mrb_str_reverse_bang, MRB_ARGS_NONE()); + + mrb_define_method(mrb, mrb->fixnum_class, "chr", mrb_fixnum_chr, MRB_ARGS_NONE()); } void diff --git a/mrbgems/mruby-struct/src/struct.c b/mrbgems/mruby-struct/src/struct.c index 23ee81fa6..baac2d3a2 100644 --- a/mrbgems/mruby-struct/src/struct.c +++ b/mrbgems/mruby-struct/src/struct.c @@ -450,7 +450,7 @@ inspect_struct(mrb_state *mrb, mrb_value s, int recur) mrb_str_append(mrb, str, mrb_str_new_cstr(mrb, cn)); } if (recur) { - return mrb_str_cat_cstr(mrb, str, ":...>"); + return mrb_str_cat_lit(mrb, str, ":...>"); } members = mrb_struct_members(mrb, s); @@ -462,10 +462,10 @@ inspect_struct(mrb_state *mrb, mrb_value s, int recur) mrb_sym id; if (i > 0) { - mrb_str_cat_cstr(mrb, str, ", "); + mrb_str_cat_lit(mrb, str, ", "); } else if (cn) { - mrb_str_cat_cstr(mrb, str, " "); + mrb_str_cat_lit(mrb, str, " "); } slot = ptr_members[i]; id = mrb_symbol(slot); @@ -479,10 +479,10 @@ inspect_struct(mrb_state *mrb, mrb_value s, int recur) else { mrb_str_append(mrb, str, mrb_inspect(mrb, slot)); } - mrb_str_cat_cstr(mrb, str, "="); + mrb_str_cat_lit(mrb, str, "="); mrb_str_append(mrb, str, mrb_inspect(mrb, ptr[i])); } - mrb_str_cat_cstr(mrb, str, ">"); + mrb_str_cat_lit(mrb, str, ">"); return str; } diff --git a/src/array.c b/src/array.c index 6c0f59e9d..ce43a0392 100644 --- a/src/array.c +++ b/src/array.c @@ -188,13 +188,11 @@ ary_expand_capa(mrb_state *mrb, struct RArray *a, mrb_int len) mrb_raise(mrb, E_ARGUMENT_ERROR, "array size too big"); } + if (capa == 0) { + capa = ARY_DEFAULT_LEN; + } while (capa < len) { - if (capa == 0) { - capa = ARY_DEFAULT_LEN; - } - else { - capa *= 2; - } + capa *= 2; } if (capa > ARY_MAX_SIZE) capa = ARY_MAX_SIZE; /* len <= capa <= ARY_MAX_SIZE */ diff --git a/src/backtrace.c b/src/backtrace.c index a221d5e5c..6469fc069 100644 --- a/src/backtrace.c +++ b/src/backtrace.c @@ -12,6 +12,7 @@ #include "mruby/string.h" #include "mruby/class.h" #include "mruby/debug.h" +#include "mruby/error.h" typedef void (*output_stream_func)(mrb_state*, void*, int, const char*, ...); @@ -57,14 +58,12 @@ get_backtrace_i(mrb_state *mrb, void *stream, int level, const char *format, ... } static void -mrb_output_backtrace(mrb_state *mrb, struct RObject *exc, output_stream_func func, void *stream) +output_backtrace(mrb_state *mrb, mrb_int ciidx, mrb_code *pc0, output_stream_func func, void *stream) { mrb_callinfo *ci; - mrb_int ciidx; const char *filename, *method, *sep; int i, lineno, tracehead = 1; - ciidx = mrb_fixnum(mrb_obj_iv_get(mrb, exc, mrb_intern_lit(mrb, "ciidx"))); if (ciidx >= mrb->c->ciend - mrb->c->cibase) ciidx = 10; /* ciidx is broken... */ @@ -87,7 +86,7 @@ mrb_output_backtrace(mrb_state *mrb, struct RObject *exc, output_stream_func fun pc = mrb->c->cibase[i+1].pc - 1; } else { - pc = (mrb_code*)mrb_cptr(mrb_obj_iv_get(mrb, exc, mrb_intern_lit(mrb, "lastpc"))); + pc = pc0; } filename = mrb_debug_get_filename(irep, pc - irep->iseq); lineno = mrb_debug_get_line(irep, pc - irep->iseq); @@ -129,6 +128,14 @@ mrb_output_backtrace(mrb_state *mrb, struct RObject *exc, output_stream_func fun } } +static void +exc_output_backtrace(mrb_state *mrb, struct RObject *exc, output_stream_func func, void *stream) +{ + output_backtrace(mrb, mrb_fixnum(mrb_obj_iv_get(mrb, exc, mrb_intern_lit(mrb, "ciidx"))), + (mrb_code*)mrb_cptr(mrb_obj_iv_get(mrb, exc, mrb_intern_lit(mrb, "lastpc"))), + func, stream); +} + /* mrb_print_backtrace/mrb_get_backtrace: function to retrieve backtrace information from the exception. @@ -140,17 +147,32 @@ void mrb_print_backtrace(mrb_state *mrb) { #ifdef ENABLE_STDIO - mrb_output_backtrace(mrb, mrb->exc, print_backtrace_i, (void*)stderr); + exc_output_backtrace(mrb, mrb->exc, print_backtrace_i, (void*)stderr); #endif } mrb_value -mrb_get_backtrace(mrb_state *mrb, mrb_value self) +mrb_exc_backtrace(mrb_state *mrb, mrb_value self) +{ + mrb_value ary; + + ary = mrb_ary_new(mrb); + exc_output_backtrace(mrb, mrb_obj_ptr(self), get_backtrace_i, (void*)mrb_ary_ptr(ary)); + + return ary; +} + +mrb_value +mrb_get_backtrace(mrb_state *mrb) { mrb_value ary; + mrb_callinfo *ci = mrb->c->ci; + mrb_code *pc = ci->pc; + mrb_int ciidx = ci - mrb->c->cibase - 1; + if (ciidx < 0) ciidx = 0; ary = mrb_ary_new(mrb); - mrb_output_backtrace(mrb, mrb_obj_ptr(self), get_backtrace_i, (void*)mrb_ary_ptr(ary)); + output_backtrace(mrb, ciidx, pc, get_backtrace_i, (void*)mrb_ary_ptr(ary)); return ary; } diff --git a/src/class.c b/src/class.c index 2c1145ed3..e0d45a7f3 100644 --- a/src/class.c +++ b/src/class.c @@ -731,8 +731,13 @@ boot_defclass(mrb_state *mrb, struct RClass *super) struct RClass *c; c = (struct RClass*)mrb_obj_alloc(mrb, MRB_TT_CLASS, mrb->class_class); - c->super = super ? super : mrb->object_class; - mrb_field_write_barrier(mrb, (struct RBasic*)c, (struct RBasic*)super); + if (super) { + c->super = super; + mrb_field_write_barrier(mrb, (struct RBasic*)c, (struct RBasic*)super); + } + else { + c->super = mrb->object_class; + } c->mt = kh_init(mt, mrb); return c; } @@ -1118,7 +1123,7 @@ mrb_class_new_class(mrb_state *mrb, mrb_value cv) } new_class = mrb_obj_value(mrb_class_new(mrb, mrb_class_ptr(super))); if (!mrb_nil_p(blk)) { - mrb_funcall_with_block(mrb, new_class, mrb_intern_cstr(mrb, "class_eval"), 0, NULL, blk); + mrb_funcall_with_block(mrb, new_class, mrb_intern_lit(mrb, "class_eval"), 0, NULL, blk); } mrb_funcall(mrb, super, "inherited", 1, new_class); return new_class; @@ -1189,22 +1194,28 @@ mrb_bob_missing(mrb_state *mrb, mrb_value mod) mrb_sym name; mrb_value *a; int alen; - mrb_value inspect; + mrb_sym inspect; + mrb_value repr; mrb_get_args(mrb, "n*", &name, &a, &alen); - if (mrb_respond_to(mrb,mod,mrb_intern_lit(mrb, "inspect"))){ - inspect = mrb_funcall(mrb, mod, "inspect", 0); - if (RSTRING_LEN(inspect) > 64) { - inspect = mrb_any_to_s(mrb, mod); + inspect = mrb_intern_lit(mrb, "inspect"); + if (mrb->c->ci > mrb->c->cibase && mrb->c->ci[-1].mid == inspect) { + /* method missing in inspect; avoid recursion */ + repr = mrb_any_to_s(mrb, mod); + } + else if (mrb_respond_to(mrb, mod, inspect)) { + repr = mrb_funcall_argv(mrb, mod, inspect, 0, 0); + if (RSTRING_LEN(repr) > 64) { + repr = mrb_any_to_s(mrb, mod); } } else { - inspect = mrb_any_to_s(mrb, mod); + repr = mrb_any_to_s(mrb, mod); } mrb_raisef(mrb, E_NOMETHOD_ERROR, "undefined method '%S' for %S", - mrb_sym2str(mrb, name), inspect); + mrb_sym2str(mrb, name), repr); /* not reached */ return mrb_nil_value(); } @@ -1285,7 +1296,7 @@ mrb_class_name(mrb_state *mrb, struct RClass* c) if (mrb_nil_p(path)) { path = mrb_str_new_lit(mrb, "#<Class:"); mrb_str_concat(mrb, path, mrb_ptr_to_str(mrb, c)); - mrb_str_cat(mrb, path, ">", 1); + mrb_str_cat_lit(mrb, path, ">"); } return mrb_str_ptr(path)->ptr; } @@ -1420,7 +1431,7 @@ mrb_mod_to_s(mrb_state *mrb, mrb_value klass) mrb_str_append(mrb, str, mrb_any_to_s(mrb, v)); break; } - mrb_str_cat(mrb, str, ">", 1); + mrb_str_cat_lit(mrb, str, ">"); } else { struct RClass *c; @@ -1433,20 +1444,20 @@ mrb_mod_to_s(mrb_state *mrb, mrb_value klass) if (mrb_nil_p(path)) { switch (mrb_type(klass)) { case MRB_TT_CLASS: - mrb_str_cat(mrb, str, "#<Class:", 8); + mrb_str_cat_lit(mrb, str, "#<Class:"); break; case MRB_TT_MODULE: - mrb_str_cat(mrb, str, "#<Module:", 9); + mrb_str_cat_lit(mrb, str, "#<Module:"); break; default: /* Shouldn't be happened? */ - mrb_str_cat(mrb, str, "#<??????:", 9); + mrb_str_cat_lit(mrb, str, "#<??????:"); break; } mrb_str_concat(mrb, str, mrb_ptr_to_str(mrb, c)); - mrb_str_cat(mrb, str, ">", 1); + mrb_str_cat_lit(mrb, str, ">"); } else { str = path; diff --git a/src/error.c b/src/error.c index 8d0ec67e0..db516d766 100644 --- a/src/error.c +++ b/src/error.c @@ -128,26 +128,26 @@ exc_inspect(mrb_state *mrb, mrb_value exc) if (!mrb_nil_p(file) && !mrb_nil_p(line)) { str = file; - mrb_str_cat(mrb, str, ":", 1); + mrb_str_cat_lit(mrb, str, ":"); mrb_str_append(mrb, str, line); - mrb_str_cat(mrb, str, ": ", 2); + mrb_str_cat_lit(mrb, str, ": "); if (!mrb_nil_p(mesg) && RSTRING_LEN(mesg) > 0) { mrb_str_append(mrb, str, mesg); - mrb_str_cat(mrb, str, " (", 2); + mrb_str_cat_lit(mrb, str, " ("); } mrb_str_cat_cstr(mrb, str, mrb_obj_classname(mrb, exc)); if (!mrb_nil_p(mesg) && RSTRING_LEN(mesg) > 0) { - mrb_str_cat(mrb, str, ")", 1); + mrb_str_cat_lit(mrb, str, ")"); } } else { str = mrb_str_new_cstr(mrb, mrb_obj_classname(mrb, exc)); if (!mrb_nil_p(mesg) && RSTRING_LEN(mesg) > 0) { - mrb_str_cat(mrb, str, ": ", 2); + mrb_str_cat_lit(mrb, str, ": "); mrb_str_append(mrb, str, mesg); } else { - mrb_str_cat(mrb, str, ": ", 2); + mrb_str_cat_lit(mrb, str, ": "); mrb_str_cat_cstr(mrb, str, mrb_obj_classname(mrb, exc)); } } @@ -431,8 +431,6 @@ mrb_sys_fail(mrb_state *mrb, const char *mesg) } } -mrb_value mrb_get_backtrace(mrb_state*, mrb_value); - void mrb_init_exception(mrb_state *mrb) { @@ -446,7 +444,7 @@ mrb_init_exception(mrb_state *mrb) mrb_define_method(mrb, e, "to_s", exc_to_s, MRB_ARGS_NONE()); mrb_define_method(mrb, e, "message", exc_message, MRB_ARGS_NONE()); mrb_define_method(mrb, e, "inspect", exc_inspect, MRB_ARGS_NONE()); - mrb_define_method(mrb, e, "backtrace", mrb_get_backtrace, MRB_ARGS_NONE()); + mrb_define_method(mrb, e, "backtrace", mrb_exc_backtrace, MRB_ARGS_NONE()); mrb->eStandardError_class = mrb_define_class(mrb, "StandardError", mrb->eException_class); /* 15.2.23 */ mrb_define_class(mrb, "RuntimeError", mrb->eStandardError_class); /* 15.2.28 */ @@ -460,13 +460,15 @@ mark_context(mrb_state *mrb, struct mrb_context *c) for (i=0; i<e; i++) { mrb_gc_mark(mrb, (struct RBasic*)c->ensure[i]); } - /* mark closure */ - for (ci = c->cibase; ci <= c->ci; ci++) { - if (!ci) continue; - mrb_gc_mark(mrb, (struct RBasic*)ci->env); - mrb_gc_mark(mrb, (struct RBasic*)ci->proc); - mrb_gc_mark(mrb, (struct RBasic*)ci->target_class); + /* mark VM stack */ + if (c->cibase) { + for (ci = c->cibase; ci <= c->ci; ci++) { + mrb_gc_mark(mrb, (struct RBasic*)ci->env); + mrb_gc_mark(mrb, (struct RBasic*)ci->proc); + mrb_gc_mark(mrb, (struct RBasic*)ci->target_class); + } } + /* mark fibers */ if (c->prev && c->prev->fib) { mrb_gc_mark(mrb, (struct RBasic*)c->prev->fib); } diff --git a/src/hash.c b/src/hash.c index 566728253..9d7927bb9 100644 --- a/src/hash.c +++ b/src/hash.c @@ -672,7 +672,7 @@ inspect_hash(mrb_state *mrb, mrb_value hash, int recur) ai = mrb_gc_arena_save(mrb); - if (RSTRING_LEN(str) > 1) mrb_str_cat(mrb, str, ", ", 2); + if (RSTRING_LEN(str) > 1) mrb_str_cat_lit(mrb, str, ", "); str2 = mrb_inspect(mrb, kh_key(h,k)); mrb_str_append(mrb, str, str2); diff --git a/src/kernel.c b/src/kernel.c index 25863c897..e61a602be 100644 --- a/src/kernel.c +++ b/src/kernel.c @@ -585,7 +585,7 @@ get_valid_iv_sym(mrb_state *mrb, mrb_value iv_name) mrb_assert(mrb_symbol_p(iv_name) || mrb_string_p(iv_name)); if (mrb_string_p(iv_name)) { - iv_name_id = mrb_intern_cstr(mrb, RSTRING_PTR(iv_name)); + iv_name_id = mrb_intern(mrb, RSTRING_PTR(iv_name), RSTRING_LEN(iv_name)); valid_iv_name(mrb, iv_name_id, RSTRING_PTR(iv_name), RSTRING_LEN(iv_name)); } else { diff --git a/src/object.c b/src/object.c index 172f2dbda..c6b72640f 100644 --- a/src/object.c +++ b/src/object.c @@ -444,7 +444,7 @@ mrb_any_to_s(mrb_state *mrb, mrb_value obj) mrb_str_buf_cat(mrb, str, "#<", 2); mrb_str_cat_cstr(mrb, str, cname); - mrb_str_cat(mrb, str, ":", 1); + mrb_str_cat_lit(mrb, str, ":"); mrb_str_concat(mrb, str, mrb_ptr_to_str(mrb, mrb_cptr(obj))); mrb_str_buf_cat(mrb, str, ">", 1); diff --git a/src/string.c b/src/string.c index 6424626d2..aa1afec47 100644 --- a/src/string.c +++ b/src/string.c @@ -216,6 +216,9 @@ mrb_value mrb_str_new(mrb_state *mrb, const char *p, size_t len) { struct RString *s; + if ((mrb_int)len < 0) { + mrb_raise(mrb, E_ARGUMENT_ERROR, "negative string size (or size too big)"); + } s = str_new(mrb, p, len); return mrb_obj_value(s); @@ -253,6 +256,9 @@ mrb_value mrb_str_new_static(mrb_state *mrb, const char *p, size_t len) { struct RString *s; + if ((mrb_int)len < 0) { + mrb_raise(mrb, E_ARGUMENT_ERROR, "negative string size (or size too big)"); + } s = mrb_obj_alloc_string(mrb); s->len = len; @@ -2361,7 +2367,7 @@ mrb_str_dump(mrb_state *mrb, mrb_value str) } } } - *q++ = '"'; + *q = '"'; return mrb_obj_value(result); } diff --git a/src/variable.c b/src/variable.c index 957383ad2..c313a8f14 100644 --- a/src/variable.c +++ b/src/variable.c @@ -568,14 +568,14 @@ inspect_i(mrb_state *mrb, mrb_sym sym, mrb_value v, void *p) /* need not to show internal data */ if (RSTRING_PTR(str)[0] == '-') { /* first element */ RSTRING_PTR(str)[0] = '#'; - mrb_str_cat(mrb, str, " ", 1); + mrb_str_cat_lit(mrb, str, " "); } else { - mrb_str_cat(mrb, str, ", ", 2); + mrb_str_cat_lit(mrb, str, ", "); } s = mrb_sym2name_len(mrb, sym, &len); mrb_str_cat(mrb, str, s, len); - mrb_str_cat(mrb, str, "=", 1); + mrb_str_cat_lit(mrb, str, "="); if (mrb_type(v) == MRB_TT_OBJECT) { ins = mrb_any_to_s(mrb, v); } @@ -598,11 +598,11 @@ mrb_obj_iv_inspect(mrb_state *mrb, struct RObject *obj) mrb_str_buf_cat(mrb, str, "-<", 2); mrb_str_cat_cstr(mrb, str, cn); - mrb_str_cat(mrb, str, ":", 1); + mrb_str_cat_lit(mrb, str, ":"); mrb_str_concat(mrb, str, mrb_ptr_to_str(mrb, obj)); iv_foreach(mrb, t, inspect_i, &str); - mrb_str_cat(mrb, str, ">", 1); + mrb_str_cat_lit(mrb, str, ">"); return str; } return mrb_any_to_s(mrb, mrb_obj_value(obj)); @@ -954,7 +954,8 @@ mrb_context_run(mrb_state *mrb, struct RProc *proc, mrb_value self, unsigned int ci = mrb->c->ci; if (!ci->target_class) { /* return from context modifying method (resume/yield) */ if (!MRB_PROC_CFUNC_P(ci[-1].proc)) { - irep = ci[-1].proc->body.irep; + proc = ci[-1].proc; + irep = proc->body.irep; pool = irep->pool; syms = irep->syms; } @@ -1342,7 +1343,7 @@ mrb_context_run(mrb_state *mrb, struct RProc *proc, mrb_value self, unsigned int goto L_RAISE; } if (mrb->c->prev->ci == mrb->c->prev->cibase) { - mrb_value exc = mrb_exc_new_str(mrb, E_RUNTIME_ERROR, mrb_str_new(mrb, "double resume", 13)); + mrb_value exc = mrb_exc_new_str(mrb, E_RUNTIME_ERROR, mrb_str_new_lit(mrb, "double resume")); mrb->exc = mrb_obj_ptr(exc); goto L_RAISE; } @@ -1358,6 +1359,13 @@ mrb_context_run(mrb_state *mrb, struct RProc *proc, mrb_value self, unsigned int localjump_error(mrb, LOCALJUMP_ERROR_BREAK); goto L_RAISE; } + /* break from fiber block */ + if (mrb->c->ci == mrb->c->cibase && mrb->c->ci->pc) { + struct mrb_context *c = mrb->c; + + mrb->c = c->prev; + c->prev = NULL; + } ci = mrb->c->ci = mrb->c->cibase + proc->env->cioff + 1; break; default: @@ -2173,7 +2181,7 @@ mrb_context_run(mrb_state *mrb, struct RProc *proc, mrb_value self, unsigned int mrb_value mrb_run(mrb_state *mrb, struct RProc *proc, mrb_value self) { - return mrb_context_run(mrb, proc, self, mrb->c->ci->argc + 2); /* argc + 2 (receiver and block) */ + return mrb_context_run(mrb, proc, self, mrb->c->ci->argc + 2); /* argc + 2 (receiver and block) */ } void diff --git a/tasks/mrbgem_spec.rake b/tasks/mrbgem_spec.rake index e9caf1d3a..6af28694e 100644 --- a/tasks/mrbgem_spec.rake +++ b/tasks/mrbgem_spec.rake @@ -62,7 +62,7 @@ module MRuby @test_objs = Dir.glob("#{dir}/test/*.{c,cpp,cxx,m,asm,S}").map do |f| objfile(f.relative_path_from(dir).to_s.pathmap("#{build_dir}/%X")) end - @test_preload = 'test/assert.rb' + @test_preload = nil # 'test/assert.rb' @test_args = {} @bins = [] diff --git a/tasks/mrbgems_test.rake b/tasks/mrbgems_test.rake index 36c8e84b7..33f1fdb48 100644 --- a/tasks/mrbgems_test.rake +++ b/tasks/mrbgems_test.rake @@ -6,11 +6,15 @@ MRuby.each_target do file g.test_rbireps => [g.test_rbfiles].flatten + [g.build.mrbcfile] do |t| open(t.name, 'w') do |f| g.print_gem_test_header(f) - test_preload = [g.dir, MRUBY_ROOT].map {|dir| + test_preload = g.test_preload and [g.dir, MRUBY_ROOT].map {|dir| File.expand_path(g.test_preload, dir) }.find {|file| File.exist?(file) } - g.build.mrbc.run f, test_preload, "gem_test_irep_#{g.funcname}_preload" + if test_preload.nil? + f.puts %Q[extern const uint8_t mrbtest_assert_irep[];] + else + g.build.mrbc.run f, test_preload, "gem_test_irep_#{g.funcname}_preload" + end g.test_rbfiles.flatten.each_with_index do |rbfile, i| g.build.mrbc.run f, rbfile, "gem_test_irep_#{g.funcname}_#{i}" end @@ -27,16 +31,20 @@ MRuby.each_target do g.test_rbfiles.count.times do |i| f.puts %Q[ ai = mrb_gc_arena_save(mrb);] f.puts %Q[ mrb2 = mrb_open();] - f.puts %Q[ val3 = mrb_gv_get(mrb, mrb_intern_cstr(mrb, "$mrbtest_verbose"));] + f.puts %Q[ val3 = mrb_gv_get(mrb, mrb_intern_lit(mrb, "$mrbtest_verbose"));] f.puts %Q[ if (mrb_test(val3)) {] - f.puts %Q[ mrb_gv_set(mrb2, mrb_intern_cstr(mrb2, "$mrbtest_verbose"), val3);] + f.puts %Q[ mrb_gv_set(mrb2, mrb_intern_lit(mrb2, "$mrbtest_verbose"), val3);] f.puts %Q[ }] - f.puts %Q[ mrb_load_irep(mrb2, gem_test_irep_#{g.funcname}_preload);] + if test_preload.nil? + f.puts %Q[ mrb_load_irep(mrb2, mrbtest_assert_irep);] + else + f.puts %Q[ mrb_load_irep(mrb2, gem_test_irep_#{g.funcname}_preload);] + end f.puts %Q[ if (mrb2->exc) {] f.puts %Q[ mrb_p(mrb2, mrb_obj_value(mrb2->exc));] f.puts %Q[ exit(EXIT_FAILURE);] f.puts %Q[ }] - f.puts %Q[ mrb_const_set(mrb2, mrb_obj_value(mrb2->object_class), mrb_intern_cstr(mrb2, "GEMNAME"), mrb_str_new(mrb2, "#{g.name}", #{g.name.length}));] + f.puts %Q[ mrb_const_set(mrb2, mrb_obj_value(mrb2->object_class), mrb_intern_lit(mrb2, "GEMNAME"), mrb_str_new(mrb2, "#{g.name}", #{g.name.length}));] unless g.test_args.empty? f.puts %Q[ test_args_hash = mrb_hash_new_capa(mrb, #{g.test_args.length}); ] @@ -45,7 +53,7 @@ MRuby.each_target do escaped_arg_value = arg_value.gsub('\\', '\\\\\\\\').gsub('"', '\"') f.puts %Q[ mrb_hash_set(mrb2, test_args_hash, mrb_str_new(mrb2, "#{escaped_arg_name.to_s}", #{escaped_arg_name.to_s.length}), mrb_str_new(mrb2, "#{escaped_arg_value.to_s}", #{escaped_arg_value.to_s.length})); ] end - f.puts %Q[ mrb_const_set(mrb2, mrb_obj_value(mrb2->object_class), mrb_intern_cstr(mrb2, "TEST_ARGS"), test_args_hash); ] + f.puts %Q[ mrb_const_set(mrb2, mrb_obj_value(mrb2->object_class), mrb_intern_lit(mrb2, "TEST_ARGS"), test_args_hash); ] end f.puts %Q[ mrb_#{g.funcname}_gem_test(mrb2);] unless g.test_objs.empty? @@ -58,16 +66,16 @@ MRuby.each_target do f.puts %Q[ ] %w(ok_test ko_test kill_test).each do |vname| - f.puts %Q[ val2 = mrb_gv_get(mrb2, mrb_intern_cstr(mrb2, "$#{vname}"));] + f.puts %Q[ val2 = mrb_gv_get(mrb2, mrb_intern_lit(mrb2, "$#{vname}"));] f.puts %Q[ if (mrb_fixnum_p(val2)) {] - f.puts %Q[ val1 = mrb_gv_get(mrb, mrb_intern_cstr(mrb, "$#{vname}"));] - f.puts %Q[ mrb_gv_set(mrb, mrb_intern_cstr(mrb, "$#{vname}"), mrb_fixnum_value(mrb_fixnum(val1) + mrb_fixnum(val2)));] + f.puts %Q[ val1 = mrb_gv_get(mrb, mrb_intern_lit(mrb, "$#{vname}"));] + f.puts %Q[ mrb_gv_set(mrb, mrb_intern_lit(mrb, "$#{vname}"), mrb_fixnum_value(mrb_fixnum(val1) + mrb_fixnum(val2)));] f.puts %Q[ }\n] end - f.puts %Q[ ary2 = mrb_gv_get(mrb2, mrb_intern_cstr(mrb2, "$asserts"));] + f.puts %Q[ ary2 = mrb_gv_get(mrb2, mrb_intern_lit(mrb2, "$asserts"));] f.puts %Q[ if (mrb_test(ary2)) {] - f.puts %Q[ ary1 = mrb_gv_get(mrb, mrb_intern_cstr(mrb, "$asserts"));] + f.puts %Q[ ary1 = mrb_gv_get(mrb, mrb_intern_lit(mrb, "$asserts"));] f.puts %Q[ val2 = mrb_ary_shift(mrb2, ary2);] f.puts %Q[ ] f.puts %Q[ while (mrb_test(val2)) {] diff --git a/test/init_mrbtest.c b/test/init_mrbtest.c index 8d01624f0..717578dc8 100644 --- a/test/init_mrbtest.c +++ b/test/init_mrbtest.c @@ -2,6 +2,7 @@ #include "mruby.h" #include "mruby/irep.h" +extern const uint8_t mrbtest_assert_irep[]; extern const uint8_t mrbtest_irep[]; void mrbgemtest_init(mrb_state* mrb); @@ -9,6 +10,7 @@ void mrbgemtest_init(mrb_state* mrb); void mrb_init_mrbtest(mrb_state *mrb) { + mrb_load_irep(mrb, mrbtest_assert_irep); mrb_load_irep(mrb, mrbtest_irep); #ifndef DISABLE_GEMS mrbgemtest_init(mrb); diff --git a/test/mrbtest.rake b/test/mrbtest.rake index 0507981d6..35495889e 100644 --- a/test/mrbtest.rake +++ b/test/mrbtest.rake @@ -8,10 +8,11 @@ MRuby.each_target do mlib = clib.ext(exts.object) mrbs = Dir.glob("#{current_dir}/t/*.rb") init = "#{current_dir}/init_mrbtest.c" - asslib = "#{current_dir}/assert.rb" + ass_c = "#{current_build_dir}/assert.c" + ass_lib = ass_c.ext(exts.object) mrbtest_lib = libfile("#{current_build_dir}/mrbtest") - file mrbtest_lib => [mlib, gems.map(&:test_objs), gems.map { |g| g.test_rbireps.ext(exts.object) }].flatten do |t| + file mrbtest_lib => [mlib, ass_lib, gems.map(&:test_objs), gems.map { |g| g.test_rbireps.ext(exts.object) }].flatten do |t| archiver.run t.name, t.prerequisites end @@ -27,13 +28,21 @@ MRuby.each_target do end end - file mlib => [clib] - file clib => [mrbcfile, init, asslib] + mrbs do |t| + file ass_lib => ass_c + file ass_c => "#{current_dir}/assert.rb" do |t| + FileUtils.mkdir_p File.dirname t.name + open(t.name, 'w') do |f| + mrbc.run f, [t.prerequisites], 'mrbtest_assert_irep' + end + end + + file mlib => clib + file clib => [mrbcfile, init] + mrbs do |t| _pp "GEN", "*.rb", "#{clib.relative_path}" FileUtils.mkdir_p File.dirname(clib) open(clib, 'w') do |f| f.puts IO.read(init) - mrbc.run f, [asslib] + mrbs, 'mrbtest_irep' + mrbc.run f, mrbs, 'mrbtest_irep' gems.each do |g| f.puts %Q[void GENERATED_TMP_mrb_#{g.funcname}_gem_test(mrb_state *mrb);] end diff --git a/test/t/array.rb b/test/t/array.rb index 1398bdc6e..48f2fe0c4 100644 --- a/test/t/array.rb +++ b/test/t/array.rb @@ -51,9 +51,9 @@ assert('Array#[]', '15.2.12.5.4') do assert_equal(nil, [1,2,3].[](-4)) a = [ "a", "b", "c", "d", "e" ] - a[1.1] == "b" and - a[1,2] == ["b", "c"] and - a[1..-2] == ["b", "c", "d"] + assert_equal("b", a[1.1]) + assert_equal(["b", "c"], a[1,2]) + assert_equal(["b", "c", "d"], a[1..-2]) end assert('Array#[]=', '15.2.12.5.5') do diff --git a/test/t/kernel.rb b/test/t/kernel.rb index 2d409940b..c7066fdd9 100644 --- a/test/t/kernel.rb +++ b/test/t/kernel.rb @@ -264,6 +264,16 @@ 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 diff --git a/test/t/syntax.rb b/test/t/syntax.rb index 13cd1198e..ee300c54d 100644 --- a/test/t/syntax.rb +++ b/test/t/syntax.rb @@ -1,3 +1,11 @@ +assert('__FILE__') do + assert_equal 'test/t/syntax.rb', __FILE__ +end + +assert('__LINE__') do + assert_equal 6, __LINE__ +end + assert('super', '11.3.4') do assert_raise NoMethodError do super |
