diff --git a/.github/labeler.yml b/.github/labeler.yml index 742fc2b3f..bdd33ca72 100644 --- a/.github/labeler.yml +++ b/.github/labeler.yml @@ -7,11 +7,17 @@ build: - any: - changed-files: - any-glob-to-any-file: + - Dockerfile - Makefile - Rakefile + - appveyor.yml + - build_config.rb - build_config/**/* + - docker-compose.yml - lib/**/* + - minirake - tasks/**/* + - .travis.yml core: - any: - changed-files: diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index b95005f2d..6f92b31d5 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -19,7 +19,7 @@ jobs: pip install pre-commit - name: Set PY run: echo "PY=$(python -VV | sha256sum | cut -d' ' -f1)" >> $GITHUB_ENV - - uses: actions/cache@v3 + - uses: actions/cache@v4 with: path: ~/.cache/pre-commit key: pre-commit|${{ env.PY }}|${{ hashFiles('.pre-commit-config.yaml') }} diff --git a/.github/workflows/super-linter.yml b/.github/workflows/super-linter.yml index d250a7f98..054b12f14 100644 --- a/.github/workflows/super-linter.yml +++ b/.github/workflows/super-linter.yml @@ -20,9 +20,8 @@ jobs: # Full git history is needed to get a proper list of changed files within `super-linter` fetch-depth: 0 - name: Lint Code Base - uses: super-linter/super-linter/slim@v5.7.2 + uses: super-linter/super-linter/slim@v6.0.0 env: - ERROR_ON_MISSING_EXEC_BIT: true VALIDATE_BASH: true # VALIDATE_BASH_EXEC: true # VALIDATE_EDITORCONFIG: true diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index d344920fd..4f8b9c48e 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -20,6 +20,8 @@ repos: - id: check-shebang-scripts-are-executable - id: check-vcs-permalinks - id: check-yaml + - id: detect-aws-credentials + args: [--allow-missing-credentials] - id: detect-private-key - id: end-of-file-fixer - id: file-contents-sorter diff --git a/AUTHORS b/AUTHORS index d21c88a0c..3464d3671 100644 --- a/AUTHORS +++ b/AUTHORS @@ -1,10 +1,10 @@ # Authors of mruby (mruby developers) -## The List of Contributors sorted by number of commits (as of 2023-12-28 67cb987) +## The List of Contributors sorted by number of commits (as of 2024-02-10 d2af9da) - 9477 Yukihiro "Matz" Matsumoto (@matz)* + 9592 Yukihiro "Matz" Matsumoto (@matz)* 586 KOBAYASHI Shuji (@shuujii) - 533 dearblue (@dearblue)* + 547 dearblue (@dearblue)* 378 Daniel Bovensiepen (@bovi)* 346 Takeshi Watanabe (@take-cheeze)* 334 Masaki Muranaka (@monaka) @@ -12,7 +12,7 @@ 234 Jun Hiroe (@suzukaze) 220 Cremno (@cremno)* 209 Yuki Kurihara (@ksss)+ - 166 John Bampton (@jbampton) + 170 John Bampton (@jbampton) 151 Yasuhiro Matsumoto (@mattn)* 113 Carson McDonald (@carsonmcdonald) 103 Tomasz Dąbrowski (@dabroz)* @@ -156,6 +156,7 @@ 3 bamchoh (@bamchoh) 3 sasaki takeru (@takeru) 3 windwiny (@windwiny) + 3 星湖新 (@hoshiumiarata) 2 Akira Moroo (@retrage) 2 Artur K (@nemerle) 2 Christian Mauceri (@mauceri) @@ -290,6 +291,7 @@ 1 Yusuke Tanaka (@csouls) 1 alpha.netzilla (@alpha-netzilla) 1 arton (@arton) + 1 buty4649 (@buty4649) 1 duangsuse (@duangsuse) 1 fl0l0u (@fl0l0u) 1 hhc0null (@hhc0null) diff --git a/LEGAL b/LEGAL index 24c8dc670..116a218f6 100644 --- a/LEGAL +++ b/LEGAL @@ -4,10 +4,41 @@ LEGAL NOTICE INFORMATION All the files in this distribution are covered under the MIT license (see the file LICENSE) except some files mentioned below: +- src/string.c: mrb_memsearch_ss() is based on 2 clause BSD license code by Wojciech Muła (@WojciechMula) - src/readfloat.c: public domain by Yasuhiro Matsumoto (@mattn) - src/fmt_fp.c: public domain by Dave Hylands (@dhylands) - mrbgems/mruby-dir/src/Win/dirent.c: MIT-like license by Kevlin Henney +[src/string.c] +The implementation of mrb_memsearch_ss() is taken from +https://github.com/WojciechMula/sse4-strstr.git + +Copyright (c) 2008-2016, Wojciech Muła +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + +1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS +IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED +TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A +PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED +TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + [src/readfloat.c] strtod implementation. diff --git a/include/mruby.h b/include/mruby.h index 4048edf69..828bb9d2e 100644 --- a/include/mruby.h +++ b/include/mruby.h @@ -798,6 +798,8 @@ MRB_API struct RClass * mrb_module_get_under_id(mrb_state *mrb, struct RClass *o MRB_API void mrb_notimplement(mrb_state*); /* a function to be replacement of unimplemented method */ MRB_API mrb_value mrb_notimplement_m(mrb_state*, mrb_value); +/* just return it self */ +MRB_API mrb_value mrb_obj_itself(mrb_state*, mrb_value); /** * Duplicate an object. diff --git a/include/mruby/error.h b/include/mruby/error.h index ee6fe8ffc..e8c63dc3e 100644 --- a/include/mruby/error.h +++ b/include/mruby/error.h @@ -17,8 +17,8 @@ MRB_BEGIN_DECL struct RException { MRB_OBJECT_HEADER; struct iv_tbl *iv; - struct RObject *mesg; // NULL or probably RString - struct RObject *backtrace; // NULL, RArray or RData + struct RBasic *mesg; // NULL or probably RString + struct RBasic *backtrace; // NULL, RArray or RData }; /* error that should terminate execution */ diff --git a/include/mruby/internal.h b/include/mruby/internal.h index 37c6fa1f0..a2948961a 100644 --- a/include/mruby/internal.h +++ b/include/mruby/internal.h @@ -61,6 +61,18 @@ mrb_value mrb_exc_mesg_get(mrb_state *mrb, struct RException *exc); mrb_value mrb_f_raise(mrb_state*, mrb_value); mrb_value mrb_make_exception(mrb_state *mrb, mrb_value exc, mrb_value mesg); +struct RBacktrace { + MRB_OBJECT_HEADER; + size_t len; + struct mrb_backtrace_location *locations; +}; + +struct mrb_backtrace_location { + mrb_sym method_id; + int32_t idx; + const mrb_irep *irep; +}; + /* gc */ void mrb_gc_mark_mt(mrb_state*, struct RClass*); size_t mrb_gc_mark_mt_size(mrb_state*, struct RClass*); diff --git a/include/mruby/string.h b/include/mruby/string.h index cd300f8bd..ac6740c5d 100644 --- a/include/mruby/string.h +++ b/include/mruby/string.h @@ -79,18 +79,19 @@ struct RStringEmbed { #define RSTR_UNSET_NOFREE_FLAG(s) ((s)->flags &= ~MRB_STR_NOFREE) #ifdef MRB_UTF8_STRING -# define RSTR_ASCII_P(s) ((s)->flags & MRB_STR_ASCII) -# define RSTR_SET_ASCII_FLAG(s) ((s)->flags |= MRB_STR_ASCII) -# define RSTR_UNSET_ASCII_FLAG(s) ((s)->flags &= ~MRB_STR_ASCII) -# define RSTR_WRITE_ASCII_FLAG(s, v) (RSTR_UNSET_ASCII_FLAG(s), (s)->flags |= v) -# define RSTR_COPY_ASCII_FLAG(dst, src) RSTR_WRITE_ASCII_FLAG(dst, RSTR_ASCII_P(src)) +# define RSTR_SINGLE_BYTE_P(s) ((s)->flags & MRB_STR_SINGLE_BYTE) +# define RSTR_SET_SINGLE_BYTE_FLAG(s) ((s)->flags |= MRB_STR_SINGLE_BYTE) +# define RSTR_UNSET_SINGLE_BYTE_FLAG(s) ((s)->flags &= ~MRB_STR_SINGLE_BYTE) +# define RSTR_WRITE_SINGLE_BYTE_FLAG(s, v) (RSTR_UNSET_SINGLE_BYTE_FLAG(s), (s)->flags |= v) +# define RSTR_COPY_SINGLE_BYTE_FLAG(dst, src) RSTR_WRITE_SINGLE_BYTE_FLAG(dst, RSTR_SINGLE_BYTE_P(src)) #else -# define RSTR_ASCII_P(s) (void)0 -# define RSTR_SET_ASCII_FLAG(s) (void)0 -# define RSTR_UNSET_ASCII_FLAG(s) (void)0 -# define RSTR_WRITE_ASCII_FLAG(s, v) (void)0 -# define RSTR_COPY_ASCII_FLAG(dst, src) (void)0 +# define RSTR_SINGLE_BYTE_P(s) (void)1 +# define RSTR_SET_SINGLE_BYTE_FLAG(s) (void)0 +# define RSTR_UNSET_SINGLE_BYTE_FLAG(s) (void)0 +# define RSTR_WRITE_SINGLE_BYTE_FLAG(s, v) (void)0 +# define RSTR_COPY_SINGLE_BYTE_FLAG(dst, src) (void)0 #endif +#define RSTR_SET_ASCII_FLAG(s) RSTR_SET_SINGLE_BYTE_FLAG(s) /** * Returns a pointer from a Ruby string @@ -108,7 +109,7 @@ struct RStringEmbed { #define MRB_STR_FSHARED 2 #define MRB_STR_NOFREE 4 #define MRB_STR_EMBED 8 /* type flags up to here */ -#define MRB_STR_ASCII 16 +#define MRB_STR_SINGLE_BYTE 16 #define MRB_STR_EMBED_LEN_SHIFT 6 #define MRB_STR_EMBED_LEN_BIT 5 #define MRB_STR_EMBED_LEN_MASK (((1 << MRB_STR_EMBED_LEN_BIT) - 1) << MRB_STR_EMBED_LEN_SHIFT) diff --git a/include/mruby/value.h b/include/mruby/value.h index 71cdaca35..16da2cbd4 100644 --- a/include/mruby/value.h +++ b/include/mruby/value.h @@ -159,7 +159,8 @@ static const unsigned int IEEE754_INFINITY_BITS_SINGLE = 0x7F800000; f(MRB_TT_BREAK, struct RBreak, "break") \ f(MRB_TT_COMPLEX, struct RComplex, "Complex") \ f(MRB_TT_RATIONAL, struct RRational, "Rational") \ - f(MRB_TT_BIGINT, struct RBigint, "Integer") + f(MRB_TT_BIGINT, struct RBigint, "Integer") \ + f(MRB_TT_BACKTRACE, struct RBacktrace, "backtrace") enum mrb_vtype { #define MRB_VTYPE_DEFINE(tt, type, name) tt, diff --git a/lib/mruby/gem.rb b/lib/mruby/gem.rb index 35aa2bd52..a2b649d71 100644 --- a/lib/mruby/gem.rb +++ b/lib/mruby/gem.rb @@ -372,6 +372,7 @@ module MRuby def each(&b) @ary.each(&b) + self end def [](name) @@ -384,6 +385,7 @@ module MRuby else # GEM was already added to this list end + self end def empty? diff --git a/mrbgems/mruby-bigint/core/bigint.c b/mrbgems/mruby-bigint/core/bigint.c index 97f545473..8877ab7e7 100644 --- a/mrbgems/mruby-bigint/core/bigint.c +++ b/mrbgems/mruby-bigint/core/bigint.c @@ -478,7 +478,6 @@ udiv(mrb_state *mrb, mpz_t *qq, mpz_t *rr, mpz_t *xx, mpz_t *yy) } mpz_t q, x, y; - size_t i; mrb_assert(!uzero(yy)); /* divided by zero */ mpz_init(mrb, &q); @@ -502,6 +501,8 @@ udiv(mrb_state *mrb, mpz_t *qq, mpz_t *rr, mpz_t *xx, mpz_t *yy) else qhat = (((mp_dbl_limb)x.p[j+yd] << DIG_SIZE) + x.p[j+yd-1]) / z; if (qhat) { + size_t i; + for (i=0; i= b; rn++) x *= bi; @@ -1119,7 +1119,7 @@ mrb_bint_new_float(mrb_state *mrb, mrb_float x) mpz_realloc(mrb, r, rn); rp = r->p; for (size_t i=rn-1;;i--) { - f = LOW((mp_limb)x); + mp_limb f = LOW((mp_limb)x); x -= f; mrb_assert(x < 1.0); rp[i] = f; diff --git a/mrbgems/mruby-bin-mruby/tools/mruby/mruby.c b/mrbgems/mruby-bin-mruby/tools/mruby/mruby.c index 10522011a..bf201deda 100644 --- a/mrbgems/mruby-bin-mruby/tools/mruby/mruby.c +++ b/mrbgems/mruby-bin-mruby/tools/mruby/mruby.c @@ -98,8 +98,8 @@ options_opt(struct options *opts) while (++opts->argv, --opts->argc) { opts->opt = *opts->argv; - /* empty || not start with `-` || `-` */ - if (!opts->opt[0] || opts->opt[0] != '-' || !opts->opt[1]) return NULL; + /* not start with `-` || `-` */ + if (opts->opt[0] != '-' || !opts->opt[1]) return NULL; if (opts->opt[1] == '-') { /* `--` */ @@ -278,10 +278,8 @@ main(int argc, char **argv) { mrb_state *mrb = mrb_open(); int n = -1; - int i; struct _args args; mrb_value ARGV; - mrb_ccontext *c; mrb_value v; if (mrb == NULL) { @@ -297,7 +295,7 @@ main(int argc, char **argv) else { int ai = mrb_gc_arena_save(mrb); ARGV = mrb_ary_new_capa(mrb, args.argc); - for (i = 0; i < args.argc; i++) { + for (int i = 0; i < args.argc; i++) { char* utf8 = mrb_utf8_from_locale(args.argv[i], -1); if (utf8) { mrb_ary_push(mrb, ARGV, mrb_str_new_cstr(mrb, utf8)); @@ -307,7 +305,7 @@ main(int argc, char **argv) mrb_define_global_const(mrb, "ARGV", ARGV); mrb_gv_set(mrb, mrb_intern_lit(mrb, "$DEBUG"), mrb_bool_value(args.debug)); - c = mrb_ccontext_new(mrb); + mrb_ccontext *c = mrb_ccontext_new(mrb); if (args.verbose) c->dump_result = TRUE; if (args.check_syntax) @@ -324,7 +322,7 @@ main(int argc, char **argv) mrb_gv_set(mrb, mrb_intern_lit(mrb, "$0"), mrb_str_new_cstr(mrb, cmdline)); /* Load libraries */ - for (i = 0; i < args.libc; i++) { + for (int i = 0; i < args.libc; i++) { FILE *lfp = fopen(args.libv[i], "rb"); if (lfp == NULL) { fprintf(stderr, "%s: Cannot open library file: %s\n", *argv, args.libv[i]); @@ -334,10 +332,10 @@ main(int argc, char **argv) } mrb_ccontext_filename(mrb, c, args.libv[i]); if (mrb_extension_p(args.libv[i])) { - v = mrb_load_irep_file_cxt(mrb, lfp, c); + mrb_load_irep_file_cxt(mrb, lfp, c); } else { - v = mrb_load_detect_file_cxt(mrb, lfp, c); + mrb_load_detect_file_cxt(mrb, lfp, c); } fclose(lfp); mrb_vm_ci_env_clear(mrb, mrb->c->cibase); diff --git a/mrbgems/mruby-complex/src/complex.c b/mrbgems/mruby-complex/src/complex.c index a2c579058..8aad4c000 100644 --- a/mrbgems/mruby-complex/src/complex.c +++ b/mrbgems/mruby-complex/src/complex.c @@ -149,12 +149,6 @@ mrb_complex_to_i(mrb_state *mrb, mrb_value self) return mrb_int_value(mrb, (mrb_int)p->real); } -static mrb_value -complex_to_c(mrb_state *mrb, mrb_value self) -{ - return self; -} - mrb_bool mrb_complex_eq(mrb_state *mrb, mrb_value x, mrb_value y) { @@ -406,7 +400,7 @@ void mrb_mruby_complex_gem_init(mrb_state *mrb) mrb_define_method(mrb, comp, "imaginary", complex_imaginary, MRB_ARGS_NONE()); mrb_define_method(mrb, comp, "to_f", mrb_complex_to_f, MRB_ARGS_NONE()); mrb_define_method(mrb, comp, "to_i", mrb_complex_to_i, MRB_ARGS_NONE()); - mrb_define_method(mrb, comp, "to_c", complex_to_c, MRB_ARGS_NONE()); + mrb_define_method(mrb, comp, "to_c", mrb_obj_itself, MRB_ARGS_NONE()); mrb_define_method(mrb, comp, "+", complex_add, MRB_ARGS_REQ(1)); mrb_define_method(mrb, comp, "-", complex_sub, MRB_ARGS_REQ(1)); mrb_define_method(mrb, comp, "*", complex_mul, MRB_ARGS_REQ(1)); diff --git a/mrbgems/mruby-enum-ext/mrblib/enum.rb b/mrbgems/mruby-enum-ext/mrblib/enum.rb index 2c9e8d3a5..28562a1b9 100644 --- a/mrbgems/mruby-enum-ext/mrblib/enum.rb +++ b/mrbgems/mruby-enum-ext/mrblib/enum.rb @@ -840,6 +840,17 @@ module Enumerable alias filter select + def grep_v(pattern, &block) + ary = [] + self.each{|*val| + sv = val.__svalue + unless pattern === sv + ary.push((block)? block.call(*val): sv) + end + } + ary + end + ## # call-seq: # enum.tally -> a_hash diff --git a/mrbgems/mruby-enum-ext/test/enum.rb b/mrbgems/mruby-enum-ext/test/enum.rb index 31181fe1a..98ace670e 100644 --- a/mrbgems/mruby-enum-ext/test/enum.rb +++ b/mrbgems/mruby-enum-ext/test/enum.rb @@ -195,3 +195,10 @@ end assert("Enumerable#tally") do assert_equal({"a"=>1, "b"=>2, "c"=>1}, ["a", "b", "c", "b"].tally) end + +assert("Enumerable#grep_v") do + a = [1, 2, 3, 4, 5, 0] + assert_equal [1, 5, 0], a.grep_v(2..4) + assert_equal [1, 2, 3, 4, 5, 0], a.grep_v(6..8) + assert_equal [2, 4, 6, 8, 10], a.grep_v(0) {|v| v * 2} +end diff --git a/mrbgems/mruby-enumerator/mrblib/enumerator.rb b/mrbgems/mruby-enumerator/mrblib/enumerator.rb index faaabf18a..44d84865a 100644 --- a/mrbgems/mruby-enumerator/mrblib/enumerator.rb +++ b/mrbgems/mruby-enumerator/mrblib/enumerator.rb @@ -701,4 +701,72 @@ module Enumerable result end + + ## + # call-seq: + # enum.chunk -> enumerator + # enum.chunk { |arr| block } -> enumerator + # + # Each element in the returned enumerator is a 2-element array consisting of: + # + # - A value returned by the block. + # - An array ("chunk") containing the element for which that value was returned, + # and all following elements for which the block returned the same value: + # + # So that: + # + # - Each block return value that is different from its predecessor + # begins a new chunk. + # - Each block return value that is the same as its predecessor + # continues the same chunk. + # + # Example: + # + # e = (0..10).chunk {|i| (i / 3).floor } # => # + # # The enumerator elements. + # e.next # => [0, [0, 1, 2]] + # e.next # => [1, [3, 4, 5]] + # e.next # => [2, [6, 7, 8]] + # e.next # => [3, [9, 10]] + # + # You can use the special symbol :_alone to force an element + # into its own separate chuck: + # + # a = [0, 0, 1, 1] + # e = a.chunk{|i| i.even? ? :_alone : true } + # e.to_a # => [[:_alone, [0]], [:_alone, [0]], [true, [1, 1]]] + # + # You can use the special symbol :_separator or +nil+ + # to force an element to be ignored (not included in any chunk): + # + # a = [0, 0, -1, 1, 1] + # e = a.chunk{|i| i < 0 ? :_separator : true } + # e.to_a # => [[true, [0, 0]], [true, [1, 1]]] + def chunk(&block) + return to_enum :chunk unless block + + enum = self + Enumerator.new do |y| + last_value, arr = nil, [] + enum.each do |element| + value = block.call(element) + case value + when :_alone + y.yield [last_value, arr] if arr.size > 0 + y.yield [value, [element]] + last_value, arr = nil, [] + when :_separator, nil + y.yield [last_value, arr] if arr.size > 0 + last_value, arr = nil, [] + when last_value + arr << element + else + raise 'symbols beginning with an underscore are reserved' if value.is_a?(Symbol) && value.to_s[0] == '_' + y.yield [last_value, arr] if arr.size > 0 + last_value, arr = value, [element] + end + end + y.yield [last_value, arr] if arr.size > 0 + end + end end diff --git a/mrbgems/mruby-enumerator/test/enumerator.rb b/mrbgems/mruby-enumerator/test/enumerator.rb index 3e0c6c3be..4baf20c25 100644 --- a/mrbgems/mruby-enumerator/test/enumerator.rb +++ b/mrbgems/mruby-enumerator/test/enumerator.rb @@ -598,3 +598,52 @@ assert 'Enumerator.produce' do ], enum.to_a } end + +assert("Enumerable#chunk") do + chunk = [1, 2, 3, 1, 2].chunk + assert_equal Enumerator, chunk.class + result = chunk.with_index { |elt, i| elt - i }.to_a + assert_equal [[1, [1, 2, 3]], [-2, [1, 2]]], result + + assert_equal Enumerator, [].chunk {}.class + + e = [1, 2, 3] + recorded = [] + e.chunk { |x| recorded << x }.to_a + assert_equal [1, 2, 3], recorded + + e = [1, 2, 3, 2, 3, 2, 1] + result = e.chunk { |x| x < 3 && 1 || 0 }.to_a + assert_equal [[1, [1, 2]], [0, [3]], [1, [2]], [0, [3]], [1, [2, 1]]], result + + e = [1, 2, 3] + assert_equal [[1, 2], [3]], e.chunk { |x| x > 2 }.map(&:last) + + e = [1, 2, 3, 2, 1] + result = e.chunk { |x| x < 2 && :_alone }.to_a + assert_equal [[:_alone, [1]], [false, [2, 3, 2]], [:_alone, [1]]], result + + e = [[1, 2]] + inner_value = [] + e.chunk { |*x| inner_value << x }.to_a + assert_equal [[[1, 2]]], inner_value + + e = [1, 2, 3, 3, 2, 1] + result = e.chunk { |x| x == 2 ? :_separator : 1 }.to_a + assert_equal [[1, [1]], [1, [3, 3]], [1, [1]]], result + + e = [1, 2, 3, 2, 1] + result = e.chunk { |x| x == 2 ? nil : 1 }.to_a + assert_equal [[1, [1]], [1, [3]], [1, [1]]], result + + + e = [1, 2, 3, 2, 1] + assert_raise(RuntimeError) { e.chunk { |x| :_arbitrary }.to_a } + + e = [1, 2, 3] + assert_raise(ArgumentError) { e.chunk(1) {} } + + e = [1, 2, 3, 2, 1] + enum = e.chunk { |x| true } + assert_nil enum.size +end diff --git a/mrbgems/mruby-errno/src/errno.c b/mrbgems/mruby-errno/src/errno.c index b2059f465..71ab61e25 100644 --- a/mrbgems/mruby-errno/src/errno.c +++ b/mrbgems/mruby-errno/src/errno.c @@ -288,7 +288,6 @@ mrb_sce_sys_fail(mrb_state *mrb, mrb_value cls) if (argc == 1) { msg = mrb_nil_value(); } - exc = mrb_obj_value(e); mrb_sce_init(mrb, exc, msg, no); mrb_exc_raise(mrb, exc); return mrb_nil_value(); /* NOTREACHED */ diff --git a/mrbgems/mruby-eval/src/eval.c b/mrbgems/mruby-eval/src/eval.c index fe1645822..db9b439bd 100644 --- a/mrbgems/mruby-eval/src/eval.c +++ b/mrbgems/mruby-eval/src/eval.c @@ -344,8 +344,8 @@ mrb_mruby_eval_gem_init(mrb_state* mrb) { mrb_define_module_function(mrb, mrb->kernel_module, "eval", f_eval, MRB_ARGS_ARG(1, 3)); mrb_define_method_id(mrb, mrb_class_get_id(mrb, MRB_SYM(BasicObject)), MRB_SYM(instance_eval), f_instance_eval, MRB_ARGS_OPT(3)|MRB_ARGS_BLOCK()); - mrb_define_method_id(mrb, mrb_class_get_id(mrb, MRB_SYM(Module)), MRB_SYM(module_eval), f_class_eval, MRB_ARGS_OPT(3)|MRB_ARGS_BLOCK()); - mrb_define_method_id(mrb, mrb_class_get_id(mrb, MRB_SYM(Module)), MRB_SYM(class_eval), f_class_eval, MRB_ARGS_OPT(3)|MRB_ARGS_BLOCK()); + mrb_define_method_id(mrb, mrb->module_class, MRB_SYM(module_eval), f_class_eval, MRB_ARGS_OPT(3)|MRB_ARGS_BLOCK()); + mrb_define_method_id(mrb, mrb->module_class, MRB_SYM(class_eval), f_class_eval, MRB_ARGS_OPT(3)|MRB_ARGS_BLOCK()); struct RClass *binding = mrb_class_get_id(mrb, MRB_SYM(Binding)); mrb_define_method(mrb, binding, "eval", mrb_binding_eval, MRB_ARGS_ANY()); diff --git a/mrbgems/mruby-fiber/src/fiber.c b/mrbgems/mruby-fiber/src/fiber.c index baddf65ce..c0fd4d751 100644 --- a/mrbgems/mruby-fiber/src/fiber.c +++ b/mrbgems/mruby-fiber/src/fiber.c @@ -43,12 +43,12 @@ fiber_init_fiber(mrb_state *mrb, struct RFiber *f, const struct RProc *p) c->stend = c->stbase + slen; { - mrb_value *p = c->stbase; - mrb_value *pend = c->stend; + mrb_value *s = c->stbase; + mrb_value *send = c->stend; - while (p < pend) { - SET_NIL_VALUE(*p); - p++; + while (s < send) { + SET_NIL_VALUE(*s); + s++; } } @@ -252,8 +252,6 @@ fiber_switch(mrb_state *mrb, mrb_value self, mrb_int len, const mrb_value *a, mr } fiber_switch_context(mrb, c); if (status == MRB_FIBER_CREATED) { - mrb_value *b, *e; - if (!c->ci->proc) { return fiber_error(mrb, "double resume (current)"); } @@ -267,8 +265,10 @@ fiber_switch(mrb_state *mrb, mrb_value self, mrb_int len, const mrb_value *a, mr } else { mrb_stack_extend(mrb, len+2); /* for receiver and (optional) block */ - b = c->stbase+1; - e = b + len; + + mrb_value *b = c->stbase+1; + mrb_value *e = b + len; + while (b +#include #ifdef MRB_NO_STDIO # error IO and File conflicts 'MRB_NO_STDIO' in your build configuration @@ -63,8 +64,8 @@ struct mrb_io { #define MRB_O_DSYNC 0x00008000 #define MRB_O_RSYNC 0x00010000 -#define E_IO_ERROR (mrb_exc_get(mrb, "IOError")) -#define E_EOF_ERROR (mrb_exc_get(mrb, "EOFError")) +#define E_IO_ERROR mrb_exc_get_id(mrb, MRB_SYM(IOError)) +#define E_EOF_ERROR mrb_exc_get_id(mrb, MRB_SYM(EOFError)) int mrb_io_fileno(mrb_state *mrb, mrb_value io); diff --git a/mrbgems/mruby-io/src/file.c b/mrbgems/mruby-io/src/file.c index 2bfef3030..4116d4777 100644 --- a/mrbgems/mruby-io/src/file.c +++ b/mrbgems/mruby-io/src/file.c @@ -120,15 +120,13 @@ mrb_file_s_unlink(mrb_state *mrb, mrb_value obj) { const mrb_value *argv; mrb_int argc, i; - char *path; mrb_get_args(mrb, "*", &argv, &argc); for (i = 0; i < argc; i++) { - const char *utf8_path; mrb_value pathv = argv[i]; mrb_ensure_string_type(mrb, pathv); - utf8_path = RSTRING_CSTR(mrb, pathv); - path = mrb_locale_from_utf8(utf8_path, -1); + const char *utf8_path = RSTRING_CSTR(mrb, pathv); + char *path = mrb_locale_from_utf8(utf8_path, -1); if (UNLINK(path) < 0) { mrb_locale_free(path); mrb_sys_fail(mrb, utf8_path); diff --git a/mrbgems/mruby-io/src/io.c b/mrbgems/mruby-io/src/io.c index 1767f66ba..265716cdf 100644 --- a/mrbgems/mruby-io/src/io.c +++ b/mrbgems/mruby-io/src/io.c @@ -102,12 +102,11 @@ io_get_open_fptr(mrb_state *mrb, mrb_value io) static void io_set_process_status(mrb_state *mrb, pid_t pid, int status) { - struct RClass *c_process, *c_status; + struct RClass *c_status = NULL; mrb_value v; - c_status = NULL; if (mrb_class_defined_id(mrb, MRB_SYM(Process))) { - c_process = mrb_module_get_id(mrb, MRB_SYM(Process)); + struct RClass *c_process = mrb_module_get_id(mrb, MRB_SYM(Process)); if (mrb_const_defined(mrb, mrb_obj_value(c_process), MRB_SYM(Status))) { c_status = mrb_class_get_under_id(mrb, c_process, MRB_SYM(Status)); } @@ -522,8 +521,6 @@ io_s_popen(mrb_state *mrb, mrb_value klass) } if (!doexec) { - // XXX - fflush(stdin); fflush(stdout); fflush(stderr); } @@ -1223,26 +1220,22 @@ time2timeval(mrb_state *mrb, mrb_value time) static mrb_value io_s_pipe(mrb_state *mrb, mrb_value klass) { - mrb_value r = mrb_nil_value(); - mrb_value w = mrb_nil_value(); - struct mrb_io *fptr_r; - struct mrb_io *fptr_w; int pipes[2]; if (io_pipe(mrb, pipes) == -1) { mrb_sys_fail(mrb, "pipe"); } - r = mrb_obj_value(mrb_data_object_alloc(mrb, mrb_class_ptr(klass), NULL, &mrb_io_type)); - fptr_r = io_alloc(mrb); + mrb_value r = mrb_obj_value(mrb_data_object_alloc(mrb, mrb_class_ptr(klass), NULL, &mrb_io_type)); + struct mrb_io *fptr_r = io_alloc(mrb); fptr_r->fd = pipes[0]; fptr_r->readable = 1; DATA_TYPE(r) = &mrb_io_type; DATA_PTR(r) = fptr_r; io_init_buf(mrb, fptr_r); - w = mrb_obj_value(mrb_data_object_alloc(mrb, mrb_class_ptr(klass), NULL, &mrb_io_type)); - fptr_w = io_alloc(mrb); + mrb_value w = mrb_obj_value(mrb_data_object_alloc(mrb, mrb_class_ptr(klass), NULL, &mrb_io_type)); + struct mrb_io *fptr_w = io_alloc(mrb); fptr_w->fd = pipes[1]; fptr_w->writable = 1; fptr_w->sync = 1; diff --git a/mrbgems/mruby-kernel-ext/src/kernel.c b/mrbgems/mruby-kernel-ext/src/kernel.c index 89116f63a..6bdcc9469 100644 --- a/mrbgems/mruby-kernel-ext/src/kernel.c +++ b/mrbgems/mruby-kernel-ext/src/kernel.c @@ -59,7 +59,7 @@ mrb_f_caller(mrb_state *mrb, mrb_value self) if (n < 0) { mrb_raisef(mrb, E_ARGUMENT_ERROR, "negative size (%d)", n); } - if (n == 0 || bt_len <= lev) { + if (n == 0) { return mrb_ary_new(mrb); } if (bt_len <= n + lev) n = bt_len - lev - 1; diff --git a/mrbgems/mruby-math/src/math.c b/mrbgems/mruby-math/src/math.c index 75f0a2202..0d2f4cc48 100644 --- a/mrbgems/mruby-math/src/math.c +++ b/mrbgems/mruby-math/src/math.c @@ -74,7 +74,7 @@ atanh(double x) } else { /* Basic formula for atanh */ - y = 0.5 * (log(1.0+x) - log(1.0-x)); + y = 0.5 * (log1p(x) - log1p(-x)); } return y; @@ -105,7 +105,7 @@ double erfc(double x); double erf(double x) { - static const double two_sqrtpi = 1.128379167095512574; + static const double two_sqrtpi = 1.128379167095512574; double sum = x; double term = x; double xsqr = x*x; @@ -129,7 +129,7 @@ erf(double x) double erfc(double x) { - static const double one_sqrtpi= 0.564189583547756287; + static const double one_sqrtpi = 0.564189583547756287; double a = 1; double b = x; double c = x; @@ -137,15 +137,15 @@ erfc(double x) double q1; double q2 = b/d; double n = 1.0; - double t; + if (fabs(x) < 2.2) { - return 1.0 - erf(x); + return erfc(x); } if (x < 0.0) { /*signbit(x)*/ return 2.0 - erfc(-x); } do { - t = a*n+b*x; + double t = a*n+b*x; a = b; b = t; t = c*n+d*x; diff --git a/mrbgems/mruby-metaprog/src/metaprog.c b/mrbgems/mruby-metaprog/src/metaprog.c index 3b93574c1..f1fe097c7 100644 --- a/mrbgems/mruby-metaprog/src/metaprog.c +++ b/mrbgems/mruby-metaprog/src/metaprog.c @@ -176,7 +176,6 @@ static mrb_value mrb_class_instance_method_list(mrb_state *mrb, mrb_bool recur, struct RClass *klass) { mrb_value ary; - struct RClass *oldklass; khash_t(st) *set = kh_init(st, mrb); if (!recur) { @@ -187,8 +186,8 @@ mrb_class_instance_method_list(mrb_state *mrb, mrb_bool recur, struct RClass *kl } else { khash_t(st) *undef = kh_init(st, mrb); + struct RClass *oldklass = NULL; - oldklass = NULL; while (klass && (klass != oldklass)) { method_entry_loop(mrb, klass, set, undef); oldklass = klass; diff --git a/mrbgems/mruby-numeric-ext/src/numeric_ext.c b/mrbgems/mruby-numeric-ext/src/numeric_ext.c index 4833f05fd..097a902f3 100644 --- a/mrbgems/mruby-numeric-ext/src/numeric_ext.c +++ b/mrbgems/mruby-numeric-ext/src/numeric_ext.c @@ -165,8 +165,7 @@ int_digits(mrb_state *mrb, mrb_value self) } while (mrb_bint_cmp(mrb, x, zero) > 0) { - mrb_value q = mrb_bint_mod(mrb, x, bv); - mrb_ary_push(mrb, digits, q); + mrb_ary_push(mrb, digits, mrb_bint_mod(mrb, x, bv)); x = mrb_bint_div(mrb, x, bv); if (!mrb_bigint_p(x)) { mrb_int n = mrb_integer(x); diff --git a/mrbgems/mruby-object-ext/src/object.c b/mrbgems/mruby-object-ext/src/object.c index f0b50bf13..62345810f 100644 --- a/mrbgems/mruby-object-ext/src/object.c +++ b/mrbgems/mruby-object-ext/src/object.c @@ -60,6 +60,8 @@ nil_to_i(mrb_state *mrb, mrb_value obj) } /* + * Document-method: Kernel#itself + * * call-seq: * obj.itself -> an_object * @@ -69,11 +71,6 @@ nil_to_i(mrb_state *mrb, mrb_value obj) * string.itself.object_id == string.object_id #=> true * */ -static mrb_value -f_itself(mrb_state *mrb, mrb_value self) -{ - return self; -} /* * call-seq: @@ -122,7 +119,7 @@ mrb_mruby_object_ext_gem_init(mrb_state* mrb) mrb_define_method(mrb, n, "to_h", nil_to_h, MRB_ARGS_NONE()); mrb_define_method(mrb, n, "to_i", nil_to_i, MRB_ARGS_NONE()); - mrb_define_method(mrb, mrb->kernel_module, "itself", f_itself, MRB_ARGS_NONE()); + mrb_define_method(mrb, mrb->kernel_module, "itself", mrb_obj_itself, MRB_ARGS_NONE()); mrb_define_method(mrb, mrb_class_get_id(mrb, MRB_SYM(BasicObject)), "instance_exec", obj_instance_exec, MRB_ARGS_ANY() | MRB_ARGS_BLOCK()); } diff --git a/mrbgems/mruby-os-memsize/src/memsize.c b/mrbgems/mruby-os-memsize/src/memsize.c index 10f77beea..8ffd313ed 100644 --- a/mrbgems/mruby-os-memsize/src/memsize.c +++ b/mrbgems/mruby-os-memsize/src/memsize.c @@ -1,4 +1,5 @@ #include +#include #include #include #include @@ -167,6 +168,9 @@ os_memsize_of_object(mrb_state* mrb, mrb_value obj) case MRB_TT_ISTRUCT: size += mrb_objspace_page_slot_size(); break; + case MRB_TT_BACKTRACE: + size += ((struct RBacktrace*)mrb_obj_ptr(obj))->len * sizeof(struct mrb_backtrace_location); + break; /* zero heap size types. * immediate VM stack values, contained within mrb_state, or on C stack */ case MRB_TT_TRUE: diff --git a/mrbgems/mruby-pack/README.md b/mrbgems/mruby-pack/README.md index d108f2a09..2871fb4b3 100644 --- a/mrbgems/mruby-pack/README.md +++ b/mrbgems/mruby-pack/README.md @@ -45,7 +45,9 @@ There is no dependency on other mrbgems. - V : 32-bit unsigned, VAX (little-endian) byte order - v : 16-bit unsigned, VAX (little-endian) byte order - x : null byte +- X : back up bytes - Z : same as "a", except that null is added with \* +- @ : absolute position ## License diff --git a/mrbgems/mruby-pack/src/pack.c b/mrbgems/mruby-pack/src/pack.c index 75d8e1a94..8f61b0bb7 100644 --- a/mrbgems/mruby-pack/src/pack.c +++ b/mrbgems/mruby-pack/src/pack.c @@ -291,27 +291,24 @@ static void u64tostr(char *buf, size_t len, uint64_t n) { #ifdef MRB_NO_STDIO - char *bufend = buf + len; - char *p = bufend - 1; + mrb_assert(len > 0); - if (len < 1) { + if (n < 10) { + buf[0] = '0' + n; + buf[1] = '\0'; return; } + char *bufend = buf + len; + char *p = bufend - 1; + *p-- = '\0'; len--; - if (n > 0) { - for (; len > 0 && n > 0; len--, n /= 10) { - *p-- = '0' + (n % 10); - } - p++; + for (; len > 0 && n > 0; len--, n /= 10) { + *p-- = '0' + (n % 10); } - else if (len > 0) { - *p = '0'; - len--; - } - + p++; memmove(buf, p, bufend - p); #else snprintf(buf, len, "%" PRIu64, n); @@ -323,9 +320,7 @@ static void i64tostr(char *buf, size_t len, int64_t n) { #ifdef MRB_NO_STDIO - if (len < 1) { - return; - } + mrb_assert(len > 0); if (n < 0) { *buf++ = '-'; @@ -731,7 +726,7 @@ unpack_str(mrb_state *mrb, const void *src, int slen, mrb_value ary, int count, CHECK_UNPACK_LEN(mrb, slen, ary); mrb_value dst; - const char *cp, *sptr; + const char *sptr; int copylen; sptr = (const char*)src; @@ -741,6 +736,8 @@ unpack_str(mrb_state *mrb, const void *src, int slen, mrb_value ary, int count, copylen = slen; if (slen >= 0 && flags & PACK_FLAG_Z) { /* "Z" */ + const char *cp; + if ((cp = (const char*)memchr(sptr, '\0', slen)) != NULL) { copylen = (int)(cp - sptr); if (count == -1) { @@ -764,7 +761,6 @@ unpack_str(mrb_state *mrb, const void *src, int slen, mrb_value ary, int count, static int pack_hex(mrb_state *mrb, mrb_value src, mrb_value dst, mrb_int didx, int count, unsigned int flags) { - int a, b; unsigned int ashift, bshift; long slen; char *dptr, *dptr0, *sptr; @@ -793,7 +789,8 @@ pack_hex(mrb_state *mrb, mrb_value src, mrb_value dst, mrb_int didx, int count, dptr0 = dptr; for (; count > 0; count -= 2) { - a = b = 0; + int a = 0, b = 0; + if (slen > 0) { a = hex2int(*sptr++); if (a < 0) break; @@ -1498,19 +1495,17 @@ static mrb_value mrb_pack_pack(mrb_state *mrb, mrb_value ary) { mrb_value o, result; - mrb_int aidx; struct tmpl tmpl; - int count; + enum pack_type type; + int count, size; unsigned int flags; enum pack_dir dir; - enum pack_type type; - int ridx, size; prepare_tmpl(mrb, &tmpl); result = mrb_str_new(mrb, NULL, 128); /* allocate initial buffer */ - aidx = 0; - ridx = 0; + mrb_int aidx = 0; + mrb_int ridx = 0; while (has_tmpl(&tmpl)) { dir = read_tmpl(mrb, &tmpl, &type, &size, &count, &flags); @@ -1667,18 +1662,23 @@ pack_unpack(mrb_state *mrb, mrb_value str, int single) switch (dir) { case PACK_DIR_HEX: srcidx += unpack_hex(mrb, sptr, srclen - srcidx, result, count, flags); + if (single) goto single_return; continue; case PACK_DIR_BSTR: srcidx += unpack_bstr(mrb, sptr, srclen - srcidx, result, count, flags); + if (single) goto single_return; continue; case PACK_DIR_STR: srcidx += unpack_str(mrb, sptr, srclen - srcidx, result, count, flags); + if (single) goto single_return; continue; case PACK_DIR_BASE64: srcidx += unpack_base64(mrb, sptr, srclen - srcidx, result); + if (single) goto single_return; continue; case PACK_DIR_QENC: srcidx += unpack_qenc(mrb, sptr, srclen - srcidx, result); + if (single) goto single_return; continue; default: break; @@ -1729,6 +1729,7 @@ pack_unpack(mrb_state *mrb, mrb_value str, int single) } } if (single) { + single_return: if (RARRAY_LEN(result) > 0) { return RARRAY_PTR(result)[0]; } diff --git a/mrbgems/mruby-pack/test/pack.rb b/mrbgems/mruby-pack/test/pack.rb index 6045f788f..a3f110ba8 100644 --- a/mrbgems/mruby-pack/test/pack.rb +++ b/mrbgems/mruby-pack/test/pack.rb @@ -156,3 +156,18 @@ assert 'pack/unpack "U"' do assert_raise(RangeError) { [-1].pack("U") } assert_raise(RangeError) { [0x40000000].pack("U") } end + +assert 'unpack1' do + d = 1234 + assert_equal(d, [d].pack("i").unpack1("i")) + d = "foobar" + assert_equal(d, [d].pack("a*").unpack1("a*")) + assert_equal(d, [d].pack("A*").unpack1("A*")) + assert_equal(d, [d].pack("Z*").unpack1("Z*")) + assert_equal(d, [d].pack("m").unpack1("m")) + assert_equal(d, [d].pack("M").unpack1("M")) + d = "10010101" + assert_equal(d, [d].pack("b*").unpack1("b*")) + d = "f00b00" + assert_equal(d, [d].pack("h*").unpack1("h*")) +end diff --git a/mrbgems/mruby-random/src/random.c b/mrbgems/mruby-random/src/random.c index c47702e94..98d4fce4d 100644 --- a/mrbgems/mruby-random/src/random.c +++ b/mrbgems/mruby-random/src/random.c @@ -344,28 +344,27 @@ mrb_ary_sample(mrb_state *mrb, mrb_value ary) } else { mrb_value result; - mrb_int i, j; if (n < 0) mrb_raise(mrb, E_ARGUMENT_ERROR, "negative sample number"); if (n > len) n = len; result = mrb_ary_new_capa(mrb, n); - for (i=0; inumerator / p->denominator); } -static mrb_value -rational_to_r(mrb_state *mrb, mrb_value self) -{ - return self; -} - static mrb_value rational_negative_p(mrb_state *mrb, mrb_value self) { @@ -702,9 +655,10 @@ rational_div(mrb_state *mrb, mrb_value x) static mrb_value rational_pow(mrb_state *mrb, mrb_value x) { +#ifndef MRB_NO_FLOAT mrb_value y = mrb_get_arg1(mrb); struct mrb_rational *p1 = rational_ptr(mrb, x); -#ifndef MRB_NO_FLOAT + double d1, d2; switch (mrb_type(y)) { @@ -770,14 +724,13 @@ void mrb_mruby_rational_gem_init(mrb_state *mrb) MRB_SET_INSTANCE_TT(rat, MRB_TT_RATIONAL); MRB_UNDEF_ALLOCATOR(rat); mrb_undef_class_method(mrb, rat, "new"); - mrb_define_class_method(mrb, rat, "_new", rational_s_new, MRB_ARGS_REQ(2)); mrb_define_method(mrb, rat, "numerator", rational_numerator, MRB_ARGS_NONE()); mrb_define_method(mrb, rat, "denominator", rational_denominator, MRB_ARGS_NONE()); #ifndef MRB_NO_FLOAT mrb_define_method(mrb, rat, "to_f", mrb_rational_to_f, MRB_ARGS_NONE()); #endif mrb_define_method(mrb, rat, "to_i", mrb_rational_to_i, MRB_ARGS_NONE()); - mrb_define_method(mrb, rat, "to_r", rational_to_r, MRB_ARGS_NONE()); + mrb_define_method(mrb, rat, "to_r", mrb_obj_itself, MRB_ARGS_NONE()); mrb_define_method(mrb, rat, "negative?", rational_negative_p, MRB_ARGS_NONE()); mrb_define_method(mrb, rat, "==", rational_eq, MRB_ARGS_REQ(1)); mrb_define_method(mrb, rat, "<=>", rational_cmp, MRB_ARGS_REQ(1)); diff --git a/mrbgems/mruby-string-ext/src/string.c b/mrbgems/mruby-string-ext/src/string.c index 79b4743ac..82a52863e 100644 --- a/mrbgems/mruby-string-ext/src/string.c +++ b/mrbgems/mruby-string-ext/src/string.c @@ -53,7 +53,7 @@ int_chr_utf8(mrb_state *mrb, mrb_value num) char utf8[4]; mrb_int len; mrb_value str; - uint32_t ascii_flag = 0; + uint32_t sb_flag = 0; if (cp < 0 || 0x10FFFF < cp) { mrb_raisef(mrb, E_RANGE_ERROR, "%v out of char range", num); @@ -61,7 +61,7 @@ int_chr_utf8(mrb_state *mrb, mrb_value num) if (cp < 0x80) { utf8[0] = (char)cp; len = 1; - ascii_flag = MRB_STR_ASCII; + sb_flag = MRB_STR_SINGLE_BYTE; } else if (cp < 0x800) { utf8[0] = (char)(0xC0 | (cp >> 6)); @@ -82,7 +82,7 @@ int_chr_utf8(mrb_state *mrb, mrb_value num) len = 4; } str = mrb_str_new(mrb, utf8, len); - mrb_str_ptr(str)->flags |= ascii_flag; + mrb_str_ptr(str)->flags |= sb_flag; return str; } #endif @@ -1304,10 +1304,6 @@ str_uplus(mrb_state *mrb, mrb_value str) * * Returns a frozen, possibly pre-existing copy of the string. * - * The returned \String will be deduplicated as long as it does not have - * any instance variables set on it and is not a String subclass. - * - * String#dedup is an alias for String#-@. */ static mrb_value str_uminus(mrb_state *mrb, mrb_value str) @@ -1332,34 +1328,39 @@ str_valid_enc_p(mrb_state *mrb, mrb_value str) #define utf8_islead(c) ((unsigned char)((c)&0xc0) != 0x80) struct RString *s = mrb_str_ptr(str); - if (RSTR_ASCII_P(s)) return mrb_true_value(); + if (RSTR_SINGLE_BYTE_P(s)) return mrb_true_value(); mrb_int byte_len = RSTR_LEN(s); mrb_int utf8_len = 0; const char *p = RSTR_PTR(s); const char *e = p + byte_len; while (p < e) { - mrb_int len = mrb_utf8len_table[(unsigned char)p[0] >> 3]; - if (len == 0 || len > e - p) - return mrb_false_value(); - switch (len) { - case 4: - if (utf8_islead(p[3])) return mrb_false_value(); - case 3: - if (utf8_islead(p[2])) return mrb_false_value(); - case 2: - if (utf8_islead(p[1])) return mrb_false_value(); - default: - break; - } + mrb_int len = mrb_utf8len(p, e); + + if (len == 1 && (*p & 0x80)) return mrb_false_value(); p += len; utf8_len++; } - if (byte_len == utf8_len) RSTR_SET_ASCII_FLAG(s); + if (byte_len == utf8_len) RSTR_SET_SINGLE_BYTE_FLAG(s); #endif return mrb_true_value(); } +static mrb_value +str_ascii_only_p(mrb_state *mrb, mrb_value str) +{ + struct RString *s = mrb_str_ptr(str); + const char *p = RSTR_PTR(s); + const char *e = p + RSTR_LEN(s); + + while (p < e) { + if (*p & 0x80) return mrb_false_value(); + p++; + } + RSTR_SET_SINGLE_BYTE_FLAG(mrb_str_ptr(str)); + return mrb_true_value(); +} + void mrb_mruby_string_ext_gem_init(mrb_state* mrb) { @@ -1398,6 +1399,7 @@ mrb_mruby_string_ext_gem_init(mrb_state* mrb) mrb_define_method(mrb, s, "+@", str_uplus, MRB_ARGS_REQ(1)); mrb_define_method(mrb, s, "-@", str_uminus, MRB_ARGS_REQ(1)); mrb_define_method(mrb, s, "valid_encoding?", str_valid_enc_p, MRB_ARGS_NONE()); + mrb_define_method(mrb, s, "ascii_only?", str_ascii_only_p, MRB_ARGS_NONE()); mrb_define_method(mrb, s, "__lines", str_lines, MRB_ARGS_NONE()); mrb_define_method(mrb, s, "__codepoints", str_codepoints, MRB_ARGS_NONE()); diff --git a/src/array.c b/src/array.c index 01ccd85a8..7e2d03c65 100644 --- a/src/array.c +++ b/src/array.c @@ -215,18 +215,18 @@ ary_expand_capa(mrb_state *mrb, struct RArray *a, mrb_int len) capa = len; } } - if (capa < len || capa > ARY_MAX_SIZE) { + if (capa > ARY_MAX_SIZE) { ary_too_big(mrb); } if (ARY_EMBED_P(a)) { mrb_value *ptr = ARY_EMBED_PTR(a); - mrb_int len = ARY_EMBED_LEN(a); + mrb_int slen = ARY_EMBED_LEN(a); mrb_value *expanded_ptr = (mrb_value*)mrb_malloc(mrb, sizeof(mrb_value)*capa); ARY_UNSET_EMBED_FLAG(a); - array_copy(expanded_ptr, ptr, len); - a->as.heap.len = len; + array_copy(expanded_ptr, ptr, slen); + a->as.heap.len = slen; a->as.heap.aux.capa = capa; a->as.heap.ptr = expanded_ptr; } diff --git a/src/backtrace.c b/src/backtrace.c index 816b0e6db..636e3ce2c 100644 --- a/src/backtrace.c +++ b/src/backtrace.c @@ -17,23 +17,30 @@ #include #include -struct backtrace_location { - mrb_sym method_id; - int32_t idx; - const mrb_irep *irep; -}; - -typedef void (*each_backtrace_func)(mrb_state*, const struct backtrace_location*, void*); - -static const mrb_data_type bt_type = { "Backtrace", mrb_free }; - -static uint32_t -each_backtrace(mrb_state *mrb, ptrdiff_t ciidx, each_backtrace_func func, void *data) +static void +copy_backtrace(mrb_state *mrb, + const struct mrb_backtrace_location *loc, + struct mrb_backtrace_location *ptr, + size_t n) { - uint32_t n = 0; + ptr[n] = *loc; + if (loc->irep) { + if (loc->irep->refcnt == UINT16_MAX) { + ptr[n].irep = NULL; + } + else { + mrb_irep_incref(mrb, (mrb_irep*)loc->irep); + } + } +} + +static size_t +pack_backtrace(mrb_state *mrb, ptrdiff_t ciidx, struct mrb_backtrace_location *ptr) +{ + size_t n = 0; for (ptrdiff_t i=ciidx; i >= 0; i--) { - struct backtrace_location loc; + struct mrb_backtrace_location loc; mrb_callinfo *ci; const mrb_code *pc; @@ -75,59 +82,42 @@ each_backtrace(mrb_state *mrb, ptrdiff_t ciidx, each_backtrace_func func, void * } loc.irep = irep; - loc.idx = (uint32_t)(pc - loc.irep->iseq); + loc.idx = (uint32_t)(pc - irep->iseq); break; } } - if (func) func(mrb, &loc, data); + copy_backtrace(mrb, &loc, ptr, n); n++; } return n; } -static void -pack_backtrace_i(mrb_state *mrb, - const struct backtrace_location *loc, - void *data) -{ - struct backtrace_location **pptr = (struct backtrace_location**)data; - struct backtrace_location *ptr = *pptr; - - *ptr = *loc; - *pptr = ptr+1; -} - -static struct RObject* +static struct RBasic* packed_backtrace(mrb_state *mrb) { - struct RData *backtrace; + struct RBacktrace *backtrace; ptrdiff_t ciidx = mrb->c->ci - mrb->c->cibase; if (ciidx >= mrb->c->ciend - mrb->c->cibase) ciidx = mrb->c->ciend - mrb->c->cibase; /* ciidx is broken... */ - /* count the number of backtraces */ - int len = each_backtrace(mrb, ciidx, NULL, NULL); - backtrace = mrb_data_object_alloc(mrb, NULL, NULL, &bt_type); - if (len > 0) { - void *ptr = mrb_malloc(mrb, len * sizeof(struct backtrace_location)); - backtrace->data = ptr; - backtrace->flags = len; - each_backtrace(mrb, ciidx, pack_backtrace_i, &ptr); - } - else { - backtrace->data = NULL; - backtrace->flags = 0; - } - return (struct RObject*)backtrace; + ptrdiff_t len = ciidx + 1; + + backtrace = MRB_OBJ_ALLOC(mrb, MRB_TT_BACKTRACE, NULL); + + void *ptr = mrb_malloc(mrb, len * sizeof(struct mrb_backtrace_location)); + backtrace->locations = (struct mrb_backtrace_location*)ptr; + backtrace->len = pack_backtrace(mrb, ciidx, backtrace->locations); + + return (struct RBasic*)backtrace; } static void -store_backtrace(mrb_state *mrb, mrb_value exc, struct RObject *backtrace) +store_backtrace(mrb_state *mrb, mrb_value exc, struct RBasic *backtrace) { struct RException *e = mrb_exc_ptr(exc); e->backtrace = backtrace; - mrb_field_write_barrier(mrb, (struct RBasic*)e, (struct RBasic*)backtrace); + mrb_field_write_barrier(mrb, (struct RBasic*)e, backtrace); } void @@ -138,48 +128,52 @@ mrb_keep_backtrace(mrb_state *mrb, mrb_value exc) if (mrb->c->ci == NULL) return; if (mrb_exc_ptr(exc)->backtrace) return; ai = mrb_gc_arena_save(mrb); - struct RObject *backtrace = packed_backtrace(mrb); + struct RBasic *backtrace = packed_backtrace(mrb); store_backtrace(mrb, exc, backtrace); mrb_gc_arena_restore(mrb, ai); } -static struct RObject* -mrb_unpack_backtrace(mrb_state *mrb, struct RObject *backtrace) +static mrb_value +decode_location(mrb_state *mrb, const struct mrb_backtrace_location *entry) { - const struct backtrace_location *bt; - mrb_int n, i; - int ai; + mrb_value btline; + int32_t lineno; + const char *filename; + if (!entry->irep || !mrb_debug_get_position(mrb, entry->irep, entry->idx, &lineno, &filename)) { + btline = mrb_str_new_lit(mrb, "(unknown):0"); + } + else if (lineno != -1) {//debug info was available + btline = mrb_format(mrb, "%s:%d", filename, (int)lineno); + } + else { //all that was left was the stack frame + btline = mrb_format(mrb, "%s:0", filename); + } + if (entry->method_id != 0) { + mrb_str_cat_lit(mrb, btline, ":in "); + mrb_str_cat_cstr(mrb, btline, mrb_sym_name(mrb, entry->method_id)); + } + return btline; +} + +static struct RBasic* +mrb_unpack_backtrace(mrb_state *mrb, struct RBasic *backtrace) +{ if (backtrace == NULL) { - empty_backtrace: - return mrb_obj_ptr(mrb_ary_new_capa(mrb, 0)); + return mrb_basic_ptr(mrb_ary_new_capa(mrb, 0)); } if (backtrace->tt == MRB_TT_ARRAY) return backtrace; - bt = (struct backtrace_location*)mrb_data_check_get_ptr(mrb, mrb_obj_value(backtrace), &bt_type); - if (bt == NULL) goto empty_backtrace; - n = (mrb_int)backtrace->flags; - if (n == 0) goto empty_backtrace; - backtrace = mrb_obj_ptr(mrb_ary_new_capa(mrb, n)); - ai = mrb_gc_arena_save(mrb); - for (i = 0; i < n; i++) { - const struct backtrace_location *entry = &bt[i]; - mrb_value btline; - int32_t lineno; - const char *filename; - if (!mrb_debug_get_position(mrb, entry->irep, entry->idx, &lineno, &filename)) { - btline = mrb_str_new_lit(mrb, "(unknown):0"); - } - else if (lineno != -1) {//debug info was available - btline = mrb_format(mrb, "%s:%d", filename, (int)lineno); - } - else { //all that was left was the stack frame - btline = mrb_format(mrb, "%s:0", filename); - } - if (entry->method_id != 0) { - mrb_str_cat_lit(mrb, btline, ":in "); - mrb_str_cat_cstr(mrb, btline, mrb_sym_name(mrb, entry->method_id)); - } + mrb_assert(backtrace->tt == MRB_TT_BACKTRACE); + + struct RBacktrace *bt = (struct RBacktrace*)backtrace; + mrb_int n = bt ? (mrb_int)bt->len : 0; + const struct mrb_backtrace_location *loc = bt->locations; + + backtrace = mrb_basic_ptr(mrb_ary_new_capa(mrb, n)); + int ai = mrb_gc_arena_save(mrb); + for (mrb_int i = 0; i < n; i++) { + mrb_value btline = decode_location(mrb, &loc[i]); mrb_ary_push(mrb, mrb_obj_value(backtrace), btline); mrb_gc_arena_restore(mrb, ai); } @@ -190,7 +184,7 @@ mrb_unpack_backtrace(mrb_state *mrb, struct RObject *backtrace) mrb_value mrb_exc_backtrace(mrb_state *mrb, mrb_value exc) { - struct RObject *backtrace = mrb_exc_ptr(exc)->backtrace; + struct RBasic *backtrace = mrb_exc_ptr(exc)->backtrace; if (backtrace == NULL) { return mrb_nil_value(); } @@ -212,25 +206,40 @@ mrb_get_backtrace(mrb_state *mrb) #ifndef MRB_NO_STDIO static void -print_backtrace(mrb_state *mrb, struct RObject *exc, struct RArray *backtrace) +print_backtrace(mrb_state *mrb, struct RObject *exc, struct RBasic *ptr) { - mrb_int i; - mrb_int n = (backtrace ? ARY_LEN(backtrace) : 0); - mrb_value *loc, mesg; + struct RArray *ary = NULL; + struct RBacktrace *bt = NULL; + mrb_int n = 0; + + if (ptr) { + if (ptr->tt == MRB_TT_ARRAY) { + ary = (struct RArray*)ptr; + n = ARY_LEN(ary); + } + else { + bt = (struct RBacktrace*)ptr; + n = (mrb_int)bt->len; + } + } if (n != 0) { - if (n > 1) { - fputs("trace (most recent call last):\n", stderr); - } - for (i=n-1,loc=&ARY_PTR(backtrace)[i]; i>0; i--,loc--) { - if (mrb_string_p(*loc)) { + mrb_value btline; + + fputs("trace (most recent call last):\n", stderr); + for (mrb_int i=n-1; i>0; i--) { + if (ary) btline = ARY_PTR(ary)[i]; + else btline = decode_location(mrb, &bt->locations[i]); + if (mrb_string_p(btline)) { fprintf(stderr, "\t[%d] ", (int)i); - fwrite(RSTRING_PTR(*loc), (int)RSTRING_LEN(*loc), 1, stderr); + fwrite(RSTRING_PTR(btline), (int)RSTRING_LEN(btline), 1, stderr); fputc('\n', stderr); } } - if (mrb_string_p(*loc)) { - fwrite(RSTRING_PTR(*loc), (int)RSTRING_LEN(*loc), 1, stderr); + if (ary) btline = ARY_PTR(ary)[0]; + else btline = decode_location(mrb, &bt->locations[0]); + if (mrb_string_p(btline)) { + fwrite(RSTRING_PTR(btline), (int)RSTRING_LEN(btline), 1, stderr); fputs(": ", stderr); } } @@ -243,7 +252,7 @@ print_backtrace(mrb_state *mrb, struct RObject *exc, struct RArray *backtrace) fwrite(nomem, sizeof(nomem)-1, 1, stderr); } else { - mesg = mrb_exc_inspect(mrb, mrb_obj_value(exc)); + mrb_value mesg = mrb_exc_inspect(mrb, mrb_obj_value(exc)); fwrite(RSTRING_PTR(mesg), RSTRING_LEN(mesg), 1, stderr); fputc('\n', stderr); } @@ -261,9 +270,8 @@ mrb_print_backtrace(mrb_state *mrb) return; } - struct RObject *backtrace = ((struct RException*)mrb->exc)->backtrace; - if (backtrace && backtrace->tt != MRB_TT_ARRAY) backtrace = mrb_unpack_backtrace(mrb, backtrace); - print_backtrace(mrb, mrb->exc, (struct RArray*)backtrace); + struct RBasic *backtrace = ((struct RException*)mrb->exc)->backtrace; + print_backtrace(mrb, mrb->exc, backtrace); } #else MRB_API void diff --git a/src/error.c b/src/error.c index c91725283..63c104c77 100644 --- a/src/error.c +++ b/src/error.c @@ -24,7 +24,7 @@ mrb_exc_mesg_set(mrb_state *mrb, struct RException *exc, mrb_value mesg) if (!mrb_string_p(mesg)) { mesg = mrb_obj_as_string(mrb, mesg); } - exc->mesg = mrb_obj_ptr(mesg); + exc->mesg = mrb_basic_ptr(mesg); mrb_field_write_barrier_value(mrb, (struct RBasic*)exc, mesg); } @@ -160,7 +160,7 @@ set_backtrace(mrb_state *mrb, mrb_value exc, mrb_value backtrace) p++; } } - mrb_exc_ptr(exc)->backtrace = mrb_obj_ptr(backtrace); + mrb_exc_ptr(exc)->backtrace = mrb_basic_ptr(backtrace); mrb_field_write_barrier_value(mrb, mrb_basic_ptr(exc), backtrace); } diff --git a/src/gc.c b/src/gc.c index 39f63c62b..c5d58cb3b 100644 --- a/src/gc.c +++ b/src/gc.c @@ -107,9 +107,11 @@ */ +typedef struct RVALUE RVALUE; + struct free_obj { MRB_OBJECT_HEADER; - struct RBasic *next; + RVALUE *next; }; struct RVALUE_initializer { @@ -117,7 +119,7 @@ struct RVALUE_initializer { char padding[sizeof(void*) * 4 - sizeof(uint32_t)]; }; -typedef struct { +struct RVALUE { union { struct RVALUE_initializer init; /* must be first member to ensure initialization */ struct free_obj free; @@ -136,7 +138,7 @@ typedef struct { struct RException exc; struct RBreak brk; } as; -} RVALUE; +}; #ifdef GC_DEBUG #define DEBUG(x) (x) @@ -149,12 +151,11 @@ typedef struct { #endif typedef struct mrb_heap_page { - struct RBasic *freelist; + RVALUE *freelist; struct mrb_heap_page *next; struct mrb_heap_page *free_next; mrb_bool old:1; - /* Flexible array members are not C++ compatible */ - /* void* objects[]; */ + RVALUE objects[MRB_HEAP_PAGE_SIZE]; } mrb_heap_page; #define GC_STEP_SIZE 1024 @@ -181,12 +182,6 @@ mrb_static_assert(MRB_GC_RED <= GC_COLOR_MASK); #define other_white_part(s) ((s)->current_white_part ^ GC_WHITES) #define is_dead(s, o) (((o)->color & other_white_part(s) & GC_WHITES) || (o)->tt == MRB_TT_FREE) -/* We have removed `objects[]` from `mrb_heap_page` since it was not C++ - * compatible. Using array index to get pointer after structure instead. */ - -/* #define objects(p) ((RVALUE*)p->objects) */ -#define objects(p) ((RVALUE*)&p[1]) - mrb_noreturn void mrb_raise_nomemory(mrb_state *mrb); MRB_API void* @@ -279,7 +274,7 @@ heap_p(mrb_gc *gc, struct RBasic *object) while (page) { RVALUE *p; - p = objects(page); + p = page->objects; if (&p[0].as.basic <= object && object <= &p[MRB_HEAP_PAGE_SIZE - 1].as.basic) { return TRUE; } @@ -299,14 +294,14 @@ mrb_object_dead_p(mrb_state *mrb, struct RBasic *object) static void add_heap(mrb_state *mrb, mrb_gc *gc) { - mrb_heap_page *page = (mrb_heap_page*)mrb_calloc(mrb, 1, sizeof(mrb_heap_page) + MRB_HEAP_PAGE_SIZE * sizeof(RVALUE)); + mrb_heap_page *page = (mrb_heap_page*)mrb_calloc(mrb, 1, sizeof(mrb_heap_page)); RVALUE *p, *e; - struct RBasic *prev = NULL; + RVALUE *prev = NULL; - for (p = objects(page), e=p+MRB_HEAP_PAGE_SIZE; pobjects, e=p+MRB_HEAP_PAGE_SIZE; pas.free.tt = MRB_TT_FREE; p->as.free.next = prev; - prev = &p->as.basic; + prev = p; } page->freelist = prev; @@ -345,7 +340,7 @@ mrb_gc_init(mrb_state *mrb, mrb_gc *gc) #endif } -static void obj_free(mrb_state *mrb, struct RBasic *obj, int end); +static void obj_free(mrb_state *mrb, struct RBasic *obj, mrb_bool end); static void free_heap(mrb_state *mrb, mrb_gc *gc) @@ -357,7 +352,7 @@ free_heap(mrb_state *mrb, mrb_gc *gc) while (page) { tmp = page; page = page->next; - for (p = objects(tmp), e=p+MRB_HEAP_PAGE_SIZE; pobjects, e=p+MRB_HEAP_PAGE_SIZE; pas.free.tt != MRB_TT_FREE) obj_free(mrb, &p->as.basic, TRUE); } @@ -498,19 +493,19 @@ mrb_obj_alloc(mrb_state *mrb, enum mrb_vtype ttype, struct RClass *cls) add_heap(mrb, gc); } - struct RBasic *p = gc->free_heaps->freelist; - gc->free_heaps->freelist = ((struct free_obj*)p)->next; + RVALUE *p = gc->free_heaps->freelist; + gc->free_heaps->freelist = p->as.free.next; if (gc->free_heaps->freelist == NULL) { gc->free_heaps = gc->free_heaps->free_next; } gc->live++; - gc_protect(mrb, gc, p); - *(RVALUE*)p = RVALUE_zero; - p->tt = ttype; - p->c = cls; - paint_partial_white(gc, p); - return p; + gc_protect(mrb, gc, &p->as.basic); + *p = RVALUE_zero; + p->as.basic.tt = ttype; + p->as.basic.c = cls; + paint_partial_white(gc, &p->as.basic); + return &p->as.basic; } static inline void @@ -704,7 +699,7 @@ mrb_gc_mark(mrb_state *mrb, struct RBasic *obj) } static void -obj_free(mrb_state *mrb, struct RBasic *obj, int end) +obj_free(mrb_state *mrb, struct RBasic *obj, mrb_bool end) { DEBUG(fprintf(stderr, "obj_free(%p,tt=%d)\n",obj,obj->tt)); switch (obj->tt) { @@ -823,6 +818,17 @@ obj_free(mrb_state *mrb, struct RBasic *obj, int end) break; #endif + case MRB_TT_BACKTRACE: + { + struct RBacktrace *bt = (struct RBacktrace*)obj; + for (size_t i = 0; i < bt->len; i++) { + const mrb_irep *irep = bt->locations[i].irep; + if (irep == NULL) continue; + mrb_irep_decref(mrb, (mrb_irep*)irep); + } + mrb_free(mrb, bt->locations); + } + default: break; } @@ -969,6 +975,10 @@ gc_gray_counts(mrb_state *mrb, mrb_gc *gc, struct RBasic *obj) } break; + case MRB_TT_BACKTRACE: + children += ((struct RBacktrace*)obj)->len; + break; + default: break; } @@ -1064,7 +1074,7 @@ incremental_sweep_phase(mrb_state *mrb, mrb_gc *gc, size_t limit) size_t tried_sweep = 0; while (page && (tried_sweep < limit)) { - RVALUE *p = objects(page); + RVALUE *p = page->objects; RVALUE *e = p + MRB_HEAP_PAGE_SIZE; size_t freed = 0; mrb_bool dead_slot = TRUE; @@ -1080,7 +1090,7 @@ incremental_sweep_phase(mrb_state *mrb, mrb_gc *gc, size_t limit) obj_free(mrb, &p->as.basic, FALSE); if (p->as.basic.tt == MRB_TT_FREE) { p->as.free.next = page->freelist; - page->freelist = (struct RBasic*)p; + page->freelist = p; freed++; } else { @@ -1524,7 +1534,7 @@ gc_each_objects(mrb_state *mrb, mrb_gc *gc, mrb_each_object_callback *callback, while (page != NULL) { RVALUE *p; - p = objects(page); + p = page->objects; for (int i=0; i < MRB_HEAP_PAGE_SIZE; i++) { if ((*callback)(mrb, &p[i].as.basic, data) == MRB_EACH_OBJ_BREAK) return; diff --git a/src/numeric.c b/src/numeric.c index 743cdb3ae..41951e6bc 100644 --- a/src/numeric.c +++ b/src/numeric.c @@ -744,18 +744,14 @@ flo_lshift(mrb_state *mrb, mrb_value x) /* 15.2.9.3.13 */ /* + * Document-method: Float#to_f + * * call-seq: * flt.to_f -> self * * As flt is already a float, returns +self+. */ -static mrb_value -flo_to_f(mrb_state *mrb, mrb_value num) -{ - return num; -} - /* 15.2.9.3.11 */ /* * call-seq: @@ -1105,19 +1101,17 @@ flo_abs(mrb_state *mrb, mrb_value num) /* 15.2.9.3.24 */ /* + * Document-method: Integer#to_i + * Document-method: Integer#to_int + * * call-seq: * int.to_i -> integer + * int.to_int -> integer * * As int is already an Integer, all these * methods simply return the receiver. */ -static mrb_value -int_to_i(mrb_state *mrb, mrb_value num) -{ - return num; -} - mrb_value mrb_int_mul(mrb_state *mrb, mrb_value x, mrb_value y) { @@ -1976,7 +1970,6 @@ MRB_API mrb_value mrb_integer_to_str(mrb_state *mrb, mrb_value x, mrb_int base) { char buf[MRB_INT_BIT+1]; - mrb_int val = mrb_integer(x); if (base < 2 || 36 < base) { mrb_raisef(mrb, E_ARGUMENT_ERROR, "invalid radix %i", base); @@ -1986,6 +1979,7 @@ mrb_integer_to_str(mrb_state *mrb, mrb_value x, mrb_int base) return mrb_bint_to_s(mrb, x, base); } #endif + mrb_int val = mrb_integer(x); const char *p = mrb_int_to_cstr(buf, sizeof(buf), val, base); mrb_assert(p != NULL); mrb_value str = mrb_str_new_cstr(mrb, p); @@ -2031,6 +2025,9 @@ cmpnum(mrb_state *mrb, mrb_value v1, mrb_value v2) if (mrb_bigint_p(v1)) { return mrb_bint_cmp(mrb, v1, v2); } + if (mrb_bigint_p(v2)) { + return mrb_bint_cmp(mrb, mrb_bint_new_int(mrb, mrb_integer(v1)), v2); + } #endif #ifdef MRB_NO_FLOAT @@ -2237,8 +2234,8 @@ mrb_init_numeric(mrb_state *mrb) mrb_define_method_id(mrb, integer, MRB_OPSYM(gt), num_gt, MRB_ARGS_REQ(1)); mrb_define_method_id(mrb, integer, MRB_OPSYM(ge), num_ge, MRB_ARGS_REQ(1)); - mrb_define_method_id(mrb, integer, MRB_SYM(to_i), int_to_i, MRB_ARGS_NONE()); /* 15.2.8.3.24 */ - mrb_define_method_id(mrb, integer, MRB_SYM(to_int), int_to_i, MRB_ARGS_NONE()); + mrb_define_method_id(mrb, integer, MRB_SYM(to_i), mrb_obj_itself, MRB_ARGS_NONE()); /* 15.2.8.3.24 */ + mrb_define_method_id(mrb, integer, MRB_SYM(to_int), mrb_obj_itself, MRB_ARGS_NONE()); mrb_define_method_id(mrb, integer, MRB_OPSYM(add), int_add, MRB_ARGS_REQ(1)); /* 15.2.8.3.1 */ mrb_define_method_id(mrb, integer, MRB_OPSYM(sub), int_sub, MRB_ARGS_REQ(1)); /* 15.2.8.3.2 */ @@ -2301,7 +2298,7 @@ mrb_init_numeric(mrb_state *mrb) mrb_define_method_id(mrb, fl, MRB_SYM(floor), flo_floor, MRB_ARGS_OPT(1)); /* 15.2.9.3.10 */ mrb_define_method_id(mrb, fl, MRB_SYM_Q(infinite),flo_infinite_p, MRB_ARGS_NONE()); /* 15.2.9.3.11 */ mrb_define_method_id(mrb, fl, MRB_SYM(round), flo_round, MRB_ARGS_OPT(1)); /* 15.2.9.3.12 */ - mrb_define_method_id(mrb, fl, MRB_SYM(to_f), flo_to_f, MRB_ARGS_NONE()); /* 15.2.9.3.13 */ + mrb_define_method_id(mrb, fl, MRB_SYM(to_f), mrb_obj_itself, MRB_ARGS_NONE()); /* 15.2.9.3.13 */ mrb_define_method_id(mrb, fl, MRB_SYM(to_i), flo_to_i, MRB_ARGS_NONE()); /* 15.2.9.3.14 */ mrb_define_method_id(mrb, fl, MRB_SYM(truncate), flo_truncate, MRB_ARGS_OPT(1)); /* 15.2.9.3.15 */ mrb_define_method_id(mrb, fl, MRB_SYM(divmod), flo_divmod, MRB_ARGS_REQ(1)); diff --git a/src/object.c b/src/object.c index f8e9c0b72..8fbcc0f57 100644 --- a/src/object.c +++ b/src/object.c @@ -649,3 +649,9 @@ mrb_eql(mrb_state *mrb, mrb_value obj1, mrb_value obj2) if (mrb_class(mrb, obj1) != mrb_class(mrb, obj2)) return FALSE; return mrb_test(mrb_funcall_argv(mrb, obj1, MRB_SYM_Q(eql), 1, &obj2)); } + +MRB_API mrb_value +mrb_obj_itself(mrb_state *mrb, mrb_value self) +{ + return self; +} diff --git a/src/state.c b/src/state.c index ced96cb88..35ea71e2d 100644 --- a/src/state.c +++ b/src/state.c @@ -161,6 +161,9 @@ mrb_irep_free(mrb_state *mrb, mrb_irep *irep) } mrb_free(mrb, (void*)irep->lv); mrb_debug_info_free(mrb, irep->debug_info); +#ifdef MRB_DEBUG + memset(irep, -1, sizeof(*irep)); +#endif mrb_free(mrb, irep); } diff --git a/src/string.c b/src/string.c index b7e3a6504..780ab4e5e 100644 --- a/src/string.c +++ b/src/string.c @@ -263,7 +263,138 @@ mrb_gc_free_str(mrb_state *mrb, struct RString *str) mrb_free(mrb, str->as.heap.ptr); } +#if defined(__i386) || defined(__i386__) || defined(_M_IX86) || \ + defined(__x86_64) || defined(__x86_64__) || defined(_M_AMD64) || \ + defined(__powerpc64__) || defined(__POWERPC__) || defined(__aarch64__) || \ + defined(__mc68020__) +# define ALIGNED_WORD_ACCESS 0 +#else +# define ALIGNED_WORD_ACCESS 1 +#endif + #ifdef MRB_UTF8_STRING + +#define NOASCII(c) ((c) & 0x80) + +#ifdef SIMPLE_SEARCH_NONASCII +/* the naive implementation. define SIMPLE_SEARCH_NONASCII, */ +/* if you need it for any constraint (e.g. code size). */ +static const char* +search_nonascii(const char* p, const char *e) +{ + for (; p < e; ++p) { + if (NOASCII(*p)) return p; + } + return e; +} + +#elif defined(__SSE2__) +# include + +static inline const char * +search_nonascii(const char *p, const char *e) +{ + if (sizeof(__m128i) < (size_t)(e - p)) { + if (!_mm_movemask_epi8(_mm_loadu_si128((__m128i const*)p))) { + const intptr_t lowbits = sizeof(__m128i) - 1; + const __m128i *s, *t; + s = (const __m128i*)(~lowbits & ((intptr_t)p + lowbits)); + t = (const __m128i*)(~lowbits & (intptr_t)e); + for (; s < t; ++s) { + if (_mm_movemask_epi8(_mm_load_si128(s))) break; + } + p = (const char *)s; + } + } + switch (e - p) { + default: + case 15: if (NOASCII(*p)) return p; ++p; + case 14: if (NOASCII(*p)) return p; ++p; + case 13: if (NOASCII(*p)) return p; ++p; + case 12: if (NOASCII(*p)) return p; ++p; + case 11: if (NOASCII(*p)) return p; ++p; + case 10: if (NOASCII(*p)) return p; ++p; + case 9: if (NOASCII(*p)) return p; ++p; + case 8: if (NOASCII(*p)) return p; ++p; + case 7: if (NOASCII(*p)) return p; ++p; + case 6: if (NOASCII(*p)) return p; ++p; + case 5: if (NOASCII(*p)) return p; ++p; + case 4: if (NOASCII(*p)) return p; ++p; + case 3: if (NOASCII(*p)) return p; ++p; + case 2: if (NOASCII(*p)) return p; ++p; + case 1: if (NOASCII(*p)) return p; ++p; + if (NOASCII(*p)) return p; + } + return e; +} + +#else + +#ifdef MRB_64BIT +# define NONASCII_MASK 0x8080808080808080ULL +#else /* MRB_32BIT */ +# define NONASCII_MASK 0x80808080UL +#endif + +static const char* +search_nonascii(const char *p, const char *e) +{ + if (e - p >= sizeof(void*)) { +#if ALIGNED_WORD_ACCESS + if ((uintptr_t)p % sizeof(void*)) { + int l = sizeof(void*) - (uintptr_t)p % sizeof(void*); + p += l; + switch (l) { +#ifdef MRB_64BIT + case 7: if (p[-7]&0x80) return p-7; + case 6: if (p[-6]&0x80) return p-6; + case 5: if (p[-5]&0x80) return p-5; + case 4: if (p[-4]&0x80) return p-4; +#endif + case 3: if (p[-3]&0x80) return p-3; + case 2: if (p[-2]&0x80) return p-2; + case 1: if (p[-1]&0x80) return p-1; + case 0: break; + } + } +#endif + + const uintptr_t *s = (uintptr_t*)p; + const uintptr_t *t = (uintptr_t*)(e - (sizeof(void*)-1)); + + for (;s < t; s++) { + if (*s & NONASCII_MASK) { + p = (const char*)s; + if (NOASCII(p[0])) return p+0; + if (NOASCII(p[1])) return p+1; + if (NOASCII(p[2])) return p+2; + if (NOASCII(p[3])) return p+3; +#ifdef MRB_64BIT + if (NOASCII(p[4])) return p+4; + if (NOASCII(p[5])) return p+5; + if (NOASCII(p[6])) return p+6; + if (NOASCII(p[7])) return p+7; +#endif + } + } + } + switch (e - p) { + default: +#ifdef MRB_64BIT + case 7: if (e[-7]&0x80) return e-7; + case 6: if (e[-6]&0x80) return e-6; + case 5: if (e[-5]&0x80) return e-5; + case 4: if (e[-4]&0x80) return e-4; +#endif + case 3: if (e[-3]&0x80) return e-3; + case 2: if (e[-2]&0x80) return e-2; + case 1: if (e[-1]&0x80) return e-1; + } + return e; +} + +#endif /* SIMPLE_SEARCH_NONASCII */ + #define utf8_islead(c) ((unsigned char)((c)&0xc0) != 0x80) extern const char mrb_utf8len_table[]; @@ -278,7 +409,7 @@ mrb_utf8len(const char* p, const char* e) mrb_int len = mrb_utf8len_table[(unsigned char)p[0] >> 3]; if (len > e - p) return 1; switch (len) { - case 1: + case 0: return 1; case 4: if (utf8_islead(p[3])) return 1; @@ -309,12 +440,12 @@ utf8_strlen(mrb_value str) struct RString *s = mrb_str_ptr(str); mrb_int byte_len = RSTR_LEN(s); - if (RSTR_ASCII_P(s)) { + if (RSTR_SINGLE_BYTE_P(s)) { return byte_len; } else { mrb_int utf8_len = mrb_utf8_strlen(RSTR_PTR(s), byte_len); - if (byte_len == utf8_len) RSTR_SET_ASCII_FLAG(s); + if (byte_len == utf8_len) RSTR_SET_SINGLE_BYTE_FLAG(s); return utf8_len; } } @@ -325,33 +456,62 @@ utf8_strlen(mrb_value str) static mrb_int chars2bytes(mrb_value s, mrb_int off, mrb_int idx) { - if (RSTR_ASCII_P(mrb_str_ptr(s))) { + if (RSTR_SINGLE_BYTE_P(mrb_str_ptr(s))) { return idx; } - else { - mrb_int i, b, n; - const char *p = RSTRING_PTR(s) + off; - const char *e = RSTRING_END(s); - for (b=i=0; p 0) { + pos = chars2bytes(str, 0, pos); + } - /* Preprocessing */ - { - mrb_int i; + pos = mrb_str_index(mrb, str, ptr, len, pos); - for (i = 0; i < 1 << CHAR_BIT; i++) { - qstable[i] = slen; - } - for (i = 0; i < slen; i++) { - qstable[(unsigned char)s[i]] = slen - (i + 1); + if (pos > 0) { + pos = bytes2chars(str, pos); + } + return pos; +} + +#else +#define RSTRING_CHAR_LEN(s) RSTRING_LEN(s) +#define chars2bytes(s, off, ci) (ci) +#define bytes2chars(s, bi) (bi) +#define char_adjust(beg, end, ptr) (ptr) +#define char_backtrack(ptr, end) ((end) - 1) +#define str_index_str_by_char(mrb, str, sub, pos) str_index_str((mrb), (str), (sub), (pos)) +#endif + +/* memsearch_swar (SWAR stands for SIMD within a register) */ +/* See https://en.wikipedia.org/wiki/SWAR */ +/* The function is taken from http://0x80.pl/articles/simd-strfind.html */ +/* The original source code is under 2-clause BSD license; see LEGAL file. */ +/* The modifications: + * port from C++ to C + * returns mrb_int + * remove alignment issue + * support bigendian CPU + * fixed potential buffer overflow +*/ +static inline mrb_int +memsearch_swar(const char *xs, mrb_int m, const char *ys, mrb_int n) +{ +#ifdef MRB_64BIT +#define bitint uint64_t +#define MASK1 0x0101010101010101ull +#define MASK2 0x7f7f7f7f7f7f7f7full +#define MASK3 0x8080808080808080ull +#else +#define bitint uint32_t +#define MASK1 0x01010101ul +#define MASK2 0x7f7f7f7ful +#define MASK3 0x80808080ul +#endif +#if defined(MRB_ENDIAN_BIG) +#ifdef MRB_64BIT +#define MASK4 0x8000000000000000ull +#else +#define MASK4 0x80000000ul +#endif +#else +#define MASK4 0x80 +#endif + + const bitint first = MASK1 * (uint8_t)xs[0]; + const bitint last = MASK1 * (uint8_t)xs[m-1]; + + const char *s0 = ys; + const char *s1 = ys+m-1; + + const mrb_int lim = n - m - (mrb_int)sizeof(bitint); + mrb_int i; + + for (i=0; i < lim; i+=sizeof(bitint)) { + bitint t0, t1; + + memcpy(&t0, s0+i, sizeof(bitint)); + memcpy(&t1, s1+i, sizeof(bitint)); + + const bitint eq = (t0 ^ first) | (t1 ^ last); + bitint zeros = ((~eq & MASK2) + MASK1) & (~eq & MASK3); + + + for (size_t j = 0; zeros; j++) { + if (zeros & MASK4) { + const mrb_int idx = i + j; + const char* p = s0 + idx + 1; + if (memcmp(p, xs + 1, m - 2) == 0) { + return idx; + } + } + +#if defined(MRB_ENDIAN_BIG) + zeros <<= 8; +#else + zeros >>= 8; +#endif } } - /* Searching */ - while (p < pend && pend - p >= slen) { - const char *pivot; - - if (memcmp(p, s, slen) == 0) { - return off; + if (i+m < n) { + const char *p = s0; + const char *e = ys + n; + for (;p= pend || pivot < p /* overflowed */) { return -1; } - - do { - p += mrb_utf8len(p, pend); - off++; - } while (p < pivot); } return -1; } static mrb_int -str_index_str_by_char(mrb_state *mrb, mrb_value str, mrb_value sub, mrb_int pos) +mrb_memsearch(const char *x, mrb_int m, const char *y, mrb_int n) { - const char *p = RSTRING_PTR(str); - const char *pend = p + RSTRING_LEN(str); - const char *s = RSTRING_PTR(sub); - const mrb_int slen = RSTRING_LEN(sub); - mrb_int off = pos; - - for (; pos > 0; pos --) { - if (pend - p < 1) { return -1; } - p += mrb_utf8len(p, pend); - } - - if (slen < 1) { return off; } - - return str_index_str_by_char_search(mrb, p, pend, s, slen, off); -} - -#define BYTES_ALIGN_CHECK(pos) if (pos < 0) return mrb_nil_value(); -#else -#define RSTRING_CHAR_LEN(s) RSTRING_LEN(s) -#define chars2bytes(p, off, ci) (ci) -#define bytes2chars(p, end, bi) (bi) -#define char_adjust(beg, end, ptr) (ptr) -#define char_backtrack(ptr, end) ((end) - 1) -#define BYTES_ALIGN_CHECK(pos) -#define str_index_str_by_char(mrb, str, sub, pos) str_index_str(mrb, str, sub, pos) -#endif - -#ifndef MRB_QS_SHORT_STRING_LENGTH -#define MRB_QS_SHORT_STRING_LENGTH 2048 -#endif - -static inline mrb_int -mrb_memsearch_qs(const unsigned char *xs, mrb_int m, const unsigned char *ys, mrb_int n) -{ - if (n + m < MRB_QS_SHORT_STRING_LENGTH) { - const unsigned char *y = ys; - const unsigned char *ye = ys+n-m+1; - - for (;;) { - y = (const unsigned char*)memchr(y, xs[0], (size_t)(ye-y)); - if (y == NULL) return -1; - if (memcmp(xs, y, m) == 0) { - return (mrb_int)(y - ys); - } - y++; - } - return -1; - } - else { - const unsigned char *x = xs, *xe = xs + m; - const unsigned char *y = ys; - ptrdiff_t qstable[256]; - - /* Preprocessing */ - for (int i = 0; i < 256; i++) - qstable[i] = m + 1; - for (; x < xe; x++) - qstable[*x] = xe - x; - /* Searching */ - for (; y + m <= ys + n; y += *(qstable + y[m])) { - if (*xs == *y && memcmp(xs, y, m) == 0) - return (mrb_int)(y - ys); - } - return -1; - } -} - -static mrb_int -mrb_memsearch(const void *x0, mrb_int m, const void *y0, mrb_int n) -{ - const unsigned char *x = (const unsigned char*)x0, *y = (const unsigned char*)y0; - if (m > n) return -1; else if (m == n) { - return memcmp(x0, y0, m) == 0 ? 0 : -1; + return memcmp(x, y, m) == 0 ? 0 : -1; } else if (m < 1) { return 0; } else if (m == 1) { - const unsigned char *ys = (const unsigned char*)memchr(y, *x, n); + const char *p = (const char*)memchr(y, *x, n); - if (ys) - return (mrb_int)(ys - y); - else - return -1; + if (p) return (mrb_int)(p - y); + return -1; } - return mrb_memsearch_qs((const unsigned char*)x0, m, (const unsigned char*)y0, n); + return memsearch_swar(x, m, y, n); } static void @@ -551,21 +711,16 @@ mrb_str_byte_subseq(mrb_state *mrb, mrb_value str, mrb_int beg, mrb_int len) s->as.heap.ptr += (mrb_ssize)beg; s->as.heap.len = (mrb_ssize)len; } - RSTR_COPY_ASCII_FLAG(s, orig); + RSTR_COPY_SINGLE_BYTE_FLAG(s, orig); return mrb_obj_value(s); } -static void -str_range_to_bytes(mrb_value str, mrb_int *pos, mrb_int *len) -{ - *pos = chars2bytes(str, 0, *pos); - *len = chars2bytes(str, *pos, *len); -} #ifdef MRB_UTF8_STRING static inline mrb_value str_subseq(mrb_state *mrb, mrb_value str, mrb_int beg, mrb_int len) { - str_range_to_bytes(str, &beg, &len); + beg = chars2bytes(str, 0, beg); + len = chars2bytes(str, beg, len); return mrb_str_byte_subseq(mrb, str, beg, len); } #else @@ -639,7 +794,7 @@ str_replace(mrb_state *mrb, struct RString *s1, struct RString *s2) mrb_check_frozen(mrb, s1); if (s1 == s2) return mrb_obj_value(s1); - RSTR_COPY_ASCII_FLAG(s1, s2); + RSTR_COPY_SINGLE_BYTE_FLAG(s1, s2); if (RSTR_SHARED_P(s1)) { str_decref(mrb, s1->as.heap.aux.shared); } @@ -765,7 +920,7 @@ MRB_API void mrb_str_modify(mrb_state *mrb, struct RString *s) { mrb_str_modify_keep_ascii(mrb, s); - RSTR_UNSET_ASCII_FLAG(s); + RSTR_UNSET_SINGLE_BYTE_FLAG(s); } MRB_API mrb_value @@ -903,7 +1058,7 @@ mrb_str_times(mrb_state *mrb, mrb_value self) memcpy(p + n, p, len-n); } p[RSTR_LEN(str2)] = '\0'; - RSTR_COPY_ASCII_FLAG(str2, mrb_str_ptr(self)); + RSTR_COPY_SINGLE_BYTE_FLAG(str2, mrb_str_ptr(self)); return mrb_obj_value(str2); } @@ -1213,7 +1368,7 @@ str_escape(mrb_state *mrb, mrb_value str, mrb_bool inspect) char buf[4]; /* `\x??` or UTF-8 character */ mrb_value result = mrb_str_new_lit(mrb, "\""); #ifdef MRB_UTF8_STRING - uint32_t ascii_flag = MRB_STR_ASCII; + uint32_t sb_flag = MRB_STR_SINGLE_BYTE; #endif p = RSTRING_PTR(str); pend = RSTRING_END(str); @@ -1225,7 +1380,7 @@ str_escape(mrb_state *mrb, mrb_value str, mrb_bool inspect) if (clen > 1) { mrb_str_cat(mrb, result, p, clen); p += clen-1; - ascii_flag = 0; + sb_flag = 0; continue; } } @@ -1267,11 +1422,11 @@ str_escape(mrb_state *mrb, mrb_value str, mrb_bool inspect) mrb_str_cat_lit(mrb, result, "\""); #ifdef MRB_UTF8_STRING if (inspect) { - mrb_str_ptr(str)->flags |= ascii_flag; - mrb_str_ptr(result)->flags |= ascii_flag; + mrb_str_ptr(str)->flags |= sb_flag; + mrb_str_ptr(result)->flags |= sb_flag; } else { - RSTR_SET_ASCII_FLAG(mrb_str_ptr(result)); + RSTR_SET_SINGLE_BYTE_FLAG(mrb_str_ptr(result)); } #endif @@ -1297,7 +1452,8 @@ mrb_str_aset(mrb_state *mrb, mrb_value str, mrb_value indx, mrb_value alen, mrb_ if (beg < 0 || beg > charlen) { str_out_of_index(mrb, indx); } /* fall through */ case STR_CHAR_RANGE_CORRECTED: - str_range_to_bytes(str, &beg, &len); + beg = chars2bytes(str, 0, beg); + len = chars2bytes(str, beg, len); /* fall through */ case STR_BYTE_RANGE_CORRECTED: if (mrb_int_add_overflow(beg, len, &len)) { @@ -1791,7 +1947,7 @@ mrb_str_byteindex_m(mrb_state *mrb, mrb_value str) static mrb_value mrb_str_index_m(mrb_state *mrb, mrb_value str) { - if (RSTR_ASCII_P(mrb_str_ptr(str))) { + if (RSTR_SINGLE_BYTE_P(mrb_str_ptr(str))) { return mrb_str_byteindex_m(mrb, str); } @@ -2062,7 +2218,7 @@ mrb_str_byterindex_m(mrb_state *mrb, mrb_value str) static mrb_value mrb_str_rindex_m(mrb_state *mrb, mrb_value str) { - if (RSTR_ASCII_P(mrb_str_ptr(str))) { + if (RSTR_SINGLE_BYTE_P(mrb_str_ptr(str))) { return mrb_str_byterindex_m(mrb, str); } @@ -2070,8 +2226,7 @@ mrb_str_rindex_m(mrb_state *mrb, mrb_value str) mrb_int pos; if (mrb_get_args(mrb, "S|i", &sub, &pos) == 1) { - pos = RSTRING_CHAR_LEN(str); - pos = chars2bytes(str, 0, pos); + pos = RSTRING_LEN(str); } else if (pos >= 0) { pos = chars2bytes(str, 0, pos); @@ -2087,8 +2242,8 @@ mrb_str_rindex_m(mrb_state *mrb, mrb_value str) } pos = str_rindex(mrb, str, sub, pos); if (pos >= 0) { - pos = bytes2chars(RSTRING_PTR(str), RSTRING_LEN(str), pos); - BYTES_ALIGN_CHECK(pos); + pos = bytes2chars(str, pos); + if (pos < 0) return mrb_nil_value(); return mrb_int_value(mrb, pos); } return mrb_nil_value(); diff --git a/src/symbol.c b/src/symbol.c index 3f0ddb535..021b80003 100644 --- a/src/symbol.c +++ b/src/symbol.c @@ -441,6 +441,8 @@ sym_name(mrb_state *mrb, mrb_value vsym) /* 15.2.11.3.4 */ /* + * Document-method: Symbol#to_sym + * * call-seq: * sym.to_sym -> sym * sym.intern -> sym @@ -450,12 +452,6 @@ sym_name(mrb_state *mrb, mrb_value vsym) * in this case. */ -static mrb_value -sym_to_sym(mrb_state *mrb, mrb_value sym) -{ - return sym; -} - /* 15.2.11.3.5(x) */ /* * call-seq: @@ -696,7 +692,7 @@ mrb_init_symbol(mrb_state *mrb) mrb_define_method_id(mrb, sym, MRB_SYM(to_s), sym_to_s, MRB_ARGS_NONE()); /* 15.2.11.3.3 */ mrb_define_method_id(mrb, sym, MRB_SYM(name), sym_name, MRB_ARGS_NONE()); - mrb_define_method_id(mrb, sym, MRB_SYM(to_sym), sym_to_sym, MRB_ARGS_NONE()); /* 15.2.11.3.4 */ + mrb_define_method_id(mrb, sym, MRB_SYM(to_sym), mrb_obj_itself, MRB_ARGS_NONE()); /* 15.2.11.3.4 */ mrb_define_method_id(mrb, sym, MRB_SYM(inspect), sym_inspect, MRB_ARGS_NONE()); /* 15.2.11.3.5(x) */ mrb_define_method_id(mrb, sym, MRB_OPSYM(cmp), sym_cmp, MRB_ARGS_REQ(1)); }