summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--README.md2
-rw-r--r--doc/guides/mrbconf.md56
-rw-r--r--include/mrbconf.h14
-rw-r--r--include/mruby.h6
-rw-r--r--include/mruby/common.h10
-rw-r--r--include/mruby/string.h3
-rw-r--r--include/mruby/value.h9
-rw-r--r--mrbgems/mruby-bin-mruby/bintest/mruby.rb56
-rw-r--r--mrbgems/mruby-bin-mruby/tools/mruby/mruby.c41
-rw-r--r--mrbgems/mruby-compiler/core/parse.y55
-rw-r--r--mrbgems/mruby-io/src/file.c23
-rw-r--r--mrbgems/mruby-io/src/file_test.c17
-rw-r--r--mrbgems/mruby-io/test/file.rb15
-rw-r--r--mrbgems/mruby-io/test/file_test.rb13
-rw-r--r--mrbgems/mruby-io/test/io.rb61
-rw-r--r--mrbgems/mruby-io/test/mruby_io_test.c6
-rw-r--r--mrbgems/mruby-kernel-ext/test/kernel.rb2
-rw-r--r--mrbgems/mruby-metaprog/test/metaprog.rb24
-rw-r--r--mrbgems/mruby-method/test/method.rb2
-rw-r--r--mrbgems/mruby-socket/src/socket.c7
-rw-r--r--mrbgems/mruby-string-ext/mrblib/string.rb10
-rw-r--r--mrbgems/mruby-string-ext/test/string.rb12
-rw-r--r--mrbgems/mruby-struct/test/struct.rb16
-rw-r--r--mrbgems/mruby-time/src/time.c18
-rw-r--r--mrbgems/mruby-time/test/time.rb126
-rw-r--r--mrblib/string.rb37
-rw-r--r--oss-fuzz/config/mruby.dict105
-rw-r--r--oss-fuzz/config/mruby_fuzzer.options5
-rw-r--r--oss-fuzz/mruby_fuzzer.c18
-rw-r--r--src/class.c25
-rw-r--r--src/etc.c16
-rw-r--r--src/gc.c14
-rw-r--r--src/kernel.c1
-rw-r--r--src/load.c2
-rw-r--r--src/numeric.c2
-rw-r--r--src/object.c6
-rw-r--r--src/string.c103
-rw-r--r--src/variable.c2
-rw-r--r--src/vm.c13
-rw-r--r--test/assert.rb2
-rw-r--r--test/t/class.rb26
-rw-r--r--test/t/float.rb8
-rw-r--r--test/t/string.rb11
43 files changed, 601 insertions, 399 deletions
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.
diff --git a/doc/guides/mrbconf.md b/doc/guides/mrbconf.md
index f957f8ce2..3c20b3388 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,27 @@ 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`.
+
+`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.
@@ -144,3 +171,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..6b0b9e37e 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 */
@@ -88,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
diff --git a/include/mruby.h b/include/mruby.h
index de6a803ef..20cdc1b83 100644
--- a/include/mruby.h
+++ b/include/mruby.h
@@ -84,7 +84,7 @@
#endif
#endif
-#include "mruby/common.h"
+#include <mruby/common.h>
#include <mruby/value.h>
#include <mruby/gc.h>
#include <mruby/version.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/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/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..be3dd397f 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 <stdarg.h>
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, ...);
@@ -180,7 +177,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.
@@ -282,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 <mach-o/getsect.h>
static inline mrb_bool
diff --git a/mrbgems/mruby-bin-mruby/bintest/mruby.rb b/mrbgems/mruby-bin-mruby/bintest/mruby.rb
index e8d1510f7..09350ff49 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'
+
+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?")
+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("", /\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
@@ -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("", /\A-e:1:7: syntax error, .*\n\z/, 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("", /\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])
+end
+
assert('mruby -r option') do
lib = Tempfile.new('lib.rb')
lib.write <<EOS
@@ -95,3 +114,32 @@ EOS
assert_equal 'hogeClass', `#{cmd('mruby')} -r #{lib.path} -r #{script.path} -e #{shellquote('print Hoge.class')}`
assert_equal 0, $?.exitstatus
end
+
+assert('mruby -r option (no library specified)') do
+ 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_])
+end
+
+assert('mruby invalid short option') do
+ 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])
+end
+
+assert('unhandled exception') do
+ 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_])
+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 498bedef2..29ab4c17c 100644
--- a/mrbgems/mruby-bin-mruby/tools/mruby/mruby.c
+++ b/mrbgems/mruby-bin-mruby/tools/mruby/mruby.c
@@ -7,19 +7,6 @@
#include <mruby/dump.h>
#include <mruby/variable.h>
-#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,19 +279,16 @@ 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");
+ puts("Syntax OK");
}
}
cleanup(mrb, &args);
- return n == 0 ? EXIT_SUCCESS : EXIT_FAILURE;
+ return n;
}
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;
+ }
}
}
diff --git a/mrbgems/mruby-io/src/file.c b/mrbgems/mruby-io/src/file.c
index c00663481..243f634b4 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,16 +416,16 @@ 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);
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);
}
diff --git a/mrbgems/mruby-io/src/file_test.c b/mrbgems/mruby-io/src/file_test.c
index e429b06b3..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,10 +53,8 @@ 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)) {
- char *path = mrb_locale_from_utf8(mrb_str_to_cstr(mrb, obj), -1);
+ else {
+ char *path = mrb_locale_from_utf8(mrb_string_value_cstr(mrb, &obj), -1);
int ret;
if (do_lstat) {
ret = LSTAT(path, st);
@@ -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.rb b/mrbgems/mruby-io/test/file.rb
index ba4100492..1535ebb44 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
@@ -35,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
@@ -108,6 +107,8 @@ assert('File.realpath') do
MRubyIOTestUtil.rmdir dir
end
end
+
+ assert_raise(ArgumentError) { File.realpath("TO\0DO") }
end
assert("File.readlink") do
@@ -204,6 +205,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..2134c6a75 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")
@@ -22,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
@@ -112,6 +109,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 44eaca6be..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
@@ -84,7 +93,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 +136,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
@@ -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
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-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/mrbgems/mruby-metaprog/test/metaprog.rb b/mrbgems/mruby-metaprog/test/metaprog.rb
index 1262c9945..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 <<self; self end).class_eval do
@@ -171,7 +187,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 +195,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/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-socket/src/socket.c b/mrbgems/mruby-socket/src/socket.c
index dff176778..8515a6057 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"
@@ -130,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 {
@@ -138,9 +139,9 @@ 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 = 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 {
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/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
diff --git a/mrbgems/mruby-time/src/time.c b/mrbgems/mruby-time/src/time.c
index 7f6c3004d..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) {
@@ -576,10 +577,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);
@@ -761,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
@@ -825,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)
@@ -845,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 54c446ca3..ce7b39928 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,30 +21,58 @@ 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(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)
+ 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
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 }
@@ -55,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 }
@@ -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("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
- Time.at(1300000000.0).utc.ctime == "Sun Mar 13 07:06:40 UTC 2011"
+ 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
- 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 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 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("2003-04-05 06:07:08 UTC", Time.gm(2003,4,5,6,7,8,9).to_s)
end
assert('Time#inspect') do
- Time.at(1300000000.0).utc.inspect == "Sun Mar 13 07:06:40 UTC 2011"
+ 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
@@ -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
diff --git a/mrblib/string.rb b/mrblib/string.rb
index c92a9e7be..b0fe4033e 100644
--- a/mrblib/string.rb
+++ b/mrblib/string.rb
@@ -165,20 +165,9 @@ class String
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)
+ return to_enum(:each_byte, &block) unless block
bytes = self.bytes
pos = 0
while pos < bytes.size
@@ -242,26 +231,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
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..132affcae
--- /dev/null
+++ b/oss-fuzz/config/mruby_fuzzer.options
@@ -0,0 +1,5 @@
+[libfuzzer]
+close_fd_mask = 3
+dict = mruby.dict
+fork = 8
+only_ascii = 1
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 <stdlib.h>
+#include <string.h>
+#include <mruby.h>
+#include <mruby/compile.h>
+
+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;
+}
diff --git a/src/class.c b/src/class.c
index 77ff04437..9d26851b9 100644
--- a/src/class.c
+++ b/src/class.c
@@ -120,6 +120,7 @@ prepare_singleton_class(mrb_state *mrb, struct RBasic *o)
mrb_field_write_barrier(mrb, (struct RBasic*)o, (struct RBasic*)sc);
mrb_field_write_barrier(mrb, (struct RBasic*)sc, (struct RBasic*)o);
mrb_obj_iv_set(mrb, (struct RObject*)sc, mrb_intern_lit(mrb, "__attached__"), mrb_obj_value(o));
+ sc->flags |= o->flags & MRB_FL_OBJ_IS_FROZEN;
}
static mrb_value
@@ -837,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/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/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());
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/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;
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/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 */
diff --git a/src/string.c b/src/string.c
index f7a805a94..578e3bdcc 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);
}
@@ -997,20 +1000,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 +1015,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,13 +1107,9 @@ 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);
}
- 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);
}
@@ -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);
@@ -2142,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));
}
}
@@ -2174,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
@@ -2301,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 */
diff --git a/src/variable.c b/src/variable.c
index e859f02bf..ee21a3b96 100644
--- a/src/variable.c
+++ b/src/variable.c
@@ -674,6 +674,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;
@@ -701,6 +702,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/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;
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
diff --git a/test/t/class.rb b/test/t/class.rb
index 290ecf74a..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
@@ -433,6 +440,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 }
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
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]