summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--Rakefile5
-rw-r--r--bintest/mrbc.rb12
-rw-r--r--doc/language/Core.md12
-rw-r--r--doc/mrbconf/README.md38
-rw-r--r--doc/mrbgems/README.md39
-rw-r--r--include/mrbconf.h6
-rw-r--r--include/mruby.h25
-rw-r--r--include/mruby/compile.h2
-rw-r--r--include/mruby/error.h1
-rw-r--r--include/mruby/string.h53
-rw-r--r--include/mruby/value.h4
-rw-r--r--mrbgems/mruby-array-ext/src/array.c75
-rw-r--r--mrbgems/mruby-array-ext/test/array.rb13
-rw-r--r--mrbgems/mruby-bin-mirb/tools/mirb/mirb.c6
-rw-r--r--mrbgems/mruby-bin-mruby/bintest/mruby.rb14
-rw-r--r--mrbgems/mruby-enum-ext/mrblib/enum.rb26
-rw-r--r--mrbgems/mruby-enum-ext/test/enum.rb16
-rw-r--r--mrbgems/mruby-fiber/test/fiber.rb38
-rw-r--r--mrbgems/mruby-hash-ext/mrblib/hash.rb11
-rw-r--r--mrbgems/mruby-hash-ext/test/hash.rb6
-rw-r--r--mrbgems/mruby-kernel-ext/src/kernel.c2
-rw-r--r--mrbgems/mruby-proc-ext/test/proc.rb2
-rw-r--r--mrbgems/mruby-sprintf/mrblib/string.rb9
-rw-r--r--mrbgems/mruby-sprintf/test/sprintf.rb9
-rw-r--r--mrbgems/mruby-string-ext/mrblib/string.rb163
-rw-r--r--mrbgems/mruby-string-ext/src/string.c66
-rw-r--r--mrbgems/mruby-string-ext/test/string.rb90
-rw-r--r--mrbgems/mruby-string-utf8/mrbgem.rake1
-rw-r--r--mrbgems/mruby-string-utf8/src/string.c133
-rw-r--r--mrbgems/mruby-string-utf8/test/string.rb41
-rw-r--r--mrbgems/mruby-struct/src/struct.c108
-rw-r--r--mrbgems/mruby-struct/test/struct.rb7
-rw-r--r--mrbgems/mruby-time/src/time.c2
-rw-r--r--mrbgems/mruby-time/test/time.rb4
-rw-r--r--mrblib/error.rb6
-rw-r--r--mrblib/kernel.rb35
-rw-r--r--mrblib/mrblib.rake4
-rw-r--r--mrblib/print.rb18
-rw-r--r--src/backtrace.c1
-rw-r--r--src/class.c3
-rw-r--r--src/codegen.c37
-rw-r--r--src/dump.c1
-rw-r--r--src/error.c31
-rw-r--r--src/gc.c16
-rw-r--r--src/hash.c3
-rw-r--r--src/init.c8
-rw-r--r--src/kernel.c6
-rw-r--r--src/mruby_core.rake4
-rw-r--r--src/parse.y88
-rw-r--r--src/state.c35
-rw-r--r--src/string.c312
-rw-r--r--src/variable.c12
-rw-r--r--src/vm.c18
-rw-r--r--tasks/libmruby.rake6
-rw-r--r--tasks/mrbgem_spec.rake50
-rw-r--r--tasks/mrbgems.rake15
-rw-r--r--tasks/mrbgems_test.rake4
-rw-r--r--tasks/mruby_build.rake1
-rw-r--r--tasks/mruby_build_gem.rake5
-rw-r--r--tasks/toolchains/gcc.rake2
-rw-r--r--tasks/toolchains/visualcpp.rake2
-rw-r--r--test/mrbtest.rake6
-rw-r--r--test/t/argumenterror.rb5
-rw-r--r--test/t/array.rb4
-rw-r--r--test/t/class.rb4
-rw-r--r--test/t/enumerable.rb8
-rw-r--r--test/t/exception.rb17
-rw-r--r--test/t/false.rb4
-rw-r--r--test/t/float.rb4
-rw-r--r--test/t/hash.rb4
-rw-r--r--test/t/indexerror.rb4
-rw-r--r--test/t/integer.rb4
-rw-r--r--test/t/kernel.rb3
-rw-r--r--test/t/module.rb4
-rw-r--r--test/t/nameerror.rb4
-rw-r--r--test/t/nil.rb4
-rw-r--r--test/t/nomethoderror.rb13
-rw-r--r--test/t/numeric.rb4
-rw-r--r--test/t/proc.rb8
-rw-r--r--test/t/range.rb4
-rw-r--r--test/t/rangeerror.rb4
-rw-r--r--test/t/standarderror.rb4
-rw-r--r--test/t/string.rb11
-rw-r--r--test/t/superclass.rb46
-rw-r--r--test/t/symbol.rb4
-rw-r--r--test/t/true.rb4
-rw-r--r--test/t/typeerror.rb5
-rw-r--r--tools/mrbc/mrbc.c2
88 files changed, 1277 insertions, 673 deletions
diff --git a/Rakefile b/Rakefile
index 681c20d05..135c7a6a2 100644
--- a/Rakefile
+++ b/Rakefile
@@ -123,3 +123,8 @@ task :deep_clean => ["clean"] do
end
puts "Cleaned up mrbgems build folder"
end
+
+desc 'generate document'
+task :doc do
+ load "#{MRUBY_ROOT}/doc/language/generator.rb"
+end
diff --git a/bintest/mrbc.rb b/bintest/mrbc.rb
new file mode 100644
index 000000000..b016378a1
--- /dev/null
+++ b/bintest/mrbc.rb
@@ -0,0 +1,12 @@
+require 'tempfile'
+
+assert('Compiling multiple files without new line in last line. #2361') do
+ a, b, out = Tempfile.new('a.rb'), Tempfile.new('b.rb'), Tempfile.new('out.mrb')
+ a.write('module A; end')
+ a.flush
+ b.write('module B; end')
+ b.flush
+ result = `bin/mrbc -c -o #{out.path} #{a.path} #{b.path} 2>&1`
+ assert_equal "bin/mrbc:#{a.path}:Syntax OK", result.chomp
+ assert_equal 0, $?.exitstatus
+end
diff --git a/doc/language/Core.md b/doc/language/Core.md
index 033939865..d7331e7f3 100644
--- a/doc/language/Core.md
+++ b/doc/language/Core.md
@@ -1328,6 +1328,12 @@ ISO Code | Source File | C Function
--- | --- | ---
15.3.1.2.5 | src/kernel.c | mrb_f_block_given_p_m
+#### local_variables
+
+ISO Code | Source File | C Function
+--- | --- | ---
+15.3.1.2.7 | src/kernel.c | mrb_local_variables
+
#### raise
ISO Code | Source File | C Function
@@ -1498,6 +1504,12 @@ ISO Code | Source File | C Function
--- | --- | ---
15.3.1.3.26 | src/kernel.c | mrb_obj_is_kind_of_m
+#### local_variables
+
+ISO Code | Source File | C Function
+--- | --- | ---
+15.3.1.3.28 | src/kernel.c | mrb_local_variables
+
#### methods
ISO Code | Source File | C Function
diff --git a/doc/mrbconf/README.md b/doc/mrbconf/README.md
new file mode 100644
index 000000000..930e185da
--- /dev/null
+++ b/doc/mrbconf/README.md
@@ -0,0 +1,38 @@
+# mruby configuration macros.
+
+## stdio setting.
+`ENABLE_STDIO`
+* Will be defined automatically if `DISABLE_STDIO` isn't defined.
+* Uses `<stdio.h>` functions.
+
+`DISABLE_STDIO`
+* When defined `<stdio.h>` functions won't be used.
+
+## Debug macros.
+`ENABLE_DEBUG`
+* When defined code fetch hook and debug OP hook will be enabled.
+* When using any of the hook set function pointer `code_fetch_hook` and/or `debug_op_hook` of `mrb_state`.
+* Fetch hook will be called before any OP.
+* Debug OP hook will be called when dispatching `OP_DEBUG`.
+
+`DISABLE_DEBUG`
+* Will be define automatically if `ENABLE_DEBUG` isn't defined.
+
+`MRB_DEBUG`
+* When defined `mrb_assert*` macro will be defined with macros from `<assert.h>`.
+* Could be enabled via `enable_debug` method of `MRuby::Build`.
+
+## Stack configuration
+
+`MRB_STACK_EXTEND_DOUBLING`
+* If defined doubles the stack size when extending it.
+* Else extends stack with `MRB_STACK_GROWTH`.
+
+`MRB_STACK_GROWTH`
+* Default value is `128`.
+* Used in stack extending.
+* Ignored when `MRB_STACK_EXTEND_DOUBLING` is defined.
+
+`MRB_STACK_MAX`
+* Default value is `0x40000 - MRB_STACK_GROWTH`.
+* Raises `RuntimeError` when stack size exceeds this value.
diff --git a/doc/mrbgems/README.md b/doc/mrbgems/README.md
index 7ac225730..231914905 100644
--- a/doc/mrbgems/README.md
+++ b/doc/mrbgems/README.md
@@ -76,6 +76,8 @@ The maximal GEM structure looks like this:
+- GEM_NAME <- Name of GEM
|
+ +- include/ <- Header for Ruby extension (will exported)
+ |
+- mrblib/ <- Source for Ruby extension
|
+- src/ <- Source for C extension
@@ -87,10 +89,10 @@ The maximal GEM structure looks like this:
+- README.md <- Readme for GEM
The folder *mrblib* contains pure Ruby files to extend mruby. The folder *src*
-contains C files to extend mruby. The folder *test* contains C and pure Ruby files
-for testing purposes which will be used by `mrbtest`. *mrbgem.rake* contains
-the specification to compile C and Ruby files. *README.md* is a short description
-of your GEM.
+contains C/C++ files to extend mruby. The folder *include* contains C/C++ header
+files. The folder *test* contains C/C++ and pure Ruby files for testing purposes
+which will be used by `mrbtest`. *mrbgem.rake* contains the specification
+to compile C and Ruby files. *README.md* is a short description of your GEM.
## Build process
@@ -159,6 +161,22 @@ Its format is same as argument of method `MRuby::Build#gem`, expect that it can'
When a special version of depedency is required,
use `MRuby::Build#gem` in *build_config.rb* to override default gem.
+If you have conflicting GEMs use the following method:
+* `spec.add_conflict(gem, *requirements)`
+ * The `requirements` argument is same as in `add_dependency` method.
+
+like following code:
+
+ MRuby::Gem::Specification.new 'some-regexp-binding' do |spec|
+ spec.license = 'BSD'
+ spec.author = 'John Doe'
+
+ spec.add_conflict 'mruby-onig-regexp', '> 0.0.0'
+ spec.add_conflict 'mruby-hs-regexp'
+ spec.add_conflict 'mruby-pcre-regexp'
+ spec.add_conflict 'mruby-regexp-pcre'
+ end
+
In case your GEM has more complex build requirements you can use
the following options additionally inside of your GEM specification:
@@ -173,6 +191,19 @@ the following options additionally inside of your GEM specification:
* `spec.test_objs` (Object test files for integration into mrbtest)
* `spec.test_preload` (Initialization files for mrbtest)
+### include_paths and depencency
+
+Your GEM can export include paths to another GEMs that depends on your GEM.
+By default, `/...absolute path.../{GEM_NAME}/include` will be exported.
+So it is recommended not to put GEM's local header files on include/.
+
+These exports are retroactive.
+For example: when B depends to C and A depends to B, A will get include paths exported by C.
+
+Exported include_paths are automatically appended to GEM local include_paths by Minirake.
+You can use `spec.export_include_paths` accessor if you want more complex build.
+
+
## C Extension
mruby can be extended with C. This is possible by using the C API to
diff --git a/include/mrbconf.h b/include/mrbconf.h
index c84b32cd8..ac33ff0bf 100644
--- a/include/mrbconf.h
+++ b/include/mrbconf.h
@@ -59,6 +59,12 @@
/* fixed size GC arena */
//#define MRB_GC_FIXED_ARENA
+/* state atexit stack size */
+//#define MRB_FIXED_STATE_ATEXIT_STACK_SIZE 5
+
+/* fixed size state atexit stack */
+//#define MRB_FIXED_STATE_ATEXIT_STACK
+
/* -DDISABLE_XXXX to drop following features */
//#define DISABLE_STDIO /* use of stdio */
diff --git a/include/mruby.h b/include/mruby.h
index c1f45bf0b..7b9f1b428 100644
--- a/include/mruby.h
+++ b/include/mruby.h
@@ -52,6 +52,10 @@ typedef void* (*mrb_allocf) (struct mrb_state *mrb, void*, size_t, void *ud);
#define MRB_GC_ARENA_SIZE 100
#endif
+#ifndef MRB_FIXED_STATE_ATEXIT_STACK_SIZE
+#define MRB_FIXED_STATE_ATEXIT_STACK_SIZE 5
+#endif
+
typedef struct {
mrb_sym mid;
struct RProc *proc;
@@ -102,6 +106,8 @@ enum gc_state {
struct mrb_jmpbuf;
+typedef void (*mrb_atexit_func)(struct mrb_state*);
+
typedef struct mrb_state {
struct mrb_jmpbuf *jmp;
@@ -167,8 +173,16 @@ typedef struct mrb_state {
struct RClass *eException_class;
struct RClass *eStandardError_class;
+ struct RObject *nomem_err; /* pre-allocated NoMemoryError */
void *ud; /* auxiliary data */
+
+#ifdef MRB_FIXED_STATE_ATEXIT_STACK
+ mrb_atexit_func atexit_stack[MRB_FIXED_STATE_ATEXIT_STACK_SIZE];
+#else
+ mrb_atexit_func *atexit_stack;
+#endif
+ mrb_int atexit_stack_len;
} mrb_state;
#if __STDC_VERSION__ >= 201112L
@@ -328,8 +342,7 @@ mrb_value mrb_obj_clone(mrb_state *mrb, mrb_value self);
/* need to include <ctype.h> to use these macros */
#ifndef ISPRINT
-/* #define ISASCII(c) isascii((int)(unsigned char)(c)) */
-#define ISASCII(c) 1
+#define ISASCII(c) (!(((int)(unsigned char)(c)) & ~0x7f))
#define ISPRINT(c) (ISASCII(c) && isprint((int)(unsigned char)(c)))
#define ISSPACE(c) (ISASCII(c) && isspace((int)(unsigned char)(c)))
#define ISUPPER(c) (ISASCII(c) && isupper((int)(unsigned char)(c)))
@@ -413,6 +426,8 @@ void* mrb_pool_realloc(struct mrb_pool*, void*, size_t oldlen, size_t newlen);
mrb_bool mrb_pool_can_realloc(struct mrb_pool*, void*, size_t);
void* mrb_alloca(mrb_state *mrb, size_t);
+void mrb_state_atexit(mrb_state *mrb, mrb_atexit_func func);
+
#ifdef MRB_DEBUG
#include <assert.h>
#define mrb_assert(p) assert(p)
@@ -422,6 +437,12 @@ void* mrb_alloca(mrb_state *mrb, size_t);
#define mrb_assert_int_fit(t1,n,t2,max) ((void)0)
#endif
+#if __STDC_VERSION__ >= 201112L
+#define mrb_static_assert(exp, str) _Static_assert(exp, str)
+#else
+#define mrb_static_assert(exp, str) mrb_assert(exp)
+#endif
+
mrb_value mrb_format(mrb_state *mrb, const char *format, ...);
#if defined(__cplusplus)
diff --git a/include/mruby/compile.h b/include/mruby/compile.h
index 9af9c39c6..7f896e1fd 100644
--- a/include/mruby/compile.h
+++ b/include/mruby/compile.h
@@ -35,6 +35,8 @@ void mrbc_context_free(mrb_state *mrb, mrbc_context *cxt);
const char *mrbc_filename(mrb_state *mrb, mrbc_context *c, const char *s);
void mrbc_partial_hook(mrb_state *mrb, mrbc_context *c, int (*partial_hook)(struct mrb_parser_state*), void*data);
+mrb_value mrb_toplevel_run_keep(mrb_state*, struct RProc*, unsigned int);
+
/* AST node structure */
typedef struct mrb_ast_node {
struct mrb_ast_node *car, *cdr;
diff --git a/include/mruby/error.h b/include/mruby/error.h
index 7ae2d4348..4d37f1701 100644
--- a/include/mruby/error.h
+++ b/include/mruby/error.h
@@ -19,6 +19,7 @@ void mrb_exc_print(mrb_state *mrb, struct RObject *exc);
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);
+mrb_noreturn void mrb_no_method_error(mrb_state *mrb, mrb_sym id, mrb_int argc, const mrb_value *argv, const char *fmt, ...);
/* declaration for fail method */
mrb_value mrb_f_raise(mrb_state*, mrb_value);
diff --git a/include/mruby/string.h b/include/mruby/string.h
index dd73f5f1e..f8a1fa7bd 100644
--- a/include/mruby/string.h
+++ b/include/mruby/string.h
@@ -11,8 +11,6 @@
extern "C" {
#endif
-#define IS_EVSTR(p,e) ((p) < (e) && (*(p) == '$' || *(p) == '@' || *(p) == '{'))
-
extern const char mrb_digitmap[];
#define RSTRING_EMBED_LEN_MAX ((mrb_int)(sizeof(void*) * 3 - 1))
@@ -32,21 +30,42 @@ struct RString {
} as;
};
-#define mrb_str_ptr(s) ((struct RString*)(mrb_ptr(s)))
-#define RSTRING(s) ((struct RString*)(mrb_ptr(s)))
-#define RSTRING_PTR(s)\
- ((RSTRING(s)->flags & MRB_STR_EMBED) ?\
- RSTRING(s)->as.ary :\
- RSTRING(s)->as.heap.ptr)
-#define RSTRING_LEN(s)\
- ((RSTRING(s)->flags & MRB_STR_EMBED) ?\
- (mrb_int)((RSTRING(s)->flags & MRB_STR_EMBED_LEN_MASK) >> MRB_STR_EMBED_LEN_SHIFT) :\
- RSTRING(s)->as.heap.len)
-#define RSTRING_CAPA(s)\
- ((RSTRING(s)->flags & MRB_STR_EMBED) ?\
- RSTRING_EMBED_LEN_MAX :\
- RSTRING(s)->as.heap.aux.capa)
-#define RSTRING_END(s) (RSTRING_PTR(s) + RSTRING_LEN(s))
+#define RSTR_EMBED_P(s) ((s)->flags & MRB_STR_EMBED)
+#define RSTR_SET_EMBED_FLAG(s) ((s)->flags |= MRB_STR_EMBED)
+#define RSTR_UNSET_EMBED_FLAG(s) ((s)->flags &= ~(MRB_STR_EMBED|MRB_STR_EMBED_LEN_MASK))
+#define RSTR_SET_EMBED_LEN(s, n) do {\
+ size_t tmp_n = (n);\
+ s->flags &= ~MRB_STR_EMBED_LEN_MASK;\
+ s->flags |= (tmp_n) << MRB_STR_EMBED_LEN_SHIFT;\
+} while (0)
+#define RSTR_SET_LEN(s, n) do {\
+ if (RSTR_EMBED_P(s)) {\
+ RSTR_SET_EMBED_LEN((s),(n));\
+ } else {\
+ s->as.heap.len = (mrb_int)(n);\
+ }\
+} while (0)
+#define RSTR_EMBED_LEN(s)\
+ (mrb_int)(((s)->flags & MRB_STR_EMBED_LEN_MASK) >> MRB_STR_EMBED_LEN_SHIFT)
+#define RSTR_PTR(s) ((RSTR_EMBED_P(s)) ? (s)->as.ary : (s)->as.heap.ptr)
+#define RSTR_LEN(s) ((RSTR_EMBED_P(s)) ? RSTR_EMBED_LEN(s) : (s)->as.heap.len)
+#define RSTR_CAPA(s) (RSTR_EMBED_P(s) ? RSTRING_EMBED_LEN_MAX : (s)->as.heap.aux.capa)
+
+#define RSTR_SHARED_P(s) ((s)->flags & MRB_STR_SHARED)
+#define RSTR_SET_SHARED_FLAG(s) ((s)->flags |= MRB_STR_SHARED)
+#define RSTR_UNSET_SHARED_FLAG(s) ((s)->flags &= ~MRB_STR_SHARED)
+
+#define RSTR_NOFREE_P(s) ((s)->flags & MRB_STR_NOFREE)
+#define RSTR_SET_NOFREE_FLAG(s) ((s)->flags |= MRB_STR_NOFREE)
+#define RSTR_UNSET_NOFREE_FLAG(s) ((s)->flags &= ~MRB_STR_NOFREE)
+
+#define mrb_str_ptr(s) ((struct RString*)(mrb_ptr(s)))
+#define RSTRING(s) mrb_str_ptr(s)
+#define RSTRING_PTR(s) RSTR_PTR(RSTRING(s))
+#define RSTRING_EMBED_LEN(s) RSTR_ENBED_LEN(RSTRING(s))
+#define RSTRING_LEN(s) RSTR_LEN(RSTRING(s))
+#define RSTRING_CAPA(s) RSTR_CAPA(RSTRING(s))
+#define RSTRING_END(s) (RSTRING_PTR(s) + RSTRING_LEN(s))
mrb_int mrb_str_strlen(mrb_state*, struct RString*);
#define MRB_STR_SHARED 1
diff --git a/include/mruby/value.h b/include/mruby/value.h
index 83696715d..98af9626d 100644
--- a/include/mruby/value.h
+++ b/include/mruby/value.h
@@ -70,7 +70,9 @@ typedef short mrb_sym;
# ifndef __cplusplus
# define inline __inline
# endif
-# define snprintf _snprintf
+# if _MSC_VER < 1900
+# define snprintf _snprintf
+# endif
# if _MSC_VER < 1800
# include <float.h>
# define isfinite(n) _finite(n)
diff --git a/mrbgems/mruby-array-ext/src/array.c b/mrbgems/mruby-array-ext/src/array.c
index ae9d8296e..d69f0ac44 100644
--- a/mrbgems/mruby-array-ext/src/array.c
+++ b/mrbgems/mruby-array-ext/src/array.c
@@ -2,35 +2,7 @@
#include "mruby/value.h"
#include "mruby/array.h"
#include "mruby/range.h"
-
-/*
- * call-seq:
- * Array.try_convert(obj) -> array or nil
- *
- * Try to convert <i>obj</i> into an array, using +to_ary+ method.
- * Returns converted array or +nil+ if <i>obj</i> cannot be converted
- * for any reason. This method can be used to check if an argument is an
- * array.
- *
- * Array.try_convert([1]) #=> [1]
- * Array.try_convert("1") #=> nil
- *
- * if tmp = Array.try_convert(arg)
- * # the argument is an array
- * elsif tmp = String.try_convert(arg)
- * # the argument is a string
- * end
- *
- */
-
-static mrb_value
-mrb_ary_s_try_convert(mrb_state *mrb, mrb_value self)
-{
- mrb_value ary;
-
- mrb_get_args(mrb, "o", &ary);
- return mrb_check_array_type(mrb, ary);
-}
+#include "mruby/hash.h"
/*
* call-seq:
@@ -134,17 +106,58 @@ mrb_ary_values_at(mrb_state *mrb, mrb_value self)
return mrb_get_values_at(mrb, self, RARRAY_LEN(self), argc, argv, mrb_ary_ref);
}
+/*
+ * call-seq:
+ * ary.to_h -> Hash
+ *
+ * Returns the result of interpreting <i>aray</i> as an array of
+ * <tt>[key, value]</tt> paris.
+ *
+ * [[:foo, :bar], [1, 2]].to_h
+ * # => {:foo => :bar, 1 => 2}
+ */
+
+static mrb_value
+mrb_ary_to_h(mrb_state *mrb, mrb_value ary)
+{
+ mrb_int i;
+ mrb_value v, hash;
+
+ hash = mrb_hash_new_capa(mrb, 0);
+
+ for (i = 0; i < RARRAY_LEN(ary); ++i) {
+ v = mrb_check_array_type(mrb, RARRAY_PTR(ary)[i]);
+
+ if (mrb_nil_p(v)) {
+ mrb_raisef(mrb, E_TYPE_ERROR, "wrong element type %S at %S (expected array)",
+ mrb_str_new_cstr(mrb, mrb_obj_classname(mrb, RARRAY_PTR(ary)[i])),
+ mrb_fixnum_value(i)
+ );
+ }
+
+ if (RARRAY_LEN(v) != 2) {
+ mrb_raisef(mrb, E_ARGUMENT_ERROR, "wrong array length at %S (expected 2, was %S)",
+ mrb_fixnum_value(i),
+ mrb_fixnum_value(RARRAY_LEN(v))
+ );
+ }
+
+ mrb_hash_set(mrb, hash, RARRAY_PTR(v)[0], RARRAY_PTR(v)[1]);
+ }
+
+ return hash;
+}
+
void
mrb_mruby_array_ext_gem_init(mrb_state* mrb)
{
struct RClass * a = mrb->array_class;
- mrb_define_class_method(mrb, a, "try_convert", mrb_ary_s_try_convert, MRB_ARGS_REQ(1));
-
mrb_define_method(mrb, a, "assoc", mrb_ary_assoc, MRB_ARGS_REQ(1));
mrb_define_method(mrb, a, "at", mrb_ary_at, MRB_ARGS_REQ(1));
mrb_define_method(mrb, a, "rassoc", mrb_ary_rassoc, MRB_ARGS_REQ(1));
mrb_define_method(mrb, a, "values_at", mrb_ary_values_at, MRB_ARGS_ANY());
+ mrb_define_method(mrb, a, "to_h", mrb_ary_to_h, MRB_ARGS_REQ(0));
}
void
diff --git a/mrbgems/mruby-array-ext/test/array.rb b/mrbgems/mruby-array-ext/test/array.rb
index 1fa7cfc04..8c919f7e0 100644
--- a/mrbgems/mruby-array-ext/test/array.rb
+++ b/mrbgems/mruby-array-ext/test/array.rb
@@ -1,11 +1,6 @@
##
# Array(Ext) Test
-assert("Array::try_convert") do
- assert_equal [1], Array.try_convert([1])
- assert_nil Array.try_convert("1")
-end
-
assert("Array#assoc") do
s1 = [ "colors", "red", "blue", "green" ]
s2 = [ "letters", "a", "b", "c" ]
@@ -290,3 +285,11 @@ assert('Array#values_at') do
assert_equal ['none', nil, nil, 'red', 'green', 'purple'], a.values_at(4..6, 0...3)
assert_raise(TypeError) { a.values_at 'tt' }
end
+
+assert('Array#to_h') do
+ assert_equal({}, [].to_h)
+ assert_equal({a: 1, b:2}, [[:a, 1], [:b, 2]].to_h)
+
+ assert_raise(TypeError) { [1].to_h }
+ assert_raise(ArgumentError) { [[1]].to_h }
+end
diff --git a/mrbgems/mruby-bin-mirb/tools/mirb/mirb.c b/mrbgems/mruby-bin-mirb/tools/mirb/mirb.c
index 5c9524161..dece361a5 100644
--- a/mrbgems/mruby-bin-mirb/tools/mirb/mirb.c
+++ b/mrbgems/mruby-bin-mirb/tools/mirb/mirb.c
@@ -258,7 +258,7 @@ check_keyword(const char *buf, const char *word)
size_t len = strlen(word);
/* skip preceding spaces */
- while (*p && isspace(*p)) {
+ while (*p && isspace((unsigned char)*p)) {
p++;
}
/* check keyword */
@@ -268,7 +268,7 @@ check_keyword(const char *buf, const char *word)
p += len;
/* skip trailing spaces */
while (*p) {
- if (!isspace(*p)) return 0;
+ if (!isspace((unsigned char)*p)) return 0;
p++;
}
return 1;
@@ -424,7 +424,7 @@ main(int argc, char **argv)
else {
/* no */
if (!mrb_respond_to(mrb, result, mrb_intern_lit(mrb, "inspect"))){
- result = mrb_any_to_s(mrb,result);
+ result = mrb_any_to_s(mrb, result);
}
p(mrb, result, 1);
}
diff --git a/mrbgems/mruby-bin-mruby/bintest/mruby.rb b/mrbgems/mruby-bin-mruby/bintest/mruby.rb
index a453400fc..de211c1ba 100644
--- a/mrbgems/mruby-bin-mruby/bintest/mruby.rb
+++ b/mrbgems/mruby-bin-mruby/bintest/mruby.rb
@@ -30,3 +30,17 @@ assert '$0 value' do
# one liner
assert_equal '"-e"', `./bin/mruby -e 'p $0'`.chomp
end
+
+assert '__END__', '8.6' do
+ script = Tempfile.new('test.rb')
+
+ script.write <<EOS
+p 'test'
+ __END__ = 'fin'
+p __END__
+__END__
+p 'legend'
+EOS
+ script.flush
+ assert_equal "\"test\"\n\"fin\"\n", `./bin/mruby #{script.path}`
+end
diff --git a/mrbgems/mruby-enum-ext/mrblib/enum.rb b/mrbgems/mruby-enum-ext/mrblib/enum.rb
index 5abb75d54..b13d00a84 100644
--- a/mrbgems/mruby-enum-ext/mrblib/enum.rb
+++ b/mrbgems/mruby-enum-ext/mrblib/enum.rb
@@ -669,4 +669,30 @@ module Enumerable
end
ary
end
+
+ ##
+ # call-seq:
+ # enum.to_h -> hash
+ #
+ # Returns the result of interpreting <i>enum</i> as a list of
+ # <tt>[key, value]</tt> pairs.
+ #
+ # %i[hello world].each_with_index.to_h
+ # # => {:hello => 0, :world => 1}
+ #
+
+ def to_h
+ h = {}
+ self.each do |*v|
+ v = v.__svalue
+ raise TypeError, "wrong element type #{v.class} (expected Array)" unless v.is_a? Array
+ raise ArgumentError, "element has wrong array length (expected 2, was #{v.size})" if v.size != 2
+ h[v[0]] = v[1]
+ end
+ h
+ end
+
+ def nil.to_h
+ {}
+ end
end
diff --git a/mrbgems/mruby-enum-ext/test/enum.rb b/mrbgems/mruby-enum-ext/test/enum.rb
index bce9cb15d..08b553fe5 100644
--- a/mrbgems/mruby-enum-ext/test/enum.rb
+++ b/mrbgems/mruby-enum-ext/test/enum.rb
@@ -144,3 +144,19 @@ assert("Enumerable#zip") do
assert_equal [[1, 4, 7], [2, 5, 8]], [1, 2].zip(a, b)
assert_equal [[4, 1, 8], [5, 2, nil], [6, nil, nil]], a.zip([1, 2], [8])
end
+
+assert("Enumerable#to_h") do
+ c = Class.new {
+ include Enumerable
+ def each
+ yield [1,2]
+ yield [3,4]
+ end
+ }
+ h0 = {1=>2, 3=>4}
+ h = c.new.to_h
+ assert_equal Hash, h.class
+ assert_equal h0, h
+ # mruby-enum-ext also provides nil.to_h
+ assert_equal Hash.new, nil.to_h
+end
diff --git a/mrbgems/mruby-fiber/test/fiber.rb b/mrbgems/mruby-fiber/test/fiber.rb
index c2bae2259..d063a0a62 100644
--- a/mrbgems/mruby-fiber/test/fiber.rb
+++ b/mrbgems/mruby-fiber/test/fiber.rb
@@ -1,12 +1,12 @@
-assert('Fiber.new') {
+assert('Fiber.new') do
f = Fiber.new{}
- f.class == Fiber
-}
+ assert_kind_of Fiber, f
+end
-assert('Fiber#resume') {
- f = Fiber.new{|x| x == 2}
- f.resume(2)
-}
+assert('Fiber#resume') do
+ f = Fiber.new{|x| x }
+ assert_equal 2, f.resume(2)
+end
assert('Fiber#transfer') do
f2 = nil
@@ -29,14 +29,13 @@ assert('Fiber#transfer') do
assert_false f2.alive?
end
-assert('Fiber#alive?') {
+assert('Fiber#alive?') do
f = Fiber.new{ Fiber.yield }
f.resume
- r1 = f.alive?
+ assert_true f.alive?
f.resume
- r2 = f.alive?
- r1 == true and r2 == false
-}
+ assert_false f.alive?
+end
assert('Fiber#==') do
root = Fiber.current
@@ -51,16 +50,17 @@ assert('Fiber#==') do
assert_true f != root
end
-assert('Fiber.yield') {
- f = Fiber.new{|x| Fiber.yield(x == 3)}
- f.resume(3)
-}
+assert('Fiber.yield') do
+ f = Fiber.new{|x| Fiber.yield x }
+ assert_equal 3, f.resume(3)
+ assert_true f.alive?
+end
assert('FiberError') do
assert_equal StandardError, FiberError.superclass
end
-assert('Fiber iteration') {
+assert('Fiber iteration') do
f1 = Fiber.new{
[1,2,3].each{|x| Fiber.yield(x)}
}
@@ -72,8 +72,8 @@ assert('Fiber iteration') {
a << f1.resume
a << f2.resume
}
- a == [1,9,2,8,3,7]
-}
+ assert_equal [1,9,2,8,3,7], a
+end
assert('Fiber with splat in the block argument list') {
Fiber.new{|*x|x}.resume(1) == [1]
diff --git a/mrbgems/mruby-hash-ext/mrblib/hash.rb b/mrbgems/mruby-hash-ext/mrblib/hash.rb
index 504848a74..9da08dc3a 100644
--- a/mrbgems/mruby-hash-ext/mrblib/hash.rb
+++ b/mrbgems/mruby-hash-ext/mrblib/hash.rb
@@ -182,4 +182,15 @@ class Hash
end
nil
end
+
+ ##
+ # call-seq:
+ # hsh.to_h -> hsh or new_hash
+ #
+ # Returns +self+. If called on a subclass of Hash, converts
+ # the receiver to a Hash object.
+ #
+ def to_h
+ self
+ end
end
diff --git a/mrbgems/mruby-hash-ext/test/hash.rb b/mrbgems/mruby-hash-ext/test/hash.rb
index 62cfc8856..2bc5b911a 100644
--- a/mrbgems/mruby-hash-ext/test/hash.rb
+++ b/mrbgems/mruby-hash-ext/test/hash.rb
@@ -115,3 +115,9 @@ assert("Hash#key") do
assert_nil h.key('nil')
assert_equal 'nil', h.key(nil)
end
+
+assert("Hash#to_h") do
+ h = { "a" => 100, "b" => 200 }
+ assert_equal Hash, h.to_h.class
+ assert_equal h, h.to_h
+end
diff --git a/mrbgems/mruby-kernel-ext/src/kernel.c b/mrbgems/mruby-kernel-ext/src/kernel.c
index 1ce63ac94..a6ecd72bd 100644
--- a/mrbgems/mruby-kernel-ext/src/kernel.c
+++ b/mrbgems/mruby-kernel-ext/src/kernel.c
@@ -26,7 +26,7 @@ mrb_mruby_kernel_ext_gem_init(mrb_state *mrb)
{
struct RClass *krn = mrb->kernel_module;
- mrb_define_module_function(mrb, krn, "fail", mrb_f_raise, MRB_ARGS_NONE());
+ mrb_define_module_function(mrb, krn, "fail", mrb_f_raise, MRB_ARGS_OPT(2));
mrb_define_method(mrb, krn, "__method__", mrb_f_method, MRB_ARGS_NONE());
}
diff --git a/mrbgems/mruby-proc-ext/test/proc.rb b/mrbgems/mruby-proc-ext/test/proc.rb
index 0f5ecfb94..1565873a0 100644
--- a/mrbgems/mruby-proc-ext/test/proc.rb
+++ b/mrbgems/mruby-proc-ext/test/proc.rb
@@ -10,7 +10,7 @@ end
assert('Proc#inspect') do
ins = Proc.new{}.inspect
- assert_true ins.kind_of? String
+ assert_kind_of String, ins
end
assert('Proc#lambda?') do
diff --git a/mrbgems/mruby-sprintf/mrblib/string.rb b/mrbgems/mruby-sprintf/mrblib/string.rb
new file mode 100644
index 000000000..d7e55536a
--- /dev/null
+++ b/mrbgems/mruby-sprintf/mrblib/string.rb
@@ -0,0 +1,9 @@
+class String
+ def %(args)
+ if args.is_a? Array
+ sprintf(self, *args)
+ else
+ sprintf(self, args)
+ end
+ end
+end
diff --git a/mrbgems/mruby-sprintf/test/sprintf.rb b/mrbgems/mruby-sprintf/test/sprintf.rb
index 52e94fb83..7007df1fa 100644
--- a/mrbgems/mruby-sprintf/test/sprintf.rb
+++ b/mrbgems/mruby-sprintf/test/sprintf.rb
@@ -1,3 +1,8 @@
-##
-# Kernel#sprintf Kernel#format Test
+#assert('Kernel.sprintf') do
+#end
+assert('String#%') do
+ assert_equal "one=1", "one=%d" % 1
+ assert_equal "1 one 1.0", "%d %s %3.1f" % [ 1, "one", 1.01 ]
+ assert_equal "123 < 456", "%{num} < %<str>s" % { num: 123, str: "456" }
+end
diff --git a/mrbgems/mruby-string-ext/mrblib/string.rb b/mrbgems/mruby-string-ext/mrblib/string.rb
index 45c631b94..1acdf150f 100644
--- a/mrbgems/mruby-string-ext/mrblib/string.rb
+++ b/mrbgems/mruby-string-ext/mrblib/string.rb
@@ -1,4 +1,28 @@
class String
+
+ ##
+ # call-seq:
+ # string.clear -> string
+ #
+ # Makes string empty.
+ #
+ # a = "abcde"
+ # a.clear #=> ""
+ #
+ def clear
+ self.replace("")
+ end
+
+ ##
+ # call-seq:
+ # str.lstrip -> new_str
+ #
+ # Returns a copy of <i>str</i> with leading whitespace removed. See also
+ # <code>String#rstrip</code> and <code>String#strip</code>.
+ #
+ # " hello ".lstrip #=> "hello "
+ # "hello".lstrip #=> "hello"
+ #
def lstrip
a = 0
z = self.size - 1
@@ -6,6 +30,16 @@ class String
(z >= 0) ? self[a..z] : ""
end
+ ##
+ # call-seq:
+ # str.rstrip -> new_str
+ #
+ # Returns a copy of <i>str</i> with trailing whitespace removed. See also
+ # <code>String#lstrip</code> and <code>String#strip</code>.
+ #
+ # " hello ".rstrip #=> " hello"
+ # "hello".rstrip #=> "hello"
+ #
def rstrip
a = 0
z = self.size - 1
@@ -13,6 +47,15 @@ class String
(z >= 0) ? self[a..z] : ""
end
+ ##
+ # call-seq:
+ # str.strip -> new_str
+ #
+ # Returns a copy of <i>str</i> with leading and trailing whitespace removed.
+ #
+ # " hello ".strip #=> "hello"
+ # "\tgoodbye\r\n".strip #=> "goodbye"
+ #
def strip
a = 0
z = self.size - 1
@@ -21,31 +64,61 @@ class String
(z >= 0) ? self[a..z] : ""
end
+ ##
+ # call-seq:
+ # str.lstrip! -> self or nil
+ #
+ # Removes leading whitespace from <i>str</i>, returning <code>nil</code> if no
+ # change was made. See also <code>String#rstrip!</code> and
+ # <code>String#strip!</code>.
+ #
+ # " hello ".lstrip #=> "hello "
+ # "hello".lstrip! #=> nil
+ #
def lstrip!
s = self.lstrip
(s == self) ? nil : self.replace(s)
end
+ ##
+ # call-seq:
+ # str.rstrip! -> self or nil
+ #
+ # Removes trailing whitespace from <i>str</i>, returning <code>nil</code> if
+ # no change was made. See also <code>String#lstrip!</code> and
+ # <code>String#strip!</code>.
+ #
+ # " hello ".rstrip #=> " hello"
+ # "hello".rstrip! #=> nil
+ #
def rstrip!
s = self.rstrip
(s == self) ? nil : self.replace(s)
end
+ ##
+ # call-seq:
+ # str.strip! -> str or nil
+ #
+ # Removes leading and trailing whitespace from <i>str</i>. Returns
+ # <code>nil</code> if <i>str</i> was not altered.
+ #
def strip!
s = self.strip
(s == self) ? nil : self.replace(s)
end
-# call-seq:
-# str.casecmp(other_str) -> -1, 0, +1 or nil
-#
-# Case-insensitive version of <code>String#<=></code>.
-#
-# "abcdef".casecmp("abcde") #=> 1
-# "aBcDeF".casecmp("abcdef") #=> 0
-# "abcdef".casecmp("abcdefg") #=> -1
-# "abcdef".casecmp("ABCDEF") #=> 0
-#
+ ##
+ # call-seq:
+ # str.casecmp(other_str) -> -1, 0, +1 or nil
+ #
+ # Case-insensitive version of <code>String#<=></code>.
+ #
+ # "abcdef".casecmp("abcde") #=> 1
+ # "aBcDeF".casecmp("abcdef") #=> 0
+ # "abcdef".casecmp("abcdefg") #=> -1
+ # "abcdef".casecmp("ABCDEF") #=> 0
+ #
def casecmp(str)
self.downcase <=> str.to_str.downcase
rescue NoMethodError
@@ -73,4 +146,74 @@ class String
[ "", "", self ]
end
end
+
+ ##
+ # call-seq:
+ # str.slice!(fixnum) -> new_str or nil
+ # str.slice!(fixnum, fixnum) -> new_str or nil
+ # str.slice!(range) -> new_str or nil
+ # str.slice!(other_str) -> new_str or nil
+ #
+ # Deletes the specified portion from <i>str</i>, and returns the portion
+ # deleted.
+ #
+ # string = "this is a string"
+ # string.slice!(2) #=> "i"
+ # string.slice!(3..6) #=> " is "
+ # string.slice!("r") #=> "r"
+ # string #=> "thsa sting"
+ #
+ def slice!(arg1, arg2=nil)
+ raise "wrong number of arguments (for 1..2)" if arg1 == nil && arg2 == nil
+
+ if arg1 != nil && arg2 != nil
+ idx = arg1
+ idx += self.size if arg1 < 0
+ if idx >= 0 && idx < self.size && arg2 > 0
+ str = self[idx, arg2]
+ else
+ return nil
+ end
+ else
+ validated = false
+ if arg1.kind_of?(Range)
+ beg = arg1.begin
+ ed = arg1.end
+ beg += self.size if beg < 0
+ ed += self.size if ed < 0
+ validated = true
+ elsif arg1.kind_of?(String)
+ validated = true
+ else
+ idx = arg1
+ idx += self.size if arg1 < 0
+ validated = true if idx >=0 && arg1 < self.size
+ end
+ if validated
+ str = self[arg1]
+ else
+ return nil
+ end
+ end
+ unless str == nil || str == ""
+ if arg1 != nil && arg2 !=nil
+ idx = arg1 >= 0 ? arg1 : self.size+arg1
+ str2 = self[0...idx] + self[idx+arg2..-1]
+ else
+ if arg1.kind_of?(Range)
+ idx = beg >= 0 ? beg : self.size+beg
+ idx2 = ed>= 0 ? ed : self.size+ed
+ str2 = self[0...idx] + self[idx2+1..-1]
+ elsif arg1.kind_of?(String)
+ idx = self.index(arg1)
+ str2 = self[0...idx] + self[idx+arg1.size..-1] unless idx == nil
+ else
+ idx = arg1 >= 0 ? arg1 : self.size+arg1
+ str2 = self[0...idx] + self[idx+1..-1]
+ end
+ end
+ self.replace(str2) unless str2 == nil
+ end
+ str
+ end
end
diff --git a/mrbgems/mruby-string-ext/src/string.c b/mrbgems/mruby-string-ext/src/string.c
index 2c0a406ad..f04f12c4b 100644
--- a/mrbgems/mruby-string-ext/src/string.c
+++ b/mrbgems/mruby-string-ext/src/string.c
@@ -1,6 +1,8 @@
#include <ctype.h>
#include <string.h>
#include "mruby.h"
+#include "mruby/array.h"
+#include "mruby/class.h"
#include "mruby/string.h"
static mrb_value
@@ -175,6 +177,68 @@ mrb_str_oct(mrb_state *mrb, mrb_value self)
return mrb_str_to_inum(mrb, self, 8, FALSE);
}
+/*
+ * call-seq:
+ * string.chr -> string
+ *
+ * Returns a one-character string at the beginning of the string.
+ *
+ * a = "abcde"
+ * a.chr #=> "a"
+ */
+static mrb_value
+mrb_str_chr(mrb_state *mrb, mrb_value self)
+{
+ return mrb_str_substr(mrb, self, 0, 1);
+}
+
+/*
+ * call-seq:
+ * string.lines -> array of string
+ *
+ * Returns strings per line;
+ *
+ * a = "abc\ndef"
+ * a.lines #=> ["abc\n", "def"]
+ */
+static mrb_value
+mrb_str_lines(mrb_state *mrb, mrb_value self)
+{
+ mrb_value result;
+ mrb_value blk;
+ int ai;
+ mrb_int len;
+ mrb_value arg;
+ char *p = RSTRING_PTR(self), *t;
+ char *e = p + RSTRING_LEN(self);
+
+ mrb_get_args(mrb, "&", &blk);
+
+ result = mrb_ary_new(mrb);
+
+ if (!mrb_nil_p(blk)) {
+ while (p < e) {
+ t = p;
+ while (p < e && *p != '\n') p++;
+ if (*p == '\n') p++;
+ len = (mrb_int) (p - t);
+ arg = mrb_str_new(mrb, t, len);
+ mrb_yield_argv(mrb, blk, 1, &arg);
+ }
+ return self;
+ }
+ while (p < e) {
+ ai = mrb_gc_arena_save(mrb);
+ t = p;
+ while (p < e && *p != '\n') p++;
+ if (*p == '\n') p++;
+ len = (mrb_int) (p - t);
+ mrb_ary_push(mrb, result, mrb_str_new(mrb, t, len));
+ mrb_gc_arena_restore(mrb, ai);
+ }
+ return result;
+}
+
void
mrb_mruby_string_ext_gem_init(mrb_state* mrb)
{
@@ -190,6 +254,8 @@ mrb_mruby_string_ext_gem_init(mrb_state* mrb)
mrb_define_method(mrb, s, "end_with?", mrb_str_end_with, MRB_ARGS_REST());
mrb_define_method(mrb, s, "hex", mrb_str_hex, MRB_ARGS_NONE());
mrb_define_method(mrb, s, "oct", mrb_str_oct, MRB_ARGS_NONE());
+ mrb_define_method(mrb, s, "chr", mrb_str_chr, MRB_ARGS_NONE());
+ mrb_define_method(mrb, s, "lines", mrb_str_lines, MRB_ARGS_NONE());
}
void
diff --git a/mrbgems/mruby-string-ext/test/string.rb b/mrbgems/mruby-string-ext/test/string.rb
index 01712a607..01c0be9d2 100644
--- a/mrbgems/mruby-string-ext/test/string.rb
+++ b/mrbgems/mruby-string-ext/test/string.rb
@@ -161,3 +161,93 @@ assert('String#oct') do
assert_equal 8, "010".oct
assert_equal (-8), "-10".oct
end
+
+assert('String#chr') do
+ assert_equal "a", "abcde".chr
+end
+
+assert('String#lines') do
+ assert_equal ["Hel\n", "lo\n", "World!"], "Hel\nlo\nWorld!".lines
+ assert_equal ["Hel\n", "lo\n", "World!\n"], "Hel\nlo\nWorld!\n".lines
+ assert_equal ["\n", "\n", "\n"], "\n\n\n".lines
+ assert_equal [], "".lines
+end
+
+assert('String#clear') do
+ # embed string
+ s = "foo"
+ assert_equal("", s.clear)
+ assert_equal("", s)
+
+ # not embed string and not shared string
+ s = "foo" * 100
+ a = s
+ assert_equal("", s.clear)
+ assert_equal("", s)
+ assert_equal("", a)
+
+ # shared string
+ s = "foo" * 100
+ a = s[10, 90] # create shared string
+ assert_equal("", s.clear) # clear
+ assert_equal("", s) # s is cleared
+ assert_not_equal("", a) # a should not be affected
+end
+
+assert('String#slice!') do
+ a = "AooBar"
+ b = a.dup
+ assert_equal "A", a.slice!(0)
+ assert_equal "AooBar", b
+
+ a = "FooBar"
+ assert_equal "r", a.slice!(-1)
+ assert_equal "FooBa", a
+
+ a = "FooBar"
+ assert_nil a.slice!(6)
+ assert_nil a.slice!(-7)
+ assert_equal "FooBar", a
+
+ a = "FooBar"
+ assert_equal "Foo", a.slice!(0, 3)
+ assert_equal "Bar", a
+
+ a = "FooBar"
+ assert_equal "Bar", a.slice!(-3, 3)
+ assert_equal "Foo", a
+
+ a = "FooBar"
+ assert_nil a.slice!(6, 2)
+ assert_equal "FooBar", a
+
+ a = "FooBar"
+ assert_nil a.slice!(-7,10)
+ assert_equal "FooBar", a
+
+ a = "FooBar"
+ assert_equal "Foo", a.slice!(0..2)
+ assert_equal "Bar", a
+
+ a = "FooBar"
+ assert_equal "Bar", a.slice!(-3..-1)
+ assert_equal "Foo", a
+
+ a = "FooBar"
+ assert_equal "", a.slice!(6..2)
+ assert_equal "FooBar", a
+
+ a = "FooBar"
+ assert_nil a.slice!(-10..-7)
+ assert_equal "FooBar", a
+
+ a = "FooBar"
+ assert_equal "Foo", a.slice!("Foo")
+ assert_equal "Bar", a
+
+ a = "FooBar"
+ assert_nil a.slice!("xyzzy")
+ assert_equal "FooBar", a
+
+ assert_raise(ArgumentError) { "foo".slice! }
+end
diff --git a/mrbgems/mruby-string-utf8/mrbgem.rake b/mrbgems/mruby-string-utf8/mrbgem.rake
index 86d0a6da3..7642d4e07 100644
--- a/mrbgems/mruby-string-utf8/mrbgem.rake
+++ b/mrbgems/mruby-string-utf8/mrbgem.rake
@@ -2,4 +2,5 @@ MRuby::Gem::Specification.new('mruby-string-utf8') do |spec|
spec.license = 'MIT'
spec.author = 'mruby developers'
spec.summary = 'UTF-8 support in String class'
+ spec.add_dependency('mruby-string-ext', :core => 'mruby-string-ext')
end
diff --git a/mrbgems/mruby-string-utf8/src/string.c b/mrbgems/mruby-string-utf8/src/string.c
index edda491fc..874fa8dbb 100644
--- a/mrbgems/mruby-string-utf8/src/string.c
+++ b/mrbgems/mruby-string-utf8/src/string.c
@@ -1,17 +1,12 @@
#include "mruby.h"
#include "mruby/array.h"
+#include "mruby/class.h"
#include "mruby/string.h"
#include "mruby/range.h"
#include "mruby/re.h"
#include <ctype.h>
#include <string.h>
-#define STR_EMBED_P(s) ((s)->flags & MRB_STR_EMBED)
-#define STR_EMBED_LEN(s)\
- (mrb_int)(((s)->flags & MRB_STR_EMBED_LEN_MASK) >> MRB_STR_EMBED_LEN_SHIFT)
-#define STR_PTR(s) ((STR_EMBED_P(s)) ? (s)->as.ary : (s)->as.heap.ptr)
-#define STR_LEN(s) ((STR_EMBED_P(s)) ? STR_EMBED_LEN(s) : (mrb_int)(s)->as.heap.len)
-
static const char utf8len_codepage[256] =
{
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
@@ -36,27 +31,6 @@ static char utf8len_codepage_zero[256] =
3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,4,4,4,4,4,0,0,0,0,0,0,0,0,0,0,0,
};
-static const char isspacetable[256] = {
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
-};
-
-#define ascii_isspace(c) isspacetable[(unsigned char)(c)]
-
static mrb_int
utf8code(unsigned char* p)
{
@@ -127,9 +101,7 @@ mrb_utf8_strlen(mrb_value str, mrb_int len)
static mrb_value
mrb_str_size(mrb_state *mrb, mrb_value str)
{
- mrb_int size = mrb_utf8_strlen(str, -1);
-
- return mrb_fixnum_value(size);
+ return mrb_fixnum_value(mrb_utf8_strlen(str, -1));
}
#define RSTRING_LEN_UTF8(s) mrb_utf8_strlen(s, -1)
@@ -161,10 +133,10 @@ mrb_memsearch_qs(const unsigned char *xs, mrb_int m, const unsigned char *ys, mr
qstable[i] = m + 1;
for (; x < xe; ++x)
qstable[*x] = xe - x;
- /* Searching */
+ /* Searching */
for (; y + m <= ys + n; y += *(qstable + y[m])) {
if (*xs == *y && memcmp(xs, y, m) == 0)
- return y - ys;
+ return y - ys;
}
return -1;
}
@@ -272,17 +244,17 @@ str_rindex(mrb_state *mrb, mrb_value str, mrb_value sub, mrb_int pos)
mrb_int len = RSTRING_LEN(sub);
/* substring longer than string */
- if (STR_LEN(ps) < len) return -1;
- if (STR_LEN(ps) - pos < len) {
- pos = STR_LEN(ps) - len;
+ if (RSTR_LEN(ps) < len) return -1;
+ if (RSTR_LEN(ps) - pos < len) {
+ pos = RSTR_LEN(ps) - len;
}
- sbeg = STR_PTR(ps);
- s = STR_PTR(ps) + pos;
+ sbeg = RSTR_PTR(ps);
+ s = RSTR_PTR(ps) + pos;
t = RSTRING_PTR(sub);
if (len) {
while (sbeg <= s) {
if (memcmp(s, t, len) == 0) {
- return s - STR_PTR(ps);
+ return s - RSTR_PTR(ps);
}
s--;
}
@@ -572,7 +544,7 @@ mrb_str_split_m(mrb_state *mrb, mrb_value str)
if (mrb_string_p(spat)) {
split_type = string;
if (RSTRING_LEN(spat) == 1 && RSTRING_PTR(spat)[0] == ' '){
- split_type = awk;
+ split_type = awk;
}
}
else {
@@ -594,7 +566,7 @@ mrb_str_split_m(mrb_state *mrb, mrb_value str)
int ai = mrb_gc_arena_save(mrb);
c = (unsigned char)*ptr++;
if (skip) {
- if (ascii_isspace(c)) {
+ if (ISSPACE(c)) {
beg = ptr - bptr;
}
else {
@@ -603,7 +575,7 @@ mrb_str_split_m(mrb_state *mrb, mrb_value str)
if (lim_p && lim <= i) break;
}
}
- else if (ascii_isspace(c)) {
+ else if (ISSPACE(c)) {
mrb_ary_push(mrb, result, str_subseq(mrb, str, beg, end-beg));
mrb_gc_arena_restore(mrb, ai);
skip = 1;
@@ -667,6 +639,80 @@ mrb_str_split_m(mrb_state *mrb, mrb_value str)
return result;
}
+static mrb_value
+mrb_str_chr(mrb_state *mrb, mrb_value self)
+{
+ return str_substr(mrb, self, 0, 1);
+}
+
+static mrb_value
+mrb_str_chars(mrb_state *mrb, mrb_value self)
+{
+ mrb_value result;
+ mrb_value blk;
+ int ai;
+ mrb_int len;
+ mrb_value arg;
+ char *p = RSTRING_PTR(self);
+ char *e = p + RSTRING_LEN(self);
+
+ mrb_get_args(mrb, "&", &blk);
+
+ result = mrb_ary_new(mrb);
+
+ if (!mrb_nil_p(blk)) {
+ while (p < e) {
+ len = utf8len((unsigned char*) p);
+ arg = mrb_str_new(mrb, p, len);
+ mrb_yield_argv(mrb, blk, 1, &arg);
+ p += len;
+ }
+ return self;
+ }
+ while (p < e) {
+ ai = mrb_gc_arena_save(mrb);
+ len = utf8len((unsigned char*) p);
+ mrb_ary_push(mrb, result, mrb_str_new(mrb, p, len));
+ mrb_gc_arena_restore(mrb, ai);
+ p += len;
+ }
+ return result;
+}
+
+static mrb_value
+mrb_str_codepoints(mrb_state *mrb, mrb_value self)
+{
+ mrb_value result;
+ mrb_value blk;
+ int ai;
+ mrb_int len;
+ mrb_value arg;
+ char *p = RSTRING_PTR(self);
+ char *e = p + RSTRING_LEN(self);
+
+ mrb_get_args(mrb, "&", &blk);
+
+ result = mrb_ary_new(mrb);
+
+ if (!mrb_nil_p(blk)) {
+ while (p < e) {
+ len = utf8len((unsigned char*) p);
+ arg = mrb_fixnum_value(utf8code((unsigned char*) p));
+ mrb_yield_argv(mrb, blk, 1, &arg);
+ p += len;
+ }
+ return self;
+ }
+ while (p < e) {
+ ai = mrb_gc_arena_save(mrb);
+ len = utf8len((unsigned char*) p);
+ mrb_ary_push(mrb, result, mrb_fixnum_value(utf8code((unsigned char*) p)));
+ mrb_gc_arena_restore(mrb, ai);
+ p += len;
+ }
+ return result;
+}
+
void
mrb_mruby_string_utf8_gem_init(mrb_state* mrb)
{
@@ -682,6 +728,11 @@ mrb_mruby_string_utf8_gem_init(mrb_state* mrb)
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, s, "rindex", mrb_str_rindex_m, MRB_ARGS_ANY());
+ mrb_define_method(mrb, s, "chr", mrb_str_chr, MRB_ARGS_NONE());
+ mrb_define_method(mrb, s, "chars", mrb_str_chars, MRB_ARGS_NONE());
+ mrb_alias_method(mrb, s, mrb_intern_lit(mrb, "each_char"), mrb_intern_lit(mrb, "chars"));
+ mrb_define_method(mrb, s, "codepoints", mrb_str_codepoints, MRB_ARGS_NONE());
+ mrb_alias_method(mrb, s, mrb_intern_lit(mrb, "each_codepoint"), mrb_intern_lit(mrb, "codepoints"));
mrb_define_method(mrb, mrb->fixnum_class, "chr", mrb_fixnum_chr, MRB_ARGS_NONE());
}
diff --git a/mrbgems/mruby-string-utf8/test/string.rb b/mrbgems/mruby-string-utf8/test/string.rb
index 1bfa8512c..5b4180037 100644
--- a/mrbgems/mruby-string-utf8/test/string.rb
+++ b/mrbgems/mruby-string-utf8/test/string.rb
@@ -66,3 +66,44 @@ assert('String#rindex') do
assert_equal 12, str.rindex('ち')
assert_equal 3, str.rindex('ち', 10)
end
+
+assert('String#chr(utf-8)') do
+ assert_equal "こ", "こんにちは世界!".chr
+end
+
+assert('String#chars') do
+ expect = ['こ', 'ん', 'に', 'ち', 'は', '世', '界', '!']
+ assert_equal expect, "こんにちは世界!".chars
+ s = ""
+ "こんにちは世界!".chars do |x|
+ s += x
+ end
+ assert_equal "こんにちは世界!", s
+end
+
+assert('String#each_char') do
+ expect = ['こ', 'ん', 'に', 'ち', 'は', '世', '界', '!']
+ s = ""
+ "こんにちは世界!".each_char do |x|
+ s += x
+ end
+ assert_equal "こんにちは世界!", s
+end
+assert('String#codepoints') do
+ expect = [12371, 12435, 12395, 12385, 12399, 19990, 30028, 33]
+ assert_equal expect, "こんにちは世界!".codepoints
+ cp = []
+ "こんにちは世界!".codepoints do |x|
+ cp << x
+ end
+ assert_equal expect, cp
+end
+
+assert('String#each_codepoint') do
+ expect = [12371, 12435, 12395, 12385, 12399, 19990, 30028, 33]
+ cp = []
+ "こんにちは世界!".each_codepoint do |x|
+ cp << x
+ end
+ assert_equal expect, cp
+end
diff --git a/mrbgems/mruby-struct/src/struct.c b/mrbgems/mruby-struct/src/struct.c
index a15655dbb..930384806 100644
--- a/mrbgems/mruby-struct/src/struct.c
+++ b/mrbgems/mruby-struct/src/struct.c
@@ -4,8 +4,8 @@
** See Copyright Notice in mruby.h
*/
+#include <ctype.h>
#include <string.h>
-#include <stdarg.h>
#include "mruby.h"
#include "mruby/array.h"
#include "mruby/string.h"
@@ -40,13 +40,7 @@ struct_ivar_get(mrb_state *mrb, mrb_value c, mrb_sym id)
}
}
-mrb_value
-mrb_struct_iv_get(mrb_state *mrb, mrb_value c, const char *name)
-{
- return struct_ivar_get(mrb, c, mrb_intern_cstr(mrb, name));
-}
-
-mrb_value
+static mrb_value
mrb_struct_s_members(mrb_state *mrb, mrb_value klass)
{
mrb_value members = struct_ivar_get(mrb, klass, mrb_intern_lit(mrb, "__members__"));
@@ -60,7 +54,7 @@ mrb_struct_s_members(mrb_state *mrb, mrb_value klass)
return members;
}
-mrb_value
+static mrb_value
mrb_struct_members(mrb_state *mrb, mrb_value s)
{
mrb_value members = mrb_struct_s_members(mrb, mrb_obj_value(mrb_obj_class(mrb, s)));
@@ -109,7 +103,7 @@ mrb_struct_members_m(mrb_state *mrb, mrb_value obj)
return mrb_struct_s_members_m(mrb, mrb_obj_value(mrb_obj_class(mrb, obj)));
}
-mrb_value
+static mrb_value
mrb_struct_getmember(mrb_state *mrb, mrb_value obj, mrb_sym id)
{
mrb_value members, slot, *ptr, *ptr_members;
@@ -149,7 +143,7 @@ static mrb_value mrb_struct_ref9(mrb_state* mrb, mrb_value obj) {return RSTRUCT_
#define numberof(array) (int)(sizeof(array) / sizeof((array)[0]))
#define N_REF_FUNC numberof(ref_func)
-static mrb_value (*const ref_func[])(mrb_state*, mrb_value) = {
+static const mrb_func_t ref_func[] = {
mrb_struct_ref0,
mrb_struct_ref1,
mrb_struct_ref2,
@@ -162,7 +156,7 @@ static mrb_value (*const ref_func[])(mrb_state*, mrb_value) = {
mrb_struct_ref9,
};
-mrb_sym
+static mrb_sym
mrb_id_attrset(mrb_state *mrb, mrb_sym id)
{
const char *name;
@@ -185,8 +179,7 @@ static mrb_value
mrb_struct_set(mrb_state *mrb, mrb_value obj, mrb_value val)
{
const char *name;
- size_t i, len;
- mrb_int slen;
+ mrb_int i, len, slen;
mrb_sym mid;
mrb_value members, slot, *ptr, *ptr_members;
@@ -217,19 +210,18 @@ mrb_struct_set_m(mrb_state *mrb, mrb_value obj)
return mrb_struct_set(mrb, obj, val);
}
-#define is_notop_id(id) (id) /* ((id)>tLAST_TOKEN) */
-#define is_local_id(id) (is_notop_id(id)) /* &&((id)&ID_SCOPE_MASK)==ID_LOCAL) */
-int
-mrb_is_local_id(mrb_sym id)
+static mrb_bool
+is_local_id(mrb_state *mrb, const char *name)
{
- return is_local_id(id);
+ if (!name) return FALSE;
+ return !ISUPPER(name[0]);
}
-#define is_const_id(id) (is_notop_id(id)) /* &&((id)&ID_SCOPE_MASK)==ID_CONST) */
-int
-mrb_is_const_id(mrb_sym id)
+static mrb_bool
+is_const_id(mrb_state *mrb, const char *name)
{
- return is_const_id(id);
+ if (!name) return FALSE;
+ return ISUPPER(name[0]);
}
static mrb_value
@@ -248,7 +240,7 @@ make_struct(mrb_state *mrb, mrb_value name, mrb_value members, struct RClass * k
/* old style: should we warn? */
name = mrb_str_to_str(mrb, name);
id = mrb_obj_to_sym(mrb, name);
- if (!mrb_is_const_id(id)) {
+ if (!is_const_id(mrb, mrb_sym2name_len(mrb, id, NULL))) {
mrb_name_error(mrb, id, "identifier %S needs to be constant", name);
}
if (mrb_const_defined_at(mrb, klass, id)) {
@@ -270,7 +262,9 @@ make_struct(mrb_state *mrb, mrb_value name, mrb_value members, struct RClass * k
ai = mrb_gc_arena_save(mrb);
for (i=0; i< len; i++) {
mrb_sym id = mrb_symbol(ptr_members[i]);
- if (mrb_is_local_id(id) || mrb_is_const_id(id)) {
+ const char *name = mrb_sym2name_len(mrb, id, NULL);
+
+ if (is_local_id(mrb, name) || is_const_id(mrb, name)) {
if (i < N_REF_FUNC) {
mrb_define_method_id(mrb, c, id, ref_func[i], MRB_ARGS_NONE());
}
@@ -284,27 +278,6 @@ make_struct(mrb_state *mrb, mrb_value name, mrb_value members, struct RClass * k
return nstr;
}
-mrb_value
-mrb_struct_define(mrb_state *mrb, const char *name, ...)
-{
- va_list ar;
- mrb_value nm, ary;
- char *mem;
-
- if (!name) nm = mrb_nil_value();
- else nm = mrb_str_new_cstr(mrb, name);
- ary = mrb_ary_new(mrb);
-
- va_start(ar, name);
- while ((mem = va_arg(ar, char*)) != 0) {
- mrb_sym slot = mrb_intern_cstr(mrb, mem);
- mrb_ary_push(mrb, ary, mrb_symbol_value(slot));
- }
- va_end(ar);
-
- return make_struct(mrb, nm, ary, struct_class(mrb));
-}
-
/* 15.2.18.3.1 */
/*
* call-seq:
@@ -344,7 +317,7 @@ mrb_struct_s_def(mrb_state *mrb, mrb_value klass)
{
mrb_value name, rest;
mrb_value *pargv;
- int argcnt;
+ mrb_int argcnt;
mrb_int i;
mrb_value b, st;
mrb_sym id;
@@ -391,7 +364,7 @@ mrb_struct_s_def(mrb_state *mrb, mrb_value klass)
return st;
}
-static int
+static mrb_int
num_members(mrb_state *mrb, struct RClass *klass)
{
mrb_value members;
@@ -407,10 +380,10 @@ num_members(mrb_state *mrb, struct RClass *klass)
/*
*/
static mrb_value
-mrb_struct_initialize_withArg(mrb_state *mrb, int argc, mrb_value *argv, mrb_value self)
+mrb_struct_initialize_withArg(mrb_state *mrb, mrb_int argc, mrb_value *argv, mrb_value self)
{
struct RClass *klass = mrb_obj_class(mrb, self);
- int i, n;
+ mrb_int i, n;
n = num_members(mrb, klass);
if (n < argc) {
@@ -436,14 +409,8 @@ mrb_struct_initialize_m(mrb_state *mrb, /*int argc, mrb_value *argv,*/ mrb_value
return mrb_struct_initialize_withArg(mrb, argc, argv, self);
}
-mrb_value
-mrb_struct_initialize(mrb_state *mrb, mrb_value self, mrb_value values)
-{
- return mrb_struct_initialize_withArg(mrb, RARRAY_LEN(values), RARRAY_PTR(values), self);
-}
-
static mrb_value
-inspect_struct(mrb_state *mrb, mrb_value s, int recur)
+inspect_struct(mrb_state *mrb, mrb_value s, mrb_bool recur)
{
const char *cn = mrb_class_name(mrb, mrb_obj_class(mrb, s));
mrb_value members, str = mrb_str_new_lit(mrb, "#<struct ");
@@ -464,6 +431,8 @@ inspect_struct(mrb_state *mrb, mrb_value s, int recur)
for (i=0; i<len; i++) {
mrb_value slot;
mrb_sym id;
+ const char *name;
+ mrb_int len;
if (i > 0) {
mrb_str_cat_lit(mrb, str, ", ");
@@ -473,11 +442,8 @@ inspect_struct(mrb_state *mrb, mrb_value s, int recur)
}
slot = ptr_members[i];
id = mrb_symbol(slot);
- if (mrb_is_local_id(id) || mrb_is_const_id(id)) {
- const char *name;
- mrb_int len;
-
- name = mrb_sym2name_len(mrb, id, &len);
+ name = mrb_sym2name_len(mrb, id, &len);
+ if (is_local_id(mrb, name) || is_const_id(mrb, name)) {
mrb_str_append(mrb, str, mrb_str_new(mrb, name, len));
}
else {
@@ -501,12 +467,12 @@ inspect_struct(mrb_state *mrb, mrb_value s, int recur)
static mrb_value
mrb_struct_inspect(mrb_state *mrb, mrb_value s)
{
- return inspect_struct(mrb, s, 0);
+ return inspect_struct(mrb, s, FALSE);
}
/* 15.2.18.4.9 */
/* :nodoc: */
-mrb_value
+static mrb_value
mrb_struct_init_copy(mrb_state *mrb, mrb_value copy)
{
mrb_value s;
@@ -584,7 +550,7 @@ struct_aref_int(mrb_state *mrb, mrb_value s, mrb_int i)
* joe[:name] #=> "Joe Smith"
* joe[0] #=> "Joe Smith"
*/
-mrb_value
+static mrb_value
mrb_struct_aref(mrb_state *mrb, mrb_value s)
{
mrb_value idx;
@@ -651,7 +617,7 @@ mrb_struct_aset_sym(mrb_state *mrb, mrb_value s, mrb_sym id, mrb_value val)
* joe.zip #=> "90210"
*/
-mrb_value
+static mrb_value
mrb_struct_aset(mrb_state *mrb, mrb_value s)
{
mrb_int i;
@@ -660,11 +626,19 @@ mrb_struct_aset(mrb_state *mrb, mrb_value s)
mrb_get_args(mrb, "oo", &idx, &val);
+ if (mrb_string_p(idx)) {
+ mrb_value sym = mrb_check_intern_str(mrb, idx);
+
+ if (mrb_nil_p(sym)) {
+ mrb_raisef(mrb, E_INDEX_ERROR, "no member '%S' in struct", idx);
+ }
+ idx = sym;
+ }
if (mrb_symbol_p(idx)) {
return mrb_struct_aset_sym(mrb, s, mrb_symbol(idx), val);
}
- i = mrb_fixnum(idx);
+ i = mrb_int(mrb, idx);
if (i < 0) i = RSTRUCT_LEN(s) + i;
if (i < 0) {
mrb_raisef(mrb, E_INDEX_ERROR,
diff --git a/mrbgems/mruby-struct/test/struct.rb b/mrbgems/mruby-struct/test/struct.rb
index b3b9ce33f..911e657bd 100644
--- a/mrbgems/mruby-struct/test/struct.rb
+++ b/mrbgems/mruby-struct/test/struct.rb
@@ -5,10 +5,6 @@ assert('Struct', '15.2.18') do
Struct.class == Class
end
-assert('Struct superclass', '15.2.18.2') do
- Struct.superclass == Object
-end
-
assert('Struct.new', '15.2.18.3.1') do
c = Struct.new(:m1, :m2)
c.superclass == Struct and
@@ -39,6 +35,9 @@ assert('Struct#[]=', '15.2.18.4.3') do
cc = c.new(1,2)
cc[:m1] = 3
cc[:m1] == 3
+ cc["m2"] = 3
+ assert_equal 3, cc["m2"]
+ assert_raise(TypeError) { cc[[]] = 3 }
end
assert('Struct#each', '15.2.18.4.4') do
diff --git a/mrbgems/mruby-time/src/time.c b/mrbgems/mruby-time/src/time.c
index 3f8ffabef..410b36173 100644
--- a/mrbgems/mruby-time/src/time.c
+++ b/mrbgems/mruby-time/src/time.c
@@ -713,7 +713,7 @@ mrb_mruby_time_gem_init(mrb_state* mrb)
tc = mrb_define_class(mrb, "Time", mrb->object_class);
MRB_SET_INSTANCE_TT(tc, MRB_TT_DATA);
mrb_include_module(mrb, tc, mrb_module_get(mrb, "Comparable"));
- mrb_define_class_method(mrb, tc, "at", mrb_time_at, MRB_ARGS_ANY()); /* 15.2.19.6.1 */
+ mrb_define_class_method(mrb, tc, "at", mrb_time_at, MRB_ARGS_REQ(1) | MRB_ARGS_OPT(1)); /* 15.2.19.6.1 */
mrb_define_class_method(mrb, tc, "gm", mrb_time_gm, MRB_ARGS_ARG(1,6)); /* 15.2.19.6.2 */
mrb_define_class_method(mrb, tc, "local", mrb_time_local, MRB_ARGS_ARG(1,6)); /* 15.2.19.6.3 */
mrb_define_class_method(mrb, tc, "mktime", mrb_time_local, MRB_ARGS_ARG(1,6));/* 15.2.19.6.4 */
diff --git a/mrbgems/mruby-time/test/time.rb b/mrbgems/mruby-time/test/time.rb
index 450d87b43..ba9b48fab 100644
--- a/mrbgems/mruby-time/test/time.rb
+++ b/mrbgems/mruby-time/test/time.rb
@@ -9,10 +9,6 @@ assert('Time', '15.2.19') do
Time.class == Class
end
-assert('Time superclass', '15.2.19.2') do
- Time.superclass == Object
-end
-
assert('Time.at', '15.2.19.6.1') do
Time.at(1300000000.0)
end
diff --git a/mrblib/error.rb b/mrblib/error.rb
index 6e8181e9d..a5b6b3223 100644
--- a/mrblib/error.rb
+++ b/mrblib/error.rb
@@ -48,6 +48,12 @@ end
# ISO 15.2.32
class NoMethodError < NameError
+ attr_reader :args
+
+ def initialize(message=nil, name=nil, args=nil)
+ @args = args
+ super message, name
+ end
end
# ISO 15.2.33
diff --git a/mrblib/kernel.rb b/mrblib/kernel.rb
index 81d7acf5d..d0fe47300 100644
--- a/mrblib/kernel.rb
+++ b/mrblib/kernel.rb
@@ -4,39 +4,24 @@
# ISO 15.3.1
module Kernel
- # 15.3.1.2.1
- def self.`(s)
- raise NotImplementedError.new("` not implemented")
- end
-
+ # 15.3.1.2.1 Kernel.`
+ # provided by Kernel#`
# 15.3.1.3.5
def `(s)
- Kernel.`(s)
+ raise NotImplementedError.new("backquotes not implemented")
end
##
- # Calls the given block repetitively.
- #
- # ISO 15.3.1.2.8
- # provided by Kernel#loop
- # def self.loop #(&block)
- # while(true)
- # yield
- # end
- # end
+ # 15.3.1.2.3 Kernel.eval
+ # 15.3.1.3.12 Kernel#eval
+ # NotImplemented by mruby core; use mruby-eval gem
- # 15.3.1.2.3
- def self.eval(s)
- raise NotImplementedError.new("eval not implemented")
- end
-
- # 15.3.1.3.12
- def eval(s)
- Kernel.eval(s)
- end
+ ##
+ # ISO 15.3.1.2.8 Kernel.loop
+ # provided by Kernel#loop
##
- # Alias for +Kernel.loop+.
+ # Calls the given block repetitively.
#
# ISO 15.3.1.3.29
def loop
diff --git a/mrblib/mrblib.rake b/mrblib/mrblib.rake
index 0c549f5b8..d156a2683 100644
--- a/mrblib/mrblib.rake
+++ b/mrblib/mrblib.rake
@@ -6,8 +6,8 @@ MRuby.each_target do
self.libmruby << objfile("#{current_build_dir}/mrblib")
file objfile("#{current_build_dir}/mrblib") => "#{current_build_dir}/mrblib.c"
- file "#{current_build_dir}/mrblib.c" => [mrbcfile] + Dir.glob("#{current_dir}/*.rb").sort do |t|
- mrbc_, *rbfiles = t.prerequisites
+ file "#{current_build_dir}/mrblib.c" => [mrbcfile, __FILE__] + Dir.glob("#{current_dir}/*.rb").sort do |t|
+ _, _, *rbfiles = t.prerequisites
FileUtils.mkdir_p File.dirname(t.name)
open(t.name, 'w') do |f|
_pp "GEN", "*.rb", "#{t.name.relative_path}"
diff --git a/mrblib/print.rb b/mrblib/print.rb
deleted file mode 100644
index 1ae3ae84b..000000000
--- a/mrblib/print.rb
+++ /dev/null
@@ -1,18 +0,0 @@
-##
-# Kernel
-#
-# ISO 15.3.1
-module Kernel
- def print(*a)
- raise NotImplementedError.new('print not available')
- end
- def puts(*a)
- raise NotImplementedError.new('puts not available')
- end
- def p(*a)
- raise NotImplementedError.new('p not available')
- end
- def printf(*args)
- raise NotImplementedError.new('printf not available')
- end
-end
diff --git a/src/backtrace.c b/src/backtrace.c
index 7768a3206..1e1f9fa1a 100644
--- a/src/backtrace.c
+++ b/src/backtrace.c
@@ -71,7 +71,6 @@ output_backtrace(mrb_state *mrb, mrb_int ciidx, mrb_code *pc0, output_stream_fun
for (i = ciidx; i >= 0; i--) {
ci = &mrb->c->cibase[i];
filename = NULL;
- lineno = -1;
if (!ci->proc) continue;
if (MRB_PROC_CFUNC_P(ci->proc)) {
diff --git a/src/class.c b/src/class.c
index db9a8ac26..ba078911b 100644
--- a/src/class.c
+++ b/src/class.c
@@ -1216,8 +1216,7 @@ mrb_bob_missing(mrb_state *mrb, mrb_value mod)
repr = mrb_any_to_s(mrb, mod);
}
- mrb_raisef(mrb, E_NOMETHOD_ERROR, "undefined method '%S' for %S",
- mrb_sym2str(mrb, name), repr);
+ mrb_no_method_error(mrb, name, alen, a, "undefined method '%S' for %S", mrb_sym2str(mrb, name), repr);
/* not reached */
return mrb_nil_value();
}
diff --git a/src/codegen.c b/src/codegen.c
index cec0d226f..03c752826 100644
--- a/src/codegen.c
+++ b/src/codegen.c
@@ -475,6 +475,8 @@ new_msym(codegen_scope *s, mrb_sym sym)
{
size_t i, len;
+ mrb_assert(s->irep);
+
len = s->irep->slen;
if (len > 256) len = 256;
for (i=0; i<len; i++) {
@@ -549,7 +551,8 @@ for_body(codegen_scope *s, node *tree)
/* generate receiver */
codegen(s, tree->cdr->car, VAL);
/* generate loop-block */
- s = scope_new(s->mrb, s, tree->car);
+ s = scope_new(s->mrb, s, NULL);
+ push(); /* push for a block parameter */
lp = loop_push(s, LOOP_FOR);
lp->pc1 = new_label(s);
@@ -1105,21 +1108,23 @@ readint_mrb_int(codegen_scope *s, const char *p, int base, mrb_bool neg, mrb_boo
codegen_error(s, "malformed readint input");
}
- if (neg) {
- if ((MRB_INT_MIN + n)/base > result) {
- *overflow = TRUE;
- return 0;
+ if(base > 0) {
+ if (neg) {
+ if ((MRB_INT_MIN + n)/base > result) {
+ *overflow = TRUE;
+ return 0;
+ }
+ result *= base;
+ result -= n;
}
- result *= base;
- result -= n;
- }
- else {
- if ((MRB_INT_MAX - n)/base < result) {
- *overflow = TRUE;
- return 0;
+ else {
+ if ((MRB_INT_MAX - n)/base < result) {
+ *overflow = TRUE;
+ return 0;
+ }
+ result *= base;
+ result += n;
}
- result *= base;
- result += n;
}
p++;
}
@@ -2651,7 +2656,7 @@ print_r(mrb_state *mrb, mrb_irep *irep, size_t n, int pre)
if (n == 0) return 0;
- for (i=0; i<irep->nlocals; i++) {
+ for (i=0; i+1<irep->nlocals; i++) {
if (irep->lv[i].r == n) {
mrb_sym sym = irep->lv[i].name;
if (pre) printf(" ");
@@ -2994,7 +2999,7 @@ codedump(mrb_state *mrb, mrb_irep *irep)
{
mrb_value v = irep->pool[GETARG_Bx(c)];
mrb_value s = mrb_str_dump(mrb, mrb_str_new(mrb, RSTRING_PTR(v), RSTRING_LEN(v)));
- printf("OP_STRING\tR%d\tL(%d)\t; %s", GETARG_A(c), GETARG_B(c), RSTRING_PTR(s));
+ printf("OP_STRING\tR%d\tL(%d)\t; %s", GETARG_A(c), GETARG_Bx(c), RSTRING_PTR(s));
}
print_lv(mrb, irep, c, RA);
break;
diff --git a/src/dump.c b/src/dump.c
index 1acb466a0..b820f1a68 100644
--- a/src/dump.c
+++ b/src/dump.c
@@ -343,7 +343,6 @@ write_section_irep(mrb_state *mrb, mrb_irep *irep, uint8_t *bin)
if (result != MRB_DUMP_OK) {
return result;
}
- cur += rsize;
section_size += rsize;
write_section_irep_header(mrb, section_size, bin);
diff --git a/src/error.c b/src/error.c
index 360df8f2e..5ca013527 100644
--- a/src/error.c
+++ b/src/error.c
@@ -227,7 +227,9 @@ mrb_noreturn void
mrb_exc_raise(mrb_state *mrb, mrb_value exc)
{
mrb->exc = mrb_obj_ptr(exc);
- exc_debug_info(mrb, mrb->exc);
+ if (!mrb->out_of_memory) {
+ exc_debug_info(mrb, mrb->exc);
+ }
if (!mrb->jmp) {
mrb_p(mrb, exc);
abort();
@@ -442,12 +444,26 @@ mrb_sys_fail(mrb_state *mrb, const char *mesg)
}
}
+mrb_noreturn void
+mrb_no_method_error(mrb_state *mrb, mrb_sym id, mrb_int argc, const mrb_value *argv, char const* fmt, ...)
+{
+ mrb_value exc;
+ va_list ap;
+
+ va_start(ap, fmt);
+ exc = mrb_funcall(mrb, mrb_obj_value(E_NOMETHOD_ERROR), "new", 3,
+ mrb_vformat(mrb, fmt, ap), mrb_symbol_value(id),
+ mrb_ary_new_from_values(mrb, argc, argv));
+ va_end(ap);
+ mrb_exc_raise(mrb, exc);
+}
+
void
mrb_init_exception(mrb_state *mrb)
{
- struct RClass *exception, *script_error;
+ struct RClass *exception, *runtime_error, *script_error;
- mrb->eException_class = exception = mrb_define_class(mrb, "Exception", mrb->object_class); /* 15.2.22 */
+ mrb->eException_class = exception = mrb_define_class(mrb, "Exception", mrb->object_class); /* 15.2.22 */
mrb_define_class_method(mrb, exception, "exception", mrb_instance_new, MRB_ARGS_ANY());
mrb_define_method(mrb, exception, "exception", exc_exception, MRB_ARGS_ANY());
mrb_define_method(mrb, exception, "initialize", exc_initialize, MRB_ARGS_ANY());
@@ -457,8 +473,9 @@ mrb_init_exception(mrb_state *mrb)
mrb_define_method(mrb, exception, "inspect", exc_inspect, MRB_ARGS_NONE());
mrb_define_method(mrb, exception, "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 */
- script_error = mrb_define_class(mrb, "ScriptError", mrb->eException_class); /* 15.2.37 */
- mrb_define_class(mrb, "SyntaxError", script_error); /* 15.2.38 */
+ mrb->eStandardError_class = mrb_define_class(mrb, "StandardError", mrb->eException_class); /* 15.2.23 */
+ runtime_error = mrb_define_class(mrb, "RuntimeError", mrb->eStandardError_class); /* 15.2.28 */
+ mrb->nomem_err = mrb_obj_ptr(mrb_exc_new_str(mrb, runtime_error, mrb_str_new_lit(mrb, "Out of memory")));
+ script_error = mrb_define_class(mrb, "ScriptError", mrb->eException_class); /* 15.2.37 */
+ mrb_define_class(mrb, "SyntaxError", script_error); /* 15.2.38 */
}
diff --git a/src/gc.c b/src/gc.c
index 4478b71f3..6eb9808e3 100644
--- a/src/gc.c
+++ b/src/gc.c
@@ -34,7 +34,7 @@
== Two White Types
- There're two white color types in a flip-flop fassion: White-A and White-B,
+ There're two white color types in a flip-flop fashion: White-A and White-B,
which respectively represent the Current White color (the newly allocated
objects in the current GC cycle) and the Sweep Target White color (the
dead objects to be swept).
@@ -43,8 +43,8 @@
that time, all the dead objects have been swept, while the newly created
objects in the current GC cycle which finally remains White are now
regarded as dead objects. Instead of traversing all the White-A objects and
- paint them as White-B, just switch the meaning of White-A and White-B would
- be much cheaper.
+ painting them as White-B, just switch the meaning of White-A and White-B as
+ this will be much cheaper.
As a result, the objects we sweep in the current GC cycle are always
left from the previous GC cycle. This allows us to sweep objects
@@ -73,8 +73,8 @@
mruby's GC offers an Generational Mode while re-using the tri-color GC
infrastructure. It will treat the Black objects as Old objects after each
- sweep phase, instead of paint them to White. The key idea are still same as
- the traditional generational GC:
+ sweep phase, instead of painting them White. The key ideas are still the same
+ as traditional generational GC:
* Minor GC - just traverse the Young objects (Gray objects) in the mark
phase, then only sweep the newly created objects, and leave
@@ -82,7 +82,7 @@
* Major GC - same as a full regular GC cycle.
- The difference to a "traditional" generational GC is, that the major GC
+ The difference from "traditional" generational GC is, that the major GC
in mruby is triggered incrementally in a tri-color manner.
@@ -189,7 +189,7 @@ mrb_realloc(mrb_state *mrb, void *p, size_t len)
}
else {
mrb->out_of_memory = TRUE;
- mrb_raise(mrb, E_RUNTIME_ERROR, "Out of memory");
+ mrb_exc_raise(mrb, mrb_obj_value(mrb->nomem_err));
}
}
else {
@@ -705,6 +705,8 @@ root_scan_phase(mrb_state *mrb)
mrb_gc_mark(mrb, (struct RBasic*)mrb->top_self);
/* mark exception */
mrb_gc_mark(mrb, (struct RBasic*)mrb->exc);
+ /* mark pre-allocated exception */
+ mrb_gc_mark(mrb, (struct RBasic*)mrb->nomem_err);
mark_context(mrb, mrb->root_c);
if (mrb->root_c->fib) {
diff --git a/src/hash.c b/src/hash.c
index 997610953..1d449db3f 100644
--- a/src/hash.c
+++ b/src/hash.c
@@ -216,11 +216,12 @@ mrb_hash_set(mrb_state *mrb, mrb_value hash, mrb_value key, mrb_value val)
if (r != 0) {
/* expand */
int ai = mrb_gc_arena_save(mrb);
- kh_key(h, k) = KEY(key);
+ key = kh_key(h, k) = KEY(key);
mrb_gc_arena_restore(mrb, ai);
kh_value(h, k).n = kh_size(h)-1;
}
+ mrb_field_write_barrier_value(mrb, (struct RBasic*)RHASH(hash), key);
mrb_field_write_barrier_value(mrb, (struct RBasic*)RHASH(hash), val);
return;
}
diff --git a/src/init.c b/src/init.c
index c08c4b046..9489cea10 100644
--- a/src/init.c
+++ b/src/init.c
@@ -54,11 +54,3 @@ mrb_init_core(mrb_state *mrb)
mrb_init_mrbgems(mrb); DONE;
#endif
}
-
-void
-mrb_final_core(mrb_state *mrb)
-{
-#ifndef DISABLE_GEMS
- mrb_final_mrbgems(mrb); DONE;
-#endif
-}
diff --git a/src/kernel.c b/src/kernel.c
index 6d13bb6e9..0258e5c15 100644
--- a/src/kernel.c
+++ b/src/kernel.c
@@ -977,7 +977,9 @@ obj_respond_to(mrb_state *mrb, mrb_value self)
if (!respond_to_p) {
rtm_id = mrb_intern_lit(mrb, "respond_to_missing?");
if (basic_obj_respond_to(mrb, self, rtm_id, !priv)) {
- mrb_value args[] = { mid, mrb_bool_value(priv) };
+ mrb_value args[2];
+ args[0] = mid;
+ args[1] = mrb_bool_value(priv);
return mrb_funcall_argv(mrb, self, rtm_id, 2, args);
}
}
@@ -1116,7 +1118,7 @@ mrb_init_kernel(mrb_state *mrb)
mrb_define_class_method(mrb, krn, "iterator?", mrb_f_block_given_p_m, MRB_ARGS_NONE()); /* 15.3.1.2.5 */
mrb_define_class_method(mrb, krn, "local_variables", mrb_local_variables, MRB_ARGS_NONE()); /* 15.3.1.2.7 */
; /* 15.3.1.2.11 */
- mrb_define_class_method(mrb, krn, "raise", mrb_f_raise, MRB_ARGS_ANY()); /* 15.3.1.2.12 */
+ mrb_define_class_method(mrb, krn, "raise", mrb_f_raise, MRB_ARGS_OPT(2)); /* 15.3.1.2.12 */
mrb_define_method(mrb, krn, "singleton_class", mrb_singleton_class, MRB_ARGS_NONE());
diff --git a/src/mruby_core.rake b/src/mruby_core.rake
index 04be0736c..88fca83fc 100644
--- a/src/mruby_core.rake
+++ b/src/mruby_core.rake
@@ -13,7 +13,7 @@ MRuby.each_target do
cxx_abi_dependency = %w(codegen error vm)
cxx_abi_objs = cxx_abi_dependency.map { |v|
src = "#{current_build_dir}/#{v}.cxx"
- file src => "#{current_dir}/#{v}.c" do |t|
+ file src => ["#{current_dir}/#{v}.c", __FILE__] do |t|
File.open(t.name, 'w') do |f|
f.write <<EOS
#define __STDC_CONSTANT_MACROS
@@ -37,7 +37,7 @@ EOS
}
cxx_abi_objs << objfile("#{current_build_dir}/y.tab")
- file "#{current_build_dir}/y.tab.cxx" => "#{current_build_dir}/y.tab.c" do |t|
+ file "#{current_build_dir}/y.tab.cxx" => ["#{current_build_dir}/y.tab.c", __FILE__] do |t|
File.open(t.name, 'w') do |f|
f.write <<EOS
#define __STDC_CONSTANT_MACROS
diff --git a/src/parse.y b/src/parse.y
index 217289aff..2c7e788d9 100644
--- a/src/parse.y
+++ b/src/parse.y
@@ -42,11 +42,7 @@ static void yywarning(parser_state *p, const char *s);
static void backref_error(parser_state *p, node *n);
static void tokadd(parser_state *p, int32_t c);
-#ifndef isascii
-#define isascii(c) (((c) & ~0x7f) == 0)
-#endif
-
-#define identchar(c) (isalnum(c) || (c) == '_' || !isascii(c))
+#define identchar(c) (ISALNUM(c) || (c) == '_' || !ISASCII(c))
typedef unsigned int stack_type;
@@ -257,7 +253,11 @@ local_var_p(parser_state *p, mrb_sym sym)
static void
local_add_f(parser_state *p, mrb_sym sym)
{
- p->locals->car = push(p->locals->car, nsym(sym));
+ if (p->locals->car && !p->locals->car->car) {
+ p->locals->car->car = nsym(sym);
+ } else {
+ p->locals->car = push(p->locals->car, nsym(sym));
+ }
}
static void
@@ -2875,15 +2875,15 @@ var_ref : variable
| keyword_self
{
$$ = new_self(p);
- }
+ }
| keyword_true
{
$$ = new_true(p);
- }
+ }
| keyword_false
{
$$ = new_false(p);
- }
+ }
| keyword__FILE__
{
if (!p->filename) {
@@ -3377,7 +3377,9 @@ nextc(parser_state *p)
c = (unsigned char)*p->s++;
}
}
- p->column++;
+ if (c >= 0) {
+ p->column++;
+ }
if (c == '\r') {
c = nextc(p);
if (c != '\n') {
@@ -3392,16 +3394,17 @@ nextc(parser_state *p)
if (!p->cxt) return -1;
else {
if (p->cxt->partial_hook(p) < 0)
- return -1;
- return -2;
+ return -1; /* end of program(s) */
+ return -2; /* end of a file in the program files */
}
}
static void
pushback(parser_state *p, int c)
{
- if (c < 0) return;
- p->column--;
+ if (c >= 0) {
+ p->column--;
+ }
p->pb = cons((node*)(intptr_t)c, p->pb);
}
@@ -3425,7 +3428,7 @@ peekc_n(parser_state *p, int n)
do {
c0 = nextc(p);
- if (c0 < 0) return c0;
+ if (c0 == -1) return c0; /* do not skip partial EOF */
list = push(list, (node*)(intptr_t)c0);
} while(n--);
if (p->pb) {
@@ -3781,7 +3784,7 @@ read_escape(parser_state *p)
eof:
case -1:
- case -2:
+ case -2: /* end of a file */
yyerror(p, "Invalid escape character syntax");
return '\0';
@@ -3911,7 +3914,8 @@ parse_string(parser_state *p)
return tHD_LITERAL_DELIM;
}
}
- } while (ISSPACE(c = nextc(p)));
+ c = nextc(p);
+ } while (ISSPACE(c));
pushback(p, c);
return tLITERAL_DELIM;
}
@@ -4096,7 +4100,7 @@ parser_yylex(parser_state *p)
case '#': /* it's a comment */
skip(p, '\n');
/* fall through */
- case -2: /* end of partial script. */
+ case -2: /* end of a file */
case '\n':
maybe_heredoc:
heredoc_treat_nextline(p);
@@ -4131,7 +4135,7 @@ parser_yylex(parser_state *p)
goto retry;
}
case -1: /* EOF */
- case -2: /* end of partial script */
+ case -2: /* end of a file */
goto normal_newline;
default:
pushback(p, c);
@@ -4205,14 +4209,14 @@ parser_yylex(parser_state *p)
static const char end[] = "\n=end";
if (peeks(p, begin)) {
c = peekc_n(p, sizeof(begin)-1);
- if (c < 0 || isspace(c)) {
+ if (c < 0 || ISSPACE(c)) {
do {
if (!skips(p, end)) {
yyerror(p, "embedded document meets end of file");
return 0;
}
c = nextc(p);
- } while (!(c < 0 || isspace(c)));
+ } while (!(c < 0 || ISSPACE(c)));
if (c != '\n') skip(p, '\n');
p->lineno++;
p->column = 0;
@@ -4243,7 +4247,6 @@ parser_yylex(parser_state *p)
return '=';
case '<':
- last_state = p->lstate;
c = nextc(p);
if (c == '<' &&
p->lstate != EXPR_DOT &&
@@ -4337,7 +4340,7 @@ parser_yylex(parser_state *p)
yyerror(p, "incomplete character syntax");
return 0;
}
- if (isspace(c)) {
+ if (ISSPACE(c)) {
if (!IS_ARG()) {
int c2;
switch (c) {
@@ -4374,7 +4377,7 @@ parser_yylex(parser_state *p)
p->lstate = EXPR_VALUE;
return '?';
}
- token_column = newtok(p);
+ newtok(p);
/* need support UTF-8 if configured */
if ((isalnum(c) || c == '_')) {
int c2 = nextc(p);
@@ -4538,7 +4541,7 @@ parser_yylex(parser_state *p)
is_float = seen_point = seen_e = nondigit = 0;
p->lstate = EXPR_END;
- token_column = newtok(p);
+ newtok(p);
if (c == '-' || c == '+') {
tokadd(p, c);
c = nextc(p);
@@ -5160,7 +5163,6 @@ parser_yylex(parser_state *p)
{
int result = 0;
- last_state = p->lstate;
switch (tok(p)[0]) {
case '$':
p->lstate = EXPR_END;
@@ -5190,7 +5192,7 @@ parser_yylex(parser_state *p)
pushback(p, c);
}
}
- if (result == 0 && isupper((int)(unsigned char)tok(p)[0])) {
+ if (result == 0 && ISUPPER(tok(p)[0])) {
result = tCONSTANT;
}
else {
@@ -5336,20 +5338,20 @@ mrb_parser_parse(parser_state *p, mrbc_context *c)
MRB_TRY(p->jmp) {
- p->cmd_start = TRUE;
- p->in_def = p->in_single = 0;
- p->nerr = p->nwarn = 0;
- p->lex_strterm = NULL;
+ p->cmd_start = TRUE;
+ p->in_def = p->in_single = 0;
+ p->nerr = p->nwarn = 0;
+ p->lex_strterm = NULL;
- parser_init_cxt(p, c);
- yyparse(p);
- if (!p->tree) {
- p->tree = new_nil(p);
- }
- parser_update_cxt(p, c);
- if (c && c->dump_result) {
- mrb_parser_dump(p->mrb, p->tree, 0);
- }
+ parser_init_cxt(p, c);
+ yyparse(p);
+ if (!p->tree) {
+ p->tree = new_nil(p);
+ }
+ parser_update_cxt(p, c);
+ if (c && c->dump_result) {
+ mrb_parser_dump(p->mrb, p->tree, 0);
+ }
}
MRB_CATCH(p->jmp) {
@@ -5522,6 +5524,7 @@ load_exec(mrb_state *mrb, parser_state *p, mrbc_context *c)
struct RClass *target = mrb->object_class;
struct RProc *proc;
mrb_value v;
+ unsigned int keep = 0;
if (!p) {
return mrb_undef_value();
@@ -5555,12 +5558,13 @@ load_exec(mrb_state *mrb, parser_state *p, mrbc_context *c)
if (c->target_class) {
target = c->target_class;
}
+ keep = c->slen + 1;
}
proc->target_class = target;
if (mrb->c->ci) {
mrb->c->ci->target_class = target;
}
- v = mrb_toplevel_run(mrb, proc);
+ v = mrb_toplevel_run_keep(mrb, proc, keep);
if (mrb->exc) return mrb_nil_value();
return v;
}
@@ -5854,7 +5858,7 @@ mrb_parser_dump(mrb_state *mrb, node *tree, int offset)
{
node *n2 = tree->car;
- if (n2 && (n2->car || n2->cdr)) {
+ if (n2 && (n2->car || n2->cdr)) {
dump_prefix(offset+1);
printf("local variables:\n");
dump_prefix(offset+2);
diff --git a/src/state.c b/src/state.c
index 9dd798f92..3e82a159d 100644
--- a/src/state.c
+++ b/src/state.c
@@ -14,7 +14,6 @@
void mrb_init_heap(mrb_state*);
void mrb_init_core(mrb_state*);
-void mrb_final_core(mrb_state*);
static mrb_value
inspect_main(mrb_state *mrb, mrb_value mod)
@@ -30,7 +29,7 @@ mrb_open_allocf(mrb_allocf f, void *ud)
mrb_state *mrb;
#ifdef MRB_NAN_BOXING
- mrb_assert(sizeof(void*) == 4);
+ mrb_static_assert(sizeof(void*) == 4, "when using NaN boxing sizeof pointer must be 4 byte");
#endif
mrb = (mrb_state *)(f)(NULL, NULL, sizeof(mrb_state), ud);
@@ -40,6 +39,7 @@ mrb_open_allocf(mrb_allocf f, void *ud)
mrb->ud = ud;
mrb->allocf = f;
mrb->current_white_part = MRB_GC_WHITE_A;
+ mrb->atexit_stack_len = 0;
#ifndef MRB_GC_FIXED_ARENA
mrb->arena = (struct RBasic**)mrb_malloc(mrb, sizeof(struct RBasic*)*MRB_GC_ARENA_SIZE);
@@ -221,7 +221,15 @@ mrb_free_context(mrb_state *mrb, struct mrb_context *c)
void
mrb_close(mrb_state *mrb)
{
- mrb_final_core(mrb);
+ if (mrb->atexit_stack_len > 0) {
+ mrb_int i;
+ for (i = mrb->atexit_stack_len; i > 0; --i) {
+ mrb->atexit_stack[i - 1](mrb);
+ }
+#ifndef MRB_FIXED_STATE_ATEXIT_STACK
+ mrb_free(mrb, mrb->atexit_stack);
+#endif
+ }
/* free */
mrb_gc_free_gv(mrb);
@@ -258,3 +266,24 @@ mrb_top_self(mrb_state *mrb)
}
return mrb_obj_value(mrb->top_self);
}
+
+void
+mrb_state_atexit(mrb_state *mrb, mrb_atexit_func f)
+{
+#ifdef MRB_FIXED_STATE_ATEXIT_STACK
+ if (mrb->atexit_stack_len + 1 > MRB_FIXED_STATE_ATEXIT_STACK_SIZE) {
+ mrb_raise(mrb, E_RUNTIME_ERROR, "exceeded fixed state atexit stack limit");
+ }
+#else
+ size_t stack_size;
+
+ stack_size = sizeof(mrb_atexit_func) * (mrb->atexit_stack_len + 1);
+ if (mrb->atexit_stack_len == 0) {
+ mrb->atexit_stack = (mrb_atexit_func*)mrb_malloc(mrb, stack_size);
+ } else {
+ mrb->atexit_stack = (mrb_atexit_func*)mrb_realloc(mrb, mrb->atexit_stack, stack_size);
+ }
+#endif
+
+ mrb->atexit_stack[mrb->atexit_stack_len++] = f;
+}
diff --git a/src/string.c b/src/string.c
index 1572cab14..6570c89fb 100644
--- a/src/string.c
+++ b/src/string.c
@@ -17,28 +17,6 @@
#include "mruby/string.h"
#include "mruby/re.h"
-#define STR_EMBED_P(s) ((s)->flags & MRB_STR_EMBED)
-#define STR_SET_EMBED_FLAG(s) ((s)->flags |= MRB_STR_EMBED)
-#define STR_UNSET_EMBED_FLAG(s) ((s)->flags &= ~(MRB_STR_EMBED|MRB_STR_EMBED_LEN_MASK))
-#define STR_SET_EMBED_LEN(s, n) do {\
- size_t tmp_n = (n);\
- s->flags &= ~MRB_STR_EMBED_LEN_MASK;\
- s->flags |= (tmp_n) << MRB_STR_EMBED_LEN_SHIFT;\
-} while (0)
-#define STR_SET_LEN(s, n) do {\
- if (STR_EMBED_P(s)) {\
- STR_SET_EMBED_LEN((s),(n));\
- } else {\
- s->as.heap.len = (mrb_int)(n);\
- }\
-} while (0)
-#define RSTRING_EMBED_LEN(s) \
- (mrb_int)((RSTRING(s)->flags & MRB_STR_EMBED_LEN_MASK) >> MRB_STR_EMBED_LEN_SHIFT)
-#define STR_EMBED_LEN(s)\
- (mrb_int)(((s)->flags & MRB_STR_EMBED_LEN_MASK) >> MRB_STR_EMBED_LEN_SHIFT)
-#define STR_PTR(s) ((STR_EMBED_P(s)) ? (s)->as.ary : (s)->as.heap.ptr)
-#define STR_LEN(s) ((STR_EMBED_P(s)) ? STR_EMBED_LEN(s) : (s)->as.heap.len)
-
const char mrb_digitmap[] = "0123456789abcdefghijklmnopqrstuvwxyz";
typedef struct mrb_shared_string {
@@ -48,18 +26,14 @@ typedef struct mrb_shared_string {
mrb_int len;
} mrb_shared_string;
-#define STR_SHARED_P(s) ((s)->flags & MRB_STR_SHARED)
-#define STR_SET_SHARED_FLAG(s) ((s)->flags |= MRB_STR_SHARED)
-#define STR_UNSET_SHARED_FLAG(s) ((s)->flags &= ~MRB_STR_SHARED)
-
static mrb_value str_replace(mrb_state *mrb, struct RString *s1, struct RString *s2);
static mrb_value mrb_str_subseq(mrb_state *mrb, mrb_value str, mrb_int beg, mrb_int len);
mrb_int
mrb_str_strlen(mrb_state *mrb, struct RString *s)
{
- mrb_int i, max = STR_LEN(s);
- char *p = STR_PTR(s);
+ mrb_int i, max = RSTR_LEN(s);
+ char *p = RSTR_PTR(s);
if (!p) return 0;
for (i=0; i<max; i++) {
@@ -73,19 +47,19 @@ mrb_str_strlen(mrb_state *mrb, struct RString *s)
static inline void
resize_capa(mrb_state *mrb, struct RString *s, mrb_int capacity)
{
- if (STR_EMBED_P(s)) {
+ if (RSTR_EMBED_P(s)) {
if (RSTRING_EMBED_LEN_MAX < capacity) {
char *const tmp = (char *)mrb_malloc(mrb, capacity+1);
- const mrb_int len = STR_EMBED_LEN(s);
+ const mrb_int len = RSTR_EMBED_LEN(s);
memcpy(tmp, s->as.ary, len);
- STR_UNSET_EMBED_FLAG(s);
+ RSTR_UNSET_EMBED_FLAG(s);
s->as.heap.ptr = tmp;
s->as.heap.len = len;
s->as.heap.aux.capa = capacity;
}
}
else {
- s->as.heap.ptr = (char *)mrb_realloc(mrb, STR_PTR(s), capacity+1);
+ s->as.heap.ptr = (char *)mrb_realloc(mrb, RSTR_PTR(s), capacity+1);
s->as.heap.aux.capa = capacity;
}
}
@@ -105,20 +79,20 @@ str_decref(mrb_state *mrb, mrb_shared_string *shared)
void
mrb_str_modify(mrb_state *mrb, struct RString *s)
{
- if (STR_SHARED_P(s)) {
+ if (RSTR_SHARED_P(s)) {
mrb_shared_string *shared = s->as.heap.aux.shared;
if (shared->refcnt == 1 && s->as.heap.ptr == shared->ptr) {
s->as.heap.ptr = shared->ptr;
s->as.heap.aux.capa = shared->len;
- STR_PTR(s)[s->as.heap.len] = '\0';
+ RSTR_PTR(s)[s->as.heap.len] = '\0';
mrb_free(mrb, shared);
}
else {
char *ptr, *p;
mrb_int len;
- p = STR_PTR(s);
+ p = RSTR_PTR(s);
len = s->as.heap.len;
ptr = (char *)mrb_malloc(mrb, (size_t)len + 1);
if (p) {
@@ -129,19 +103,19 @@ mrb_str_modify(mrb_state *mrb, struct RString *s)
s->as.heap.aux.capa = len;
str_decref(mrb, shared);
}
- STR_UNSET_SHARED_FLAG(s);
+ RSTR_UNSET_SHARED_FLAG(s);
return;
}
- if (s->flags & MRB_STR_NOFREE) {
+ if (RSTR_NOFREE_P(s)) {
char *p = s->as.heap.ptr;
s->as.heap.ptr = (char *)mrb_malloc(mrb, (size_t)s->as.heap.len+1);
if (p) {
- memcpy(STR_PTR(s), p, s->as.heap.len);
+ memcpy(RSTR_PTR(s), p, s->as.heap.len);
}
- STR_PTR(s)[s->as.heap.len] = '\0';
+ RSTR_PTR(s)[s->as.heap.len] = '\0';
s->as.heap.aux.capa = s->as.heap.len;
- s->flags &= ~MRB_STR_NOFREE;
+ RSTR_UNSET_NOFREE_FLAG(s);
return;
}
}
@@ -153,13 +127,13 @@ mrb_str_resize(mrb_state *mrb, mrb_value str, mrb_int len)
struct RString *s = mrb_str_ptr(str);
mrb_str_modify(mrb, s);
- slen = STR_LEN(s);
+ slen = RSTR_LEN(s);
if (len != slen) {
if (slen < len || slen - len > 256) {
resize_capa(mrb, s, len);
}
- STR_SET_LEN(s, len);
- STR_PTR(s)[len] = '\0'; /* sentinel */
+ RSTR_SET_LEN(s, len);
+ RSTR_PTR(s)[len] = '\0'; /* sentinel */
}
return str;
}
@@ -173,8 +147,8 @@ str_new(mrb_state *mrb, const char *p, size_t len)
s = mrb_obj_alloc_string(mrb);
if (len < RSTRING_EMBED_LEN_MAX) {
- STR_SET_EMBED_FLAG(s);
- STR_SET_EMBED_LEN(s,len);
+ RSTR_SET_EMBED_FLAG(s);
+ RSTR_SET_EMBED_LEN(s,len);
if (p) {
memcpy(s->as.ary, p, len);
}
@@ -189,7 +163,7 @@ str_new(mrb_state *mrb, const char *p, size_t len)
memcpy(s->as.heap.ptr, p, len);
}
}
- STR_PTR(s)[len] = '\0';
+ RSTR_PTR(s)[len] = '\0';
return s;
}
@@ -228,7 +202,7 @@ mrb_str_buf_new(mrb_state *mrb, size_t capa)
s->as.heap.len = 0;
s->as.heap.aux.capa = capa;
s->as.heap.ptr = (char *)mrb_malloc(mrb, capa+1);
- STR_PTR(s)[0] = '\0';
+ RSTR_PTR(s)[0] = '\0';
return mrb_obj_value(s);
}
@@ -242,19 +216,19 @@ str_buf_cat(mrb_state *mrb, struct RString *s, const char *ptr, size_t len)
if (len == 0) return;
mrb_str_modify(mrb, s);
- if (ptr >= STR_PTR(s) && ptr <= STR_PTR(s) + (size_t)STR_LEN(s)) {
- off = ptr - STR_PTR(s);
+ if (ptr >= RSTR_PTR(s) && ptr <= RSTR_PTR(s) + (size_t)RSTR_LEN(s)) {
+ off = ptr - RSTR_PTR(s);
}
- if (STR_EMBED_P(s))
+ if (RSTR_EMBED_P(s))
capa = RSTRING_EMBED_LEN_MAX;
else
capa = s->as.heap.aux.capa;
- if (STR_LEN(s) >= MRB_INT_MAX - (mrb_int)len) {
+ if (RSTR_LEN(s) >= MRB_INT_MAX - (mrb_int)len) {
mrb_raise(mrb, E_ARGUMENT_ERROR, "string size too big");
}
- total = STR_LEN(s)+len;
+ total = RSTR_LEN(s)+len;
if (capa <= total) {
while (total > capa) {
if (capa + 1 >= MRB_INT_MAX / 2) {
@@ -266,12 +240,12 @@ str_buf_cat(mrb_state *mrb, struct RString *s, const char *ptr, size_t len)
resize_capa(mrb, s, capa);
}
if (off != -1) {
- ptr = STR_PTR(s) + off;
+ ptr = RSTR_PTR(s) + off;
}
- memcpy(STR_PTR(s) + STR_LEN(s), ptr, len);
+ memcpy(RSTR_PTR(s) + RSTR_LEN(s), ptr, len);
mrb_assert_int_fit(size_t, total, mrb_int, MRB_INT_MAX);
- STR_SET_LEN(s, total);
- STR_PTR(s)[total] = '\0'; /* sentinel */
+ RSTR_SET_LEN(s, total);
+ RSTR_PTR(s)[total] = '\0'; /* sentinel */
}
mrb_value
@@ -324,11 +298,11 @@ mrb_str_new_static(mrb_state *mrb, const char *p, size_t len)
void
mrb_gc_free_str(mrb_state *mrb, struct RString *str)
{
- if (STR_EMBED_P(str))
+ if (RSTR_EMBED_P(str))
/* no code */;
- else if (STR_SHARED_P(str))
+ else if (RSTR_SHARED_P(str))
str_decref(mrb, str->as.heap.aux.shared);
- else if ((str->flags & MRB_STR_NOFREE) == 0)
+ else if (!RSTR_NOFREE_P(str))
mrb_free(mrb, str->as.heap.ptr);
}
@@ -342,34 +316,34 @@ mrb_str_to_cstr(mrb_state *mrb, mrb_value str0)
}
s = str_new(mrb, RSTRING_PTR(str0), RSTRING_LEN(str0));
- if ((strlen(STR_PTR(s)) ^ STR_LEN(s)) != 0) {
+ if ((strlen(RSTR_PTR(s)) ^ RSTR_LEN(s)) != 0) {
mrb_raise(mrb, E_ARGUMENT_ERROR, "string contains null byte");
}
- return STR_PTR(s);
+ return RSTR_PTR(s);
}
static void
str_make_shared(mrb_state *mrb, struct RString *s)
{
- if (!STR_SHARED_P(s)) {
+ if (!RSTR_SHARED_P(s)) {
mrb_shared_string *shared = (mrb_shared_string *)mrb_malloc(mrb, sizeof(mrb_shared_string));
shared->refcnt = 1;
- if (STR_EMBED_P(s)) {
- const mrb_int len = STR_EMBED_LEN(s);
+ if (RSTR_EMBED_P(s)) {
+ const mrb_int len = RSTR_EMBED_LEN(s);
char *const tmp = (char *)mrb_malloc(mrb, len+1);
memcpy(tmp, s->as.ary, len);
tmp[len] = '\0';
- STR_UNSET_EMBED_FLAG(s);
+ RSTR_UNSET_EMBED_FLAG(s);
s->as.heap.ptr = tmp;
s->as.heap.len = len;
shared->nofree = FALSE;
shared->ptr = s->as.heap.ptr;
}
- else if (s->flags & MRB_STR_NOFREE) {
+ else if (RSTR_NOFREE_P(s)) {
shared->nofree = TRUE;
shared->ptr = s->as.heap.ptr;
- s->flags &= ~MRB_STR_NOFREE;
+ RSTR_UNSET_NOFREE_FLAG(s);
}
else {
shared->nofree = FALSE;
@@ -382,7 +356,7 @@ str_make_shared(mrb_state *mrb, struct RString *s)
}
shared->len = s->as.heap.len;
s->as.heap.aux.shared = shared;
- STR_SET_SHARED_FLAG(s);
+ RSTR_SET_SHARED_FLAG(s);
}
}
@@ -397,8 +371,8 @@ mrb_str_body(mrb_value str, int *len_p)
{
struct RString *s = mrb_str_ptr(str);
- *len_p = STR_LEN(s);
- return STR_PTR(s);
+ *len_p = RSTR_LEN(s);
+ return RSTR_PTR(s);
}
/*
@@ -418,14 +392,14 @@ mrb_str_concat(mrb_state *mrb, mrb_value self, mrb_value other)
other = mrb_str_to_str(mrb, other);
}
s2 = mrb_str_ptr(other);
- len = STR_LEN(s1) + STR_LEN(s2);
+ len = RSTR_LEN(s1) + RSTR_LEN(s2);
if (RSTRING_CAPA(self) < len) {
resize_capa(mrb, s1, len);
}
- memcpy(STR_PTR(s1)+STR_LEN(s1), STR_PTR(s2), STR_LEN(s2));
- STR_SET_LEN(s1, len);
- STR_PTR(s1)[len] = '\0';
+ memcpy(RSTR_PTR(s1)+RSTR_LEN(s1), RSTR_PTR(s2), RSTR_LEN(s2));
+ RSTR_SET_LEN(s1, len);
+ RSTR_PTR(s1)[len] = '\0';
}
/*
@@ -441,9 +415,9 @@ mrb_str_plus(mrb_state *mrb, mrb_value a, mrb_value b)
struct RString *s2 = mrb_str_ptr(b);
struct RString *t;
- t = str_new(mrb, 0, STR_LEN(s) + STR_LEN(s2));
- memcpy(STR_PTR(t), STR_PTR(s), STR_LEN(s));
- memcpy(STR_PTR(t) + STR_LEN(s), STR_PTR(s2), STR_LEN(s2));
+ t = str_new(mrb, 0, RSTR_LEN(s) + RSTR_LEN(s2));
+ memcpy(RSTR_PTR(t), RSTR_PTR(s), RSTR_LEN(s));
+ memcpy(RSTR_PTR(t) + RSTR_LEN(s), RSTR_PTR(s2), RSTR_LEN(s2));
return mrb_obj_value(t);
}
@@ -475,7 +449,7 @@ static mrb_value
mrb_str_bytesize(mrb_state *mrb, mrb_value self)
{
struct RString *s = mrb_str_ptr(self);
- return mrb_fixnum_value(STR_LEN(s));
+ return mrb_fixnum_value(RSTR_LEN(s));
}
/* 15.2.10.5.26 */
@@ -490,7 +464,7 @@ mrb_value
mrb_str_size(mrb_state *mrb, mrb_value self)
{
struct RString *s = mrb_str_ptr(self);
- return mrb_fixnum_value(STR_LEN(s));
+ return mrb_fixnum_value(RSTR_LEN(s));
}
/* 15.2.10.5.1 */
@@ -521,7 +495,7 @@ mrb_str_times(mrb_state *mrb, mrb_value self)
len = RSTRING_LEN(self)*times;
str2 = str_new(mrb, 0, len);
str_with_class(mrb, str2, self);
- p = STR_PTR(str2);
+ p = RSTR_PTR(str2);
if (len > 0) {
n = RSTRING_LEN(self);
memcpy(p, RSTRING_PTR(self), n);
@@ -531,7 +505,7 @@ mrb_str_times(mrb_state *mrb, mrb_value self)
}
memcpy(p + n, p, len-n);
}
- p[STR_LEN(str2)] = '\0';
+ p[RSTR_LEN(str2)] = '\0';
return mrb_obj_value(str2);
}
@@ -555,11 +529,11 @@ mrb_str_cmp(mrb_state *mrb, mrb_value str1, mrb_value str2)
struct RString *s1 = mrb_str_ptr(str1);
struct RString *s2 = mrb_str_ptr(str2);
- len = lesser(STR_LEN(s1), STR_LEN(s2));
- retval = memcmp(STR_PTR(s1), STR_PTR(s2), len);
+ len = lesser(RSTR_LEN(s1), RSTR_LEN(s2));
+ retval = memcmp(RSTR_PTR(s1), RSTR_PTR(s2), len);
if (retval == 0) {
- if (STR_LEN(s1) == STR_LEN(s2)) return 0;
- if (STR_LEN(s1) > STR_LEN(s2)) return 1;
+ if (RSTR_LEN(s1) == RSTR_LEN(s2)) return 0;
+ if (RSTR_LEN(s1) > RSTR_LEN(s2)) return 1;
return -1;
}
if (retval > 0) return 1;
@@ -840,8 +814,6 @@ num_index:
* str.slice(fixnum) => fixnum or nil
* str.slice(fixnum, fixnum) => new_str or nil
* str.slice(range) => new_str or nil
- * str.slice(regexp) => new_str or nil
- * str.slice(regexp, fixnum) => new_str or nil
* str.slice(other_str) => new_str or nil
*
* Element Reference---If passed a single <code>Fixnum</code>, returns the code
@@ -853,10 +825,7 @@ num_index:
* <code>nil</code> if the initial offset falls outside the string, the length
* is negative, or the beginning of the range is greater than the end.
*
- * If a <code>Regexp</code> is supplied, the matching portion of <i>str</i> is
- * returned. If a numeric parameter follows the regular expression, that
- * component of the <code>MatchData</code> is returned instead. If a
- * <code>String</code> is given, that string is returned if it occurs in
+ * If a <code>String</code> is given, that string is returned if it occurs in
* <i>str</i>. In both cases, <code>nil</code> is returned if there is no
* match.
*
@@ -868,10 +837,6 @@ num_index:
* a[-4..-2] #=> "her"
* a[12..-1] #=> nil
* a[-2..-4] #=> ""
- * a[/[aeiou](.)\1/] #=> "ell"
- * a[/[aeiou](.)\1/, 0] #=> "ell"
- * a[/[aeiou](.)\1/, 1] #=> "l"
- * a[/[aeiou](.)\1/, 2] #=> nil
* a["lo"] #=> "lo"
* a["bye"] #=> nil
*/
@@ -913,8 +878,8 @@ mrb_str_capitalize_bang(mrb_state *mrb, mrb_value str)
struct RString *s = mrb_str_ptr(str);
mrb_str_modify(mrb, s);
- if (STR_LEN(s) == 0 || !STR_PTR(s)) return mrb_nil_value();
- p = STR_PTR(s); pend = STR_PTR(s) + STR_LEN(s);
+ if (RSTR_LEN(s) == 0 || !RSTR_PTR(s)) return mrb_nil_value();
+ p = RSTR_PTR(s); pend = RSTR_PTR(s) + RSTR_LEN(s);
if (ISLOWER(*p)) {
*p = TOUPPER(*p);
modify = TRUE;
@@ -970,29 +935,29 @@ mrb_str_chomp_bang(mrb_state *mrb, mrb_value str)
struct RString *s = mrb_str_ptr(str);
mrb_str_modify(mrb, s);
- len = STR_LEN(s);
+ len = RSTR_LEN(s);
if (mrb_get_args(mrb, "|S", &rs) == 0) {
if (len == 0) return mrb_nil_value();
smart_chomp:
- if (STR_PTR(s)[len-1] == '\n') {
- STR_SET_LEN(s, STR_LEN(s) - 1);
- if (STR_LEN(s) > 0 &&
- STR_PTR(s)[STR_LEN(s)-1] == '\r') {
- STR_SET_LEN(s, STR_LEN(s) - 1);
+ if (RSTR_PTR(s)[len-1] == '\n') {
+ RSTR_SET_LEN(s, RSTR_LEN(s) - 1);
+ if (RSTR_LEN(s) > 0 &&
+ RSTR_PTR(s)[RSTR_LEN(s)-1] == '\r') {
+ RSTR_SET_LEN(s, RSTR_LEN(s) - 1);
}
}
- else if (STR_PTR(s)[len-1] == '\r') {
- STR_SET_LEN(s, STR_LEN(s) - 1);
+ else if (RSTR_PTR(s)[len-1] == '\r') {
+ RSTR_SET_LEN(s, RSTR_LEN(s) - 1);
}
else {
return mrb_nil_value();
}
- STR_PTR(s)[STR_LEN(s)] = '\0';
+ RSTR_PTR(s)[RSTR_LEN(s)] = '\0';
return str;
}
if (len == 0 || mrb_nil_p(rs)) return mrb_nil_value();
- p = STR_PTR(s);
+ p = RSTR_PTR(s);
rslen = RSTRING_LEN(rs);
if (rslen == 0) {
while (len>0 && p[len-1] == '\n') {
@@ -1000,8 +965,8 @@ mrb_str_chomp_bang(mrb_state *mrb, mrb_value str)
if (len>0 && p[len-1] == '\r')
len--;
}
- if (len < STR_LEN(s)) {
- STR_SET_LEN(s, len);
+ if (len < RSTR_LEN(s)) {
+ RSTR_SET_LEN(s, len);
p[len] = '\0';
return str;
}
@@ -1018,8 +983,8 @@ mrb_str_chomp_bang(mrb_state *mrb, mrb_value str)
if (p[len-1] == newline &&
(rslen <= 1 ||
memcmp(RSTRING_PTR(rs), pp, rslen) == 0)) {
- STR_SET_LEN(s, len - rslen);
- p[STR_LEN(s)] = '\0';
+ RSTR_SET_LEN(s, len - rslen);
+ p[RSTR_LEN(s)] = '\0';
return str;
}
return mrb_nil_value();
@@ -1069,17 +1034,17 @@ mrb_str_chop_bang(mrb_state *mrb, mrb_value str)
struct RString *s = mrb_str_ptr(str);
mrb_str_modify(mrb, s);
- if (STR_LEN(s) > 0) {
+ if (RSTR_LEN(s) > 0) {
mrb_int len;
- len = STR_LEN(s) - 1;
- if (STR_PTR(s)[len] == '\n') {
+ len = RSTR_LEN(s) - 1;
+ if (RSTR_PTR(s)[len] == '\n') {
if (len > 0 &&
- STR_PTR(s)[len-1] == '\r') {
+ RSTR_PTR(s)[len-1] == '\r') {
len--;
}
}
- STR_SET_LEN(s, len);
- STR_PTR(s)[len] = '\0';
+ RSTR_SET_LEN(s, len);
+ RSTR_PTR(s)[len] = '\0';
return str;
}
return mrb_nil_value();
@@ -1127,8 +1092,8 @@ mrb_str_downcase_bang(mrb_state *mrb, mrb_value str)
struct RString *s = mrb_str_ptr(str);
mrb_str_modify(mrb, s);
- p = STR_PTR(s);
- pend = STR_PTR(s) + STR_LEN(s);
+ p = RSTR_PTR(s);
+ pend = RSTR_PTR(s) + RSTR_LEN(s);
while (p < pend) {
if (ISUPPER(*p)) {
*p = TOLOWER(*p);
@@ -1177,7 +1142,7 @@ mrb_str_empty_p(mrb_state *mrb, mrb_value self)
{
struct RString *s = mrb_str_ptr(self);
- return mrb_bool_value(STR_LEN(s) == 0);
+ return mrb_bool_value(RSTR_LEN(s) == 0);
}
/* 15.2.10.5.17 */
@@ -1206,7 +1171,7 @@ mrb_str_subseq(mrb_state *mrb, mrb_value str, mrb_int beg, mrb_int len)
mrb_shared_string *shared;
orig = mrb_str_ptr(str);
- if (STR_EMBED_P(orig)) {
+ if (RSTR_EMBED_P(orig)) {
s = str_new(mrb, orig->as.ary+beg, len);
} else {
str_make_shared(mrb, orig);
@@ -1215,7 +1180,7 @@ mrb_str_subseq(mrb_state *mrb, mrb_value str, mrb_int beg, mrb_int len)
s->as.heap.ptr = orig->as.heap.ptr + beg;
s->as.heap.len = len;
s->as.heap.aux.shared = shared;
- STR_SET_SHARED_FLAG(s);
+ RSTR_SET_SHARED_FLAG(s);
shared->refcnt++;
}
@@ -1247,8 +1212,8 @@ mrb_str_hash(mrb_state *mrb, mrb_value str)
{
/* 1-8-7 */
struct RString *s = mrb_str_ptr(str);
- mrb_int len = STR_LEN(s);
- char *p = STR_PTR(s);
+ mrb_int len = RSTR_LEN(s);
+ char *p = RSTR_PTR(s);
mrb_int key = 0;
while (len--) {
@@ -1393,27 +1358,31 @@ str_replace(mrb_state *mrb, struct RString *s1, struct RString *s2)
{
long len;
- len = STR_LEN(s2);
- if (STR_SHARED_P(s2)) {
- L_SHARE:
- if (STR_SHARED_P(s1)) {
- str_decref(mrb, s1->as.heap.aux.shared);
- }
- else if (!STR_EMBED_P(s1) && !(s1->flags & MRB_STR_NOFREE)) {
- mrb_free(mrb, s1->as.heap.ptr);
- }
- STR_UNSET_EMBED_FLAG(s1);
+ len = RSTR_LEN(s2);
+ if (RSTR_SHARED_P(s1)) {
+ str_decref(mrb, s1->as.heap.aux.shared);
+ }
+ else if (!RSTR_EMBED_P(s1) && !RSTR_NOFREE_P(s1)) {
+ mrb_free(mrb, s1->as.heap.ptr);
+ }
+
+ RSTR_UNSET_NOFREE_FLAG(s1);
+
+ if (RSTR_SHARED_P(s2)) {
+L_SHARE:
+ RSTR_UNSET_EMBED_FLAG(s1);
s1->as.heap.ptr = s2->as.heap.ptr;
s1->as.heap.len = len;
s1->as.heap.aux.shared = s2->as.heap.aux.shared;
- STR_SET_SHARED_FLAG(s1);
+ RSTR_SET_SHARED_FLAG(s1);
s1->as.heap.aux.shared->refcnt++;
}
else {
if (len <= RSTRING_EMBED_LEN_MAX) {
- STR_SET_EMBED_FLAG(s1);
- memcpy(s1->as.ary, STR_PTR(s2), len);
- STR_SET_EMBED_LEN(s1, len);
+ RSTR_UNSET_SHARED_FLAG(s1);
+ RSTR_SET_EMBED_FLAG(s1);
+ memcpy(s1->as.ary, RSTR_PTR(s2), len);
+ RSTR_SET_EMBED_LEN(s1, len);
}
else {
str_make_shared(mrb, s2);
@@ -1510,7 +1479,7 @@ mrb_ptr_to_str(mrb_state *mrb, void *p)
uintptr_t n = (uintptr_t)p;
p_str = str_new(mrb, NULL, 2 + sizeof(uintptr_t) * CHAR_BIT / 4);
- p1 = STR_PTR(p_str);
+ p1 = RSTR_PTR(p_str);
*p1++ = '0';
*p1++ = 'x';
p2 = p1;
@@ -1520,7 +1489,7 @@ mrb_ptr_to_str(mrb_state *mrb, void *p)
n /= 16;
} while (n > 0);
*p2 = '\0';
- STR_SET_LEN(p_str, (mrb_int)(p2 - STR_PTR(p_str)));
+ RSTR_SET_LEN(p_str, (mrb_int)(p2 - RSTR_PTR(p_str)));
while (p1 < p2) {
const char c = *p1;
@@ -1564,7 +1533,7 @@ mrb_str_reverse(mrb_state *mrb, mrb_value str)
s2 = str_new(mrb, 0, RSTRING_LEN(str));
str_with_class(mrb, s2, str);
s = RSTRING_PTR(str); e = RSTRING_END(str) - 1;
- p = STR_PTR(s2);
+ p = RSTR_PTR(s2);
while (e >= s) {
*p++ = *e--;
@@ -1587,9 +1556,9 @@ mrb_str_reverse_bang(mrb_state *mrb, mrb_value str)
char c;
mrb_str_modify(mrb, s);
- if (STR_LEN(s) > 1) {
- p = STR_PTR(s);
- e = p + STR_LEN(s) - 1;
+ if (RSTR_LEN(s) > 1) {
+ p = RSTR_PTR(s);
+ e = p + RSTR_LEN(s) - 1;
while (p < e) {
c = *p;
*p++ = *e;
@@ -1625,17 +1594,17 @@ mrb_str_rindex(mrb_state *mrb, mrb_value str, mrb_value sub, mrb_int pos)
mrb_int len = RSTRING_LEN(sub);
/* substring longer than string */
- if (STR_LEN(ps) < len) return -1;
- if (STR_LEN(ps) - pos < len) {
- pos = STR_LEN(ps) - len;
+ if (RSTR_LEN(ps) < len) return -1;
+ if (RSTR_LEN(ps) - pos < len) {
+ pos = RSTR_LEN(ps) - len;
}
- sbeg = STR_PTR(ps);
- s = STR_PTR(ps) + pos;
+ sbeg = RSTR_PTR(ps);
+ s = RSTR_PTR(ps) + pos;
t = RSTRING_PTR(sub);
if (len) {
while (sbeg <= s) {
if (memcmp(s, t, len) == 0) {
- return s - STR_PTR(ps);
+ return s - RSTR_PTR(ps);
}
s--;
}
@@ -1728,27 +1697,6 @@ mrb_str_rindex_m(mrb_state *mrb, mrb_value str)
return mrb_nil_value();
}
-static const char isspacetable[256] = {
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
-};
-
-#define ascii_isspace(c) isspacetable[(unsigned char)(c)]
-
/* 15.2.10.5.35 */
/*
@@ -1844,7 +1792,7 @@ mrb_str_split_m(mrb_state *mrb, mrb_value str)
int ai = mrb_gc_arena_save(mrb);
c = (unsigned char)*ptr++;
if (skip) {
- if (ascii_isspace(c)) {
+ if (ISSPACE(c)) {
beg = ptr - bptr;
}
else {
@@ -1853,7 +1801,7 @@ mrb_str_split_m(mrb_state *mrb, mrb_value str)
if (lim_p && lim <= i) break;
}
}
- else if (ascii_isspace(c)) {
+ else if (ISSPACE(c)) {
mrb_ary_push(mrb, result, mrb_str_subseq(mrb, str, beg, end-beg));
mrb_gc_arena_restore(mrb, ai);
skip = TRUE;
@@ -2068,11 +2016,11 @@ mrb_string_value_cstr(mrb_state *mrb, mrb_value *ptr)
{
struct RString *ps = mrb_str_ptr(*ptr);
mrb_int len = mrb_str_strlen(mrb, ps);
- char *p = STR_PTR(ps);
+ char *p = RSTR_PTR(ps);
if (!p || p[len] != '\0') {
mrb_str_modify(mrb, ps);
- return STR_PTR(ps);
+ return RSTR_PTR(ps);
}
return p;
}
@@ -2094,7 +2042,7 @@ mrb_str_to_inum(mrb_state *mrb, mrb_value str, mrb_int base, mrb_bool badcheck)
len = RSTRING_LEN(str);
if (s[len]) { /* no sentinel somehow */
struct RString *temp_str = str_new(mrb, s, len);
- s = STR_PTR(temp_str);
+ s = RSTR_PTR(temp_str);
}
}
return mrb_cstr_to_inum(mrb, s, base, badcheck);
@@ -2214,7 +2162,7 @@ mrb_str_to_dbl(mrb_state *mrb, mrb_value str, mrb_bool badcheck)
}
if (s[len]) { /* no sentinel somehow */
struct RString *temp_str = str_new(mrb, s, len);
- s = STR_PTR(temp_str);
+ s = RSTR_PTR(temp_str);
}
}
return mrb_cstr_to_dbl(mrb, s, badcheck);
@@ -2308,6 +2256,8 @@ mrb_str_upcase(mrb_state *mrb, mrb_value self)
return str;
}
+#define IS_EVSTR(p,e) ((p) < (e) && (*(p) == '$' || *(p) == '@' || *(p) == '{'))
+
/*
* call-seq:
* str.dump -> new_str
@@ -2353,7 +2303,7 @@ mrb_str_dump(mrb_state *mrb, mrb_value str)
result = str_new(mrb, 0, len);
str_with_class(mrb, result, str);
p = RSTRING_PTR(str); pend = p + RSTRING_LEN(str);
- q = STR_PTR(result);
+ q = RSTR_PTR(result);
*q++ = '"';
while (p < pend) {
unsigned char c = *p++;
@@ -2532,8 +2482,8 @@ static mrb_value
mrb_str_bytes(mrb_state *mrb, mrb_value str)
{
struct RString *s = mrb_str_ptr(str);
- mrb_value a = mrb_ary_new_capa(mrb, STR_LEN(s));
- unsigned char *p = (unsigned char *)(STR_PTR(s)), *pend = p + STR_LEN(s);
+ mrb_value a = mrb_ary_new_capa(mrb, RSTR_LEN(s));
+ unsigned char *p = (unsigned char *)(RSTR_PTR(s)), *pend = p + RSTR_LEN(s);
while (p < pend) {
mrb_ary_push(mrb, a, mrb_fixnum_value(p[0]));
@@ -2548,6 +2498,8 @@ mrb_init_string(mrb_state *mrb)
{
struct RClass *s;
+ mrb_static_assert(RSTRING_EMBED_LEN_MAX < (1 << 5), "pointer size too big for embedded string");
+
s = mrb->string_class = mrb_define_class(mrb, "String", mrb->object_class); /* 15.2.10 */
MRB_SET_INSTANCE_TT(s, MRB_TT_STRING);
diff --git a/src/variable.c b/src/variable.c
index 5f762dd0b..74bb591cf 100644
--- a/src/variable.c
+++ b/src/variable.c
@@ -124,10 +124,10 @@ iv_put(mrb_state *mrb, iv_tbl *t, mrb_sym sym, mrb_value val)
* mrb
* t the variable table to be searched.
* sym the symbol to be used as the key.
- * vp the value pointer. Recieves the value if the specified symbol contains
- * in the instance variable table.
+ * vp the value pointer. Receives the value if the specified symbol is
+ * contained in the instance variable table.
* Returns
- * true if the specfiyed symbol contains in the instance variable table.
+ * true if the specified symbol is contained in the instance variable table.
*/
static mrb_bool
iv_get(mrb_state *mrb, iv_tbl *t, mrb_sym sym, mrb_value *vp)
@@ -159,10 +159,10 @@ iv_get(mrb_state *mrb, iv_tbl *t, mrb_sym sym, mrb_value *vp)
* Parameters
* t the variable table to be searched.
* sym the symbol to be used as the key.
- * vp the value pointer. Recieve the deleted value if the symbol contans
- * in the instance varible table.
+ * vp the value pointer. Receive the deleted value if the symbol is
+ * contained in the instance variable table.
* Returns
- * true if the specfied symbol contains in the instance variable table.
+ * true if the specified symbol is contained in the instance variable table.
*/
static mrb_bool
iv_del(mrb_state *mrb, iv_tbl *t, mrb_sym sym, mrb_value *vp)
diff --git a/src/vm.c b/src/vm.c
index 649596713..9a0f03aba 100644
--- a/src/vm.c
+++ b/src/vm.c
@@ -625,7 +625,7 @@ mrb_yield_with_class(mrb_state *mrb, mrb_value b, mrb_int argc, const mrb_value
stack_extend(mrb, ci->nregs, 0);
}
else {
- ci->nregs = p->body.irep->nregs + 1;
+ ci->nregs = p->body.irep->nregs;
stack_extend(mrb, ci->nregs, argc+2);
}
@@ -793,7 +793,7 @@ RETRY_TRY_BLOCK:
}
stack_extend(mrb, irep->nregs, stack_keep);
mrb->c->ci->proc = proc;
- mrb->c->ci->nregs = irep->nregs + 1;
+ mrb->c->ci->nregs = irep->nregs;
regs = mrb->c->stack;
regs[0] = self;
@@ -811,7 +811,7 @@ RETRY_TRY_BLOCK:
CASE(OP_LOADL) {
/* A Bx R(A) := Pool(Bx) */
- regs[GETARG_A(i)] = pool[GETARG_Bx(i)];
+ regs[GETARG_A(i)] = pool[GETARG_Bx(i)];
NEXT;
}
@@ -2402,19 +2402,25 @@ mrb_run(mrb_state *mrb, struct RProc *proc, mrb_value self)
}
mrb_value
-mrb_toplevel_run(mrb_state *mrb, struct RProc *proc)
+mrb_toplevel_run_keep(mrb_state *mrb, struct RProc *proc, unsigned int stack_keep)
{
mrb_callinfo *ci;
mrb_value v;
if (!mrb->c->cibase || mrb->c->ci == mrb->c->cibase) {
- return mrb_context_run(mrb, proc, mrb_top_self(mrb), 0);
+ return mrb_context_run(mrb, proc, mrb_top_self(mrb), stack_keep);
}
ci = cipush(mrb);
ci->acc = CI_ACC_SKIP;
ci->target_class = mrb->object_class;
- v = mrb_context_run(mrb, proc, mrb_top_self(mrb), 0);
+ v = mrb_context_run(mrb, proc, mrb_top_self(mrb), stack_keep);
cipop(mrb);
return v;
}
+
+mrb_value
+mrb_toplevel_run(mrb_state *mrb, struct RProc *proc)
+{
+ return mrb_toplevel_run_keep(mrb, proc, 0);
+}
diff --git a/tasks/libmruby.rake b/tasks/libmruby.rake
index 887cc69aa..095bedd52 100644
--- a/tasks/libmruby.rake
+++ b/tasks/libmruby.rake
@@ -1,7 +1,10 @@
MRuby.each_target do
file libfile("#{build_dir}/lib/libmruby") => libmruby.flatten do |t|
archiver.run t.name, t.prerequisites
- open("#{build_dir}/lib/libmruby.flags.mak", 'w') do |f|
+ end
+
+ file "#{build_dir}/lib/libmruby.flags.mak" => [__FILE__, libfile("#{build_dir}/lib/libmruby")] do |t|
+ open(t.name, 'w') do |f|
f.puts "MRUBY_CFLAGS = #{cc.all_flags.gsub('"', '\\"')}"
gem_flags = gems.map { |g| g.linker.flags }
@@ -15,4 +18,5 @@ MRuby.each_target do
f.puts "MRUBY_LIBS = #{linker.option_library % 'mruby'} #{linker.library_flags(gem_libraries).gsub('"', '\\"')}"
end
end
+ task :all => "#{build_dir}/lib/libmruby.flags.mak"
end
diff --git a/tasks/mrbgem_spec.rake b/tasks/mrbgem_spec.rake
index 67edffbc5..2a15a1f46 100644
--- a/tasks/mrbgem_spec.rake
+++ b/tasks/mrbgem_spec.rake
@@ -32,7 +32,9 @@ module MRuby
attr_accessor :bins
attr_accessor :requirements
- attr_reader :dependencies
+ attr_reader :dependencies, :conflicts
+
+ attr_accessor :export_include_paths
attr_block MRuby::Build::COMMANDS
@@ -44,27 +46,24 @@ module MRuby
end
def run_test_in_other_mrb_state?
- not test_preload.nil? or not test_objs.empty?
+ not test_preload.nil? or not test_objs.empty? or not test_args.empty?
end
def setup
MRuby::Gem.current = self
- @build.compilers.each do |compiler|
- compiler.include_paths << "#{dir}/include"
- end if File.directory? "#{dir}/include"
MRuby::Build::COMMANDS.each do |command|
instance_variable_set("@#{command}", @build.send(command).clone)
end
@linker = LinkerConfig.new([], [], [], [])
@rbfiles = Dir.glob("#{dir}/mrblib/*.rb").sort
- @objs = Dir.glob("#{dir}/src/*.{c,cpp,cxx,cc,m,asm,S}").map do |f|
+ @objs = Dir.glob("#{dir}/src/*.{c,cpp,cxx,cc,m,asm,s,S}").map do |f|
objfile(f.relative_path_from(@dir).to_s.pathmap("#{build_dir}/%X"))
end
@objs << objfile("#{build_dir}/gem_init")
@test_rbfiles = Dir.glob("#{dir}/test/*.rb")
- @test_objs = Dir.glob("#{dir}/test/*.{c,cpp,cxx,cc,m,asm,S}").map do |f|
+ @test_objs = Dir.glob("#{dir}/test/*.{c,cpp,cxx,cc,m,asm,s,S}").map do |f|
objfile(f.relative_path_from(dir).to_s.pathmap("#{build_dir}/%X"))
end
@test_preload = nil # 'test/assert.rb'
@@ -73,7 +72,9 @@ module MRuby
@bins = []
@requirements = []
- @dependencies = []
+ @dependencies, @conflicts = [], []
+ @export_include_paths = []
+ @export_include_paths << "#{dir}/include" if File.directory? "#{dir}/include"
instance_eval(&@initializer)
@@ -88,6 +89,7 @@ module MRuby
compilers.each do |compiler|
compiler.define_rules build_dir, "#{dir}"
compiler.defines << %Q[MRBGEM_#{funcname.upcase}_VERSION=#{version}]
+ compiler.include_paths << "#{dir}/include" if File.directory? "#{dir}/include"
end
define_gem_init_builder
@@ -100,6 +102,10 @@ module MRuby
@dependencies << {:gem => name, :requirements => requirements, :default => default_gem}
end
+ def add_conflict(name, *req)
+ @conflicts << {:gem => name, :requirements => req.empty? ? nil : req}
+ end
+
def self.bin=(bin)
@bins = [bin].flatten
end
@@ -124,7 +130,7 @@ module MRuby
def define_gem_init_builder
file objfile("#{build_dir}/gem_init") => "#{build_dir}/gem_init.c"
- file "#{build_dir}/gem_init.c" => [build.mrbcfile] + [rbfiles].flatten do |t|
+ file "#{build_dir}/gem_init.c" => [build.mrbcfile, __FILE__] + [rbfiles].flatten do |t|
FileUtils.mkdir_p build_dir
generate_gem_init("#{build_dir}/gem_init.c")
end
@@ -182,6 +188,7 @@ module MRuby
f.puts %Q[#include "mruby/irep.h"]
f.puts %Q[#include "mruby/string.h"]
f.puts %Q[#include "mruby/variable.h"]
+ f.puts %Q[#include "mruby/hash.h"] unless test_args.empty?
end
def version_ok?(req_versions)
@@ -320,6 +327,12 @@ module MRuby
fail "#{name} version should be #{req_versions.join(' and ')} but was '#{dep_g.version}'"
end
end
+
+ cfls = g.conflicts.select { |c|
+ cfl_g = gem_table[c[:gem]]
+ cfl_g and cfl_g.version_ok?(c[:requirements] || ['>= 0.0.0'])
+ }.map { |c| "#{c[:gem]}(#{gem_table[c[:gem]].version})" }
+ fail "Conflicts of gem `#{g.name}` found: #{cfls.join ', '}" unless cfls.empty?
end
class << gem_table
@@ -337,6 +350,25 @@ module MRuby
rescue TSort::Cyclic => e
fail "Circular mrbgem dependency found: #{e.message}"
end
+
+ each do |g|
+ import_include_paths(g)
+ end
+ end
+
+ def import_include_paths(g)
+ gem_table = @ary.reduce({}) { |res,v| res[v.name] = v; res }
+ g.dependencies.each do |dep|
+ dep_g = gem_table[dep[:gem]]
+ # We can do recursive call safely
+ # as circular dependency has already detected in the caller.
+ import_include_paths(dep_g)
+
+ g.compilers.each do |compiler|
+ compiler.include_paths += dep_g.export_include_paths
+ g.export_include_paths += dep_g.export_include_paths
+ end
+ end
end
end # List
end # Gem
diff --git a/tasks/mrbgems.rake b/tasks/mrbgems.rake
index b57f318e0..2d17be931 100644
--- a/tasks/mrbgems.rake
+++ b/tasks/mrbgems.rake
@@ -7,7 +7,7 @@ MRuby.each_target do
# loader all gems
self.libmruby << objfile("#{build_dir}/mrbgems/gem_init")
file objfile("#{build_dir}/mrbgems/gem_init") => ["#{build_dir}/mrbgems/gem_init.c", "#{build_dir}/LEGAL"]
- file "#{build_dir}/mrbgems/gem_init.c" => [MRUBY_CONFIG] do |t|
+ file "#{build_dir}/mrbgems/gem_init.c" => [MRUBY_CONFIG, __FILE__] do |t|
FileUtils.mkdir_p "#{build_dir}/mrbgems"
open(t.name, 'w') do |f|
f.puts %Q[/*]
@@ -26,21 +26,22 @@ MRuby.each_target do
f.puts %Q[]
f.puts %Q[#{gems.map{|g| "void GENERATED_TMP_mrb_%s_gem_final(mrb_state* mrb);" % g.funcname}.join("\n")}]
f.puts %Q[]
- f.puts %Q[void]
- f.puts %Q[mrb_init_mrbgems(mrb_state *mrb) {]
- f.puts %Q[#{gems.map{|g| "GENERATED_TMP_mrb_%s_gem_init(mrb);" % g.funcname}.join("\n")}]
+ f.puts %Q[static void]
+ f.puts %Q[mrb_final_mrbgems(mrb_state *mrb) {]
+ f.puts %Q[#{gems.map{|g| "GENERATED_TMP_mrb_%s_gem_final(mrb);" % g.funcname}.join("\n")}]
f.puts %Q[}]
f.puts %Q[]
f.puts %Q[void]
- f.puts %Q[mrb_final_mrbgems(mrb_state *mrb) {]
- f.puts %Q[#{gems.map{|g| "GENERATED_TMP_mrb_%s_gem_final(mrb);" % g.funcname}.join("\n")}]
+ f.puts %Q[mrb_init_mrbgems(mrb_state *mrb) {]
+ f.puts %Q[#{gems.map{|g| "GENERATED_TMP_mrb_%s_gem_init(mrb);" % g.funcname}.join("\n")}]
+ f.puts %Q[mrb_state_atexit(mrb, mrb_final_mrbgems);]
f.puts %Q[}]
end
end
end
# legal documents
- file "#{build_dir}/LEGAL" => [MRUBY_CONFIG] do |t|
+ file "#{build_dir}/LEGAL" => [MRUBY_CONFIG, __FILE__] do |t|
open(t.name, 'w+') do |f|
f.puts <<LEGAL
Copyright (c) #{Time.now.year} mruby developers
diff --git a/tasks/mrbgems_test.rake b/tasks/mrbgems_test.rake
index d06b7a24c..a6e9eb99e 100644
--- a/tasks/mrbgems_test.rake
+++ b/tasks/mrbgems_test.rake
@@ -10,7 +10,7 @@ MRuby.each_target do
test_rbobj = g.test_rbireps.ext(exts.object)
file test_rbobj => g.test_rbireps
- file g.test_rbireps => [g.test_rbfiles].flatten + [g.build.mrbcfile] do |t|
+ file g.test_rbireps => [g.test_rbfiles].flatten + [g.build.mrbcfile, __FILE__] do |t|
open(t.name, 'w') do |f|
g.print_gem_test_header(f)
test_preload = g.test_preload and [g.dir, MRUBY_ROOT].map {|dir|
@@ -117,7 +117,7 @@ MRuby.each_target do
no_mrb_open_test_lib = no_mrb_open_test.ext(exts.object)
file no_mrb_open_test_lib => "#{no_mrb_open_test}.c"
- file "#{no_mrb_open_test}.c" => no_mrb_open_test_rbfiles + [MRUBY_CONFIG] do |t|
+ file "#{no_mrb_open_test}.c" => no_mrb_open_test_rbfiles + [MRUBY_CONFIG, __FILE__] do |t|
open(t.name, 'w') do |f|
f.puts %Q[/*]
f.puts %Q[ * This file contains a test code for following gems:]
diff --git a/tasks/mruby_build.rake b/tasks/mruby_build.rake
index 966c602a4..09175d533 100644
--- a/tasks/mruby_build.rake
+++ b/tasks/mruby_build.rake
@@ -209,6 +209,7 @@ module MRuby
def run_bintest
targets = @gems.select { |v| File.directory? "#{v.dir}/bintest" }.map { |v| filename v.dir }
+ targets << filename(".") if File.directory? "./bintest"
sh "ruby test/bintest.rb #{targets.join ' '}"
end
diff --git a/tasks/mruby_build_gem.rake b/tasks/mruby_build_gem.rake
index e58dc5c71..5d2dc030c 100644
--- a/tasks/mruby_build_gem.rake
+++ b/tasks/mruby_build_gem.rake
@@ -35,8 +35,9 @@ module MRuby
Gem.current.build_config_initializer = block
gems << Gem.current
- cxx_srcs = Dir.glob("#{Gem.current.dir}/src/*.{cpp,cxx,cc}")
- cxx_srcs += Dir.glob("#{Gem.current.dir}/test/*.{cpp,cxx,cc}")
+ cxx_srcs = ['src', 'test', 'tools'].map do |subdir|
+ Dir.glob("#{Gem.current.dir}/#{subdir}/*.{cpp,cxx,cc}")
+ end.flatten
enable_cxx_abi unless cxx_srcs.empty?
Gem.current
diff --git a/tasks/toolchains/gcc.rake b/tasks/toolchains/gcc.rake
index 821100748..7edf93642 100644
--- a/tasks/toolchains/gcc.rake
+++ b/tasks/toolchains/gcc.rake
@@ -2,7 +2,6 @@ MRuby::Toolchain.new(:gcc) do |conf|
[conf.cc, conf.objc, conf.asm].each do |cc|
cc.command = ENV['CC'] || 'gcc'
cc.flags = [ENV['CFLAGS'] || %w(-g -std=gnu99 -O3 -Wall -Werror-implicit-function-declaration -Wdeclaration-after-statement)]
- cc.include_paths = ["#{MRUBY_ROOT}/include"]
cc.defines = %w(DISABLE_GEMS)
cc.option_include_path = '-I%s'
cc.option_define = '-D%s'
@@ -12,7 +11,6 @@ MRuby::Toolchain.new(:gcc) do |conf|
[conf.cxx].each do |cxx|
cxx.command = ENV['CXX'] || 'g++'
cxx.flags = [ENV['CXXFLAGS'] || ENV['CFLAGS'] || %w(-g -O3 -Wall -Werror-implicit-function-declaration)]
- cxx.include_paths = ["#{MRUBY_ROOT}/include"]
cxx.defines = %w(DISABLE_GEMS)
cxx.option_include_path = '-I%s'
cxx.option_define = '-D%s'
diff --git a/tasks/toolchains/visualcpp.rake b/tasks/toolchains/visualcpp.rake
index a5726dce7..8838f8a41 100644
--- a/tasks/toolchains/visualcpp.rake
+++ b/tasks/toolchains/visualcpp.rake
@@ -3,7 +3,6 @@ MRuby::Toolchain.new(:visualcpp) do |conf|
cc.command = ENV['CC'] || 'cl.exe'
# C4013: implicit function declaration
cc.flags = [ENV['CFLAGS'] || %w(/c /nologo /W3 /we4013 /Zi /MD /O2 /D_CRT_SECURE_NO_WARNINGS)]
- cc.include_paths = ["#{MRUBY_ROOT}/include"]
cc.defines = %w(DISABLE_GEMS MRB_STACK_EXTEND_DOUBLING)
cc.option_include_path = '/I%s'
cc.option_define = '/D%s'
@@ -13,7 +12,6 @@ MRuby::Toolchain.new(:visualcpp) do |conf|
[conf.cxx].each do |cxx|
cxx.command = ENV['CXX'] || 'cl.exe'
cxx.flags = [ENV['CXXFLAGS'] || ENV['CFLAGS'] || %w(/c /nologo /W3 /Zi /MD /O2 /EHsc /D_CRT_SECURE_NO_WARNINGS)]
- cxx.include_paths = ["#{MRUBY_ROOT}/include"]
cxx.defines = %w(DISABLE_GEMS MRB_STACK_EXTEND_DOUBLING)
cxx.option_include_path = '/I%s'
cxx.option_define = '/D%s'
diff --git a/test/mrbtest.rake b/test/mrbtest.rake
index e8eb6addd..c28cf3577 100644
--- a/test/mrbtest.rake
+++ b/test/mrbtest.rake
@@ -31,15 +31,15 @@ MRuby.each_target do
end
file ass_lib => ass_c
- file ass_c => "#{current_dir}/assert.rb" do |t|
+ file ass_c => ["#{current_dir}/assert.rb", __FILE__] do |t|
FileUtils.mkdir_p File.dirname t.name
open(t.name, 'w') do |f|
- mrbc.run f, [t.prerequisites], 'mrbtest_assert_irep'
+ mrbc.run f, [t.prerequisites.first], 'mrbtest_assert_irep'
end
end
file mlib => clib
- file clib => [mrbcfile, init] + mrbs do |t|
+ file clib => [mrbcfile, init, __FILE__] + mrbs do |t|
_pp "GEN", "*.rb", "#{clib.relative_path}"
FileUtils.mkdir_p File.dirname(clib)
open(clib, 'w') do |f|
diff --git a/test/t/argumenterror.rb b/test/t/argumenterror.rb
index c8d277cc5..abb53429b 100644
--- a/test/t/argumenterror.rb
+++ b/test/t/argumenterror.rb
@@ -14,8 +14,3 @@ assert('ArgumentError', '15.2.24') do
assert_equal(Class, ArgumentError.class)
assert_equal(ArgumentError, e2.class)
end
-
-assert('ArgumentError superclass', '15.2.24.2') do
- assert_equal(StandardError, ArgumentError.superclass)
-end
-
diff --git a/test/t/array.rb b/test/t/array.rb
index 56daf0b01..538ea0c3f 100644
--- a/test/t/array.rb
+++ b/test/t/array.rb
@@ -5,10 +5,6 @@ assert('Array', '15.2.12') do
assert_equal(Class, Array.class)
end
-assert('Array superclass', '15.2.12.2') do
- assert_equal(Object, Array.superclass)
-end
-
assert('Array inclueded modules', '15.2.12.3') do
assert_true(Array.include?(Enumerable))
end
diff --git a/test/t/class.rb b/test/t/class.rb
index 821259c5e..f49ccf494 100644
--- a/test/t/class.rb
+++ b/test/t/class.rb
@@ -5,10 +5,6 @@ assert('Class', '15.2.3') do
assert_equal(Class, Class.class)
end
-assert('Class superclass', '15.2.3.2') do
- assert_equal(Module, Class.superclass)
-end
-
assert('Class#initialize', '15.2.3.3.1') do
c = Class.new do
def test
diff --git a/test/t/enumerable.rb b/test/t/enumerable.rb
index 97f86e561..21acd209e 100644
--- a/test/t/enumerable.rb
+++ b/test/t/enumerable.rb
@@ -44,7 +44,7 @@ assert('Enumerable#collect', '15.3.2.2.3') do
end
assert('Enumerable#detect', '15.3.2.2.4') do
- assert_true [1,2,3].detect() { true }
+ assert_equal 1, [1,2,3].detect() { true }
assert_equal 'a', [1,2,3].detect("a") { false }
end
@@ -63,7 +63,7 @@ assert('Enumerable#entries', '15.3.2.2.6') do
end
assert('Enumerable#find', '15.3.2.2.7') do
- assert_true [1,2,3].find() { true }
+ assert_equal 1, [1,2,3].find() { true }
assert_equal 'a', [1,2,3].find("a") { false }
end
@@ -106,8 +106,8 @@ assert('Enumerable#member?', '15.3.2.2.15') do
assert_false [1,2,3,4,5,6,7,8,9].member?(0)
end
-assert('Enumerable#partion', '15.3.2.2.16') do
- partition = [0,1,2,3,4,5,6,7,8,9].partition do |i|
+assert('Enumerable#partition', '15.3.2.2.16') do
+ [0,1,2,3,4,5,6,7,8,9].partition do |i|
i % 2 == 0
end
assert_equal [[0,2,4,6,8], [1,3,5,7,9]], partition
diff --git a/test/t/exception.rb b/test/t/exception.rb
index 8aa07e813..d27813028 100644
--- a/test/t/exception.rb
+++ b/test/t/exception.rb
@@ -5,10 +5,6 @@ assert('Exception', '15.2.22') do
assert_equal Class, Exception.class
end
-assert('Exception superclass', '15.2.22.2') do
- assert_equal Object, Exception.superclass
-end
-
assert('Exception.exception', '15.2.22.4.1') do
e = Exception.exception('a')
@@ -16,11 +12,14 @@ assert('Exception.exception', '15.2.22.4.1') do
end
assert('Exception#exception', '15.2.22.5.1') do
- e1 = Exception.exception()
- e2 = Exception.exception('b')
-
- assert_equal Exception, e1.class
- assert_equal Exception, e2.class
+ e = Exception.new
+ re = RuntimeError.new
+ assert_equal e, e.exception
+ assert_equal e, e.exception(e)
+ assert_equal re, re.exception(re)
+ changed_re = re.exception('message has changed')
+ assert_not_equal re, changed_re
+ assert_equal 'message has changed', changed_re.message
end
assert('Exception#message', '15.2.22.5.2') do
diff --git a/test/t/false.rb b/test/t/false.rb
index bc684f2e6..3582f697a 100644
--- a/test/t/false.rb
+++ b/test/t/false.rb
@@ -11,10 +11,6 @@ assert('FalseClass false', '15.2.6.1') do
assert_false FalseClass.method_defined? :new
end
-assert('FalseClass superclass', '15.2.6.2') do
- assert_equal Object, FalseClass.superclass
-end
-
assert('FalseClass#&', '15.2.6.3.1') do
assert_false false.&(true)
assert_false false.&(false)
diff --git a/test/t/float.rb b/test/t/float.rb
index ded434320..d45709173 100644
--- a/test/t/float.rb
+++ b/test/t/float.rb
@@ -5,10 +5,6 @@ assert('Float', '15.2.9') do
assert_equal Class, Float.class
end
-assert('Float superclass', '15.2.9.2') do
- assert_equal Numeric, Float.superclass
-end
-
assert('Float#+', '15.2.9.3.1') do
a = 3.123456788 + 0.000000001
b = 3.123456789 + 1
diff --git a/test/t/hash.rb b/test/t/hash.rb
index 0d8d137c4..eee7c7b6a 100644
--- a/test/t/hash.rb
+++ b/test/t/hash.rb
@@ -5,10 +5,6 @@ assert('Hash', '15.2.13') do
assert_equal Class, Hash.class
end
-assert('Hash superclass', '15.2.13.2') do
- assert_equal Object, Hash.superclass
-end
-
assert('Hash#==', '15.2.13.4.1') do
assert_true({ 'abc' => 'abc' } == { 'abc' => 'abc' })
assert_false({ 'abc' => 'abc' } == { 'cba' => 'cba' })
diff --git a/test/t/indexerror.rb b/test/t/indexerror.rb
index ea008a227..a8dce23a0 100644
--- a/test/t/indexerror.rb
+++ b/test/t/indexerror.rb
@@ -4,7 +4,3 @@
assert('IndexError', '15.2.33') do
assert_equal Class, IndexError.class
end
-
-assert('IndexError superclass', '15.2.33.2') do
- assert_equal StandardError, IndexError.superclass
-end
diff --git a/test/t/integer.rb b/test/t/integer.rb
index 6560dddfe..c50ef112c 100644
--- a/test/t/integer.rb
+++ b/test/t/integer.rb
@@ -5,10 +5,6 @@ assert('Integer', '15.2.8') do
assert_equal Class, Integer.class
end
-assert('Integer superclass', '15.2.8.2') do
- assert_equal Numeric, Integer.superclass
-end
-
assert('Integer#+', '15.2.8.3.1') do
a = 1+1
b = 1+1.0
diff --git a/test/t/kernel.rb b/test/t/kernel.rb
index 427d71e36..6df2294d5 100644
--- a/test/t/kernel.rb
+++ b/test/t/kernel.rb
@@ -586,8 +586,5 @@ assert('stack extend') do
end
assert_equal 6, recurse(0, 5)
- assert_raise RuntimeError do
- recurse(0, 100000)
- end
end
diff --git a/test/t/module.rb b/test/t/module.rb
index fcf46fe3a..5ac794330 100644
--- a/test/t/module.rb
+++ b/test/t/module.rb
@@ -5,10 +5,6 @@ assert('Module', '15.2.2') do
assert_equal Class, Module.class
end
-assert('Module superclass', '15.2.2.2') do
- assert_equal Object, Module.superclass
-end
-
# TODO not implemented ATM assert('Module.constants', '15.2.2.3.1') do
# TODO not implemented ATM assert('Module.nesting', '15.2.2.3.2') do
diff --git a/test/t/nameerror.rb b/test/t/nameerror.rb
index 3e3c59264..28682bedc 100644
--- a/test/t/nameerror.rb
+++ b/test/t/nameerror.rb
@@ -5,10 +5,6 @@ assert('NameError', '15.2.31') do
assert_equal Class, NameError.class
end
-assert('NameError superclass', '15.2.31.2') do
- assert_equal StandardError, NameError.superclass
-end
-
assert('NameError#name', '15.2.31.2.1') do
# This check is not duplicate with 15.2.31.2.2 check.
diff --git a/test/t/nil.rb b/test/t/nil.rb
index 971ce2e8e..53b922f9a 100644
--- a/test/t/nil.rb
+++ b/test/t/nil.rb
@@ -10,10 +10,6 @@ assert('NilClass', '15.2.4.1') do
assert_false NilClass.method_defined? :new
end
-assert('NilClass superclass', '15.2.4.2') do
- assert_equal Object, NilClass.superclass
-end
-
assert('NilClass#&', '15.2.4.3.1') do
assert_false nil.&(true)
assert_false nil.&(nil)
diff --git a/test/t/nomethoderror.rb b/test/t/nomethoderror.rb
index 561e545f9..5fed79689 100644
--- a/test/t/nomethoderror.rb
+++ b/test/t/nomethoderror.rb
@@ -8,6 +8,15 @@ assert('NoMethodError', '15.2.32') do
end
end
-assert('NoMethodError superclass', '15.2.32.2') do
- assert_equal NameError, NoMethodError.superclass
+assert('NoMethodError#args', '15.2.32.2.1') do
+ a = NoMethodError.new 'test', :test, [1, 2]
+ assert_equal [1, 2], a.args
+
+ assert_nothing_raised do
+ begin
+ doesNotExistAsAMethodNameForVerySure 3, 1, 4
+ rescue NoMethodError => e
+ assert_equal [3, 1, 4], e.args
+ end
+ end
end
diff --git a/test/t/numeric.rb b/test/t/numeric.rb
index ef977da29..2b01611a7 100644
--- a/test/t/numeric.rb
+++ b/test/t/numeric.rb
@@ -5,10 +5,6 @@ assert('Numeric', '15.2.7') do
assert_equal Class, Numeric.class
end
-assert('Numeric superclass', '15.2.7.2') do
- assert_equal Object, Numeric.superclass
-end
-
assert('Numeric#+@', '15.2.7.4.1') do
assert_equal(+1, +1)
end
diff --git a/test/t/proc.rb b/test/t/proc.rb
index e871e637e..22ccceb68 100644
--- a/test/t/proc.rb
+++ b/test/t/proc.rb
@@ -5,10 +5,6 @@ assert('Proc', '15.2.17') do
assert_equal Class, Proc.class
end
-assert('Proc superclass', '15.2.17.2') do
- assert_equal Object, Proc.superclass
-end
-
assert('Proc.new', '15.2.17.3.1') do
assert_raise ArgumentError do
Proc.new
@@ -26,8 +22,8 @@ assert('Proc#[]', '15.2.17.4.1') do
b2 = Proc.new { |i| a2 += i }
b2.[](5)
- assert_equal a, 1
- assert_equal a2, 5
+ assert_equal 1, a
+ assert_equal 5, a2
end
assert('Proc#arity', '15.2.17.4.2') do
diff --git a/test/t/range.rb b/test/t/range.rb
index b35da40ab..278b26902 100644
--- a/test/t/range.rb
+++ b/test/t/range.rb
@@ -5,10 +5,6 @@ assert('Range', '15.2.14') do
assert_equal Class, Range.class
end
-assert('Range superclass', '15.2.14.2') do
- assert_equal Object, Range.superclass
-end
-
assert('Range#==', '15.2.14.4.1') do
assert_true (1..10) == (1..10)
assert_false (1..10) == (1..100)
diff --git a/test/t/rangeerror.rb b/test/t/rangeerror.rb
index 8dc683745..97878096e 100644
--- a/test/t/rangeerror.rb
+++ b/test/t/rangeerror.rb
@@ -4,7 +4,3 @@
assert('RangeError', '15.2.26') do
assert_equal Class, RangeError.class
end
-
-assert('RangeError superclass', '15.2.26.2') do
- assert_equal StandardError, RangeError.superclass
-end
diff --git a/test/t/standarderror.rb b/test/t/standarderror.rb
index cab99834e..c349b08cf 100644
--- a/test/t/standarderror.rb
+++ b/test/t/standarderror.rb
@@ -4,7 +4,3 @@
assert('StandardError', '15.2.23') do
assert_equal Class, StandardError.class
end
-
-assert('StandardError superclass', '15.2.23.2') do
- assert_equal Exception, StandardError.superclass
-end
diff --git a/test/t/string.rb b/test/t/string.rb
index 5ecb51530..c0e545e87 100644
--- a/test/t/string.rb
+++ b/test/t/string.rb
@@ -5,10 +5,6 @@ assert('String', '15.2.10') do
assert_equal Class, String.class
end
-assert('String superclass', '15.2.10.2') do
- assert_equal Object, String.superclass
-end
-
assert('String#<=>', '15.2.10.5.1') do
a = '' <=> ''
b = '' <=> 'not empty'
@@ -320,6 +316,13 @@ assert('String#replace', '15.2.10.5.28') do
b.replace(c);
c.replace(b);
assert_equal c, b
+
+ # shared string
+ s = "foo" * 100
+ a = s[10, 90] # create shared string
+ assert_equal("", s.replace("")) # clear
+ assert_equal("", s) # s is cleared
+ assert_not_equal("", a) # a should not be affected
end
assert('String#reverse', '15.2.10.5.29') do
diff --git a/test/t/superclass.rb b/test/t/superclass.rb
new file mode 100644
index 000000000..9fd8830b3
--- /dev/null
+++ b/test/t/superclass.rb
@@ -0,0 +1,46 @@
+[
+ # [:Object, :implementation_defined_value, '15.2.2.1'],
+ [:Module, :Object, '15.2.2.2'],
+ [:Class, :Module, '15.2.3.2'],
+ [:NilClass, :Object, '15.2.4.2'],
+ [:TrueClass, :Object, '15.2.5.2'],
+ [:FalseClass, :Object, '15.2.6.2'],
+ [:Numeric, :Object, '15.2.7.2'],
+ [:Integer, :Numeric, '15.2.8.2'],
+ [:Float, :Numeric, '15.2.9.2'],
+ [:String, :Object, '15.2.10.2'],
+ [:Symbol, :Object, '15.2.11.2'],
+ [:Array, :Object, '15.2.12.2'],
+ [:Hash, :Object, '15.2.13.2'],
+ [:Range, :Object, '15.2.14.2'],
+# [:Regexp, :Object, '15.2.15.2'], #No Regexp in mruby core
+# [:MatchData, :Object, '15.2.16.2'],
+ [:Proc, :Object, '15.2.17.2'],
+# [:Struct, :Object, '15.2.18.2'],
+# [:Time, :Object, '15.2.19.2'],
+# [:IO, :Object, '15.2.20.2'],
+# [:File, :IO, '15.2.21.2'],
+ [:Exception, :Object, '15.2.22.2'],
+ [:StandardError, :Exception, '15.2.23.2'],
+ [:ArgumentError, :StandardError, '15.2.24.2'],
+ [:LocalJumpError, :StandardError, '15.2.25.2'],
+ [:RangeError, :StandardError, '12.2.26.2'],
+ [:RegexpError, :StandardError, '12.2.27.2'],
+ [:RuntimeError, :StandardError, '12.2.28.2'],
+ [:TypeError, :StandardError, '12.2.29.2'],
+# [:ZeroDivisionError, :StandardError, '12.2.30.2'], # No ZeroDivisionError in mruby
+ [:NameError, :StandardError, '15.2.31.2'],
+ [:NoMethodError, :NameError, '15.2.32.2'],
+ [:IndexError, :StandardError, '15.2.33.2'],
+# [:IOError, :StandardError, '12.2.34.2'],
+# [:EOFError, :IOError, '12.2.35.2'],
+# [:SystemCallError, :StandardError, '15.2.36.2'],
+ [:ScriptError, :Exception, '12.2.37.2'],
+ [:SyntaxError, :ScriptError, '12.2.38.2'],
+# [:LoadError, :ScriptError, '12.2.39,2'],
+].each do |cls, super_cls, iso|
+ assert "Direct superclass of #{cls}", iso do
+ skip "#{cls} isn't defined" unless Object.const_defined? cls
+ assert_equal Object.const_get(super_cls), Object.const_get(cls).superclass
+ end
+end
diff --git a/test/t/symbol.rb b/test/t/symbol.rb
index f852dcd00..b0252849d 100644
--- a/test/t/symbol.rb
+++ b/test/t/symbol.rb
@@ -5,10 +5,6 @@ assert('Symbol', '15.2.11') do
assert_equal Class, Symbol.class
end
-assert('Symbol superclass', '15.2.11.2') do
- assert_equal Object, Symbol.superclass
-end
-
assert('Symbol#===', '15.2.11.3.1') do
assert_true :abc == :abc
assert_false :abc == :cba
diff --git a/test/t/true.rb b/test/t/true.rb
index e5da2112c..74f605ef0 100644
--- a/test/t/true.rb
+++ b/test/t/true.rb
@@ -11,10 +11,6 @@ assert('TrueClass true', '15.2.5.1') do
assert_false TrueClass.method_defined? :new
end
-assert('TrueClass superclass', '15.2.5.2') do
- assert_equal Object, TrueClass.superclass
-end
-
assert('TrueClass#&', '15.2.5.3.1') do
assert_true true.&(true)
assert_false true.&(false)
diff --git a/test/t/typeerror.rb b/test/t/typeerror.rb
index a91fb1be2..32536a74f 100644
--- a/test/t/typeerror.rb
+++ b/test/t/typeerror.rb
@@ -4,8 +4,3 @@
assert('TypeError', '15.2.29') do
assert_equal Class, TypeError.class
end
-
-assert('TypeError superclass', '15.2.29.2') do
- assert_equal StandardError, TypeError.superclass
-end
-
diff --git a/tools/mrbc/mrbc.c b/tools/mrbc/mrbc.c
index e5858e54a..52e762a50 100644
--- a/tools/mrbc/mrbc.c
+++ b/tools/mrbc/mrbc.c
@@ -270,7 +270,7 @@ main(int argc, char **argv)
fprintf(stderr, "%s: no program file given\n", args.prog);
return EXIT_FAILURE;
}
- if (args.outfile == NULL) {
+ if (args.outfile == NULL && !args.check_syntax) {
if (n + 1 == argc) {
args.outfile = get_outfilename(mrb, argv[n], args.initname ? C_EXT : RITEBIN_EXT);
}