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/mrbgems/README.md39
-rw-r--r--include/mruby.h17
-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.c44
-rw-r--r--mrbgems/mruby-array-ext/test/array.rb8
-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-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-sprintf/mrblib/string.rb9
-rw-r--r--mrbgems/mruby-sprintf/test/sprintf.rb9
-rw-r--r--mrbgems/mruby-string-ext/mrblib/string.rb93
-rw-r--r--mrbgems/mruby-string-ext/src/string.c66
-rw-r--r--mrbgems/mruby-string-ext/test/string.rb32
-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.c98
-rw-r--r--mrbgems/mruby-time/src/time.c2
-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.c4
-rw-r--r--src/hash.c3
-rw-r--r--src/init.c8
-rw-r--r--src/kernel.c2
-rw-r--r--src/mruby_core.rake4
-rw-r--r--src/parse.y50
-rw-r--r--src/state.c27
-rw-r--r--src/string.c301
-rw-r--r--src/vm.c6
-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/nomethoderror.rb13
-rw-r--r--test/t/string.rb7
-rw-r--r--tools/mrbc/mrbc.c2
57 files changed, 950 insertions, 464 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/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/mruby.h b/include/mruby.h
index c1f45bf0b..dcc01b2dd 100644
--- a/include/mruby.h
+++ b/include/mruby.h
@@ -102,6 +102,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 +169,12 @@ typedef struct mrb_state {
struct RClass *eException_class;
struct RClass *eStandardError_class;
+ struct RObject *nomem_err; /* pre-allocated NoMemoryError */
void *ud; /* auxiliary data */
+
+ mrb_atexit_func *atexit_stack;
+ mrb_int atexit_stack_len;
} mrb_state;
#if __STDC_VERSION__ >= 201112L
@@ -328,8 +334,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 +418,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 +429,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/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 014137e99..d69f0ac44 100644
--- a/mrbgems/mruby-array-ext/src/array.c
+++ b/mrbgems/mruby-array-ext/src/array.c
@@ -2,6 +2,7 @@
#include "mruby/value.h"
#include "mruby/array.h"
#include "mruby/range.h"
+#include "mruby/hash.h"
/*
* call-seq:
@@ -105,6 +106,48 @@ 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)
{
@@ -114,6 +157,7 @@ mrb_mruby_array_ext_gem_init(mrb_state* mrb)
mrb_define_method(mrb, a, "at", mrb_ary_at, MRB_ARGS_REQ(1));
mrb_define_method(mrb, a, "rassoc", mrb_ary_rassoc, MRB_ARGS_REQ(1));
mrb_define_method(mrb, a, "values_at", mrb_ary_values_at, MRB_ARGS_ANY());
+ mrb_define_method(mrb, a, "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 cb5652dde..8c919f7e0 100644
--- a/mrbgems/mruby-array-ext/test/array.rb
+++ b/mrbgems/mruby-array-ext/test/array.rb
@@ -285,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-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-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..1cfb7e2f5 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
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..72c919b35 100644
--- a/mrbgems/mruby-string-ext/test/string.rb
+++ b/mrbgems/mruby-string-ext/test/string.rb
@@ -161,3 +161,35 @@ 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
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 6894ffec9..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;
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/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 171f0858d..6eb9808e3 100644
--- a/src/gc.c
+++ b/src/gc.c
@@ -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 f6f2872ea..0258e5c15 100644
--- a/src/kernel.c
+++ b/src/kernel.c
@@ -1118,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 ab5caa28e..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;
@@ -2879,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) {
@@ -3381,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') {
@@ -3396,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);
}
@@ -3429,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) {
@@ -3785,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';
@@ -3915,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;
}
@@ -4100,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);
@@ -4135,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);
@@ -4209,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;
@@ -4247,7 +4247,6 @@ parser_yylex(parser_state *p)
return '=';
case '<':
- last_state = p->lstate;
c = nextc(p);
if (c == '<' &&
p->lstate != EXPR_DOT &&
@@ -4341,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) {
@@ -4378,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);
@@ -4542,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);
@@ -5164,7 +5163,6 @@ parser_yylex(parser_state *p)
{
int result = 0;
- last_state = p->lstate;
switch (tok(p)[0]) {
case '$':
p->lstate = EXPR_END;
@@ -5194,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 {
diff --git a/src/state.c b/src/state.c
index 9dd798f92..c0a9c14c2 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,13 @@ 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);
+ }
+ mrb_free(mrb, mrb->atexit_stack);
+ }
/* free */
mrb_gc_free_gv(mrb);
@@ -258,3 +264,18 @@ mrb_top_self(mrb_state *mrb)
}
return mrb_obj_value(mrb->top_self);
}
+
+void
+mrb_state_atexit(mrb_state *mrb, mrb_atexit_func f)
+{
+ 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);
+ }
+
+ mrb->atexit_stack[mrb->atexit_stack_len++] = f;
+}
diff --git a/src/string.c b/src/string.c
index 1572cab14..9b5707dc0 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;
@@ -913,8 +887,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 +944,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 +974,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 +992,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 +1043,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 +1101,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 +1151,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 +1180,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 +1189,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 +1221,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 +1367,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 +1488,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 +1498,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 +1542,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 +1565,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 +1603,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 +1706,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 +1801,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 +1810,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 +2025,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 +2051,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 +2171,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 +2265,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 +2312,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 +2491,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 +2507,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/vm.c b/src/vm.c
index d604e5d9e..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;
}
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/nomethoderror.rb b/test/t/nomethoderror.rb
index 561e545f9..709d31165 100644
--- a/test/t/nomethoderror.rb
+++ b/test/t/nomethoderror.rb
@@ -11,3 +11,16 @@ end
assert('NoMethodError superclass', '15.2.32.2') do
assert_equal NameError, NoMethodError.superclass
end
+
+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/string.rb b/test/t/string.rb
index 5ecb51530..00e98f671 100644
--- a/test/t/string.rb
+++ b/test/t/string.rb
@@ -320,6 +320,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/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);
}