From 2af92d0ebcbeca6d3d85a27c8193273080a63090 Mon Sep 17 00:00:00 2001 From: Ichito Nagata Date: Mon, 4 Jun 2018 10:52:51 +0900 Subject: Let inspect recursion do the right thing --- mrbgems/mruby-struct/mrblib/struct.rb | 12 +++++------- mrbgems/mruby-struct/test/struct.rb | 7 ++++--- mrblib/array.rb | 12 +++++------- mrblib/hash.rb | 12 +++++------- mrblib/kernel.rb | 2 +- test/t/array.rb | 3 ++- test/t/hash.rb | 2 ++ 7 files changed, 24 insertions(+), 26 deletions(-) diff --git a/mrbgems/mruby-struct/mrblib/struct.rb b/mrbgems/mruby-struct/mrblib/struct.rb index 7cf3dd3ab..86c635df7 100644 --- a/mrbgems/mruby-struct/mrblib/struct.rb +++ b/mrbgems/mruby-struct/mrblib/struct.rb @@ -46,7 +46,9 @@ if Object.const_defined?(:Struct) ary end - def _inspect + def _inspect(recur_list) + return "#" if recur_list[self.object_id] + recur_list[self.object_id] = true name = self.class.to_s if name[0] == "#" str = "#" end @@ -70,11 +72,7 @@ if Object.const_defined?(:Struct) # 15.2.18.4.10(x) # def inspect - begin - self._inspect - rescue SystemStackError - "#" - end + self._inspect({}) end ## diff --git a/mrbgems/mruby-struct/test/struct.rb b/mrbgems/mruby-struct/test/struct.rb index 982e344e2..2b5751086 100644 --- a/mrbgems/mruby-struct/test/struct.rb +++ b/mrbgems/mruby-struct/test/struct.rb @@ -116,9 +116,10 @@ assert('struct dup') do end assert('struct inspect') do - c = Struct.new(:m1, :m2, :m3, :m4, :m5) - cc = c.new(1,2,3,4,5) - assert_equal "#", cc.inspect + c = Struct.new(:m1, :m2, :m3, :m4, :m5, :recur) + cc = c.new(1,2,3,4,5,nil) + cc.recur = cc + assert_equal "#>", cc.inspect end assert('Struct#length, Struct#size') do diff --git a/mrblib/array.rb b/mrblib/array.rb index 334f4e984..bc9a2a492 100644 --- a/mrblib/array.rb +++ b/mrblib/array.rb @@ -83,20 +83,18 @@ class Array self end - def _inspect + def _inspect(recur_list) return "[]" if self.size == 0 - "["+self.map{|x|x.inspect}.join(", ")+"]" + return "[...]" if recur_list[self.object_id] + recur_list[self.object_id] = true + "["+self.map{|x|x._inspect(recur_list)}.join(", ")+"]" end ## # Return the contents of this array as a string. # # ISO 15.2.12.5.31 (x) def inspect - begin - self._inspect - rescue SystemStackError - "[...]" - end + self._inspect({}) end # ISO 15.2.12.5.32 (x) alias to_s inspect diff --git a/mrblib/hash.rb b/mrblib/hash.rb index 7e1db905f..6fcbba173 100644 --- a/mrblib/hash.rb +++ b/mrblib/hash.rb @@ -193,10 +193,12 @@ class Hash end # internal method for Hash inspection - def _inspect + def _inspect(recur_list) return "{}" if self.size == 0 + return "{...}" if recur_list[self.object_id] + recur_list[self.object_id] = true "{"+self.map {|k,v| - k._inspect + "=>" + v._inspect + k._inspect(recur_list) + "=>" + v._inspect(recur_list) }.join(", ")+"}" end ## @@ -204,11 +206,7 @@ class Hash # # ISO 15.2.13.4.30 (x) def inspect - begin - self._inspect - rescue SystemStackError - "{...}" - end + self._inspect({}) end # ISO 15.2.13.4.31 (x) alias to_s inspect diff --git a/mrblib/kernel.rb b/mrblib/kernel.rb index 550ae8172..3fb324908 100644 --- a/mrblib/kernel.rb +++ b/mrblib/kernel.rb @@ -40,7 +40,7 @@ module Kernel end # internal method for inspect - def _inspect + def _inspect(_recur_list) self.inspect end diff --git a/test/t/array.rb b/test/t/array.rb index ecec39363..3ed3d54ec 100644 --- a/test/t/array.rb +++ b/test/t/array.rb @@ -318,11 +318,12 @@ end assert('Array#to_s', '15.2.12.5.31 / 15.2.12.5.32') do a = [2, 3, 4, 5] + a[4] = a r1 = a.to_s r2 = a.inspect assert_equal(r2, r1) - assert_equal("[2, 3, 4, 5]", r1) + assert_equal("[2, 3, 4, 5, [...]]", r1) end assert('Array#==', '15.2.12.5.33') do diff --git a/test/t/hash.rb b/test/t/hash.rb index 5403a5901..63029be42 100644 --- a/test/t/hash.rb +++ b/test/t/hash.rb @@ -351,11 +351,13 @@ end assert('Hash#inspect') do h = { "c" => 300, "a" => 100, "d" => 400, "c" => 300 } + h["recur"] = h ret = h.to_s assert_include ret, '"c"=>300' assert_include ret, '"a"=>100' assert_include ret, '"d"=>400' + assert_include ret, '"recur"=>{...}' end assert('Hash#rehash') do -- cgit v1.2.3 From 1d1b47044c7ead3a629a6c8979a5ce1bf81c65b1 Mon Sep 17 00:00:00 2001 From: Bhargava Shastry Date: Wed, 5 Dec 2018 17:45:27 +0100 Subject: ossfuzz: Add simple mruby compile test harness --- oss-fuzz/mruby_fuzzer.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100644 oss-fuzz/mruby_fuzzer.c diff --git a/oss-fuzz/mruby_fuzzer.c b/oss-fuzz/mruby_fuzzer.c new file mode 100644 index 000000000..9d3d44a5b --- /dev/null +++ b/oss-fuzz/mruby_fuzzer.c @@ -0,0 +1,18 @@ +#include +#include +#include +#include + +int LLVMFuzzerTestOneInput(uint8_t *Data, size_t size) { + if (size < 1) { + return 0; + } + char *code = malloc(size+1); + memcpy(code, Data, size); + code[size] = '\0'; + mrb_state *mrb = mrb_open(); + mrb_load_string(mrb, code); + mrb_close(mrb); + free(code); + return 0; +} -- cgit v1.2.3 From bccf9e4a3fd07ed82a57dcba138f926d400758b7 Mon Sep 17 00:00:00 2001 From: Bhargava Shastry Date: Wed, 5 Dec 2018 18:00:47 +0100 Subject: ossfuzz: Add fuzzing dictionary for mruby. --- oss-fuzz/mruby.dict | 105 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 105 insertions(+) create mode 100644 oss-fuzz/mruby.dict diff --git a/oss-fuzz/mruby.dict b/oss-fuzz/mruby.dict new file mode 100644 index 000000000..a332d3505 --- /dev/null +++ b/oss-fuzz/mruby.dict @@ -0,0 +1,105 @@ +keyword___ENCODING__="__ENCODING__" +keyword___FILE__="__FILE__" +keyword___LINE__="__LINE__" +keyword_BEGIN="BEGIN" +keyword_END="END" +keyword_alias="alias" +keyword_and="and" +keyword_begin="begin" +keyword_break="break" +keyword_case="case" +keyword_class="class" +keyword_def="def" +keyword_do="do" +keyword_else="else" +keyword_elsif="elsif" +keyword_end="end" +keyword_ensure="ensure" +keyword_false="false" +keyword_for="for" +keyword_if="if" +keyword_in="in" +keyword_module="module" +keyword_next="next" +keyword_nil="nil" +keyword_not="not" +keyword_or="or" +keyword_redo="redo" +keyword_rescue="rescue" +keyword_retry="retry" +keyword_return="return" +keyword_self="self" +keyword_super="super" +keyword_then="then" +keyword_true="true" +keyword_undef="undef" +keyword_unless="unless" +keyword_until="until" +keyword_when="when" +keyword_while="while" +keyword_yield="yield" + +operator_a=" !" +operator_b=" ~" +operator_c=" +" +operator_d=" -" +operator_e=" []" +operator_f=" []=" +operator_g=" *" +operator_h=" /" +operator_i=" %" +operator_j=" +-" +operator_k=" >>" +operator_l=" <<" +operator_m=" &" +operator_n=" ^" +operator_o=" |" +operator_p=" <=" +operator_q=" <>" +operator_r=" >=" +operator_s=" <=>" +operator_t=" ==" +operator_u=" ===" +operator_v=" !=" +operator_w=" =~" +operator_x=" !~" +operator_y=" &&" +operator_z=" ||" +operator_aa=" .." +operator_ab=" ..." +operator_ac=" ?" +operator_ad=" :" +operator_ae=" =" +operator_af=" %=" +operator_ag=" /=" +operator_ah=" -=" +operator_ai=" +=" +operator_aj=" |=" +operator_ak=" &=" +operator_al=" >>=" +operator_am=" <<=" +operator_an=" *=" +operator_ao=" &&=" +operator_ap=" ||=" +operator_aq=" **=" +operator_ar=" ^=" +operator_as=" not" +operator_at=" or" +operator_au=" and" +operator_av=" if" +operator_aw=" unless" +operator_ax=" while" +operator_ay=" until" +operator_az=" begin" +operator_ba=" end" + +snippet_1eq1=" 1=1" +snippet_dollar=" $1" +snippet_at=" @a" +snippet_symbol=" :a" +snippet_array=" [1,2]" +snippet_block=" 1.times{|x| x}" +snippet_multi=" 1*1" + +string_single_q=" 'a'" +string_dbl_q=" \"a\"" -- cgit v1.2.3 From 05b4eaac4b6bbf7d6e28887b48dcead2140c7d0b Mon Sep 17 00:00:00 2001 From: Bhargava Shastry Date: Wed, 5 Dec 2018 18:06:30 +0100 Subject: ossfuzz: Moved config related files to a namesake directory under ossfuzz --- oss-fuzz/config/mruby.dict | 105 +++++++++++++++++++++++++++++++++++ oss-fuzz/config/mruby_fuzzer.options | 3 + oss-fuzz/mruby.dict | 105 ----------------------------------- 3 files changed, 108 insertions(+), 105 deletions(-) create mode 100644 oss-fuzz/config/mruby.dict create mode 100644 oss-fuzz/config/mruby_fuzzer.options delete mode 100644 oss-fuzz/mruby.dict diff --git a/oss-fuzz/config/mruby.dict b/oss-fuzz/config/mruby.dict new file mode 100644 index 000000000..a332d3505 --- /dev/null +++ b/oss-fuzz/config/mruby.dict @@ -0,0 +1,105 @@ +keyword___ENCODING__="__ENCODING__" +keyword___FILE__="__FILE__" +keyword___LINE__="__LINE__" +keyword_BEGIN="BEGIN" +keyword_END="END" +keyword_alias="alias" +keyword_and="and" +keyword_begin="begin" +keyword_break="break" +keyword_case="case" +keyword_class="class" +keyword_def="def" +keyword_do="do" +keyword_else="else" +keyword_elsif="elsif" +keyword_end="end" +keyword_ensure="ensure" +keyword_false="false" +keyword_for="for" +keyword_if="if" +keyword_in="in" +keyword_module="module" +keyword_next="next" +keyword_nil="nil" +keyword_not="not" +keyword_or="or" +keyword_redo="redo" +keyword_rescue="rescue" +keyword_retry="retry" +keyword_return="return" +keyword_self="self" +keyword_super="super" +keyword_then="then" +keyword_true="true" +keyword_undef="undef" +keyword_unless="unless" +keyword_until="until" +keyword_when="when" +keyword_while="while" +keyword_yield="yield" + +operator_a=" !" +operator_b=" ~" +operator_c=" +" +operator_d=" -" +operator_e=" []" +operator_f=" []=" +operator_g=" *" +operator_h=" /" +operator_i=" %" +operator_j=" +-" +operator_k=" >>" +operator_l=" <<" +operator_m=" &" +operator_n=" ^" +operator_o=" |" +operator_p=" <=" +operator_q=" <>" +operator_r=" >=" +operator_s=" <=>" +operator_t=" ==" +operator_u=" ===" +operator_v=" !=" +operator_w=" =~" +operator_x=" !~" +operator_y=" &&" +operator_z=" ||" +operator_aa=" .." +operator_ab=" ..." +operator_ac=" ?" +operator_ad=" :" +operator_ae=" =" +operator_af=" %=" +operator_ag=" /=" +operator_ah=" -=" +operator_ai=" +=" +operator_aj=" |=" +operator_ak=" &=" +operator_al=" >>=" +operator_am=" <<=" +operator_an=" *=" +operator_ao=" &&=" +operator_ap=" ||=" +operator_aq=" **=" +operator_ar=" ^=" +operator_as=" not" +operator_at=" or" +operator_au=" and" +operator_av=" if" +operator_aw=" unless" +operator_ax=" while" +operator_ay=" until" +operator_az=" begin" +operator_ba=" end" + +snippet_1eq1=" 1=1" +snippet_dollar=" $1" +snippet_at=" @a" +snippet_symbol=" :a" +snippet_array=" [1,2]" +snippet_block=" 1.times{|x| x}" +snippet_multi=" 1*1" + +string_single_q=" 'a'" +string_dbl_q=" \"a\"" diff --git a/oss-fuzz/config/mruby_fuzzer.options b/oss-fuzz/config/mruby_fuzzer.options new file mode 100644 index 000000000..5d1c8d2da --- /dev/null +++ b/oss-fuzz/config/mruby_fuzzer.options @@ -0,0 +1,3 @@ +[libfuzzer] +close_fd_mask=3 +dict=mruby.dict diff --git a/oss-fuzz/mruby.dict b/oss-fuzz/mruby.dict deleted file mode 100644 index a332d3505..000000000 --- a/oss-fuzz/mruby.dict +++ /dev/null @@ -1,105 +0,0 @@ -keyword___ENCODING__="__ENCODING__" -keyword___FILE__="__FILE__" -keyword___LINE__="__LINE__" -keyword_BEGIN="BEGIN" -keyword_END="END" -keyword_alias="alias" -keyword_and="and" -keyword_begin="begin" -keyword_break="break" -keyword_case="case" -keyword_class="class" -keyword_def="def" -keyword_do="do" -keyword_else="else" -keyword_elsif="elsif" -keyword_end="end" -keyword_ensure="ensure" -keyword_false="false" -keyword_for="for" -keyword_if="if" -keyword_in="in" -keyword_module="module" -keyword_next="next" -keyword_nil="nil" -keyword_not="not" -keyword_or="or" -keyword_redo="redo" -keyword_rescue="rescue" -keyword_retry="retry" -keyword_return="return" -keyword_self="self" -keyword_super="super" -keyword_then="then" -keyword_true="true" -keyword_undef="undef" -keyword_unless="unless" -keyword_until="until" -keyword_when="when" -keyword_while="while" -keyword_yield="yield" - -operator_a=" !" -operator_b=" ~" -operator_c=" +" -operator_d=" -" -operator_e=" []" -operator_f=" []=" -operator_g=" *" -operator_h=" /" -operator_i=" %" -operator_j=" +-" -operator_k=" >>" -operator_l=" <<" -operator_m=" &" -operator_n=" ^" -operator_o=" |" -operator_p=" <=" -operator_q=" <>" -operator_r=" >=" -operator_s=" <=>" -operator_t=" ==" -operator_u=" ===" -operator_v=" !=" -operator_w=" =~" -operator_x=" !~" -operator_y=" &&" -operator_z=" ||" -operator_aa=" .." -operator_ab=" ..." -operator_ac=" ?" -operator_ad=" :" -operator_ae=" =" -operator_af=" %=" -operator_ag=" /=" -operator_ah=" -=" -operator_ai=" +=" -operator_aj=" |=" -operator_ak=" &=" -operator_al=" >>=" -operator_am=" <<=" -operator_an=" *=" -operator_ao=" &&=" -operator_ap=" ||=" -operator_aq=" **=" -operator_ar=" ^=" -operator_as=" not" -operator_at=" or" -operator_au=" and" -operator_av=" if" -operator_aw=" unless" -operator_ax=" while" -operator_ay=" until" -operator_az=" begin" -operator_ba=" end" - -snippet_1eq1=" 1=1" -snippet_dollar=" $1" -snippet_at=" @a" -snippet_symbol=" :a" -snippet_array=" [1,2]" -snippet_block=" 1.times{|x| x}" -snippet_multi=" 1*1" - -string_single_q=" 'a'" -string_dbl_q=" \"a\"" -- cgit v1.2.3 From b6850f88a1de68599e48e2c08b996d96eed5ea33 Mon Sep 17 00:00:00 2001 From: take-cheeze Date: Thu, 6 Dec 2018 11:47:17 +0900 Subject: Support lock file for git. --- Rakefile | 14 ++++++++++++++ lib/mruby/build.rb | 12 ++++++++++-- lib/mruby/build/command.rb | 30 +++++++++++++++++++----------- lib/mruby/build/load_gems.rb | 30 ++++++++++++++++++++++-------- 4 files changed, 65 insertions(+), 21 deletions(-) diff --git a/Rakefile b/Rakefile index 20b6096f5..e18f15c97 100644 --- a/Rakefile +++ b/Rakefile @@ -8,12 +8,19 @@ MRUBY_BUILD_HOST_IS_OPENBSD = RUBY_PLATFORM.include?('openbsd') $LOAD_PATH << File.join(MRUBY_ROOT, "lib") # load build systems +require 'yaml' require "mruby-core-ext" require "mruby/build" require "mruby/gem" # load configuration file MRUBY_CONFIG = (ENV['MRUBY_CONFIG'] && ENV['MRUBY_CONFIG'] != '') ? ENV['MRUBY_CONFIG'] : "#{MRUBY_ROOT}/build_config.rb" +MRUBY_CONFIG_LOCK_FILE = "#{MRUBY_CONFIG}.lock" +MRUBY_CONFIG_LOCK = if File.exist? MRUBY_CONFIG_LOCK_FILE + YAML.load File.read MRUBY_CONFIG_LOCK_FILE + else + {} + end load MRUBY_CONFIG # load basic rules @@ -115,6 +122,13 @@ task :all => depfiles do MRuby.each_target do print_build_summary end + + locks_result = { 'builds' => {} } + MRuby.each_target do + locks_result['builds'][name] = locks + end + + File.write MRUBY_CONFIG_LOCK_FILE, YAML.dump(locks_result) end desc "run all mruby tests" diff --git a/lib/mruby/build.rb b/lib/mruby/build.rb index e2d9fc41e..ae17d372c 100644 --- a/lib/mruby/build.rb +++ b/lib/mruby/build.rb @@ -45,7 +45,7 @@ module MRuby include Rake::DSL include LoadGems attr_accessor :name, :bins, :exts, :file_separator, :build_dir, :gem_clone_dir - attr_reader :libmruby_objs, :gems, :toolchains + attr_reader :libmruby_objs, :gems, :toolchains, :locks attr_writer :enable_bintest, :enable_test alias libmruby libmruby_objs @@ -70,7 +70,7 @@ module MRuby @file_separator = '/' @build_dir = "#{build_dir}/#{@name}" - @gem_clone_dir = "#{build_dir}/mrbgems" + @gem_clone_dir = "#{@build_dir}/repos" @cc = Command::Compiler.new(self, %w(.c)) @cxx = Command::Compiler.new(self, %w(.cc .cxx .cpp)) @objc = Command::Compiler.new(self, %w(.m)) @@ -92,6 +92,10 @@ module MRuby @enable_test = false @toolchains = [] + @locks = MRUBY_CONFIG_LOCK['builds'][@name] if MRUBY_CONFIG_LOCK['builds'] + @locks ||= {} + @enable_lock = true + MRuby.targets[@name] = self end @@ -118,6 +122,10 @@ module MRuby @enable_debug = true end + def disable_lock + @enable_lock = false + end + def disable_cxx_exception if @cxx_exception_enabled or @cxx_abi_enabled raise "cxx_exception already enabled" diff --git a/lib/mruby/build/command.rb b/lib/mruby/build/command.rb index 694b4a24c..e3dc0d78c 100644 --- a/lib/mruby/build/command.rb +++ b/lib/mruby/build/command.rb @@ -243,15 +243,16 @@ module MRuby class Command::Git < Command attr_accessor :flags - attr_accessor :clone_options, :pull_options, :checkout_options + attr_accessor :clone_options, :pull_options, :checkout_options, :reset_options def initialize(build) super @command = 'git' @flags = %w[] @clone_options = "clone %{flags} %{url} %{dir}" - @pull_options = "pull" - @checkout_options = "checkout %{checksum_hash}" + @pull_options = "--git-dir '%{repo_dir}/.git' --work-tree '%{repo_dir}' pull" + @checkout_options = "--git-dir '%{repo_dir}/.git' --work-tree '%{repo_dir}' checkout %{checksum_hash}" + @reset_options = "--git-dir '%{repo_dir}/.git' --work-tree '%{repo_dir}' reset %{checksum_hash}" end def run_clone(dir, url, _flags = []) @@ -260,19 +261,26 @@ module MRuby end def run_pull(dir, url) - root = Dir.pwd - Dir.chdir dir _pp "GIT PULL", url, dir.relative_path - _run pull_options - Dir.chdir root + _run pull_options, { :repo_dir => dir } end def run_checkout(dir, checksum_hash) - root = Dir.pwd - Dir.chdir dir _pp "GIT CHECKOUT", checksum_hash - _run checkout_options, { :checksum_hash => checksum_hash } - Dir.chdir root + _run checkout_options, { :checksum_hash => checksum_hash, :repo_dir => dir } + end + + def run_reset_hard(dir, checksum_hash) + _pp "GIT RESET", checksum_hash + _run reset_options, { :checksum_hash => checksum_hash, :repo_dir => dir } + end + + def commit_hash(dir) + `#{@command} --git-dir '#{dir}/.git' --work-tree '#{dir}' rev-parse --verify HEAD`.strip + end + + def current_branch(dir) + `#{@command} --git-dir '#{dir}/.git' --work-tree '#{dir}' rev-parse --abbrev-ref HEAD`.strip end end diff --git a/lib/mruby/build/load_gems.rb b/lib/mruby/build/load_gems.rb index 723be6ffc..481f91a94 100644 --- a/lib/mruby/build/load_gems.rb +++ b/lib/mruby/build/load_gems.rb @@ -83,11 +83,18 @@ module MRuby # by default the 'master' branch is used branch = params[:branch] ? params[:branch] : 'master' + lock = @locks[url] if @enable_lock + if File.exist?(gemdir) if $pull_gems git.run_pull gemdir, url - else - gemdir + # Jump to the top of the branch + git.run_checkout(gemdir, branch) + git.run_reset_hard gemdir, "origin/#{branch}" + elsif params[:checksum_hash] + git.run_reset_hard(gemdir, params[:checksum_hash]) + elsif lock + git.run_reset_hard(gemdir, lock['commit']) end else options = [params[:options]] || [] @@ -96,14 +103,21 @@ module MRuby options << "--depth 1" unless params[:checksum_hash] FileUtils.mkdir_p "#{gem_clone_dir}" git.run_clone gemdir, url, options - end - if params[:checksum_hash] # Jump to the specified commit - git.run_checkout gemdir, params[:checksum_hash] - else - # Jump to the top of the branch - git.run_checkout gemdir, branch if $pull_gems + if params[:checksum_hash] + git.run_reset_hard gemdir, params[:checksum_hash] + elsif lock + git.run_reset_hard gemdir, lock['commit'] + end + end + + if @enable_lock + @locks[url] = { + 'url' => url, + 'branch' => git.current_branch(gemdir), + 'commit' => git.commit_hash(gemdir), + } end gemdir << "/#{params[:path]}" if params[:path] -- cgit v1.2.3 From 465fdde52d7c70f07534f7de0c6e3d63b45b3553 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Thu, 31 Jan 2019 21:25:35 +0900 Subject: `Enumerator#size` is not supported [ci skip] --- mrbgems/mruby-enumerator/mrblib/enumerator.rb | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) diff --git a/mrbgems/mruby-enumerator/mrblib/enumerator.rb b/mrbgems/mruby-enumerator/mrblib/enumerator.rb index cbf53974a..76b4add72 100644 --- a/mrbgems/mruby-enumerator/mrblib/enumerator.rb +++ b/mrbgems/mruby-enumerator/mrblib/enumerator.rb @@ -89,7 +89,6 @@ class Enumerator include Enumerable ## - # @overload initialize(size = nil, &block) # @overload initialize(obj, method = :each, *args) # # Creates a new Enumerator object, which can be used as an @@ -561,15 +560,10 @@ module Kernel # call-seq: # obj.to_enum(method = :each, *args) -> enum # obj.enum_for(method = :each, *args) -> enum - # obj.to_enum(method = :each, *args) {|*args| block} -> enum - # obj.enum_for(method = :each, *args){|*args| block} -> enum # # Creates a new Enumerator which will enumerate by calling +method+ on # +obj+, passing +args+ if any. # - # If a block is given, it will be used to calculate the size of - # the enumerator without the need to iterate it (see Enumerator#size). - # # === Examples # # str = "xyz" @@ -587,17 +581,14 @@ module Kernel # It is typical to call to_enum when defining methods for # a generic Enumerable, in case no block is passed. # - # Here is such an example, with parameter passing and a sizing block: + # Here is such an example with parameter passing: # # module Enumerable # # a generic method to repeat the values of any enumerable # def repeat(n) # raise ArgumentError, "#{n} is negative!" if n < 0 # unless block_given? - # return to_enum(__method__, n) do # __method__ is :repeat here - # sz = size # Call size and multiply by n... - # sz * n if sz # but return nil if size itself is nil - # end + # return to_enum(__method__, n) # __method__ is :repeat here # end # each do |*val| # n.times { yield *val } -- cgit v1.2.3 From 55cb625808ab9b498d42d13442f5ce5115d606a5 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Mon, 1 Apr 2019 19:49:30 +0900 Subject: Fix modifiable class name Fix the following example: Object.const_set :A, Module.new{const_set :B, Class.new} ab = A::B.to_s p ab #=> "A::B" # Good ab[0] = "x" p A::B.to_s #=> "x::B" # Bad --- src/variable.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/variable.c b/src/variable.c index 724b153fe..9edfb32bd 100644 --- a/src/variable.c +++ b/src/variable.c @@ -1106,6 +1106,7 @@ mrb_class_find_path(mrb_state *mrb, struct RClass *c) iv_del(mrb, c->iv, mrb_intern_lit(mrb, "__outer__"), NULL); iv_put(mrb, c->iv, mrb_intern_lit(mrb, "__classname__"), path); mrb_field_write_barrier_value(mrb, (struct RBasic*)c, path); + path = mrb_str_dup(mrb, path); } return path; } -- cgit v1.2.3 From 9b7e9addcdd517d66f9dca7506027ff05ecce206 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Tue, 2 Apr 2019 16:24:07 +0900 Subject: Pad leading zero to month and day in `MRUBY_RELEASE_DATE` For Ruby compatibility. --- include/mruby/version.h | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/include/mruby/version.h b/include/mruby/version.h index 680533ab4..da7a2eb9d 100644 --- a/include/mruby/version.h +++ b/include/mruby/version.h @@ -77,7 +77,21 @@ MRB_BEGIN_DECL /* * Release date as a string. */ -#define MRUBY_RELEASE_DATE MRB_STRINGIZE(MRUBY_RELEASE_YEAR) "-" MRB_STRINGIZE(MRUBY_RELEASE_MONTH) "-" MRB_STRINGIZE(MRUBY_RELEASE_DAY) +#define MRUBY_RELEASE_DATE \ + MRUBY_RELEASE_YEAR_STR "-" \ + MRUBY_RELEASE_MONTH_STR "-" \ + MRUBY_RELEASE_DAY_STR +#define MRUBY_RELEASE_YEAR_STR MRB_STRINGIZE(MRUBY_RELEASE_YEAR) +#if MRUBY_RELEASE_MONTH < 10 +#define MRUBY_RELEASE_MONTH_STR "0" MRB_STRINGIZE(MRUBY_RELEASE_MONTH) +#else +#define MRUBY_RELEASE_MONTH_STR MRB_STRINGIZE(MRUBY_RELEASE_MONTH) +#endif +#if MRUBY_RELEASE_DAY < 10 +#define MRUBY_RELEASE_DAY_STR "0" MRB_STRINGIZE(MRUBY_RELEASE_DAY) +#else +#define MRUBY_RELEASE_DAY_STR MRB_STRINGIZE(MRUBY_RELEASE_DAY) +#endif /* * The year mruby was first created. -- cgit v1.2.3 From abc6c990a636058f41f9d34f12451036cb9c89fd Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Wed, 3 Apr 2019 18:54:25 +0900 Subject: Remove unnecessary `_set_output_format` call Three-digit exponent issue was fixed via another workaround (63b8f5c). --- src/state.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/state.c b/src/state.c index c3ce1dc33..08d7ba906 100644 --- a/src/state.c +++ b/src/state.c @@ -42,10 +42,6 @@ mrb_open_core(mrb_allocf f, void *ud) mrb_init_core(mrb); -#if !defined(MRB_DISABLE_STDIO) && defined(_MSC_VER) && _MSC_VER < 1900 - _set_output_format(_TWO_DIGIT_EXPONENT); -#endif - return mrb; } -- cgit v1.2.3 From 5e0caefa58bb0fae4174858abb3ba8cd7ccf7058 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Wed, 3 Apr 2019 19:25:06 +0900 Subject: Modify `#else` and `#endif` annotations in `src/fmt_fp.c` [ci skip] --- src/fmt_fp.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/fmt_fp.c b/src/fmt_fp.c index 14c74ef9e..1f1af6764 100644 --- a/src/fmt_fp.c +++ b/src/fmt_fp.c @@ -372,7 +372,7 @@ mrb_float_to_str(mrb_state *mrb, mrb_value flo, const char *fmt) } return f.str; } -#else /* MRB_DISABLE_STDIO */ +#else /* MRB_DISABLE_STDIO || _WIN32 || _WIN64 */ #include #include @@ -384,5 +384,5 @@ mrb_float_to_str(mrb_state *mrb, mrb_value flo, const char *fmt) snprintf(buf, sizeof(buf), fmt, mrb_float(flo)); return mrb_str_new_cstr(mrb, buf); } -#endif /* MRB_DISABLE_STDIO */ +#endif /* MRB_DISABLE_STDIO || _WIN32 || _WIN64 */ #endif -- cgit v1.2.3 From ed41bbb199fb614bb68423d19d26c09c5027319a Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Thu, 4 Apr 2019 22:17:26 +0900 Subject: Use `mrb_proc_arity` instead of `Proc#arity` call in `Method#arity` --- include/mruby/proc.h | 1 + mrbgems/mruby-method/src/method.c | 15 ++------- src/proc.c | 69 +++++++++++++++++++++------------------ 3 files changed, 40 insertions(+), 45 deletions(-) diff --git a/include/mruby/proc.h b/include/mruby/proc.h index 021f9c117..a8b16db1d 100644 --- a/include/mruby/proc.h +++ b/include/mruby/proc.h @@ -86,6 +86,7 @@ struct RProc *mrb_closure_new(mrb_state*, mrb_irep*); MRB_API struct RProc *mrb_proc_new_cfunc(mrb_state*, mrb_func_t); MRB_API struct RProc *mrb_closure_new_cfunc(mrb_state *mrb, mrb_func_t func, int nlocals); void mrb_proc_copy(struct RProc *a, struct RProc *b); +mrb_int mrb_proc_arity(const struct RProc *p); /* implementation of #send method */ mrb_value mrb_f_send(mrb_state *mrb, mrb_value self); diff --git a/mrbgems/mruby-method/src/method.c b/mrbgems/mruby-method/src/method.c index fa8985694..9f1134227 100644 --- a/mrbgems/mruby-method/src/method.c +++ b/mrbgems/mruby-method/src/method.c @@ -212,19 +212,8 @@ static mrb_value method_arity(mrb_state *mrb, mrb_value self) { mrb_value proc = mrb_iv_get(mrb, self, mrb_intern_lit(mrb, "proc")); - struct RProc *rproc; - struct RClass *orig; - mrb_value ret; - - if (mrb_nil_p(proc)) - return mrb_fixnum_value(-1); - - rproc = mrb_proc_ptr(proc); - orig = rproc->c; - rproc->c = mrb->proc_class; - ret = mrb_funcall(mrb, proc, "arity", 0); - rproc->c = orig; - return ret; + mrb_int arity = mrb_nil_p(proc) ? -1 : mrb_proc_arity(mrb_proc_ptr(proc)); + return mrb_fixnum_value(arity); } static mrb_value diff --git a/src/proc.c b/src/proc.c index dab95e465..bf3f01504 100644 --- a/src/proc.c +++ b/src/proc.c @@ -221,38 +221,9 @@ mrb_proc_cfunc_p(struct RProc *p) /* 15.2.17.4.2 */ static mrb_value -mrb_proc_arity(mrb_state *mrb, mrb_value self) +proc_arity(mrb_state *mrb, mrb_value self) { - struct RProc *p = mrb_proc_ptr(self); - struct mrb_irep *irep; - mrb_code *pc; - mrb_aspec aspec; - int ma, op, ra, pa, arity; - - if (MRB_PROC_CFUNC_P(p)) { - /* TODO cfunc aspec not implemented yet */ - return mrb_fixnum_value(-1); - } - - irep = p->body.irep; - if (!irep) { - return mrb_fixnum_value(0); - } - - pc = irep->iseq; - /* arity is depend on OP_ENTER */ - if (*pc != OP_ENTER) { - return mrb_fixnum_value(0); - } - - aspec = PEEK_W(pc+1); - ma = MRB_ASPEC_REQ(aspec); - op = MRB_ASPEC_OPT(aspec); - ra = MRB_ASPEC_REST(aspec); - pa = MRB_ASPEC_POST(aspec); - arity = ra || (MRB_PROC_STRICT_P(p) && op) ? -(ma + pa + 1) : ma + pa; - - return mrb_fixnum_value(arity); + return mrb_fixnum_value(mrb_proc_arity(mrb_proc_ptr(self))); } /* 15.3.1.2.6 */ @@ -287,6 +258,40 @@ proc_lambda(mrb_state *mrb, mrb_value self) return blk; } +mrb_int +mrb_proc_arity(const struct RProc *p) +{ + struct mrb_irep *irep; + mrb_code *pc; + mrb_aspec aspec; + int ma, op, ra, pa, arity; + + if (MRB_PROC_CFUNC_P(p)) { + /* TODO cfunc aspec not implemented yet */ + return -1; + } + + irep = p->body.irep; + if (!irep) { + return 0; + } + + pc = irep->iseq; + /* arity is depend on OP_ENTER */ + if (*pc != OP_ENTER) { + return 0; + } + + aspec = PEEK_W(pc+1); + ma = MRB_ASPEC_REQ(aspec); + op = MRB_ASPEC_OPT(aspec); + ra = MRB_ASPEC_REST(aspec); + pa = MRB_ASPEC_POST(aspec); + arity = ra || (MRB_PROC_STRICT_P(p) && op) ? -(ma + pa + 1) : ma + pa; + + return arity; +} + void mrb_init_proc(mrb_state *mrb) { @@ -303,7 +308,7 @@ mrb_init_proc(mrb_state *mrb) mrb_define_class_method(mrb, mrb->proc_class, "new", mrb_proc_s_new, MRB_ARGS_NONE()|MRB_ARGS_BLOCK()); mrb_define_method(mrb, mrb->proc_class, "initialize_copy", mrb_proc_init_copy, MRB_ARGS_REQ(1)); - mrb_define_method(mrb, mrb->proc_class, "arity", mrb_proc_arity, MRB_ARGS_NONE()); + mrb_define_method(mrb, mrb->proc_class, "arity", proc_arity, MRB_ARGS_NONE()); p = mrb_proc_new(mrb, call_irep); MRB_METHOD_FROM_PROC(m, p); -- cgit v1.2.3 From 623e15936a6c8b8ecaf9dca341be80c9316fd8be Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Fri, 5 Apr 2019 19:03:46 +0900 Subject: `Module#alias_method` should return `self` in ISO standard --- src/class.c | 2 +- test/t/module.rb | 11 +++++++++++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/src/class.c b/src/class.c index 5c5ee9d17..eaef787f7 100644 --- a/src/class.c +++ b/src/class.c @@ -1843,7 +1843,7 @@ mrb_mod_alias(mrb_state *mrb, mrb_value mod) mrb_get_args(mrb, "nn", &new_name, &old_name); mrb_alias_method(mrb, c, new_name, old_name); - return mrb_nil_value(); + return mod; } void diff --git a/test/t/module.rb b/test/t/module.rb index ec36855e8..da0f78fad 100644 --- a/test/t/module.rb +++ b/test/t/module.rb @@ -25,6 +25,17 @@ assert('Module', '15.2.2') do assert_equal Class, Module.class end +assert('Module#alias_method', '15.2.2.4.8') do + cls = Class.new do + def foo + "FOO" + end + end + + assert_same(cls, cls.alias_method(:bar, :foo)) + assert_equal("FOO", cls.new.bar) +end + # TODO not implemented ATM assert('Module.constants', '15.2.2.3.1') do assert('Module#ancestors', '15.2.2.4.9') do -- cgit v1.2.3 From 271a91c64815900338f0f9c152f9f3dabab8246d Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Sat, 6 Apr 2019 16:32:27 +0900 Subject: Remove unused `mrb_proc_cfunc_p()` --- src/proc.c | 6 ------ src/vm.c | 2 +- 2 files changed, 1 insertion(+), 7 deletions(-) diff --git a/src/proc.c b/src/proc.c index bf3f01504..094fff816 100644 --- a/src/proc.c +++ b/src/proc.c @@ -213,12 +213,6 @@ mrb_proc_init_copy(mrb_state *mrb, mrb_value self) return self; } -int -mrb_proc_cfunc_p(struct RProc *p) -{ - return MRB_PROC_CFUNC_P(p); -} - /* 15.2.17.4.2 */ static mrb_value proc_arity(mrb_state *mrb, mrb_value self) diff --git a/src/vm.c b/src/vm.c index a381de21f..60d5dee14 100644 --- a/src/vm.c +++ b/src/vm.c @@ -1004,7 +1004,7 @@ void mrb_hash_check_kdict(mrb_state *mrb, mrb_value self); MRB_API mrb_value mrb_vm_exec(mrb_state *mrb, struct RProc *proc, mrb_code *pc) { - /* mrb_assert(mrb_proc_cfunc_p(proc)) */ + /* mrb_assert(MRB_PROC_CFUNC_P(proc)) */ mrb_code *pc0 = pc; mrb_irep *irep = proc->body.irep; mrb_value *pool = irep->pool; -- cgit v1.2.3 From 5adef8ba44b92ca01692451e21af5c3f47e8853c Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Sat, 6 Apr 2019 17:40:51 +0900 Subject: Move `Array#(append|prepend)` from core to `mruby-ary-ext` They are not included in ISO standard. --- mrbgems/mruby-array-ext/mrblib/array.rb | 3 +++ src/array.c | 2 -- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/mrbgems/mruby-array-ext/mrblib/array.rb b/mrbgems/mruby-array-ext/mrblib/array.rb index 387bd6c90..59b6087d2 100644 --- a/mrbgems/mruby-array-ext/mrblib/array.rb +++ b/mrbgems/mruby-array-ext/mrblib/array.rb @@ -936,4 +936,7 @@ class Array end h end + + alias append push + alias prepend unshift end diff --git a/src/array.c b/src/array.c index 707820ab9..43f4c98b5 100644 --- a/src/array.c +++ b/src/array.c @@ -1286,7 +1286,6 @@ mrb_init_array(mrb_state *mrb) mrb_define_method(mrb, a, "length", mrb_ary_size, MRB_ARGS_NONE()); /* 15.2.12.5.19 */ mrb_define_method(mrb, a, "pop", mrb_ary_pop, MRB_ARGS_NONE()); /* 15.2.12.5.21 */ mrb_define_method(mrb, a, "push", mrb_ary_push_m, MRB_ARGS_ANY()); /* 15.2.12.5.22 */ - mrb_define_method(mrb, a, "append", mrb_ary_push_m, MRB_ARGS_ANY()); mrb_define_method(mrb, a, "replace", mrb_ary_replace_m, MRB_ARGS_REQ(1)); /* 15.2.12.5.23 */ mrb_define_method(mrb, a, "reverse", mrb_ary_reverse, MRB_ARGS_NONE()); /* 15.2.12.5.24 */ mrb_define_method(mrb, a, "reverse!", mrb_ary_reverse_bang, MRB_ARGS_NONE()); /* 15.2.12.5.25 */ @@ -1295,7 +1294,6 @@ mrb_init_array(mrb_state *mrb) mrb_define_method(mrb, a, "size", mrb_ary_size, MRB_ARGS_NONE()); /* 15.2.12.5.28 */ mrb_define_method(mrb, a, "slice", mrb_ary_aget, MRB_ARGS_ANY()); /* 15.2.12.5.29 */ mrb_define_method(mrb, a, "unshift", mrb_ary_unshift_m, MRB_ARGS_ANY()); /* 15.2.12.5.30 */ - mrb_define_method(mrb, a, "prepend", mrb_ary_unshift_m, MRB_ARGS_ANY()); mrb_define_method(mrb, a, "__ary_eq", mrb_ary_eq, MRB_ARGS_REQ(1)); mrb_define_method(mrb, a, "__ary_cmp", mrb_ary_cmp, MRB_ARGS_REQ(1)); -- cgit v1.2.3 From f65b35dc9f5428e7d07b304c01c7836d5be7ec52 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Sun, 7 Apr 2019 21:31:12 +0900 Subject: Fix test for `Array#slice` --- test/t/array.rb | 37 ++++++++++++++++++++++++++++++++----- 1 file changed, 32 insertions(+), 5 deletions(-) diff --git a/test/t/array.rb b/test/t/array.rb index 2b19fe0d4..3df99056f 100644 --- a/test/t/array.rb +++ b/test/t/array.rb @@ -298,11 +298,38 @@ assert('Array#size', '15.2.12.5.28') do end assert('Array#slice', '15.2.12.5.29') do - a = "12345".slice(1, 3) - b = a.slice(0) - - assert_equal("2:", "#{b}:") - assert_equal(2, [1,2,3].[](1)) + a = [*(1..100)] + b = a.dup + + assert_equal(1, a.slice(0)) + assert_equal(100, a.slice(99)) + assert_nil(a.slice(100)) + assert_equal(100, a.slice(-1)) + assert_equal(99, a.slice(-2)) + assert_equal(1, a.slice(-100)) + assert_nil(a.slice(-101)) + assert_equal([1], a.slice(0,1)) + assert_equal([100], a.slice(99,1)) + assert_equal([], a.slice(100,1)) + assert_equal([100], a.slice(99,100)) + assert_equal([100], a.slice(-1,1)) + assert_equal([99], a.slice(-2,1)) + assert_equal([10, 11, 12], a.slice(9, 3)) + assert_equal([10, 11, 12], a.slice(-91, 3)) + assert_nil(a.slice(-101, 2)) + assert_equal([1], a.slice(0..0)) + assert_equal([100], a.slice(99..99)) + assert_equal([], a.slice(100..100)) + assert_equal([100], a.slice(99..200)) + assert_equal([100], a.slice(-1..-1)) + assert_equal([99], a.slice(-2..-2)) + assert_equal([10, 11, 12], a.slice(9..11)) + assert_equal([10, 11, 12], a.slice(-91..-89)) + assert_equal([10, 11, 12], a.slice(-91..-89)) + assert_nil(a.slice(-101..-1)) + assert_nil(a.slice(10, -3)) + assert_equal([], a.slice(10..7)) + assert_equal(b, a) end assert('Array#unshift', '15.2.12.5.30') do -- cgit v1.2.3 From 6cec0c9f62c176e9bd926d12551b384315e98388 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Mon, 8 Apr 2019 19:02:45 +0900 Subject: Fix C99 style inline declaration; fix #4365 --- src/numeric.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/numeric.c b/src/numeric.c index 4128ea3a6..742df7b76 100644 --- a/src/numeric.c +++ b/src/numeric.c @@ -207,12 +207,12 @@ flo_to_s(mrb_state *mrb, mrb_value flt) char fmt[] = "%." MRB_STRINGIZE(FLO_TO_STR_PREC) "g"; mrb_value str = mrb_float_to_str(mrb, flt, fmt); mrb_int len; - char *begp; + char *begp, *p, *endp; insert_dot_zero: begp = RSTRING_PTR(str); len = RSTRING_LEN(str); - for (char *p = begp, *endp = p + len; p < endp; ++p) { + for (p = begp, endp = p + len; p < endp; ++p) { if (*p == '.') { return str; } -- cgit v1.2.3 From ec1688807ef301483321919778b2ccb578822767 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Mon, 8 Apr 2019 19:04:56 +0900 Subject: Avoid using `snprintf` when `MRB_DISABLE_STDIO` is set; fix #4173 --- mrbgems/mruby-compiler/core/parse.y | 90 ++++++++++++++++++++++++++++--------- 1 file changed, 68 insertions(+), 22 deletions(-) diff --git a/mrbgems/mruby-compiler/core/parse.y b/mrbgems/mruby-compiler/core/parse.y index 88d9ea4ee..f6c77859a 100644 --- a/mrbgems/mruby-compiler/core/parse.y +++ b/mrbgems/mruby-compiler/core/parse.y @@ -220,6 +220,25 @@ parser_strdup(parser_state *p, const char *s) #undef strdup #define strdup(s) parser_strdup(p, s) +static void +itoa(short i, char *s) +{ + char *p = s; + char *t = s; + + while (i > 0) { + *p++ = (i % 10)+'0'; + i /= 10; + } + if (p == s) *p++ = '0'; + *p = 0; + p--; /* point the last char */ + while (t < p) { + char c = *t; + *t++ = *p; + *p-- = c; + } +} /* xxx ----------------------------- */ static node* @@ -3172,7 +3191,7 @@ var_ref : variable { char buf[16]; - snprintf(buf, sizeof(buf), "%d", p->lineno); + itoa(p->lineno, buf); $$ = new_int(p, buf, 10); } | keyword__ENCODING__ @@ -3692,11 +3711,12 @@ yyerror(parser_state *p, const char *s) } static void -yyerror_i(parser_state *p, const char *fmt, int i) +yyerror_c(parser_state *p, const char *msg, char c) { char buf[256]; - snprintf(buf, sizeof(buf), fmt, i); + strcpy(buf, msg); + strcat(buf, &c); yyerror(p, buf); } @@ -3735,11 +3755,13 @@ yywarning(parser_state *p, const char *s) } static void -yywarning_s(parser_state *p, const char *fmt, const char *s) +yywarning_s(parser_state *p, const char *msg, const char *s) { char buf[256]; - snprintf(buf, sizeof(buf), fmt, s); + strcpy(buf, msg); + strcat(buf, ": "); + strcat(buf, s); yywarning(p, buf); } @@ -3751,10 +3773,10 @@ backref_error(parser_state *p, node *n) c = intn(n->car); if (c == NODE_NTH_REF) { - yyerror_i(p, "can't set variable $%" MRB_PRId, intn(n->cdr)); + yyerror_c(p, "can't set variable $", (char)intn(n->cdr)+'0'); } else if (c == NODE_BACK_REF) { - yyerror_i(p, "can't set variable $%c", intn(n->cdr)); + yyerror_c(p, "can't set variable $", (char)intn(n->cdr)); } else { mrb_bug(p->mrb, "Internal error in backref_error() : n=>car == %S", mrb_fixnum_value(c)); @@ -4298,7 +4320,15 @@ parse_string(parser_state *p) } if (c < 0) { char buf[256]; - snprintf(buf, sizeof(buf), "can't find heredoc delimiter \"%s\" anywhere before EOF", hinf->term); + const char s1[] = "can't find heredoc delimiter \""; + const char s2[] = "\" anywhere before EOF"; + + if (sizeof(s1)+sizeof(s2)+strlen(hinf->term)+1 >= sizeof(buf)) { + yyerror(p, "can't find heredoc delimiter anywhere before EOF"); + } + strcpy(buf, s1); + strcat(buf, hinf->term); + strcat(buf, s2); yyerror(p, buf); return 0; } @@ -4449,9 +4479,14 @@ parse_string(parser_state *p) pushback(p, re_opt); if (toklen(p)) { char msg[128]; + + strcpy(msg, "unknown regexp option"); tokfix(p); - snprintf(msg, sizeof(msg), "unknown regexp option%s - %s", - toklen(p) > 1 ? "s" : "", tok(p)); + if (toklen(p) > 1) { + strcat(msg, "s"); + } + strcat(msg, " - "); + strcat(msg, tok(p)); yyerror(p, msg); } if (f != 0) { @@ -4879,7 +4914,10 @@ parser_yylex(parser_state *p) } if (c2) { char buf[256]; - snprintf(buf, sizeof(buf), "invalid character syntax; use ?\\%c", c2); + char cc = (char)c2; + + strcpy(buf, "invalid character syntax; use ?\\"); + strcat(buf, &cc); yyerror(p, buf); } } @@ -5252,7 +5290,7 @@ parser_yylex(parser_state *p) pushback(p, c); if (nondigit) { trailing_uc: - yyerror_i(p, "trailing '%c' in number", nondigit); + yyerror_c(p, "trailing non digit in number: ", (char)nondigit); } tokfix(p); if (is_float) { @@ -5267,10 +5305,10 @@ parser_yylex(parser_state *p) errno = 0; d = mrb_float_read(tok(p), &endp); if (d == 0 && endp == tok(p)) { - yywarning_s(p, "corrupted float value %s", tok(p)); + yywarning_s(p, "corrupted float value", tok(p)); } else if (errno == ERANGE) { - yywarning_s(p, "float %s out of range", tok(p)); + yywarning_s(p, "float out of range", tok(p)); errno = 0; } pylval.nd = new_float(p, tok(p)); @@ -5612,7 +5650,7 @@ parser_yylex(parser_state *p) { unsigned long n = strtoul(tok(p), NULL, 10); if (n > INT_MAX) { - yyerror_i(p, "capture group index must be <= %d", INT_MAX); + yyerror(p, "capture group index must be <= " MRB_STRINGIZE(INT_MAX)); return 0; } pylval.nd = new_nth_ref(p, (int)n); @@ -5649,10 +5687,10 @@ parser_yylex(parser_state *p) } else if (ISDIGIT(c)) { if (p->tidx == 1) { - yyerror_i(p, "'@%c' is not allowed as an instance variable name", c); + yyerror_c(p, "wrong instance variable name: @", c); } else { - yyerror_i(p, "'@@%c' is not allowed as a class variable name", c); + yyerror_c(p, "wrong class variable name: @@", c); } return 0; } @@ -5668,7 +5706,14 @@ parser_yylex(parser_state *p) default: if (!identchar(c)) { - yyerror_i(p, "Invalid char '\\x%02X' in expression", c); + char buf[36]; + const char s[] = "Invalid char in expression: 0x"; + + strcpy(buf, s); + buf[sizeof(s)] = (c & 0xff00) >> 8; + buf[sizeof(s)+1] = (c & 0xff); + buf[sizeof(s)+2] = 0; + yyerror(p, buf); goto retry; } @@ -6097,11 +6142,12 @@ mrb_load_exec(mrb_state *mrb, struct mrb_parser_state *p, mrbc_context *c) if (c) c->parser_nerr = p->nerr; if (p->capture_errors) { char buf[256]; - int n; - n = snprintf(buf, sizeof(buf), "line %d: %s\n", - p->error_buffer[0].lineno, p->error_buffer[0].message); - mrb->exc = mrb_obj_ptr(mrb_exc_new(mrb, E_SYNTAX_ERROR, buf, n)); + strcpy(buf, "line "); + itoa(p->error_buffer[0].lineno, buf+5); + strcat(buf, ": "); + strcat(buf, p->error_buffer[0].message); + mrb->exc = mrb_obj_ptr(mrb_exc_new(mrb, E_SYNTAX_ERROR, buf, strlen(buf))); mrb_parser_free(p); return mrb_undef_value(); } -- cgit v1.2.3 From 292bffb32e7434b4725f39924adf0e9f8af5d1cf Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Mon, 8 Apr 2019 20:27:28 +0900 Subject: Avoid infinite loop when no `Regexp` class is available; fix #4363 --- mrblib/string.rb | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/mrblib/string.rb b/mrblib/string.rb index 64e85c5b6..62c925885 100644 --- a/mrblib/string.rb +++ b/mrblib/string.rb @@ -242,25 +242,27 @@ class String end end + def _regexp(re, mid) + if String === re + if Object.const_defined?(:Regexp) + return Regexp.new(re) + else + raise NotImplementedError, "String##{mid} needs Regexp class" + end + end + re + end + ## # ISO 15.2.10.5.3 def =~(re) - re =~ self + _regexp(re, :=~) =~ self end ## # ISO 15.2.10.5.27 def match(re, &block) - if String === re - if Object.const_defined?(:Regexp) - r = Regexp.new(re) - r.match(self, &block) - else - raise NotImplementedError, "String#match needs Regexp class" - end - else - re.match(self, &block) - end + _regexp(re, :match).match(self, &block) end end -- cgit v1.2.3 From f89fe04d546a0c18ae45a3b2045343143feab19c Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Mon, 8 Apr 2019 22:34:49 +0900 Subject: Remove unneeded function prototypes --- include/mruby.h | 3 --- 1 file changed, 3 deletions(-) diff --git a/include/mruby.h b/include/mruby.h index 5b0d84cd3..df26cdbc2 100644 --- a/include/mruby.h +++ b/include/mruby.h @@ -1083,9 +1083,6 @@ MRB_API mrb_value mrb_Float(mrb_state *mrb, mrb_value val); MRB_API mrb_value mrb_inspect(mrb_state *mrb, mrb_value obj); MRB_API mrb_bool mrb_eql(mrb_state *mrb, mrb_value obj1, mrb_value obj2); -static inline int mrb_gc_arena_save(mrb_state*); -static inline void mrb_gc_arena_restore(mrb_state*,int); - static inline int mrb_gc_arena_save(mrb_state *mrb) { -- cgit v1.2.3 From e3beef065c2de80a843f329599b424676d83086c Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Tue, 9 Apr 2019 18:23:11 +0900 Subject: Extract frozen checking to function --- include/mruby.h | 6 ++++++ mrbgems/mruby-struct/src/struct.c | 5 +---- src/array.c | 4 +--- src/class.c | 7 +------ src/error.c | 7 +++++++ src/hash.c | 5 +---- src/string.c | 12 ++---------- src/variable.c | 4 +--- 8 files changed, 20 insertions(+), 30 deletions(-) diff --git a/include/mruby.h b/include/mruby.h index 5b0d84cd3..939601b4d 100644 --- a/include/mruby.h +++ b/include/mruby.h @@ -1143,6 +1143,7 @@ MRB_API mrb_noreturn void mrb_exc_raise(mrb_state *mrb, mrb_value exc); MRB_API mrb_noreturn void mrb_raise(mrb_state *mrb, struct RClass *c, const char *msg); MRB_API mrb_noreturn void mrb_raisef(mrb_state *mrb, struct RClass *c, const char *fmt, ...); MRB_API mrb_noreturn void mrb_name_error(mrb_state *mrb, mrb_sym id, const char *fmt, ...); +MRB_API mrb_noreturn void mrb_frozen_error(mrb_state *mrb, void *frozen_obj); MRB_API void mrb_warn(mrb_state *mrb, const char *fmt, ...); MRB_API mrb_noreturn void mrb_bug(mrb_state *mrb, const char *fmt, ...); MRB_API void mrb_print_backtrace(mrb_state *mrb); @@ -1196,6 +1197,11 @@ MRB_API mrb_value mrb_to_int(mrb_state *mrb, mrb_value val); MRB_API mrb_value mrb_to_str(mrb_state *mrb, mrb_value val); MRB_API void mrb_check_type(mrb_state *mrb, mrb_value x, enum mrb_vtype t); +static inline void mrb_check_frozen(mrb_state *mrb, void *o) +{ + if (MRB_FROZEN_P((struct RBasic*)o)) mrb_frozen_error(mrb, o); +} + typedef enum call_type { CALL_PUBLIC, CALL_FCALL, diff --git a/mrbgems/mruby-struct/src/struct.c b/mrbgems/mruby-struct/src/struct.c index c0ce71219..1df135a9f 100644 --- a/mrbgems/mruby-struct/src/struct.c +++ b/mrbgems/mruby-struct/src/struct.c @@ -87,10 +87,7 @@ mrb_struct_s_members_m(mrb_state *mrb, mrb_value klass) static void mrb_struct_modify(mrb_state *mrb, mrb_value strct) { - if (MRB_FROZEN_P(mrb_basic_ptr(strct))) { - mrb_raise(mrb, E_FROZEN_ERROR, "can't modify frozen struct"); - } - + mrb_check_frozen(mrb, mrb_basic_ptr(strct)); mrb_write_barrier(mrb, mrb_basic_ptr(strct)); } diff --git a/src/array.c b/src/array.c index 43f4c98b5..d4302cb22 100644 --- a/src/array.c +++ b/src/array.c @@ -120,9 +120,7 @@ ary_fill_with_nil(mrb_value *ptr, mrb_int size) static void ary_modify_check(mrb_state *mrb, struct RArray *a) { - if (MRB_FROZEN_P(a)) { - mrb_raise(mrb, E_FROZEN_ERROR, "can't modify frozen array"); - } + mrb_check_frozen(mrb, a); } static void diff --git a/src/class.c b/src/class.c index eaef787f7..fd56fa399 100644 --- a/src/class.c +++ b/src/class.c @@ -441,12 +441,7 @@ mrb_define_method_raw(mrb_state *mrb, struct RClass *c, mrb_sym mid, mrb_method_ MRB_CLASS_ORIGIN(c); h = c->mt; - if (MRB_FROZEN_P(c)) { - if (c->tt == MRB_TT_MODULE) - mrb_raise(mrb, E_FROZEN_ERROR, "can't modify frozen module"); - else - mrb_raise(mrb, E_FROZEN_ERROR, "can't modify frozen class"); - } + mrb_check_frozen(mrb, c); if (!h) h = c->mt = kh_init(mt, mrb); k = kh_put(mt, mrb, h, mid); kh_value(h, k) = m; diff --git a/src/error.c b/src/error.c index e69812dda..4c1b67c99 100644 --- a/src/error.c +++ b/src/error.c @@ -484,6 +484,13 @@ mrb_no_method_error(mrb_state *mrb, mrb_sym id, mrb_value args, char const* fmt, mrb_exc_raise(mrb, exc); } +MRB_API mrb_noreturn void +mrb_frozen_error(mrb_state *mrb, void *frozen_obj) +{ + mrb_raisef(mrb, E_FROZEN_ERROR, "can't modify frozen %S", + mrb_obj_value(mrb_class(mrb, mrb_obj_value(frozen_obj)))); +} + void mrb_init_exception(mrb_state *mrb) { diff --git a/src/hash.c b/src/hash.c index fd963c3de..c4820513b 100644 --- a/src/hash.c +++ b/src/hash.c @@ -746,10 +746,7 @@ mrb_hash_set(mrb_state *mrb, mrb_value hash, mrb_value key, mrb_value val) static void mrb_hash_modify(mrb_state *mrb, mrb_value hash) { - if (MRB_FROZEN_P(mrb_hash_ptr(hash))) { - mrb_raise(mrb, E_FROZEN_ERROR, "can't modify frozen hash"); - } - + mrb_check_frozen(mrb, mrb_hash_ptr(hash)); if (!RHASH_TBL(hash)) { RHASH_TBL(hash) = ht_new(mrb); } diff --git a/src/string.c b/src/string.c index 63c592d59..f7a805a94 100644 --- a/src/string.c +++ b/src/string.c @@ -493,20 +493,12 @@ str_index_str(mrb_state *mrb, mrb_value str, mrb_value str2, mrb_int offset) return mrb_str_index(mrb, str, ptr, len, offset); } -static void -check_frozen(mrb_state *mrb, struct RString *s) -{ - if (MRB_FROZEN_P(s)) { - mrb_raise(mrb, E_FROZEN_ERROR, "can't modify frozen string"); - } -} - static mrb_value str_replace(mrb_state *mrb, struct RString *s1, struct RString *s2) { mrb_int len; - check_frozen(mrb, s1); + mrb_check_frozen(mrb, s1); if (s1 == s2) return mrb_obj_value(s1); s1->flags &= ~MRB_STR_NO_UTF; s1->flags |= s2->flags&MRB_STR_NO_UTF; @@ -646,7 +638,7 @@ mrb_locale_from_utf8(const char *utf8, int len) MRB_API void mrb_str_modify(mrb_state *mrb, struct RString *s) { - check_frozen(mrb, s); + mrb_check_frozen(mrb, s); s->flags &= ~MRB_STR_NO_UTF; if (RSTR_SHARED_P(s)) { mrb_shared_string *shared = s->as.heap.aux.shared; diff --git a/src/variable.c b/src/variable.c index 9edfb32bd..cf89a4a02 100644 --- a/src/variable.c +++ b/src/variable.c @@ -346,9 +346,7 @@ mrb_obj_iv_set(mrb_state *mrb, struct RObject *obj, mrb_sym sym, mrb_value v) { iv_tbl *t; - if (MRB_FROZEN_P(obj)) { - mrb_raisef(mrb, E_FROZEN_ERROR, "can't modify frozen %S", mrb_obj_value(obj)); - } + mrb_check_frozen(mrb, obj); assign_class_name(mrb, obj, sym, v); if (!obj->iv) { obj->iv = iv_new(mrb); -- cgit v1.2.3 From 16f86f8ede2f0d33fdd642d734c796b9435a57bf Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Wed, 10 Apr 2019 05:42:36 +0900 Subject: Use the old style declaration; ref #4365 --- src/variable.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/variable.c b/src/variable.c index 9edfb32bd..02e4f38a1 100644 --- a/src/variable.c +++ b/src/variable.c @@ -1116,7 +1116,9 @@ mrb_class_find_path(mrb_state *mrb, struct RClass *c) mrb_bool mrb_ident_p(const char *s, mrb_int len) { - for (mrb_int i = 0; i < len; i++) { + mrb_int i; + + for (i = 0; i < len; i++) { if (!identchar(s[i])) return FALSE; } return TRUE; -- cgit v1.2.3 From d529501cbfd2331c530ca37efa7295d9e627af97 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Wed, 10 Apr 2019 05:55:40 +0900 Subject: Rename `itoa` to `dump_int` to avoid name crash; ref #4173 --- mrbgems/mruby-compiler/core/parse.y | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/mrbgems/mruby-compiler/core/parse.y b/mrbgems/mruby-compiler/core/parse.y index f6c77859a..cb62ec3f2 100644 --- a/mrbgems/mruby-compiler/core/parse.y +++ b/mrbgems/mruby-compiler/core/parse.y @@ -221,7 +221,7 @@ parser_strdup(parser_state *p, const char *s) #define strdup(s) parser_strdup(p, s) static void -itoa(short i, char *s) +dump_int(short i, char *s) { char *p = s; char *t = s; @@ -239,6 +239,7 @@ itoa(short i, char *s) *p-- = c; } } + /* xxx ----------------------------- */ static node* @@ -3191,7 +3192,7 @@ var_ref : variable { char buf[16]; - itoa(p->lineno, buf); + dump_int(p->lineno, buf); $$ = new_int(p, buf, 10); } | keyword__ENCODING__ @@ -6144,7 +6145,7 @@ mrb_load_exec(mrb_state *mrb, struct mrb_parser_state *p, mrbc_context *c) char buf[256]; strcpy(buf, "line "); - itoa(p->error_buffer[0].lineno, buf+5); + dump_int(p->error_buffer[0].lineno, buf+5); strcat(buf, ": "); strcat(buf, p->error_buffer[0].message); mrb->exc = mrb_obj_ptr(mrb_exc_new(mrb, E_SYNTAX_ERROR, buf, strlen(buf))); -- cgit v1.2.3 From b351bdb8d53ef2ff2d91c51e2179103e3c76e9a4 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Wed, 10 Apr 2019 06:00:38 +0900 Subject: Fixed old style declaration; ref #4365 --- mrbgems/mruby-test/driver.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/mrbgems/mruby-test/driver.c b/mrbgems/mruby-test/driver.c index fd180b1bb..fcbe15a56 100644 --- a/mrbgems/mruby-test/driver.c +++ b/mrbgems/mruby-test/driver.c @@ -51,9 +51,10 @@ t_print(mrb_state *mrb, mrb_value self) { mrb_value *argv; mrb_int argc; + mrb_int i; mrb_get_args(mrb, "*!", &argv, &argc); - for (mrb_int i = 0; i < argc; ++i) { + for (i = 0; i < argc; ++i) { mrb_value s = mrb_obj_as_string(mrb, argv[i]); fwrite(RSTRING_PTR(s), RSTRING_LEN(s), 1, stdout); } -- cgit v1.2.3 From 88ac7549c08411b8d96a7ed0ed8ab2299228f28f Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Wed, 10 Apr 2019 17:14:08 +0900 Subject: Remove `MRB_API` from `mrb_instance_new`. --- include/mruby.h | 2 -- include/mruby/class.h | 1 + src/class.c | 2 +- 3 files changed, 2 insertions(+), 3 deletions(-) diff --git a/include/mruby.h b/include/mruby.h index e567e1da4..7026c1f5e 100644 --- a/include/mruby.h +++ b/include/mruby.h @@ -570,8 +570,6 @@ MRB_INLINE mrb_value mrb_class_new_instance(mrb_state *mrb, mrb_int argc, const return mrb_obj_new(mrb,c,argc,argv); } -MRB_API mrb_value mrb_instance_new(mrb_state *mrb, mrb_value cv); - /** * Creates a new instance of Class, Class. * diff --git a/include/mruby/class.h b/include/mruby/class.h index b667e2051..5ac6e5c40 100644 --- a/include/mruby/class.h +++ b/include/mruby/class.h @@ -85,6 +85,7 @@ MRB_API mrb_method_t mrb_method_search_vm(mrb_state*, struct RClass**, mrb_sym); MRB_API mrb_method_t mrb_method_search(mrb_state*, struct RClass*, mrb_sym); MRB_API struct RClass* mrb_class_real(struct RClass* cl); +mrb_value mrb_instance_new(mrb_state *mrb, mrb_value cv); void mrb_class_name_class(mrb_state*, struct RClass*, struct RClass*, mrb_sym); mrb_value mrb_class_find_path(mrb_state*, struct RClass*); diff --git a/src/class.c b/src/class.c index fd56fa399..6f6b3feda 100644 --- a/src/class.c +++ b/src/class.c @@ -1498,7 +1498,7 @@ mrb_instance_alloc(mrb_state *mrb, mrb_value cv) * */ -MRB_API mrb_value +mrb_value mrb_instance_new(mrb_state *mrb, mrb_value cv) { mrb_value obj, blk; -- cgit v1.2.3 From 4776ac50ed39652e56a084475a5d79c1bbccc6c0 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Wed, 10 Apr 2019 19:07:22 +0900 Subject: Remove too aggressive `initialize` call in `mrb_instance_new`. --- src/class.c | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/src/class.c b/src/class.c index 6f6b3feda..d6efdbdc4 100644 --- a/src/class.c +++ b/src/class.c @@ -1505,22 +1505,13 @@ mrb_instance_new(mrb_state *mrb, mrb_value cv) mrb_value *argv; mrb_int argc; mrb_sym init; - mrb_method_t m; mrb_get_args(mrb, "*&", &argv, &argc, &blk); obj = mrb_instance_alloc(mrb, cv); init = mrb_intern_lit(mrb, "initialize"); - m = mrb_method_search(mrb, mrb_class(mrb, obj), init); - if (MRB_METHOD_CFUNC_P(m)) { - mrb_func_t f = MRB_METHOD_CFUNC(m); - if (f != mrb_bob_init) { - f(mrb, obj); - } - } - else { + if (!mrb_func_basic_p(mrb, obj, init, mrb_bob_init)) { mrb_funcall_with_block(mrb, obj, init, argc, argv, blk); } - return obj; } -- cgit v1.2.3 From 7b0ebed033777cd8bdb8e3668e5c49cfe1b69c5d Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Wed, 10 Apr 2019 19:17:00 +0900 Subject: Use `mrb_immediate_p()` in `mrb_obj_freeze()` and `mrb_obj_frozen()` --- src/etc.c | 2 ++ src/kernel.c | 44 ++++++-------------------------------------- test/t/kernel.rb | 17 +++++++++++++++++ 3 files changed, 25 insertions(+), 38 deletions(-) diff --git a/src/etc.c b/src/etc.c index 12d948a55..6c5fb7480 100644 --- a/src/etc.c +++ b/src/etc.c @@ -167,6 +167,7 @@ mrb_word_boxing_float_value(mrb_state *mrb, mrb_float f) v.value.p = mrb_obj_alloc(mrb, MRB_TT_FLOAT, mrb->float_class); v.value.fp->f = f; + MRB_SET_FROZEN_FLAG(v.value.bp); return v; } @@ -177,6 +178,7 @@ mrb_word_boxing_float_pool(mrb_state *mrb, mrb_float f) nf->tt = MRB_TT_FLOAT; nf->c = mrb->float_class; nf->f = f; + MRB_SET_FROZEN_FLAG(nf); return mrb_obj_value(nf); } #endif /* MRB_WITHOUT_FLOAT */ diff --git a/src/kernel.c b/src/kernel.c index 7890e3dac..d9a1d36ce 100644 --- a/src/kernel.c +++ b/src/kernel.c @@ -434,24 +434,11 @@ mrb_obj_extend_m(mrb_state *mrb, mrb_value self) static mrb_value mrb_obj_freeze(mrb_state *mrb, mrb_value self) { - struct RBasic *b; - - switch (mrb_type(self)) { - case MRB_TT_FALSE: - case MRB_TT_TRUE: - case MRB_TT_FIXNUM: - case MRB_TT_SYMBOL: -#ifndef MRB_WITHOUT_FLOAT - case MRB_TT_FLOAT: -#endif - return self; - default: - break; - } - - b = mrb_basic_ptr(self); - if (!MRB_FROZEN_P(b)) { - MRB_SET_FROZEN_FLAG(b); + if (!mrb_immediate_p(self)) { + struct RBasic *b = mrb_basic_ptr(self); + if (!MRB_FROZEN_P(b)) { + MRB_SET_FROZEN_FLAG(b); + } } return self; } @@ -459,26 +446,7 @@ mrb_obj_freeze(mrb_state *mrb, mrb_value self) static mrb_value mrb_obj_frozen(mrb_state *mrb, mrb_value self) { - struct RBasic *b; - - switch (mrb_type(self)) { - case MRB_TT_FALSE: - case MRB_TT_TRUE: - case MRB_TT_FIXNUM: - case MRB_TT_SYMBOL: -#ifndef MRB_WITHOUT_FLOAT - case MRB_TT_FLOAT: -#endif - return mrb_true_value(); - default: - break; - } - - b = mrb_basic_ptr(self); - if (!MRB_FROZEN_P(b)) { - return mrb_false_value(); - } - return mrb_true_value(); + return mrb_bool_value(mrb_immediate_p(self) || MRB_FROZEN_P(mrb_basic_ptr(self))); } /* 15.3.1.3.15 */ diff --git a/test/t/kernel.rb b/test/t/kernel.rb index d99358c0c..bf7dbe94c 100644 --- a/test/t/kernel.rb +++ b/test/t/kernel.rb @@ -247,6 +247,23 @@ assert('Kernel#freeze') do assert_equal obj, obj.freeze assert_equal 0, 0.freeze assert_equal :a, :a.freeze + assert_equal true, true.freeze + assert_equal false, false.freeze + assert_equal nil, nil.freeze + skip unless Object.const_defined?(:Float) + assert_equal 0.0, 0.0.freeze +end + +assert('Kernel#frozen?') do + assert_false "".frozen? + assert_true "".freeze.frozen? + assert_true 0.frozen? + assert_true :a.frozen? + assert_true true.frozen? + assert_true false.frozen? + assert_true nil.frozen? + skip unless Object.const_defined?(:Float) + assert_true 0.0.frozen? end assert('Kernel#global_variables', '15.3.1.3.14') do -- cgit v1.2.3 From 0c9c3f08ee2c62f6f1b4ce9968a4d12e2ea60276 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Thu, 11 Apr 2019 21:42:18 +0900 Subject: Remove incorrect flags updating in `mrb_regexp_p()` --- src/etc.c | 1 - 1 file changed, 1 deletion(-) diff --git a/src/etc.c b/src/etc.c index 6c5fb7480..d15b398dd 100644 --- a/src/etc.c +++ b/src/etc.c @@ -205,7 +205,6 @@ mrb_regexp_p(mrb_state *mrb, mrb_value v) return mrb_obj_is_kind_of(mrb, v, mrb_class_get(mrb, REGEXP_CLASS)); } else { - mrb->flags |= MRB_STATE_REGEXP; mrb->flags |= MRB_STATE_NO_REGEXP; } return FALSE; -- cgit v1.2.3 From 57e617620a4fa8b144dd87e94dc22ae2acd87679 Mon Sep 17 00:00:00 2001 From: Clayton Smith Date: Thu, 11 Apr 2019 20:07:43 -0400 Subject: Fix buffer overflows in parser. --- mrbgems/mruby-compiler/core/parse.y | 27 +++++++++++++++------------ 1 file changed, 15 insertions(+), 12 deletions(-) diff --git a/mrbgems/mruby-compiler/core/parse.y b/mrbgems/mruby-compiler/core/parse.y index cb62ec3f2..ca4c90770 100644 --- a/mrbgems/mruby-compiler/core/parse.y +++ b/mrbgems/mruby-compiler/core/parse.y @@ -3716,8 +3716,9 @@ yyerror_c(parser_state *p, const char *msg, char c) { char buf[256]; - strcpy(buf, msg); - strcat(buf, &c); + strncpy(buf, msg, sizeof(buf) - 2); + buf[sizeof(buf) - 2] = '\0'; + strncat(buf, &c, 1); yyerror(p, buf); } @@ -3760,9 +3761,10 @@ yywarning_s(parser_state *p, const char *msg, const char *s) { char buf[256]; - strcpy(buf, msg); - strcat(buf, ": "); - strcat(buf, s); + strncpy(buf, msg, sizeof(buf) - 1); + buf[sizeof(buf) - 1] = '\0'; + strncat(buf, ": ", sizeof(buf) - strlen(buf) - 1); + strncat(buf, s, sizeof(buf) - strlen(buf) - 1); yywarning(p, buf); } @@ -4326,11 +4328,12 @@ parse_string(parser_state *p) if (sizeof(s1)+sizeof(s2)+strlen(hinf->term)+1 >= sizeof(buf)) { yyerror(p, "can't find heredoc delimiter anywhere before EOF"); + } else { + strcpy(buf, s1); + strcat(buf, hinf->term); + strcat(buf, s2); + yyerror(p, buf); } - strcpy(buf, s1); - strcat(buf, hinf->term); - strcat(buf, s2); - yyerror(p, buf); return 0; } pylval.nd = new_str(p, tok(p), toklen(p)); @@ -4487,7 +4490,7 @@ parse_string(parser_state *p) strcat(msg, "s"); } strcat(msg, " - "); - strcat(msg, tok(p)); + strncat(msg, tok(p), sizeof(msg) - strlen(msg) - 1); yyerror(p, msg); } if (f != 0) { @@ -4918,7 +4921,7 @@ parser_yylex(parser_state *p) char cc = (char)c2; strcpy(buf, "invalid character syntax; use ?\\"); - strcat(buf, &cc); + strncat(buf, &cc, 1); yyerror(p, buf); } } @@ -6147,7 +6150,7 @@ mrb_load_exec(mrb_state *mrb, struct mrb_parser_state *p, mrbc_context *c) strcpy(buf, "line "); dump_int(p->error_buffer[0].lineno, buf+5); strcat(buf, ": "); - strcat(buf, p->error_buffer[0].message); + strncat(buf, p->error_buffer[0].message, sizeof(buf) - strlen(buf) - 1); mrb->exc = mrb_obj_ptr(mrb_exc_new(mrb, E_SYNTAX_ERROR, buf, strlen(buf))); mrb_parser_free(p); return mrb_undef_value(); -- cgit v1.2.3 From 6626fbc5006d662f8fc69a51660ae7c1e998a1f0 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Fri, 12 Apr 2019 22:27:07 +0900 Subject: Refine `assert_float` Avoid arithmetic operations when `exp` and/or `act` are infinity or NaN. --- test/assert.rb | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/test/assert.rb b/test/assert.rb index c57b04c12..e0fac4d90 100644 --- a/test/assert.rb +++ b/test/assert.rb @@ -149,11 +149,11 @@ end # Fails unless +exp+ is equal to +act+ in terms of a Float def assert_float(exp, act, msg = nil) e, a = exp.to_f, act.to_f - if (e.infinite? || a.infinite?) && e != a || + if e.finite? && a.finite? && (n = (e - a).abs) > Mrbtest::FLOAT_TOLERANCE + flunk(msg, " Expected |#{exp} - #{act}| (#{n}) to be <= #{Mrbtest::FLOAT_TOLERANCE}.") + elsif (e.infinite? || a.infinite?) && e != a || e.nan? && !a.nan? || !e.nan? && a.nan? flunk(msg, " Expected #{act} to be #{exp}.") - elsif (n = (e - a).abs) > Mrbtest::FLOAT_TOLERANCE - flunk(msg, " Expected |#{exp} - #{act}| (#{n}) to be <= #{Mrbtest::FLOAT_TOLERANCE}.") else pass end -- cgit v1.2.3 From 00545fc51d33a9c71d610cc8da5e779cf29487af Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Fri, 12 Apr 2019 22:52:26 +0900 Subject: The number of local variables should be less than 1024; fix #4370 The `env` stores stack length in a 10 bit field. See `MRB_ENV_STACK_LEN()` macro. --- mrbgems/mruby-compiler/core/codegen.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/mrbgems/mruby-compiler/core/codegen.c b/mrbgems/mruby-compiler/core/codegen.c index 927cc3a0f..4bb81f415 100644 --- a/mrbgems/mruby-compiler/core/codegen.c +++ b/mrbgems/mruby-compiler/core/codegen.c @@ -3020,6 +3020,9 @@ scope_finish(codegen_scope *s) mrb_state *mrb = s->mrb; mrb_irep *irep = s->irep; + if (s->nlocals >= 0x3ff) { + codegen_error(s, "too many local variables"); + } irep->flags = 0; if (s->iseq) { irep->iseq = (mrb_code *)codegen_realloc(s, s->iseq, sizeof(mrb_code)*s->pc); -- cgit v1.2.3 From befdf59e610b43e7043b83074a2cc34070ae4e5f Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Fri, 12 Apr 2019 22:54:25 +0900 Subject: Deallocate `s->lines` in `codegen_error`; ref #4370 --- mrbgems/mruby-compiler/core/codegen.c | 1 + 1 file changed, 1 insertion(+) diff --git a/mrbgems/mruby-compiler/core/codegen.c b/mrbgems/mruby-compiler/core/codegen.c index 4bb81f415..b6d35f363 100644 --- a/mrbgems/mruby-compiler/core/codegen.c +++ b/mrbgems/mruby-compiler/core/codegen.c @@ -102,6 +102,7 @@ codegen_error(codegen_scope *s, const char *message) while (s->prev) { codegen_scope *tmp = s->prev; mrb_free(s->mrb, s->iseq); + mrb_free(s->mrb, s->lines); mrb_pool_close(s->mpool); s = tmp; } -- cgit v1.2.3 From 79fd986bcb2c6bc056a08669664c0024d77725f9 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Fri, 12 Apr 2019 23:03:38 +0900 Subject: Small refactoring in `mrb_funcall_with_block`. --- src/vm.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/src/vm.c b/src/vm.c index 60d5dee14..6bd9d53f9 100644 --- a/src/vm.c +++ b/src/vm.c @@ -486,6 +486,7 @@ mrb_funcall_with_block(mrb_state *mrb, mrb_value self, mrb_sym mid, mrb_int argc ci->argc = (int)argc; ci->target_class = c; mrb->c->stack = mrb->c->stack + n; + if (argc < 0) argc = 1; if (mrb->c->stbase <= argv && argv < mrb->c->stend) { voff = argv - mrb->c->stbase; } @@ -500,11 +501,10 @@ mrb_funcall_with_block(mrb_state *mrb, mrb_value self, mrb_sym mid, mrb_int argc ci->argc = -1; argc = 1; } - else { + else if (MRB_METHOD_PROC_P(m)) { struct RProc *p = MRB_METHOD_PROC(m); ci->proc = p; - if (argc < 0) argc = 1; mrb_stack_extend(mrb, p->body.irep->nregs + argc); } if (voff >= 0) { @@ -520,9 +520,6 @@ mrb_funcall_with_block(mrb_state *mrb, mrb_value self, mrb_sym mid, mrb_int argc int ai = mrb_gc_arena_save(mrb); ci->acc = CI_ACC_DIRECT; - if (MRB_METHOD_PROC_P(m)) { - ci->proc = MRB_METHOD_PROC(m); - } val = MRB_METHOD_CFUNC(m)(mrb, self); mrb->c->stack = mrb->c->ci->stackent; cipop(mrb); -- cgit v1.2.3 From f639da0f1c32c20255c32821191697d35350c1ad Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Sat, 13 Apr 2019 18:16:28 +0900 Subject: Fix broken NaN with `MRB_NAN_BOXING` Example: $ bin/mruby -e '(Float::INFINITY - Float::INFINITY).nan?' zsh: segmentation fault Cause: `SET_FLOAT_VALUE` is not used. It is needed for normalizing NaN. Treatment: In my environment, this issue could be reproduced only when `infinity - infinity`, however `SET_FLOAT_VALUE` should be used in all arithmetic operations (regardless of boxing setting), I think. So I fixed all similar codes by extracting to macro. --- src/vm.c | 96 +++++++++++----------------------------------------------------- 1 file changed, 16 insertions(+), 80 deletions(-) diff --git a/src/vm.c b/src/vm.c index 6bd9d53f9..712d39b66 100644 --- a/src/vm.c +++ b/src/vm.c @@ -2214,9 +2214,13 @@ RETRY_TRY_BLOCK: } #define TYPES2(a,b) ((((uint16_t)(a))<<8)|(((uint16_t)(b))&0xff)) -#define OP_MATH_BODY(op,v1,v2) do {\ - v1(regs[a]) = v1(regs[a]) op v2(regs[a+1]);\ -} while(0) +#define OP_MATH_FLOAT_BODY(op,t1,t2) do { \ + RETURN_TYPE_OF_##t1 x = t1(regs[a]); \ + RETURN_TYPE_OF_##t2 y = t2(regs[a+1]); \ + SET_FLOAT_VALUE(mrb, regs[a], x op y); \ +} while (0) +#define RETURN_TYPE_OF_mrb_fixnum mrb_int +#define RETURN_TYPE_OF_mrb_float mrb_float CASE(OP_ADD, B) { /* need to check if op is overridden */ @@ -2239,33 +2243,13 @@ RETRY_TRY_BLOCK: break; #ifndef MRB_WITHOUT_FLOAT case TYPES2(MRB_TT_FIXNUM,MRB_TT_FLOAT): - { - mrb_int x = mrb_fixnum(regs[a]); - mrb_float y = mrb_float(regs[a+1]); - SET_FLOAT_VALUE(mrb, regs[a], (mrb_float)x + y); - } + OP_MATH_FLOAT_BODY(+,mrb_fixnum,mrb_float); break; case TYPES2(MRB_TT_FLOAT,MRB_TT_FIXNUM): -#ifdef MRB_WORD_BOXING - { - mrb_float x = mrb_float(regs[a]); - mrb_int y = mrb_fixnum(regs[a+1]); - SET_FLOAT_VALUE(mrb, regs[a], x + y); - } -#else - OP_MATH_BODY(+,mrb_float,mrb_fixnum); -#endif + OP_MATH_FLOAT_BODY(+,mrb_float,mrb_fixnum); break; case TYPES2(MRB_TT_FLOAT,MRB_TT_FLOAT): -#ifdef MRB_WORD_BOXING - { - mrb_float x = mrb_float(regs[a]); - mrb_float y = mrb_float(regs[a+1]); - SET_FLOAT_VALUE(mrb, regs[a], x + y); - } -#else - OP_MATH_BODY(+,mrb_float,mrb_float); -#endif + OP_MATH_FLOAT_BODY(+,mrb_float,mrb_float); break; #endif case TYPES2(MRB_TT_STRING,MRB_TT_STRING): @@ -2300,33 +2284,13 @@ RETRY_TRY_BLOCK: break; #ifndef MRB_WITHOUT_FLOAT case TYPES2(MRB_TT_FIXNUM,MRB_TT_FLOAT): - { - mrb_int x = mrb_fixnum(regs[a]); - mrb_float y = mrb_float(regs[a+1]); - SET_FLOAT_VALUE(mrb, regs[a], (mrb_float)x - y); - } + OP_MATH_FLOAT_BODY(-,mrb_fixnum,mrb_float); break; case TYPES2(MRB_TT_FLOAT,MRB_TT_FIXNUM): -#ifdef MRB_WORD_BOXING - { - mrb_float x = mrb_float(regs[a]); - mrb_int y = mrb_fixnum(regs[a+1]); - SET_FLOAT_VALUE(mrb, regs[a], x - y); - } -#else - OP_MATH_BODY(-,mrb_float,mrb_fixnum); -#endif + OP_MATH_FLOAT_BODY(-,mrb_float,mrb_fixnum); break; case TYPES2(MRB_TT_FLOAT,MRB_TT_FLOAT): -#ifdef MRB_WORD_BOXING - { - mrb_float x = mrb_float(regs[a]); - mrb_float y = mrb_float(regs[a+1]); - SET_FLOAT_VALUE(mrb, regs[a], x - y); - } -#else - OP_MATH_BODY(-,mrb_float,mrb_float); -#endif + OP_MATH_FLOAT_BODY(-,mrb_float,mrb_float); break; #endif default: @@ -2357,33 +2321,13 @@ RETRY_TRY_BLOCK: break; #ifndef MRB_WITHOUT_FLOAT case TYPES2(MRB_TT_FIXNUM,MRB_TT_FLOAT): - { - mrb_int x = mrb_fixnum(regs[a]); - mrb_float y = mrb_float(regs[a+1]); - SET_FLOAT_VALUE(mrb, regs[a], (mrb_float)x * y); - } + OP_MATH_FLOAT_BODY(*,mrb_fixnum,mrb_float); break; case TYPES2(MRB_TT_FLOAT,MRB_TT_FIXNUM): -#ifdef MRB_WORD_BOXING - { - mrb_float x = mrb_float(regs[a]); - mrb_int y = mrb_fixnum(regs[a+1]); - SET_FLOAT_VALUE(mrb, regs[a], x * y); - } -#else - OP_MATH_BODY(*,mrb_float,mrb_fixnum); -#endif + OP_MATH_FLOAT_BODY(*,mrb_float,mrb_fixnum); break; case TYPES2(MRB_TT_FLOAT,MRB_TT_FLOAT): -#ifdef MRB_WORD_BOXING - { - mrb_float x = mrb_float(regs[a]); - mrb_float y = mrb_float(regs[a+1]); - SET_FLOAT_VALUE(mrb, regs[a], x * y); - } -#else - OP_MATH_BODY(*,mrb_float,mrb_float); -#endif + OP_MATH_FLOAT_BODY(*,mrb_float,mrb_float); break; #endif default: @@ -2466,14 +2410,10 @@ RETRY_TRY_BLOCK: break; #ifndef MRB_WITHOUT_FLOAT case MRB_TT_FLOAT: -#ifdef MRB_WORD_BOXING { mrb_float x = mrb_float(regs[a]); SET_FLOAT_VALUE(mrb, regs[a], x + b); } -#else - mrb_float(regs[a]) += b; -#endif break; #endif default: @@ -2507,14 +2447,10 @@ RETRY_TRY_BLOCK: break; #ifndef MRB_WITHOUT_FLOAT case MRB_TT_FLOAT: -#ifdef MRB_WORD_BOXING { mrb_float x = mrb_float(regs[a]); SET_FLOAT_VALUE(mrb, regs[a], (mrb_float)x - (mrb_float)b); } -#else - mrb_float(regs_a[0]) -= b; -#endif break; #endif default: -- cgit v1.2.3 From 0ebbc491a1ce45b85934be04e5824d69463ca593 Mon Sep 17 00:00:00 2001 From: dearblue Date: Sun, 14 Apr 2019 15:35:51 +0900 Subject: Include `RFiber` and `RIstruct` as a part of `RVALUE` --- src/gc.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/gc.c b/src/gc.c index ec52787e8..798e2c00a 100644 --- a/src/gc.c +++ b/src/gc.c @@ -10,6 +10,7 @@ #include #include #include +#include #include #include #include @@ -109,8 +110,10 @@ typedef struct { struct RHash hash; struct RRange range; struct RData data; + struct RIstruct istruct; struct RProc proc; struct REnv env; + struct RFiber fiber; struct RException exc; struct RBreak brk; #ifdef MRB_WORD_BOXING -- cgit v1.2.3 From c2fa935fee31c201ba4b07e72690e78a3094cf68 Mon Sep 17 00:00:00 2001 From: dearblue Date: Sun, 14 Apr 2019 16:11:21 +0900 Subject: Fix hexdigits convertion --- mrbgems/mruby-compiler/core/parse.y | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/mrbgems/mruby-compiler/core/parse.y b/mrbgems/mruby-compiler/core/parse.y index ca4c90770..f6b883b9e 100644 --- a/mrbgems/mruby-compiler/core/parse.y +++ b/mrbgems/mruby-compiler/core/parse.y @@ -5712,10 +5712,11 @@ parser_yylex(parser_state *p) if (!identchar(c)) { char buf[36]; const char s[] = "Invalid char in expression: 0x"; + const char hexdigits[] = "0123456789ABCDEF"; strcpy(buf, s); - buf[sizeof(s)] = (c & 0xff00) >> 8; - buf[sizeof(s)+1] = (c & 0xff); + buf[sizeof(s)] = hexdigits[(c & 0xf0) >> 4]; + buf[sizeof(s)+1] = hexdigits[(c & 0x0f)]; buf[sizeof(s)+2] = 0; yyerror(p, buf); goto retry; -- cgit v1.2.3 From dac0f3f5e85d067b15c44a933b151acefb2d5598 Mon Sep 17 00:00:00 2001 From: dearblue Date: Sun, 14 Apr 2019 16:16:05 +0900 Subject: Fix string index for appending `sizeof(string-literal)` is included `'\0'` character --- mrbgems/mruby-compiler/core/parse.y | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/mrbgems/mruby-compiler/core/parse.y b/mrbgems/mruby-compiler/core/parse.y index f6b883b9e..7838b6dfb 100644 --- a/mrbgems/mruby-compiler/core/parse.y +++ b/mrbgems/mruby-compiler/core/parse.y @@ -5715,9 +5715,9 @@ parser_yylex(parser_state *p) const char hexdigits[] = "0123456789ABCDEF"; strcpy(buf, s); - buf[sizeof(s)] = hexdigits[(c & 0xf0) >> 4]; - buf[sizeof(s)+1] = hexdigits[(c & 0x0f)]; - buf[sizeof(s)+2] = 0; + buf[sizeof(s)-1] = hexdigits[(c & 0xf0) >> 4]; + buf[sizeof(s)] = hexdigits[(c & 0x0f)]; + buf[sizeof(s)+1] = 0; yyerror(p, buf); goto retry; } -- cgit v1.2.3 From 3f3e4754d931004838278c1483e047a3635ebeb0 Mon Sep 17 00:00:00 2001 From: dearblue Date: Sun, 14 Apr 2019 15:58:11 +0900 Subject: Fix leaked function symbols - `free_heap()` in src/gc.c - `symhash()` in src/symbol.c - `no_optimize()` in mrbgems/mruby-compiler/core/codegen.c --- mrbgems/mruby-compiler/core/codegen.c | 3 +-- src/gc.c | 2 +- src/symbol.c | 2 +- 3 files changed, 3 insertions(+), 4 deletions(-) diff --git a/mrbgems/mruby-compiler/core/codegen.c b/mrbgems/mruby-compiler/core/codegen.c index b6d35f363..ed8fc3150 100644 --- a/mrbgems/mruby-compiler/core/codegen.c +++ b/mrbgems/mruby-compiler/core/codegen.c @@ -273,8 +273,7 @@ genop_W(codegen_scope *s, mrb_code i, uint32_t a) #define NOVAL 0 #define VAL 1 -//static -mrb_bool +static mrb_bool no_optimize(codegen_scope *s) { if (s && s->parser && s->parser->no_optimize) diff --git a/src/gc.c b/src/gc.c index ec52787e8..d07335eca 100644 --- a/src/gc.c +++ b/src/gc.c @@ -396,7 +396,7 @@ mrb_gc_init(mrb_state *mrb, mrb_gc *gc) static void obj_free(mrb_state *mrb, struct RBasic *obj, int end); -void +static void free_heap(mrb_state *mrb, mrb_gc *gc) { mrb_heap_page *page = gc->heaps; diff --git a/src/symbol.c b/src/symbol.c index 96ca9dd17..b26f2b1fd 100644 --- a/src/symbol.c +++ b/src/symbol.c @@ -91,7 +91,7 @@ sym_inline_unpack(mrb_sym sym, char *buf, mrb_int *lenp) } #endif -uint8_t +static uint8_t symhash(const char *key, size_t len) { uint32_t hash, i; -- cgit v1.2.3 From d557f977324bc55ae99205608099a788038712d6 Mon Sep 17 00:00:00 2001 From: dearblue Date: Sun, 14 Apr 2019 17:39:50 +0900 Subject: Remove pointer check after `mrb_malloc()` --- src/variable.c | 1 - 1 file changed, 1 deletion(-) diff --git a/src/variable.c b/src/variable.c index f97b09c52..6899d7475 100644 --- a/src/variable.c +++ b/src/variable.c @@ -87,7 +87,6 @@ iv_put(mrb_state *mrb, iv_tbl *t, mrb_sym sym, mrb_value val) } seg = (segment*)mrb_malloc(mrb, sizeof(segment)); - if (!seg) return; seg->next = NULL; seg->key[0] = sym; seg->val[0] = val; -- cgit v1.2.3 From d8527d17ea504aebcdbd3970127899e0216d46dc Mon Sep 17 00:00:00 2001 From: dearblue Date: Sun, 14 Apr 2019 17:42:35 +0900 Subject: Fix wrong size of instance variable if occur out of memory --- src/variable.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/variable.c b/src/variable.c index 6899d7475..983fe52f7 100644 --- a/src/variable.c +++ b/src/variable.c @@ -79,10 +79,10 @@ iv_put(mrb_state *mrb, iv_tbl *t, mrb_sym sym, mrb_value val) } /* Not found */ - t->size++; if (matched_seg) { matched_seg->key[matched_idx] = sym; matched_seg->val[matched_idx] = val; + t->size++; return; } @@ -91,6 +91,7 @@ iv_put(mrb_state *mrb, iv_tbl *t, mrb_sym sym, mrb_value val) seg->key[0] = sym; seg->val[0] = val; t->last_len = 1; + t->size++; if (prev) { prev->next = seg; } -- cgit v1.2.3 From d328808892bf866f9ad72ba476fcee00edd06293 Mon Sep 17 00:00:00 2001 From: dearblue Date: Sun, 14 Apr 2019 17:55:20 +0900 Subject: Fix memory leak for hash table index if occur out of memory --- src/hash.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hash.c b/src/hash.c index c4820513b..a9367a426 100644 --- a/src/hash.c +++ b/src/hash.c @@ -182,7 +182,7 @@ ht_index(mrb_state *mrb, htable *t) if (!index || index->capa < size) { index = (segindex*)mrb_realloc_simple(mrb, index, sizeof(segindex)+sizeof(struct segkv*)*size); if (index == NULL) { - mrb_free(mrb, index); + mrb_free(mrb, t->index); t->index = NULL; return; } -- cgit v1.2.3 From 716a99b069461b11c2b46099119f8578cd2c8f3f Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Wed, 3 Apr 2019 21:38:47 +0900 Subject: Add `assert_match` and `assert_not_match` --- mrbgems/mruby-test/driver.c | 146 ++++++++++++++++++++++++++++++++++++++++++++ test/assert.rb | 33 ++++++++++ test/t/module.rb | 7 +-- 3 files changed, 181 insertions(+), 5 deletions(-) diff --git a/mrbgems/mruby-test/driver.c b/mrbgems/mruby-test/driver.c index fd180b1bb..9e3dbea9d 100644 --- a/mrbgems/mruby-test/driver.c +++ b/mrbgems/mruby-test/driver.c @@ -62,6 +62,151 @@ t_print(mrb_state *mrb, mrb_value self) return mrb_nil_value(); } +#define UNESCAPE(p, endp) ((p) != (endp) && *(p) == '\\' ? (p)+1 : (p)) +#define CHAR_CMP(c1, c2) ((unsigned char)(c1) - (unsigned char)(c2)) + +static const char * +str_match_bracket(const char *p, const char *pat_end, + const char *s, const char *str_end) +{ + mrb_bool ok = FALSE, negated = FALSE; + + if (p == pat_end) return NULL; + if (*p == '!' || *p == '^') { + negated = TRUE; + ++p; + } + + while (*p != ']') { + const char *t1 = p; + if ((t1 = UNESCAPE(t1, pat_end)) == pat_end) return NULL; + if ((p = t1 + 1) == pat_end) return NULL; + if (p[0] == '-' && p[1] != ']') { + const char *t2 = p + 1; + if ((t2 = UNESCAPE(t2, pat_end)) == pat_end) return NULL; + p = t2 + 1; + if (!ok && CHAR_CMP(*t1, *s) <= 0 && CHAR_CMP(*s, *t2) <= 0) ok = TRUE; + } + else { + if (!ok && CHAR_CMP(*t1, *s) == 0) ok = TRUE; + } + } + + return ok == negated ? NULL : p + 1; +} + +static mrb_bool +str_match_no_brace_p(const char *pat, mrb_int pat_len, + const char *str, mrb_int str_len) +{ + const char *p = pat, *s = str; + const char *pat_end = pat + pat_len, *str_end = str + str_len; + const char *p_tmp = NULL, *s_tmp = NULL; + + for (;;) { + if (p == pat_end) return s == str_end; + switch (*p) { + case '*': + do { ++p; } while (p != pat_end && *p == '*'); + if (UNESCAPE(p, pat_end) == pat_end) return TRUE; + if (s == str_end) return FALSE; + p_tmp = p; + s_tmp = s; + continue; + case '?': + if (s == str_end) return FALSE; + ++p; + ++s; + continue; + case '[': { + const char *t; + if (s == str_end) return FALSE; + if ((t = str_match_bracket(p+1, pat_end, s, str_end))) { + p = t; + ++s; + continue; + } + goto L_failed; + } + } + + /* ordinary */ + p = UNESCAPE(p, pat_end); + if (s == str_end) return p == pat_end; + if (p == pat_end) goto L_failed; + if (*p++ != *s++) goto L_failed; + continue; + + L_failed: + if (p_tmp && s_tmp) { + /* try next '*' position */ + p = p_tmp; + s = ++s_tmp; + continue; + } + + return FALSE; + } +} + +#define COPY_AND_INC(dst, src, len) \ + do { memcpy(dst, src, len); dst += len; } while (0) + +static mrb_bool +str_match_p(mrb_state *mrb, + const char *pat, mrb_int pat_len, + const char *str, mrb_int str_len) +{ + const char *p = pat, *pat_end = pat + pat_len; + const char *lbrace = NULL, *rbrace = NULL; + int nest = 0; + mrb_bool ret = FALSE; + + for (; p != pat_end; ++p) { + if (*p == '{' && nest++ == 0) lbrace = p; + else if (*p == '}' && lbrace && --nest == 0) { rbrace = p; break; } + else if (*p == '\\' && ++p == pat_end) break; + } + + if (lbrace && rbrace) { + /* expand brace */ + char *ex_pat = (char *)mrb_malloc(mrb, pat_len-2); /* expanded pattern */ + char *ex_p = ex_pat; + + COPY_AND_INC(ex_p, pat, lbrace-pat); + p = lbrace; + while (p < rbrace) { + char *orig_ex_p = ex_p; + const char *t = ++p; + for (nest = 0; p < rbrace && !(*p == ',' && nest == 0); ++p) { + if (*p == '{') ++nest; + else if (*p == '}') --nest; + else if (*p == '\\' && ++p == rbrace) break; + } + COPY_AND_INC(ex_p, t, p-t); + COPY_AND_INC(ex_p, rbrace+1, pat_end-rbrace-1); + if ((ret = str_match_p(mrb, ex_pat, ex_p-ex_pat, str, str_len))) break; + ex_p = orig_ex_p; + } + mrb_free(mrb, ex_pat); + } + else if (!lbrace && !rbrace) { + ret = str_match_no_brace_p(pat, pat_len, str, str_len); + } + + return ret; +} + +static mrb_value +m_str_match_p(mrb_state *mrb, mrb_value self) +{ + const char *pat, *str; + mrb_int pat_len, str_len; + + mrb_get_args(mrb, "ss", &pat, &pat_len, &str, &str_len); + return mrb_bool_value(str_match_p(mrb, pat, pat_len, str, str_len)); +} + void mrb_init_test_driver(mrb_state *mrb, mrb_bool verbose) { @@ -69,6 +214,7 @@ mrb_init_test_driver(mrb_state *mrb, mrb_bool verbose) krn = mrb->kernel_module; mrb_define_method(mrb, krn, "t_print", t_print, MRB_ARGS_ANY()); + mrb_define_method(mrb, krn, "_str_match?", m_str_match_p, MRB_ARGS_REQ(2)); mrbtest = mrb_define_module(mrb, "Mrbtest"); diff --git a/test/assert.rb b/test/assert.rb index c57b04c12..4b01bd450 100644 --- a/test/assert.rb +++ b/test/assert.rb @@ -136,6 +136,39 @@ def _assert_include(affirmed, collection, obj, msg = nil) assert_true(ret, msg, diff) end +## +# Fail unless +str+ matches against +pattern+. +# +# +pattern+ is interpreted as pattern for File.fnmatch?. It may contain the +# following metacharacters: +# +# * :: +# Matches any string. +# +# ? :: +# Matches any one character. +# +# [_SET_], [^_SET_] ([!_SET_]) :: +# Matches any one character in _SET_. Behaves like character sets in +# Regexp, including set negation ([^a-z]). +# +# {_A_,_B_} :: +# Matches pattern _A_ or pattern _B_. +# +# \ :: +# Escapes the next character. +def assert_match(*args); _assert_match(true, *args) end +def assert_not_match(*args); _assert_match(false, *args) end +def _assert_match(affirmed, pattern, str, msg = nil) + receiver, *args = RUBY_ENGINE == "mruby" ? + [self, :_str_match?, pattern, str] : + [File, :fnmatch?, pattern, str, File::FNM_EXTGLOB|File::FNM_DOTMATCH] + unless ret = !receiver.__send__(*args) == !affirmed + diff = " Expected #{pattern.inspect} to #{'not ' unless affirmed}match #{str.inspect}." + end + assert_true(ret, msg, diff) +end + ## # Fails unless +obj+ is a kind of +cls+. def assert_kind_of(cls, obj, msg = nil) diff --git a/test/t/module.rb b/test/t/module.rb index ec36855e8..1694ef577 100644 --- a/test/t/module.rb +++ b/test/t/module.rb @@ -640,11 +640,8 @@ assert('Module#to_s') do assert_equal 'SetOuter', SetOuter.to_s assert_equal 'SetOuter::SetInner', SetOuter::SetInner.to_s - mod = Module.new - cls = Class.new - - assert_equal "#", Module.new.to_s + assert_match "#", Class.new.to_s end assert('Module#inspect') do -- cgit v1.2.3 From 30c880bea9ace559ccef50d5ed1a5dbf75659bbf Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Sun, 14 Apr 2019 22:40:17 +0900 Subject: Extract similar codes to macros for math opcode in `mrb_vm_exec` --- src/vm.c | 269 +++++++++++++++++++++------------------------------------------ 1 file changed, 89 insertions(+), 180 deletions(-) diff --git a/src/vm.c b/src/vm.c index 712d39b66..a7ecc575d 100644 --- a/src/vm.c +++ b/src/vm.c @@ -2214,128 +2214,67 @@ RETRY_TRY_BLOCK: } #define TYPES2(a,b) ((((uint16_t)(a))<<8)|(((uint16_t)(b))&0xff)) -#define OP_MATH_FLOAT_BODY(op,t1,t2) do { \ - RETURN_TYPE_OF_##t1 x = t1(regs[a]); \ - RETURN_TYPE_OF_##t2 y = t2(regs[a+1]); \ - SET_FLOAT_VALUE(mrb, regs[a], x op y); \ -} while (0) -#define RETURN_TYPE_OF_mrb_fixnum mrb_int -#define RETURN_TYPE_OF_mrb_float mrb_float +#define OP_MATH(op_name) \ + /* need to check if op is overridden */ \ + switch (TYPES2(mrb_type(regs[a]),mrb_type(regs[a+1]))) { \ + OP_MATH_CASE_FIXNUM(op_name); \ + OP_MATH_CASE_FLOAT(op_name, fixnum, float); \ + OP_MATH_CASE_FLOAT(op_name, float, fixnum); \ + OP_MATH_CASE_FLOAT(op_name, float, float); \ + OP_MATH_CASE_STRING_##op_name(); \ + default: \ + c = 1; \ + mid = mrb_intern_lit(mrb, MRB_STRINGIZE(OP_MATH_OP_##op_name)); \ + goto L_SEND_SYM; \ + } \ + NEXT; +#define OP_MATH_CASE_FIXNUM(op_name) \ + case TYPES2(MRB_TT_FIXNUM, MRB_TT_FIXNUM): \ + { \ + mrb_int x = mrb_fixnum(regs[a]), y = mrb_fixnum(regs[a+1]), z; \ + if (mrb_int_##op_name##_overflow(x, y, &z)) \ + OP_MATH_OVERFLOW_INT(op_name, x, y, z); \ + else \ + SET_INT_VALUE(regs[a], z); \ + } \ + break +#ifdef MRB_WITHOUT_FLOAT +#define OP_MATH_CASE_FLOAT(op_name, t1, t2) (void)0 +#define OP_MATH_OVERFLOW_INT(op_name, x, y, z) SET_INT_VALUE(regs[a], z) +#else +#define OP_MATH_CASE_FLOAT(op_name, t1, t2) \ + case TYPES2(OP_MATH_TT_##t1, OP_MATH_TT_##t2): \ + { \ + mrb_float z = mrb_##t1(regs[a]) OP_MATH_OP_##op_name mrb_##t2(regs[a+1]); \ + SET_FLOAT_VALUE(mrb, regs[a], z); \ + } \ + break +#define OP_MATH_OVERFLOW_INT(op_name, x, y, z) \ + SET_FLOAT_VALUE(mrb, regs[a], (mrb_float)x OP_MATH_OP_##op_name (mrb_float)y) +#endif +#define OP_MATH_CASE_STRING_add() \ + case TYPES2(MRB_TT_STRING, MRB_TT_STRING): \ + regs[a] = mrb_str_plus(mrb, regs[a], regs[a+1]); \ + mrb_gc_arena_restore(mrb, ai); \ + break +#define OP_MATH_CASE_STRING_sub() (void)0 +#define OP_MATH_CASE_STRING_mul() (void)0 +#define OP_MATH_OP_add + +#define OP_MATH_OP_sub - +#define OP_MATH_OP_mul * +#define OP_MATH_TT_fixnum MRB_TT_FIXNUM +#define OP_MATH_TT_float MRB_TT_FLOAT CASE(OP_ADD, B) { - /* need to check if op is overridden */ - switch (TYPES2(mrb_type(regs[a]),mrb_type(regs[a+1]))) { - case TYPES2(MRB_TT_FIXNUM,MRB_TT_FIXNUM): - { - mrb_int x, y, z; - mrb_value *regs_a = regs + a; - - x = mrb_fixnum(regs_a[0]); - y = mrb_fixnum(regs_a[1]); - if (mrb_int_add_overflow(x, y, &z)) { -#ifndef MRB_WITHOUT_FLOAT - SET_FLOAT_VALUE(mrb, regs_a[0], (mrb_float)x + (mrb_float)y); - break; -#endif - } - SET_INT_VALUE(regs[a], z); - } - break; -#ifndef MRB_WITHOUT_FLOAT - case TYPES2(MRB_TT_FIXNUM,MRB_TT_FLOAT): - OP_MATH_FLOAT_BODY(+,mrb_fixnum,mrb_float); - break; - case TYPES2(MRB_TT_FLOAT,MRB_TT_FIXNUM): - OP_MATH_FLOAT_BODY(+,mrb_float,mrb_fixnum); - break; - case TYPES2(MRB_TT_FLOAT,MRB_TT_FLOAT): - OP_MATH_FLOAT_BODY(+,mrb_float,mrb_float); - break; -#endif - case TYPES2(MRB_TT_STRING,MRB_TT_STRING): - regs[a] = mrb_str_plus(mrb, regs[a], regs[a+1]); - break; - default: - c = 1; - mid = mrb_intern_lit(mrb, "+"); - goto L_SEND_SYM; - } - mrb_gc_arena_restore(mrb, ai); - NEXT; + OP_MATH(add); } CASE(OP_SUB, B) { - /* need to check if op is overridden */ - switch (TYPES2(mrb_type(regs[a]),mrb_type(regs[a+1]))) { - case TYPES2(MRB_TT_FIXNUM,MRB_TT_FIXNUM): - { - mrb_int x, y, z; - - x = mrb_fixnum(regs[a]); - y = mrb_fixnum(regs[a+1]); - if (mrb_int_sub_overflow(x, y, &z)) { -#ifndef MRB_WITHOUT_FLOAT - SET_FLOAT_VALUE(mrb, regs[a], (mrb_float)x - (mrb_float)y); - break; -#endif - } - SET_INT_VALUE(regs[a], z); - } - break; -#ifndef MRB_WITHOUT_FLOAT - case TYPES2(MRB_TT_FIXNUM,MRB_TT_FLOAT): - OP_MATH_FLOAT_BODY(-,mrb_fixnum,mrb_float); - break; - case TYPES2(MRB_TT_FLOAT,MRB_TT_FIXNUM): - OP_MATH_FLOAT_BODY(-,mrb_float,mrb_fixnum); - break; - case TYPES2(MRB_TT_FLOAT,MRB_TT_FLOAT): - OP_MATH_FLOAT_BODY(-,mrb_float,mrb_float); - break; -#endif - default: - c = 1; - mid = mrb_intern_lit(mrb, "-"); - goto L_SEND_SYM; - } - NEXT; + OP_MATH(sub); } CASE(OP_MUL, B) { - /* need to check if op is overridden */ - switch (TYPES2(mrb_type(regs[a]),mrb_type(regs[a+1]))) { - case TYPES2(MRB_TT_FIXNUM,MRB_TT_FIXNUM): - { - mrb_int x, y, z; - - x = mrb_fixnum(regs[a]); - y = mrb_fixnum(regs[a+1]); - if (mrb_int_mul_overflow(x, y, &z)) { -#ifndef MRB_WITHOUT_FLOAT - SET_FLOAT_VALUE(mrb, regs[a], (mrb_float)x * (mrb_float)y); - break; -#endif - } - SET_INT_VALUE(regs[a], z); - } - break; -#ifndef MRB_WITHOUT_FLOAT - case TYPES2(MRB_TT_FIXNUM,MRB_TT_FLOAT): - OP_MATH_FLOAT_BODY(*,mrb_fixnum,mrb_float); - break; - case TYPES2(MRB_TT_FLOAT,MRB_TT_FIXNUM): - OP_MATH_FLOAT_BODY(*,mrb_float,mrb_fixnum); - break; - case TYPES2(MRB_TT_FLOAT,MRB_TT_FLOAT): - OP_MATH_FLOAT_BODY(*,mrb_float,mrb_float); - break; -#endif - default: - c = 1; - mid = mrb_intern_lit(mrb, "*"); - goto L_SEND_SYM; - } - NEXT; + OP_MATH(mul); } CASE(OP_DIV, B) { @@ -2390,76 +2329,46 @@ RETRY_TRY_BLOCK: NEXT; } - CASE(OP_ADDI, BB) { - /* need to check if + is overridden */ - switch (mrb_type(regs[a])) { - case MRB_TT_FIXNUM: - { - mrb_int x = mrb_fixnum(regs[a]); - mrb_int y = (mrb_int)b; - mrb_int z; - - if (mrb_int_add_overflow(x, y, &z)) { -#ifndef MRB_WITHOUT_FLOAT - SET_FLOAT_VALUE(mrb, regs[a], (mrb_float)x + (mrb_float)y); - break; -#endif - } - SET_INT_VALUE(regs[a], z); - } - break; -#ifndef MRB_WITHOUT_FLOAT - case MRB_TT_FLOAT: - { - mrb_float x = mrb_float(regs[a]); - SET_FLOAT_VALUE(mrb, regs[a], x + b); - } - break; +#define OP_MATHI(op_name) \ + /* need to check if op is overridden */ \ + switch (mrb_type(regs[a])) { \ + OP_MATHI_CASE_FIXNUM(op_name); \ + OP_MATHI_CASE_FLOAT(op_name); \ + default: \ + SET_INT_VALUE(regs[a+1], b); \ + c = 1; \ + mid = mrb_intern_lit(mrb, MRB_STRINGIZE(OP_MATH_OP_##op_name)); \ + goto L_SEND_SYM; \ + } \ + NEXT; +#define OP_MATHI_CASE_FIXNUM(op_name) \ + case MRB_TT_FIXNUM: \ + { \ + mrb_int x = mrb_fixnum(regs[a]), y = (mrb_int)b, z; \ + if (mrb_int_##op_name##_overflow(x, y, &z)) \ + OP_MATH_OVERFLOW_INT(op_name, x, y, z); \ + else \ + SET_INT_VALUE(regs[a], z); \ + } \ + break +#ifdef MRB_WITHOUT_FLOAT +#define OP_MATHI_CASE_FLOAT(op_name) (void)0 +#else +#define OP_MATHI_CASE_FLOAT(op_name) \ + case MRB_TT_FLOAT: \ + { \ + mrb_float z = mrb_float(regs[a]) OP_MATH_OP_##op_name b; \ + SET_FLOAT_VALUE(mrb, regs[a], z); \ + } \ + break #endif - default: - SET_INT_VALUE(regs[a+1], b); - c = 1; - mid = mrb_intern_lit(mrb, "+"); - goto L_SEND_SYM; - } - NEXT; + + CASE(OP_ADDI, BB) { + OP_MATHI(add); } CASE(OP_SUBI, BB) { - mrb_value *regs_a = regs + a; - - /* need to check if + is overridden */ - switch (mrb_type(regs_a[0])) { - case MRB_TT_FIXNUM: - { - mrb_int x = mrb_fixnum(regs_a[0]); - mrb_int y = (mrb_int)b; - mrb_int z; - - if (mrb_int_sub_overflow(x, y, &z)) { -#ifndef MRB_WITHOUT_FLOAT - SET_FLOAT_VALUE(mrb, regs_a[0], (mrb_float)x - (mrb_float)y); - break; -#endif - } - SET_INT_VALUE(regs_a[0], z); - } - break; -#ifndef MRB_WITHOUT_FLOAT - case MRB_TT_FLOAT: - { - mrb_float x = mrb_float(regs[a]); - SET_FLOAT_VALUE(mrb, regs[a], (mrb_float)x - (mrb_float)b); - } - break; -#endif - default: - SET_INT_VALUE(regs_a[1], b); - c = 1; - mid = mrb_intern_lit(mrb, "-"); - goto L_SEND_SYM; - } - NEXT; + OP_MATHI(sub); } #define OP_CMP_BODY(op,v1,v2) (v1(regs[a]) op v2(regs[a+1])) -- cgit v1.2.3 From 6b8d3c70702948e630536e7c42400e928ed9d773 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Mon, 15 Apr 2019 07:13:19 +0900 Subject: Fixed wrong function names; fix #4380 --- src/numeric.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/numeric.c b/src/numeric.c index 742df7b76..8205e41f6 100644 --- a/src/numeric.c +++ b/src/numeric.c @@ -510,7 +510,7 @@ flo_shift(mrb_state *mrb, mrb_value x, mrb_int width) } static mrb_value -flo_lshift(mrb_state *mrb, mrb_value x) +flo_rshift(mrb_state *mrb, mrb_value x) { mrb_int width; @@ -519,7 +519,7 @@ flo_lshift(mrb_state *mrb, mrb_value x) } static mrb_value -flo_rshift(mrb_state *mrb, mrb_value x) +flo_lshift(mrb_state *mrb, mrb_value x) { mrb_int width; @@ -1608,8 +1608,8 @@ mrb_init_numeric(mrb_state *mrb) mrb_define_method(mrb, fl, "&", flo_and, MRB_ARGS_REQ(1)); mrb_define_method(mrb, fl, "|", flo_or, MRB_ARGS_REQ(1)); mrb_define_method(mrb, fl, "^", flo_xor, MRB_ARGS_REQ(1)); - mrb_define_method(mrb, fl, ">>", flo_lshift, MRB_ARGS_REQ(1)); - mrb_define_method(mrb, fl, "<<", flo_rshift, MRB_ARGS_REQ(1)); + mrb_define_method(mrb, fl, ">>", flo_rshift, MRB_ARGS_REQ(1)); + mrb_define_method(mrb, fl, "<<", flo_lshift, MRB_ARGS_REQ(1)); mrb_define_method(mrb, fl, "ceil", flo_ceil, MRB_ARGS_NONE()); /* 15.2.9.3.8 */ mrb_define_method(mrb, fl, "finite?", flo_finite_p, MRB_ARGS_NONE()); /* 15.2.9.3.9 */ mrb_define_method(mrb, fl, "floor", flo_floor, MRB_ARGS_NONE()); /* 15.2.9.3.10 */ -- cgit v1.2.3 From 164985881b6d7d96218ec5cd986ca1bb4c919698 Mon Sep 17 00:00:00 2001 From: Shouji Kuboyama Date: Mon, 15 Apr 2019 17:16:08 +0900 Subject: Fix test, popen and cmd in mruby-io --- mrbgems/mruby-io/test/io.rb | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/mrbgems/mruby-io/test/io.rb b/mrbgems/mruby-io/test/io.rb index 85852c179..44eaca6be 100644 --- a/mrbgems/mruby-io/test/io.rb +++ b/mrbgems/mruby-io/test/io.rb @@ -3,7 +3,7 @@ assert('IO TEST SETUP') do MRubyIOTestUtil.io_test_setup - $cr = MRubyIOTestUtil.win? ? 1 : 0 # "\n" include CR or not + $cr, $crlf, $cmd = MRubyIOTestUtil.win? ? [1, "\r\n", "cmd /c "] : [0, "\n", ""] end assert('IO', '15.2.20') do @@ -419,7 +419,7 @@ end assert('IO.popen') do begin $? = nil - io = IO.popen("echo mruby-io") + io = IO.popen("#{$cmd}echo mruby-io") assert_true io.close_on_exec? assert_equal Fixnum, io.pid.class @@ -598,7 +598,7 @@ end assert('`cmd`') do begin - assert_equal `echo foo`, "foo\n" + assert_equal `#{$cmd}echo foo`, "foo#{$crlf}" rescue NotImplementedError => e skip e.message end -- cgit v1.2.3 From d53eb8a3779735dc5df8a57f11f150cddf96e877 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Mon, 15 Apr 2019 19:03:39 +0900 Subject: Fix missing assertions in `mruby-random` test --- mrbgems/mruby-random/test/random.rb | 70 ++++++++++++++++++++++++------------- 1 file changed, 45 insertions(+), 25 deletions(-) diff --git a/mrbgems/mruby-random/test/random.rb b/mrbgems/mruby-random/test/random.rb index 1653ae4a6..813e23968 100644 --- a/mrbgems/mruby-random/test/random.rb +++ b/mrbgems/mruby-random/test/random.rb @@ -1,48 +1,66 @@ ## # Random Test -assert("Random#srand") do +assert("Random.new") do r1 = Random.new(123) r2 = Random.new(123) - r1.rand == r2.rand + r3 = Random.new(124) + assert_equal(r1.rand, r2.rand) + assert_not_equal(r1.rand, r3.rand) end -assert("Kernel::srand") do +assert("Kernel.srand") do srand(234) r1 = rand srand(234) r2 = rand - r1 == r2 + srand(235) + r3 = rand + assert_equal(r1, r2) + assert_not_equal(r1, r3) end -assert("Random::srand") do +assert("Random.srand") do Random.srand(345) r1 = rand srand(345) r2 = Random.rand - r1 == r2 + Random.srand(346) + r3 = rand + assert_equal(r1, r2) + assert_not_equal(r1, r3) end -assert("fixnum") do - rand(3).class == Fixnum -end - -assert("float") do - rand.class == Float +assert("return class of Kernel.rand") do + assert_kind_of(Fixnum, rand(3)) + assert_kind_of(Fixnum, rand(1.5)) + assert_kind_of(Float, rand) + assert_kind_of(Float, rand(0.5)) end assert("Array#shuffle") do ary = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] + orig = ary.dup shuffled = ary.shuffle - - ary == [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] and shuffled != ary and 10.times { |x| ary.include? x } + assert_equal(orig, ary) + assert_not_equal(ary, shuffled) + assert_equal(ary.size, shuffled.size) + shuffled.each do |x| + assert_include(ary, x) + ary.delete(x) + end end assert('Array#shuffle!') do ary = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] - ary.shuffle! - - ary != [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] and 10.times { |x| ary.include? x } + orig = ary.dup + assert_same(ary, ary.shuffle!) + assert_not_equal(orig, ary) + assert_equal(orig.size, ary.size) + ary.each do |x| + assert_include(orig, x) + orig.delete(x) + end end assert("Array#shuffle(random)") do @@ -52,12 +70,12 @@ assert("Array#shuffle(random)") do end # verify that the same seed causes the same results - ary1 = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] - shuffle1 = ary1.shuffle Random.new 345 - ary2 = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] - shuffle2 = ary2.shuffle Random.new 345 - - ary1 != shuffle1 and 10.times { |x| shuffle1.include? x } and shuffle1 == shuffle2 + ary = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] + shuffled1 = ary.shuffle Random.new 345 + shuffled2 = ary.shuffle Random.new 345 + shuffled3 = ary.shuffle Random.new 346 + assert_equal(shuffled1, shuffled2) + assert_not_equal(shuffled1, shuffled3) end assert('Array#shuffle!(random)') do @@ -71,6 +89,8 @@ assert('Array#shuffle!(random)') do ary1.shuffle! Random.new 345 ary2 = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] ary2.shuffle! Random.new 345 - - ary1 != [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] and 10.times { |x| ary1.include? x } and ary1 == ary2 + ary3 = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] + ary3.shuffle! Random.new 346 + assert_equal(ary1, ary2) + assert_not_equal(ary1, ary3) end -- cgit v1.2.3 From 4e45e320b05afb500a9acedc5b7a2c19b2b7158d Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Tue, 16 Apr 2019 18:47:46 +0900 Subject: Fixed a bug in recursive `mrb_top_run` calls; fix #4384 --- src/vm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vm.c b/src/vm.c index a7ecc575d..9c07b8caa 100644 --- a/src/vm.c +++ b/src/vm.c @@ -2863,11 +2863,11 @@ mrb_top_run(mrb_state *mrb, struct RProc *proc, mrb_value self, unsigned int sta return mrb_vm_run(mrb, proc, self, stack_keep); } ci = cipush(mrb); + ci->stackent = mrb->c->stack; ci->mid = 0; ci->acc = CI_ACC_SKIP; ci->target_class = mrb->object_class; v = mrb_vm_run(mrb, proc, self, stack_keep); - cipop(mrb); return v; } -- cgit v1.2.3 From 79a7f181507674a6e56846d1dc82fa97341ec544 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Tue, 16 Apr 2019 19:23:30 +0900 Subject: Avoid potential zero size array declaration; fix #4382 --- include/mruby/array.h | 3 +-- tasks/toolchains/clang.rake | 2 ++ 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/include/mruby/array.h b/include/mruby/array.h index 2e6951c0d..0c0a002f5 100644 --- a/include/mruby/array.h +++ b/include/mruby/array.h @@ -33,7 +33,6 @@ struct RArray { } aux; mrb_value *ptr; } heap; - mrb_value embed[MRB_ARY_EMBED_LEN_MAX]; } as; }; @@ -46,7 +45,7 @@ struct RArray { #define ARY_UNSET_EMBED_FLAG(a) ((a)->flags &= ~(MRB_ARY_EMBED_MASK)) #define ARY_EMBED_LEN(a) ((mrb_int)(((a)->flags & MRB_ARY_EMBED_MASK) - 1)) #define ARY_SET_EMBED_LEN(a,len) ((a)->flags = ((a)->flags&~MRB_ARY_EMBED_MASK) | ((uint32_t)(len) + 1)) -#define ARY_EMBED_PTR(a) (&((a)->as.embed[0])) +#define ARY_EMBED_PTR(a) ((mrb_value*)&(a)->as) #define ARY_LEN(a) (ARY_EMBED_P(a)?ARY_EMBED_LEN(a):(a)->as.heap.len) #define ARY_PTR(a) (ARY_EMBED_P(a)?ARY_EMBED_PTR(a):(a)->as.heap.ptr) diff --git a/tasks/toolchains/clang.rake b/tasks/toolchains/clang.rake index 2832dad5f..7d0fe6a45 100644 --- a/tasks/toolchains/clang.rake +++ b/tasks/toolchains/clang.rake @@ -3,7 +3,9 @@ MRuby::Toolchain.new(:clang) do |conf, _params| [conf.cc, conf.objc, conf.asm].each do |cc| cc.command = ENV['CC'] || 'clang' + cc.flags << '-Wzero-length-array' unless ENV['CFLAGS'] end conf.cxx.command = ENV['CXX'] || 'clang++' + conf.cxx.flags << '-Wzero-length-array' unless ENV['CXXFLAGS'] || ENV['CFLAGS'] conf.linker.command = ENV['LD'] || ENV['CXX'] || ENV['CC'] || 'clang' end -- cgit v1.2.3 From 2ae727ac3aacd892f71f32ba4b3f343bd8705e54 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Wed, 17 Apr 2019 21:04:46 +0900 Subject: Add `Array#sample` test And simplify tests for `Array#shuffle` and `Array#shuffle!`. --- mrbgems/mruby-random/test/random.rb | 54 +++++++++++++++++++++++++++---------- 1 file changed, 40 insertions(+), 14 deletions(-) diff --git a/mrbgems/mruby-random/test/random.rb b/mrbgems/mruby-random/test/random.rb index 813e23968..cf4a55141 100644 --- a/mrbgems/mruby-random/test/random.rb +++ b/mrbgems/mruby-random/test/random.rb @@ -39,28 +39,20 @@ assert("return class of Kernel.rand") do end assert("Array#shuffle") do - ary = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] - orig = ary.dup + orig = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] + ary = orig.dup shuffled = ary.shuffle assert_equal(orig, ary) assert_not_equal(ary, shuffled) - assert_equal(ary.size, shuffled.size) - shuffled.each do |x| - assert_include(ary, x) - ary.delete(x) - end + assert_equal(orig, shuffled.sort) end assert('Array#shuffle!') do - ary = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] - orig = ary.dup + orig = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] + ary = orig.dup assert_same(ary, ary.shuffle!) assert_not_equal(orig, ary) - assert_equal(orig.size, ary.size) - ary.each do |x| - assert_include(orig, x) - orig.delete(x) - end + assert_equal(orig, ary.sort) end assert("Array#shuffle(random)") do @@ -94,3 +86,37 @@ assert('Array#shuffle!(random)') do assert_equal(ary1, ary2) assert_not_equal(ary1, ary3) end + +assert('Array#sample') do + 100.times do + assert_include([0, 1, 2], [2, 1, 0].sample) + [2, 1, 0].sample(2).each { |sample| assert_include([0, 1, 2], sample) } + h = {} + (1..10).to_a.sample(7).each do |sample| + assert_not_include(h, sample) + h[sample] = true + end + end + + assert_nil([].sample) + assert_equal([], [].sample(1)) + assert_equal([], [2, 1].sample(0)) + assert_raise(TypeError) { [2, 1].sample(true) } + assert_raise(ArgumentError) { [2, 1].sample(-1) } +end + +assert('Array#sample(random)') do + assert_raise(TypeError) do + # this will cause an exception due to the wrong argument + [1, 2].sample(2, "Not a Random instance") + end + + # verify that the same seed causes the same results + ary = (1..10).to_a + srand(15) + samples1 = ary.sample(4) + samples2 = ary.sample(4, Random.new(15)) + samples3 = ary.sample(4, Random.new(16)) + assert_equal(samples1, samples2) + assert_not_equal(samples1, samples3) +end -- cgit v1.2.3 From 916045921e629b59264a6f1e00e2347e64ef85cb Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Thu, 18 Apr 2019 19:58:05 +0900 Subject: Remove duplicated `include Comparable` in `mrblib/string.rb` --- mrblib/string.rb | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/mrblib/string.rb b/mrblib/string.rb index 62c925885..9ad8e8e73 100644 --- a/mrblib/string.rb +++ b/mrblib/string.rb @@ -3,7 +3,9 @@ # # ISO 15.2.10 class String + # ISO 15.2.10.3 include Comparable + ## # Calls the given block for each line # and pass the respective line. @@ -265,12 +267,3 @@ class String _regexp(re, :match).match(self, &block) end end - -## -# String is comparable -# -# ISO 15.2.10.3 -module Comparable; end -class String - include Comparable -end -- cgit v1.2.3 From 4a8b88f7757f71d7d88b89764b533dd5ba59fd44 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Fri, 19 Apr 2019 20:14:23 +0900 Subject: Add type check (conversion) in `String#[]=` Before this patch: 'a'[0] = 1 #=> 1 'a'[:a] = '1' #=> ArgumentError 'a'[:a, 0] = '1' #=> ArgumentError 'a'[0, :a] = '1' #=> ArgumentError 'a'[0, 1] = 1 #=> 1 After this patch / Ruby: 'a'[0] = 1 #=> TypeError 'a'[:a] = '1' #=> TypeError 'a'[:a, 0] = '1' #=> TypeError 'a'[0, :a] = '1' #=> TypeError 'a'[0, 1] = 1 #=> TypeError --- mrblib/string.rb | 11 ++++++----- test/t/string.rb | 7 +++++++ 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/mrblib/string.rb b/mrblib/string.rb index 9ad8e8e73..e9eb2be1d 100644 --- a/mrblib/string.rb +++ b/mrblib/string.rb @@ -197,12 +197,12 @@ class String def []=(*args) anum = args.size if anum == 2 - pos, value = args + pos, value = args[0], args[1].__to_str case pos when String posnum = self.index(pos) if posnum - b = self[0, posnum.to_i] + b = self[0, posnum] a = self[(posnum + pos.length)..-1] self.replace([b, value, a].join('')) else @@ -217,17 +217,18 @@ class String end return self[head, tail-head]=value else + pos = pos.__to_int pos += self.length if pos < 0 if pos < 0 || pos > self.length raise IndexError, "index #{args[0]} out of string" end - b = self[0, pos.to_i] + b = self[0, pos] a = self[pos + 1..-1] self.replace([b, value, a].join('')) end return value elsif anum == 3 - pos, len, value = args + pos, len, value = args[0].__to_int, args[1].__to_int, args[2].__to_str pos += self.length if pos < 0 if pos < 0 || pos > self.length raise IndexError, "index #{args[0]} out of string" @@ -235,7 +236,7 @@ class String if len < 0 raise IndexError, "negative length #{len}" end - b = self[0, pos.to_i] + b = self[0, pos] a = self[pos + len..-1] self.replace([b, value, a].join('')) return value diff --git a/test/t/string.rb b/test/t/string.rb index cf3702cbe..404cf03e1 100644 --- a/test/t/string.rb +++ b/test/t/string.rb @@ -161,6 +161,9 @@ assert('String#[]=') do assert_equal 'aXc', e end + assert_raise(TypeError) { 'a'[0] = 1 } + assert_raise(TypeError) { 'a'[:a] = '1' } + # length of args is 2 a1 = 'abc' assert_raise(IndexError) do @@ -197,6 +200,10 @@ assert('String#[]=') do assert_raise(IndexError) do b3['XX'] = 'Y' end + + assert_raise(TypeError) { 'a'[:a, 0] = '1' } + assert_raise(TypeError) { 'a'[0, :a] = '1' } + assert_raise(TypeError) { 'a'[0, 1] = 1 } end assert('String#capitalize', '15.2.10.5.7') do -- cgit v1.2.3 From 6907e97fa16507018a3c082fe5621d2662e59e08 Mon Sep 17 00:00:00 2001 From: dearblue Date: Fri, 19 Apr 2019 22:24:22 +0900 Subject: Change modifier to `MRB_INLINE` from `static inline` --- include/mruby.h | 8 ++++---- include/mruby/boxing_word.h | 2 +- include/mruby/class.h | 2 +- include/mruby/data.h | 2 +- include/mruby/value.h | 10 +++++----- 5 files changed, 12 insertions(+), 12 deletions(-) diff --git a/include/mruby.h b/include/mruby.h index 7026c1f5e..de6a803ef 100644 --- a/include/mruby.h +++ b/include/mruby.h @@ -868,7 +868,7 @@ typedef const char *mrb_args_format; */ MRB_API mrb_int mrb_get_args(mrb_state *mrb, mrb_args_format format, ...); -static inline mrb_sym +MRB_INLINE mrb_sym mrb_get_mid(mrb_state *mrb) /* get method symbol */ { return mrb->c->ci->mid; @@ -1081,13 +1081,13 @@ MRB_API mrb_value mrb_Float(mrb_state *mrb, mrb_value val); MRB_API mrb_value mrb_inspect(mrb_state *mrb, mrb_value obj); MRB_API mrb_bool mrb_eql(mrb_state *mrb, mrb_value obj1, mrb_value obj2); -static inline int +MRB_INLINE int mrb_gc_arena_save(mrb_state *mrb) { return mrb->gc.arena_idx; } -static inline void +MRB_INLINE void mrb_gc_arena_restore(mrb_state *mrb, int idx) { mrb->gc.arena_idx = idx; @@ -1192,7 +1192,7 @@ MRB_API mrb_value mrb_to_int(mrb_state *mrb, mrb_value val); MRB_API mrb_value mrb_to_str(mrb_state *mrb, mrb_value val); MRB_API void mrb_check_type(mrb_state *mrb, mrb_value x, enum mrb_vtype t); -static inline void mrb_check_frozen(mrb_state *mrb, void *o) +MRB_INLINE void mrb_check_frozen(mrb_state *mrb, void *o) { if (MRB_FROZEN_P((struct RBasic*)o)) mrb_frozen_error(mrb, o); } diff --git a/include/mruby/boxing_word.h b/include/mruby/boxing_word.h index 3b7167b28..a8eb7da9b 100644 --- a/include/mruby/boxing_word.h +++ b/include/mruby/boxing_word.h @@ -91,7 +91,7 @@ MRB_API mrb_value mrb_word_boxing_float_pool(struct mrb_state*, mrb_float); #define mrb_fixnum(o) ((mrb_int)(o).value.i) #define mrb_symbol(o) (o).value.sym -static inline enum mrb_vtype +MRB_INLINE enum mrb_vtype mrb_type(mrb_value o) { switch (o.w) { diff --git a/include/mruby/class.h b/include/mruby/class.h index 5ac6e5c40..a68724538 100644 --- a/include/mruby/class.h +++ b/include/mruby/class.h @@ -23,7 +23,7 @@ struct RClass { #define mrb_class_ptr(v) ((struct RClass*)(mrb_ptr(v))) -static inline struct RClass* +MRB_INLINE struct RClass* mrb_class(mrb_state *mrb, mrb_value v) { switch (mrb_type(v)) { diff --git a/include/mruby/data.h b/include/mruby/data.h index 415684342..d85edeb3a 100644 --- a/include/mruby/data.h +++ b/include/mruby/data.h @@ -63,7 +63,7 @@ MRB_API void *mrb_data_check_get_ptr(mrb_state *mrb, mrb_value, const mrb_data_t *(void**)&sval = mrb_data_get_ptr(mrb, obj, type); \ } while (0) -static inline void +MRB_INLINE void mrb_data_init(mrb_value v, void *ptr, const mrb_data_type *type) { mrb_assert(mrb_type(v) == MRB_TT_DATA); diff --git a/include/mruby/value.h b/include/mruby/value.h index 1ed20858f..14e342d14 100644 --- a/include/mruby/value.h +++ b/include/mruby/value.h @@ -189,7 +189,7 @@ MRB_INLINE mrb_value mrb_float_value(struct mrb_state *mrb, mrb_float f) } #endif -static inline mrb_value +MRB_INLINE mrb_value mrb_cptr_value(struct mrb_state *mrb, void *p) { mrb_value v; @@ -208,7 +208,7 @@ MRB_INLINE mrb_value mrb_fixnum_value(mrb_int i) return v; } -static inline mrb_value +MRB_INLINE mrb_value mrb_symbol_value(mrb_sym i) { mrb_value v; @@ -216,7 +216,7 @@ mrb_symbol_value(mrb_sym i) return v; } -static inline mrb_value +MRB_INLINE mrb_value mrb_obj_value(void *p) { mrb_value v; @@ -260,7 +260,7 @@ MRB_INLINE mrb_value mrb_true_value(void) return v; } -static inline mrb_value +MRB_INLINE mrb_value mrb_bool_value(mrb_bool boolean) { mrb_value v; @@ -268,7 +268,7 @@ mrb_bool_value(mrb_bool boolean) return v; } -static inline mrb_value +MRB_INLINE mrb_value mrb_undef_value(void) { mrb_value v; -- cgit v1.2.3 From 125c3bef19c364c958173ea27d35ffd683045ee2 Mon Sep 17 00:00:00 2001 From: dearblue Date: Fri, 19 Apr 2019 22:50:05 +0900 Subject: Add `mrb_true_p()` and `mrb_false_p()` macro functions --- include/mruby/boxing_word.h | 2 ++ include/mruby/value.h | 6 ++++++ 2 files changed, 8 insertions(+) diff --git a/include/mruby/boxing_word.h b/include/mruby/boxing_word.h index 3b7167b28..59fdb730d 100644 --- a/include/mruby/boxing_word.h +++ b/include/mruby/boxing_word.h @@ -116,6 +116,8 @@ mrb_type(mrb_value o) #define mrb_fixnum_p(o) ((o).value.i_flag == MRB_FIXNUM_FLAG) #define mrb_undef_p(o) ((o).w == MRB_Qundef) #define mrb_nil_p(o) ((o).w == MRB_Qnil) +#define mrb_false_p(o) ((o).w == MRB_Qfalse) +#define mrb_true_p(o) ((o).w == MRB_Qtrue) #define BOXWORD_SET_VALUE(o, ttt, attr, v) do { \ switch (ttt) {\ diff --git a/include/mruby/value.h b/include/mruby/value.h index 1ed20858f..8530950a9 100644 --- a/include/mruby/value.h +++ b/include/mruby/value.h @@ -157,6 +157,12 @@ typedef void mrb_value; #ifndef mrb_nil_p #define mrb_nil_p(o) (mrb_type(o) == MRB_TT_FALSE && !mrb_fixnum(o)) #endif +#ifndef mrb_false_p +#define mrb_false_p(o) (mrb_type(o) == MRB_TT_FALSE && !!mrb_fixnum(o)) +#endif +#ifndef mrb_true_p +#define mrb_true_p(o) (mrb_type(o) == MRB_TT_TRUE) +#endif #ifndef mrb_bool #define mrb_bool(o) (mrb_type(o) != MRB_TT_FALSE) #endif -- cgit v1.2.3 From 73bb144ef0dcf1f3dc4e721e0fd2d557f18cfe07 Mon Sep 17 00:00:00 2001 From: Rob Date: Fri, 19 Apr 2019 14:27:12 -0400 Subject: Fixes the twiddle wakka comparison algorithm to support passing only a major number --- lib/mruby/gem.rb | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/lib/mruby/gem.rb b/lib/mruby/gem.rb index ce2e01ab1..95c1d4bc3 100644 --- a/lib/mruby/gem.rb +++ b/lib/mruby/gem.rb @@ -267,16 +267,18 @@ module MRuby # ~> compare algorithm # # Example: + # ~> 2 means >= 2.0.0 and < 3.0.0 # ~> 2.2 means >= 2.2.0 and < 3.0.0 - # ~> 2.2.0 means >= 2.2.0 and < 2.3.0 + # ~> 2.2.2 means >= 2.2.2 and < 2.3.0 def twiddle_wakka_ok?(other) gr_or_eql = (self <=> other) >= 0 - still_minor = (self <=> other.skip_minor) < 0 - gr_or_eql and still_minor + still_major_or_minor = (self <=> other.skip_major_or_minor) < 0 + gr_or_eql and still_major_or_minor end - def skip_minor + def skip_major_or_minor a = @ary.dup + a << 0 if a.size == 1 # ~> 2 can also be represented as ~> 2.0 a.slice!(-1) a[-1] = a[-1].succ a -- cgit v1.2.3 From b2120500266c710a130bd17a5e1c7215445c884d Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Sat, 20 Apr 2019 21:23:58 +0900 Subject: Expand `BOXWORD_SET_VALUE()` macro in `include/mruby/boxing_word.h` In `SET_OBJ_VALUE()`, branch isn't removed because `switch` condition isn't constant expression. --- include/mruby/boxing_word.h | 39 ++++++++++++++++++++------------------- 1 file changed, 20 insertions(+), 19 deletions(-) diff --git a/include/mruby/boxing_word.h b/include/mruby/boxing_word.h index 59fdb730d..21ba9962a 100644 --- a/include/mruby/boxing_word.h +++ b/include/mruby/boxing_word.h @@ -119,28 +119,29 @@ mrb_type(mrb_value o) #define mrb_false_p(o) ((o).w == MRB_Qfalse) #define mrb_true_p(o) ((o).w == MRB_Qtrue) -#define BOXWORD_SET_VALUE(o, ttt, attr, v) do { \ - switch (ttt) {\ - case MRB_TT_FALSE: (o).w = (v) ? MRB_Qfalse : MRB_Qnil; break;\ - case MRB_TT_TRUE: (o).w = MRB_Qtrue; break;\ - case MRB_TT_UNDEF: (o).w = MRB_Qundef; break;\ - case MRB_TT_FIXNUM: (o).w = 0;(o).value.i_flag = MRB_FIXNUM_FLAG; (o).attr = (v); break;\ - case MRB_TT_SYMBOL: (o).w = 0;(o).value.sym_flag = MRB_SYMBOL_FLAG; (o).attr = (v); break;\ - default: (o).w = 0; (o).attr = (v); if ((o).value.bp) (o).value.bp->tt = ttt; break;\ - }\ -} while (0) - #ifndef MRB_WITHOUT_FLOAT #define SET_FLOAT_VALUE(mrb,r,v) ((r) = mrb_word_boxing_float_value(mrb, v)) #endif #define SET_CPTR_VALUE(mrb,r,v) ((r) = mrb_word_boxing_cptr_value(mrb, v)) -#define SET_NIL_VALUE(r) BOXWORD_SET_VALUE(r, MRB_TT_FALSE, value.i, 0) -#define SET_FALSE_VALUE(r) BOXWORD_SET_VALUE(r, MRB_TT_FALSE, value.i, 1) -#define SET_TRUE_VALUE(r) BOXWORD_SET_VALUE(r, MRB_TT_TRUE, value.i, 1) -#define SET_BOOL_VALUE(r,b) BOXWORD_SET_VALUE(r, (b) ? MRB_TT_TRUE : MRB_TT_FALSE, value.i, 1) -#define SET_INT_VALUE(r,n) BOXWORD_SET_VALUE(r, MRB_TT_FIXNUM, value.i, (n)) -#define SET_SYM_VALUE(r,v) BOXWORD_SET_VALUE(r, MRB_TT_SYMBOL, value.sym, (v)) -#define SET_OBJ_VALUE(r,v) BOXWORD_SET_VALUE(r, (((struct RObject*)(v))->tt), value.p, (v)) -#define SET_UNDEF_VALUE(r) BOXWORD_SET_VALUE(r, MRB_TT_UNDEF, value.i, 0) +#define SET_UNDEF_VALUE(r) ((r).w = MRB_Qundef) +#define SET_NIL_VALUE(r) ((r).w = MRB_Qnil) +#define SET_FALSE_VALUE(r) ((r).w = MRB_Qfalse) +#define SET_TRUE_VALUE(r) ((r).w = MRB_Qtrue) +#define SET_BOOL_VALUE(r,b) ((b) ? SET_TRUE_VALUE(r) : SET_FALSE_VALUE(r)) +#define SET_INT_VALUE(r,n) do { \ + (r).w = 0; \ + (r).value.i_flag = MRB_FIXNUM_FLAG; \ + (r).value.i = (n); \ +} while (0) +#define SET_SYM_VALUE(r,v) do { \ + (r).w = 0; \ + (r).value.sym_flag = MRB_SYMBOL_FLAG; \ + (r).value.sym = (v); \ +} while (0) +#define SET_OBJ_VALUE(r,v) do { \ + (r).w = 0; \ + (r).value.p = (v); \ + if ((r).value.bp) (r).value.bp->tt = ((struct RObject*)(v))->tt; \ +} while (0) #endif /* MRUBY_BOXING_WORD_H */ -- cgit v1.2.3 From cdb458ed4e07698ecb028bfe397fa273ed454e13 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Sun, 21 Apr 2019 20:34:39 +0900 Subject: Commented out `String#scan` because it is not implemented yet --- mrbgems/mruby-enumerator/mrblib/enumerator.rb | 7 ++++--- mrblib/string.rb | 21 +++++++++------------ test/t/string.rb | 4 +++- 3 files changed, 16 insertions(+), 16 deletions(-) diff --git a/mrbgems/mruby-enumerator/mrblib/enumerator.rb b/mrbgems/mruby-enumerator/mrblib/enumerator.rb index 457687268..89472ef01 100644 --- a/mrbgems/mruby-enumerator/mrblib/enumerator.rb +++ b/mrbgems/mruby-enumerator/mrblib/enumerator.rb @@ -244,9 +244,10 @@ class Enumerator # # === Examples # - # "Hello, world!".scan(/\w+/) #=> ["Hello", "world"] - # "Hello, world!".to_enum(:scan, /\w+/).to_a #=> ["Hello", "world"] - # "Hello, world!".to_enum(:scan).each(/\w+/).to_a #=> ["Hello", "world"] + # Array.new(3) #=> [nil, nil, nil] + # Array.new(3) { |i| i } #=> [0, 1, 2] + # Array.to_enum(:new, 3).to_a #=> [0, 1, 2] + # Array.to_enum(:new).each(3).to_a #=> [0, 1, 2] # # obj = Object.new # diff --git a/mrblib/string.rb b/mrblib/string.rb index e9eb2be1d..c92a9e7be 100644 --- a/mrblib/string.rb +++ b/mrblib/string.rb @@ -105,18 +105,15 @@ class String self.replace(str) end - ## - # Calls the given block for each match of +pattern+ - # If no block is given return an array with all - # matches of +pattern+. - # - # ISO 15.2.10.5.32 - def scan(reg, &block) - ### *** TODO *** ### - unless Object.const_defined?(:Regexp) - raise NotImplementedError, "scan not available (yet)" - end - end +# ## +# # Calls the given block for each match of +pattern+ +# # If no block is given return an array with all +# # matches of +pattern+. +# # +# # ISO 15.2.10.5.32 +# def scan(pattern, &block) +# # TODO: String#scan is not implemented yet +# end ## # Replace only the first match of +pattern+ with diff --git a/test/t/string.rb b/test/t/string.rb index 404cf03e1..e563db55a 100644 --- a/test/t/string.rb +++ b/test/t/string.rb @@ -509,7 +509,9 @@ assert('String#rindex(UTF-8)', '15.2.10.5.31') do assert_equal nil, str.index("さ") end if UTF8STRING -# 'String#scan', '15.2.10.5.32' will be tested in mrbgems. +# assert('String#scan', '15.2.10.5.32') do +# # Not implemented yet +# end assert('String#size', '15.2.10.5.33') do assert_equal 3, 'abc'.size -- cgit v1.2.3 From 0e6a93a9ca9b207ce26073597e2abe26bbbb2c0d Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Mon, 22 Apr 2019 19:09:29 +0900 Subject: Use `MRB_ASPEC_XXX()` macro in `codedump()` --- src/codedump.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/codedump.c b/src/codedump.c index 5bffefddb..12d609075 100644 --- a/src/codedump.c +++ b/src/codedump.c @@ -266,13 +266,13 @@ codedump(mrb_state *mrb, mrb_irep *irep) break; CASE(OP_ENTER, W): printf("OP_ENTER\t%d:%d:%d:%d:%d:%d:%d\n", - (a>>18)&0x1f, - (a>>13)&0x1f, - (a>>12)&0x1, - (a>>7)&0x1f, - (a>>2)&0x1f, - (a>>1)&0x1, - a & 0x1); + MRB_ASPEC_REQ(a), + MRB_ASPEC_OPT(a), + MRB_ASPEC_REST(a), + MRB_ASPEC_POST(a), + MRB_ASPEC_KEY(a), + MRB_ASPEC_KDICT(a), + MRB_ASPEC_BLOCK(a)); break; CASE(OP_KEY_P, BB): printf("OP_KEY_P\tR%d\t:%s\t", a, mrb_sym2name(mrb, irep->syms[b])); -- cgit v1.2.3 From 0debf154ee9aa4c4f9aa0190a54a810801c3d31d Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Mon, 22 Apr 2019 17:35:49 +0900 Subject: Add `assert_predicate` and `assert_operator` --- test/assert.rb | 20 ++++++++++++++++++++ test/t/float.rb | 20 ++++++++++---------- 2 files changed, 30 insertions(+), 10 deletions(-) diff --git a/test/assert.rb b/test/assert.rb index e0fac4d90..385de49bd 100644 --- a/test/assert.rb +++ b/test/assert.rb @@ -1,3 +1,4 @@ +$undefined = Object.new $ok_test = 0 $ko_test = 0 $kill_test = 0 @@ -136,6 +137,25 @@ def _assert_include(affirmed, collection, obj, msg = nil) assert_true(ret, msg, diff) end +def assert_predicate(*args); _assert_predicate(true, *args) end +def assert_not_predicate(*args); _assert_predicate(false, *args) end +def _assert_predicate(affirmed, obj, op, msg = nil) + unless ret = obj.__send__(op) == affirmed + diff = " Expected #{obj.inspect} to #{'not ' unless affirmed}be #{op}." + end + assert_true(ret, msg, diff) +end + +def assert_operator(*args); _assert_operator(true, *args) end +def assert_not_operator(*args); _assert_operator(false, *args) end +def _assert_operator(affirmed, obj1, op, obj2 = $undefined, msg = nil) + return _assert_predicate(affirmed, obj1, op, msg) if obj2 == $undefined + unless ret = obj1.__send__(op, obj2) == affirmed + diff = " Expected #{obj1.inspect} to #{'not ' unless affirmed}be #{op} #{obj2.inspect}." + end + assert_true(ret, msg, diff) +end + ## # Fails unless +obj+ is a kind of +cls+. def assert_kind_of(cls, obj, msg = nil) diff --git a/test/t/float.rb b/test/t/float.rb index 4e9d347b8..b4eb0bfd6 100644 --- a/test/t/float.rb +++ b/test/t/float.rb @@ -82,8 +82,8 @@ assert('Float#ceil', '15.2.9.3.8') do end assert('Float#finite?', '15.2.9.3.9') do - assert_true 3.123456789.finite? - assert_false (1.0 / 0.0).finite? + assert_predicate 3.123456789, :finite? + assert_not_predicate 1.0 / 0.0, :finite? end assert('Float#floor', '15.2.9.3.10') do @@ -139,7 +139,7 @@ assert('Float#round', '15.2.9.3.12') do nan = 0.0/0.0 assert_raise(FloatDomainError){ nan.round } assert_raise(FloatDomainError){ nan.round(-1) } - assert_true(nan.round(1).nan?) + assert_predicate(nan.round(1), :nan?) end assert('Float#to_f', '15.2.9.3.13') do @@ -178,10 +178,10 @@ assert('Float#divmod') do end assert('Float#nan?') do - assert_true (0.0/0.0).nan? - assert_false 0.0.nan? - assert_false (1.0/0.0).nan? - assert_false (-1.0/0.0).nan? + assert_predicate 0.0/0.0, :nan? + assert_not_predicate 0.0, :nan? + assert_not_predicate 1.0/0.0, :nan? + assert_not_predicate -1.0/0.0, :nan? end assert('Float#<<') do @@ -240,9 +240,9 @@ assert('Float#to_s') do end assert('Float#eql?') do - assert_true(5.0.eql?(5.0)) - assert_false(5.0.eql?(5)) - assert_false(5.0.eql?("5.0")) + assert_operator(5.0, :eql?, 5.0) + assert_not_operator(5.0, :eql?, 5) + assert_not_operator(5.0, :eql?, "5.0") end end # const_defined?(:Float) -- cgit v1.2.3 From e9f3902ab5544de31fc91459e1846650aa228142 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Tue, 23 Apr 2019 15:30:10 +0900 Subject: Fixed the condition in `mrb_funcall_with_block`; fix #4389 --- src/vm.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/src/vm.c b/src/vm.c index 9c07b8caa..8dc6623d1 100644 --- a/src/vm.c +++ b/src/vm.c @@ -490,22 +490,21 @@ mrb_funcall_with_block(mrb_state *mrb, mrb_value self, mrb_sym mid, mrb_int argc if (mrb->c->stbase <= argv && argv < mrb->c->stend) { voff = argv - mrb->c->stbase; } - if (MRB_METHOD_CFUNC_P(m)) { - mrb_stack_extend(mrb, argc + 2); - } - else if (argc >= CALL_MAXARGS) { + if (argc >= CALL_MAXARGS) { mrb_value args = mrb_ary_new_from_values(mrb, argc, argv); - mrb_stack_extend(mrb, 3); mrb->c->stack[1] = args; ci->argc = -1; argc = 1; } - else if (MRB_METHOD_PROC_P(m)) { + mrb_stack_extend(mrb, argc + 2); + if (MRB_METHOD_PROC_P(m)) { struct RProc *p = MRB_METHOD_PROC(m); ci->proc = p; - mrb_stack_extend(mrb, p->body.irep->nregs + argc); + if (!MRB_PROC_CFUNC_P(p)) { + mrb_stack_extend(mrb, p->body.irep->nregs + argc); + } } if (voff >= 0) { argv = mrb->c->stbase + voff; -- cgit v1.2.3 From cc7f9190ba93ef45bf85a7278dffe6326cf620a3 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Tue, 23 Apr 2019 20:45:38 +0900 Subject: Fix name assignment to frozen anonymous class/module Fix the following issues: A = Class.new.freeze #=> FrozenError Module.new::B = Class.new.freeze #=> FrozenError String::B = Module.new.freeze #=> FrozenError --- include/mruby/variable.h | 1 + src/class.c | 6 +++--- src/variable.c | 21 ++++++++++++--------- test/t/module.rb | 4 ++++ 4 files changed, 20 insertions(+), 12 deletions(-) diff --git a/include/mruby/variable.h b/include/mruby/variable.h index ba6037959..ff01e5cc8 100644 --- a/include/mruby/variable.h +++ b/include/mruby/variable.h @@ -117,6 +117,7 @@ MRB_API void mrb_mod_cv_set(mrb_state *mrb, struct RClass * c, mrb_sym sym, mrb_ MRB_API void mrb_cv_set(mrb_state *mrb, mrb_value mod, mrb_sym sym, mrb_value v); MRB_API mrb_bool mrb_cv_defined(mrb_state *mrb, mrb_value mod, mrb_sym sym); mrb_value mrb_obj_iv_inspect(mrb_state*, struct RObject*); +void mrb_obj_iv_set_force(mrb_state *mrb, struct RObject *obj, mrb_sym sym, mrb_value v); mrb_value mrb_mod_constants(mrb_state *mrb, mrb_value mod); mrb_value mrb_f_global_variables(mrb_state *mrb, mrb_value self); mrb_value mrb_obj_instance_variables(mrb_state*, mrb_value); diff --git a/src/class.c b/src/class.c index d6efdbdc4..77ff04437 100644 --- a/src/class.c +++ b/src/class.c @@ -66,15 +66,15 @@ mrb_class_name_class(mrb_state *mrb, struct RClass *outer, struct RClass *c, mrb name = mrb_class_path(mrb, outer); if (mrb_nil_p(name)) { /* unnamed outer class */ if (outer != mrb->object_class && outer != c) { - mrb_obj_iv_set(mrb, (struct RObject*)c, mrb_intern_lit(mrb, "__outer__"), - mrb_obj_value(outer)); + mrb_obj_iv_set_force(mrb, (struct RObject*)c, mrb_intern_lit(mrb, "__outer__"), + mrb_obj_value(outer)); } return; } mrb_str_cat_cstr(mrb, name, "::"); mrb_str_cat_cstr(mrb, name, mrb_sym2name(mrb, id)); } - mrb_obj_iv_set(mrb, (struct RObject*)c, nsym, name); + mrb_obj_iv_set_force(mrb, (struct RObject*)c, nsym, name); } static void diff --git a/src/variable.c b/src/variable.c index 983fe52f7..e859f02bf 100644 --- a/src/variable.c +++ b/src/variable.c @@ -341,21 +341,24 @@ mrb_iv_get(mrb_state *mrb, mrb_value obj, mrb_sym sym) static inline void assign_class_name(mrb_state *mrb, struct RObject *obj, mrb_sym sym, mrb_value v); -MRB_API void -mrb_obj_iv_set(mrb_state *mrb, struct RObject *obj, mrb_sym sym, mrb_value v) +void +mrb_obj_iv_set_force(mrb_state *mrb, struct RObject *obj, mrb_sym sym, mrb_value v) { - iv_tbl *t; - - mrb_check_frozen(mrb, obj); assign_class_name(mrb, obj, sym, v); if (!obj->iv) { obj->iv = iv_new(mrb); } - t = obj->iv; - iv_put(mrb, t, sym, v); + iv_put(mrb, obj->iv, sym, v); mrb_write_barrier(mrb, (struct RBasic*)obj); } +MRB_API void +mrb_obj_iv_set(mrb_state *mrb, struct RObject *obj, mrb_sym sym, mrb_value v) +{ + mrb_check_frozen(mrb, obj); + mrb_obj_iv_set_force(mrb, obj, sym, v); +} + /* Iterates over the instance variable table. */ MRB_API void mrb_iv_foreach(mrb_state *mrb, mrb_value obj, mrb_iv_foreach_func *func, void *p) @@ -385,10 +388,10 @@ assign_class_name(mrb_state *mrb, struct RObject *obj, mrb_sym sym, mrb_value v) if (mrb_nil_p(o)) { if ((struct RClass *)obj == mrb->object_class) { - mrb_obj_iv_set(mrb, c, id_classname, mrb_symbol_value(sym)); + mrb_obj_iv_set_force(mrb, c, id_classname, mrb_symbol_value(sym)); } else { - mrb_obj_iv_set(mrb, c, id_outer, mrb_obj_value(obj)); + mrb_obj_iv_set_force(mrb, c, id_outer, mrb_obj_value(obj)); } } } diff --git a/test/t/module.rb b/test/t/module.rb index 09613e1bc..f4999019a 100644 --- a/test/t/module.rb +++ b/test/t/module.rb @@ -653,6 +653,10 @@ assert('Module#to_s') do assert_match "#", Module.new.to_s assert_match "#", Class.new.to_s + + assert_equal "FrozenClassToS", (FrozenClassToS = Class.new.freeze).to_s + assert_equal "Outer::A", (Outer::A = Module.new.freeze).to_s + assert_match "#::A", (Module.new::A = Class.new.freeze).to_s end assert('Module#inspect') do -- cgit v1.2.3 From 9f4147f28e9319a55ff7e865355fd7e70ff0aa73 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Tue, 23 Apr 2019 21:02:42 +0900 Subject: Fix "ambiguous first argument" warning in `test/t/float.rb` --- test/t/float.rb | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/test/t/float.rb b/test/t/float.rb index b4eb0bfd6..63bf83f40 100644 --- a/test/t/float.rb +++ b/test/t/float.rb @@ -178,10 +178,10 @@ assert('Float#divmod') do end assert('Float#nan?') do - assert_predicate 0.0/0.0, :nan? - assert_not_predicate 0.0, :nan? - assert_not_predicate 1.0/0.0, :nan? - assert_not_predicate -1.0/0.0, :nan? + assert_predicate(0.0/0.0, :nan?) + assert_not_predicate(0.0, :nan?) + assert_not_predicate(1.0/0.0, :nan?) + assert_not_predicate(-1.0/0.0, :nan?) end assert('Float#<<') do -- cgit v1.2.3 From 0c5f26e0ffc30bdc88b857daed1c9fe18c4b8f0c Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Wed, 24 Apr 2019 09:43:12 +0900 Subject: Remove unnecessary `mrb_regexp_check()` and related functions. --- include/mruby.h | 4 ---- include/mruby/string.h | 3 --- include/mruby/value.h | 1 - src/etc.c | 16 ---------------- src/string.c | 39 ++++++--------------------------------- 5 files changed, 6 insertions(+), 57 deletions(-) diff --git a/include/mruby.h b/include/mruby.h index de6a803ef..dcd64b2d8 100644 --- a/include/mruby.h +++ b/include/mruby.h @@ -196,13 +196,9 @@ struct mrb_jmpbuf; typedef void (*mrb_atexit_func)(struct mrb_state*); -#define MRB_STATE_NO_REGEXP 1 -#define MRB_STATE_REGEXP 2 - typedef struct mrb_state { struct mrb_jmpbuf *jmp; - uint32_t flags; mrb_allocf allocf; /* memory allocation function */ void *allocf_ud; /* auxiliary data of allocf */ diff --git a/include/mruby/string.h b/include/mruby/string.h index 0b90debec..22445f654 100644 --- a/include/mruby/string.h +++ b/include/mruby/string.h @@ -433,9 +433,6 @@ mrb_value mrb_str_dump(mrb_state *mrb, mrb_value str); */ mrb_value mrb_str_inspect(mrb_state *mrb, mrb_value str); -void mrb_noregexp(mrb_state *mrb, mrb_value self); -void mrb_regexp_check(mrb_state *mrb, mrb_value obj); - /* For backward compatibility */ #define mrb_str_cat2(mrb, str, ptr) mrb_str_cat_cstr(mrb, str, ptr) #define mrb_str_buf_cat(mrb, str, ptr, len) mrb_str_cat(mrb, str, ptr, len) diff --git a/include/mruby/value.h b/include/mruby/value.h index 0446e772c..4d47d30ff 100644 --- a/include/mruby/value.h +++ b/include/mruby/value.h @@ -180,7 +180,6 @@ typedef void mrb_value; #define mrb_cptr_p(o) (mrb_type(o) == MRB_TT_CPTR) #define mrb_exception_p(o) (mrb_type(o) == MRB_TT_EXCEPTION) #define mrb_test(o) mrb_bool(o) -MRB_API mrb_bool mrb_regexp_p(struct mrb_state*, mrb_value); /* * Returns a float in Ruby. diff --git a/src/etc.c b/src/etc.c index d15b398dd..ac1540f92 100644 --- a/src/etc.c +++ b/src/etc.c @@ -194,22 +194,6 @@ mrb_word_boxing_cptr_value(mrb_state *mrb, void *p) } #endif /* MRB_WORD_BOXING */ -MRB_API mrb_bool -mrb_regexp_p(mrb_state *mrb, mrb_value v) -{ - if (mrb->flags & MRB_STATE_NO_REGEXP) { - return FALSE; - } - if ((mrb->flags & MRB_STATE_REGEXP) || mrb_class_defined(mrb, REGEXP_CLASS)) { - mrb->flags |= MRB_STATE_REGEXP; - return mrb_obj_is_kind_of(mrb, v, mrb_class_get(mrb, REGEXP_CLASS)); - } - else { - mrb->flags |= MRB_STATE_NO_REGEXP; - } - return FALSE; -} - #if defined _MSC_VER && _MSC_VER < 1900 #ifndef va_copy diff --git a/src/string.c b/src/string.c index f7a805a94..89ab59d4b 100644 --- a/src/string.c +++ b/src/string.c @@ -997,20 +997,6 @@ mrb_string_value_len(mrb_state *mrb, mrb_value ptr) return RSTRING_LEN(ptr); } -void -mrb_noregexp(mrb_state *mrb, mrb_value self) -{ - mrb_raise(mrb, E_NOTIMP_ERROR, "Regexp class not implemented"); -} - -void -mrb_regexp_check(mrb_state *mrb, mrb_value obj) -{ - if (mrb_regexp_p(mrb, obj)) { - mrb_noregexp(mrb, obj); - } -} - MRB_API mrb_value mrb_str_dup(mrb_state *mrb, mrb_value str) { @@ -1026,7 +1012,6 @@ mrb_str_aref(mrb_state *mrb, mrb_value str, mrb_value indx) { mrb_int idx; - mrb_regexp_check(mrb, indx); switch (mrb_type(indx)) { case MRB_TT_FIXNUM: idx = mrb_fixnum(indx); @@ -1119,7 +1104,6 @@ mrb_str_aref_m(mrb_state *mrb, mrb_value str) if (argc == 2) { mrb_int n1, n2; - mrb_regexp_check(mrb, a1); mrb_get_args(mrb, "ii", &n1, &n2); return str_substr(mrb, str, n1, n2); } @@ -1549,7 +1533,6 @@ mrb_str_index_m(mrb_state *mrb, mrb_value str) else sub = mrb_nil_value(); } - mrb_regexp_check(mrb, sub); clen = RSTRING_CHAR_LEN(str); if (pos < 0) { pos += clen; @@ -1801,7 +1784,6 @@ mrb_str_rindex(mrb_state *mrb, mrb_value str) if (pos < 0) { pos += len; if (pos < 0) { - mrb_regexp_check(mrb, sub); return mrb_nil_value(); } } @@ -1815,7 +1797,6 @@ mrb_str_rindex(mrb_state *mrb, mrb_value str) sub = mrb_nil_value(); } pos = chars2bytes(str, 0, pos); - mrb_regexp_check(mrb, sub); switch (mrb_type(sub)) { default: { @@ -1909,16 +1890,11 @@ mrb_str_split_m(mrb_state *mrb, mrb_value str) if (argc == 0 || mrb_nil_p(spat)) { split_type = awk; } - else { - if (mrb_string_p(spat)) { - split_type = string; - if (RSTRING_LEN(spat) == 1 && RSTRING_PTR(spat)[0] == ' ') { - split_type = awk; - } - } - else { - mrb_noregexp(mrb, str); - } + else if (!mrb_string_p(spat)) { + mrb_raise(mrb, E_TYPE_ERROR, "expected String"); + } + else if (RSTRING_LEN(spat) == 1 && RSTRING_PTR(spat)[0] == ' ') { + split_type = awk; } result = mrb_ary_new(mrb); @@ -1955,7 +1931,7 @@ mrb_str_split_m(mrb_state *mrb, mrb_value str) } } } - else if (split_type == string) { + else { /* split_type == string */ mrb_int str_len = RSTRING_LEN(str); mrb_int pat_len = RSTRING_LEN(spat); mrb_int idx = 0; @@ -1976,9 +1952,6 @@ mrb_str_split_m(mrb_state *mrb, mrb_value str) } beg = idx; } - else { - mrb_noregexp(mrb, str); - } if (RSTRING_LEN(str) > 0 && (lim_p || RSTRING_LEN(str) > beg || lim < 0)) { if (RSTRING_LEN(str) == beg) { tmp = mrb_str_new_empty(mrb, str); -- cgit v1.2.3 From 163a6d01e035f16b15d3b08c0dfddd2caec09f9b Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Wed, 24 Apr 2019 12:09:16 +0900 Subject: Reorganize defines related to `MRB_INLINE`; ref #4391 --- include/mruby/common.h | 10 +++++----- include/mruby/value.h | 3 --- 2 files changed, 5 insertions(+), 8 deletions(-) diff --git a/include/mruby/common.h b/include/mruby/common.h index 4eaac9af7..dc9e3acc5 100644 --- a/include/mruby/common.h +++ b/include/mruby/common.h @@ -54,12 +54,12 @@ MRB_BEGIN_DECL #endif /** Declare a function as always inlined. */ -#if defined(_MSC_VER) -# define MRB_INLINE static __inline -#else -# define MRB_INLINE static inline +#if defined _MSC_VER && _MSC_VER < 1900 +# ifndef __cplusplus +# define inline __inline +# endif #endif - +#define MRB_INLINE static inline /** Declare a public MRuby API function. */ #if defined(MRB_BUILD_AS_DLL) diff --git a/include/mruby/value.h b/include/mruby/value.h index 4d47d30ff..6838daaa5 100644 --- a/include/mruby/value.h +++ b/include/mruby/value.h @@ -73,9 +73,6 @@ MRB_API double mrb_float_read(const char*, char**); #endif #if defined _MSC_VER && _MSC_VER < 1900 -# ifndef __cplusplus -# define inline __inline -# endif # include MRB_API int mrb_msvc_vsnprintf(char *s, size_t n, const char *format, va_list arg); MRB_API int mrb_msvc_snprintf(char *s, size_t n, const char *format, ...); -- cgit v1.2.3 From 4720648137f2698cceb635c251475dec645cd598 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Wed, 24 Apr 2019 21:05:44 +0900 Subject: Fix modiying class variable to frozen class/module --- mrbgems/mruby-metaprog/test/metaprog.rb | 8 +++++++- src/variable.c | 2 ++ test/t/class.rb | 19 +++++++++++++++++++ 3 files changed, 28 insertions(+), 1 deletion(-) diff --git a/mrbgems/mruby-metaprog/test/metaprog.rb b/mrbgems/mruby-metaprog/test/metaprog.rb index 1262c9945..0abeb90a6 100644 --- a/mrbgems/mruby-metaprog/test/metaprog.rb +++ b/mrbgems/mruby-metaprog/test/metaprog.rb @@ -171,7 +171,6 @@ assert('Module#class_variable_set', '15.2.2.4.18') do @@foo end end - assert_equal 99, Test4ClassVariableSet.class_variable_set(:@@cv, 99) assert_equal 101, Test4ClassVariableSet.class_variable_set(:@@foo, 101) assert_true Test4ClassVariableSet.class_variables.include? :@@cv @@ -180,6 +179,13 @@ assert('Module#class_variable_set', '15.2.2.4.18') do %w[@@ @@1 @@x= @x @ x 1].each do |n| assert_raise(NameError) { Test4ClassVariableSet.class_variable_set(n, 1) } end + + m = Module.new.freeze + assert_raise(FrozenError) { m.class_variable_set(:@@cv, 1) } + + parent = Class.new{ class_variable_set(:@@a, nil) }.freeze + child = Class.new(parent) + assert_raise(FrozenError) { child.class_variable_set(:@@a, 1) } end assert('Module#class_variables', '15.2.2.4.19') do diff --git a/src/variable.c b/src/variable.c index 983fe52f7..c4c9d369f 100644 --- a/src/variable.c +++ b/src/variable.c @@ -671,6 +671,7 @@ mrb_mod_cv_set(mrb_state *mrb, struct RClass *c, mrb_sym sym, mrb_value v) iv_tbl *t = c->iv; if (iv_get(mrb, t, sym, NULL)) { + mrb_check_frozen(mrb, c); iv_put(mrb, t, sym, v); mrb_write_barrier(mrb, (struct RBasic*)c); return; @@ -698,6 +699,7 @@ mrb_mod_cv_set(mrb_state *mrb, struct RClass *c, mrb_sym sym, mrb_value v) c = cls; } + mrb_check_frozen(mrb, c); if (!c->iv) { c->iv = iv_new(mrb); } diff --git a/test/t/class.rb b/test/t/class.rb index 290ecf74a..0c95677fc 100644 --- a/test/t/class.rb +++ b/test/t/class.rb @@ -433,6 +433,25 @@ assert('overriding class variable with a module (#3235)') do end end +assert('class variable for frozen class/module') do + module CVarForFrozenModule + freeze + assert_raise(FrozenError) { @@cv = 1 } + end + + class CVarForFrozenClassA + @@a = nil + freeze + end + class CVarForFrozenClassB < CVarForFrozenClassA + def a=(v) + @@a = v + end + end + b = CVarForFrozenClassB.new + assert_raise(FrozenError) { b.a = 1 } +end + assert('class with non-class/module outer raises TypeError') do assert_raise(TypeError) { class 0::C1; end } assert_raise(TypeError) { class []::C2; end } -- cgit v1.2.3 From 4d85019e4cc3748a75d7c542fba80fcbf8554d5c Mon Sep 17 00:00:00 2001 From: dearblue Date: Wed, 24 Apr 2019 22:14:12 +0900 Subject: Check mruby binary version --- src/load.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/load.c b/src/load.c index ab0346750..01c97b926 100644 --- a/src/load.c +++ b/src/load.c @@ -539,6 +539,10 @@ read_binary_header(const uint8_t *bin, size_t *bin_size, uint16_t *crc, uint8_t return MRB_DUMP_INVALID_FILE_HEADER; } + if (memcmp(header->binary_version, RITE_BINARY_FORMAT_VER, sizeof(header->binary_version)) != 0) { + return MRB_DUMP_INVALID_FILE_HEADER; + } + if (crc) { *crc = bin_to_uint16(header->binary_crc); } -- cgit v1.2.3 From 58d525c9fafcc78af25d22f984821eda19d0913c Mon Sep 17 00:00:00 2001 From: dearblue Date: Sat, 6 Apr 2019 14:25:26 +0900 Subject: Check mruby binary size --- src/load.c | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/src/load.c b/src/load.c index 01c97b926..cc011fba7 100644 --- a/src/load.c +++ b/src/load.c @@ -519,10 +519,14 @@ lv_exit: } static int -read_binary_header(const uint8_t *bin, size_t *bin_size, uint16_t *crc, uint8_t *flags) +read_binary_header(const uint8_t *bin, size_t bufsize, size_t *bin_size, uint16_t *crc, uint8_t *flags) { const struct rite_binary_header *header = (const struct rite_binary_header *)bin; + if (bufsize < sizeof(struct rite_binary_header)) { + return MRB_DUMP_READ_FAULT; + } + if (memcmp(header->binary_ident, RITE_BINARY_IDENT, sizeof(header->binary_ident)) == 0) { if (bigendian_p()) *flags |= FLAG_BYTEORDER_NATIVE; @@ -548,11 +552,15 @@ read_binary_header(const uint8_t *bin, size_t *bin_size, uint16_t *crc, uint8_t } *bin_size = (size_t)bin_to_uint32(header->binary_size); + if (bufsize < *bin_size) { + return MRB_DUMP_READ_FAULT; + } + return MRB_DUMP_OK; } static mrb_irep* -read_irep(mrb_state *mrb, const uint8_t *bin, uint8_t flags) +read_irep(mrb_state *mrb, const uint8_t *bin, size_t bufsize, uint8_t flags) { int result; mrb_irep *irep = NULL; @@ -565,7 +573,7 @@ read_irep(mrb_state *mrb, const uint8_t *bin, uint8_t flags) return NULL; } - result = read_binary_header(bin, &bin_size, &crc, &flags); + result = read_binary_header(bin, bufsize, &bin_size, &crc, &flags); if (result != MRB_DUMP_OK) { return NULL; } @@ -618,7 +626,7 @@ mrb_read_irep(mrb_state *mrb, const uint8_t *bin) uint8_t flags = FLAG_SRC_STATIC; #endif - return read_irep(mrb, bin, flags); + return read_irep(mrb, bin, (size_t)-1, flags); } void mrb_exc_set(mrb_state *mrb, mrb_value exc); @@ -680,7 +688,7 @@ mrb_read_irep_file(mrb_state *mrb, FILE* fp) if (fread(buf, header_size, 1, fp) == 0) { goto irep_exit; } - result = read_binary_header(buf, &buf_size, NULL, &flags); + result = read_binary_header(buf, (size_t)-1, &buf_size, NULL, &flags); if (result != MRB_DUMP_OK || buf_size <= header_size) { goto irep_exit; } @@ -689,7 +697,7 @@ mrb_read_irep_file(mrb_state *mrb, FILE* fp) if (fread(buf+header_size, buf_size-header_size, 1, fp) == 0) { goto irep_exit; } - irep = read_irep(mrb, buf, FLAG_SRC_MALLOC); + irep = read_irep(mrb, buf, (size_t)-1, FLAG_SRC_MALLOC); irep_exit: mrb_free(mrb, buf); -- cgit v1.2.3 From 8f6f36f6540408d3b1b5a0dddf440d53b43e53e4 Mon Sep 17 00:00:00 2001 From: dearblue Date: Sat, 6 Apr 2019 14:37:25 +0900 Subject: Add mruby binary loader functions from buffer memory Add new functions (with `MRB_API`): - `mrb_read_irep_buf()` - `mrb_load_irep_buf()` - `mrb_load_irep_buf_cxt()` --- include/mruby/dump.h | 1 + include/mruby/irep.h | 12 ++++++++++++ src/load.c | 18 ++++++++++++++++++ 3 files changed, 31 insertions(+) diff --git a/include/mruby/dump.h b/include/mruby/dump.h index 0234a362b..201d7ef61 100644 --- a/include/mruby/dump.h +++ b/include/mruby/dump.h @@ -31,6 +31,7 @@ MRB_API mrb_value mrb_load_irep_file(mrb_state*,FILE*); MRB_API mrb_value mrb_load_irep_file_cxt(mrb_state*, FILE*, mrbc_context*); #endif MRB_API mrb_irep *mrb_read_irep(mrb_state*, const uint8_t*); +MRB_API mrb_irep *mrb_read_irep_buf(mrb_state*, const void*, size_t); /* dump/load error code * diff --git a/include/mruby/irep.h b/include/mruby/irep.h index 027a294d5..d42fd0fb8 100644 --- a/include/mruby/irep.h +++ b/include/mruby/irep.h @@ -52,9 +52,21 @@ MRB_API mrb_irep *mrb_add_irep(mrb_state *mrb); /* @param [const uint8_t*] irep code, expected as a literal */ MRB_API mrb_value mrb_load_irep(mrb_state*, const uint8_t*); +/* + * @param [const void*] irep code + * @param [size_t] size of irep buffer. If -1 is given, it is considered unrestricted. + */ +MRB_API mrb_value mrb_load_irep_buf(mrb_state*, const void*, size_t); + /* @param [const uint8_t*] irep code, expected as a literal */ MRB_API mrb_value mrb_load_irep_cxt(mrb_state*, const uint8_t*, mrbc_context*); +/* + * @param [const void*] irep code + * @param [size_t] size of irep buffer. If -1 is given, it is considered unrestricted. + */ +MRB_API mrb_value mrb_load_irep_buf_cxt(mrb_state*, const void*, size_t, mrbc_context*); + void mrb_irep_free(mrb_state*, struct mrb_irep*); void mrb_irep_incref(mrb_state*, struct mrb_irep*); void mrb_irep_decref(mrb_state*, struct mrb_irep*); diff --git a/src/load.c b/src/load.c index cc011fba7..0274f30d4 100644 --- a/src/load.c +++ b/src/load.c @@ -629,6 +629,12 @@ mrb_read_irep(mrb_state *mrb, const uint8_t *bin) return read_irep(mrb, bin, (size_t)-1, flags); } +MRB_API mrb_irep* +mrb_read_irep_buf(mrb_state *mrb, const void *buf, size_t bufsize) +{ + return read_irep(mrb, (const uint8_t *)buf, bufsize, FLAG_SRC_MALLOC); +} + void mrb_exc_set(mrb_state *mrb, mrb_value exc); static void @@ -662,12 +668,24 @@ mrb_load_irep_cxt(mrb_state *mrb, const uint8_t *bin, mrbc_context *c) return load_irep(mrb, mrb_read_irep(mrb, bin), c); } +MRB_API mrb_value +mrb_load_irep_buf_cxt(mrb_state *mrb, const void *buf, size_t bufsize, mrbc_context *c) +{ + return load_irep(mrb, mrb_read_irep_buf(mrb, buf, bufsize), c); +} + MRB_API mrb_value mrb_load_irep(mrb_state *mrb, const uint8_t *bin) { return mrb_load_irep_cxt(mrb, bin, NULL); } +MRB_API mrb_value +mrb_load_irep_buf(mrb_state *mrb, const void *buf, size_t bufsize) +{ + return mrb_load_irep_buf_cxt(mrb, buf, bufsize, NULL); +} + #ifndef MRB_DISABLE_STDIO mrb_irep* -- cgit v1.2.3 From 8fa3995a1a02e9014ce01351e0260bec20ceefd7 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Thu, 25 Apr 2019 19:48:40 +0900 Subject: Singleton class of frozen object should be frozen Before this patch: p (class << Object.new.freeze; self end).frozen? #=> false sc = class << (o=Object.new); self end; o.freeze; p sc.frozen? #=> false After this patch / Ruby: p (class << Object.new.freeze; self end).frozen? #=> true sc = class << (o=Object.new); self end; o.freeze; p sc.frozen? #=> true --- mrbgems/mruby-metaprog/test/metaprog.rb | 16 ++++++++++++++++ src/class.c | 1 + src/kernel.c | 1 + test/t/class.rb | 7 +++++++ 4 files changed, 25 insertions(+) diff --git a/mrbgems/mruby-metaprog/test/metaprog.rb b/mrbgems/mruby-metaprog/test/metaprog.rb index 0abeb90a6..3aa1d8732 100644 --- a/mrbgems/mruby-metaprog/test/metaprog.rb +++ b/mrbgems/mruby-metaprog/test/metaprog.rb @@ -122,6 +122,22 @@ assert('Kernel#define_singleton_method') do assert_equal :singleton_method_ok, o.test_method end +assert('Kernel#singleton_class') do + o1 = Object.new + assert_same(o1.singleton_class, class << o1; self end) + + o2 = Object.new + sc2 = class << o2; self end + assert_same(o2.singleton_class, sc2) + + o3 = Object.new + sc3 = o3.singleton_class + o3.freeze + assert_predicate(sc3, :frozen?) + + assert_predicate(Object.new.freeze.singleton_class, :frozen?) +end + def labeled_module(name, &block) Module.new do (class <flags |= o->flags & MRB_FL_OBJ_IS_FROZEN; } static mrb_value diff --git a/src/kernel.c b/src/kernel.c index d9a1d36ce..45bca7558 100644 --- a/src/kernel.c +++ b/src/kernel.c @@ -438,6 +438,7 @@ mrb_obj_freeze(mrb_state *mrb, mrb_value self) struct RBasic *b = mrb_basic_ptr(self); if (!MRB_FROZEN_P(b)) { MRB_SET_FROZEN_FLAG(b); + if (b->c->tt == MRB_TT_SCLASS) MRB_SET_FROZEN_FLAG(b->c); } } return self; diff --git a/test/t/class.rb b/test/t/class.rb index 0c95677fc..e2839111c 100644 --- a/test/t/class.rb +++ b/test/t/class.rb @@ -356,6 +356,13 @@ assert('singleton tests') do end end end if Object.const_defined?(:Float) + + o = Object.new + sc = class << o; self end + o.freeze + assert_predicate(sc, :frozen?) + + assert_predicate(class << Object.new.freeze; self end, :frozen?) end assert('clone Class') do -- cgit v1.2.3 From 302ad847a35f6bf3395ff8605c2007dc9698cea5 Mon Sep 17 00:00:00 2001 From: dearblue Date: Fri, 26 Apr 2019 21:28:57 +0900 Subject: Add customized `mrb_ro_data_p()` User definable `mrb_ro_data_p()` functions are available by defining `MRB_USE_CUSTOM_RO_DATA_P`. (Limitation) It can not be defined as an inline function. --- include/mruby/value.h | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/include/mruby/value.h b/include/mruby/value.h index 6838daaa5..be3dd397f 100644 --- a/include/mruby/value.h +++ b/include/mruby/value.h @@ -278,7 +278,10 @@ mrb_undef_value(void) return v; } -#ifdef MRB_USE_ETEXT_EDATA +#if defined(MRB_USE_CUSTOM_RO_DATA_P) +/* If you define `MRB_USE_CUSTOM_RO_DATA_P`, you must implement `mrb_ro_data_p()`. */ +mrb_bool mrb_ro_data_p(const char *p); +#elif defined(MRB_USE_ETEXT_EDATA) #if (defined(__APPLE__) && defined(__MACH__)) #include static inline mrb_bool -- cgit v1.2.3 From 1fb635ac03d3948898623126a8b3d7705e9cdb0f Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Fri, 26 Apr 2019 21:36:29 +0900 Subject: Add `assert_raise_with_message` and `assert_raise_with_message_pattern` --- test/assert.rb | 36 ++++++++++++++++++++++++++++++------ test/t/kernel.rb | 10 ++++------ test/t/module.rb | 24 +++++++++++++++++------- 3 files changed, 51 insertions(+), 19 deletions(-) diff --git a/test/assert.rb b/test/assert.rb index 121bd0a8e..da313bf6a 100644 --- a/test/assert.rb +++ b/test/assert.rb @@ -6,13 +6,17 @@ $skip_test = 0 $asserts = [] $test_start = Time.now if Object.const_defined?(:Time) +# For bintest on Ruby unless RUBY_ENGINE == "mruby" - # For bintest on Ruby def t_print(*args) print(*args) $stdout.flush nil end + + def _str_match?(pattern, str) + File.fnmatch?(pattern, str, File::FNM_EXTGLOB|File::FNM_DOTMATCH) + end end ## @@ -180,10 +184,7 @@ end def assert_match(*args); _assert_match(true, *args) end def assert_not_match(*args); _assert_match(false, *args) end def _assert_match(affirmed, pattern, str, msg = nil) - receiver, *args = RUBY_ENGINE == "mruby" ? - [self, :_str_match?, pattern, str] : - [File, :fnmatch?, pattern, str, File::FNM_EXTGLOB|File::FNM_DOTMATCH] - unless ret = !receiver.__send__(*args) == !affirmed + unless ret = _str_match?(pattern, str) == affirmed diff = " Expected #{pattern.inspect} to #{'not ' unless affirmed}match #{str.inspect}." end assert_true(ret, msg, diff) @@ -217,8 +218,9 @@ def assert_raise(*exc) exc = exc.empty? ? StandardError : exc.size == 1 ? exc[0] : exc begin yield - rescue *exc + rescue *exc => e pass + e rescue Exception => e diff = " #{exc} exception expected, not\n" \ " Class: <#{e.class}>\n" \ @@ -243,6 +245,28 @@ def assert_nothing_raised(msg = nil) end end +def assert_raise_with_message(*args, &block) + _assert_raise_with_message(:plain, *args, &block) +end +def assert_raise_with_message_pattern(*args, &block) + _assert_raise_with_message(:pattern, *args, &block) +end +def _assert_raise_with_message(type, exc, exp_msg, msg = nil, &block) + e = msg ? assert_raise(exc, msg, &block) : assert_raise(exc, &block) + e ? ($mrbtest_assert_idx -= 1) : (return e) + + err_msg = e.message + unless ret = type == :pattern ? _str_match?(exp_msg, err_msg) : exp_msg == err_msg + diff = " Expected Exception(#{exc}) was raised, but the message doesn't match.\n" + if type == :pattern + diff += " Expected #{exp_msg.inspect} to match #{err_msg.inspect}." + else + diff += assertion_diff(exp_msg, err_msg) + end + end + assert_true(ret, msg, diff) +end + def pass assert_true(true) end diff --git a/test/t/kernel.rb b/test/t/kernel.rb index bf7dbe94c..7fc8cd2e7 100644 --- a/test/t/kernel.rb +++ b/test/t/kernel.rb @@ -346,17 +346,15 @@ assert('Kernel#method_missing', '15.3.1.3.30') do end end no_super_test = NoSuperMethodTestClass.new - begin + msg = "undefined method 'no_super_method_named_this'" + assert_raise_with_message(NoMethodError, msg) do no_super_test.no_super_method_named_this - rescue NoMethodError => e - assert_equal "undefined method 'no_super_method_named_this'", e.message end a = String.new - begin + msg = "undefined method 'no_method_named_this'" + assert_raise_with_message(NoMethodError, msg) do a.no_method_named_this - rescue NoMethodError => e - assert_equal "undefined method 'no_method_named_this'", e.message end end diff --git a/test/t/module.rb b/test/t/module.rb index 09613e1bc..5c659f149 100644 --- a/test/t/module.rb +++ b/test/t/module.rb @@ -21,6 +21,14 @@ def labeled_class(name, supklass = Object, &block) end end +def assert_uninitialized_const(&block) + assert_raise_with_message_pattern(NameError, "uninitialized constant *", &block) +end + +def assert_wrong_const_name(&block) + assert_raise_with_message_pattern(NameError, "wrong constant name *", &block) +end + assert('Module', '15.2.2') do assert_equal Class, Module.class end @@ -221,7 +229,7 @@ assert('Module#const_defined?', '15.2.2.4.20') do assert_true Test4ConstDefined.const_defined?(:Const4Test4ConstDefined) assert_false Test4ConstDefined.const_defined?(:NotExisting) - assert_raise(NameError){ Test4ConstDefined.const_defined?(:wrong_name) } + assert_wrong_const_name{ Test4ConstDefined.const_defined?(:wrong_name) } end assert('Module#const_get', '15.2.2.4.21') do @@ -234,9 +242,9 @@ assert('Module#const_get', '15.2.2.4.21') do assert_equal 42, Object.const_get("Test4ConstGet::Const4Test4ConstGet") assert_raise(TypeError){ Test4ConstGet.const_get(123) } - assert_raise(NameError){ Test4ConstGet.const_get(:I_DO_NOT_EXIST) } - assert_raise(NameError){ Test4ConstGet.const_get("I_DO_NOT_EXIST::ME_NEITHER") } - assert_raise(NameError){ Test4ConstGet.const_get(:wrong_name) } + assert_uninitialized_const{ Test4ConstGet.const_get(:I_DO_NOT_EXIST) } + assert_uninitialized_const{ Test4ConstGet.const_get("I_DO_NOT_EXIST::ME_NEITHER") } + assert_wrong_const_name{ Test4ConstGet.const_get(:wrong_name) } end assert('Module#const_set', '15.2.2.4.23') do @@ -247,7 +255,7 @@ assert('Module#const_set', '15.2.2.4.23') do assert_equal 23, Test4ConstSet.const_set(:Const4Test4ConstSet, 23) assert_equal 23, Test4ConstSet.const_get(:Const4Test4ConstSet) ["", "wrongNAME", "Wrong-Name"].each do |n| - assert_raise(NameError) { Test4ConstSet.const_set(n, 1) } + assert_wrong_const_name { Test4ConstSet.const_set(n, 1) } end end @@ -258,9 +266,11 @@ assert('Module#remove_const', '15.2.2.4.40') do assert_equal 23, Test4RemoveConst.remove_const(:ExistingConst) assert_false Test4RemoveConst.const_defined?(:ExistingConst) - assert_raise(NameError) { Test4RemoveConst.remove_const(:NonExistingConst) } + assert_raise_with_message_pattern(NameError, "constant * not defined") do + Test4RemoveConst.remove_const(:NonExistingConst) + end %i[x X!].each do |n| - assert_raise(NameError) { Test4RemoveConst.remove_const(n) } + assert_wrong_const_name { Test4RemoveConst.remove_const(n) } end end -- cgit v1.2.3 From 270131253f62d806ea480ef4793e0b39cd068ee4 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Sat, 27 Apr 2019 12:50:02 +0900 Subject: Remove duplicated `String#each_char` --- mrbgems/mruby-io/test/io.rb | 4 ++-- mrbgems/mruby-method/test/method.rb | 2 +- mrbgems/mruby-string-ext/mrblib/string.rb | 10 +++++++--- mrbgems/mruby-string-ext/test/string.rb | 12 ++++++------ mrblib/string.rb | 12 ------------ 5 files changed, 16 insertions(+), 24 deletions(-) diff --git a/mrbgems/mruby-io/test/io.rb b/mrbgems/mruby-io/test/io.rb index 44eaca6be..2b3f9cf13 100644 --- a/mrbgems/mruby-io/test/io.rb +++ b/mrbgems/mruby-io/test/io.rb @@ -84,7 +84,7 @@ end assert('IO#getc', '15.2.20.5.8') do io = IO.new(IO.sysopen($mrbtest_io_rfname)) - $mrbtest_io_msg.each_char { |ch| + $mrbtest_io_msg.split("").each { |ch| assert_equal ch, io.getc } assert_equal nil, io.getc @@ -127,7 +127,7 @@ end assert('IO#readchar', '15.2.20.5.15') do # almost same as IO#getc IO.open(IO.sysopen($mrbtest_io_rfname)) do |io| - $mrbtest_io_msg.each_char { |ch| + $mrbtest_io_msg.split("").each { |ch| assert_equal ch, io.readchar } assert_raise(EOFError) do diff --git a/mrbgems/mruby-method/test/method.rb b/mrbgems/mruby-method/test/method.rb index dfddde9cc..0b67d3e61 100644 --- a/mrbgems/mruby-method/test/method.rb +++ b/mrbgems/mruby-method/test/method.rb @@ -21,7 +21,7 @@ class Interpreter } def interpret(string) @ret = "" - string.each_char {|b| Dispatcher[b].bind(self).call } + string.split("").each {|b| Dispatcher[b].bind(self).call } end end diff --git a/mrbgems/mruby-string-ext/mrblib/string.rb b/mrbgems/mruby-string-ext/mrblib/string.rb index 311803ea2..fdaf2f960 100644 --- a/mrbgems/mruby-string-ext/mrblib/string.rb +++ b/mrbgems/mruby-string-ext/mrblib/string.rb @@ -310,11 +310,15 @@ class String end end + ## + # Call the given block for each character of + # +self+. def each_char(&block) return to_enum :each_char unless block - - split('').each do |i| - block.call(i) + pos = 0 + while pos < self.size + block.call(self[pos]) + pos += 1 end self end diff --git a/mrbgems/mruby-string-ext/test/string.rb b/mrbgems/mruby-string-ext/test/string.rb index 44ca1fde2..02777e594 100644 --- a/mrbgems/mruby-string-ext/test/string.rb +++ b/mrbgems/mruby-string-ext/test/string.rb @@ -657,19 +657,19 @@ assert('String#chars(UTF-8)') do end if UTF8STRING assert('String#each_char') do - s = "" + chars = [] "hello!".each_char do |x| - s += x + chars << x end - assert_equal "hello!", s + assert_equal ["h", "e", "l", "l", "o", "!"], chars end assert('String#each_char(UTF-8)') do - s = "" + chars = [] "こんにちは世界!".each_char do |x| - s += x + chars << x end - assert_equal "こんにちは世界!", s + assert_equal ["こ", "ん", "に", "ち", "は", "世", "界", "!"], chars end if UTF8STRING assert('String#codepoints') do diff --git a/mrblib/string.rb b/mrblib/string.rb index c92a9e7be..506f23c83 100644 --- a/mrblib/string.rb +++ b/mrblib/string.rb @@ -164,18 +164,6 @@ class String self.replace(str) end - ## - # Call the given block for each character of - # +self+. - def each_char(&block) - pos = 0 - while pos < self.size - block.call(self[pos]) - pos += 1 - end - self - end - ## # Call the given block for each byte of +self+. def each_byte(&block) -- cgit v1.2.3 From b57f61ac95254cdd9becf8aab1e4e15bae404564 Mon Sep 17 00:00:00 2001 From: dearblue Date: Sat, 27 Apr 2019 22:28:54 +0900 Subject: Update document for any configurations - (Modify) `MRB_INT16` - (Add) `MRB_INT32` - (Modify) `MRB_INT64` - (Add) `MRB_USE_ETEXT_EDATA` - (Add) `MRB_NO_INIT_ARRAY_START - (Add) `MRB_WITHOUT_FLOAT` - (Add) `MRB_METHOD_CACHE` - (Add) `MRB_METHOD_CACHE_SIZE` - (Add) `MRB_METHOD_TABLE_INLINE - (Add) `MRB_ENABLE_ALL_SYMBOLS` --- doc/guides/mrbconf.md | 49 +++++++++++++++++++++++++++++++++++++++++++------ include/mrbconf.h | 9 +++++++-- 2 files changed, 50 insertions(+), 8 deletions(-) diff --git a/doc/guides/mrbconf.md b/doc/guides/mrbconf.md index f957f8ce2..4e3a81aa3 100644 --- a/doc/guides/mrbconf.md +++ b/doc/guides/mrbconf.md @@ -50,15 +50,21 @@ You can use mrbconfs with following ways: * When defined single precision floating point type(C type `float`) is used as `mrb_float`. * Else double precision floating point type(C type `double`) is used as `mrb_float`. +`MRB_WITHOUT_FLOAT` +* When defined removes floating point numbers from mruby. +* It makes mruby easier to handle in "Microcontroller without FPU" and "Kernel Space". + `MRB_INT16` * When defined `int16_t` will be defined as `mrb_int`. -* Conflicts with `MRB_INT64`. +* Conflicts with `MRB_INT32` and `MRB_INT64`. + +`MRB_INT32` +* When defined, or both `MRB_INT16` and `MRB_INT64` are not defined on 32-bit CPU mode, `int32_t` will be defined as `mrb_int`. +* Conflicts with `MRB_INT16` and `MRB_INT64`. `MRB_INT64` -* When defined `int64_t` will be defined as `mrb_int`. -* Conflicts with `MRB_INT16`. -* When `MRB_INT16` or `MRB_INT64` isn't defined `int`(most of the times 32-bit integer) -will be defined as `mrb_int`. +* When defined, or both `MRB_INT16` and `MRB_INT32` are not defined on 64-bit CPU mode, `int64_t` will be defined as `mrb_int`. +* Conflicts with `MRB_INT16` and `MRB_INT32`. ## Garbage collector configuration. @@ -115,7 +121,7 @@ largest value of required alignment. `MRB_NAN_BOXING` * If defined represent `mrb_value` in boxed `double`. -* Conflicts with `MRB_USE_FLOAT`. +* Conflicts with `MRB_USE_FLOAT` and `MRB_WITHOUT_FLOAT`. `MRB_WORD_BOXING` * If defined represent `mrb_value` as a word. @@ -126,6 +132,20 @@ largest value of required alignment. * Default value is `4`. * Specifies size of each segment in segment list. +## Reduce heap memory configuration. + +`MRB_USE_ETEXT_EDATA` +* If you specify the address of a read-only section when creating a symbol or string, that string will be used as it is. +* Heap memory can be saved. +* Uses `_etext` and `__init_array_start`. +* It must be `_etext < data_addr < &__init_array_start`. + +`MRB_NO_INIT_ARRAY_START` +* Ignored if `MRB_USE_ETEXT_EDATA` is not defined. +* Please try if `__init_array_start` is not available. +* Uses `_etext` and `_edata`. +* It must be `_etext < data_addr < _edata`. + ## Other configuration. `MRB_UTF8_STRING` * Adds UTF-8 encoding support to character-oriented String instance methods. @@ -144,3 +164,20 @@ largest value of required alignment. `MRB_STR_BUF_MIN_SIZE` * Default value is `128`. * Specifies initial capacity of `RString` created by `mrb_str_buf_new` function.. + +`MRB_METHOD_CACHE` +* Improve performance for method dispatch. + +`MRB_METHOD_CACHE_SIZE` +* Default value is `128`. +* Ignored if `MRB_METHOD_CACHE` is not defined. +* Need to be the power of 2. + +`MRB_METHOD_TABLE_INLINE` +* Reduce the size of method table. +* Requires LSB of function pointers to be zero. +* For example, you might need to specify `--falign-functions=n` (where `n > 1`) for GCC. + +`MRB_ENABLE_ALL_SYMBOLS` +* Make it available `Symbols.all_symbols` in `mrbgems/mruby-symbol-ext` +* Increase heap memory usage. diff --git a/include/mrbconf.h b/include/mrbconf.h index 08e69d3aa..caae08d7c 100644 --- a/include/mrbconf.h +++ b/include/mrbconf.h @@ -41,10 +41,15 @@ /* you might need to specify --falign-functions=n (where n>1) */ //#define MRB_METHOD_TABLE_INLINE -/* add -DMRB_INT16 to use 16bit integer for mrb_int; conflict with MRB_INT64 */ +/* add -DMRB_INT16 to use 16bit integer for mrb_int; conflict with MRB_INT32 and MRB_INT64 */ //#define MRB_INT16 -/* add -DMRB_INT64 to use 64bit integer for mrb_int; conflict with MRB_INT16 */ +/* add -DMRB_INT32 to use 32bit integer for mrb_int; conflict with MRB_INT16 and MRB_INT64; + Default for 32-bit CPU mode. */ +//#define MRB_INT32 + +/* add -DMRB_INT64 to use 64bit integer for mrb_int; conflict with MRB_INT16 and MRB_INT32; + Default for 64-bit CPU mode. */ //#define MRB_INT64 /* if no specific integer type is chosen */ -- cgit v1.2.3 From 828a99894179e858b4ddda4ba686413b56f986de Mon Sep 17 00:00:00 2001 From: dearblue Date: Sat, 27 Apr 2019 22:29:20 +0900 Subject: Update document for `MRB_USE_CUSTOM_RO_DATA_P` --- doc/guides/mrbconf.md | 7 +++++++ include/mrbconf.h | 5 +++++ 2 files changed, 12 insertions(+) diff --git a/doc/guides/mrbconf.md b/doc/guides/mrbconf.md index 4e3a81aa3..3c20b3388 100644 --- a/doc/guides/mrbconf.md +++ b/doc/guides/mrbconf.md @@ -146,6 +146,13 @@ largest value of required alignment. * Uses `_etext` and `_edata`. * It must be `_etext < data_addr < _edata`. +`MRB_USE_CUSTOM_RO_DATA_P` +* Takes precedence over `MRB_USE_ETEXT_EDATA`. +* Please try if both `MRB_USE_ETEXT_EDATA` and `MRB_NO_INIT_ARRAY_START` are not available. +* The `mrb_ro_data_p()` function is implemented by the user in an arbitrary file. +* The prototype declaration is `mrb_bool mrb_ro_data_p(const char *ptr)`. +* Return `TRUE` if `ptr` is in read-only section, otherwise return `FALSE`. + ## Other configuration. `MRB_UTF8_STRING` * Adds UTF-8 encoding support to character-oriented String instance methods. diff --git a/include/mrbconf.h b/include/mrbconf.h index caae08d7c..6b0b9e37e 100644 --- a/include/mrbconf.h +++ b/include/mrbconf.h @@ -93,6 +93,11 @@ effective only when MRB_USE_ETEXT_EDATA is defined */ //#define MRB_NO_INIT_ARRAY_START +/* if do not works both MRB_USE_ETEXT_EDATA and MRB_NO_INIT_ARRAY_START, + you can try mrb_ro_data_p() that you have implemented yourself in any file; + prototype is `mrb_bool mrb_ro_data_p(const char *ptr)` */ +//#define MRB_USE_CUSTOM_RO_DATA_P + /* turn off generational GC by default */ //#define MRB_GC_TURN_OFF_GENERATIONAL -- cgit v1.2.3 From 5969ed1afb0f28a2a3ce9504b4f1cb2f7c14ea57 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Sun, 28 Apr 2019 18:42:23 +0900 Subject: Commented out "Struct.new removes existing constant" test Because this test is always skipped. --- mrbgems/mruby-struct/test/struct.rb | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/mrbgems/mruby-struct/test/struct.rb b/mrbgems/mruby-struct/test/struct.rb index c298fef9f..91e8cecc6 100644 --- a/mrbgems/mruby-struct/test/struct.rb +++ b/mrbgems/mruby-struct/test/struct.rb @@ -152,14 +152,14 @@ assert("Struct#dig") do assert_equal 1, a.dig(1, 0) end -assert("Struct.new removes existing constant") do - skip "redefining Struct with same name cause warnings" - begin - assert_not_equal Struct.new("Test", :a), Struct.new("Test", :a, :b) - ensure - Struct.remove_const :Test - end -end +# TODO: suppress redefining Struct warning during test +# assert("Struct.new removes existing constant") do +# begin +# assert_not_equal Struct.new("Test", :a), Struct.new("Test", :a, :b) +# ensure +# Struct.remove_const :Test +# end +# end assert("Struct#initialize_copy requires struct to be the same type") do begin -- cgit v1.2.3 From 8cc2ad3348d00825d5daa6aed63a952ac6cec845 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Mon, 29 Apr 2019 11:09:35 +0900 Subject: Fix missing assertions in `mruby-io` test --- mrbgems/mruby-io/test/file.rb | 12 +++----- mrbgems/mruby-io/test/file_test.rb | 8 ++---- mrbgems/mruby-io/test/io.rb | 57 ++++++++++++++++++++------------------ 3 files changed, 36 insertions(+), 41 deletions(-) diff --git a/mrbgems/mruby-io/test/file.rb b/mrbgems/mruby-io/test/file.rb index ba4100492..88ced31a6 100644 --- a/mrbgems/mruby-io/test/file.rb +++ b/mrbgems/mruby-io/test/file.rb @@ -1,15 +1,13 @@ ## # File Test -assert('File TEST SETUP') do - MRubyIOTestUtil.io_test_setup -end +MRubyIOTestUtil.io_test_setup -assert('File', '15.2.21') do +assert('File.class', '15.2.21') do assert_equal Class, File.class end -assert('File', '15.2.21.2') do +assert('File.superclass', '15.2.21.2') do assert_equal IO, File.superclass end @@ -204,6 +202,4 @@ assert('File.chmod') do end end -assert('File TEST CLEANUP') do - assert_nil MRubyIOTestUtil.io_test_cleanup -end +MRubyIOTestUtil.io_test_cleanup diff --git a/mrbgems/mruby-io/test/file_test.rb b/mrbgems/mruby-io/test/file_test.rb index 04e10e0c8..72e921ce9 100644 --- a/mrbgems/mruby-io/test/file_test.rb +++ b/mrbgems/mruby-io/test/file_test.rb @@ -1,9 +1,7 @@ ## # FileTest -assert('FileTest TEST SETUP') do - MRubyIOTestUtil.io_test_setup -end +MRubyIOTestUtil.io_test_setup assert("FileTest.directory?") do dir = MRubyIOTestUtil.mkdtemp("mruby-io-test.XXXXXX") @@ -112,6 +110,4 @@ assert("FileTest.zero?") do assert_true fp2.closed? end -assert('FileTest TEST CLEANUP') do - assert_nil MRubyIOTestUtil.io_test_cleanup -end +MRubyIOTestUtil.io_test_cleanup diff --git a/mrbgems/mruby-io/test/io.rb b/mrbgems/mruby-io/test/io.rb index 2b3f9cf13..5004d0042 100644 --- a/mrbgems/mruby-io/test/io.rb +++ b/mrbgems/mruby-io/test/io.rb @@ -1,35 +1,44 @@ ## # IO Test -assert('IO TEST SETUP') do - MRubyIOTestUtil.io_test_setup - $cr, $crlf, $cmd = MRubyIOTestUtil.win? ? [1, "\r\n", "cmd /c "] : [0, "\n", ""] +MRubyIOTestUtil.io_test_setup +$cr, $crlf, $cmd = MRubyIOTestUtil.win? ? [1, "\r\n", "cmd /c "] : [0, "\n", ""] + +assert_io_open = ->(meth) do + fd = IO.sysopen($mrbtest_io_rfname) + assert_equal Fixnum, fd.class + io1 = IO.__send__(meth, fd) + begin + assert_equal IO, io1.class + assert_equal $mrbtest_io_msg, io1.read + ensure + io1.close + end + + io2 = IO.__send__(meth, IO.sysopen($mrbtest_io_rfname))do |io| + if meth == :open + assert_equal $mrbtest_io_msg, io.read + else + flunk "IO.#{meth} does not take block" + end + end + io2.close unless meth == :open end -assert('IO', '15.2.20') do +assert('IO.class', '15.2.20') do assert_equal(Class, IO.class) end -assert('IO', '15.2.20.2') do +assert('IO.superclass', '15.2.20.2') do assert_equal(Object, IO.superclass) end -assert('IO', '15.2.20.3') do +assert('IO.ancestors', '15.2.20.3') do assert_include(IO.ancestors, Enumerable) end assert('IO.open', '15.2.20.4.1') do - fd = IO.sysopen $mrbtest_io_rfname - assert_equal Fixnum, fd.class - io = IO.open fd - assert_equal IO, io.class - assert_equal $mrbtest_io_msg, io.read - io.close - - fd = IO.sysopen $mrbtest_io_rfname - IO.open(fd) do |io| - assert_equal $mrbtest_io_msg, io.read - end + assert_io_open.(:open) end assert('IO#close', '15.2.20.5.1') do @@ -215,19 +224,15 @@ assert('IO#dup for writable') do end assert('IO.for_fd') do - fd = IO.sysopen($mrbtest_io_rfname) - io = IO.for_fd(fd) - assert_equal $mrbtest_io_msg, io.read - io.close + assert_io_open.(:for_fd) end assert('IO.new') do - io = IO.new(0) - io.close + assert_io_open.(:new) end assert('IO gc check') do - 100.times { IO.new(0) } + assert_nothing_raised { 100.times { IO.new(0) } } end assert('IO.sysopen("./nonexistent")') do @@ -604,6 +609,4 @@ assert('`cmd`') do end end -assert('IO TEST CLEANUP') do - assert_nil MRubyIOTestUtil.io_test_cleanup -end +MRubyIOTestUtil.io_test_cleanup -- cgit v1.2.3 From 4bf6b8c136ecd6b4bf78e9a66c21943f3f8ab506 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Mon, 29 Apr 2019 11:34:41 +0900 Subject: Refine the default values of `flunk` The default message for the second argument should be set to the first argument because only one argument is normally specified. --- test/assert.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/assert.rb b/test/assert.rb index 121bd0a8e..a9bbc9a05 100644 --- a/test/assert.rb +++ b/test/assert.rb @@ -247,7 +247,7 @@ def pass assert_true(true) end -def flunk(msg = nil, diff = "Epic Fail!") +def flunk(msg = "Epic Fail!", diff = "") assert_true(false, msg, diff) end -- cgit v1.2.3 From 9bd17226d5cc9e36937497664886d05d527bfd19 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Tue, 30 Apr 2019 16:35:47 +0900 Subject: Refine error message output for `mruby` command - Write message to stderr instead of stdout. - Avoid duplicate message output (`SyntaxError`, `ScriptError` etc). - Refine invalid option message. - Suppress redundant usage output. - Fix some incorrect exit code. --- mrbgems/mruby-bin-mruby/bintest/mruby.rb | 51 ++++++++++++++++++++++++++--- mrbgems/mruby-bin-mruby/tools/mruby/mruby.c | 39 ++++++++-------------- 2 files changed, 60 insertions(+), 30 deletions(-) diff --git a/mrbgems/mruby-bin-mruby/bintest/mruby.rb b/mrbgems/mruby-bin-mruby/bintest/mruby.rb index e8d1510f7..1dced07f9 100644 --- a/mrbgems/mruby-bin-mruby/bintest/mruby.rb +++ b/mrbgems/mruby-bin-mruby/bintest/mruby.rb @@ -1,10 +1,16 @@ require 'tempfile' +require 'open3' + +assert_mruby = ->(exp_out_pattern, exp_err_pattern, exp_success, args) do + out, err, stat = Open3.capture3(cmd("mruby"), *args) + assert_match(exp_out_pattern, out, "standard output") + assert_match(exp_err_pattern, err, "standard error") + assert_equal(exp_success, stat.success?, "exit success?") +end assert('regression for #1564') do - o = `#{cmd('mruby')} -e #{shellquote('<<')} 2>&1` - assert_include o, "-e:1:2: syntax error" - o = `#{cmd('mruby')} -e #{shellquote('<<-')} 2>&1` - assert_include o, "-e:1:3: syntax error" + assert_mruby.("", "-e:1:2: syntax error, *", false, %w[-e <<]) + assert_mruby.("", "-e:1:3: syntax error, *", false, %w[-e <<-]) end assert('regression for #1572') do @@ -66,6 +72,11 @@ RUBY assert_equal 0, $?.exitstatus end +assert('mruby -c option') do + assert_mruby.("Syntax OK\n", "", true, ["-c", "-e", "p 1"]) + assert_mruby.("", "-e:1:7: syntax error, *", false, ["-c", "-e", "p 1; 1."]) +end + assert('mruby -d option') do o = `#{cmd('mruby')} -e #{shellquote('p $DEBUG')}` assert_equal "false\n", o @@ -73,6 +84,14 @@ assert('mruby -d option') do assert_equal "true\n", o end +assert('mruby -e option (no code specified)') do + assert_mruby.("", "* No code specified for -e\n", false, %w[-e]) +end + +assert('mruby -h option') do + assert_mruby.("Usage: *mruby*", "", true, %w[-h]) +end + assert('mruby -r option') do lib = Tempfile.new('lib.rb') lib.write < #include -#ifdef MRB_DISABLE_STDIO -static void -p(mrb_state *mrb, mrb_value obj) -{ - mrb_value val = mrb_inspect(mrb, obj); - - fwrite(RSTRING_PTR(val), RSTRING_LEN(val), 1, stdout); - putc('\n', stdout); -} -#else -#define p(mrb,obj) mrb_p(mrb,obj) -#endif - struct _args { FILE *rfp; char* cmdline; @@ -119,14 +106,17 @@ append_cmdline: } } else { - printf("%s: No code specified for -e\n", *origargv); - return EXIT_SUCCESS; + fprintf(stderr, "%s: No code specified for -e\n", *origargv); + return EXIT_FAILURE; } break; + case 'h': + usage(*origargv); + exit(EXIT_SUCCESS); case 'r': if (!item[0]) { if (argc <= 1) { - printf("%s: No library specified for -r\n", *origargv); + fprintf(stderr, "%s: No library specified for -r\n", *origargv); return EXIT_FAILURE; } argc--; argv++; @@ -158,6 +148,7 @@ append_cmdline: exit(EXIT_SUCCESS); } default: + fprintf(stderr, "%s: invalid option %s (-h will show valid options)\n", *origargv, *argv); return EXIT_FAILURE; } } @@ -167,7 +158,7 @@ append_cmdline: else { args->rfp = fopen(argv[0], args->mrbfile ? "rb" : "r"); if (args->rfp == NULL) { - printf("%s: Cannot open program file. (%s)\n", *origargv, *argv); + fprintf(stderr, "%s: Cannot open program file. (%s)\n", *origargv, *argv); return EXIT_FAILURE; } args->fname = TRUE; @@ -212,14 +203,13 @@ main(int argc, char **argv) mrb_sym zero_sym; if (mrb == NULL) { - fputs("Invalid mrb_state, exiting mruby\n", stderr); + fprintf(stderr, "%s: Invalid mrb_state, exiting mruby\n", *argv); return EXIT_FAILURE; } n = parse_args(mrb, argc, argv, &args); if (n == EXIT_FAILURE || (args.cmdline == NULL && args.rfp == NULL)) { cleanup(mrb, &args); - usage(argv[0]); return n; } else { @@ -258,7 +248,7 @@ main(int argc, char **argv) for (i = 0; i < args.libc; i++) { FILE *lfp = fopen(args.libv[i], args.mrbfile ? "rb" : "r"); if (lfp == NULL) { - printf("Cannot open library file: %s\n", args.libv[i]); + fprintf(stderr, "%s: Cannot open library file: %s\n", *argv, args.libv[i]); mrbc_context_free(mrb, c); cleanup(mrb, &args); return EXIT_FAILURE; @@ -289,13 +279,10 @@ main(int argc, char **argv) mrb_gc_arena_restore(mrb, ai); mrbc_context_free(mrb, c); if (mrb->exc) { - if (mrb_undef_p(v)) { - mrb_p(mrb, mrb_obj_value(mrb->exc)); - } - else { + if (!mrb_undef_p(v)) { mrb_print_error(mrb); } - n = -1; + n = EXIT_FAILURE; } else if (args.check_syntax) { printf("Syntax OK\n"); @@ -303,5 +290,5 @@ main(int argc, char **argv) } cleanup(mrb, &args); - return n == 0 ? EXIT_SUCCESS : EXIT_FAILURE; + return n; } -- cgit v1.2.3 From 1a8f6e70b5e91dcbdf92a3b671e00cd7410c3cc1 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Wed, 1 May 2019 15:04:08 +0900 Subject: Remove unneeded `argc` check in `mrb_str_aref_m()` --- src/string.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/string.c b/src/string.c index 89ab59d4b..90e609992 100644 --- a/src/string.c +++ b/src/string.c @@ -1107,9 +1107,6 @@ mrb_str_aref_m(mrb_state *mrb, mrb_value str) mrb_get_args(mrb, "ii", &n1, &n2); return str_substr(mrb, str, n1, n2); } - if (argc != 1) { - mrb_raisef(mrb, E_ARGUMENT_ERROR, "wrong number of arguments (%S for 1)", mrb_fixnum_value(argc)); - } return mrb_str_aref(mrb, str, a1); } -- cgit v1.2.3 From 2a94bf8fbd9afb49e1c2b83126f5952b2864d781 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Wed, 1 May 2019 16:49:56 +0900 Subject: Small fix in `mruby-bin-mruby` - Modify some error messages for consistency. - Add test for codegen error. - Use regular expression for error message matching in test. --- mrbgems/mruby-bin-mruby/bintest/mruby.rb | 33 +++++++++++++++++------------ mrbgems/mruby-bin-mruby/tools/mruby/mruby.c | 4 ++-- 2 files changed, 21 insertions(+), 16 deletions(-) diff --git a/mrbgems/mruby-bin-mruby/bintest/mruby.rb b/mrbgems/mruby-bin-mruby/bintest/mruby.rb index 1dced07f9..d1262254b 100644 --- a/mrbgems/mruby-bin-mruby/bintest/mruby.rb +++ b/mrbgems/mruby-bin-mruby/bintest/mruby.rb @@ -1,16 +1,16 @@ require 'tempfile' require 'open3' -assert_mruby = ->(exp_out_pattern, exp_err_pattern, exp_success, args) do +assert_mruby = ->(exp_out, exp_err, exp_success, args) do out, err, stat = Open3.capture3(cmd("mruby"), *args) - assert_match(exp_out_pattern, out, "standard output") - assert_match(exp_err_pattern, err, "standard error") + assert_operator(exp_out, :===, out, "standard output") + assert_operator(exp_err, :===, err, "standard error") assert_equal(exp_success, stat.success?, "exit success?") end assert('regression for #1564') do - assert_mruby.("", "-e:1:2: syntax error, *", false, %w[-e <<]) - assert_mruby.("", "-e:1:3: syntax error, *", false, %w[-e <<-]) + assert_mruby.("", /\A-e:1:2: syntax error, .*\n\z/, false, %w[-e <<]) + assert_mruby.("", /\A-e:1:3: syntax error, .*\n\z/, false, %w[-e <<-]) end assert('regression for #1572') do @@ -74,7 +74,7 @@ end assert('mruby -c option') do assert_mruby.("Syntax OK\n", "", true, ["-c", "-e", "p 1"]) - assert_mruby.("", "-e:1:7: syntax error, *", false, ["-c", "-e", "p 1; 1."]) + assert_mruby.("", /\A-e:1:7: syntax error, .*\n\z/, false, ["-c", "-e", "p 1; 1."]) end assert('mruby -d option') do @@ -85,11 +85,11 @@ assert('mruby -d option') do end assert('mruby -e option (no code specified)') do - assert_mruby.("", "* No code specified for -e\n", false, %w[-e]) + assert_mruby.("", /\A.*: No code specified for -e\n\z/, false, %w[-e]) end assert('mruby -h option') do - assert_mruby.("Usage: *mruby*", "", true, %w[-h]) + assert_mruby.(/\AUsage: #{Regexp.escape cmd("mruby")} .*/m, "", true, %w[-h]) end assert('mruby -r option') do @@ -116,25 +116,30 @@ EOS end assert('mruby -r option (no library specified)') do - assert_mruby.("", "*: No library specified for -r\n", false, %w[-r]) + assert_mruby.("", /\A.*: No library specified for -r\n\z/, false, %w[-r]) end assert('mruby -r option (file not found)') do - assert_mruby.("", "*: Cannot open library file: *", false, %w[-r _no_exists_]) + assert_mruby.("", /\A.*: Cannot open library file: .*\n\z/, false, %w[-r _no_exists_]) end assert('mruby invalid short option') do - assert_mruby.("", "*: invalid option -1 *", false, %w[-1]) + assert_mruby.("", /\A.*: invalid option -1 .*\n\z/, false, %w[-1]) end assert('mruby invalid long option') do - assert_mruby.("", "*: invalid option --longopt *", false, %w[--longopt]) + assert_mruby.("", /\A.*: invalid option --longopt .*\n\z/, false, %w[--longopt]) end assert('unhandled exception') do - assert_mruby.("", "* EXCEPTION!*", false, %w[-e raise("EXCEPTION!")]) + assert_mruby.("", /\bEXCEPTION\b.*\n\z/, false, %w[-e raise("EXCEPTION")]) end assert('program file not found') do - assert_mruby.("", "*: Cannot open program file*", false, %w[_no_exists_]) + assert_mruby.("", /\A.*: Cannot open program file: .*\n\z/, false, %w[_no_exists_]) +end + +assert('codegen error') do + code = "def f(#{(1..100).map{|n| "a#{n}"} * ","}); end" + assert_mruby.("", /\Acodegen error:.*\n\z/, false, ["-e", code]) end diff --git a/mrbgems/mruby-bin-mruby/tools/mruby/mruby.c b/mrbgems/mruby-bin-mruby/tools/mruby/mruby.c index c96365c9f..29ab4c17c 100644 --- a/mrbgems/mruby-bin-mruby/tools/mruby/mruby.c +++ b/mrbgems/mruby-bin-mruby/tools/mruby/mruby.c @@ -158,7 +158,7 @@ append_cmdline: else { args->rfp = fopen(argv[0], args->mrbfile ? "rb" : "r"); if (args->rfp == NULL) { - fprintf(stderr, "%s: Cannot open program file. (%s)\n", *origargv, *argv); + fprintf(stderr, "%s: Cannot open program file: %s\n", *origargv, *argv); return EXIT_FAILURE; } args->fname = TRUE; @@ -285,7 +285,7 @@ main(int argc, char **argv) n = EXIT_FAILURE; } else if (args.check_syntax) { - printf("Syntax OK\n"); + puts("Syntax OK"); } } cleanup(mrb, &args); -- cgit v1.2.3 From 95a92d35c89ec9c39c97c5f948255389a129029e Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Thu, 2 May 2019 20:45:31 +0900 Subject: Unify overflow error class for conversion to integer to `RangeError` --- src/numeric.c | 2 +- src/string.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/numeric.c b/src/numeric.c index 8205e41f6..101b338de 100644 --- a/src/numeric.c +++ b/src/numeric.c @@ -1230,7 +1230,7 @@ mrb_flo_to_fixnum(mrb_state *mrb, mrb_value x) z = (mrb_int)d; } else { - mrb_raisef(mrb, E_ARGUMENT_ERROR, "number (%S) too big for integer", x); + mrb_raisef(mrb, E_RANGE_ERROR, "number (%S) too big for integer", x); } } return mrb_fixnum_value(z); diff --git a/src/string.c b/src/string.c index 89ab59d4b..955ad57ce 100644 --- a/src/string.c +++ b/src/string.c @@ -2115,7 +2115,7 @@ mrb_str_len_to_inum(mrb_state *mrb, const char *str, mrb_int len, mrb_int base, else #endif { - mrb_raisef(mrb, E_ARGUMENT_ERROR, "string (%S) too big for integer", + mrb_raisef(mrb, E_RANGE_ERROR, "string (%S) too big for integer", mrb_str_new(mrb, str, pend-str)); } } -- cgit v1.2.3 From f83112cea21ba37ad9e3a1b27a0066e4dd6c6ae4 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Wed, 24 Apr 2019 12:43:19 +0900 Subject: Fixed include specifier format for `mruby/common.h`. --- include/mruby.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/mruby.h b/include/mruby.h index dcd64b2d8..20cdc1b83 100644 --- a/include/mruby.h +++ b/include/mruby.h @@ -84,7 +84,7 @@ #endif #endif -#include "mruby/common.h" +#include #include #include #include -- cgit v1.2.3 From 35319bed01d58c785f73ce03e67d4e58be30f4b5 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Thu, 2 May 2019 23:03:38 +0900 Subject: Use a normal method instead of a lambda in bintest/mruby; ref #4416 --- mrbgems/mruby-bin-mruby/bintest/mruby.rb | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/mrbgems/mruby-bin-mruby/bintest/mruby.rb b/mrbgems/mruby-bin-mruby/bintest/mruby.rb index d1262254b..09350ff49 100644 --- a/mrbgems/mruby-bin-mruby/bintest/mruby.rb +++ b/mrbgems/mruby-bin-mruby/bintest/mruby.rb @@ -1,7 +1,7 @@ require 'tempfile' require 'open3' -assert_mruby = ->(exp_out, exp_err, exp_success, args) do +def assert_mruby(exp_out, exp_err, exp_success, args) out, err, stat = Open3.capture3(cmd("mruby"), *args) assert_operator(exp_out, :===, out, "standard output") assert_operator(exp_err, :===, err, "standard error") @@ -9,8 +9,8 @@ assert_mruby = ->(exp_out, exp_err, exp_success, args) do end assert('regression for #1564') do - assert_mruby.("", /\A-e:1:2: syntax error, .*\n\z/, false, %w[-e <<]) - assert_mruby.("", /\A-e:1:3: syntax error, .*\n\z/, false, %w[-e <<-]) + assert_mruby("", /\A-e:1:2: syntax error, .*\n\z/, false, %w[-e <<]) + assert_mruby("", /\A-e:1:3: syntax error, .*\n\z/, false, %w[-e <<-]) end assert('regression for #1572') do @@ -73,8 +73,8 @@ RUBY end assert('mruby -c option') do - assert_mruby.("Syntax OK\n", "", true, ["-c", "-e", "p 1"]) - assert_mruby.("", /\A-e:1:7: syntax error, .*\n\z/, false, ["-c", "-e", "p 1; 1."]) + assert_mruby("Syntax OK\n", "", true, ["-c", "-e", "p 1"]) + assert_mruby("", /\A-e:1:7: syntax error, .*\n\z/, false, ["-c", "-e", "p 1; 1."]) end assert('mruby -d option') do @@ -85,11 +85,11 @@ assert('mruby -d option') do end assert('mruby -e option (no code specified)') do - assert_mruby.("", /\A.*: No code specified for -e\n\z/, false, %w[-e]) + assert_mruby("", /\A.*: No code specified for -e\n\z/, false, %w[-e]) end assert('mruby -h option') do - assert_mruby.(/\AUsage: #{Regexp.escape cmd("mruby")} .*/m, "", true, %w[-h]) + assert_mruby(/\AUsage: #{Regexp.escape cmd("mruby")} .*/m, "", true, %w[-h]) end assert('mruby -r option') do @@ -116,30 +116,30 @@ EOS end assert('mruby -r option (no library specified)') do - assert_mruby.("", /\A.*: No library specified for -r\n\z/, false, %w[-r]) + assert_mruby("", /\A.*: No library specified for -r\n\z/, false, %w[-r]) end assert('mruby -r option (file not found)') do - assert_mruby.("", /\A.*: Cannot open library file: .*\n\z/, false, %w[-r _no_exists_]) + assert_mruby("", /\A.*: Cannot open library file: .*\n\z/, false, %w[-r _no_exists_]) end assert('mruby invalid short option') do - assert_mruby.("", /\A.*: invalid option -1 .*\n\z/, false, %w[-1]) + assert_mruby("", /\A.*: invalid option -1 .*\n\z/, false, %w[-1]) end assert('mruby invalid long option') do - assert_mruby.("", /\A.*: invalid option --longopt .*\n\z/, false, %w[--longopt]) + assert_mruby("", /\A.*: invalid option --longopt .*\n\z/, false, %w[--longopt]) end assert('unhandled exception') do - assert_mruby.("", /\bEXCEPTION\b.*\n\z/, false, %w[-e raise("EXCEPTION")]) + assert_mruby("", /\bEXCEPTION\b.*\n\z/, false, %w[-e raise("EXCEPTION")]) end assert('program file not found') do - assert_mruby.("", /\A.*: Cannot open program file: .*\n\z/, false, %w[_no_exists_]) + assert_mruby("", /\A.*: Cannot open program file: .*\n\z/, false, %w[_no_exists_]) end assert('codegen error') do code = "def f(#{(1..100).map{|n| "a#{n}"} * ","}); end" - assert_mruby.("", /\Acodegen error:.*\n\z/, false, ["-e", code]) + assert_mruby("", /\Acodegen error:.*\n\z/, false, ["-e", code]) end -- cgit v1.2.3 From f5d5caaf82f68f5146594050d833cc1ceda6c72b Mon Sep 17 00:00:00 2001 From: dearblue Date: Fri, 3 May 2019 11:36:31 +0900 Subject: Clean duplicate code Removed duplicates in the code entered for "Concatenate string literal". --- mrbgems/mruby-compiler/core/parse.y | 55 ++++++++++++++++++------------------- 1 file changed, 27 insertions(+), 28 deletions(-) diff --git a/mrbgems/mruby-compiler/core/parse.y b/mrbgems/mruby-compiler/core/parse.y index 7838b6dfb..b7d47118f 100644 --- a/mrbgems/mruby-compiler/core/parse.y +++ b/mrbgems/mruby-compiler/core/parse.y @@ -913,40 +913,39 @@ concat_string(parser_state *p, node *a, node *b) } } } - else if (string_node_p(b)) { - /* a == NODE_DSTR && b == NODE_STR */ - - node *c; + else { + node *c; /* last node of a */ for (c = a; c->cdr != NULL; c = c->cdr) ; - if (string_node_p(c->car)) { - /* a->[..., NODE_STR] && b == NODE_STR */ - composite_string_node(p, c->car->cdr, b->cdr); - cons_free(b); - return a; - } - push(a, b); - return a; - } - else { - /* a == NODE_DSTR && b == NODE_DSTR */ + if (string_node_p(b)) { + /* a == NODE_DSTR && b == NODE_STR */ + if (string_node_p(c->car)) { + /* a->[..., NODE_STR] && b == NODE_STR */ + composite_string_node(p, c->car->cdr, b->cdr); + cons_free(b); + return a; + } - node *c, *d; - for (c = a; c->cdr != NULL; c = c->cdr) ; - if (string_node_p(c->car) && string_node_p(b->cdr->car)) { - /* a->[..., NODE_STR] && b->[NODE_STR, ...] */ - d = b->cdr; - cons_free(b); - composite_string_node(p, c->car->cdr, d->car->cdr); - cons_free(d->car); - c->cdr = d->cdr; - cons_free(d); + push(a, b); return a; } else { - c->cdr = b->cdr; - cons_free(b); - return a; + /* a == NODE_DSTR && b == NODE_DSTR */ + if (string_node_p(c->car) && string_node_p(b->cdr->car)) { + /* a->[..., NODE_STR] && b->[NODE_STR, ...] */ + node *d = b->cdr; + cons_free(b); + composite_string_node(p, c->car->cdr, d->car->cdr); + cons_free(d->car); + c->cdr = d->cdr; + cons_free(d); + return a; + } + else { + c->cdr = b->cdr; + cons_free(b); + return a; + } } } -- cgit v1.2.3 From e86e360b360029a432af42dbb414b7df21eb0c2b Mon Sep 17 00:00:00 2001 From: dearblue Date: Fri, 3 May 2019 11:42:14 +0900 Subject: Fix `FLAG_SRC_STATIC` always set in `mrb_read_irep()` with `MRB_USE_CUSTOM_RO_DATA_P` --- src/load.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/load.c b/src/load.c index ab0346750..70f18da31 100644 --- a/src/load.c +++ b/src/load.c @@ -608,7 +608,7 @@ read_irep(mrb_state *mrb, const uint8_t *bin, uint8_t flags) mrb_irep* mrb_read_irep(mrb_state *mrb, const uint8_t *bin) { -#ifdef MRB_USE_ETEXT_EDATA +#if defined(MRB_USE_ETEXT_EDATA) || defined(MRB_USE_CUSTOM_RO_DATA_P) uint8_t flags = mrb_ro_data_p((char*)bin) ? FLAG_SRC_STATIC : FLAG_SRC_MALLOC; #else uint8_t flags = FLAG_SRC_STATIC; -- cgit v1.2.3 From 0692f7916cc9865e276a58812186cac7f02dc042 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Fri, 3 May 2019 13:39:19 +0900 Subject: Simplify conversion process for `i` in `mrb_get_args()` --- src/class.c | 24 +----------------------- test/t/string.rb | 11 +++++++---- 2 files changed, 8 insertions(+), 27 deletions(-) diff --git a/src/class.c b/src/class.c index 254f5b005..2cabc820e 100644 --- a/src/class.c +++ b/src/class.c @@ -838,29 +838,7 @@ mrb_get_args(mrb_state *mrb, const char *format, ...) p = va_arg(ap, mrb_int*); if (i < argc) { - switch (mrb_type(ARGV[arg_i])) { - case MRB_TT_FIXNUM: - *p = mrb_fixnum(ARGV[arg_i]); - break; -#ifndef MRB_WITHOUT_FLOAT - case MRB_TT_FLOAT: - { - mrb_float f = mrb_float(ARGV[arg_i]); - - if (!FIXABLE_FLOAT(f)) { - mrb_raise(mrb, E_RANGE_ERROR, "float too big for int"); - } - *p = (mrb_int)f; - } - break; -#endif - case MRB_TT_STRING: - mrb_raise(mrb, E_TYPE_ERROR, "no implicit conversion of String into Integer"); - break; - default: - *p = mrb_fixnum(mrb_Integer(mrb, ARGV[arg_i])); - break; - } + *p = mrb_fixnum(mrb_to_int(mrb, ARGV[arg_i])); arg_i++; i++; } diff --git a/test/t/string.rb b/test/t/string.rb index e563db55a..e5b001366 100644 --- a/test/t/string.rb +++ b/test/t/string.rb @@ -37,11 +37,14 @@ end assert('String#*', '15.2.10.5.5') do assert_equal 'aaaaa', 'a' * 5 assert_equal '', 'a' * 0 - assert_raise(ArgumentError) do - 'a' * -1 - end + assert_equal 'aa', 'a' * 2.1 + assert_raise(ArgumentError) { 'a' * -1 } + assert_raise(RangeError) { '' * 1e30 } + assert_raise(RangeError) { '' * Float::INFINITY } + assert_raise(RangeError) { '' * Float::NAN } + assert_raise(TypeError) { 'a' * '1' } + assert_raise(TypeError) { 'a' * nil } end - assert('String#[]', '15.2.10.5.6') do # length of args is 1 a = 'abc'[0] -- cgit v1.2.3 From a5bda13fb76ba50c3742b24b854fb2e86c50b31d Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Sat, 4 May 2019 16:38:07 +0900 Subject: Check whether object is immediate in `mrb_gc_(register|unregister)` --- src/gc.c | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/src/gc.c b/src/gc.c index 27f3716ec..5e7440d50 100644 --- a/src/gc.c +++ b/src/gc.c @@ -466,9 +466,12 @@ mrb_gc_protect(mrb_state *mrb, mrb_value obj) MRB_API void mrb_gc_register(mrb_state *mrb, mrb_value obj) { - mrb_sym root = mrb_intern_lit(mrb, GC_ROOT_NAME); - mrb_value table = mrb_gv_get(mrb, root); + mrb_sym root; + mrb_value table; + if (mrb_immediate_p(obj)) return; + root = mrb_intern_lit(mrb, GC_ROOT_NAME); + table = mrb_gv_get(mrb, root); if (mrb_nil_p(table) || mrb_type(table) != MRB_TT_ARRAY) { table = mrb_ary_new(mrb); mrb_gv_set(mrb, root, table); @@ -480,11 +483,14 @@ mrb_gc_register(mrb_state *mrb, mrb_value obj) MRB_API void mrb_gc_unregister(mrb_state *mrb, mrb_value obj) { - mrb_sym root = mrb_intern_lit(mrb, GC_ROOT_NAME); - mrb_value table = mrb_gv_get(mrb, root); + mrb_sym root; + mrb_value table; struct RArray *a; mrb_int i; + if (mrb_immediate_p(obj)) return; + root = mrb_intern_lit(mrb, GC_ROOT_NAME); + table = mrb_gv_get(mrb, root); if (mrb_nil_p(table)) return; if (mrb_type(table) != MRB_TT_ARRAY) { mrb_gv_set(mrb, root, mrb_nil_value()); -- cgit v1.2.3 From 0ccb058b90e5b3f50c185f8e642cd358a6edca87 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Sun, 5 May 2019 20:31:12 +0900 Subject: Use `mrb_fixnum_to_str()` instead of `Fixnum#to_s` --- mrbgems/mruby-socket/src/socket.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/mrbgems/mruby-socket/src/socket.c b/mrbgems/mruby-socket/src/socket.c index dff176778..2a8ae1b2c 100644 --- a/mrbgems/mruby-socket/src/socket.c +++ b/mrbgems/mruby-socket/src/socket.c @@ -38,6 +38,7 @@ #include "mruby/array.h" #include "mruby/class.h" #include "mruby/data.h" +#include "mruby/numeric.h" #include "mruby/string.h" #include "mruby/variable.h" #include "error.h" @@ -140,7 +141,7 @@ mrb_addrinfo_getaddrinfo(mrb_state *mrb, mrb_value klass) if (mrb_string_p(service)) { servname = mrb_str_to_cstr(mrb, service); } else if (mrb_fixnum_p(service)) { - servname = mrb_str_to_cstr(mrb, mrb_funcall(mrb, service, "to_s", 0)); + servname = RSTRING_PTR(mrb_fixnum_to_str(mrb, service, 10)); } else if (mrb_nil_p(service)) { servname = NULL; } else { -- cgit v1.2.3 From e2604c1550562b6fa507570e817cadf9981e1c82 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Mon, 6 May 2019 23:16:03 +0900 Subject: Avoid using `mrb_str_to_cstr` if possible Because it always allocate new string. Replace with the followings: - Use `RSRING_PTR` if string is guaranteed to be null-terminated. - Use `mrb_string_value_cstr` or `mrb_get_args("z")` if return value isn't modified. --- mrbgems/mruby-io/src/file.c | 21 ++++++++++----------- mrbgems/mruby-io/src/file_test.c | 2 +- mrbgems/mruby-io/test/mruby_io_test.c | 6 ++---- mrbgems/mruby-socket/src/socket.c | 4 ++-- 4 files changed, 15 insertions(+), 18 deletions(-) diff --git a/mrbgems/mruby-io/src/file.c b/mrbgems/mruby-io/src/file.c index c00663481..b17b95e24 100644 --- a/mrbgems/mruby-io/src/file.c +++ b/mrbgems/mruby-io/src/file.c @@ -146,7 +146,7 @@ mrb_file_s_rename(mrb_state *mrb, mrb_value obj) #endif mrb_locale_free(src); mrb_locale_free(dst); - mrb_sys_fail(mrb, mrb_str_to_cstr(mrb, mrb_format(mrb, "(%S, %S)", from, to))); + mrb_sys_fail(mrb, RSTRING_PTR(mrb_format(mrb, "(%S, %S)", from, to))); } mrb_locale_free(src); mrb_locale_free(dst); @@ -159,12 +159,12 @@ mrb_file_dirname(mrb_state *mrb, mrb_value klass) #if defined(_WIN32) || defined(_WIN64) char dname[_MAX_DIR], vname[_MAX_DRIVE]; char buffer[_MAX_DRIVE + _MAX_DIR]; + const char *utf8_path; char *path; size_t ridx; - mrb_value s; - mrb_get_args(mrb, "S", &s); - path = mrb_locale_from_utf8(mrb_str_to_cstr(mrb, s), -1); - _splitpath((const char*)path, vname, dname, NULL, NULL); + mrb_get_args(mrb, "z", &utf8_path); + path = mrb_locale_from_utf8(utf8_path, -1); + _splitpath(path, vname, dname, NULL, NULL); snprintf(buffer, _MAX_DRIVE + _MAX_DIR, "%s%s", vname, dname); mrb_locale_free(path); ridx = strlen(buffer); @@ -248,7 +248,7 @@ mrb_file_realpath(mrb_state *mrb, mrb_value klass) s = mrb_str_append(mrb, s, pathname); pathname = s; } - cpath = mrb_locale_from_utf8(mrb_str_to_cstr(mrb, pathname), -1); + cpath = mrb_locale_from_utf8(mrb_string_value_cstr(mrb, &pathname), -1); result = mrb_str_buf_new(mrb, PATH_MAX); if (realpath(cpath, RSTRING_PTR(result)) == NULL) { mrb_locale_free(cpath); @@ -300,7 +300,7 @@ mrb_file__gethome(mrb_state *mrb, mrb_value klass) mrb_raise(mrb, E_ARGUMENT_ERROR, "non-absolute home"); } } else { - const char *cuser = mrb_str_to_cstr(mrb, username); + const char *cuser = mrb_string_value_cstr(mrb, &username); struct passwd *pwd = getpwnam(cuser); if (pwd == NULL) { return mrb_nil_value(); @@ -393,9 +393,8 @@ mrb_file_s_symlink(mrb_state *mrb, mrb_value klass) int ai = mrb_gc_arena_save(mrb); mrb_get_args(mrb, "SS", &from, &to); - src = mrb_locale_from_utf8(mrb_str_to_cstr(mrb, from), -1); - dst = mrb_locale_from_utf8(mrb_str_to_cstr(mrb, to), -1); - + src = mrb_locale_from_utf8(mrb_string_value_cstr(mrb, &from), -1); + dst = mrb_locale_from_utf8(mrb_string_value_cstr(mrb, &to), -1); if (symlink(src, dst) == -1) { mrb_locale_free(src); mrb_locale_free(dst); @@ -417,7 +416,7 @@ mrb_file_s_chmod(mrb_state *mrb, mrb_value klass) { mrb_get_args(mrb, "i*", &mode, &filenames, &argc); for (i = 0; i < argc; i++) { - const char *utf8_path = mrb_str_to_cstr(mrb, filenames[i]); + const char *utf8_path = mrb_string_value_cstr(mrb, &filenames[i]); char *path = mrb_locale_from_utf8(utf8_path, -1); if (CHMOD(path, mode) == -1) { mrb_locale_free(path); diff --git a/mrbgems/mruby-io/src/file_test.c b/mrbgems/mruby-io/src/file_test.c index e429b06b3..7d36f79b3 100644 --- a/mrbgems/mruby-io/src/file_test.c +++ b/mrbgems/mruby-io/src/file_test.c @@ -63,7 +63,7 @@ mrb_stat0(mrb_state *mrb, mrb_value obj, struct stat *st, int do_lstat) tmp = mrb_funcall(mrb, obj, "is_a?", 1, str_klass); if (mrb_test(tmp)) { - char *path = mrb_locale_from_utf8(mrb_str_to_cstr(mrb, obj), -1); + char *path = mrb_locale_from_utf8(mrb_string_value_cstr(mrb, &obj), -1); int ret; if (do_lstat) { ret = LSTAT(path, st); diff --git a/mrbgems/mruby-io/test/mruby_io_test.c b/mrbgems/mruby-io/test/mruby_io_test.c index 71239a827..3312d6c7e 100644 --- a/mrbgems/mruby-io/test/mruby_io_test.c +++ b/mrbgems/mruby-io/test/mruby_io_test.c @@ -215,11 +215,9 @@ mrb_io_test_mkdtemp(mrb_state *mrb, mrb_value klass) static mrb_value mrb_io_test_rmdir(mrb_state *mrb, mrb_value klass) { - mrb_value str; - char *cp; + const char *cp; - mrb_get_args(mrb, "S", &str); - cp = mrb_str_to_cstr(mrb, str); + mrb_get_args(mrb, "z", &cp); if (rmdir(cp) == -1) { mrb_sys_fail(mrb, "rmdir"); } diff --git a/mrbgems/mruby-socket/src/socket.c b/mrbgems/mruby-socket/src/socket.c index 2a8ae1b2c..8515a6057 100644 --- a/mrbgems/mruby-socket/src/socket.c +++ b/mrbgems/mruby-socket/src/socket.c @@ -131,7 +131,7 @@ mrb_addrinfo_getaddrinfo(mrb_state *mrb, mrb_value klass) mrb_get_args(mrb, "oo|oooi", &nodename, &service, &family, &socktype, &protocol, &flags); if (mrb_string_p(nodename)) { - hostname = mrb_str_to_cstr(mrb, nodename); + hostname = mrb_string_value_cstr(mrb, &nodename); } else if (mrb_nil_p(nodename)) { hostname = NULL; } else { @@ -139,7 +139,7 @@ mrb_addrinfo_getaddrinfo(mrb_state *mrb, mrb_value klass) } if (mrb_string_p(service)) { - servname = mrb_str_to_cstr(mrb, service); + servname = mrb_string_value_cstr(mrb, &service); } else if (mrb_fixnum_p(service)) { servname = RSTRING_PTR(mrb_fixnum_to_str(mrb, service, 10)); } else if (mrb_nil_p(service)) { -- cgit v1.2.3 From 35943e7beb0e4fd22f2096b56817e0cf22b8cf42 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Tue, 7 May 2019 23:01:13 +0900 Subject: Refactor `mrb_str_to_cstr` and `mrb_string_value_cstr` - Extract null byte check to function. - Avoid string allocation if null byte is included. - Use `str_new` instead of `mrb_str_dup` + `mrb_str_modify` --- mrbgems/mruby-io/test/file.rb | 3 +++ src/string.c | 42 ++++++++++++++++++++++++++---------------- 2 files changed, 29 insertions(+), 16 deletions(-) diff --git a/mrbgems/mruby-io/test/file.rb b/mrbgems/mruby-io/test/file.rb index 88ced31a6..1535ebb44 100644 --- a/mrbgems/mruby-io/test/file.rb +++ b/mrbgems/mruby-io/test/file.rb @@ -33,6 +33,7 @@ assert('File.basename') do assert_equal 'a', File.basename('/a/') assert_equal 'b', File.basename('/a/b') assert_equal 'b', File.basename('../a/b') + assert_raise(ArgumentError) { File.basename("/a/b\0") } end assert('File.dirname') do @@ -106,6 +107,8 @@ assert('File.realpath') do MRubyIOTestUtil.rmdir dir end end + + assert_raise(ArgumentError) { File.realpath("TO\0DO") } end assert("File.readlink") do diff --git a/src/string.c b/src/string.c index f043bfd5a..7fc405a2b 100644 --- a/src/string.c +++ b/src/string.c @@ -194,6 +194,15 @@ str_decref(mrb_state *mrb, mrb_shared_string *shared) } } +static void +check_null_byte(mrb_state *mrb, mrb_value str) +{ + mrb_to_str(mrb, str); + if (memchr(RSTRING_PTR(str), '\0', RSTRING_LEN(str))) { + mrb_raise(mrb, E_ARGUMENT_ERROR, "string contains null byte"); + } +} + void mrb_gc_free_str(mrb_state *mrb, struct RString *str) { @@ -723,14 +732,8 @@ mrb_str_to_cstr(mrb_state *mrb, mrb_value str0) { struct RString *s; - if (!mrb_string_p(str0)) { - mrb_raise(mrb, E_TYPE_ERROR, "expected String"); - } - + check_null_byte(mrb, str0); s = str_new(mrb, RSTRING_PTR(str0), RSTRING_LEN(str0)); - if ((strlen(RSTR_PTR(s)) ^ RSTR_LEN(s)) != 0) { - mrb_raise(mrb, E_ARGUMENT_ERROR, "string contains null byte"); - } return RSTR_PTR(s); } @@ -2144,20 +2147,27 @@ mrb_cstr_to_inum(mrb_state *mrb, const char *str, mrb_int base, mrb_bool badchec MRB_API const char* mrb_string_value_cstr(mrb_state *mrb, mrb_value *ptr) { - mrb_value str = mrb_to_str(mrb, *ptr); - struct RString *ps = mrb_str_ptr(str); - mrb_int len = mrb_str_strlen(mrb, ps); - char *p = RSTR_PTR(ps); + struct RString *ps; + const char *p; + mrb_int len; - if (!p || p[len] != '\0') { + check_null_byte(mrb, *ptr); + ps = mrb_str_ptr(*ptr); + p = RSTR_PTR(ps); + len = RSTR_LEN(ps); + if (p[len] == '\0') { + return p; + } + else { if (MRB_FROZEN_P(ps)) { - *ptr = str = mrb_str_dup(mrb, str); - ps = mrb_str_ptr(str); + ps = str_new(mrb, p, len); + *ptr = mrb_obj_value(ps); + } + else { + mrb_str_modify(mrb, ps); } - mrb_str_modify(mrb, ps); return RSTR_PTR(ps); } - return p; } MRB_API mrb_value -- cgit v1.2.3 From 1975dedb214b9d181630c337374702a1b4725288 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Wed, 8 May 2019 20:35:03 +0900 Subject: Use `mrb_string_value_cstr` in `mrb_str_to_dbl` --- mrbgems/mruby-kernel-ext/test/kernel.rb | 2 ++ src/string.c | 17 +---------------- 2 files changed, 3 insertions(+), 16 deletions(-) diff --git a/mrbgems/mruby-kernel-ext/test/kernel.rb b/mrbgems/mruby-kernel-ext/test/kernel.rb index 28f089007..ad9177165 100644 --- a/mrbgems/mruby-kernel-ext/test/kernel.rb +++ b/mrbgems/mruby-kernel-ext/test/kernel.rb @@ -65,6 +65,8 @@ assert('Kernel#Float') do assert_equal(123.456, Float(123.456)) assert_equal(123.456, Float("123.456")) assert_raise(TypeError) { Float(nil) } + assert_raise(ArgumentError) { Float("1.5a") } + assert_raise(ArgumentError) { Float("1.5\0") } end assert('Kernel#String') do diff --git a/src/string.c b/src/string.c index 7fc405a2b..578e3bdcc 100644 --- a/src/string.c +++ b/src/string.c @@ -2281,22 +2281,7 @@ bad: MRB_API double mrb_str_to_dbl(mrb_state *mrb, mrb_value str, mrb_bool badcheck) { - char *s; - mrb_int len; - - mrb_to_str(mrb, str); - s = RSTRING_PTR(str); - len = RSTRING_LEN(str); - if (s) { - if (badcheck && memchr(s, '\0', len)) { - mrb_raise(mrb, E_ARGUMENT_ERROR, "string for Float contains null byte"); - } - if (s[len]) { /* no sentinel somehow */ - struct RString *temp_str = str_new(mrb, s, len); - s = RSTR_PTR(temp_str); - } - } - return mrb_cstr_to_dbl(mrb, s, badcheck); + return mrb_cstr_to_dbl(mrb, mrb_string_value_cstr(mrb, &str), badcheck); } /* 15.2.10.5.39 */ -- cgit v1.2.3 From 9a4f3029d98f50f2142af99ba3dea4c504849593 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Sat, 4 May 2019 21:56:55 +0900 Subject: Update `README.md`; mruby is now Ruby 2.x compatible. --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 3e71ef7ca..2acc8de1a 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@ ## What is mruby mruby is the lightweight implementation of the Ruby language complying to (part -of) the [ISO standard][ISO-standard]. Its syntax is Ruby 1.9 compatible. +of) the [ISO standard][ISO-standard]. Its syntax is Ruby 2.x compatible. mruby can be linked and embedded within your application. We provide the interpreter program "mruby" and the interactive mruby shell "mirb" as examples. -- cgit v1.2.3 From 0d94a2e3a917b39ffcf4ed930edeacf9fabcff5b Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Thu, 9 May 2019 23:26:40 +0900 Subject: Raise `TypeError` if the argument type is unsupported in `mrb_stat0` --- mrbgems/mruby-io/src/file_test.c | 15 ++------------- mrbgems/mruby-io/test/file_test.rb | 5 ++--- 2 files changed, 4 insertions(+), 16 deletions(-) diff --git a/mrbgems/mruby-io/src/file_test.c b/mrbgems/mruby-io/src/file_test.c index 7d36f79b3..ec731b094 100644 --- a/mrbgems/mruby-io/src/file_test.c +++ b/mrbgems/mruby-io/src/file_test.c @@ -42,14 +42,7 @@ extern struct mrb_data_type mrb_io_type; static int mrb_stat0(mrb_state *mrb, mrb_value obj, struct stat *st, int do_lstat) { - mrb_value tmp; - mrb_value io_klass, str_klass; - - io_klass = mrb_obj_value(mrb_class_get(mrb, "IO")); - str_klass = mrb_obj_value(mrb_class_get(mrb, "String")); - - tmp = mrb_funcall(mrb, obj, "is_a?", 1, io_klass); - if (mrb_test(tmp)) { + if (mrb_obj_is_kind_of(mrb, obj, mrb_class_get(mrb, "IO"))) { struct mrb_io *fptr; fptr = (struct mrb_io *)mrb_get_datatype(mrb, obj, &mrb_io_type); @@ -60,9 +53,7 @@ mrb_stat0(mrb_state *mrb, mrb_value obj, struct stat *st, int do_lstat) mrb_raise(mrb, E_IO_ERROR, "closed stream"); return -1; } - - tmp = mrb_funcall(mrb, obj, "is_a?", 1, str_klass); - if (mrb_test(tmp)) { + else { char *path = mrb_locale_from_utf8(mrb_string_value_cstr(mrb, &obj), -1); int ret; if (do_lstat) { @@ -73,8 +64,6 @@ mrb_stat0(mrb_state *mrb, mrb_value obj, struct stat *st, int do_lstat) mrb_locale_free(path); return ret; } - - return -1; } static int diff --git a/mrbgems/mruby-io/test/file_test.rb b/mrbgems/mruby-io/test/file_test.rb index 72e921ce9..2134c6a75 100644 --- a/mrbgems/mruby-io/test/file_test.rb +++ b/mrbgems/mruby-io/test/file_test.rb @@ -20,9 +20,8 @@ assert("FileTest.exist?") do assert_equal true, FileTest.exist?(io), "io obj - exist" io.close assert_equal true, io.closed? - assert_raise IOError do - FileTest.exist?(io) - end + assert_raise(IOError) { FileTest.exist?(io) } + assert_raise(TypeError) { File.exist?($mrbtest_io_rfname.to_sym) } end assert("FileTest.file?") do -- cgit v1.2.3 From f2719e903aef90bc1e8c45f866abb3471c2d6e52 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Fri, 10 May 2019 20:52:15 +0900 Subject: Move `mrb_gc_arena_restore` to inside the loop in `mrb_file_s_chmod` --- mrbgems/mruby-io/src/file.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mrbgems/mruby-io/src/file.c b/mrbgems/mruby-io/src/file.c index b17b95e24..243f634b4 100644 --- a/mrbgems/mruby-io/src/file.c +++ b/mrbgems/mruby-io/src/file.c @@ -423,9 +423,9 @@ mrb_file_s_chmod(mrb_state *mrb, mrb_value klass) { mrb_sys_fail(mrb, utf8_path); } mrb_locale_free(path); + mrb_gc_arena_restore(mrb, ai); } - mrb_gc_arena_restore(mrb, ai); return mrb_fixnum_value(argc); } -- cgit v1.2.3 From 1e2983bd043d91a21d2594dea8460194afad489b Mon Sep 17 00:00:00 2001 From: Bhargava Shastry Date: Fri, 10 May 2019 16:13:05 +0200 Subject: Update ossfuzz options --- oss-fuzz/config/mruby_fuzzer.options | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/oss-fuzz/config/mruby_fuzzer.options b/oss-fuzz/config/mruby_fuzzer.options index 5d1c8d2da..132affcae 100644 --- a/oss-fuzz/config/mruby_fuzzer.options +++ b/oss-fuzz/config/mruby_fuzzer.options @@ -1,3 +1,5 @@ [libfuzzer] -close_fd_mask=3 -dict=mruby.dict +close_fd_mask = 3 +dict = mruby.dict +fork = 8 +only_ascii = 1 -- cgit v1.2.3 From fa317fabbd400204dfb11171155c30feb92a2293 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Sat, 11 May 2019 18:40:33 +0900 Subject: Use `mrb_ensure_string_type` in `mrb_to_str` --- src/object.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/object.c b/src/object.c index d45ab27c7..7c1879019 100644 --- a/src/object.c +++ b/src/object.c @@ -584,11 +584,7 @@ mrb_Float(mrb_state *mrb, mrb_value val) MRB_API mrb_value mrb_to_str(mrb_state *mrb, mrb_value val) { - if (!mrb_string_p(val)) { - mrb_value type = inspect_type(mrb, val); - mrb_raisef(mrb, E_TYPE_ERROR, "can't convert %S to String", type); - } - return val; + return mrb_ensure_string_type(mrb, val); } /* obsolete: use mrb_ensure_string_type() instead */ -- cgit v1.2.3 From 2c2584138a28de2cffeed8f2b2171e4415cad480 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Sun, 12 May 2019 20:25:11 +0900 Subject: Fix missing assertions in `mruby-time` test --- mrbgems/mruby-time/test/time.rb | 122 +++++++++++++++++++++++++--------------- 1 file changed, 78 insertions(+), 44 deletions(-) diff --git a/mrbgems/mruby-time/test/time.rb b/mrbgems/mruby-time/test/time.rb index 54c446ca3..8a93b4938 100644 --- a/mrbgems/mruby-time/test/time.rb +++ b/mrbgems/mruby-time/test/time.rb @@ -2,11 +2,11 @@ # Time ISO Test assert('Time.new', '15.2.3.3.3') do - Time.new.class == Time + assert_equal(Time, Time.new.class) end assert('Time', '15.2.19') do - Time.class == Class + assert_equal(Class, Time.class) end assert('Time.at', '15.2.19.6.1') do @@ -21,23 +21,51 @@ assert('Time.at', '15.2.19.6.1') do end assert('Time.gm', '15.2.19.6.2') do - Time.gm(2012, 12, 23) + t = Time.gm(2012, 9, 23) + assert_operator(2012, :eql?, t.year) + assert_operator( 9, :eql?, t.month) + assert_operator( 23, :eql?, t.day) + assert_operator( 0, :eql?, t.hour) + assert_operator( 0, :eql?, t.min) + assert_operator( 0, :eql?, t.sec) + assert_operator( 0, :eql?, t.usec) end assert('Time.local', '15.2.19.6.3') do - Time.local(2012, 12, 23) + t = Time.local(2014, 12, 27, 18) + assert_operator(2014, :eql?, t.year) + assert_operator( 12, :eql?, t.month) + assert_operator( 27, :eql?, t.day) + assert_operator( 18, :eql?, t.hour) + assert_operator( 0, :eql?, t.min) + assert_operator( 0, :eql?, t.sec) + assert_operator( 0, :eql?, t.usec) end assert('Time.mktime', '15.2.19.6.4') do - Time.mktime(2012, 12, 23) + t = Time.mktime(2013, 10, 4, 6, 15, 58, 3485) + assert_operator(2013, :eql?, t.year) + assert_operator( 10, :eql?, t.month) + assert_operator( 4, :eql?, t.day) + assert_operator( 6, :eql?, t.hour) + assert_operator( 15, :eql?, t.min) + assert_operator( 58, :eql?, t.sec) + assert_operator(3485, :eql?, t.usec) end assert('Time.now', '15.2.19.6.5') do - Time.now.class == Time + assert_equal(Time, Time.now.class) end assert('Time.utc', '15.2.19.6.6') do - Time.utc(2012, 12, 23) + t = Time.utc(2134) + assert_operator(2134, :eql?, t.year) + assert_operator( 1, :eql?, t.month) + assert_operator( 1, :eql?, t.day) + assert_operator( 0, :eql?, t.hour) + assert_operator( 0, :eql?, t.min) + assert_operator( 0, :eql?, t.sec) + assert_operator( 0, :eql?, t.usec) end assert('Time#+', '15.2.19.7.1') do @@ -67,30 +95,30 @@ assert('Time#<=>', '15.2.19.7.3') do t2 = Time.at(1400000000.0) t3 = Time.at(1500000000.0) - t2.<=>(t1) == 1 and - t2.<=>(t2) == 0 and - t2.<=>(t3) == -1 and - t2.<=>(nil) == nil + assert_equal(1, t2 <=> t1) + assert_equal(0, t2 <=> t2) + assert_equal(-1, t2 <=> t3) + assert_nil(t2 <=> nil) end assert('Time#asctime', '15.2.19.7.4') do - Time.at(1300000000.0).utc.asctime == "Sun Mar 13 07:06:40 UTC 2011" + assert_equal("Sun Mar 13 07:06:40 UTC 2011", Time.at(1300000000.0).utc.asctime) end assert('Time#ctime', '15.2.19.7.5') do - Time.at(1300000000.0).utc.ctime == "Sun Mar 13 07:06:40 UTC 2011" + assert_equal("Sun Mar 13 07:06:40 UTC 2011", Time.at(1300000000.0).utc.ctime) end assert('Time#day', '15.2.19.7.6') do - Time.gm(2012, 12, 23).day == 23 + assert_equal(23, Time.gm(2012, 12, 23).day) end assert('Time#dst?', '15.2.19.7.7') do - not Time.gm(2012, 12, 23).utc.dst? + assert_not_predicate(Time.gm(2012, 12, 23).utc, :dst?) end assert('Time#getgm', '15.2.19.7.8') do - Time.at(1300000000.0).getgm.asctime == "Sun Mar 13 07:06:40 UTC 2011" + assert_equal("Sun Mar 13 07:06:40 UTC 2011", Time.at(1300000000.0).getgm.asctime) end assert('Time#getlocal', '15.2.19.7.9') do @@ -98,114 +126,120 @@ assert('Time#getlocal', '15.2.19.7.9') do t2 = Time.at(1300000000.0) t3 = t1.getlocal - t1 == t3 and t3 == t2.getlocal + assert_equal(t1, t3) + assert_equal(t3, t2.getlocal) end assert('Time#getutc', '15.2.19.7.10') do - Time.at(1300000000.0).getutc.asctime == "Sun Mar 13 07:06:40 UTC 2011" + assert_equal("Sun Mar 13 07:06:40 UTC 2011", Time.at(1300000000.0).getutc.asctime) end assert('Time#gmt?', '15.2.19.7.11') do - Time.at(1300000000.0).utc.gmt? + assert_predicate(Time.at(1300000000.0).utc, :gmt?) end # ATM not implemented # assert('Time#gmt_offset', '15.2.19.7.12') do assert('Time#gmtime', '15.2.19.7.13') do - Time.at(1300000000.0).gmtime + t = Time.now + assert_predicate(t.gmtime, :gmt?) + assert_predicate(t, :gmt?) end # ATM not implemented # assert('Time#gmtoff', '15.2.19.7.14') do assert('Time#hour', '15.2.19.7.15') do - Time.gm(2012, 12, 23, 7, 6).hour == 7 + assert_equal(7, Time.gm(2012, 12, 23, 7, 6).hour) end # ATM doesn't really work # assert('Time#initialize', '15.2.19.7.16') do assert('Time#initialize_copy', '15.2.19.7.17') do - time_tmp_2 = Time.at(7.0e6) - time_tmp_2.clone == time_tmp_2 + t = Time.at(7.0e6) + assert_equal(t, t.clone) end assert('Time#localtime', '15.2.19.7.18') do - t1 = Time.at(1300000000.0) - t2 = Time.at(1300000000.0) + t1 = Time.utc(2014, 5 ,6) + t2 = Time.utc(2014, 5 ,6) + t3 = t2.getlocal - t1.localtime - t1 == t2.getlocal + assert_equal(t3, t1.localtime) + assert_equal(t3, t1) end assert('Time#mday', '15.2.19.7.19') do - Time.gm(2012, 12, 23).mday == 23 + assert_equal(23, Time.gm(2012, 12, 23).mday) end assert('Time#min', '15.2.19.7.20') do - Time.gm(2012, 12, 23, 7, 6).min == 6 + assert_equal(6, Time.gm(2012, 12, 23, 7, 6).min) end assert('Time#mon', '15.2.19.7.21') do - Time.gm(2012, 12, 23).mon == 12 + assert_equal(12, Time.gm(2012, 12, 23).mon) end assert('Time#month', '15.2.19.7.22') do - Time.gm(2012, 12, 23).month == 12 + assert_equal(12, Time.gm(2012, 12, 23).month) end assert('Times#sec', '15.2.19.7.23') do - Time.gm(2012, 12, 23, 7, 6, 40).sec == 40 + assert_equal(40, Time.gm(2012, 12, 23, 7, 6, 40).sec) end assert('Time#to_f', '15.2.19.7.24') do - Time.at(1300000000.0).to_f == 1300000000.0 + assert_operator(2.0, :eql?, Time.at(2).to_f) end assert('Time#to_i', '15.2.19.7.25') do - Time.at(1300000000.0).to_i == 1300000000 + assert_operator(2, :eql?, Time.at(2.0).to_i) end assert('Time#usec', '15.2.19.7.26') do - Time.at(1300000000.0).usec == 0 + assert_equal(0, Time.at(1300000000.0).usec) end assert('Time#utc', '15.2.19.7.27') do - Time.at(1300000000.0).utc + t = Time.now + assert_predicate(t.utc, :gmt?) + assert_predicate(t, :gmt?) end assert('Time#utc?', '15.2.19.7.28') do - Time.at(1300000000.0).utc.utc? + assert_predicate(Time.at(1300000000.0).utc, :utc?) end # ATM not implemented # assert('Time#utc_offset', '15.2.19.7.29') do assert('Time#wday', '15.2.19.7.30') do - Time.gm(2012, 12, 23).wday == 0 + assert_equal(0, Time.gm(2012, 12, 23).wday) end assert('Time#yday', '15.2.19.7.31') do - Time.gm(2012, 12, 23).yday == 358 + assert_equal(358, Time.gm(2012, 12, 23).yday) end assert('Time#year', '15.2.19.7.32') do - Time.gm(2012, 12, 23).year == 2012 + assert_equal(2012, Time.gm(2012, 12, 23).year) end assert('Time#zone', '15.2.19.7.33') do - Time.at(1300000000.0).utc.zone == 'UTC' + assert_equal('UTC', Time.at(1300000000.0).utc.zone) end # Not ISO specified assert('Time#to_s') do - Time.at(1300000000.0).utc.to_s == "Sun Mar 13 07:06:40 UTC 2011" + assert_equal("Sun Mar 13 07:06:40 UTC 2011", Time.at(1300000000.0).utc.to_s) end assert('Time#inspect') do - Time.at(1300000000.0).utc.inspect == "Sun Mar 13 07:06:40 UTC 2011" + assert_equal("Sun Mar 13 07:06:40 UTC 2011", Time.at(1300000000.0).utc.inspect) end assert('day of week methods') do @@ -224,7 +258,7 @@ assert('2000 times 500us make a second') do 2000.times do t += 0.0005 end - t.usec == 0 + assert_equal(0, t.usec) end assert('Time.gm with Dec 31 23:59:59 1969 raise ArgumentError') do -- cgit v1.2.3 From a2616db4dc810aa44d90d768a627c62d2a67886c Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Mon, 13 May 2019 19:46:26 +0900 Subject: Fix `Time#(asctime|ctime)` according to ISO Ruby - A leading charactor for day is space. - Time zone does not included. Before this patch: Time.gm(1982,3,4,5,6,7).asctime #=> "Thu Mar 04 05:06:07 UTC 1982" After this patch: Time.gm(1982,3,4,5,6,7).asctime #=> "Thu Mar 4 05:06:07 1982" --- mrbgems/mruby-time/src/time.c | 3 +-- mrbgems/mruby-time/test/time.rb | 20 ++++++++++---------- 2 files changed, 11 insertions(+), 12 deletions(-) diff --git a/mrbgems/mruby-time/src/time.c b/mrbgems/mruby-time/src/time.c index 7f6c3004d..bc8abc7ae 100644 --- a/mrbgems/mruby-time/src/time.c +++ b/mrbgems/mruby-time/src/time.c @@ -576,10 +576,9 @@ mrb_time_asctime(mrb_state *mrb, mrb_value self) #else char buf[256]; - len = snprintf(buf, sizeof(buf), "%s %s %02d %02d:%02d:%02d %s%d", + len = snprintf(buf, sizeof(buf), "%s %s %2d %02d:%02d:%02d %.4d", wday_names[d->tm_wday], mon_names[d->tm_mon], d->tm_mday, d->tm_hour, d->tm_min, d->tm_sec, - tm->timezone == MRB_TIMEZONE_UTC ? "UTC " : "", d->tm_year + 1900); #endif return mrb_str_new(mrb, buf, len); diff --git a/mrbgems/mruby-time/test/time.rb b/mrbgems/mruby-time/test/time.rb index 8a93b4938..c7ad35ab2 100644 --- a/mrbgems/mruby-time/test/time.rb +++ b/mrbgems/mruby-time/test/time.rb @@ -58,8 +58,8 @@ assert('Time.now', '15.2.19.6.5') do end assert('Time.utc', '15.2.19.6.6') do - t = Time.utc(2134) - assert_operator(2134, :eql?, t.year) + t = Time.utc(2034) + assert_operator(2034, :eql?, t.year) assert_operator( 1, :eql?, t.month) assert_operator( 1, :eql?, t.day) assert_operator( 0, :eql?, t.hour) @@ -72,7 +72,7 @@ assert('Time#+', '15.2.19.7.1') do t1 = Time.at(1300000000.0) t2 = t1.+(60) - assert_equal(t2.utc.asctime, "Sun Mar 13 07:07:40 UTC 2011") + assert_equal(t2.utc.asctime, "Sun Mar 13 07:07:40 2011") assert_raise(FloatDomainError) { Time.at(0) + Float::NAN } assert_raise(FloatDomainError) { Time.at(0) + Float::INFINITY } @@ -83,7 +83,7 @@ assert('Time#-', '15.2.19.7.2') do t1 = Time.at(1300000000.0) t2 = t1.-(60) - assert_equal(t2.utc.asctime, "Sun Mar 13 07:05:40 UTC 2011") + assert_equal(t2.utc.asctime, "Sun Mar 13 07:05:40 2011") assert_raise(FloatDomainError) { Time.at(0) - Float::NAN } assert_raise(FloatDomainError) { Time.at(0) - Float::INFINITY } @@ -102,11 +102,11 @@ assert('Time#<=>', '15.2.19.7.3') do end assert('Time#asctime', '15.2.19.7.4') do - assert_equal("Sun Mar 13 07:06:40 UTC 2011", Time.at(1300000000.0).utc.asctime) + assert_equal("Thu Mar 4 05:06:07 1982", Time.gm(1982,3,4,5,6,7).asctime) end assert('Time#ctime', '15.2.19.7.5') do - assert_equal("Sun Mar 13 07:06:40 UTC 2011", Time.at(1300000000.0).utc.ctime) + assert_equal("Thu Oct 24 15:26:47 2013", Time.gm(2013,10,24,15,26,47).ctime) end assert('Time#day', '15.2.19.7.6') do @@ -118,7 +118,7 @@ assert('Time#dst?', '15.2.19.7.7') do end assert('Time#getgm', '15.2.19.7.8') do - assert_equal("Sun Mar 13 07:06:40 UTC 2011", Time.at(1300000000.0).getgm.asctime) + assert_equal("Sun Mar 13 07:06:40 2011", Time.at(1300000000.0).getgm.asctime) end assert('Time#getlocal', '15.2.19.7.9') do @@ -131,7 +131,7 @@ assert('Time#getlocal', '15.2.19.7.9') do end assert('Time#getutc', '15.2.19.7.10') do - assert_equal("Sun Mar 13 07:06:40 UTC 2011", Time.at(1300000000.0).getutc.asctime) + assert_equal("Sun Mar 13 07:06:40 2011", Time.at(1300000000.0).getutc.asctime) end assert('Time#gmt?', '15.2.19.7.11') do @@ -235,11 +235,11 @@ end # Not ISO specified assert('Time#to_s') do - assert_equal("Sun Mar 13 07:06:40 UTC 2011", Time.at(1300000000.0).utc.to_s) + assert_equal("Sun Mar 13 07:06:40 2011", Time.at(1300000000.0).utc.to_s) end assert('Time#inspect') do - assert_equal("Sun Mar 13 07:06:40 UTC 2011", Time.at(1300000000.0).utc.inspect) + assert_equal("Sun Mar 13 07:06:40 2011", Time.at(1300000000.0).utc.inspect) end assert('day of week methods') do -- cgit v1.2.3 From edf4b33c61d04148ef11406d37256feda5fe78fb Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Tue, 14 May 2019 22:05:45 +0900 Subject: Refine `Time#(to_s|inspect)` For the following reasons: - Ruby compatibility. - Add UTC offset (time zone informations was not included by #4433). - More readable. Example: Before this patch: p Time.gm(2003,4,5,6,7,8,9) #=> Sat Apr 5 06:07:08 2003 p Time.local(2013,10,28,16,27,48) #=> Mon Oct 28 16:27:48 2013 After this patch: p Time.gm(2003,4,5,6,7,8,9) #=> 2003-04-05 06:07:08 UTC p Time.local(2013,10,28,16,27,48) #=> 2013-10-28 16:27:48 +0900 Implementation: I use `strftime(3)` because UTC offset can be added and program size become smaller than the other implementations (using `sprintf(3)`, self conversion etc) in my environment. --- mrbgems/mruby-time/src/time.c | 15 ++++++++++++--- mrbgems/mruby-time/test/time.rb | 4 ++-- 2 files changed, 14 insertions(+), 5 deletions(-) diff --git a/mrbgems/mruby-time/src/time.c b/mrbgems/mruby-time/src/time.c index bc8abc7ae..b5a540d09 100644 --- a/mrbgems/mruby-time/src/time.c +++ b/mrbgems/mruby-time/src/time.c @@ -18,6 +18,7 @@ #endif #define NDIV(x,y) (-(-((x)+1)/(y))-1) +#define TO_S_FMT "%Y-%m-%d %H:%M:%S " #if defined(_MSC_VER) && _MSC_VER < 1800 double round(double x) { @@ -760,7 +761,6 @@ mrb_time_sec(mrb_state *mrb, mrb_value self) return mrb_fixnum_value(tm->datetime.tm_sec); } - /* 15.2.19.7.24 */ /* Returns a Float with the time since the epoch in seconds. */ static mrb_value @@ -824,6 +824,15 @@ mrb_time_utc_p(mrb_state *mrb, mrb_value self) return mrb_bool_value(tm->timezone == MRB_TIMEZONE_UTC); } +static mrb_value +mrb_time_to_s(mrb_state *mrb, mrb_value self) +{ + char buf[64]; + struct mrb_time *tm = time_get_ptr(mrb, self); + const char *fmt = tm->timezone == MRB_TIMEZONE_UTC ? TO_S_FMT "UTC" : TO_S_FMT "%z"; + size_t len = strftime(buf, sizeof(buf), fmt, &tm->datetime); + return mrb_str_new(mrb, buf, len); +} void mrb_mruby_time_gem_init(mrb_state* mrb) @@ -844,8 +853,8 @@ mrb_mruby_time_gem_init(mrb_state* mrb) mrb_define_method(mrb, tc, "<=>" , mrb_time_cmp , MRB_ARGS_REQ(1)); /* 15.2.19.7.1 */ mrb_define_method(mrb, tc, "+" , mrb_time_plus , MRB_ARGS_REQ(1)); /* 15.2.19.7.2 */ mrb_define_method(mrb, tc, "-" , mrb_time_minus , MRB_ARGS_REQ(1)); /* 15.2.19.7.3 */ - mrb_define_method(mrb, tc, "to_s" , mrb_time_asctime, MRB_ARGS_NONE()); - mrb_define_method(mrb, tc, "inspect", mrb_time_asctime, MRB_ARGS_NONE()); + mrb_define_method(mrb, tc, "to_s" , mrb_time_to_s , MRB_ARGS_NONE()); + mrb_define_method(mrb, tc, "inspect", mrb_time_to_s , MRB_ARGS_NONE()); mrb_define_method(mrb, tc, "asctime", mrb_time_asctime, MRB_ARGS_NONE()); /* 15.2.19.7.4 */ mrb_define_method(mrb, tc, "ctime" , mrb_time_asctime, MRB_ARGS_NONE()); /* 15.2.19.7.5 */ mrb_define_method(mrb, tc, "day" , mrb_time_day , MRB_ARGS_NONE()); /* 15.2.19.7.6 */ diff --git a/mrbgems/mruby-time/test/time.rb b/mrbgems/mruby-time/test/time.rb index c7ad35ab2..ce7b39928 100644 --- a/mrbgems/mruby-time/test/time.rb +++ b/mrbgems/mruby-time/test/time.rb @@ -235,11 +235,11 @@ end # Not ISO specified assert('Time#to_s') do - assert_equal("Sun Mar 13 07:06:40 2011", Time.at(1300000000.0).utc.to_s) + assert_equal("2003-04-05 06:07:08 UTC", Time.gm(2003,4,5,6,7,8,9).to_s) end assert('Time#inspect') do - assert_equal("Sun Mar 13 07:06:40 2011", Time.at(1300000000.0).utc.inspect) + assert_match("2013-10-28 16:27:48 [^U]*", Time.local(2013,10,28,16,27,48).inspect) end assert('day of week methods') do -- cgit v1.2.3 From fd37bc53deb2d52fe3134838eab002dfb9ac35ab Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Wed, 15 May 2019 09:55:21 +0900 Subject: Remove `String#=~` and `String#match` that requires `Regexp`. --- mrblib/string.rb | 24 +++++++----------------- 1 file changed, 7 insertions(+), 17 deletions(-) diff --git a/mrblib/string.rb b/mrblib/string.rb index 506f23c83..42d594055 100644 --- a/mrblib/string.rb +++ b/mrblib/string.rb @@ -230,26 +230,16 @@ class String end end - def _regexp(re, mid) - if String === re - if Object.const_defined?(:Regexp) - return Regexp.new(re) - else - raise NotImplementedError, "String##{mid} needs Regexp class" - end - end - re - end - + # those two methods requires Regexp that is optional in mruby ## # ISO 15.2.10.5.3 - def =~(re) - _regexp(re, :=~) =~ self - end + #def =~(re) + # re =~ self + #end ## # ISO 15.2.10.5.27 - def match(re, &block) - _regexp(re, :match).match(self, &block) - end + #def match(re, &block) + # re.match(self, &block) + #end end -- cgit v1.2.3 From 780342eddb880a1c0a457311b005398ce36d0c9f Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Wed, 15 May 2019 14:59:48 +0900 Subject: Add Enumerator support to `String#each_byte`. `String#each_byte` is not defined in ISO Ruby but it is implemented in the core mruby because it's useful. --- mrblib/string.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/mrblib/string.rb b/mrblib/string.rb index 42d594055..b0fe4033e 100644 --- a/mrblib/string.rb +++ b/mrblib/string.rb @@ -167,6 +167,7 @@ class String ## # Call the given block for each byte of +self+. def each_byte(&block) + return to_enum(:each_byte, &block) unless block bytes = self.bytes pos = 0 while pos < bytes.size -- cgit v1.2.3 From 5f664fb6f890e9c3a6c8e56cf1d173fa46dd39e9 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Wed, 15 May 2019 16:27:08 +0900 Subject: Fix typo in `mrbgems/mruby-io/src/file_test.c` [ci skip] --- mrbgems/mruby-io/src/file_test.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mrbgems/mruby-io/src/file_test.c b/mrbgems/mruby-io/src/file_test.c index ec731b094..5d5ecb93f 100644 --- a/mrbgems/mruby-io/src/file_test.c +++ b/mrbgems/mruby-io/src/file_test.c @@ -1,5 +1,5 @@ /* -** file.c - File class +** file_test.c - FileTest class */ #include "mruby.h" -- cgit v1.2.3 From 8808219e6d51673e6fa582819703e6e5912439b0 Mon Sep 17 00:00:00 2001 From: Ukrainskiy Sergey Date: Thu, 9 Aug 2018 17:09:02 +0900 Subject: Initial suffix support --- include/mrbconf.h | 3 + mrbgems/default.gembox | 6 ++ mrbgems/mruby-compiler/core/parse.y | 148 +++++++++++++++++++++++++++--- mrbgems/mruby-complex/mrbgem.rake | 5 + mrbgems/mruby-complex/mrblib/complex.rb | 95 +++++++++++++++++++ mrbgems/mruby-complex/test/complex.rb | 3 + mrbgems/mruby-rational/mrbgem.rake | 5 + mrbgems/mruby-rational/mrblib/rational.rb | 46 ++++++++++ mrbgems/mruby-rational/test/rational.rb | 3 + 9 files changed, 301 insertions(+), 13 deletions(-) create mode 100644 mrbgems/mruby-complex/mrbgem.rake create mode 100644 mrbgems/mruby-complex/mrblib/complex.rb create mode 100644 mrbgems/mruby-complex/test/complex.rb create mode 100644 mrbgems/mruby-rational/mrbgem.rake create mode 100644 mrbgems/mruby-rational/mrblib/rational.rb create mode 100644 mrbgems/mruby-rational/test/rational.rb diff --git a/include/mrbconf.h b/include/mrbconf.h index 6b0b9e37e..ee816e322 100644 --- a/include/mrbconf.h +++ b/include/mrbconf.h @@ -63,6 +63,9 @@ # endif #endif +#define MRB_COMPLEX_NUMBERS +#define MRB_RATIONAL_NUMBERS + /* define on big endian machines; used by MRB_NAN_BOXING, etc. */ #ifndef MRB_ENDIAN_BIG # if (defined(BYTE_ORDER) && defined(BIG_ENDIAN) && BYTE_ORDER == BIG_ENDIAN) || \ diff --git a/mrbgems/default.gembox b/mrbgems/default.gembox index 23e65fcee..501aee146 100644 --- a/mrbgems/default.gembox +++ b/mrbgems/default.gembox @@ -68,6 +68,12 @@ MRuby::GemBox.new do |conf| # Use Enumerator::Lazy class (require mruby-enumerator) conf.gem :core => "mruby-enum-lazy" + # Use Complex class + #conf.gem :core => "mruby-complex" + + # Use Rational class + #conf.gem :core => "mruby-rational" + # Use toplevel object (main) methods extension conf.gem :core => "mruby-toplevel-ext" diff --git a/mrbgems/mruby-compiler/core/parse.y b/mrbgems/mruby-compiler/core/parse.y index b7d47118f..b18906ed3 100644 --- a/mrbgems/mruby-compiler/core/parse.y +++ b/mrbgems/mruby-compiler/core/parse.y @@ -76,6 +76,24 @@ typedef unsigned int stack_type; #define nint(x) ((node*)(intptr_t)(x)) #define intn(x) ((int)(intptr_t)(x)) +#if defined(MRB_COMPLEX_NUMBERS) || defined(MRB_RATIONAL_NUMBERS) + #define MRB_SUFFIX_SUPPORT + + #ifdef MRB_RATIONAL_NUMBERS + #define NUM_SUFFIX_R (1<<0) + #else + #define NUM_SUFFIX_R 0 + #endif + + #ifdef MRB_COMPLEX_NUMBERS + #define NUM_SUFFIX_I (1<<1) + #else + #define NUM_SUFFIX_I 0 + #endif + + #define NUM_SUFFIX_ALL (NUM_SUFFIX_R | NUM_SUFFIX_I) +#endif + static inline mrb_sym intern_cstr_gen(parser_state *p, const char *s) { @@ -842,19 +860,62 @@ new_op_asgn(parser_state *p, node *a, mrb_sym op, node *b) return list4((node*)NODE_OP_ASGN, a, nsym(op), b); } +#ifdef MRB_COMPLEX_NUMBERS +static node* +new_imaginary(parser_state *p, node *imaginary); +#endif + +#ifdef MRB_RATIONAL_NUMBERS +static node* +new_rational(parser_state *p, node *rational) +{ + return new_call(p, new_const(p, intern_cstr("Rational")), intern_cstr("new"), list1(list1(rational)), 1); +} +#endif + /* (:int . i) */ static node* -new_int(parser_state *p, const char *s, int base) +new_int(parser_state *p, const char *s, int base, int suffix) { - return list3((node*)NODE_INT, (node*)strdup(s), nint(base)); + node* result = list3((node*)NODE_INT, (node*)strdup(s), nint(base)); +#ifdef MRB_RATIONAL_NUMBERS + if (suffix & NUM_SUFFIX_R) { + result = new_rational(p, result); + } +#endif +#ifdef MRB_COMPLEX_NUMBERS + if (suffix & NUM_SUFFIX_I) { + result = new_imaginary(p, result); + } +#endif + return result; } #ifndef MRB_WITHOUT_FLOAT /* (:float . i) */ static node* -new_float(parser_state *p, const char *s) +new_float(parser_state *p, const char *s, int suffix) +{ + node* result = cons((node*)NODE_FLOAT, (node*)strdup(s)); +#ifdef MRB_RATIONAL_NUMBERS + if (suffix & NUM_SUFFIX_R) { + result = new_rational(p, result); + } +#endif +#ifdef MRB_COMPLEX_NUMBERS + if (suffix & NUM_SUFFIX_I) { + result = new_imaginary(p, result); + } +#endif + return result; +} +#endif + +#ifdef MRB_COMPLEX_NUMBERS +static node* +new_imaginary(parser_state *p, node *imaginary) { - return cons((node*)NODE_FLOAT, (node*)strdup(s)); + return new_call(p, new_const(p, intern_cstr("Complex")), intern_cstr("new"), list1(list2(new_int(p, "0", 10, 0), imaginary)), 1); } #endif @@ -3192,7 +3253,7 @@ var_ref : variable char buf[16]; dump_int(p->lineno, buf); - $$ = new_int(p, buf, 10); + $$ = new_int(p, buf, 10, 0); } | keyword__ENCODING__ { @@ -4520,6 +4581,45 @@ parse_string(parser_state *p) return tSTRING; } +#ifdef MRB_SUFFIX_SUPPORT +static int +number_literal_suffix(parser_state *p, int mask) +{ + int c, result = 0; + node *list = 0; + int column = p->column; + + while ((c = nextc(p)) != -1) { + list = push(list, (node*)(intptr_t)c); + + if ((mask & NUM_SUFFIX_I) && c == 'i') { + result |= (mask & NUM_SUFFIX_I); + mask &= ~NUM_SUFFIX_I; + /* r after i, rational of complex is disallowed */ + mask &= ~NUM_SUFFIX_R; + continue; + } + if ((mask & NUM_SUFFIX_R) && c == 'r') { + result |= (mask & NUM_SUFFIX_R); + mask &= ~NUM_SUFFIX_R; + continue; + } + if (!ISASCII(c) || ISALPHA(c) || c == '_') { + p->column = column; + if (p->pb) { + p->pb = append((node*)list, p->pb); + } + else { + p->pb = list; + } + return 0; + } + pushback(p, c); + break; + } + return result; +} +#endif static int heredoc_identifier(parser_state *p) @@ -5094,6 +5194,7 @@ parser_yylex(parser_state *p) case '5': case '6': case '7': case '8': case '9': { int is_float, seen_point, seen_e, nondigit; + int suffix; is_float = seen_point = seen_e = nondigit = 0; p->lstate = EXPR_ENDARG; @@ -5127,7 +5228,10 @@ parser_yylex(parser_state *p) no_digits(); } else if (nondigit) goto trailing_uc; - pylval.nd = new_int(p, tok(p), 16); + #ifdef MRB_SUFFIX_SUPPORT + suffix = number_literal_suffix(p, NUM_SUFFIX_ALL); + #endif + pylval.nd = new_int(p, tok(p), 16, suffix); return tINTEGER; } if (c == 'b' || c == 'B') { @@ -5151,7 +5255,10 @@ parser_yylex(parser_state *p) no_digits(); } else if (nondigit) goto trailing_uc; - pylval.nd = new_int(p, tok(p), 2); + #ifdef MRB_SUFFIX_SUPPORT + suffix = number_literal_suffix(p, NUM_SUFFIX_ALL); + #endif + pylval.nd = new_int(p, tok(p), 2, suffix); return tINTEGER; } if (c == 'd' || c == 'D') { @@ -5175,7 +5282,10 @@ parser_yylex(parser_state *p) no_digits(); } else if (nondigit) goto trailing_uc; - pylval.nd = new_int(p, tok(p), 10); + #ifdef MRB_SUFFIX_SUPPORT + suffix = number_literal_suffix(p, NUM_SUFFIX_ALL); + #endif + pylval.nd = new_int(p, tok(p), 10, suffix); return tINTEGER; } if (c == '_') { @@ -5208,7 +5318,10 @@ parser_yylex(parser_state *p) pushback(p, c); tokfix(p); if (nondigit) goto trailing_uc; - pylval.nd = new_int(p, tok(p), 8); + #ifdef MRB_SUFFIX_SUPPORT + suffix = number_literal_suffix(p, NUM_SUFFIX_ALL); + #endif + pylval.nd = new_int(p, tok(p), 8, suffix); return tINTEGER; } if (nondigit) { @@ -5225,7 +5338,10 @@ parser_yylex(parser_state *p) } else { pushback(p, c); - pylval.nd = new_int(p, "0", 10); + #ifdef MRB_SUFFIX_SUPPORT + suffix = number_literal_suffix(p, NUM_SUFFIX_ALL); + #endif + pylval.nd = new_int(p, "0", 10, suffix); return tINTEGER; } } @@ -5299,7 +5415,7 @@ parser_yylex(parser_state *p) if (is_float) { #ifdef MRB_WITHOUT_FLOAT yywarning(p, "floating point numbers are not supported"); - pylval.nd = new_int(p, "0", 10); + pylval.nd = new_int(p, "0", 10, 0); return tINTEGER; #else double d; @@ -5314,11 +5430,17 @@ parser_yylex(parser_state *p) yywarning_s(p, "float out of range", tok(p)); errno = 0; } - pylval.nd = new_float(p, tok(p)); + #ifdef MRB_SUFFIX_SUPPORT + suffix = number_literal_suffix(p, NUM_SUFFIX_ALL); + #endif + pylval.nd = new_float(p, tok(p), suffix); return tFLOAT; #endif } - pylval.nd = new_int(p, tok(p), 10); + #ifdef MRB_SUFFIX_SUPPORT + suffix = number_literal_suffix(p, NUM_SUFFIX_ALL); + #endif + pylval.nd = new_int(p, tok(p), 10, suffix); return tINTEGER; } diff --git a/mrbgems/mruby-complex/mrbgem.rake b/mrbgems/mruby-complex/mrbgem.rake new file mode 100644 index 000000000..f8f04d0b8 --- /dev/null +++ b/mrbgems/mruby-complex/mrbgem.rake @@ -0,0 +1,5 @@ +MRuby::Gem::Specification.new('mruby-complex') do |spec| + spec.license = 'MIT' + spec.author = 'mruby developers' + spec.summary = 'Complex class' +end diff --git a/mrbgems/mruby-complex/mrblib/complex.rb b/mrbgems/mruby-complex/mrblib/complex.rb new file mode 100644 index 000000000..0815c9a71 --- /dev/null +++ b/mrbgems/mruby-complex/mrblib/complex.rb @@ -0,0 +1,95 @@ +class Complex < Numeric + def initialize(real = 0, imaginary = 0) + @real = real + @imaginary = imaginary + end + + def inspect + "(#{to_s})" + end + + def to_s + "#{real}#{'+'}#{imaginary}i" + end + + def +@ + Complex.new(real, imaginary) + end + + def -@ + Complex.new(-real, -imaginary) + end + + def +(rhs) + if rhs.is_a? Complex + Complex.new(real + rhs.real, imaginary + rhs.imaginary) + elsif rhs.is_a? Numeric + Complex.new(real + rhs, imaginary) + end + end + + def -(rhs) + if rhs.is_a? Complex + Complex.new(real - rhs.real, imaginary - rhs.imaginary) + elsif rhs.is_a? Numeric + Complex.new(real - rhs, imaginary) + end + end + + def *(rhs) + if rhs.is_a? Complex + Complex.new(real * rhs.real - imaginary * rhs.imaginary, real * rhs.imaginary + rhs.real * imaginary) + elsif rhs.is_a? Numeric + Complex.new(real * rhs, imaginary * rhs) + end + end + + def /(rhs) + if rhs.is_a? Complex + div = rhs.real * rhs.real + rhs.imaginary * rhs.imaginary + Complex.new((real * rhs.real + imaginary * rhs.imaginary) / div, (rhs.real * imaginary - real * rhs.imaginary) / div) + elsif rhs.is_a? Numeric + Complex.new(real / rhs, imaginary / rhs) + end + end + + attr_reader :real, :imaginary +end + +def Complex(real = 0, imaginary = 0) + Complex.new(real, imaginary) +end + +module ForwardOperatorToComplex + def __forward_operator_to_complex(op, &b) + original_operator_name = "__original_operator_#{op}_complex" + alias_method original_operator_name, op + define_method op do |rhs| + if rhs.is_a? Complex + Complex.new(self).send(op, rhs) + else + send(original_operator_name, rhs) + end + end + end + + def __forward_operators_to_complex + __forward_operator_to_complex :+ + __forward_operator_to_complex :- + __forward_operator_to_complex :* + __forward_operator_to_complex :/ + + singleton_class.undef_method :__forward_operator_to_complex + singleton_class.undef_method :__forward_operators_to_complex + end +end + +class Fixnum + extend ForwardOperatorToComplex + __forward_operators_to_complex +end + +class Float + extend ForwardOperatorToComplex + __forward_operators_to_complex +end \ No newline at end of file diff --git a/mrbgems/mruby-complex/test/complex.rb b/mrbgems/mruby-complex/test/complex.rb new file mode 100644 index 000000000..890dd4ff1 --- /dev/null +++ b/mrbgems/mruby-complex/test/complex.rb @@ -0,0 +1,3 @@ +assert 'Complex' do + assert_equal Complex, 0i.class +end \ No newline at end of file diff --git a/mrbgems/mruby-rational/mrbgem.rake b/mrbgems/mruby-rational/mrbgem.rake new file mode 100644 index 000000000..4b540dec4 --- /dev/null +++ b/mrbgems/mruby-rational/mrbgem.rake @@ -0,0 +1,5 @@ +MRuby::Gem::Specification.new('mruby-rational') do |spec| + spec.license = 'MIT' + spec.author = 'mruby developers' + spec.summary = 'Rational class' +end diff --git a/mrbgems/mruby-rational/mrblib/rational.rb b/mrbgems/mruby-rational/mrblib/rational.rb new file mode 100644 index 000000000..457c0488a --- /dev/null +++ b/mrbgems/mruby-rational/mrblib/rational.rb @@ -0,0 +1,46 @@ +class Rational < Numeric + def initialize(numerator = 0, denominator = 1) + @numerator = numerator + @denominator = denominator + end + + attr_reader :numerator, :denominator +end + +def Rational(numerator = 0, denominator = 1) + Rational.new(numerator, denominator) +end + +module ForwardOperatorToRational + def __forward_operator_to_rational(op, &b) + original_operator_name = "__original_operator_#{op}_rational" + alias_method original_operator_name, op + define_method op do |rhs| + if rhs.is_a? Rational + Rational.new(self).send(op, rhs) + else + send(original_operator_name, rhs) + end + end + end + + def __forward_operators_to_rational + __forward_operator_to_rational :+ + __forward_operator_to_rational :- + __forward_operator_to_rational :* + __forward_operator_to_rational :/ + + singleton_class.undef_method :__forward_operator_to_rational + singleton_class.undef_method :__forward_operators_to_rational + end +end + +class Fixnum + extend ForwardOperatorToRational + __forward_operators_to_rational +end + +class Float + extend ForwardOperatorToRational + __forward_operators_to_rational +end \ No newline at end of file diff --git a/mrbgems/mruby-rational/test/rational.rb b/mrbgems/mruby-rational/test/rational.rb new file mode 100644 index 000000000..6f20a6cd4 --- /dev/null +++ b/mrbgems/mruby-rational/test/rational.rb @@ -0,0 +1,3 @@ +assert 'Rational' do + assert_equal Rational, 0r.class +end \ No newline at end of file -- cgit v1.2.3 From 79c3335e8d22ec76340b3028a7bbc658d631b17c Mon Sep 17 00:00:00 2001 From: Ukrainskiy Sergey Date: Sun, 9 Sep 2018 11:55:21 +0900 Subject: Small refactoring --- mrbgems/mruby-compiler/core/parse.y | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/mrbgems/mruby-compiler/core/parse.y b/mrbgems/mruby-compiler/core/parse.y index b18906ed3..2c5e0c991 100644 --- a/mrbgems/mruby-compiler/core/parse.y +++ b/mrbgems/mruby-compiler/core/parse.y @@ -862,14 +862,17 @@ new_op_asgn(parser_state *p, node *a, mrb_sym op, node *b) #ifdef MRB_COMPLEX_NUMBERS static node* -new_imaginary(parser_state *p, node *imaginary); +new_imaginary(parser_state *p, node *imaginary) +{ + return new_call(p, new_const(p, intern_cstr("Kernel")), intern_cstr("Complex"), list1(list2(list3((node*)NODE_INT, (node*)strdup("0"), nint(10)), imaginary)), 1); +} #endif #ifdef MRB_RATIONAL_NUMBERS static node* new_rational(parser_state *p, node *rational) { - return new_call(p, new_const(p, intern_cstr("Rational")), intern_cstr("new"), list1(list1(rational)), 1); + return new_call(p, new_const(p, intern_cstr("Kernel")), intern_cstr("Rational"), list1(list1(rational)), 1); } #endif @@ -911,14 +914,6 @@ new_float(parser_state *p, const char *s, int suffix) } #endif -#ifdef MRB_COMPLEX_NUMBERS -static node* -new_imaginary(parser_state *p, node *imaginary) -{ - return new_call(p, new_const(p, intern_cstr("Complex")), intern_cstr("new"), list1(list2(new_int(p, "0", 10, 0), imaginary)), 1); -} -#endif - /* (:str . (s . len)) */ static node* new_str(parser_state *p, const char *s, size_t len) -- cgit v1.2.3 From d67d2ae8e88b93536e71dfa41a90721ce351da7c Mon Sep 17 00:00:00 2001 From: Ukrainskiy Sergey Date: Sun, 9 Sep 2018 11:57:16 +0900 Subject: Basic implementation of Complex and Rational classes --- mrbgems/default.gembox | 4 +- mrbgems/mruby-complex/mrbgem.rake | 4 + mrbgems/mruby-complex/mrblib/complex.rb | 155 ++++++++++++++++++++++-------- mrbgems/mruby-complex/test/complex.rb | 129 ++++++++++++++++++++++++- mrbgems/mruby-rational/mrbgem.rake | 3 + mrbgems/mruby-rational/mrblib/rational.rb | 100 +++++++++++++------ mrbgems/mruby-rational/test/rational.rb | 41 +++++++- 7 files changed, 363 insertions(+), 73 deletions(-) diff --git a/mrbgems/default.gembox b/mrbgems/default.gembox index 501aee146..ae085309c 100644 --- a/mrbgems/default.gembox +++ b/mrbgems/default.gembox @@ -69,10 +69,10 @@ MRuby::GemBox.new do |conf| conf.gem :core => "mruby-enum-lazy" # Use Complex class - #conf.gem :core => "mruby-complex" + # conf.gem :core => "mruby-complex" # Use Rational class - #conf.gem :core => "mruby-rational" + # conf.gem :core => "mruby-rational" # Use toplevel object (main) methods extension conf.gem :core => "mruby-toplevel-ext" diff --git a/mrbgems/mruby-complex/mrbgem.rake b/mrbgems/mruby-complex/mrbgem.rake index f8f04d0b8..25b8966da 100644 --- a/mrbgems/mruby-complex/mrbgem.rake +++ b/mrbgems/mruby-complex/mrbgem.rake @@ -2,4 +2,8 @@ MRuby::Gem::Specification.new('mruby-complex') do |spec| spec.license = 'MIT' spec.author = 'mruby developers' spec.summary = 'Complex class' + + spec.add_dependency 'mruby-object-ext', core: 'mruby-object-ext' + spec.add_dependency 'mruby-numeric-ext', core: 'mruby-numeric-ext' + spec.add_dependency 'mruby-math', core: 'mruby-math' end diff --git a/mrbgems/mruby-complex/mrblib/complex.rb b/mrbgems/mruby-complex/mrblib/complex.rb index 0815c9a71..266c00c36 100644 --- a/mrbgems/mruby-complex/mrblib/complex.rb +++ b/mrbgems/mruby-complex/mrblib/complex.rb @@ -1,95 +1,168 @@ class Complex < Numeric - def initialize(real = 0, imaginary = 0) + def initialize(real, imaginary) + real = real.to_f unless real.is_a? Numeric + imaginary = imaginary.to_f unless imaginary.is_a? Numeric @real = real @imaginary = imaginary end + def self.polar(abs, arg = 0) + Complex(abs * Math.cos(arg), abs * Math.sin(arg)) + end + + def self.rectangular(real, imaginary = 0) + _new(real, imaginary) + end + def inspect "(#{to_s})" end def to_s - "#{real}#{'+'}#{imaginary}i" + "#{real}#{'+' unless imaginary.negative?}#{imaginary}i" end def +@ - Complex.new(real, imaginary) + Complex(real, imaginary) end def -@ - Complex.new(-real, -imaginary) + Complex(-real, -imaginary) end def +(rhs) if rhs.is_a? Complex - Complex.new(real + rhs.real, imaginary + rhs.imaginary) + Complex(real + rhs.real, imaginary + rhs.imaginary) elsif rhs.is_a? Numeric - Complex.new(real + rhs, imaginary) + Complex(real + rhs, imaginary) end end def -(rhs) if rhs.is_a? Complex - Complex.new(real - rhs.real, imaginary - rhs.imaginary) + Complex(real - rhs.real, imaginary - rhs.imaginary) elsif rhs.is_a? Numeric - Complex.new(real - rhs, imaginary) + Complex(real - rhs, imaginary) end end def *(rhs) if rhs.is_a? Complex - Complex.new(real * rhs.real - imaginary * rhs.imaginary, real * rhs.imaginary + rhs.real * imaginary) + Complex(real * rhs.real - imaginary * rhs.imaginary, real * rhs.imaginary + rhs.real * imaginary) elsif rhs.is_a? Numeric - Complex.new(real * rhs, imaginary * rhs) + Complex(real * rhs, imaginary * rhs) end end def /(rhs) if rhs.is_a? Complex div = rhs.real * rhs.real + rhs.imaginary * rhs.imaginary - Complex.new((real * rhs.real + imaginary * rhs.imaginary) / div, (rhs.real * imaginary - real * rhs.imaginary) / div) + Complex((real * rhs.real + imaginary * rhs.imaginary) / div, (rhs.real * imaginary - real * rhs.imaginary) / div) elsif rhs.is_a? Numeric - Complex.new(real / rhs, imaginary / rhs) + Complex(real / rhs, imaginary / rhs) end end + alias_method :quo, :/ - attr_reader :real, :imaginary -end + def ==(rhs) + if rhs.is_a? Complex + real == rhs.real && imaginary == rhs.imaginary + elsif rhs.is_a? Numeric + imaginary.zero? && real == rhs + end + end -def Complex(real = 0, imaginary = 0) - Complex.new(real, imaginary) -end + def abs + Math.sqrt(abs2) + end + alias_method :magnitude, :abs -module ForwardOperatorToComplex - def __forward_operator_to_complex(op, &b) - original_operator_name = "__original_operator_#{op}_complex" - alias_method original_operator_name, op - define_method op do |rhs| - if rhs.is_a? Complex - Complex.new(self).send(op, rhs) - else - send(original_operator_name, rhs) - end - end + def abs2 + real * real + imaginary * imaginary + end + + def arg + Math.atan2 imaginary, real + end + alias_method :angle, :arg + alias_method :phase, :arg + + def conjugate + Complex(real, -imaginary) + end + alias_method :conj, :conjugate + + def numerator + self + end + + def denominator + 1 + end + + def fdiv(numeric) + Complex(real.to_f / numeric, imaginary.to_f / numeric) + end + + def polar + [abs, arg] + end + + def real? + false end - def __forward_operators_to_complex - __forward_operator_to_complex :+ - __forward_operator_to_complex :- - __forward_operator_to_complex :* - __forward_operator_to_complex :/ + def rectangular + [real, imaginary] + end + alias_method :rect, :rectangular + + def to_c + self + end + + def to_f + raise RangeError.new "can't convert #{to_s} into Float" unless imaginary.zero? + real.to_f + end - singleton_class.undef_method :__forward_operator_to_complex - singleton_class.undef_method :__forward_operators_to_complex + def to_i + raise RangeError.new "can't convert #{to_s} into Integer" unless imaginary.zero? + real.to_i end + + def to_r + raise RangeError.new "can't convert #{to_s} into Rational" unless imaginary.zero? + Rational(real, 1) + end + + attr_reader :real, :imaginary + alias_method :imag, :imaginary +end + +class << Complex + alias_method :_new, :new + undef_method :new + + alias_method :rect, :rectangular end -class Fixnum - extend ForwardOperatorToComplex - __forward_operators_to_complex +def Complex(real, imaginary = 0) + Complex.rectangular(real, imaginary) end -class Float - extend ForwardOperatorToComplex - __forward_operators_to_complex +[Fixnum, Float].each do |cls| + [:+, :-, :*, :/, :==].each do |op| + cls.instance_exec do + original_operator_name = "__original_operator_#{op}_complex" + alias_method original_operator_name, op + define_method op do |rhs| + if rhs.is_a? Complex + Complex(self).send(op, rhs) + else + send(original_operator_name, rhs) + end + end + end + end end \ No newline at end of file diff --git a/mrbgems/mruby-complex/test/complex.rb b/mrbgems/mruby-complex/test/complex.rb index 890dd4ff1..ca58202c2 100644 --- a/mrbgems/mruby-complex/test/complex.rb +++ b/mrbgems/mruby-complex/test/complex.rb @@ -1,3 +1,130 @@ +def assert_complex(real, exp) + assert_float real.real, exp.real + assert_float real.imaginary, exp.imaginary +end + assert 'Complex' do - assert_equal Complex, 0i.class + c = 123i + assert_equal Complex, c.class + assert_equal [c.real, c.imaginary], [0, 123] + c = 123 + -1.23i + assert_equal Complex, c.class + assert_equal [c.real, c.imaginary], [123, -1.23] +end + +assert 'Complex::polar' do + assert_complex Complex.polar(3, 0), (3 + 0i) + assert_complex Complex.polar(3, Math::PI/2), (0 + 3i) + assert_complex Complex.polar(3, Math::PI), (-3 + 0i) + assert_complex Complex.polar(3, -Math::PI/2), (0 + -3i) +end + +assert 'Complex::rectangular' do + assert_complex Complex.rectangular(1, 2), (1 + 2i) +end + +assert 'Complex#*' do + assert_complex Complex(2, 3) * Complex(2, 3), (-5 + 12i) + assert_complex Complex(900) * Complex(1), (900 + 0i) + assert_complex Complex(-2, 9) * Complex(-9, 2), (0 - 85i) + assert_complex Complex(9, 8) * 4, (36 + 32i) + assert_complex Complex(20, 9) * 9.8, (196.0 + 88.2i) +end + +assert 'Complex#+' do + assert_complex Complex(2, 3) + Complex(2, 3) , (4 + 6i) + assert_complex Complex(900) + Complex(1) , (901 + 0i) + assert_complex Complex(-2, 9) + Complex(-9, 2), (-11 + 11i) + assert_complex Complex(9, 8) + 4 , (13 + 8i) + assert_complex Complex(20, 9) + 9.8 , (29.8 + 9i) +end + +assert 'Complex#-' do + assert_complex Complex(2, 3) - Complex(2, 3) , (0 + 0i) + assert_complex Complex(900) - Complex(1) , (899 + 0i) + assert_complex Complex(-2, 9) - Complex(-9, 2), (7 + 7i) + assert_complex Complex(9, 8) - 4 , (5 + 8i) + assert_complex Complex(20, 9) - 9.8 , (10.2 + 9i) +end + +assert 'Complex#-@' do + assert_complex -Complex(1, 2), (-1 - 2i) +end + +assert 'Complex#/' do + assert_complex Complex(2, 3) / Complex(2, 3) , (1 + 0i) + assert_complex Complex(900) / Complex(1) , (900 + 0i) + assert_complex Complex(-2, 9) / Complex(-9, 2), ((36 / 85) - (77i / 85)) + assert_complex Complex(9, 8) / 4 , ((9 / 4) + 2i) + assert_complex Complex(20, 9) / 9.8 , (2.0408163265306123 + 0.9183673469387754i) +end + +assert 'Complex#==' do + assert_true Complex(2, 3) == Complex(2, 3) + assert_true Complex(5) == 5 + assert_true Complex(0) == 0.0 + assert_false Complex('1/3') == 0.33 + assert_false Complex('1/2') == '1/2' +end + +assert 'Complex#abs' do + assert_float Complex(-1).abs, 1 + assert_float Complex(3.0, -4.0).abs, 5.0 +end + +assert 'Complex#abs2' do + assert_float Complex(-1).abs2, 1 + assert_float Complex(3.0, -4.0).abs2, 25.0 +end + +assert 'Complex#arg' do + assert_float Complex.polar(3, Math::PI/2).arg, 1.5707963267948966 +end + +assert 'Complex#conjugate' do + assert_complex Complex(1, 2).conjugate, (1 - 2i) +end + +assert 'Complex#fdiv' do + assert_complex Complex(11, 22).fdiv(3), (3.6666666666666665 + 7.333333333333333i) +end + +assert 'Complex#imaginary' do + assert_float Complex(7).imaginary , 0 + assert_float Complex(9, -4).imaginary, -4 +end + +assert 'Complex#polar' do + assert_equal Complex(1, 2).polar, [2.23606797749979, 1.1071487177940904] +end + +assert 'Complex#real' do + assert_float Complex(7).real, 7 + assert_float Complex(9, -4).real, 9 +end + +assert 'Complex#real?' do + assert_false Complex(1).real? +end + +assert 'Complex::rectangular' do + assert_equal Complex(1, 2).rectangular, [1, 2] +end + +assert 'Complex::to_c' do + assert_equal Complex(1, 2).to_c, Complex(1, 2) +end + +assert 'Complex::to_f' do + assert_float Complex(1, 0).to_f, 1.0 + assert_raise(RangeError) do + Complex(1, 2).to_f + end +end + +assert 'Complex::to_i' do + assert_equal Complex(1, 0).to_i, 1 + assert_raise(RangeError) do + Complex(1, 2).to_i + end end \ No newline at end of file diff --git a/mrbgems/mruby-rational/mrbgem.rake b/mrbgems/mruby-rational/mrbgem.rake index 4b540dec4..496082709 100644 --- a/mrbgems/mruby-rational/mrbgem.rake +++ b/mrbgems/mruby-rational/mrbgem.rake @@ -2,4 +2,7 @@ MRuby::Gem::Specification.new('mruby-rational') do |spec| spec.license = 'MIT' spec.author = 'mruby developers' spec.summary = 'Rational class' + + spec.add_dependency 'mruby-object-ext', core: 'mruby-object-ext' + spec.add_dependency 'mruby-numeric-ext', core: 'mruby-numeric-ext' end diff --git a/mrbgems/mruby-rational/mrblib/rational.rb b/mrbgems/mruby-rational/mrblib/rational.rb index 457c0488a..ffadd55eb 100644 --- a/mrbgems/mruby-rational/mrblib/rational.rb +++ b/mrbgems/mruby-rational/mrblib/rational.rb @@ -2,45 +2,89 @@ class Rational < Numeric def initialize(numerator = 0, denominator = 1) @numerator = numerator @denominator = denominator + + _simplify end - attr_reader :numerator, :denominator -end + def inspect + "(#{to_s})" + end -def Rational(numerator = 0, denominator = 1) - Rational.new(numerator, denominator) -end + def to_s + "#{numerator}/#{denominator}" + end -module ForwardOperatorToRational - def __forward_operator_to_rational(op, &b) - original_operator_name = "__original_operator_#{op}_rational" - alias_method original_operator_name, op - define_method op do |rhs| - if rhs.is_a? Rational - Rational.new(self).send(op, rhs) - else - send(original_operator_name, rhs) - end + def *(rhs) + if rhs.is_a? Rational + Rational(numerator * rhs.numerator, denominator * rhs.denominator) + elsif rhs.is_a? Integer + Rational(numerator * rhs, denominator) + elsif rhs.is_a? Numeric + numerator * rhs / denominator + end + end + + def +(rhs) + if rhs.is_a? Rational + Rational(numerator * rhs.denominator + rhs.numerator * denominator, denominator * rhs.denominator) + elsif rhs.is_a? Integer + Rational(numerator + rhs * denominator, denominator) + elsif rhs.is_a? Numeric + (numerator + rhs * denominator) / denominator + end + end + + def -(rhs) + if rhs.is_a? Rational + Rational(numerator * rhs.denominator - rhs.numerator * denominator, denominator * rhs.denominator) + elsif rhs.is_a? Integer + Rational(numerator - rhs * denominator, denominator) + elsif rhs.is_a? Numeric + (numerator - rhs * denominator) / denominator end end - def __forward_operators_to_rational - __forward_operator_to_rational :+ - __forward_operator_to_rational :- - __forward_operator_to_rational :* - __forward_operator_to_rational :/ + def /(rhs) + if rhs.is_a? Rational + Rational(numerator * rhs.denominator, denominator * rhs.numerator) + elsif rhs.is_a? Integer + Rational(numerator, denominator * rhs) + elsif rhs.is_a? Numeric + numerator / rhs / denominator + end + end - singleton_class.undef_method :__forward_operator_to_rational - singleton_class.undef_method :__forward_operators_to_rational + def negative? + numerator.negative? end + + def _simplify + a = numerator + b = denominator + a, b = b, a % b while !b.zero? + @numerator /= a + @denominator /= a + end + + attr_reader :numerator, :denominator end -class Fixnum - extend ForwardOperatorToRational - __forward_operators_to_rational +def Rational(numerator = 0, denominator = 1) + Rational.new(numerator, denominator) end -class Float - extend ForwardOperatorToRational - __forward_operators_to_rational +[Fixnum, Float].each do |cls| + [:+, :-, :*, :/, :==].each do |op| + cls.instance_exec do + original_operator_name = "__original_operator_#{op}_rational" + alias_method original_operator_name, op + define_method op do |rhs| + if rhs.is_a? Rational + Rational(self).send(op, rhs) + else + send(original_operator_name, rhs) + end + end + end + end end \ No newline at end of file diff --git a/mrbgems/mruby-rational/test/rational.rb b/mrbgems/mruby-rational/test/rational.rb index 6f20a6cd4..a86f00690 100644 --- a/mrbgems/mruby-rational/test/rational.rb +++ b/mrbgems/mruby-rational/test/rational.rb @@ -1,3 +1,42 @@ +def assert_rational(real, exp) + assert_float real.numerator, exp.numerator + assert_float real.denominator, exp.denominator +end + assert 'Rational' do - assert_equal Rational, 0r.class + r = 5r + assert_equal Rational, r.class + assert_equal [r.numerator, r.denominator], [5, 1] +end + +assert 'Rational#*' do + assert_rational Rational(2, 3) * Rational(2, 3), Rational(4, 9) + assert_rational Rational(900) * Rational(1), Rational(900, 1) + assert_rational Rational(-2, 9) * Rational(-9, 2), Rational(1, 1) + assert_rational Rational(9, 8) * 4, Rational(9, 2) + assert_float Rational(20, 9) * 9.8, 21.77777777777778 +end + +assert 'Rational#+' do + assert_rational Rational(2, 3) + Rational(2, 3), Rational(4, 3) + assert_rational Rational(900) + Rational(1), Rational(901, 1) + assert_rational Rational(-2, 9) + Rational(-9, 2), Rational(-85, 18) + assert_rational Rational(9, 8) + 4, Rational(41, 8) + assert_float Rational(20, 9) + 9.8, 12.022222222222222 +end + +assert 'Rational#-' do + assert_rational Rational(2, 3) - Rational(2, 3), Rational(0, 1) + assert_rational Rational(900) - Rational(1), Rational(899, 1) + assert_rational Rational(-2, 9) - Rational(-9, 2), Rational(77, 18) + assert_rational Rational(9, 8) - 4, Rational(-23, 8) + assert_float Rational(20, 9) - 9.8, -7.577777777777778 +end + +assert 'Rational#/' do + assert_rational Rational(2, 3) / Rational(2, 3), Rational(1, 1) + assert_rational Rational(900) / Rational(1), Rational(900, 1) + assert_rational Rational(-2, 9) / Rational(-9, 2), Rational(4, 81) + assert_rational Rational(9, 8) / 4, Rational(9, 32) + assert_float Rational(20, 9) / 9.8, 0.22675736961451246 end \ No newline at end of file -- cgit v1.2.3 From fa45cc42726720b89732bf43d1bf433970007c89 Mon Sep 17 00:00:00 2001 From: Ukrainskiy Sergey Date: Sat, 22 Sep 2018 16:53:56 +0900 Subject: Fix dependencies --- mrbgems/default.gembox | 6 ------ mrbgems/mruby-complex/mrbgem.rake | 1 + mrbgems/mruby-rational/mrbgem.rake | 1 + mrbgems/mruby-rational/mrblib/rational.rb | 12 ++++++++++++ mrbgems/mruby-rational/test/rational.rb | 15 +++++++++++++++ 5 files changed, 29 insertions(+), 6 deletions(-) diff --git a/mrbgems/default.gembox b/mrbgems/default.gembox index ae085309c..23e65fcee 100644 --- a/mrbgems/default.gembox +++ b/mrbgems/default.gembox @@ -68,12 +68,6 @@ MRuby::GemBox.new do |conf| # Use Enumerator::Lazy class (require mruby-enumerator) conf.gem :core => "mruby-enum-lazy" - # Use Complex class - # conf.gem :core => "mruby-complex" - - # Use Rational class - # conf.gem :core => "mruby-rational" - # Use toplevel object (main) methods extension conf.gem :core => "mruby-toplevel-ext" diff --git a/mrbgems/mruby-complex/mrbgem.rake b/mrbgems/mruby-complex/mrbgem.rake index 25b8966da..19612e74d 100644 --- a/mrbgems/mruby-complex/mrbgem.rake +++ b/mrbgems/mruby-complex/mrbgem.rake @@ -3,6 +3,7 @@ MRuby::Gem::Specification.new('mruby-complex') do |spec| spec.author = 'mruby developers' spec.summary = 'Complex class' + spec.add_dependency 'mruby-metaprog', core: 'mruby-metaprog' spec.add_dependency 'mruby-object-ext', core: 'mruby-object-ext' spec.add_dependency 'mruby-numeric-ext', core: 'mruby-numeric-ext' spec.add_dependency 'mruby-math', core: 'mruby-math' diff --git a/mrbgems/mruby-rational/mrbgem.rake b/mrbgems/mruby-rational/mrbgem.rake index 496082709..93f5b601c 100644 --- a/mrbgems/mruby-rational/mrbgem.rake +++ b/mrbgems/mruby-rational/mrbgem.rake @@ -3,6 +3,7 @@ MRuby::Gem::Specification.new('mruby-rational') do |spec| spec.author = 'mruby developers' spec.summary = 'Rational class' + spec.add_dependency 'mruby-metaprog', core: 'mruby-metaprog' spec.add_dependency 'mruby-object-ext', core: 'mruby-object-ext' spec.add_dependency 'mruby-numeric-ext', core: 'mruby-numeric-ext' end diff --git a/mrbgems/mruby-rational/mrblib/rational.rb b/mrbgems/mruby-rational/mrblib/rational.rb index ffadd55eb..7d5b87362 100644 --- a/mrbgems/mruby-rational/mrblib/rational.rb +++ b/mrbgems/mruby-rational/mrblib/rational.rb @@ -10,6 +10,18 @@ class Rational < Numeric "(#{to_s})" end + def to_f + @numerator.to_f / @denominator.to_f + end + + def to_i + to_f.to_i + end + + def to_r + self + end + def to_s "#{numerator}/#{denominator}" end diff --git a/mrbgems/mruby-rational/test/rational.rb b/mrbgems/mruby-rational/test/rational.rb index a86f00690..85cebc316 100644 --- a/mrbgems/mruby-rational/test/rational.rb +++ b/mrbgems/mruby-rational/test/rational.rb @@ -9,6 +9,21 @@ assert 'Rational' do assert_equal [r.numerator, r.denominator], [5, 1] end +assert 'Rational#to_f' do + assert_float Rational(2).to_f, 2.0 + assert_float Rational(9, 4).to_f, 2.25 + assert_float Rational(-3, 4).to_f, -0.75 + assert_float Rational(20, 3).to_f, 6.666666666666667 +end + +assert 'Rational#to_i' do + assert_equal Rational(2, 3).to_i, 0 + assert_equal Rational(3).to_i, 3 + assert_equal Rational(300.6).to_i, 300 + assert_equal Rational(98, 71).to_i, 1 + assert_equal Rational(-30, 2).to_i, -15 +end + assert 'Rational#*' do assert_rational Rational(2, 3) * Rational(2, 3), Rational(4, 9) assert_rational Rational(900) * Rational(1), Rational(900, 1) -- cgit v1.2.3 From 31bfc5586615a759b3c415ec8550ee67827bd296 Mon Sep 17 00:00:00 2001 From: Ukrainskiy Sergey Date: Sat, 22 Sep 2018 17:23:03 +0900 Subject: Fix --- mrbgems/mruby-compiler/core/parse.y | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mrbgems/mruby-compiler/core/parse.y b/mrbgems/mruby-compiler/core/parse.y index 2c5e0c991..3ad11f406 100644 --- a/mrbgems/mruby-compiler/core/parse.y +++ b/mrbgems/mruby-compiler/core/parse.y @@ -5189,7 +5189,7 @@ parser_yylex(parser_state *p) case '5': case '6': case '7': case '8': case '9': { int is_float, seen_point, seen_e, nondigit; - int suffix; + int suffix = 0; is_float = seen_point = seen_e = nondigit = 0; p->lstate = EXPR_ENDARG; -- cgit v1.2.3 From 936f72fdd239e37474b51e2af6d2041a9f018693 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Wed, 15 May 2019 16:58:35 +0900 Subject: Do not overwrite `conf.cc.defines`. --- appveyor_config.rb | 2 +- travis_config.rb | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/appveyor_config.rb b/appveyor_config.rb index 2555b2f62..b50a9e4ef 100644 --- a/appveyor_config.rb +++ b/appveyor_config.rb @@ -17,7 +17,7 @@ MRuby::Build.new('full-debug') do |conf| # include all core GEMs conf.gembox 'full-core' - conf.cc.defines = %w(MRB_ENABLE_DEBUG_HOOK) + conf.cc.defines += %w(MRB_ENABLE_DEBUG_HOOK) conf.enable_test end diff --git a/travis_config.rb b/travis_config.rb index e12bae648..7a13ced72 100644 --- a/travis_config.rb +++ b/travis_config.rb @@ -18,7 +18,7 @@ MRuby::Build.new('full-debug') do |conf| # include all core GEMs conf.gembox 'full-core' - conf.cc.defines = %w(MRB_ENABLE_DEBUG_HOOK) + conf.cc.defines += %w(MRB_ENABLE_DEBUG_HOOK) conf.enable_test end -- cgit v1.2.3 From 752edf413f09fb3e78d79ca7d752ae5dc2e25c02 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Thu, 16 May 2019 09:51:27 +0900 Subject: Terminate float right shift if shift value is too big. --- src/numeric.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/numeric.c b/src/numeric.c index 101b338de..5dbf9df22 100644 --- a/src/numeric.c +++ b/src/numeric.c @@ -484,6 +484,10 @@ flo_shift(mrb_state *mrb, mrb_value x, mrb_int width) if (width < 0) { while (width++) { val /= 2; + if (val < 1.0) { + val = 0; + break; + } } #if defined(_ISOC99_SOURCE) val = trunc(val); -- cgit v1.2.3 From 2f1425414226f4ff6698de99b0d1b743368cdb39 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Thu, 16 May 2019 10:13:52 +0900 Subject: Avoid potential integer overflow. --- mrbgems/mruby-pack/src/pack.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/mrbgems/mruby-pack/src/pack.c b/mrbgems/mruby-pack/src/pack.c index ac29fdbf3..0c4f0d965 100644 --- a/mrbgems/mruby-pack/src/pack.c +++ b/mrbgems/mruby-pack/src/pack.c @@ -1075,10 +1075,11 @@ alias: if (ISDIGIT(ch)) { count = ch - '0'; while (tmpl->idx < tlen && ISDIGIT(tptr[tmpl->idx])) { - count = count * 10 + (tptr[tmpl->idx++] - '0'); - if (count < 0) { + int ch = tptr[tmpl->idx++] - '0'; + if (count+ch > INT_MAX/10) { mrb_raise(mrb, E_RUNTIME_ERROR, "too big template length"); } + count = count * 10 + ch; } continue; /* special case */ } else if (ch == '*') { -- cgit v1.2.3 From 7aff5507dddf63dab578165471205b674e28524c Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Thu, 16 May 2019 10:15:11 +0900 Subject: Avoid potential type mismatch warnings in `pack.c`. --- mrbgems/mruby-pack/src/pack.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/mrbgems/mruby-pack/src/pack.c b/mrbgems/mruby-pack/src/pack.c index 0c4f0d965..75a447d6c 100644 --- a/mrbgems/mruby-pack/src/pack.c +++ b/mrbgems/mruby-pack/src/pack.c @@ -118,9 +118,9 @@ make_base64_dec_tab(void) base64_dec_tab['a' + i] = i + 26; for (i = 0; i < 10; i++) base64_dec_tab['0' + i] = i + 52; - base64_dec_tab['+'] = 62; - base64_dec_tab['/'] = 63; - base64_dec_tab['='] = PACK_BASE64_PADDING; + base64_dec_tab['+'+0] = 62; + base64_dec_tab['/'+0] = 63; + base64_dec_tab['='+0] = PACK_BASE64_PADDING; } static mrb_value -- cgit v1.2.3 From 304b52fabe1c9672adac79dcc7777b07a468b6a4 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Thu, 16 May 2019 11:44:51 +0900 Subject: Set maximum string (and symbol) size to 65534 (`UINT16_MAX-1`). The previous value (`UINT16_MAX`) was too long for symbols, so it raises an exception after the length check. --- include/mruby/compile.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/mruby/compile.h b/include/mruby/compile.h index f19d9b0b3..8f8f2ebd7 100644 --- a/include/mruby/compile.h +++ b/include/mruby/compile.h @@ -105,7 +105,7 @@ struct mrb_parser_heredoc_info { mrb_ast_node *doc; }; -#define MRB_PARSER_TOKBUF_MAX 65536 +#define MRB_PARSER_TOKBUF_MAX (UINT16_MAX-1) #define MRB_PARSER_TOKBUF_SIZE 256 /* parser structure */ -- cgit v1.2.3 From 9b604abc8300d378bb32fb0e88d6f0831ed7e0d9 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Thu, 16 May 2019 11:46:37 +0900 Subject: Enable `YYSTACK_USE_ALLOCA`. It used heap allocated memory for the parser stack, but there's possibility of parser termination by exceptions. In that case, the parser stack memory is leaked. We were afraid of stack consumption, but parser stack size is only 4KB, so we don't have to worry about it (at least for the parser). --- mrbgems/mruby-compiler/core/parse.y | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/mrbgems/mruby-compiler/core/parse.y b/mrbgems/mruby-compiler/core/parse.y index 3ad11f406..37d4d1bf1 100644 --- a/mrbgems/mruby-compiler/core/parse.y +++ b/mrbgems/mruby-compiler/core/parse.y @@ -10,13 +10,7 @@ # define YYDEBUG 1 #endif #define YYERROR_VERBOSE 1 -/* - * Force yacc to use our memory management. This is a little evil because - * the macros assume that "parser_state *p" is in scope - */ -#define YYMALLOC(n) mrb_malloc(p->mrb, (n)) -#define YYFREE(o) mrb_free(p->mrb, (o)) -#define YYSTACK_USE_ALLOCA 0 +#define YYSTACK_USE_ALLOCA 1 #include #include -- cgit v1.2.3 From f5fb1307b017fb972c12b4ec4b1866d789b0ca09 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Thu, 16 May 2019 22:09:56 +0900 Subject: Fix `Rational#==` --- mrbgems/mruby-rational/mrbgem.rake | 1 - mrbgems/mruby-rational/mrblib/rational.rb | 29 +++++++++++++++--- mrbgems/mruby-rational/test/rational.rb | 49 +++++++++++++++++++++++++++++-- 3 files changed, 72 insertions(+), 7 deletions(-) diff --git a/mrbgems/mruby-rational/mrbgem.rake b/mrbgems/mruby-rational/mrbgem.rake index 93f5b601c..496082709 100644 --- a/mrbgems/mruby-rational/mrbgem.rake +++ b/mrbgems/mruby-rational/mrbgem.rake @@ -3,7 +3,6 @@ MRuby::Gem::Specification.new('mruby-rational') do |spec| spec.author = 'mruby developers' spec.summary = 'Rational class' - spec.add_dependency 'mruby-metaprog', core: 'mruby-metaprog' spec.add_dependency 'mruby-object-ext', core: 'mruby-object-ext' spec.add_dependency 'mruby-numeric-ext', core: 'mruby-numeric-ext' end diff --git a/mrbgems/mruby-rational/mrblib/rational.rb b/mrbgems/mruby-rational/mrblib/rational.rb index 7d5b87362..dbc855af0 100644 --- a/mrbgems/mruby-rational/mrblib/rational.rb +++ b/mrbgems/mruby-rational/mrblib/rational.rb @@ -1,4 +1,7 @@ class Rational < Numeric + # Override #<, #<=, #>, #>= in Numeric + prepend Comparable + def initialize(numerator = 0, denominator = 1) @numerator = numerator @denominator = denominator @@ -66,6 +69,24 @@ class Rational < Numeric end end + def <=>(rhs) + case rhs + when Fixnum + return @numerator <=> rhs if @denominator == 1 + rhs = Rational(rhs) + when Float + return to_f <=> rhs + end + case rhs + when Rational + (@numerator * rhs.denominator - @denominator * rhs.numerator) <=> 0 + when Numeric + return rhs <=> self + else + nil + end + end + def negative? numerator.negative? end @@ -86,17 +107,17 @@ def Rational(numerator = 0, denominator = 1) end [Fixnum, Float].each do |cls| - [:+, :-, :*, :/, :==].each do |op| + [:+, :-, :*, :/, :<=>, :==, :<, :<=, :>, :>=].each do |op| cls.instance_exec do original_operator_name = "__original_operator_#{op}_rational" alias_method original_operator_name, op define_method op do |rhs| if rhs.is_a? Rational - Rational(self).send(op, rhs) + Rational(self).__send__(op, rhs) else - send(original_operator_name, rhs) + __send__(original_operator_name, rhs) end end end end -end \ No newline at end of file +end diff --git a/mrbgems/mruby-rational/test/rational.rb b/mrbgems/mruby-rational/test/rational.rb index 85cebc316..4d3d36ccc 100644 --- a/mrbgems/mruby-rational/test/rational.rb +++ b/mrbgems/mruby-rational/test/rational.rb @@ -1,8 +1,18 @@ def assert_rational(real, exp) - assert_float real.numerator, exp.numerator + assert_float real.numerator, exp.numerator assert_float real.denominator, exp.denominator end +def assert_equal_rational(exp, r1, r2) + if exp + assert_operator(r1, :==, r2) + assert_not_operator(r1, :!=, r2) + else + assert_not_operator(r1, :==, r2) + assert_operator(r1, :!=, r2) + end +end + assert 'Rational' do r = 5r assert_equal Rational, r.class @@ -54,4 +64,39 @@ assert 'Rational#/' do assert_rational Rational(-2, 9) / Rational(-9, 2), Rational(4, 81) assert_rational Rational(9, 8) / 4, Rational(9, 32) assert_float Rational(20, 9) / 9.8, 0.22675736961451246 -end \ No newline at end of file +end + +assert 'Rational#==, Rational#!=' do + assert_equal_rational(true, Rational(1,1), Rational(1)) + assert_equal_rational(true, Rational(-1,1), -1r) + assert_equal_rational(true, Rational(13,4), 3.25) + assert_equal_rational(true, Rational(13,3.25), Rational(4,1)) + assert_equal_rational(true, Rational(-3,-4), Rational(3,4)) + assert_equal_rational(true, Rational(-4,5), Rational(4,-5)) + assert_equal_rational(true, Rational(4,2), 2) + assert_equal_rational(true, Rational(-4,2), -2) + assert_equal_rational(true, Rational(4,-2), -2) + assert_equal_rational(true, Rational(4,2), 2.0) + assert_equal_rational(true, Rational(-4,2), -2.0) + assert_equal_rational(true, Rational(4,-2), -2.0) + assert_equal_rational(true, Rational(8,6), Rational(4,3)) + assert_equal_rational(false, Rational(13,4), 3) + assert_equal_rational(false, Rational(13,4), 3.3) + assert_equal_rational(false, Rational(2,1), 1r) + assert_equal_rational(false, Rational(1), nil) + assert_equal_rational(false, Rational(1), '') +end + +assert 'Fixnum#==(Rational), Fixnum#!=(Rational)' do + assert_equal_rational(true, 2, Rational(4,2)) + assert_equal_rational(true, -2, Rational(-4,2)) + assert_equal_rational(true, -2, Rational(4,-2)) + assert_equal_rational(false, 3, Rational(13,4)) +end + +assert 'Float#==(Rational), Float#!=(Rational)' do + assert_equal_rational(true, 2.0, Rational(4,2)) + assert_equal_rational(true, -2.0, Rational(-4,2)) + assert_equal_rational(true, -2.0, Rational(4,-2)) + assert_equal_rational(false, 3.3, Rational(13,4)) +end -- cgit v1.2.3 From 4bc48d0b76924f936dc389406c68ed1a8e144e9c Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Thu, 16 May 2019 13:37:36 +0900 Subject: Refactor `time.c` regarding memory allocation. --- mrbgems/mruby-time/src/time.c | 28 ++++++++++++++++------------ 1 file changed, 16 insertions(+), 12 deletions(-) diff --git a/mrbgems/mruby-time/src/time.c b/mrbgems/mruby-time/src/time.c index b5a540d09..34376c286 100644 --- a/mrbgems/mruby-time/src/time.c +++ b/mrbgems/mruby-time/src/time.c @@ -205,17 +205,18 @@ static struct mrb_time* time_update_datetime(mrb_state *mrb, struct mrb_time *self, int dealloc) { struct tm *aid; + time_t t = self->sec; if (self->timezone == MRB_TIMEZONE_UTC) { - aid = gmtime_r(&self->sec, &self->datetime); + aid = gmtime_r(&t, &self->datetime); } else { - aid = localtime_r(&self->sec, &self->datetime); + aid = localtime_r(&t, &self->datetime); } if (!aid) { - mrb_float sec = (mrb_float)self->sec; + mrb_float sec = (mrb_float)t; - mrb_free(mrb, self); + if (dealloc) mrb_free(mrb, self); mrb_raisef(mrb, E_ARGUMENT_ERROR, "%S out of Time range", mrb_float_value(mrb, sec)); /* not reached */ return NULL; @@ -292,24 +293,24 @@ mrb_time_make(mrb_state *mrb, struct RClass *c, double sec, double usec, enum mr static struct mrb_time* current_mrb_time(mrb_state *mrb) { + struct mrb_time tmzero = {0}; struct mrb_time *tm; + time_t sec, usec; - tm = (struct mrb_time *)mrb_malloc(mrb, sizeof(*tm)); #if defined(TIME_UTC) && !defined(__ANDROID__) { struct timespec ts; if (timespec_get(&ts, TIME_UTC) == 0) { - mrb_free(mrb, tm); mrb_raise(mrb, E_RUNTIME_ERROR, "timespec_get() failed for unknown reasons"); } - tm->sec = ts.tv_sec; - tm->usec = ts.tv_nsec / 1000; + sec = ts.tv_sec; + usec = ts.tv_nsec / 1000; } #elif defined(NO_GETTIMEOFDAY) { static time_t last_sec = 0, last_usec = 0; - tm->sec = time(NULL); + sec = time(NULL); if (tm->sec != last_sec) { last_sec = tm->sec; last_usec = 0; @@ -318,17 +319,20 @@ current_mrb_time(mrb_state *mrb) /* add 1 usec to differentiate two times */ last_usec += 1; } - tm->usec = last_usec; + usec = last_usec; } #else { struct timeval tv; gettimeofday(&tv, NULL); - tm->sec = tv.tv_sec; - tm->usec = tv.tv_usec; + sec = tv.tv_sec; + usec = tv.tv_usec; } #endif + tm = (struct mrb_time *)mrb_malloc(mrb, sizeof(*tm)); + *tm = tmzero; + tm->sec = sec; tm->usec = usec; tm->timezone = MRB_TIMEZONE_LOCAL; time_update_datetime(mrb, tm, TRUE); -- cgit v1.2.3 From 283530b19b4140301a395d34c49f3188373dd69d Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Fri, 17 May 2019 10:37:49 +0900 Subject: Use `mrb_float` instead of `double` in `FIXABLE_FLOAT`. --- include/mruby/numeric.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/mruby/numeric.h b/include/mruby/numeric.h index da9225aaa..9a04631d6 100644 --- a/include/mruby/numeric.h +++ b/include/mruby/numeric.h @@ -23,7 +23,7 @@ MRB_BEGIN_DECL #define NEGFIXABLE(f) TYPED_NEGFIXABLE(f,mrb_int) #define FIXABLE(f) TYPED_FIXABLE(f,mrb_int) #ifndef MRB_WITHOUT_FLOAT -#define FIXABLE_FLOAT(f) TYPED_FIXABLE(f,double) +#define FIXABLE_FLOAT(f) TYPED_FIXABLE(f,mrb_float) #endif #ifndef MRB_WITHOUT_FLOAT -- cgit v1.2.3 From 80c789b3941160312ac7ffed202abe8c23bc0628 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Fri, 17 May 2019 10:40:19 +0900 Subject: Use `int64_t` instead of `mrb_int` in `int64_value`. --- src/numeric.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/numeric.c b/src/numeric.c index 5dbf9df22..113413502 100644 --- a/src/numeric.c +++ b/src/numeric.c @@ -421,7 +421,7 @@ value_int64(mrb_state *mrb, mrb_value x) static mrb_value int64_value(mrb_state *mrb, int64_t v) { - if (FIXABLE(v)) { + if (TYPED_FIXABLE(v,int64_t)) { return mrb_fixnum_value((mrb_int)v); } return mrb_float_value(mrb, (mrb_float)v); -- cgit v1.2.3 From 8a9f984eb8771a3d4956783116f972d4f5f70dfd Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Fri, 17 May 2019 10:42:16 +0900 Subject: Add a new function `mrb_int_value`. This function returns `Fixnum` if the value fits in `mrb_int`, otherwise it returns `Float` value (mruby behavior of handling integers). --- src/numeric.c | 29 +++++++++++++---------------- 1 file changed, 13 insertions(+), 16 deletions(-) diff --git a/src/numeric.c b/src/numeric.c index 113413502..30b6b230e 100644 --- a/src/numeric.c +++ b/src/numeric.c @@ -44,6 +44,15 @@ mrb_to_flo(mrb_state *mrb, mrb_value val) } return mrb_float(val); } + +static mrb_value +mrb_int_value(mrb_state *mrb, mrb_float f) +{ + if (FIXABLE_FLOAT(f)) { + return mrb_fixnum_value((mrb_int)f); + } + return mrb_float_value(mrb, f); +} #endif /* @@ -507,10 +516,7 @@ flo_shift(mrb_state *mrb, mrb_value x, mrb_int width) val *= 2; } } - if (FIXABLE_FLOAT(val)) { - return mrb_fixnum_value((mrb_int)val); - } - return mrb_float_value(mrb, val); + return mrb_int_value(mrb, val); } static mrb_value @@ -616,10 +622,7 @@ flo_floor(mrb_state *mrb, mrb_value num) mrb_float f = floor(mrb_float(num)); mrb_check_num_exact(mrb, f); - if (!FIXABLE_FLOAT(f)) { - return mrb_float_value(mrb, f); - } - return mrb_fixnum_value((mrb_int)f); + return mrb_int_value(mrb, f); } /* 15.2.9.3.8 */ @@ -642,10 +645,7 @@ flo_ceil(mrb_state *mrb, mrb_value num) mrb_float f = ceil(mrb_float(num)); mrb_check_num_exact(mrb, f); - if (!FIXABLE_FLOAT(f)) { - return mrb_float_value(mrb, f); - } - return mrb_fixnum_value((mrb_int)f); + return mrb_int_value(mrb, f); } /* 15.2.9.3.12 */ @@ -748,10 +748,7 @@ flo_truncate(mrb_state *mrb, mrb_value num) if (f < 0.0) f = ceil(f); mrb_check_num_exact(mrb, f); - if (!FIXABLE_FLOAT(f)) { - return mrb_float_value(mrb, f); - } - return mrb_fixnum_value((mrb_int)f); + return mrb_int_value(mrb, f); } static mrb_value -- cgit v1.2.3 From bc18060149fae9121fe744544521ca58989010ae Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Fri, 17 May 2019 10:44:56 +0900 Subject: Change the `num.divmod(float)` to return `[int,num]`. --- src/numeric.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/numeric.c b/src/numeric.c index 30b6b230e..ab8771e1a 100644 --- a/src/numeric.c +++ b/src/numeric.c @@ -934,7 +934,7 @@ fix_divmod(mrb_state *mrb, mrb_value x) mrb_value a, b; flodivmod(mrb, (mrb_float)mrb_fixnum(x), mrb_to_flo(mrb, y), &div, &mod); - a = mrb_float_value(mrb, div); + a = mrb_int_value(mrb, div); b = mrb_float_value(mrb, mod); return mrb_assoc_new(mrb, a, b); } @@ -952,7 +952,7 @@ flo_divmod(mrb_state *mrb, mrb_value x) mrb_get_args(mrb, "o", &y); flodivmod(mrb, mrb_float(x), mrb_to_flo(mrb, y), &div, &mod); - a = mrb_float_value(mrb, div); + a = mrb_int_value(mrb, div); b = mrb_float_value(mrb, mod); return mrb_assoc_new(mrb, a, b); } -- cgit v1.2.3 From 3734c53eb8e5fd34f572b62e2f85ed43b4f6d921 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Fri, 17 May 2019 11:13:12 +0900 Subject: Make `flo_rount` to return `Integeral`. --- src/numeric.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/numeric.c b/src/numeric.c index ab8771e1a..954e91019 100644 --- a/src/numeric.c +++ b/src/numeric.c @@ -726,7 +726,7 @@ flo_round(mrb_state *mrb, mrb_value num) if (!isfinite(number)) return num; return mrb_float_value(mrb, number); } - return mrb_fixnum_value((mrb_int)number); + return mrb_int_value(mrb, number); } /* 15.2.9.3.14 */ -- cgit v1.2.3 From 223defd62ae511786a2b50c68ed97b73bfc05d59 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Fri, 17 May 2019 11:26:16 +0900 Subject: Move `Numeric#div` to the core. --- mrbgems/mruby-numeric-ext/mrblib/numeric_ext.rb | 4 ---- src/numeric.c | 20 ++++++++++++++++++++ 2 files changed, 20 insertions(+), 4 deletions(-) diff --git a/mrbgems/mruby-numeric-ext/mrblib/numeric_ext.rb b/mrbgems/mruby-numeric-ext/mrblib/numeric_ext.rb index f250538fe..e86e8b283 100644 --- a/mrbgems/mruby-numeric-ext/mrblib/numeric_ext.rb +++ b/mrbgems/mruby-numeric-ext/mrblib/numeric_ext.rb @@ -1,8 +1,4 @@ module Integral - def div(other) - self.divmod(other)[0] - end - def zero? self == 0 end diff --git a/src/numeric.c b/src/numeric.c index 954e91019..8c17635a2 100644 --- a/src/numeric.c +++ b/src/numeric.c @@ -136,6 +136,25 @@ mrb_num_div(mrb_state *mrb, mrb_value x, mrb_value y) #endif } +static mrb_value +num_idiv(mrb_state *mrb, mrb_value x) +{ +#ifdef MRB_WITHOUT_FLOAT + mrb_value y; + + mrb_get_args(mrb, "o", &y); + if (!mrb_fixnum_p(y)) { + mrb_raise(mrb, E_TYPE_ERROR, "non fixnum value"); + } + return mrb_fixnum_value(mrb_fixnum(x) / mrb_fixnum(y)); +#else + mrb_float y; + + mrb_get_args(mrb, "f", &y); + return mrb_int_value(mrb, mrb_to_flo(mrb, x) / y); +#endif +} + /* 15.2.9.3.19(x) */ /* * call-seq: @@ -1552,6 +1571,7 @@ mrb_init_numeric(mrb_state *mrb) mrb_define_method(mrb, numeric, "**", num_pow, MRB_ARGS_REQ(1)); mrb_define_method(mrb, numeric, "/", num_div, MRB_ARGS_REQ(1)); /* 15.2.8.3.4 */ mrb_define_method(mrb, numeric, "quo", num_div, MRB_ARGS_REQ(1)); /* 15.2.7.4.5 (x) */ + mrb_define_method(mrb, numeric, "div", num_idiv, MRB_ARGS_REQ(1)); mrb_define_method(mrb, numeric, "<=>", num_cmp, MRB_ARGS_REQ(1)); /* 15.2.9.3.6 */ mrb_define_method(mrb, numeric, "<", num_lt, MRB_ARGS_REQ(1)); mrb_define_method(mrb, numeric, "<=", num_le, MRB_ARGS_REQ(1)); -- cgit v1.2.3 From 0c91da257bf64769d85a709852cfa2da313a4185 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Fri, 17 May 2019 11:27:21 +0900 Subject: Remove unused `mrb_num_div()` function. --- include/mruby/numeric.h | 1 - src/numeric.c | 35 +++++++++++------------------------ 2 files changed, 11 insertions(+), 25 deletions(-) diff --git a/include/mruby/numeric.h b/include/mruby/numeric.h index 9a04631d6..2fae3142d 100644 --- a/include/mruby/numeric.h +++ b/include/mruby/numeric.h @@ -39,7 +39,6 @@ MRB_API mrb_float mrb_to_flo(mrb_state *mrb, mrb_value x); mrb_value mrb_fixnum_plus(mrb_state *mrb, mrb_value x, mrb_value y); mrb_value mrb_fixnum_minus(mrb_state *mrb, mrb_value x, mrb_value y); mrb_value mrb_fixnum_mul(mrb_state *mrb, mrb_value x, mrb_value y); -mrb_value mrb_num_div(mrb_state *mrb, mrb_value x, mrb_value y); #ifndef __has_builtin #define __has_builtin(x) 0 diff --git a/src/numeric.c b/src/numeric.c index 8c17635a2..8e5fefa04 100644 --- a/src/numeric.c +++ b/src/numeric.c @@ -112,30 +112,6 @@ num_pow(mrb_state *mrb, mrb_value x) #endif } -/* 15.2.8.3.4 */ -/* 15.2.9.3.4 */ -/* - * call-seq: - * num / other -> num - * - * Performs division: the class of the resulting object depends on - * the class of num and on the magnitude of the - * result. - */ - -mrb_value -mrb_num_div(mrb_state *mrb, mrb_value x, mrb_value y) -{ -#ifdef MRB_WITHOUT_FLOAT - if (!mrb_fixnum_p(y)) { - mrb_raise(mrb, E_TYPE_ERROR, "non fixnum value"); - } - return mrb_fixnum_value(mrb_fixnum(x) / mrb_fixnum(y)); -#else - return mrb_float_value(mrb, mrb_to_flo(mrb, x) / mrb_to_flo(mrb, y)); -#endif -} - static mrb_value num_idiv(mrb_state *mrb, mrb_value x) { @@ -155,6 +131,17 @@ num_idiv(mrb_state *mrb, mrb_value x) #endif } +/* 15.2.8.3.4 */ +/* 15.2.9.3.4 */ +/* + * call-seq: + * num / other -> num + * + * Performs division: the class of the resulting object depends on + * the class of num and on the magnitude of the + * result. + */ + /* 15.2.9.3.19(x) */ /* * call-seq: -- cgit v1.2.3 From 0d61bcd823df74c65d8d5a3f8e36661780f92914 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Fri, 17 May 2019 11:27:52 +0900 Subject: Use `div` (integer divition) instead of `/` for rational numbers. --- mrbgems/mruby-rational/mrblib/rational.rb | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/mrbgems/mruby-rational/mrblib/rational.rb b/mrbgems/mruby-rational/mrblib/rational.rb index dbc855af0..30aaef915 100644 --- a/mrbgems/mruby-rational/mrblib/rational.rb +++ b/mrbgems/mruby-rational/mrblib/rational.rb @@ -94,9 +94,9 @@ class Rational < Numeric def _simplify a = numerator b = denominator - a, b = b, a % b while !b.zero? - @numerator /= a - @denominator /= a + a, b = b, a % b until b.zero? + @numerator = @numerator.div(a) + @denominator = @denominator.div(a) end attr_reader :numerator, :denominator -- cgit v1.2.3 From 237a57bbe831c57d3ebb0f9cc69768dbc8dda589 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Fri, 17 May 2019 11:30:38 +0900 Subject: Make unused functions private. * mrb_fixnum_plus() * mrb_fixnum_minus() * mrb_fixnum_mul() --- include/mruby/numeric.h | 4 ---- src/numeric.c | 6 +++--- 2 files changed, 3 insertions(+), 7 deletions(-) diff --git a/include/mruby/numeric.h b/include/mruby/numeric.h index 2fae3142d..9d87ca5c4 100644 --- a/include/mruby/numeric.h +++ b/include/mruby/numeric.h @@ -36,10 +36,6 @@ MRB_API mrb_value mrb_float_to_str(mrb_state *mrb, mrb_value x, const char *fmt) MRB_API mrb_float mrb_to_flo(mrb_state *mrb, mrb_value x); #endif -mrb_value mrb_fixnum_plus(mrb_state *mrb, mrb_value x, mrb_value y); -mrb_value mrb_fixnum_minus(mrb_state *mrb, mrb_value x, mrb_value y); -mrb_value mrb_fixnum_mul(mrb_state *mrb, mrb_value x, mrb_value y); - #ifndef __has_builtin #define __has_builtin(x) 0 #endif diff --git a/src/numeric.c b/src/numeric.c index 8e5fefa04..6622a46e9 100644 --- a/src/numeric.c +++ b/src/numeric.c @@ -787,7 +787,7 @@ int_to_i(mrb_state *mrb, mrb_value num) return num; } -mrb_value +static mrb_value mrb_fixnum_mul(mrb_state *mrb, mrb_value x, mrb_value y) { mrb_int a; @@ -1244,7 +1244,7 @@ mrb_flo_to_fixnum(mrb_state *mrb, mrb_value x) } #endif -mrb_value +static mrb_value mrb_fixnum_plus(mrb_state *mrb, mrb_value x, mrb_value y) { mrb_int a; @@ -1287,7 +1287,7 @@ fix_plus(mrb_state *mrb, mrb_value self) return mrb_fixnum_plus(mrb, self, other); } -mrb_value +static mrb_value mrb_fixnum_minus(mrb_state *mrb, mrb_value x, mrb_value y) { mrb_int a; -- cgit v1.2.3 From 912d23634d60def0c6a370b059f69999fe363c9b Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Fri, 17 May 2019 16:18:46 +0900 Subject: Fixed wrong overloading. `float op rational` should return `float`, since float is an inexact value. --- mrbgems/mruby-rational/mrblib/rational.rb | 30 +++++++++++++++++++----------- 1 file changed, 19 insertions(+), 11 deletions(-) diff --git a/mrbgems/mruby-rational/mrblib/rational.rb b/mrbgems/mruby-rational/mrblib/rational.rb index 30aaef915..82ae98425 100644 --- a/mrbgems/mruby-rational/mrblib/rational.rb +++ b/mrbgems/mruby-rational/mrblib/rational.rb @@ -106,18 +106,26 @@ def Rational(numerator = 0, denominator = 1) Rational.new(numerator, denominator) end -[Fixnum, Float].each do |cls| - [:+, :-, :*, :/, :<=>, :==, :<, :<=, :>, :>=].each do |op| - cls.instance_exec do - original_operator_name = "__original_operator_#{op}_rational" - alias_method original_operator_name, op - define_method op do |rhs| - if rhs.is_a? Rational - Rational(self).__send__(op, rhs) - else - __send__(original_operator_name, rhs) - end +[:+, :-, :*, :/, :<=>, :==, :<, :<=, :>, :>=].each do |op| + Fixnum.instance_exec do + original_operator_name = "__original_operator_#{op}_rational" + alias_method original_operator_name, op + define_method op do |rhs| + if rhs.is_a? Rational + Rational(self).__send__(op, rhs) + else + __send__(original_operator_name, rhs) end end end + Float.instance_exec do + original_operator_name = "__original_operator_#{op}_rational" + alias_method original_operator_name, op + define_method op do |rhs| + if rhs.is_a? Rational + rhs = rhs.to_f + end + __send__(original_operator_name, rhs) + end + end end -- cgit v1.2.3 From cec92673ae9e24d73a6feb2d69602b5fa60dcddd Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Fri, 17 May 2019 16:22:23 +0900 Subject: Avoid direct access to instance variables in `rational.rb`. --- mrbgems/mruby-rational/mrblib/rational.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mrbgems/mruby-rational/mrblib/rational.rb b/mrbgems/mruby-rational/mrblib/rational.rb index 82ae98425..a38f71407 100644 --- a/mrbgems/mruby-rational/mrblib/rational.rb +++ b/mrbgems/mruby-rational/mrblib/rational.rb @@ -72,14 +72,14 @@ class Rational < Numeric def <=>(rhs) case rhs when Fixnum - return @numerator <=> rhs if @denominator == 1 + return numerator <=> rhs if denominator == 1 rhs = Rational(rhs) when Float return to_f <=> rhs end case rhs when Rational - (@numerator * rhs.denominator - @denominator * rhs.numerator) <=> 0 + (numerator * rhs.denominator - denominator * rhs.numerator) <=> 0 when Numeric return rhs <=> self else -- cgit v1.2.3 From b6e9fab64949b91f00d07c890935642f44147615 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Fri, 17 May 2019 16:37:34 +0900 Subject: Implement part of `Rational` in C. --- mrbgems/mruby-rational/mrblib/rational.rb | 43 +++++---------- mrbgems/mruby-rational/src/rational.c | 90 +++++++++++++++++++++++++++++++ 2 files changed, 102 insertions(+), 31 deletions(-) create mode 100644 mrbgems/mruby-rational/src/rational.c diff --git a/mrbgems/mruby-rational/mrblib/rational.rb b/mrbgems/mruby-rational/mrblib/rational.rb index a38f71407..54324b05f 100644 --- a/mrbgems/mruby-rational/mrblib/rational.rb +++ b/mrbgems/mruby-rational/mrblib/rational.rb @@ -2,29 +2,10 @@ class Rational < Numeric # Override #<, #<=, #>, #>= in Numeric prepend Comparable - def initialize(numerator = 0, denominator = 1) - @numerator = numerator - @denominator = denominator - - _simplify - end - def inspect "(#{to_s})" end - def to_f - @numerator.to_f / @denominator.to_f - end - - def to_i - to_f.to_i - end - - def to_r - self - end - def to_s "#{numerator}/#{denominator}" end @@ -86,24 +67,24 @@ class Rational < Numeric nil end end +end - def negative? - numerator.negative? - end - - def _simplify - a = numerator - b = denominator - a, b = b, a % b until b.zero? - @numerator = @numerator.div(a) - @denominator = @denominator.div(a) +class << Numeric + def to_r + Rational(self, 1) end +end - attr_reader :numerator, :denominator +class << Rational + alias_method :_new, :new + undef_method :new end def Rational(numerator = 0, denominator = 1) - Rational.new(numerator, denominator) + a = numerator + b = denominator + a, b = b, a % b until b.zero? + Rational._new(numerator.div(a), denominator.div(a)) end [:+, :-, :*, :/, :<=>, :==, :<, :<=, :>, :>=].each do |op| diff --git a/mrbgems/mruby-rational/src/rational.c b/mrbgems/mruby-rational/src/rational.c new file mode 100644 index 000000000..14a9b045d --- /dev/null +++ b/mrbgems/mruby-rational/src/rational.c @@ -0,0 +1,90 @@ +#include +#include +#include +#include + +struct mrb_rational { + mrb_int numerator; + mrb_int denominator; +}; + +static struct mrb_rational* +rational_ptr(mrb_value v) +{ + return (struct mrb_rational*)mrb_istruct_ptr(v); +} + +static mrb_value +rational_numerator(mrb_state *mrb, mrb_value self) +{ + struct mrb_rational *p = rational_ptr(self); + return mrb_fixnum_value(p->numerator); +} + +static mrb_value +rational_denominator(mrb_state *mrb, mrb_value self) +{ + struct mrb_rational *p = rational_ptr(self); + return mrb_fixnum_value(p->denominator); +} + +static mrb_value +rational_initialize(mrb_state *mrb, mrb_value self) +{ + struct mrb_rational *p = rational_ptr(self); + mrb_get_args(mrb, "ii", &p->numerator, &p->denominator); + return self; +} + +static mrb_value +rational_to_f(mrb_state *mrb, mrb_value self) +{ + struct mrb_rational *p = rational_ptr(self); + mrb_float f = (mrb_float)p->numerator / (mrb_float)p->denominator; + + return mrb_float_value(mrb, f); +} + +static mrb_value +rational_to_i(mrb_state *mrb, mrb_value self) +{ + struct mrb_rational *p = rational_ptr(self); + return mrb_fixnum_value(p->numerator / 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) +{ + struct mrb_rational *p = rational_ptr(self); + if (p->numerator < 0) { + return mrb_true_value(); + } + return mrb_false_value(); +} + +void mrb_mruby_rational_gem_init(mrb_state *mrb) +{ + struct RClass *rat; + + mrb_assert(sizeof(struct mrb_rational) < ISTRUCT_DATA_SIZE); + rat = mrb_define_class(mrb, "Rational", mrb_class_get(mrb, "Numeric")); + MRB_SET_INSTANCE_TT(rat, MRB_TT_ISTRUCT); + mrb_define_method(mrb, rat, "numerator", rational_numerator, MRB_ARGS_NONE()); + mrb_define_method(mrb, rat, "denominator", rational_denominator, MRB_ARGS_NONE()); + mrb_define_method(mrb, rat, "initialize", rational_initialize, MRB_ARGS_REQ(2)); + mrb_define_method(mrb, rat, "to_f", rational_to_f, MRB_ARGS_NONE()); + mrb_define_method(mrb, rat, "to_i", rational_to_i, MRB_ARGS_NONE()); + mrb_define_method(mrb, rat, "to_r", rational_to_r, MRB_ARGS_NONE()); + mrb_define_method(mrb, rat, "negative?", rational_negative_p, MRB_ARGS_NONE()); +} + +void +mrb_mruby_rational_gem_final(mrb_state* mrb) +{ +} -- cgit v1.2.3 From d5c8868346b49e2b2228cb8733398d88f744985b Mon Sep 17 00:00:00 2001 From: Kouhei Sutou Date: Fri, 17 May 2019 17:59:24 +0900 Subject: Add support for CC="gcc --option ..." again If $rake_root_fiber is used, sh runs command in another Fiber. If command is ran in another Fiber, "rescue RuntimEerror" can't rescue exception for system(...) failure. How to reproduce: $ CC="gcc -std=gnu99" ./minirake (in /home/kou/work/ruby/mruby.kou) CC mrbgems/mruby-compiler/core/codegen.c -> build/test/mrbgems/mruby-compiler/core/codegen.o sh: 1: gcc -std=gnu99: not found rake aborted! Command Failed: ["gcc -std=gnu99" -g -std=gnu99 ...] --- lib/mruby/build/command.rb | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lib/mruby/build/command.rb b/lib/mruby/build/command.rb index 0f18e0e62..0fa4746da 100644 --- a/lib/mruby/build/command.rb +++ b/lib/mruby/build/command.rb @@ -30,10 +30,13 @@ module MRuby def _run(options, params={}) return sh command + ' ' + ( options % params ) if NotFoundCommands.key? @command begin + fiber, $rake_root_fiber = $rake_root_fiber, nil sh build.filename(command) + ' ' + ( options % params ) rescue RuntimeError NotFoundCommands[@command] = true _run options, params + ensure + $rake_root_fiber = fiber end end end -- cgit v1.2.3 From eeb95e058a579a45207079369b19869cb48a39de Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Fri, 17 May 2019 19:53:31 +0900 Subject: Fix `Numeric#to_r` --- mrbgems/mruby-rational/mrblib/rational.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mrbgems/mruby-rational/mrblib/rational.rb b/mrbgems/mruby-rational/mrblib/rational.rb index 54324b05f..37dcfc2a0 100644 --- a/mrbgems/mruby-rational/mrblib/rational.rb +++ b/mrbgems/mruby-rational/mrblib/rational.rb @@ -69,7 +69,7 @@ class Rational < Numeric end end -class << Numeric +class Numeric def to_r Rational(self, 1) end -- cgit v1.2.3 From aa41a5c9af4d8ee61867d4f0bfdaeab4deb7cf0e Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Fri, 17 May 2019 20:44:48 +0900 Subject: Drop dependency from `mruby-rational` to `mruby-numeric-ext` --- mrbgems/mruby-rational/mrbgem.rake | 1 - mrbgems/mruby-rational/mrblib/rational.rb | 2 +- mrbgems/mruby-rational/test/rational.rb | 7 +++++++ 3 files changed, 8 insertions(+), 2 deletions(-) diff --git a/mrbgems/mruby-rational/mrbgem.rake b/mrbgems/mruby-rational/mrbgem.rake index 496082709..15c3429f2 100644 --- a/mrbgems/mruby-rational/mrbgem.rake +++ b/mrbgems/mruby-rational/mrbgem.rake @@ -4,5 +4,4 @@ MRuby::Gem::Specification.new('mruby-rational') do |spec| spec.summary = 'Rational class' spec.add_dependency 'mruby-object-ext', core: 'mruby-object-ext' - spec.add_dependency 'mruby-numeric-ext', core: 'mruby-numeric-ext' end diff --git a/mrbgems/mruby-rational/mrblib/rational.rb b/mrbgems/mruby-rational/mrblib/rational.rb index 54324b05f..ccb67541f 100644 --- a/mrbgems/mruby-rational/mrblib/rational.rb +++ b/mrbgems/mruby-rational/mrblib/rational.rb @@ -83,7 +83,7 @@ end def Rational(numerator = 0, denominator = 1) a = numerator b = denominator - a, b = b, a % b until b.zero? + a, b = b, a % b until b == 0 Rational._new(numerator.div(a), denominator.div(a)) end diff --git a/mrbgems/mruby-rational/test/rational.rb b/mrbgems/mruby-rational/test/rational.rb index 4d3d36ccc..a65926bfb 100644 --- a/mrbgems/mruby-rational/test/rational.rb +++ b/mrbgems/mruby-rational/test/rational.rb @@ -100,3 +100,10 @@ assert 'Float#==(Rational), Float#!=(Rational)' do assert_equal_rational(true, -2.0, Rational(4,-2)) assert_equal_rational(false, 3.3, Rational(13,4)) end + +assert 'Rational#negative?' do + assert_predicate(Rational(-2,3), :negative?) + assert_predicate(Rational(2,-3), :negative?) + assert_not_predicate(Rational(2,3), :negative?) + assert_not_predicate(Rational(0), :negative?) +end -- cgit v1.2.3 From c5c39f585b48ef9cede6059ae5bc16b00f160db8 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Fri, 17 May 2019 21:13:31 +0900 Subject: Move `Integral#(zero|nonzero|positive|negative)?` to `Numeric` Because these methods work if object is `Comparable`, and `Numeric` is `Comparable`. --- mrbgems/mruby-numeric-ext/mrblib/numeric_ext.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mrbgems/mruby-numeric-ext/mrblib/numeric_ext.rb b/mrbgems/mruby-numeric-ext/mrblib/numeric_ext.rb index e86e8b283..576605cb1 100644 --- a/mrbgems/mruby-numeric-ext/mrblib/numeric_ext.rb +++ b/mrbgems/mruby-numeric-ext/mrblib/numeric_ext.rb @@ -1,4 +1,4 @@ -module Integral +class Numeric def zero? self == 0 end -- cgit v1.2.3 From 647569bfe84799c7452da278b64fa72338e48246 Mon Sep 17 00:00:00 2001 From: Bhargava Shastry Date: Fri, 17 May 2019 14:26:41 +0200 Subject: Add/Edit ossfuzz config options --- oss-fuzz/config/mruby_fuzzer.options | 2 +- oss-fuzz/config/mruby_proto_fuzzer.options | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) create mode 100644 oss-fuzz/config/mruby_proto_fuzzer.options diff --git a/oss-fuzz/config/mruby_fuzzer.options b/oss-fuzz/config/mruby_fuzzer.options index 132affcae..8658e71b2 100644 --- a/oss-fuzz/config/mruby_fuzzer.options +++ b/oss-fuzz/config/mruby_fuzzer.options @@ -1,5 +1,5 @@ [libfuzzer] close_fd_mask = 3 dict = mruby.dict -fork = 8 +fork = 1 only_ascii = 1 diff --git a/oss-fuzz/config/mruby_proto_fuzzer.options b/oss-fuzz/config/mruby_proto_fuzzer.options new file mode 100644 index 000000000..4ced8516c --- /dev/null +++ b/oss-fuzz/config/mruby_proto_fuzzer.options @@ -0,0 +1,4 @@ +[libfuzzer] +close_fd_mask = 3 +dict = mruby.dict +fork = 1 -- cgit v1.2.3 From 1f3ece9631d3b52911ff7b5fff88fa8fccbbc3f9 Mon Sep 17 00:00:00 2001 From: Bhargava Shastry Date: Fri, 17 May 2019 14:22:43 +0200 Subject: proto fuzzer: Add source files necessary to compile proto fuzzer --- oss-fuzz/mruby_proto_fuzzer.cpp | 44 ++++ oss-fuzz/proto_to_ruby.cpp | 455 ++++++++++++++++++++++++++++++++++++++++ oss-fuzz/proto_to_ruby.h | 55 +++++ oss-fuzz/ruby.proto | 201 ++++++++++++++++++ 4 files changed, 755 insertions(+) create mode 100644 oss-fuzz/mruby_proto_fuzzer.cpp create mode 100644 oss-fuzz/proto_to_ruby.cpp create mode 100644 oss-fuzz/proto_to_ruby.h create mode 100644 oss-fuzz/ruby.proto diff --git a/oss-fuzz/mruby_proto_fuzzer.cpp b/oss-fuzz/mruby_proto_fuzzer.cpp new file mode 100644 index 000000000..2999c5470 --- /dev/null +++ b/oss-fuzz/mruby_proto_fuzzer.cpp @@ -0,0 +1,44 @@ +#include +#include +#include + +#include +#include + +#include "libprotobuf-mutator/src/libfuzzer/libfuzzer_macro.h" +#include "ruby.pb.h" +#include "proto_to_ruby.h" + +using namespace ruby_fuzzer; +using namespace std; + +int FuzzRB(const uint8_t *Data, size_t size) { + mrb_value v; + mrb_state *mrb = mrb_open(); + if (!mrb) + return 0; + + char *code = (char *)malloc(size+1); + if (!code) + return 0; + memcpy(code, Data, size); + code[size] = '\0'; + + if (const char *dump_path = getenv("PROTO_FUZZER_DUMP_PATH")) { + // With libFuzzer binary run this to generate an RB file x.rb: + // PROTO_FUZZER_DUMP_PATH=x.rb ./a.out proto-input + std::ofstream of(dump_path); + of.write(code, size); + } + v = mrb_load_string(mrb, code); + mrb_close(mrb); + + free(code); + return 0; +} + +DEFINE_PROTO_FUZZER(const Function &function) { + protoConverter converter; + auto s = converter.FunctionToString(function); + (void)FuzzRB((const uint8_t*)s.data(), s.size()); +} diff --git a/oss-fuzz/proto_to_ruby.cpp b/oss-fuzz/proto_to_ruby.cpp new file mode 100644 index 000000000..92ad039e2 --- /dev/null +++ b/oss-fuzz/proto_to_ruby.cpp @@ -0,0 +1,455 @@ +#include "proto_to_ruby.h" + +using namespace ruby_fuzzer; + +std::string protoConverter::removeSpecial(const std::string &x) +{ + std::string tmp(x); + if (!tmp.empty()) + tmp.erase(std::remove_if(tmp.begin(), tmp.end(), + [](char c) { return !(std::isalpha(c) || std::isdigit(c)); } ), tmp.end()); + return tmp; +} + +void protoConverter::visit(ArrType const& x) +{ + if (x.elements_size() > 0) { + int i = x.elements_size(); + m_output << "["; + for (auto &e : x.elements()) { + i--; + if (i == 0) { + visit(e); + } else { + visit(e); + m_output << ", "; + } + } + m_output << "]"; + } else { + m_output << "[1]"; + } +} + +void protoConverter::visit(Array const& x) +{ + switch (x.arr_func()) { + case Array::FLATTEN: + visit(x.arr_arg()); + m_output << ".flatten"; + break; + case Array::COMPACT: + visit(x.arr_arg()); + m_output << ".compact"; + break; + case Array::FETCH: + visit(x.arr_arg()); + m_output << ".fetch"; + break; + case Array::FILL: + visit(x.arr_arg()); + m_output << ".fill"; + break; + case Array::ROTATE: + visit(x.arr_arg()); + m_output << ".rotate"; + break; + case Array::ROTATE_E: + visit(x.arr_arg()); + m_output << ".rotate!"; + break; + case Array::DELETEIF: + visit(x.arr_arg()); + m_output << ".delete_if"; + break; + case Array::INSERT: + visit(x.arr_arg()); + m_output << ".insert"; + break; + case Array::BSEARCH: + visit(x.arr_arg()); + m_output << ".bsearch"; + break; + case Array::KEEPIF: + visit(x.arr_arg()); + m_output << ".keep_if"; + break; + case Array::SELECT: + visit(x.arr_arg()); + m_output << ".select"; + break; + case Array::VALUES_AT: + visit(x.arr_arg()); + m_output << ".values_at"; + break; + case Array::BLOCK: + visit(x.arr_arg()); + m_output << ".index"; + break; + case Array::DIG: + visit(x.arr_arg()); + m_output << ".dig"; + break; + case Array::SLICE: + visit(x.arr_arg()); + m_output << ".slice"; + break; + case Array::PERM: + visit(x.arr_arg()); + m_output << ".permutation"; + break; + case Array::COMB: + visit(x.arr_arg()); + m_output << ".combination"; + break; + case Array::ASSOC: + visit(x.arr_arg()); + m_output << ".assoc"; + break; + case Array::RASSOC: + visit(x.arr_arg()); + m_output << ".rassoc"; + break; + } + m_output << "("; + visit(x.val_arg()); + m_output << ")"; +} + +void protoConverter::visit(AssignmentStatement const& x) +{ + m_output << "var_" << m_numLiveVars << " = "; + visit(x.rvalue()); + m_numVarsPerScope.top()++; + m_numLiveVars++; + m_output << "\n"; +} + +void protoConverter::visit(BinaryOp const& x) +{ + m_output << "("; + visit(x.left()); + switch (x.op()) { + case BinaryOp::ADD: m_output << " + "; break; + case BinaryOp::SUB: m_output << " - "; break; + case BinaryOp::MUL: m_output << " * "; break; + case BinaryOp::DIV: m_output << " / "; break; + case BinaryOp::MOD: m_output << " % "; break; + case BinaryOp::XOR: m_output << " ^ "; break; + case BinaryOp::AND: m_output << " and "; break; + case BinaryOp::OR: m_output << " or "; break; + case BinaryOp::EQ: m_output << " == "; break; + case BinaryOp::NE: m_output << " != "; break; + case BinaryOp::LE: m_output << " <= "; break; + case BinaryOp::GE: m_output << " >= "; break; + case BinaryOp::LT: m_output << " < "; break; + case BinaryOp::GT: m_output << " > "; break; + case BinaryOp::RS: m_output << " >> "; break; + } + visit(x.right()); + m_output << ")"; +} + +void protoConverter::visit(BuiltinFuncs const& x) +{ + switch (x.bifunc_oneof_case()) { + case BuiltinFuncs::kOs: + visit(x.os()); + break; + case BuiltinFuncs::kTime: + visit(x.time()); + break; + case BuiltinFuncs::kArr: + visit(x.arr()); + break; + case BuiltinFuncs::kMops: + visit(x.mops()); + break; + case BuiltinFuncs::BIFUNC_ONEOF_NOT_SET: + m_output << "1"; + break; + } + m_output << "\n"; +} + +void protoConverter::visit(Const const& x) +{ + switch (x.const_oneof_case()) { + case Const::kIntLit: + m_output << "(" << (x.int_lit() % 13) << ")"; + break; + case Const::kBoolVal: + m_output << "(" << x.bool_val() << ")"; + break; + case Const::CONST_ONEOF_NOT_SET: + m_output << "1"; + break; + } +} + +void protoConverter::visit(Function const& x) +{ + m_output << "def foo()\nvar_0 = 1\n"; + visit(x.statements()); + m_output << "end\n"; + m_output << "foo\n"; +} + +void protoConverter::visit(HashType const& x) +{ + if (x.keyval_size() > 0) { + int i = x.keyval_size(); + m_output << "{"; + for (auto &e : x.keyval()) { + i--; + if (i == 0) { + visit(e); + } + else { + visit(e); + m_output << ", "; + } + } + m_output << "}"; + } +} + +void protoConverter::visit(IfElse const& x) +{ + m_output << "if "; + visit(x.cond()); + m_output << "\n"; + visit(x.if_body()); + m_output << "\nelse\n"; + visit(x.else_body()); + m_output << "\nend\n"; +} + +void protoConverter::visit(KVPair const& x) +{ + m_output << "\"" << removeSpecial(x.key()) << "\""; + m_output << " => "; + m_output << "\"" << removeSpecial(x.val()) << "\""; +} + +void protoConverter::visit(MathConst const& x) +{ + switch (x.math_const()) { + case MathConst::PI: + m_output << "Math::PI"; + break; + case MathConst::E: + m_output << "Math::E"; + break; + } +} + +void protoConverter::visit(MathOps const& x) +{ + switch (x.math_op()) { + case MathOps::CBRT: + m_output << "Math.cbrt("; + visit(x.math_arg()); + m_output << ")"; + break; + case MathOps::COS: + m_output << "Math.cos("; + visit(x.math_arg()); + m_output << ")"; + break; + case MathOps::ERF: + m_output << "Math.erf("; + visit(x.math_arg()); + m_output << ")"; + break; + case MathOps::ERFC: + m_output << "Math.erfc("; + visit(x.math_arg()); + m_output << ")"; + break; + case MathOps::LOG: + m_output << "Math.log("; + visit(x.math_arg()); + m_output << ")"; + break; + case MathOps::LOG10: + m_output << "Math.log10("; + visit(x.math_arg()); + m_output << ")"; + break; + case MathOps::LOG2: + m_output << "Math.log2("; + visit(x.math_arg()); + m_output << ")"; + break; + case MathOps::SIN: + m_output << "Math.sin("; + visit(x.math_arg()); + m_output << ")"; + break; + case MathOps::SQRT: + m_output << "Math.sqrt("; + visit(x.math_arg()); + m_output << ")"; + break; + case MathOps::TAN: + m_output << "Math.tan("; + visit(x.math_arg()); + m_output << ")"; + break; + } +} + +void protoConverter::visit(MathType const& x) +{ + switch (x.math_arg_oneof_case()) { + case MathType::kMathRval: + visit(x.math_rval()); + break; + case MathType::kMathConst: + visit(x.math_const()); + break; + case MathType::MATH_ARG_ONEOF_NOT_SET: + m_output << "1"; + break; + } +} + +void protoConverter::visit(ObjectSpace const& x) +{ + switch (x.os_func()) { + case ObjectSpace::COUNT: + m_output << "ObjectSpace.count_objects"; + break; + } + m_output << "("; + visit(x.os_arg()); + m_output << ")" << "\n"; +} + +void protoConverter::visit(Rvalue const& x) +{ + switch (x.rvalue_oneof_case()) { + case Rvalue::kVarref: + visit(x.varref()); + break; + case Rvalue::kCons: + visit(x.cons()); + break; + case Rvalue::kBinop: + visit(x.binop()); + break; + case Rvalue::RVALUE_ONEOF_NOT_SET: + m_output << "1"; + break; + } +} + +void protoConverter::visit(Statement const& x) +{ + switch (x.stmt_oneof_case()) { + case Statement::kAssignment: + visit(x.assignment()); + break; + case Statement::kIfelse: + visit(x.ifelse()); + break; + case Statement::kTernaryStmt: + visit(x.ternary_stmt()); + break; + case Statement::kBuiltins: + visit(x.builtins()); + break; + case Statement::kBlockstmt: + visit(x.blockstmt()); + break; + case Statement::STMT_ONEOF_NOT_SET: + break; + } + m_output << "\n"; +} + +void protoConverter::visit(StatementSeq const& x) +{ + if (x.statements_size() > 0) { + m_numVarsPerScope.push(0); + m_output << "@scope ||= begin\n"; + for (auto &st : x.statements()) + visit(st); + m_output << "end\n"; + m_numLiveVars -= m_numVarsPerScope.top(); + m_numVarsPerScope.pop(); + } +} + +void protoConverter::visit(StringExtNoArg const& x) +{ + m_output << "\"" << removeSpecial(x.str_arg()) << "\""; + switch (x.str_op()) { + case StringExtNoArg::DUMP: + m_output << ".dump"; + break; + case StringExtNoArg::STRIP: + m_output << ".strip"; + break; + case StringExtNoArg::LSTRIP: + m_output << ".lstrip"; + break; + case StringExtNoArg::RSTRIP: + m_output << ".rstrip"; + break; + case StringExtNoArg::STRIPE: + m_output << ".strip!"; + break; + case StringExtNoArg::LSTRIPE: + m_output << ".lstrip!"; + break; + case StringExtNoArg::RSTRIPE: + m_output << ".rstrip!"; + break; + case StringExtNoArg::SWAPCASE: + m_output << ".swapcase"; + break; + case StringExtNoArg::SWAPCASEE: + m_output << ".swapcase!"; + break; + case StringExtNoArg::SQUEEZE: + m_output << ".squeeze"; + break; + } +} + +void protoConverter::visit(Ternary const& x) +{ + m_output << "("; + visit(x.tern_cond()); + m_output << " ? "; + visit(x.t_branch()); + m_output << " : "; + visit(x.f_branch()); + m_output << ")\n"; +} + +void protoConverter::visit(Time const& x) +{ + switch (x.t_func()) { + case Time::AT: + m_output << "Time.at"; + break; + case Time::GM: + m_output << "Time.gm"; + break; + } + m_output << "(" << (x.t_arg()% 13) << ")" << "\n"; +} + +void protoConverter::visit(VarRef const& x) +{ + m_output << "var_" << (static_cast(x.varnum()) % m_numLiveVars); +} + +std::string protoConverter::FunctionToString(Function const& input) +{ + visit(input); + return m_output.str(); +} diff --git a/oss-fuzz/proto_to_ruby.h b/oss-fuzz/proto_to_ruby.h new file mode 100644 index 000000000..01f9d68bb --- /dev/null +++ b/oss-fuzz/proto_to_ruby.h @@ -0,0 +1,55 @@ +#include +#include +#include +#include +#include +#include +#include "ruby.pb.h" + +namespace ruby_fuzzer { + class protoConverter + { + public: + protoConverter() { + m_numLiveVars = 1; + m_numVarsPerScope.push(m_numLiveVars); + } + protoConverter(protoConverter const& x) { + m_numLiveVars = x.m_numLiveVars; + m_numVarsPerScope = x.m_numVarsPerScope; + } + ~protoConverter() {} + std::string FunctionToString(Function const& _input); + + private: + void visit(ArrType const&); + void visit(Array const&); + void visit(AssignmentStatement const&); + void visit(BinaryOp const&); + void visit(BuiltinFuncs const&); + void visit(Const const&); + void visit(Function const&); + void visit(HashType const&); + void visit(IfElse const&); + void visit(KVPair const&); + void visit(MathConst const&); + void visit(MathOps const&); + void visit(MathType const&); + void visit(ObjectSpace const&); + void visit(Rvalue const&); + void visit(Statement const&); + void visit(StatementSeq const&); + void visit(StringExtNoArg const&); + void visit(Ternary const&); + void visit(Time const&); + void visit(VarRef const&); + template + void visit(google::protobuf::RepeatedPtrField const& _repeated_field); + + std::string removeSpecial(const std::string &x); + + std::ostringstream m_output; + std::stack m_numVarsPerScope; + int32_t m_numLiveVars; + }; +} diff --git a/oss-fuzz/ruby.proto b/oss-fuzz/ruby.proto new file mode 100644 index 000000000..d9b0804c8 --- /dev/null +++ b/oss-fuzz/ruby.proto @@ -0,0 +1,201 @@ +syntax = "proto2"; + +message VarRef { + required int32 varnum = 1; +} + +message ArrType { + repeated Const elements = 1; +} + +message KVPair { + required string key = 1; + required string val = 2; +} + +message HashType { + repeated KVPair keyval = 1; +} + +message StringExtNoArg { + enum StrExtOp { + DUMP = 0; + STRIP = 1; + LSTRIP = 2; + RSTRIP = 3; + STRIPE = 4; + LSTRIPE = 5; + RSTRIPE = 6; + SWAPCASE = 7; + SWAPCASEE = 8; + SQUEEZE = 9; + } + required StrExtOp str_op = 1; + required string str_arg = 2; +} + +message MathConst { + enum MathConstLit { + PI = 0; + E = 1; + } + required MathConstLit math_const = 1; +} + +message Const { + oneof const_oneof { + uint32 int_lit = 1; + bool bool_val = 4; + } +} + +message BinaryOp { + enum Op { + ADD = 0; + SUB = 1; + MUL = 2; + DIV = 3; + MOD = 4; + XOR = 5; + AND = 6; + OR = 7; + EQ = 8; + NE = 9; + LE = 10; + GE = 11; + LT = 12; + GT = 13; + RS = 14; + }; + required Op op = 1; + required Rvalue left = 2; + required Rvalue right = 3; +} + +message Rvalue { + oneof rvalue_oneof { + VarRef varref = 1; + Const cons = 2; + BinaryOp binop = 3; + } +} + +message AssignmentStatement { + required Rvalue rvalue = 2; +} + + +message IfElse { + required Rvalue cond = 1; + required StatementSeq if_body = 2; + required StatementSeq else_body = 3; +} + +//TODO: Add Switch statement +//message Switch { +// required Rvalue switch_var = 1; +// repeated Rvalue cond = 2; +//} + +message Ternary { + required Rvalue tern_cond = 1; + required Rvalue t_branch = 2; + required Rvalue f_branch = 3; +} + +message ObjectSpace { + enum OS_methods { + COUNT = 1; + } + required OS_methods os_func = 1; + required HashType os_arg = 2; +} + +message Time { + enum T_methods { + AT = 1; + GM = 2; + } + required T_methods t_func = 1; + required uint32 t_arg = 2; +} + +message Array { + enum Arr_methods { + FLATTEN = 1; + COMPACT = 2; + FETCH = 3; + FILL = 4; + ROTATE = 5; + ROTATE_E = 6; + DELETEIF = 7; + INSERT = 8; + BSEARCH = 9; + KEEPIF = 10; + SELECT = 11; + VALUES_AT = 12; + BLOCK = 13; + DIG = 14; + SLICE = 15; + PERM = 16; + COMB = 17; + ASSOC = 18; + RASSOC = 19; + } + required Arr_methods arr_func = 1; + required ArrType arr_arg = 2; + required Rvalue val_arg = 3; +} + +message MathType { + oneof math_arg_oneof { + Rvalue math_rval = 2; + MathConst math_const = 3; + } +} + +message MathOps { + enum Mops { + CBRT = 1; + COS = 2; + ERF = 3; + ERFC = 4; + LOG = 5; + LOG10 = 6; + LOG2 = 7; + SIN = 8; + SQRT = 9; + TAN = 10; + } + required Mops math_op = 1; + required MathType math_arg = 2; +} + +message BuiltinFuncs { + oneof bifunc_oneof { + ObjectSpace os = 1; + Time time = 2; + Array arr = 3; + MathOps mops = 4; + } +} + +message Statement { + oneof stmt_oneof { + AssignmentStatement assignment = 1; + IfElse ifelse = 2; + Ternary ternary_stmt = 3; + BuiltinFuncs builtins = 4; + StatementSeq blockstmt = 5; + } +} + +message StatementSeq { + repeated Statement statements = 1; +} + +message Function { + required StatementSeq statements = 1; +} + +package ruby_fuzzer; -- cgit v1.2.3 From a14ae801022291bfa7ffcc15d1acbc0fea3407a6 Mon Sep 17 00:00:00 2001 From: dearblue Date: Fri, 17 May 2019 22:04:25 +0900 Subject: (Proof of Concept) mruby tuning profiles [ci skip] Not only mruby, it is one of the difficult things to adjust the performance vs. memory efficiency of the software. If the approximate target device is divided and the adjustment value for it is prepared by default, it is a good indicator to do fine adjustment. This PR divides into four profiles. ***Caution: There is no basis for the definitions in the patch.*** - `MRB_CONSTRAINED_BASELINE_PROFILE` - for microprocessors. Reduce memory consumption. - `MRB_BASELINE_PROFILE` - Default value of mruby. - `MRB_MAIN_PROFILE` - For desktop computers. Assume that a huge amount of RAM, 10 MiB or more, is on board. - `MRB_HIGH_PROFILE` - for servers. Assume that mruby VM has a long life. As you can see the profile name has been ~~stolen~~ imitated from H.264. --- include/mrbconf.h | 66 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 66 insertions(+) diff --git a/include/mrbconf.h b/include/mrbconf.h index ee816e322..f5e8858ce 100644 --- a/include/mrbconf.h +++ b/include/mrbconf.h @@ -159,4 +159,70 @@ # define TRUE 1 #endif +/* +** mruby tuning profiles +**/ + +/* A profile for micro controllers */ +#if defined(MRB_CONSTRAINED_BASELINE_PROFILE) +# ifndef KHASH_DEFAULT_SIZE +# define KHASH_DEFAULT_SIZE 16 +# endif + +# ifndef MRB_STR_BUF_MIN_SIZE +# define MRB_STR_BUF_MIN_SIZE 32 +# endif + +# ifndef MRB_HEAP_PAGE_SIZE +# define MRB_HEAP_PAGE_SIZE 256 +# endif + +/* A profile for default mruby */ +#elif defined(MRB_BASELINE_PROFILE) + +/* A profile for desktop computers or workstations; rich memory! */ +#elif defined(MRB_MAIN_PROFILE) +# ifndef MRB_METHOD_CACHE +# define MRB_METHOD_CACHE +# endif + +# ifndef MRB_METHOD_CACHE_SIZE +# define MRB_METHOD_CACHE_SIZE (1<<10) +# endif + +# ifndef MRB_METHOD_TABLE_INLINE +# define MRB_METHOD_TABLE_INLINE +# endif + +# ifndef MRB_IV_SEGMENT_SIZE +# define MRB_IV_SEGMENT_SIZE 32 +# endif + +# ifndef MRB_HEAP_PAGE_SIZE +# define MRB_HEAP_PAGE_SIZE 4096 +# endif + +/* A profile for server; mruby vm is long life */ +#elif defined(MRB_HIGH_PROFILE) +# ifndef MRB_METHOD_CACHE +# define MRB_METHOD_CACHE +# endif + +# ifndef MRB_METHOD_CACHE_SIZE +# define MRB_METHOD_CACHE_SIZE (1<<12) +# endif + +# ifndef MRB_METHOD_TABLE_INLINE +# define MRB_METHOD_TABLE_INLINE +# endif + +# ifndef MRB_IV_SEGMENT_SIZE +# define MRB_IV_SEGMENT_SIZE 64 +# endif + +# ifndef MRB_HEAP_PAGE_SIZE +# define MRB_HEAP_PAGE_SIZE 4096 +# endif +#endif + #endif /* MRUBYCONF_H */ -- cgit v1.2.3 From 8d37a3575b9d6e7648967c675395bd176b360b77 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Fri, 17 May 2019 22:37:45 +0900 Subject: Revert "Add support for CC="gcc --option ..." again" This reverts commit d5c8868346b49e2b2228cb8733398d88f744985b. --- lib/mruby/build/command.rb | 3 --- 1 file changed, 3 deletions(-) diff --git a/lib/mruby/build/command.rb b/lib/mruby/build/command.rb index 0fa4746da..0f18e0e62 100644 --- a/lib/mruby/build/command.rb +++ b/lib/mruby/build/command.rb @@ -30,13 +30,10 @@ module MRuby def _run(options, params={}) return sh command + ' ' + ( options % params ) if NotFoundCommands.key? @command begin - fiber, $rake_root_fiber = $rake_root_fiber, nil sh build.filename(command) + ' ' + ( options % params ) rescue RuntimeError NotFoundCommands[@command] = true _run options, params - ensure - $rake_root_fiber = fiber end end end -- cgit v1.2.3 From b7bc03aa18f3cc5eac0bbd6690e24062df9fe837 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Fri, 17 May 2019 22:38:07 +0900 Subject: Stop wrapping the filename by double quotes; ref #4440 --- lib/mruby/build.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/mruby/build.rb b/lib/mruby/build.rb index 016b32b3e..887a5518e 100644 --- a/lib/mruby/build.rb +++ b/lib/mruby/build.rb @@ -255,7 +255,7 @@ EOS if name.is_a?(Array) name.flatten.map { |n| filename(n) } else - '"%s"' % name.gsub('/', file_separator) + name.gsub('/', file_separator) end end @@ -263,7 +263,7 @@ EOS if name.is_a?(Array) name.flatten.map { |n| cygwin_filename(n) } else - '"%s"' % `cygpath -w "#{filename(name)}"`.strip + `cygpath -w "#{filename(name)}"`.strip end end -- cgit v1.2.3 From ace0d3949b62b3541a5ab210706f939890890cc0 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Sat, 18 May 2019 08:38:45 +0900 Subject: Support `MRB_WITHOUT_FLOAT`. I assume there's no realistic usage of `Rational` with `MRB_WITHOUT_FLOAT`. But just for consistency. --- mrbgems/mruby-rational/src/rational.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/mrbgems/mruby-rational/src/rational.c b/mrbgems/mruby-rational/src/rational.c index 14a9b045d..03f373490 100644 --- a/mrbgems/mruby-rational/src/rational.c +++ b/mrbgems/mruby-rational/src/rational.c @@ -36,6 +36,7 @@ rational_initialize(mrb_state *mrb, mrb_value self) return self; } +#ifndef MRB_WITHOUT_FLOAT static mrb_value rational_to_f(mrb_state *mrb, mrb_value self) { @@ -44,6 +45,7 @@ rational_to_f(mrb_state *mrb, mrb_value self) return mrb_float_value(mrb, f); } +#endif static mrb_value rational_to_i(mrb_state *mrb, mrb_value self) @@ -78,7 +80,9 @@ void mrb_mruby_rational_gem_init(mrb_state *mrb) mrb_define_method(mrb, rat, "numerator", rational_numerator, MRB_ARGS_NONE()); mrb_define_method(mrb, rat, "denominator", rational_denominator, MRB_ARGS_NONE()); mrb_define_method(mrb, rat, "initialize", rational_initialize, MRB_ARGS_REQ(2)); +#ifndef MRB_WITHOUT_FLOAT mrb_define_method(mrb, rat, "to_f", rational_to_f, MRB_ARGS_NONE()); +#endif mrb_define_method(mrb, rat, "to_i", rational_to_i, MRB_ARGS_NONE()); mrb_define_method(mrb, rat, "to_r", rational_to_r, MRB_ARGS_NONE()); mrb_define_method(mrb, rat, "negative?", rational_negative_p, MRB_ARGS_NONE()); -- cgit v1.2.3 From e41f15747eea34ea45e0258f0755145fcd10293b Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Sat, 18 May 2019 11:10:20 +0900 Subject: Rename `struct RIstruct` to `struct RIStruct`. --- include/mruby/istruct.h | 4 ++-- src/gc.c | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/include/mruby/istruct.h b/include/mruby/istruct.h index 4d2393ccd..23c9bfa36 100644 --- a/include/mruby/istruct.h +++ b/include/mruby/istruct.h @@ -19,12 +19,12 @@ MRB_BEGIN_DECL #define ISTRUCT_DATA_SIZE (sizeof(void*) * 3) -struct RIstruct { +struct RIStruct { MRB_OBJECT_HEADER; char inline_data[ISTRUCT_DATA_SIZE]; }; -#define RISTRUCT(obj) ((struct RIstruct*)(mrb_ptr(obj))) +#define RISTRUCT(obj) ((struct RIStruct*)(mrb_ptr(obj))) #define ISTRUCT_PTR(obj) (RISTRUCT(obj)->inline_data) MRB_INLINE mrb_int mrb_istruct_size() diff --git a/src/gc.c b/src/gc.c index 5e7440d50..6dc8e373b 100644 --- a/src/gc.c +++ b/src/gc.c @@ -110,7 +110,7 @@ typedef struct { struct RHash hash; struct RRange range; struct RData data; - struct RIstruct istruct; + struct RIStruct istruct; struct RProc proc; struct REnv env; struct RFiber fiber; -- cgit v1.2.3 From bd7328f5e606a59db25c6c17534f7db6c21fc13c Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Sat, 18 May 2019 11:23:59 +0900 Subject: Implement `Rational._new` in C. --- mrbgems/mruby-rational/mrblib/rational.rb | 5 ----- mrbgems/mruby-rational/src/rational.c | 31 ++++++++++++++++++++++++++----- 2 files changed, 26 insertions(+), 10 deletions(-) diff --git a/mrbgems/mruby-rational/mrblib/rational.rb b/mrbgems/mruby-rational/mrblib/rational.rb index 37e9d8c0f..870c12242 100644 --- a/mrbgems/mruby-rational/mrblib/rational.rb +++ b/mrbgems/mruby-rational/mrblib/rational.rb @@ -75,11 +75,6 @@ class Numeric end end -class << Rational - alias_method :_new, :new - undef_method :new -end - def Rational(numerator = 0, denominator = 1) a = numerator b = denominator diff --git a/mrbgems/mruby-rational/src/rational.c b/mrbgems/mruby-rational/src/rational.c index 03f373490..549715e7d 100644 --- a/mrbgems/mruby-rational/src/rational.c +++ b/mrbgems/mruby-rational/src/rational.c @@ -29,11 +29,24 @@ rational_denominator(mrb_state *mrb, mrb_value self) } static mrb_value -rational_initialize(mrb_state *mrb, mrb_value self) +rational_new(mrb_state *mrb, mrb_int numerator, mrb_int denominator) { - struct mrb_rational *p = rational_ptr(self); - mrb_get_args(mrb, "ii", &p->numerator, &p->denominator); - return self; + struct RClass *c = mrb_class_get(mrb, "Rational"); + struct RIStruct *s = (struct RIStruct*)mrb_obj_alloc(mrb, MRB_TT_ISTRUCT, c); + mrb_value rat = mrb_obj_value(s); + struct mrb_rational *p = rational_ptr(rat); + p->numerator = numerator; + p->denominator = denominator; + return mrb_obj_value(s); +} + +static mrb_value +rational_s_new(mrb_state *mrb, mrb_value self) +{ + mrb_int numerator, denominator; + + mrb_get_args(mrb, "ii", &numerator, &denominator); + return rational_new(mrb, numerator, denominator); } #ifndef MRB_WITHOUT_FLOAT @@ -70,6 +83,12 @@ rational_negative_p(mrb_state *mrb, mrb_value self) return mrb_false_value(); } +static mrb_value +fix_to_r(mrb_state *mrb, mrb_value self) +{ + return rational_new(mrb, mrb_fixnum(self), 1); +} + void mrb_mruby_rational_gem_init(mrb_state *mrb) { struct RClass *rat; @@ -77,15 +96,17 @@ void mrb_mruby_rational_gem_init(mrb_state *mrb) mrb_assert(sizeof(struct mrb_rational) < ISTRUCT_DATA_SIZE); rat = mrb_define_class(mrb, "Rational", mrb_class_get(mrb, "Numeric")); MRB_SET_INSTANCE_TT(rat, MRB_TT_ISTRUCT); + 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()); - mrb_define_method(mrb, rat, "initialize", rational_initialize, MRB_ARGS_REQ(2)); #ifndef MRB_WITHOUT_FLOAT mrb_define_method(mrb, rat, "to_f", rational_to_f, MRB_ARGS_NONE()); #endif mrb_define_method(mrb, rat, "to_i", rational_to_i, MRB_ARGS_NONE()); mrb_define_method(mrb, rat, "to_r", rational_to_r, MRB_ARGS_NONE()); mrb_define_method(mrb, rat, "negative?", rational_negative_p, MRB_ARGS_NONE()); + mrb_define_method(mrb, mrb->fixnum_class, "to_r", fix_to_r, MRB_ARGS_NONE()); } void -- cgit v1.2.3 From 89d29264158946a62af8874b4f04e553b0528630 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Sat, 18 May 2019 11:48:59 +0900 Subject: Add ISO section number to `Module#===`. --- src/class.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/class.c b/src/class.c index 9d26851b9..4cc60ab67 100644 --- a/src/class.c +++ b/src/class.c @@ -2191,7 +2191,7 @@ mrb_init_class(mrb_state *mrb) mrb_define_method(mrb, mod, "const_missing", mrb_mod_const_missing, MRB_ARGS_REQ(1)); mrb_define_method(mrb, mod, "method_defined?", mrb_mod_method_defined, MRB_ARGS_REQ(1)); /* 15.2.2.4.34 */ mrb_define_method(mrb, mod, "define_method", mod_define_method, MRB_ARGS_ARG(1,1)); - mrb_define_method(mrb, mod, "===", mrb_mod_eqq, MRB_ARGS_REQ(1)); + mrb_define_method(mrb, mod, "===", mrb_mod_eqq, MRB_ARGS_REQ(1)); /* 15.2.2.4.7 */ mrb_undef_method(mrb, cls, "append_features"); mrb_undef_method(mrb, cls, "extend_object"); -- cgit v1.2.3 From 4f71e9eebe2a4dc17092768aeabf75af0bbae1ce Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Sat, 18 May 2019 18:22:56 +0900 Subject: Move `Numeric#__coerce_step_counter` to `Integral` This method is only used in `Integral#step` --- src/numeric.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/numeric.c b/src/numeric.c index 6622a46e9..e73bdaca2 100644 --- a/src/numeric.c +++ b/src/numeric.c @@ -170,7 +170,7 @@ num_div(mrb_state *mrb, mrb_value x) } static mrb_value -num_coerce_step_counter(mrb_state *mrb, mrb_value self) +integral_coerce_step_counter(mrb_state *mrb, mrb_value self) { mrb_value counter = self, num, step; @@ -1551,6 +1551,7 @@ mrb_init_numeric(mrb_state *mrb) #endif integral = mrb_define_module(mrb, "Integral"); + mrb_define_method(mrb, integral, "__coerce_step_counter", integral_coerce_step_counter, MRB_ARGS_REQ(2)); /* Numeric Class */ numeric = mrb_define_class(mrb, "Numeric", mrb->object_class); /* 15.2.7 */ @@ -1566,7 +1567,6 @@ mrb_init_numeric(mrb_state *mrb) mrb_define_method(mrb, numeric, ">=", num_ge, MRB_ARGS_REQ(1)); mrb_define_method(mrb, numeric, "finite?", num_finite_p, MRB_ARGS_NONE()); mrb_define_method(mrb, numeric, "infinite?",num_infinite_p, MRB_ARGS_NONE()); - mrb_define_method(mrb, numeric, "__coerce_step_counter", num_coerce_step_counter, MRB_ARGS_REQ(2)); /* Integer Class */ integer = mrb_define_class(mrb, "Integer", numeric); /* 15.2.8 */ -- cgit v1.2.3 From 6c9c189e4b9b5a340e220b333bc5f975fdb65adc Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Sat, 18 May 2019 18:31:55 +0900 Subject: Move `Object#(Rational|Complex)` to `Kernel` --- mrbgems/mruby-complex/mrblib/complex.rb | 10 ++++++---- mrbgems/mruby-rational/mrblib/rational.rb | 12 +++++++----- 2 files changed, 13 insertions(+), 9 deletions(-) diff --git a/mrbgems/mruby-complex/mrblib/complex.rb b/mrbgems/mruby-complex/mrblib/complex.rb index 266c00c36..8ae743e77 100644 --- a/mrbgems/mruby-complex/mrblib/complex.rb +++ b/mrbgems/mruby-complex/mrblib/complex.rb @@ -107,7 +107,7 @@ class Complex < Numeric def polar [abs, arg] end - + def real? false end @@ -147,8 +147,10 @@ class << Complex alias_method :rect, :rectangular end -def Complex(real, imaginary = 0) - Complex.rectangular(real, imaginary) +module Kernel + def Complex(real, imaginary = 0) + Complex.rectangular(real, imaginary) + end end [Fixnum, Float].each do |cls| @@ -165,4 +167,4 @@ end end end end -end \ No newline at end of file +end diff --git a/mrbgems/mruby-rational/mrblib/rational.rb b/mrbgems/mruby-rational/mrblib/rational.rb index 870c12242..19c6da9e7 100644 --- a/mrbgems/mruby-rational/mrblib/rational.rb +++ b/mrbgems/mruby-rational/mrblib/rational.rb @@ -75,11 +75,13 @@ class Numeric end end -def Rational(numerator = 0, denominator = 1) - a = numerator - b = denominator - a, b = b, a % b until b == 0 - Rational._new(numerator.div(a), denominator.div(a)) +module Kernel + def Rational(numerator = 0, denominator = 1) + a = numerator + b = denominator + a, b = b, a % b until b == 0 + Rational._new(numerator.div(a), denominator.div(a)) + end end [:+, :-, :*, :/, :<=>, :==, :<, :<=, :>, :>=].each do |op| -- cgit v1.2.3 From ef5dd5d31d76d575350f06a823a23b94cb14524a Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Sat, 18 May 2019 19:19:52 +0900 Subject: Move `Kernel#instance_exec` to `BasicObject` --- mrbgems/mruby-object-ext/src/object.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mrbgems/mruby-object-ext/src/object.c b/mrbgems/mruby-object-ext/src/object.c index b076b3ec0..ac26cdc94 100644 --- a/mrbgems/mruby-object-ext/src/object.c +++ b/mrbgems/mruby-object-ext/src/object.c @@ -103,7 +103,7 @@ mrb_mruby_object_ext_gem_init(mrb_state* mrb) #endif mrb_define_method(mrb, n, "to_i", nil_to_i, MRB_ARGS_NONE()); - mrb_define_method(mrb, mrb->kernel_module, "instance_exec", mrb_obj_instance_exec, MRB_ARGS_ANY() | MRB_ARGS_BLOCK()); + mrb_define_method(mrb, mrb_class_get(mrb, "BasicObject"), "instance_exec", mrb_obj_instance_exec, MRB_ARGS_ANY() | MRB_ARGS_BLOCK()); } void -- cgit v1.2.3 From 6fb5979d29217386425044b8170acb7a9363ce0c Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Sat, 18 May 2019 20:57:54 +0900 Subject: Move `Kernel#equal? to `BasicObject` --- src/class.c | 1 + src/kernel.c | 1 - 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/src/class.c b/src/class.c index 4cc60ab67..6ceaa0cfa 100644 --- a/src/class.c +++ b/src/class.c @@ -2154,6 +2154,7 @@ mrb_init_class(mrb_state *mrb) mrb_define_method(mrb, bob, "!=", mrb_obj_not_equal_m, MRB_ARGS_REQ(1)); mrb_define_method(mrb, bob, "__id__", mrb_obj_id_m, MRB_ARGS_NONE()); /* 15.3.1.3.4 */ mrb_define_method(mrb, bob, "__send__", mrb_f_send, MRB_ARGS_ANY()); /* 15.3.1.3.5 */ + mrb_define_method(mrb, bob, "equal?", mrb_obj_equal_m, MRB_ARGS_REQ(1)); /* 15.3.1.3.11 */ mrb_define_method(mrb, bob, "instance_eval", mrb_obj_instance_eval, MRB_ARGS_ANY()); /* 15.3.1.3.18 */ mrb_define_class_method(mrb, cls, "new", mrb_class_new_class, MRB_ARGS_OPT(1)); diff --git a/src/kernel.c b/src/kernel.c index 45bca7558..349e71cb8 100644 --- a/src/kernel.c +++ b/src/kernel.c @@ -780,7 +780,6 @@ mrb_init_kernel(mrb_state *mrb) mrb_define_method(mrb, krn, "clone", mrb_obj_clone, MRB_ARGS_NONE()); /* 15.3.1.3.8 */ mrb_define_method(mrb, krn, "dup", mrb_obj_dup, MRB_ARGS_NONE()); /* 15.3.1.3.9 */ mrb_define_method(mrb, krn, "eql?", mrb_obj_equal_m, MRB_ARGS_REQ(1)); /* 15.3.1.3.10 */ - mrb_define_method(mrb, krn, "equal?", mrb_obj_equal_m, MRB_ARGS_REQ(1)); /* 15.3.1.3.11 */ mrb_define_method(mrb, krn, "extend", mrb_obj_extend_m, MRB_ARGS_ANY()); /* 15.3.1.3.13 */ mrb_define_method(mrb, krn, "freeze", mrb_obj_freeze, MRB_ARGS_NONE()); mrb_define_method(mrb, krn, "frozen?", mrb_obj_frozen, MRB_ARGS_NONE()); -- cgit v1.2.3 From 9c79c28604fe0e6cd66ba11d1e5d8d7d29ead6c2 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Sat, 18 May 2019 21:17:47 +0900 Subject: Move `Kernel#instance_eval` to `BasicObject` --- mrbgems/mruby-eval/src/eval.c | 2 +- mrbgems/mruby-eval/test/eval.rb | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/mrbgems/mruby-eval/src/eval.c b/mrbgems/mruby-eval/src/eval.c index fa687d624..a3b211ba2 100644 --- a/mrbgems/mruby-eval/src/eval.c +++ b/mrbgems/mruby-eval/src/eval.c @@ -387,7 +387,7 @@ void 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(mrb, mrb->kernel_module, "instance_eval", f_instance_eval, MRB_ARGS_ARG(1, 2)); + mrb_define_method(mrb, mrb_class_get(mrb, "BasicObject"), "instance_eval", f_instance_eval, MRB_ARGS_ARG(1, 2)); } void diff --git a/mrbgems/mruby-eval/test/eval.rb b/mrbgems/mruby-eval/test/eval.rb index 4d7dd4606..4930259c1 100644 --- a/mrbgems/mruby-eval/test/eval.rb +++ b/mrbgems/mruby-eval/test/eval.rb @@ -80,7 +80,7 @@ assert('Kernel.#eval(string) context') do assert_equal('class') { obj.const_string } end -assert('Object#instance_eval with begin-rescue-ensure execution order') do +assert('BasicObject#instance_eval with begin-rescue-ensure execution order') do class HellRaiser def raise_hell order = [:enter_raise_hell] @@ -100,7 +100,7 @@ assert('Object#instance_eval with begin-rescue-ensure execution order') do assert_equal([:enter_raise_hell, :begin, :rescue, :ensure], hell_raiser.raise_hell) end -assert('Kernel#instance_eval() to define singleton methods Issue #3141') do +assert('BasicObject#instance_eval to define singleton methods Issue #3141') do foo_class = Class.new do def bar(x) instance_eval "def baz; #{x}; end" -- cgit v1.2.3 From 67fc3428cb6c0fae2c08c5de36adc7bd0990c4c0 Mon Sep 17 00:00:00 2001 From: dearblue Date: Mon, 6 May 2019 16:28:27 +0900 Subject: Remove "LINE" section reader Because it is not currently output by `mrbc`. --- include/mruby/dump.h | 5 ---- src/load.c | 67 ---------------------------------------------------- 2 files changed, 72 deletions(-) diff --git a/include/mruby/dump.h b/include/mruby/dump.h index 0234a362b..4c7d08253 100644 --- a/include/mruby/dump.h +++ b/include/mruby/dump.h @@ -60,7 +60,6 @@ MRB_API mrb_irep *mrb_read_irep(mrb_state*, const uint8_t*); #define RITE_BINARY_EOF "END\0" #define RITE_SECTION_IREP_IDENT "IREP" -#define RITE_SECTION_LINENO_IDENT "LINE" #define RITE_SECTION_DEBUG_IDENT "DBG\0" #define RITE_SECTION_LV_IDENT "LVAR" @@ -92,10 +91,6 @@ struct rite_section_irep_header { uint8_t rite_version[4]; /* Rite Instruction Specification Version */ }; -struct rite_section_lineno_header { - RITE_SECTION_HEADER; -}; - struct rite_section_debug_header { RITE_SECTION_HEADER; }; diff --git a/src/load.c b/src/load.c index 70f18da31..9af752a15 100644 --- a/src/load.c +++ b/src/load.c @@ -233,66 +233,6 @@ read_section_irep(mrb_state *mrb, const uint8_t *bin, uint8_t flags) return read_irep_record(mrb, bin, &len, flags); } -/* ignore lineno record */ -static int -read_lineno_record_1(mrb_state *mrb, const uint8_t *bin, mrb_irep *irep, size_t *len) -{ - size_t i, fname_len, niseq; - - *len = 0; - bin += sizeof(uint32_t); /* record size */ - *len += sizeof(uint32_t); - fname_len = bin_to_uint16(bin); - bin += sizeof(uint16_t); - *len += sizeof(uint16_t); - bin += fname_len; - *len += fname_len; - - niseq = (size_t)bin_to_uint32(bin); - bin += sizeof(uint32_t); /* niseq */ - *len += sizeof(uint32_t); - - if (SIZE_ERROR_MUL(niseq, sizeof(uint16_t))) { - return MRB_DUMP_GENERAL_FAILURE; - } - for (i = 0; i < niseq; i++) { - bin += sizeof(uint16_t); /* niseq */ - *len += sizeof(uint16_t); - } - - return MRB_DUMP_OK; -} - -static int -read_lineno_record(mrb_state *mrb, const uint8_t *bin, mrb_irep *irep, size_t *lenp) -{ - int result = read_lineno_record_1(mrb, bin, irep, lenp); - int i; - - if (result != MRB_DUMP_OK) return result; - for (i = 0; i < irep->rlen; i++) { - size_t len; - - result = read_lineno_record(mrb, bin, irep->reps[i], &len); - if (result != MRB_DUMP_OK) break; - bin += len; - *lenp += len; - } - return result; -} - -static int -read_section_lineno(mrb_state *mrb, const uint8_t *bin, mrb_irep *irep) -{ - size_t len; - - len = 0; - bin += sizeof(struct rite_section_lineno_header); - - /* Read Binary Data Section */ - return read_lineno_record(mrb, bin, irep, &len); -} - static int read_debug_record(mrb_state *mrb, const uint8_t *start, mrb_irep* irep, size_t *record_len, const mrb_sym *filenames, size_t filenames_len) { @@ -578,13 +518,6 @@ read_irep(mrb_state *mrb, const uint8_t *bin, uint8_t flags) irep = read_section_irep(mrb, bin, flags); if (!irep) return NULL; } - else if (memcmp(section_header->section_ident, RITE_SECTION_LINENO_IDENT, sizeof(section_header->section_ident)) == 0) { - if (!irep) return NULL; /* corrupted data */ - result = read_section_lineno(mrb, bin, irep); - if (result < MRB_DUMP_OK) { - return NULL; - } - } else if (memcmp(section_header->section_ident, RITE_SECTION_DEBUG_IDENT, sizeof(section_header->section_ident)) == 0) { if (!irep) return NULL; /* corrupted data */ result = read_section_debug(mrb, bin, irep, flags); -- cgit v1.2.3 From a6eb01837b5d18d0a9b6fd5e22ab7d99241a1e2a Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Sun, 19 May 2019 13:52:18 +0900 Subject: Fix `Rational#<=>(Numeric)` Reported by Sergey Ukrainskiy: https://github.com/mruby/mruby/commit/f5fb1307b017fb972c12b4ec4b1866d789b0ca09#r33590698 --- mrbgems/mruby-rational/mrblib/rational.rb | 3 +- mrbgems/mruby-rational/test/rational.rb | 168 +++++++++++++++++++++++++++++- 2 files changed, 165 insertions(+), 6 deletions(-) diff --git a/mrbgems/mruby-rational/mrblib/rational.rb b/mrbgems/mruby-rational/mrblib/rational.rb index 19c6da9e7..ad1f3ab0f 100644 --- a/mrbgems/mruby-rational/mrblib/rational.rb +++ b/mrbgems/mruby-rational/mrblib/rational.rb @@ -58,11 +58,12 @@ class Rational < Numeric when Float return to_f <=> rhs end + case rhs when Rational (numerator * rhs.denominator - denominator * rhs.numerator) <=> 0 when Numeric - return rhs <=> self + (rhs <=> self)&.-@ else nil end diff --git a/mrbgems/mruby-rational/test/rational.rb b/mrbgems/mruby-rational/test/rational.rb index a65926bfb..1ff819090 100644 --- a/mrbgems/mruby-rational/test/rational.rb +++ b/mrbgems/mruby-rational/test/rational.rb @@ -3,13 +3,21 @@ def assert_rational(real, exp) assert_float real.denominator, exp.denominator end -def assert_equal_rational(exp, r1, r2) +def assert_equal_rational(exp, o1, o2) if exp - assert_operator(r1, :==, r2) - assert_not_operator(r1, :!=, r2) + assert_operator(o1, :==, o2) + assert_not_operator(o1, :!=, o2) else - assert_not_operator(r1, :==, r2) - assert_operator(r1, :!=, r2) + assert_not_operator(o1, :==, o2) + assert_operator(o1, :!=, o2) + end +end + +def assert_cmp(exp, o1, o2) + if exp == (o1 <=> o2) + pass + else + flunk "", " Expected #{o1.inspect} <=> #{o2.inspect} to be #{exp}" end end @@ -101,6 +109,156 @@ assert 'Float#==(Rational), Float#!=(Rational)' do assert_equal_rational(false, 3.3, Rational(13,4)) end +assert 'Rational#<=>' do + num = Class.new(Numeric) do + def initialize(n) + @n = n + end + + def <=>(rhs) + rhs = rhs.to_i + rhs < 0 ? nil : @n <=> rhs + end + + def inspect + "num(#{@n})" + end + end + + assert_cmp(-1, Rational(-1), Rational(0)) + assert_cmp(0, Rational(0), Rational(0)) + assert_cmp(1, Rational(1), Rational(0)) + assert_cmp(-1, Rational(-1), 0) + assert_cmp(0, Rational(0), 0) + assert_cmp(1, Rational(1), 0) + assert_cmp(-1, Rational(-1), 0.0) + assert_cmp(0, Rational(0), 0.0) + assert_cmp(1, Rational(1), 0.0) + assert_cmp(-1, Rational(1,2), Rational(2,3)) + assert_cmp(0, Rational(2,3), Rational(2,3)) + assert_cmp(1, Rational(2,3), Rational(1,2)) + assert_cmp(1, Rational(2,3), Rational(1,2)) + assert_cmp(1, Rational(0), Rational(-1)) + assert_cmp(-1, Rational(0), Rational(1)) + assert_cmp(1, Rational(2,3), Rational(1,2)) + assert_cmp(0, Rational(2,3), Rational(2,3)) + assert_cmp(-1, Rational(1,2), Rational(2,3)) + assert_cmp(-1, Rational(1,2), Rational(2,3)) + assert_cmp(nil, 3r, "3") + assert_cmp(1, 3r, num.new(2)) + assert_cmp(0, 3r, num.new(3)) + assert_cmp(-1, 3r, num.new(4)) + assert_cmp(nil, Rational(-3), num.new(5)) +end + +assert 'Fixnum#<=>(Rational)' do + assert_cmp(-1, -2, Rational(-9,5)) + assert_cmp(0, 5, 5r) + assert_cmp(1, 3, Rational(8,3)) +end + +assert 'Float#<=>(Rational)' do + assert_cmp(-1, -2.1, Rational(-9,5)) + assert_cmp(0, 5.0, 5r) + assert_cmp(1, 2.7, Rational(8,3)) +end + +assert 'Rational#<' do + assert_operator(Rational(1,2), :<, Rational(2,3)) + assert_not_operator(Rational(2,3), :<, Rational(2,3)) + assert_operator(Rational(2,3), :<, 1) + assert_not_operator(2r, :<, 2) + assert_not_operator(Rational(2,3), :<, -3) + assert_operator(Rational(-4,3), :<, -0.3) + assert_not_operator(Rational(13,4), :<, 3.25) + assert_not_operator(Rational(2,3), :<, 0.6) + assert_raise(ArgumentError) { 1r < "2" } +end + +assert 'Fixnum#<(Rational)' do + assert_not_operator(1, :<, Rational(2,3)) + assert_not_operator(2, :<, 2r) + assert_operator(-3, :<, Rational(2,3)) +end + +assert 'Float#<(Rational)' do + assert_not_operator(-0.3, :<, Rational(-4,3)) + assert_not_operator(3.25, :<, Rational(13,4)) + assert_operator(0.6, :<, Rational(2,3)) +end + +assert 'Rational#<=' do + assert_operator(Rational(1,2), :<=, Rational(2,3)) + assert_operator(Rational(2,3), :<=, Rational(2,3)) + assert_operator(Rational(2,3), :<=, 1) + assert_operator(2r, :<=, 2) + assert_not_operator(Rational(2,3), :<=, -3) + assert_operator(Rational(-4,3), :<=, -0.3) + assert_operator(Rational(13,4), :<=, 3.25) + assert_not_operator(Rational(2,3), :<=, 0.6) + assert_raise(ArgumentError) { 1r <= "2" } +end + +assert 'Fixnum#<=(Rational)' do + assert_not_operator(1, :<=, Rational(2,3)) + assert_operator(2, :<=, 2r) + assert_operator(-3, :<=, Rational(2,3)) +end + +assert 'Float#<=(Rational)' do + assert_not_operator(-0.3, :<=, Rational(-4,3)) + assert_operator(3.25, :<=, Rational(13,4)) + assert_operator(0.6, :<=, Rational(2,3)) +end + +assert 'Rational#>' do + assert_not_operator(Rational(1,2), :>, Rational(2,3)) + assert_not_operator(Rational(2,3), :>, Rational(2,3)) + assert_not_operator(Rational(2,3), :>, 1) + assert_not_operator(2r, :>, 2) + assert_operator(Rational(2,3), :>, -3) + assert_not_operator(Rational(-4,3), :>, -0.3) + assert_not_operator(Rational(13,4), :>, 3.25) + assert_operator(Rational(2,3), :>, 0.6) + assert_raise(ArgumentError) { 1r > "2" } +end + +assert 'Fixnum#>(Rational)' do + assert_operator(1, :>, Rational(2,3)) + assert_not_operator(2, :>, 2r) + assert_not_operator(-3, :>, Rational(2,3)) +end + +assert 'Float#>(Rational)' do + assert_operator(-0.3, :>, Rational(-4,3)) + assert_not_operator(3.25, :>, Rational(13,4)) + assert_not_operator(0.6, :>, Rational(2,3)) +end + +assert 'Rational#>=' do + assert_not_operator(Rational(1,2), :>=, Rational(2,3)) + assert_operator(Rational(2,3), :>=, Rational(2,3)) + assert_not_operator(Rational(2,3), :>=, 1) + assert_operator(2r, :>=, 2) + assert_operator(Rational(2,3), :>=, -3) + assert_not_operator(Rational(-4,3), :>=, -0.3) + assert_operator(Rational(13,4), :>=, 3.25) + assert_operator(Rational(2,3), :>=, 0.6) + assert_raise(ArgumentError) { 1r >= "2" } +end + +assert 'Fixnum#>=(Rational)' do + assert_operator(1, :>=, Rational(2,3)) + assert_operator(2, :>=, 2r) + assert_not_operator(-3, :>=, Rational(2,3)) +end + +assert 'Float#>=(Rational)' do + assert_operator(-0.3, :>=, Rational(-4,3)) + assert_operator(3.25, :>=, Rational(13,4)) + assert_not_operator(0.6, :>=, Rational(2,3)) +end + assert 'Rational#negative?' do assert_predicate(Rational(-2,3), :negative?) assert_predicate(Rational(2,-3), :negative?) -- cgit v1.2.3 From 8e637bdd83505e8c1723f87a8d267e00ee209787 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Sun, 19 May 2019 22:15:27 +0900 Subject: Should clarify the role of `mruby-kernel-ext` and `mruby-object-ext`; close #4449 The former should contain function like methods, and the latter should contain methods shared by all objects. --- mrbgems/mruby-kernel-ext/mrblib/kernel.rb | 15 --------------- mrbgems/mruby-kernel-ext/src/kernel.c | 17 ----------------- mrbgems/mruby-object-ext/mrblib/object.rb | 16 +++++++++++++++- mrbgems/mruby-object-ext/src/object.c | 17 +++++++++++++++++ 4 files changed, 32 insertions(+), 33 deletions(-) delete mode 100644 mrbgems/mruby-kernel-ext/mrblib/kernel.rb diff --git a/mrbgems/mruby-kernel-ext/mrblib/kernel.rb b/mrbgems/mruby-kernel-ext/mrblib/kernel.rb deleted file mode 100644 index bf739ed1a..000000000 --- a/mrbgems/mruby-kernel-ext/mrblib/kernel.rb +++ /dev/null @@ -1,15 +0,0 @@ -module Kernel - # call-seq: - # obj.yield_self {|_obj|...} -> an_object - # obj.then {|_obj|...} -> an_object - # - # Yields obj and returns the result. - # - # 'my string'.yield_self {|s|s.upcase} #=> "MY STRING" - # - def yield_self(&block) - return to_enum :yield_self unless block - block.call(self) - end - alias then yield_self -end diff --git a/mrbgems/mruby-kernel-ext/src/kernel.c b/mrbgems/mruby-kernel-ext/src/kernel.c index 99affbfa4..9288b0e6f 100644 --- a/mrbgems/mruby-kernel-ext/src/kernel.c +++ b/mrbgems/mruby-kernel-ext/src/kernel.c @@ -206,22 +206,6 @@ mrb_f_hash(mrb_state *mrb, mrb_value self) return mrb_ensure_hash_type(mrb, arg); } -/* - * call-seq: - * obj.itself -> an_object - * - * Returns obj. - * - * string = 'my string' #=> "my string" - * string.itself.object_id == string.object_id #=> true - * - */ -static mrb_value -mrb_f_itself(mrb_state *mrb, mrb_value self) -{ - return self; -} - void mrb_mruby_kernel_ext_gem_init(mrb_state *mrb) { @@ -237,7 +221,6 @@ mrb_mruby_kernel_ext_gem_init(mrb_state *mrb) mrb_define_module_function(mrb, krn, "String", mrb_f_string, MRB_ARGS_REQ(1)); mrb_define_module_function(mrb, krn, "Array", mrb_f_array, MRB_ARGS_REQ(1)); mrb_define_module_function(mrb, krn, "Hash", mrb_f_hash, MRB_ARGS_REQ(1)); - mrb_define_module_function(mrb, krn, "itself", mrb_f_itself, MRB_ARGS_NONE()); } void diff --git a/mrbgems/mruby-object-ext/mrblib/object.rb b/mrbgems/mruby-object-ext/mrblib/object.rb index 581156cb0..f014df469 100644 --- a/mrbgems/mruby-object-ext/mrblib/object.rb +++ b/mrbgems/mruby-object-ext/mrblib/object.rb @@ -1,4 +1,18 @@ -class Object +module Kernel + # call-seq: + # obj.yield_self {|_obj|...} -> an_object + # obj.then {|_obj|...} -> an_object + # + # Yields obj and returns the result. + # + # 'my string'.yield_self {|s|s.upcase} #=> "MY STRING" + # + def yield_self(&block) + return to_enum :yield_self unless block + block.call(self) + end + alias then yield_self + ## # call-seq: # obj.tap{|x|...} -> obj diff --git a/mrbgems/mruby-object-ext/src/object.c b/mrbgems/mruby-object-ext/src/object.c index b076b3ec0..dce97132c 100644 --- a/mrbgems/mruby-object-ext/src/object.c +++ b/mrbgems/mruby-object-ext/src/object.c @@ -44,6 +44,22 @@ nil_to_i(mrb_state *mrb, mrb_value obj) return mrb_fixnum_value(0); } +/* + * call-seq: + * obj.itself -> an_object + * + * Returns obj. + * + * string = 'my string' #=> "my string" + * string.itself.object_id == string.object_id #=> true + * + */ +static mrb_value +mrb_f_itself(mrb_state *mrb, mrb_value self) +{ + return self; +} + /* * call-seq: * obj.instance_exec(arg...) {|var...| block } -> obj @@ -102,6 +118,7 @@ mrb_mruby_object_ext_gem_init(mrb_state* mrb) mrb_define_method(mrb, n, "to_f", nil_to_f, MRB_ARGS_NONE()); #endif mrb_define_method(mrb, n, "to_i", nil_to_i, MRB_ARGS_NONE()); + mrb_define_module_function(mrb, mrb->kernel_module, "itself", mrb_f_itself, MRB_ARGS_NONE()); mrb_define_method(mrb, mrb->kernel_module, "instance_exec", mrb_obj_instance_exec, MRB_ARGS_ANY() | MRB_ARGS_BLOCK()); } -- cgit v1.2.3 From 8b8bf9f3f696f28836138b8106147d9d3e6071a2 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Mon, 20 May 2019 14:59:25 +0900 Subject: Add new functions for numerical operation; ref 237a57b New functions: * mrb_num_plus(mrb, x, y) * mrb_num_minus(mrb, x, y) * num_num_mul(mrb, x, y) --- include/mruby/numeric.h | 4 ++++ src/numeric.c | 54 +++++++++++++++++++++++++++++++++++++++++++------ 2 files changed, 52 insertions(+), 6 deletions(-) diff --git a/include/mruby/numeric.h b/include/mruby/numeric.h index 9d87ca5c4..d670504c2 100644 --- a/include/mruby/numeric.h +++ b/include/mruby/numeric.h @@ -36,6 +36,10 @@ MRB_API mrb_value mrb_float_to_str(mrb_state *mrb, mrb_value x, const char *fmt) MRB_API mrb_float mrb_to_flo(mrb_state *mrb, mrb_value x); #endif +MRB_API mrb_value mrb_num_plus(mrb_state *mrb, mrb_value x, mrb_value y); +MRB_API mrb_value mrb_num_minus(mrb_state *mrb, mrb_value x, mrb_value y); +MRB_API mrb_value mrb_num_mul(mrb_state *mrb, mrb_value x, mrb_value y); + #ifndef __has_builtin #define __has_builtin(x) 0 #endif diff --git a/src/numeric.c b/src/numeric.c index e73bdaca2..3ad5721ef 100644 --- a/src/numeric.c +++ b/src/numeric.c @@ -788,7 +788,7 @@ int_to_i(mrb_state *mrb, mrb_value num) } static mrb_value -mrb_fixnum_mul(mrb_state *mrb, mrb_value x, mrb_value y) +fixnum_mul(mrb_state *mrb, mrb_value x, mrb_value y) { mrb_int a; @@ -812,6 +812,20 @@ mrb_fixnum_mul(mrb_state *mrb, mrb_value x, mrb_value y) #endif } +MRB_API mrb_value +mrb_num_mul(mrb_state *mrb, mrb_value x, mrb_value y) +{ + if (mrb_fixnum_p(x)) { + return fixnum_mul(mrb, x, y); + } +#ifndef MRB_WITHOUT_FLOAT + if (mrb_float_p(x)) { + return mrb_float_value(mrb, mrb_float(x) * mrb_to_flo(mrb, y)); + } +#endif + mrb_raise(mrb, E_TYPE_ERROR, "no number multiply"); +} + /* 15.2.8.3.3 */ /* * call-seq: @@ -828,7 +842,7 @@ fix_mul(mrb_state *mrb, mrb_value x) mrb_value y; mrb_get_args(mrb, "o", &y); - return mrb_fixnum_mul(mrb, x, y); + return fixnum_mul(mrb, x, y); } static void @@ -1245,7 +1259,7 @@ mrb_flo_to_fixnum(mrb_state *mrb, mrb_value x) #endif static mrb_value -mrb_fixnum_plus(mrb_state *mrb, mrb_value x, mrb_value y) +fixnum_plus(mrb_state *mrb, mrb_value x, mrb_value y) { mrb_int a; @@ -1269,6 +1283,20 @@ mrb_fixnum_plus(mrb_state *mrb, mrb_value x, mrb_value y) #endif } +MRB_API mrb_value +mrb_num_plus(mrb_state *mrb, mrb_value x, mrb_value y) +{ + if (mrb_fixnum_p(x)) { + return fixnum_plus(mrb, x, y); + } +#ifndef MRB_WITHOUT_FLOAT + if (mrb_float_p(x)) { + return mrb_float_value(mrb, mrb_float(x) + mrb_to_flo(mrb, y)); + } +#endif + mrb_raise(mrb, E_TYPE_ERROR, "no number addition"); +} + /* 15.2.8.3.1 */ /* * call-seq: @@ -1284,11 +1312,11 @@ fix_plus(mrb_state *mrb, mrb_value self) mrb_value other; mrb_get_args(mrb, "o", &other); - return mrb_fixnum_plus(mrb, self, other); + return fixnum_plus(mrb, self, other); } static mrb_value -mrb_fixnum_minus(mrb_state *mrb, mrb_value x, mrb_value y) +fixnum_minus(mrb_state *mrb, mrb_value x, mrb_value y) { mrb_int a; @@ -1311,6 +1339,20 @@ mrb_fixnum_minus(mrb_state *mrb, mrb_value x, mrb_value y) #endif } +MRB_API mrb_value +mrb_num_minus(mrb_state *mrb, mrb_value x, mrb_value y) +{ + if (mrb_fixnum_p(x)) { + return fixnum_minus(mrb, x, y); + } +#ifdef MRB_WITHOUT_FLOAT + if (mrb_float_p(x)) { + return mrb_float_value(mrb, mrb_float(x) - mrb_to_flo(mrb, y)); + } +#endif + mrb_raise(mrb, E_TYPE_ERROR, "no number subtraction"); +} + /* 15.2.8.3.2 */ /* 15.2.8.3.16 */ /* @@ -1327,7 +1369,7 @@ fix_minus(mrb_state *mrb, mrb_value self) mrb_value other; mrb_get_args(mrb, "o", &other); - return mrb_fixnum_minus(mrb, self, other); + return fixnum_minus(mrb, self, other); } -- cgit v1.2.3 From 97600ded8d7717f327a3bf00e904a7ebb38dbd64 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Mon, 20 May 2019 18:24:18 +0900 Subject: Change the order of "expected" and "actual" in `mruby-rational` test --- mrbgems/mruby-rational/test/rational.rb | 68 ++++++++++++++++----------------- 1 file changed, 34 insertions(+), 34 deletions(-) diff --git a/mrbgems/mruby-rational/test/rational.rb b/mrbgems/mruby-rational/test/rational.rb index 1ff819090..5a1055ee7 100644 --- a/mrbgems/mruby-rational/test/rational.rb +++ b/mrbgems/mruby-rational/test/rational.rb @@ -1,6 +1,6 @@ -def assert_rational(real, exp) - assert_float real.numerator, exp.numerator - assert_float real.denominator, exp.denominator +def assert_rational(exp, real) + assert_float exp.numerator, real.numerator + assert_float exp.denominator, real.denominator end def assert_equal_rational(exp, o1, o2) @@ -23,55 +23,55 @@ end assert 'Rational' do r = 5r - assert_equal Rational, r.class - assert_equal [r.numerator, r.denominator], [5, 1] + assert_equal(r.class, Rational) + assert_equal([5, 1], [r.numerator, r.denominator]) end assert 'Rational#to_f' do - assert_float Rational(2).to_f, 2.0 - assert_float Rational(9, 4).to_f, 2.25 - assert_float Rational(-3, 4).to_f, -0.75 - assert_float Rational(20, 3).to_f, 6.666666666666667 + assert_float(2.0, Rational(2).to_f) + assert_float(2.25, Rational(9, 4).to_f) + assert_float(-0.75, Rational(-3, 4).to_f) + assert_float(6.666666666666667, Rational(20, 3).to_f) end assert 'Rational#to_i' do - assert_equal Rational(2, 3).to_i, 0 - assert_equal Rational(3).to_i, 3 - assert_equal Rational(300.6).to_i, 300 - assert_equal Rational(98, 71).to_i, 1 - assert_equal Rational(-30, 2).to_i, -15 + assert_equal(0, Rational(2, 3).to_i) + assert_equal(3, Rational(3).to_i) + assert_equal(300, Rational(300.6).to_i) + assert_equal(1, Rational(98, 71).to_i) + assert_equal(-15, Rational(-30, 2).to_i) end assert 'Rational#*' do - assert_rational Rational(2, 3) * Rational(2, 3), Rational(4, 9) - assert_rational Rational(900) * Rational(1), Rational(900, 1) - assert_rational Rational(-2, 9) * Rational(-9, 2), Rational(1, 1) - assert_rational Rational(9, 8) * 4, Rational(9, 2) - assert_float Rational(20, 9) * 9.8, 21.77777777777778 + assert_rational(Rational(4, 9), Rational(2, 3) * Rational(2, 3)) + assert_rational(Rational(900, 1), Rational(900) * Rational(1)) + assert_rational(Rational(1, 1), Rational(-2, 9) * Rational(-9, 2)) + assert_rational(Rational(9, 2), Rational(9, 8) * 4) + assert_float( 21.77777777777778, Rational(20, 9) * 9.8) end assert 'Rational#+' do - assert_rational Rational(2, 3) + Rational(2, 3), Rational(4, 3) - assert_rational Rational(900) + Rational(1), Rational(901, 1) - assert_rational Rational(-2, 9) + Rational(-9, 2), Rational(-85, 18) - assert_rational Rational(9, 8) + 4, Rational(41, 8) - assert_float Rational(20, 9) + 9.8, 12.022222222222222 + assert_rational(Rational(4, 3), Rational(2, 3) + Rational(2, 3)) + assert_rational(Rational(901, 1), Rational(900) + Rational(1)) + assert_rational(Rational(-85, 18), Rational(-2, 9) + Rational(-9, 2)) + assert_rational(Rational(41, 8), Rational(9, 8) + 4) + assert_float( 12.022222222222222, Rational(20, 9) + 9.8) end assert 'Rational#-' do - assert_rational Rational(2, 3) - Rational(2, 3), Rational(0, 1) - assert_rational Rational(900) - Rational(1), Rational(899, 1) - assert_rational Rational(-2, 9) - Rational(-9, 2), Rational(77, 18) - assert_rational Rational(9, 8) - 4, Rational(-23, 8) - assert_float Rational(20, 9) - 9.8, -7.577777777777778 + assert_rational(Rational(0, 1), Rational(2, 3) - Rational(2, 3)) + assert_rational(Rational(899, 1), Rational(900) - Rational(1)) + assert_rational(Rational(77, 18), Rational(-2, 9) - Rational(-9, 2)) + assert_rational(Rational(-23, 8), Rational(9, 8) - 4) + assert_float( -7.577777777777778, Rational(20, 9) - 9.8) end assert 'Rational#/' do - assert_rational Rational(2, 3) / Rational(2, 3), Rational(1, 1) - assert_rational Rational(900) / Rational(1), Rational(900, 1) - assert_rational Rational(-2, 9) / Rational(-9, 2), Rational(4, 81) - assert_rational Rational(9, 8) / 4, Rational(9, 32) - assert_float Rational(20, 9) / 9.8, 0.22675736961451246 + assert_rational(Rational(1, 1), Rational(2, 3) / Rational(2, 3)) + assert_rational(Rational(900, 1), Rational(900) / Rational(1)) + assert_rational(Rational(4, 81), Rational(-2, 9) / Rational(-9, 2)) + assert_rational(Rational(9, 32), Rational(9, 8) / 4) + assert_float( 0.22675736961451246, Rational(20, 9) / 9.8) end assert 'Rational#==, Rational#!=' do -- cgit v1.2.3 From 3db5d7fe3d91c17719ab69a2161d1a0581e5ed2c Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Mon, 20 May 2019 18:36:13 +0900 Subject: Drop dependency from `mruby-rational` to `mruby-object-ext` --- mrbgems/mruby-rational/mrbgem.rake | 2 -- mrbgems/mruby-rational/mrblib/rational.rb | 4 ++-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/mrbgems/mruby-rational/mrbgem.rake b/mrbgems/mruby-rational/mrbgem.rake index 15c3429f2..4b540dec4 100644 --- a/mrbgems/mruby-rational/mrbgem.rake +++ b/mrbgems/mruby-rational/mrbgem.rake @@ -2,6 +2,4 @@ MRuby::Gem::Specification.new('mruby-rational') do |spec| spec.license = 'MIT' spec.author = 'mruby developers' spec.summary = 'Rational class' - - spec.add_dependency 'mruby-object-ext', core: 'mruby-object-ext' end diff --git a/mrbgems/mruby-rational/mrblib/rational.rb b/mrbgems/mruby-rational/mrblib/rational.rb index ad1f3ab0f..28c96c69f 100644 --- a/mrbgems/mruby-rational/mrblib/rational.rb +++ b/mrbgems/mruby-rational/mrblib/rational.rb @@ -86,7 +86,7 @@ module Kernel end [:+, :-, :*, :/, :<=>, :==, :<, :<=, :>, :>=].each do |op| - Fixnum.instance_exec do + Fixnum.instance_eval do original_operator_name = "__original_operator_#{op}_rational" alias_method original_operator_name, op define_method op do |rhs| @@ -97,7 +97,7 @@ end end end end - Float.instance_exec do + Float.instance_eval do original_operator_name = "__original_operator_#{op}_rational" alias_method original_operator_name, op define_method op do |rhs| -- cgit v1.2.3 From 5d6c1794ad8620279514f45770ab4e8eeb16c734 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Tue, 21 May 2019 09:31:06 +0900 Subject: Revert part of #4457 --- mrbgems/mruby-rational/test/rational.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mrbgems/mruby-rational/test/rational.rb b/mrbgems/mruby-rational/test/rational.rb index 5a1055ee7..ea55880fe 100644 --- a/mrbgems/mruby-rational/test/rational.rb +++ b/mrbgems/mruby-rational/test/rational.rb @@ -23,7 +23,7 @@ end assert 'Rational' do r = 5r - assert_equal(r.class, Rational) + assert_equal(Rational, r.class) assert_equal([5, 1], [r.numerator, r.denominator]) end -- cgit v1.2.3 From 3b46831da83b4d5d5355c60261fb3ebe2a885513 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Tue, 21 May 2019 20:26:53 +0900 Subject: Move `**`,`/`,`quo`,`div` and comparison methods to Integral from Numeric Having these methods in Numeric can get in the way of creating subclasses of Numeric because they only support Fixnum and Float. --- mrbgems/mruby-rational/mrblib/rational.rb | 3 --- src/numeric.c | 37 +++++++++++++++---------------- 2 files changed, 18 insertions(+), 22 deletions(-) diff --git a/mrbgems/mruby-rational/mrblib/rational.rb b/mrbgems/mruby-rational/mrblib/rational.rb index 28c96c69f..cecede48a 100644 --- a/mrbgems/mruby-rational/mrblib/rational.rb +++ b/mrbgems/mruby-rational/mrblib/rational.rb @@ -1,7 +1,4 @@ class Rational < Numeric - # Override #<, #<=, #>, #>= in Numeric - prepend Comparable - def inspect "(#{to_s})" end diff --git a/src/numeric.c b/src/numeric.c index 3ad5721ef..c740a32e3 100644 --- a/src/numeric.c +++ b/src/numeric.c @@ -65,7 +65,7 @@ mrb_int_value(mrb_state *mrb, mrb_float f) * 2.0**3 #=> 8.0 */ static mrb_value -num_pow(mrb_state *mrb, mrb_value x) +integral_pow(mrb_state *mrb, mrb_value x) { mrb_value y; #ifndef MRB_WITHOUT_FLOAT @@ -113,7 +113,7 @@ num_pow(mrb_state *mrb, mrb_value x) } static mrb_value -num_idiv(mrb_state *mrb, mrb_value x) +integral_idiv(mrb_state *mrb, mrb_value x) { #ifdef MRB_WITHOUT_FLOAT mrb_value y; @@ -151,7 +151,7 @@ num_idiv(mrb_state *mrb, mrb_value x) */ static mrb_value -num_div(mrb_state *mrb, mrb_value x) +integral_div(mrb_state *mrb, mrb_value x) { #ifdef MRB_WITHOUT_FLOAT mrb_value y; @@ -1479,7 +1479,7 @@ cmpnum(mrb_state *mrb, mrb_value v1, mrb_value v2) * basis for the tests in Comparable. */ static mrb_value -num_cmp(mrb_state *mrb, mrb_value self) +integral_cmp(mrb_state *mrb, mrb_value self) { mrb_value other; mrb_int n; @@ -1499,7 +1499,7 @@ cmperr(mrb_state *mrb, mrb_value v1, mrb_value v2) } static mrb_value -num_lt(mrb_state *mrb, mrb_value self) +integral_lt(mrb_state *mrb, mrb_value self) { mrb_value other; mrb_int n; @@ -1512,7 +1512,7 @@ num_lt(mrb_state *mrb, mrb_value self) } static mrb_value -num_le(mrb_state *mrb, mrb_value self) +integral_le(mrb_state *mrb, mrb_value self) { mrb_value other; mrb_int n; @@ -1525,7 +1525,7 @@ num_le(mrb_state *mrb, mrb_value self) } static mrb_value -num_gt(mrb_state *mrb, mrb_value self) +integral_gt(mrb_state *mrb, mrb_value self) { mrb_value other; mrb_int n; @@ -1538,7 +1538,7 @@ num_gt(mrb_state *mrb, mrb_value self) } static mrb_value -num_ge(mrb_state *mrb, mrb_value self) +integral_ge(mrb_state *mrb, mrb_value self) { mrb_value other; mrb_int n; @@ -1593,20 +1593,19 @@ mrb_init_numeric(mrb_state *mrb) #endif integral = mrb_define_module(mrb, "Integral"); - mrb_define_method(mrb, integral, "__coerce_step_counter", integral_coerce_step_counter, MRB_ARGS_REQ(2)); + mrb_define_method(mrb, integral,"**", integral_pow, MRB_ARGS_REQ(1)); + mrb_define_method(mrb, integral,"/", integral_div, MRB_ARGS_REQ(1)); /* 15.2.8.3.4 */ + mrb_define_method(mrb, integral,"quo", integral_div, MRB_ARGS_REQ(1)); /* 15.2.7.4.5 (x) */ + mrb_define_method(mrb, integral,"div", integral_idiv, MRB_ARGS_REQ(1)); + mrb_define_method(mrb, integral,"<=>", integral_cmp, MRB_ARGS_REQ(1)); /* 15.2.9.3.6 */ + mrb_define_method(mrb, integral,"<", integral_lt, MRB_ARGS_REQ(1)); + mrb_define_method(mrb, integral,"<=", integral_le, MRB_ARGS_REQ(1)); + mrb_define_method(mrb, integral,">", integral_gt, MRB_ARGS_REQ(1)); + mrb_define_method(mrb, integral,">=", integral_ge, MRB_ARGS_REQ(1)); + mrb_define_method(mrb, integral,"__coerce_step_counter", integral_coerce_step_counter, MRB_ARGS_REQ(2)); /* Numeric Class */ numeric = mrb_define_class(mrb, "Numeric", mrb->object_class); /* 15.2.7 */ - - mrb_define_method(mrb, numeric, "**", num_pow, MRB_ARGS_REQ(1)); - mrb_define_method(mrb, numeric, "/", num_div, MRB_ARGS_REQ(1)); /* 15.2.8.3.4 */ - mrb_define_method(mrb, numeric, "quo", num_div, MRB_ARGS_REQ(1)); /* 15.2.7.4.5 (x) */ - mrb_define_method(mrb, numeric, "div", num_idiv, MRB_ARGS_REQ(1)); - mrb_define_method(mrb, numeric, "<=>", num_cmp, MRB_ARGS_REQ(1)); /* 15.2.9.3.6 */ - mrb_define_method(mrb, numeric, "<", num_lt, MRB_ARGS_REQ(1)); - mrb_define_method(mrb, numeric, "<=", num_le, MRB_ARGS_REQ(1)); - mrb_define_method(mrb, numeric, ">", num_gt, MRB_ARGS_REQ(1)); - mrb_define_method(mrb, numeric, ">=", num_ge, MRB_ARGS_REQ(1)); mrb_define_method(mrb, numeric, "finite?", num_finite_p, MRB_ARGS_NONE()); mrb_define_method(mrb, numeric, "infinite?",num_infinite_p, MRB_ARGS_NONE()); -- cgit v1.2.3 From 5d30309e9826fe1a392fa7a7a33e11ad58857b3f Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Mon, 20 May 2019 16:32:00 +0900 Subject: Silence the return value warnings from gcc; ref 237a57b --- src/numeric.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/numeric.c b/src/numeric.c index c740a32e3..140cd0101 100644 --- a/src/numeric.c +++ b/src/numeric.c @@ -824,6 +824,7 @@ mrb_num_mul(mrb_state *mrb, mrb_value x, mrb_value y) } #endif mrb_raise(mrb, E_TYPE_ERROR, "no number multiply"); + return mrb_nil_value(); /* not reached */ } /* 15.2.8.3.3 */ @@ -1295,6 +1296,7 @@ mrb_num_plus(mrb_state *mrb, mrb_value x, mrb_value y) } #endif mrb_raise(mrb, E_TYPE_ERROR, "no number addition"); + return mrb_nil_value(); /* not reached */ } /* 15.2.8.3.1 */ @@ -1351,6 +1353,7 @@ mrb_num_minus(mrb_state *mrb, mrb_value x, mrb_value y) } #endif mrb_raise(mrb, E_TYPE_ERROR, "no number subtraction"); + return mrb_nil_value(); /* not reached */ } /* 15.2.8.3.2 */ -- cgit v1.2.3 From b7f85b9df91168f8c6338354bc50a621ca0e098b Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Mon, 20 May 2019 16:35:06 +0900 Subject: Should not refer `Float` class in case of `MRB_WITHOUT_FLOAT`. This commit removes `Float` from `rational.c`. --- mrbgems/mruby-rational/mrblib/rational.rb | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/mrbgems/mruby-rational/mrblib/rational.rb b/mrbgems/mruby-rational/mrblib/rational.rb index cecede48a..c8614ecea 100644 --- a/mrbgems/mruby-rational/mrblib/rational.rb +++ b/mrbgems/mruby-rational/mrblib/rational.rb @@ -48,12 +48,9 @@ class Rational < Numeric end def <=>(rhs) - case rhs - when Fixnum + if rhs.is_a?(Integral) return numerator <=> rhs if denominator == 1 rhs = Rational(rhs) - when Float - return to_f <=> rhs end case rhs @@ -103,5 +100,5 @@ end end __send__(original_operator_name, rhs) end - end + end if Object.const_defined?(:Float) end -- cgit v1.2.3 From f6e4145ad960d9bc748f9c91fd4c5db5afeebbd0 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Tue, 21 May 2019 16:06:37 +0900 Subject: Remove `Complex(string)` complex generation. It should raise an error. --- mrbgems/mruby-complex/test/complex.rb | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/mrbgems/mruby-complex/test/complex.rb b/mrbgems/mruby-complex/test/complex.rb index ca58202c2..e7fcc7322 100644 --- a/mrbgems/mruby-complex/test/complex.rb +++ b/mrbgems/mruby-complex/test/complex.rb @@ -63,8 +63,6 @@ assert 'Complex#==' do assert_true Complex(2, 3) == Complex(2, 3) assert_true Complex(5) == 5 assert_true Complex(0) == 0.0 - assert_false Complex('1/3') == 0.33 - assert_false Complex('1/2') == '1/2' end assert 'Complex#abs' do @@ -127,4 +125,4 @@ assert 'Complex::to_i' do assert_raise(RangeError) do Complex(1, 2).to_i end -end \ No newline at end of file +end -- cgit v1.2.3 From e941cf06a3e0351107d36d49d540562fdf49f9b4 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Tue, 21 May 2019 16:08:02 +0900 Subject: Export `mrb_int_value` that converts `mrb_float` to `Fixnum`. Or `Float` if `mrb_float` value is too big (or too small) to fit in `mrb_int`. The `_int_` in `mrb_int_value` means `Integral` module, which represents integer-like values in mruby. --- include/mruby/numeric.h | 1 + src/numeric.c | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/include/mruby/numeric.h b/include/mruby/numeric.h index d670504c2..34707e441 100644 --- a/include/mruby/numeric.h +++ b/include/mruby/numeric.h @@ -34,6 +34,7 @@ MRB_API mrb_value mrb_fixnum_to_str(mrb_state *mrb, mrb_value x, mrb_int base); #ifndef MRB_WITHOUT_FLOAT MRB_API mrb_value mrb_float_to_str(mrb_state *mrb, mrb_value x, const char *fmt); MRB_API mrb_float mrb_to_flo(mrb_state *mrb, mrb_value x); +MRB_API mrb_value mrb_int_value(mrb_state *mrb, mrb_float f); #endif MRB_API mrb_value mrb_num_plus(mrb_state *mrb, mrb_value x, mrb_value y); diff --git a/src/numeric.c b/src/numeric.c index 140cd0101..e15b7f671 100644 --- a/src/numeric.c +++ b/src/numeric.c @@ -45,7 +45,7 @@ mrb_to_flo(mrb_state *mrb, mrb_value val) return mrb_float(val); } -static mrb_value +MRB_API mrb_value mrb_int_value(mrb_state *mrb, mrb_float f) { if (FIXABLE_FLOAT(f)) { -- cgit v1.2.3 From fccec8964a1b30cef8ff9d97e0e01f3a348e318b Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Tue, 21 May 2019 16:11:25 +0900 Subject: Implements part of `Complex` class in C. --- mrbgems/mruby-complex/mrblib/complex.rb | 50 +++----------- mrbgems/mruby-complex/src/complex.c | 116 ++++++++++++++++++++++++++++++++ mrbgems/mruby-rational/src/rational.c | 2 +- 3 files changed, 127 insertions(+), 41 deletions(-) create mode 100644 mrbgems/mruby-complex/src/complex.c diff --git a/mrbgems/mruby-complex/mrblib/complex.rb b/mrbgems/mruby-complex/mrblib/complex.rb index 8ae743e77..4c0c19c70 100644 --- a/mrbgems/mruby-complex/mrblib/complex.rb +++ b/mrbgems/mruby-complex/mrblib/complex.rb @@ -23,43 +23,43 @@ class Complex < Numeric end def +@ - Complex(real, imaginary) + Complex._new(real, imaginary) end def -@ - Complex(-real, -imaginary) + Complex._new(-real, -imaginary) end def +(rhs) if rhs.is_a? Complex - Complex(real + rhs.real, imaginary + rhs.imaginary) + Complex._new(real + rhs.real, imaginary + rhs.imaginary) elsif rhs.is_a? Numeric - Complex(real + rhs, imaginary) + Complex._new(real + rhs, imaginary) end end def -(rhs) if rhs.is_a? Complex - Complex(real - rhs.real, imaginary - rhs.imaginary) + Complex._new(real - rhs.real, imaginary - rhs.imaginary) elsif rhs.is_a? Numeric - Complex(real - rhs, imaginary) + Complex._new(real - rhs, imaginary) end end def *(rhs) if rhs.is_a? Complex - Complex(real * rhs.real - imaginary * rhs.imaginary, real * rhs.imaginary + rhs.real * imaginary) + Complex._new(real * rhs.real - imaginary * rhs.imaginary, real * rhs.imaginary + rhs.real * imaginary) elsif rhs.is_a? Numeric - Complex(real * rhs, imaginary * rhs) + Complex._new(real * rhs, imaginary * rhs) end end def /(rhs) if rhs.is_a? Complex div = rhs.real * rhs.real + rhs.imaginary * rhs.imaginary - Complex((real * rhs.real + imaginary * rhs.imaginary) / div, (rhs.real * imaginary - real * rhs.imaginary) / div) + Complex._new((real * rhs.real + imaginary * rhs.imaginary) / div, (rhs.real * imaginary - real * rhs.imaginary) / div) elsif rhs.is_a? Numeric - Complex(real / rhs, imaginary / rhs) + Complex._new(real / rhs, imaginary / rhs) end end alias_method :quo, :/ @@ -92,14 +92,6 @@ class Complex < Numeric end alias_method :conj, :conjugate - def numerator - self - end - - def denominator - 1 - end - def fdiv(numeric) Complex(real.to_f / numeric, imaginary.to_f / numeric) end @@ -117,36 +109,14 @@ class Complex < Numeric end alias_method :rect, :rectangular - def to_c - self - end - - def to_f - raise RangeError.new "can't convert #{to_s} into Float" unless imaginary.zero? - real.to_f - end - - def to_i - raise RangeError.new "can't convert #{to_s} into Integer" unless imaginary.zero? - real.to_i - end - def to_r raise RangeError.new "can't convert #{to_s} into Rational" unless imaginary.zero? Rational(real, 1) end - attr_reader :real, :imaginary alias_method :imag, :imaginary end -class << Complex - alias_method :_new, :new - undef_method :new - - alias_method :rect, :rectangular -end - module Kernel def Complex(real, imaginary = 0) Complex.rectangular(real, imaginary) diff --git a/mrbgems/mruby-complex/src/complex.c b/mrbgems/mruby-complex/src/complex.c new file mode 100644 index 000000000..5de0ae9a4 --- /dev/null +++ b/mrbgems/mruby-complex/src/complex.c @@ -0,0 +1,116 @@ +#include +#include +#include + +struct mrb_complex { + mrb_float real; + mrb_float imaginary; +}; + +#include + +static const struct mrb_data_type mrb_complex_type = {"Complex", mrb_free}; + +static mrb_value +complex_new(mrb_state *mrb, mrb_float real, mrb_float imaginary) +{ + struct RClass *c = mrb_class_get(mrb, "Complex"); + struct mrb_complex *p; + + p = (struct mrb_complex*)mrb_malloc(mrb, sizeof(struct mrb_complex)); + p->real = real; + p->imaginary = imaginary; + + return mrb_obj_value(Data_Wrap_Struct(mrb, c, &mrb_complex_type, p)); +} + +static struct mrb_complex* +complex_ptr(mrb_state *mrb, mrb_value v) +{ + struct mrb_complex *p; + + p = DATA_GET_PTR(mrb, v, &mrb_complex_type, struct mrb_complex); + if (!p) { + mrb_raise(mrb, E_ARGUMENT_ERROR, "uninitialized complex"); + } + return p; +} + +static mrb_value +complex_real(mrb_state *mrb, mrb_value self) +{ + struct mrb_complex *p = complex_ptr(mrb, self); + return mrb_float_value(mrb, p->real); +} + +static mrb_value +complex_imaginary(mrb_state *mrb, mrb_value self) +{ + struct mrb_complex *p = complex_ptr(mrb, self); + return mrb_float_value(mrb, p->imaginary); +} + +static mrb_value +complex_s_new(mrb_state *mrb, mrb_value self) +{ + mrb_float real, imaginary; + + mrb_get_args(mrb, "ff", &real, &imaginary); + return complex_new(mrb, real, imaginary); +} + +#ifndef MRB_WITHOUT_FLOAT +static mrb_value +complex_to_f(mrb_state *mrb, mrb_value self) +{ + struct mrb_complex *p = complex_ptr(mrb, self); + + if (p->imaginary != 0) { + mrb_raisef(mrb, E_RANGE_ERROR, "can't convert %S into Float", self); + } + + return mrb_float_value(mrb, p->real); +} +#endif + +static mrb_value +complex_to_i(mrb_state *mrb, mrb_value self) +{ + struct mrb_complex *p = complex_ptr(mrb, self); + + if (p->imaginary != 0) { + mrb_raisef(mrb, E_RANGE_ERROR, "can't convert %S into Float", self); + } + return mrb_int_value(mrb, p->real); +} + +static mrb_value +complex_to_c(mrb_state *mrb, mrb_value self) +{ + return self; +} + +void mrb_mruby_complex_gem_init(mrb_state *mrb) +{ + struct RClass *comp; + +#ifdef COMPLEX_USE_ISTRUCT + mrb_assert(sizeof(struct mrb_complex) < ISTRUCT_DATA_SIZE); +#endif + comp = mrb_define_class(mrb, "Complex", mrb_class_get(mrb, "Numeric")); + //MRB_SET_INSTANCE_TT(comp, MRB_TT_ISTRUCT); + mrb_undef_class_method(mrb, comp, "new"); + mrb_define_class_method(mrb, comp, "_new", complex_s_new, MRB_ARGS_REQ(2)); + mrb_define_method(mrb, comp, "real", complex_real, MRB_ARGS_NONE()); + mrb_define_method(mrb, comp, "imaginary", complex_imaginary, MRB_ARGS_NONE()); +#ifndef MRB_WITHOUT_FLOAT + mrb_define_method(mrb, comp, "to_f", complex_to_f, MRB_ARGS_NONE()); +#endif + mrb_define_method(mrb, comp, "to_i", complex_to_i, MRB_ARGS_NONE()); + mrb_define_method(mrb, comp, "to_c", complex_to_c, MRB_ARGS_NONE()); +} + +void +mrb_mruby_complex_gem_final(mrb_state* mrb) +{ +} diff --git a/mrbgems/mruby-rational/src/rational.c b/mrbgems/mruby-rational/src/rational.c index 549715e7d..2a3f6df09 100644 --- a/mrbgems/mruby-rational/src/rational.c +++ b/mrbgems/mruby-rational/src/rational.c @@ -37,7 +37,7 @@ rational_new(mrb_state *mrb, mrb_int numerator, mrb_int denominator) struct mrb_rational *p = rational_ptr(rat); p->numerator = numerator; p->denominator = denominator; - return mrb_obj_value(s); + return rat; } static mrb_value -- cgit v1.2.3 From c02e63eb77b68377239287acccf371516177a8b9 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Tue, 21 May 2019 16:17:21 +0900 Subject: Use `MRB_TT_ISTRUCT` for `Complex` numbers if possible. --- mrbgems/mruby-complex/src/complex.c | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/mrbgems/mruby-complex/src/complex.c b/mrbgems/mruby-complex/src/complex.c index 5de0ae9a4..c6fb7a829 100644 --- a/mrbgems/mruby-complex/src/complex.c +++ b/mrbgems/mruby-complex/src/complex.c @@ -7,6 +7,29 @@ struct mrb_complex { mrb_float imaginary; }; +#if defined(MRB_64BIT) || defined(MRB_USE_FLOAT) + +#define COMPLEX_USE_ISTRUCT +/* use TT_ISTRUCT */ +#include + +#define complex_ptr(mrb, v) (struct mrb_complex*)mrb_istruct_ptr(v) + +static mrb_value +complex_new(mrb_state *mrb, mrb_float real, mrb_float imaginary) +{ + struct RClass *c = mrb_class_get(mrb, "Complex"); + struct RIStruct *s = (struct RIStruct*)mrb_obj_alloc(mrb, MRB_TT_ISTRUCT, c); + mrb_value comp = mrb_obj_value(s); + struct mrb_complex *p = complex_ptr(mrb, comp); + p->real = real; + p->imaginary = imaginary; + + return comp; +} + +#else +/* use TT_DATA */ #include static const struct mrb_data_type mrb_complex_type = {"Complex", mrb_free}; @@ -35,6 +58,7 @@ complex_ptr(mrb_state *mrb, mrb_value v) } return p; } +#endif static mrb_value complex_real(mrb_state *mrb, mrb_value self) -- cgit v1.2.3 From 38f8edbdd7463ee5e3331d09b2d031d55f2fd05e Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Tue, 21 May 2019 21:12:33 +0900 Subject: Update ISO section number for some Numeric methods. --- src/numeric.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/numeric.c b/src/numeric.c index e15b7f671..608b4f289 100644 --- a/src/numeric.c +++ b/src/numeric.c @@ -1597,10 +1597,10 @@ mrb_init_numeric(mrb_state *mrb) integral = mrb_define_module(mrb, "Integral"); mrb_define_method(mrb, integral,"**", integral_pow, MRB_ARGS_REQ(1)); - mrb_define_method(mrb, integral,"/", integral_div, MRB_ARGS_REQ(1)); /* 15.2.8.3.4 */ + mrb_define_method(mrb, integral,"/", integral_div, MRB_ARGS_REQ(1)); /* 15.2.{8,9}.3.6 */ mrb_define_method(mrb, integral,"quo", integral_div, MRB_ARGS_REQ(1)); /* 15.2.7.4.5 (x) */ mrb_define_method(mrb, integral,"div", integral_idiv, MRB_ARGS_REQ(1)); - mrb_define_method(mrb, integral,"<=>", integral_cmp, MRB_ARGS_REQ(1)); /* 15.2.9.3.6 */ + mrb_define_method(mrb, integral,"<=>", integral_cmp, MRB_ARGS_REQ(1)); /* 15.2.{8,9}.3.1 */ mrb_define_method(mrb, integral,"<", integral_lt, MRB_ARGS_REQ(1)); mrb_define_method(mrb, integral,"<=", integral_le, MRB_ARGS_REQ(1)); mrb_define_method(mrb, integral,">", integral_gt, MRB_ARGS_REQ(1)); -- cgit v1.2.3 From 8513abd40404ef8cb8340da906f2d15101536de1 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Wed, 22 May 2019 19:57:35 +0900 Subject: `Kernel#Rational` requires numerator --- mrbgems/mruby-rational/mrblib/rational.rb | 2 +- mrbgems/mruby-rational/test/rational.rb | 13 +++++++++++++ 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/mrbgems/mruby-rational/mrblib/rational.rb b/mrbgems/mruby-rational/mrblib/rational.rb index c8614ecea..4936b1123 100644 --- a/mrbgems/mruby-rational/mrblib/rational.rb +++ b/mrbgems/mruby-rational/mrblib/rational.rb @@ -71,7 +71,7 @@ class Numeric end module Kernel - def Rational(numerator = 0, denominator = 1) + def Rational(numerator, denominator = 1) a = numerator b = denominator a, b = b, a % b until b == 0 diff --git a/mrbgems/mruby-rational/test/rational.rb b/mrbgems/mruby-rational/test/rational.rb index ea55880fe..914f8505e 100644 --- a/mrbgems/mruby-rational/test/rational.rb +++ b/mrbgems/mruby-rational/test/rational.rb @@ -27,6 +27,19 @@ assert 'Rational' do assert_equal([5, 1], [r.numerator, r.denominator]) end +assert 'Kernel#Rational' do + r = Rational(4,10) + assert_equal(2, r.numerator) + assert_equal(5, r.denominator) + + r = Rational(3) + assert_equal(3, r.numerator) + assert_equal(1, r.denominator) + + assert_raise(ArgumentError) { Rational() } + assert_raise(ArgumentError) { Rational(1,2,3) } +end + assert 'Rational#to_f' do assert_float(2.0, Rational(2).to_f) assert_float(2.25, Rational(9, 4).to_f) -- cgit v1.2.3 From 48903850e9041e74c526fef5e63857007d2cac38 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Thu, 23 May 2019 13:40:49 +0900 Subject: Freeze `Rational` and `Complex` objects --- mrbgems/mruby-complex/src/complex.c | 1 + mrbgems/mruby-complex/test/complex.rb | 8 +++++++- mrbgems/mruby-rational/src/rational.c | 1 + mrbgems/mruby-rational/test/rational.rb | 6 ++++++ 4 files changed, 15 insertions(+), 1 deletion(-) diff --git a/mrbgems/mruby-complex/src/complex.c b/mrbgems/mruby-complex/src/complex.c index c6fb7a829..1b030c317 100644 --- a/mrbgems/mruby-complex/src/complex.c +++ b/mrbgems/mruby-complex/src/complex.c @@ -24,6 +24,7 @@ complex_new(mrb_state *mrb, mrb_float real, mrb_float imaginary) struct mrb_complex *p = complex_ptr(mrb, comp); p->real = real; p->imaginary = imaginary; + MRB_SET_FROZEN_FLAG(s); return comp; } diff --git a/mrbgems/mruby-complex/test/complex.rb b/mrbgems/mruby-complex/test/complex.rb index e7fcc7322..6996eb214 100644 --- a/mrbgems/mruby-complex/test/complex.rb +++ b/mrbgems/mruby-complex/test/complex.rb @@ -1,5 +1,5 @@ def assert_complex(real, exp) - assert_float real.real, exp.real + assert_float real.real, exp.real assert_float real.imaginary, exp.imaginary end @@ -126,3 +126,9 @@ assert 'Complex::to_i' do Complex(1, 2).to_i end end + +assert 'Complex#frozen?' do + assert_predicate(1i, :frozen?) + assert_predicate(Complex(2,3), :frozen?) + assert_predicate(4+5i, :frozen?) +end diff --git a/mrbgems/mruby-rational/src/rational.c b/mrbgems/mruby-rational/src/rational.c index 2a3f6df09..fa061c0b8 100644 --- a/mrbgems/mruby-rational/src/rational.c +++ b/mrbgems/mruby-rational/src/rational.c @@ -37,6 +37,7 @@ rational_new(mrb_state *mrb, mrb_int numerator, mrb_int denominator) struct mrb_rational *p = rational_ptr(rat); p->numerator = numerator; p->denominator = denominator; + MRB_SET_FROZEN_FLAG(s); return rat; } diff --git a/mrbgems/mruby-rational/test/rational.rb b/mrbgems/mruby-rational/test/rational.rb index 914f8505e..1ed3b3a07 100644 --- a/mrbgems/mruby-rational/test/rational.rb +++ b/mrbgems/mruby-rational/test/rational.rb @@ -278,3 +278,9 @@ assert 'Rational#negative?' do assert_not_predicate(Rational(2,3), :negative?) assert_not_predicate(Rational(0), :negative?) end + +assert 'Rational#frozen?' do + assert_predicate(1r, :frozen?) + assert_predicate(Rational(2,3), :frozen?) + assert_predicate(4/5r, :frozen?) +end -- cgit v1.2.3 From 240bbc39e11e317a902e30b2cf790509c2e75464 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Fri, 24 May 2019 21:02:22 +0900 Subject: Fix the order of "expected" and "actual" in `mruby-time` test --- mrbgems/mruby-time/test/time.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mrbgems/mruby-time/test/time.rb b/mrbgems/mruby-time/test/time.rb index ce7b39928..f59e27bc1 100644 --- a/mrbgems/mruby-time/test/time.rb +++ b/mrbgems/mruby-time/test/time.rb @@ -72,7 +72,7 @@ assert('Time#+', '15.2.19.7.1') do t1 = Time.at(1300000000.0) t2 = t1.+(60) - assert_equal(t2.utc.asctime, "Sun Mar 13 07:07:40 2011") + assert_equal("Sun Mar 13 07:07:40 2011", t2.utc.asctime) assert_raise(FloatDomainError) { Time.at(0) + Float::NAN } assert_raise(FloatDomainError) { Time.at(0) + Float::INFINITY } @@ -83,7 +83,7 @@ assert('Time#-', '15.2.19.7.2') do t1 = Time.at(1300000000.0) t2 = t1.-(60) - assert_equal(t2.utc.asctime, "Sun Mar 13 07:05:40 2011") + assert_equal("Sun Mar 13 07:05:40 2011", t2.utc.asctime) assert_raise(FloatDomainError) { Time.at(0) - Float::NAN } assert_raise(FloatDomainError) { Time.at(0) - Float::INFINITY } -- cgit v1.2.3 From 56e0e1934d4ec751d83f9f54ce93ca74b0e21194 Mon Sep 17 00:00:00 2001 From: dearblue Date: Sat, 25 May 2019 12:12:21 +0900 Subject: Name the return value of `mrb_range_beg_len()` --- include/mruby/range.h | 8 +++++++- mrbgems/mruby-array-ext/src/array.c | 2 +- mrbgems/mruby-kernel-ext/src/kernel.c | 2 +- mrbgems/mruby-string-ext/src/string.c | 6 +++--- src/array.c | 8 ++++---- src/range.c | 12 ++++++------ src/string.c | 4 ++-- 7 files changed, 24 insertions(+), 18 deletions(-) diff --git a/include/mruby/range.h b/include/mruby/range.h index b5626993a..ee6eb8d1d 100644 --- a/include/mruby/range.h +++ b/include/mruby/range.h @@ -64,7 +64,13 @@ MRB_API struct RRange* mrb_range_ptr(mrb_state *mrb, mrb_value range); */ MRB_API mrb_value mrb_range_new(mrb_state *mrb, mrb_value start, mrb_value end, mrb_bool exclude); -MRB_API mrb_int mrb_range_beg_len(mrb_state *mrb, mrb_value range, mrb_int *begp, mrb_int *lenp, mrb_int len, mrb_bool trunc); +enum mrb_range_beg_len { + MRB_RANGE_TYPE_MISMATCH = 0, /* (failure) not range */ + MRB_RANGE_OK = 1, /* (success) range */ + MRB_RANGE_OUT = 2 /* (failure) out of range */ +}; + +MRB_API enum mrb_range_beg_len mrb_range_beg_len(mrb_state *mrb, mrb_value range, mrb_int *begp, mrb_int *lenp, mrb_int len, mrb_bool trunc); mrb_value mrb_get_values_at(mrb_state *mrb, mrb_value obj, mrb_int olen, mrb_int argc, const mrb_value *argv, mrb_value (*func)(mrb_state*, mrb_value, mrb_int)); void mrb_gc_mark_range(mrb_state *mrb, struct RRange *r); diff --git a/mrbgems/mruby-array-ext/src/array.c b/mrbgems/mruby-array-ext/src/array.c index b6d9c9c80..20c771a97 100644 --- a/mrbgems/mruby-array-ext/src/array.c +++ b/mrbgems/mruby-array-ext/src/array.c @@ -145,7 +145,7 @@ mrb_ary_slice_bang(mrb_state *mrb, mrb_value self) mrb_get_args(mrb, "o|i", &index, &len); switch (mrb_type(index)) { case MRB_TT_RANGE: - if (mrb_range_beg_len(mrb, index, &i, &len, ARY_LEN(a), TRUE) == 1) { + if (mrb_range_beg_len(mrb, index, &i, &len, ARY_LEN(a), TRUE) == MRB_RANGE_OK) { goto delete_pos_len; } else { diff --git a/mrbgems/mruby-kernel-ext/src/kernel.c b/mrbgems/mruby-kernel-ext/src/kernel.c index 9288b0e6f..8e7e03c56 100644 --- a/mrbgems/mruby-kernel-ext/src/kernel.c +++ b/mrbgems/mruby-kernel-ext/src/kernel.c @@ -22,7 +22,7 @@ mrb_f_caller(mrb_state *mrb, mrb_value self) case 1: if (mrb_type(v) == MRB_TT_RANGE) { mrb_int beg, len; - if (mrb_range_beg_len(mrb, v, &beg, &len, bt_len, TRUE) == 1) { + if (mrb_range_beg_len(mrb, v, &beg, &len, bt_len, TRUE) == MRB_RANGE_OK) { lev = beg; n = len; } diff --git a/mrbgems/mruby-string-ext/src/string.c b/mrbgems/mruby-string-ext/src/string.c index ba7e3c610..85180516c 100644 --- a/mrbgems/mruby-string-ext/src/string.c +++ b/mrbgems/mruby-string-ext/src/string.c @@ -58,11 +58,11 @@ mrb_str_byteslice(mrb_state *mrb, mrb_value str) len = RSTRING_LEN(str); switch (mrb_range_beg_len(mrb, a1, &beg, &len, len, TRUE)) { - case 0: /* not range */ + case MRB_RANGE_TYPE_MISMATCH: break; - case 1: /* range */ + case MRB_RANGE_OK: return mrb_str_substr(mrb, str, beg, len); - case 2: /* out of range */ + case MRB_RANGE_OUT: mrb_raisef(mrb, E_RANGE_ERROR, "%S out of range", a1); break; } diff --git a/src/array.c b/src/array.c index d4302cb22..bd9b4d358 100644 --- a/src/array.c +++ b/src/array.c @@ -858,7 +858,7 @@ mrb_ary_aget(mrb_state *mrb, mrb_value self) switch (mrb_type(index)) { /* a[n..m] */ case MRB_TT_RANGE: - if (mrb_range_beg_len(mrb, index, &i, &len, ARY_LEN(a), TRUE) == 1) { + if (mrb_range_beg_len(mrb, index, &i, &len, ARY_LEN(a), TRUE) == MRB_RANGE_OK) { return ary_subseq(mrb, a, i, len); } else { @@ -927,13 +927,13 @@ mrb_ary_aset(mrb_state *mrb, mrb_value self) if (mrb_get_args(mrb, "oo|o", &v1, &v2, &v3) == 2) { /* a[n..m] = v */ switch (mrb_range_beg_len(mrb, v1, &i, &len, RARRAY_LEN(self), FALSE)) { - case 0: /* not range */ + case MRB_RANGE_TYPE_MISMATCH: mrb_ary_set(mrb, self, aget_index(mrb, v1), v2); break; - case 1: /* range */ + case MRB_RANGE_OK: mrb_ary_splice(mrb, self, i, len, v2); break; - case 2: /* out of range */ + case MRB_RANGE_OUT: mrb_raisef(mrb, E_RANGE_ERROR, "%S out of range", v1); break; } diff --git a/src/range.c b/src/range.c index 21771c8ec..9036ef093 100644 --- a/src/range.c +++ b/src/range.c @@ -352,7 +352,7 @@ mrb_get_values_at(mrb_state *mrb, mrb_value obj, mrb_int olen, mrb_int argc, con if (mrb_fixnum_p(argv[i])) { mrb_ary_push(mrb, result, func(mrb, obj, mrb_fixnum(argv[i]))); } - else if (mrb_range_beg_len(mrb, argv[i], &beg, &len, olen, FALSE) == 1) { + else if (mrb_range_beg_len(mrb, argv[i], &beg, &len, olen, FALSE) == MRB_RANGE_OK) { mrb_int const end = olen < beg + len ? olen : beg + len; for (j = beg; j < end; ++j) { mrb_ary_push(mrb, result, func(mrb, obj, j)); @@ -398,13 +398,13 @@ mrb_range_new(mrb_state *mrb, mrb_value beg, mrb_value end, mrb_bool excl) return mrb_range_value(r); } -MRB_API mrb_int +MRB_API enum mrb_range_beg_len mrb_range_beg_len(mrb_state *mrb, mrb_value range, mrb_int *begp, mrb_int *lenp, mrb_int len, mrb_bool trunc) { mrb_int beg, end; struct RRange *r; - if (mrb_type(range) != MRB_TT_RANGE) return 0; + if (mrb_type(range) != MRB_TT_RANGE) return MRB_RANGE_TYPE_MISMATCH; r = mrb_range_ptr(mrb, range); beg = mrb_int(mrb, RANGE_BEG(r)); @@ -412,11 +412,11 @@ mrb_range_beg_len(mrb_state *mrb, mrb_value range, mrb_int *begp, mrb_int *lenp, if (beg < 0) { beg += len; - if (beg < 0) return 2; + if (beg < 0) return MRB_RANGE_OUT; } if (trunc) { - if (beg > len) return 2; + if (beg > len) return MRB_RANGE_OUT; if (end > len) end = len; } @@ -427,7 +427,7 @@ mrb_range_beg_len(mrb_state *mrb, mrb_value range, mrb_int *begp, mrb_int *lenp, *begp = beg; *lenp = len; - return 1; + return MRB_RANGE_OK; } void diff --git a/src/string.c b/src/string.c index 578e3bdcc..db2d73e32 100644 --- a/src/string.c +++ b/src/string.c @@ -1041,9 +1041,9 @@ num_index: len = RSTRING_CHAR_LEN(str); switch (mrb_range_beg_len(mrb, indx, &beg, &len, len, TRUE)) { - case 1: + case MRB_RANGE_OK: return str_subseq(mrb, str, beg, len); - case 2: + case MRB_RANGE_OUT: return mrb_nil_value(); default: break; -- cgit v1.2.3 From ecfca8def78043f891bcbe6bc1eb036048996169 Mon Sep 17 00:00:00 2001 From: dearblue Date: Sat, 25 May 2019 22:24:08 +0900 Subject: Fix double rounded by negative index - Before patched: ``` $ mruby -e 'p (-12..-1).map { |i| "Hello"[i] }.join' "HelloHello" ``` - After patched: ``` $ mruby -e 'p (-12..-1).map { |i| "Hello"[i] }.join' "Hello" ``` --- src/string.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/string.c b/src/string.c index db2d73e32..bfe73b359 100644 --- a/src/string.c +++ b/src/string.c @@ -449,9 +449,6 @@ str_substr(mrb_state *mrb, mrb_value str, mrb_int beg, mrb_int len) if (clen == 0) { len = 0; } - else if (beg < 0) { - beg = clen + beg; - } if (beg > clen) return mrb_nil_value(); if (beg < 0) { beg += clen; -- cgit v1.2.3 From d1e1bb0d5b45d9f1c5de943a036c86542698af49 Mon Sep 17 00:00:00 2001 From: dearblue Date: Sat, 25 May 2019 23:59:43 +0900 Subject: Remove `mrb_alloca()` function When I found this function, I expected it to behave the same as the `alloca(3)` function, but it is accually the `mrb_alloca()` function does not free the heap until the `mrb_close()` function is called. Also, even if it is deleted, it can be replaced with the combination of the `MRB_TT_DATA` object and the `mrb_gv_set()` function if it is sure necessary. --- include/mruby.h | 2 -- src/state.c | 33 --------------------------------- 2 files changed, 35 deletions(-) diff --git a/include/mruby.h b/include/mruby.h index 20cdc1b83..5d5c759dd 100644 --- a/include/mruby.h +++ b/include/mruby.h @@ -228,7 +228,6 @@ typedef struct mrb_state { struct RClass *symbol_class; struct RClass *kernel_module; - struct alloca_header *mems; mrb_gc gc; #ifdef MRB_METHOD_CACHE @@ -1247,7 +1246,6 @@ MRB_API void mrb_pool_close(struct mrb_pool*); MRB_API void* mrb_pool_alloc(struct mrb_pool*, size_t); MRB_API void* mrb_pool_realloc(struct mrb_pool*, void*, size_t oldlen, size_t newlen); MRB_API mrb_bool mrb_pool_can_realloc(struct mrb_pool*, void*, size_t); -MRB_API void* mrb_alloca(mrb_state *mrb, size_t); MRB_API void mrb_state_atexit(mrb_state *mrb, mrb_atexit_func func); diff --git a/src/state.c b/src/state.c index 08d7ba906..c42df71ba 100644 --- a/src/state.c +++ b/src/state.c @@ -57,38 +57,6 @@ mrb_default_allocf(mrb_state *mrb, void *p, size_t size, void *ud) } } -struct alloca_header { - struct alloca_header *next; - char buf[1]; -}; - -MRB_API void* -mrb_alloca(mrb_state *mrb, size_t size) -{ - struct alloca_header *p; - - p = (struct alloca_header*) mrb_malloc(mrb, sizeof(struct alloca_header)+size); - p->next = mrb->mems; - mrb->mems = p; - return (void*)p->buf; -} - -static void -mrb_alloca_free(mrb_state *mrb) -{ - struct alloca_header *p; - struct alloca_header *tmp; - - if (mrb == NULL) return; - p = mrb->mems; - - while (p) { - tmp = p; - p = p->next; - mrb_free(mrb, tmp); - } -} - MRB_API mrb_state* mrb_open(void) { @@ -256,7 +224,6 @@ mrb_close(mrb_state *mrb) mrb_gc_free_gv(mrb); mrb_free_context(mrb, mrb->root_c); mrb_free_symtbl(mrb); - mrb_alloca_free(mrb); mrb_gc_destroy(mrb, &mrb->gc); mrb_free(mrb, mrb); } -- cgit v1.2.3 From 4261ba944330f27dcb80e5e4580f73bd6b3a7106 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Fri, 24 May 2019 13:15:26 +0900 Subject: Remove some overhead from methods defined in Ruby in Complex. --- mrbgems/mruby-complex/mrblib/complex.rb | 37 +++++++++------------------------ mrbgems/mruby-complex/src/complex.c | 9 ++++---- 2 files changed, 15 insertions(+), 31 deletions(-) diff --git a/mrbgems/mruby-complex/mrblib/complex.rb b/mrbgems/mruby-complex/mrblib/complex.rb index 4c0c19c70..0299e7675 100644 --- a/mrbgems/mruby-complex/mrblib/complex.rb +++ b/mrbgems/mruby-complex/mrblib/complex.rb @@ -1,19 +1,8 @@ class Complex < Numeric - def initialize(real, imaginary) - real = real.to_f unless real.is_a? Numeric - imaginary = imaginary.to_f unless imaginary.is_a? Numeric - @real = real - @imaginary = imaginary - end - def self.polar(abs, arg = 0) Complex(abs * Math.cos(arg), abs * Math.sin(arg)) end - def self.rectangular(real, imaginary = 0) - _new(real, imaginary) - end - def inspect "(#{to_s})" end @@ -23,43 +12,43 @@ class Complex < Numeric end def +@ - Complex._new(real, imaginary) + Complex(real, imaginary) end def -@ - Complex._new(-real, -imaginary) + Complex(-real, -imaginary) end def +(rhs) if rhs.is_a? Complex - Complex._new(real + rhs.real, imaginary + rhs.imaginary) + Complex(real + rhs.real, imaginary + rhs.imaginary) elsif rhs.is_a? Numeric - Complex._new(real + rhs, imaginary) + Complex(real + rhs, imaginary) end end def -(rhs) if rhs.is_a? Complex - Complex._new(real - rhs.real, imaginary - rhs.imaginary) + Complex(real - rhs.real, imaginary - rhs.imaginary) elsif rhs.is_a? Numeric - Complex._new(real - rhs, imaginary) + Complex(real - rhs, imaginary) end end def *(rhs) if rhs.is_a? Complex - Complex._new(real * rhs.real - imaginary * rhs.imaginary, real * rhs.imaginary + rhs.real * imaginary) + Complex(real * rhs.real - imaginary * rhs.imaginary, real * rhs.imaginary + rhs.real * imaginary) elsif rhs.is_a? Numeric - Complex._new(real * rhs, imaginary * rhs) + Complex(real * rhs, imaginary * rhs) end end def /(rhs) if rhs.is_a? Complex div = rhs.real * rhs.real + rhs.imaginary * rhs.imaginary - Complex._new((real * rhs.real + imaginary * rhs.imaginary) / div, (rhs.real * imaginary - real * rhs.imaginary) / div) + Complex((real * rhs.real + imaginary * rhs.imaginary) / div, (rhs.real * imaginary - real * rhs.imaginary) / div) elsif rhs.is_a? Numeric - Complex._new(real / rhs, imaginary / rhs) + Complex(real / rhs, imaginary / rhs) end end alias_method :quo, :/ @@ -117,12 +106,6 @@ class Complex < Numeric alias_method :imag, :imaginary end -module Kernel - def Complex(real, imaginary = 0) - Complex.rectangular(real, imaginary) - end -end - [Fixnum, Float].each do |cls| [:+, :-, :*, :/, :==].each do |op| cls.instance_exec do diff --git a/mrbgems/mruby-complex/src/complex.c b/mrbgems/mruby-complex/src/complex.c index 1b030c317..0678d4b26 100644 --- a/mrbgems/mruby-complex/src/complex.c +++ b/mrbgems/mruby-complex/src/complex.c @@ -76,11 +76,11 @@ complex_imaginary(mrb_state *mrb, mrb_value self) } static mrb_value -complex_s_new(mrb_state *mrb, mrb_value self) +complex_s_rect(mrb_state *mrb, mrb_value self) { - mrb_float real, imaginary; + mrb_float real, imaginary = 0.0; - mrb_get_args(mrb, "ff", &real, &imaginary); + mrb_get_args(mrb, "f|f", &real, &imaginary); return complex_new(mrb, real, imaginary); } @@ -125,7 +125,8 @@ void mrb_mruby_complex_gem_init(mrb_state *mrb) comp = mrb_define_class(mrb, "Complex", mrb_class_get(mrb, "Numeric")); //MRB_SET_INSTANCE_TT(comp, MRB_TT_ISTRUCT); mrb_undef_class_method(mrb, comp, "new"); - mrb_define_class_method(mrb, comp, "_new", complex_s_new, MRB_ARGS_REQ(2)); + mrb_define_class_method(mrb, comp, "rectangular", complex_s_rect, MRB_ARGS_REQ(1)|MRB_ARGS_OPT(1)); + mrb_define_method(mrb, mrb->kernel_module, "Complex", complex_s_rect, MRB_ARGS_REQ(1)|MRB_ARGS_OPT(1)); mrb_define_method(mrb, comp, "real", complex_real, MRB_ARGS_NONE()); mrb_define_method(mrb, comp, "imaginary", complex_imaginary, MRB_ARGS_NONE()); #ifndef MRB_WITHOUT_FLOAT -- cgit v1.2.3 From 0bdb185a6fc1a6440b90b015bdb9d137db57ab77 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Sun, 26 May 2019 20:17:03 +0900 Subject: Add `Complex.rect` --- mrbgems/mruby-complex/src/complex.c | 1 + 1 file changed, 1 insertion(+) diff --git a/mrbgems/mruby-complex/src/complex.c b/mrbgems/mruby-complex/src/complex.c index 0678d4b26..5371332cd 100644 --- a/mrbgems/mruby-complex/src/complex.c +++ b/mrbgems/mruby-complex/src/complex.c @@ -126,6 +126,7 @@ void mrb_mruby_complex_gem_init(mrb_state *mrb) //MRB_SET_INSTANCE_TT(comp, MRB_TT_ISTRUCT); mrb_undef_class_method(mrb, comp, "new"); mrb_define_class_method(mrb, comp, "rectangular", complex_s_rect, MRB_ARGS_REQ(1)|MRB_ARGS_OPT(1)); + mrb_define_class_method(mrb, comp, "rect", complex_s_rect, MRB_ARGS_REQ(1)|MRB_ARGS_OPT(1)); mrb_define_method(mrb, mrb->kernel_module, "Complex", complex_s_rect, MRB_ARGS_REQ(1)|MRB_ARGS_OPT(1)); mrb_define_method(mrb, comp, "real", complex_real, MRB_ARGS_NONE()); mrb_define_method(mrb, comp, "imaginary", complex_imaginary, MRB_ARGS_NONE()); -- cgit v1.2.3 From 779251de64bdf63f71b02927db511fb8633c5d60 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Sun, 26 May 2019 20:32:04 +0900 Subject: Move `mrb_mod_s_nesting()` to `mruby-metaprog` gem from the core --- mrbgems/mruby-metaprog/src/metaprog.c | 26 ++++++++++++++++++++++++-- src/vm.c | 25 ------------------------- 2 files changed, 24 insertions(+), 27 deletions(-) diff --git a/mrbgems/mruby-metaprog/src/metaprog.c b/mrbgems/mruby-metaprog/src/metaprog.c index 0aafb4c34..38f75d460 100644 --- a/mrbgems/mruby-metaprog/src/metaprog.c +++ b/mrbgems/mruby-metaprog/src/metaprog.c @@ -657,8 +657,30 @@ mrb_mod_s_constants(mrb_state *mrb, mrb_value mod) return mrb_nil_value(); /* not reached */ } -/* implementation of Module.nesting */ -mrb_value mrb_mod_s_nesting(mrb_state*, mrb_value); +mrb_value +mrb_mod_s_nesting(mrb_state *mrb, mrb_value mod) +{ + struct RProc *proc; + mrb_value ary; + struct RClass *c = NULL; + + mrb_get_args(mrb, ""); + ary = mrb_ary_new(mrb); + proc = mrb->c->ci[-1].proc; /* callee proc */ + mrb_assert(!MRB_PROC_CFUNC_P(proc)); + while (proc) { + if (MRB_PROC_SCOPE_P(proc)) { + struct RClass *c2 = MRB_PROC_TARGET_CLASS(proc); + + if (c2 != c) { + c = c2; + mrb_ary_push(mrb, ary, mrb_obj_value(c)); + } + } + proc = proc->upper; + } + return ary; +} void mrb_mruby_metaprog_gem_init(mrb_state* mrb) diff --git a/src/vm.c b/src/vm.c index 8dc6623d1..0a6d4af8d 100644 --- a/src/vm.c +++ b/src/vm.c @@ -830,31 +830,6 @@ mrb_yield_cont(mrb_state *mrb, mrb_value b, mrb_value self, mrb_int argc, const return mrb_exec_irep(mrb, self, p); } -mrb_value -mrb_mod_s_nesting(mrb_state *mrb, mrb_value mod) -{ - struct RProc *proc; - mrb_value ary; - struct RClass *c = NULL; - - mrb_get_args(mrb, ""); - ary = mrb_ary_new(mrb); - proc = mrb->c->ci[-1].proc; /* callee proc */ - mrb_assert(!MRB_PROC_CFUNC_P(proc)); - while (proc) { - if (MRB_PROC_SCOPE_P(proc)) { - struct RClass *c2 = MRB_PROC_TARGET_CLASS(proc); - - if (c2 != c) { - c = c2; - mrb_ary_push(mrb, ary, mrb_obj_value(c)); - } - } - proc = proc->upper; - } - return ary; -} - static struct RBreak* break_new(mrb_state *mrb, struct RProc *p, mrb_value val) { -- cgit v1.2.3 From 534b578da7ae3742a67b1e950b5aea2ad97b8b9b Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Mon, 27 May 2019 18:26:54 +0900 Subject: Make some functions static in `mrbgems/mruby-metaprog/src/metaprog.c` --- mrbgems/mruby-metaprog/src/metaprog.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/mrbgems/mruby-metaprog/src/metaprog.c b/mrbgems/mruby-metaprog/src/metaprog.c index 38f75d460..e57d10d8d 100644 --- a/mrbgems/mruby-metaprog/src/metaprog.c +++ b/mrbgems/mruby-metaprog/src/metaprog.c @@ -186,7 +186,7 @@ method_entry_loop(mrb_state *mrb, struct RClass* klass, khash_t(st)* set) } } -mrb_value +static mrb_value mrb_class_instance_method_list(mrb_state *mrb, mrb_bool recur, struct RClass* klass, int obj) { khint_t i; @@ -565,8 +565,6 @@ mrb_mod_included_modules(mrb_state *mrb, mrb_value self) return result; } -mrb_value mrb_class_instance_method_list(mrb_state*, mrb_bool, struct RClass*, int); - /* 15.2.2.4.33 */ /* * call-seq: @@ -657,7 +655,7 @@ mrb_mod_s_constants(mrb_state *mrb, mrb_value mod) return mrb_nil_value(); /* not reached */ } -mrb_value +static mrb_value mrb_mod_s_nesting(mrb_state *mrb, mrb_value mod) { struct RProc *proc; -- cgit v1.2.3 From 902b2ce3c669d4e3b5c20b2c90a3b3982f17d820 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Mon, 27 May 2019 21:29:49 +0900 Subject: Fix `Rational#==(Complex)` Consider a Numreic class like `Complex` that does not have `<=>` but `==` works (`0i == 0r` is `true`). --- mrbgems/mruby-rational/mrblib/rational.rb | 13 +++++++ mrbgems/mruby-rational/test/rational.rb | 58 ++++++++++++++++++++----------- 2 files changed, 51 insertions(+), 20 deletions(-) diff --git a/mrbgems/mruby-rational/mrblib/rational.rb b/mrbgems/mruby-rational/mrblib/rational.rb index 4936b1123..54d9a955f 100644 --- a/mrbgems/mruby-rational/mrblib/rational.rb +++ b/mrbgems/mruby-rational/mrblib/rational.rb @@ -62,6 +62,19 @@ class Rational < Numeric nil end end + + def ==(rhs) + if rhs.is_a?(Integral) + return numerator == rhs if denominator == 1 + rhs = Rational(rhs) + end + + if rhs.is_a?(Rational) + numerator * rhs.denominator == denominator * rhs.numerator + else + rhs == self + end + end end class Numeric diff --git a/mrbgems/mruby-rational/test/rational.rb b/mrbgems/mruby-rational/test/rational.rb index 1ed3b3a07..5e9d9ea48 100644 --- a/mrbgems/mruby-rational/test/rational.rb +++ b/mrbgems/mruby-rational/test/rational.rb @@ -1,3 +1,27 @@ +class UserDefinedNumeric < Numeric + def initialize(n) + @n = n + end + + def <=>(rhs) + return nil unless rhs.respond_to?(:to_i) + rhs = rhs.to_i + rhs < 0 ? nil : @n <=> rhs + end + + def inspect + "#{self.class}(#{@n})" + end +end + +class ComplexLikeNumeric < UserDefinedNumeric + def ==(rhs) + @n == 0 && rhs == 0 + end + + undef <=> +end + def assert_rational(exp, real) assert_float exp.numerator, real.numerator assert_float exp.denominator, real.denominator @@ -17,7 +41,7 @@ def assert_cmp(exp, o1, o2) if exp == (o1 <=> o2) pass else - flunk "", " Expected #{o1.inspect} <=> #{o2.inspect} to be #{exp}" + flunk "", " Expected #{o1.inspect} <=> #{o2.inspect} to be #{exp}." end end @@ -106,6 +130,13 @@ assert 'Rational#==, Rational#!=' do assert_equal_rational(false, Rational(2,1), 1r) assert_equal_rational(false, Rational(1), nil) assert_equal_rational(false, Rational(1), '') + assert_equal_rational(true, 0r, UserDefinedNumeric.new(0)) + assert_equal_rational(true, 1r, UserDefinedNumeric.new(1)) + assert_equal_rational(false, 1r, UserDefinedNumeric.new(2)) + assert_equal_rational(false, -1r, UserDefinedNumeric.new(-1)) + assert_equal_rational(true, 0r, ComplexLikeNumeric.new(0)) + assert_equal_rational(false, 1r, ComplexLikeNumeric.new(1)) + assert_equal_rational(false, 1r, ComplexLikeNumeric.new(2)) end assert 'Fixnum#==(Rational), Fixnum#!=(Rational)' do @@ -123,21 +154,6 @@ assert 'Float#==(Rational), Float#!=(Rational)' do end assert 'Rational#<=>' do - num = Class.new(Numeric) do - def initialize(n) - @n = n - end - - def <=>(rhs) - rhs = rhs.to_i - rhs < 0 ? nil : @n <=> rhs - end - - def inspect - "num(#{@n})" - end - end - assert_cmp(-1, Rational(-1), Rational(0)) assert_cmp(0, Rational(0), Rational(0)) assert_cmp(1, Rational(1), Rational(0)) @@ -158,10 +174,12 @@ assert 'Rational#<=>' do assert_cmp(-1, Rational(1,2), Rational(2,3)) assert_cmp(-1, Rational(1,2), Rational(2,3)) assert_cmp(nil, 3r, "3") - assert_cmp(1, 3r, num.new(2)) - assert_cmp(0, 3r, num.new(3)) - assert_cmp(-1, 3r, num.new(4)) - assert_cmp(nil, Rational(-3), num.new(5)) + assert_cmp(1, 3r, UserDefinedNumeric.new(2)) + assert_cmp(0, 3r, UserDefinedNumeric.new(3)) + assert_cmp(-1, 3r, UserDefinedNumeric.new(4)) + assert_cmp(nil, Rational(-3), UserDefinedNumeric.new(5)) + assert_raise(NoMethodError) { 0r <=> ComplexLikeNumeric.new(0) } + assert_raise(NoMethodError) { 1r <=> ComplexLikeNumeric.new(2) } end assert 'Fixnum#<=>(Rational)' do -- cgit v1.2.3 From a97a455c031c77f01eaae85ce683e9c1346eb8c9 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Mon, 27 May 2019 20:51:47 +0900 Subject: Use `$undefined.equal?(obj2)` instead of `obj2 == $undefined` in `assert.rb` In case `obj2.==` is broken. --- test/assert.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/assert.rb b/test/assert.rb index a9bbc9a05..5e2e104b3 100644 --- a/test/assert.rb +++ b/test/assert.rb @@ -149,7 +149,7 @@ end def assert_operator(*args); _assert_operator(true, *args) end def assert_not_operator(*args); _assert_operator(false, *args) end def _assert_operator(affirmed, obj1, op, obj2 = $undefined, msg = nil) - return _assert_predicate(affirmed, obj1, op, msg) if obj2 == $undefined + return _assert_predicate(affirmed, obj1, op, msg) if $undefined.equal?(obj2) unless ret = obj1.__send__(op, obj2) == affirmed diff = " Expected #{obj1.inspect} to #{'not ' unless affirmed}be #{op} #{obj2.inspect}." end -- cgit v1.2.3 From ffc915fdee4407a7ff757d02795863524a74bce9 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Tue, 28 May 2019 18:26:01 +0900 Subject: Fix missing assertions in `mruby-pack` test --- mrbgems/mruby-pack/test/pack.rb | 79 ++++++++++++++++------------------------- 1 file changed, 30 insertions(+), 49 deletions(-) diff --git a/mrbgems/mruby-pack/test/pack.rb b/mrbgems/mruby-pack/test/pack.rb index 1788c2b72..110aee5db 100644 --- a/mrbgems/mruby-pack/test/pack.rb +++ b/mrbgems/mruby-pack/test/pack.rb @@ -1,101 +1,82 @@ +PACK_IS_LITTLE_ENDIAN = "\x01\00".unpack('S')[0] == 0x01 + +def assert_pack tmpl, packed, unpacked + t = tmpl.inspect + assert_equal packed, unpacked.pack(tmpl), "#{unpacked.inspect}.pack(#{t})" + assert_equal unpacked, packed.unpack(tmpl), "#{packed.inspect}.unpack(#{t})" +end + # pack & unpack 'm' (base64) assert('[""].pack("m")') do - ary = "" - str = "" - [ary].pack("m") == str and - str.unpack("m") == [ary] + assert_pack "m", "", [""] end assert('["\0"].pack("m")') do - ary = "\0" - str = "AA==\n" - [ary].pack("m") == str and - str.unpack("m") == [ary] + assert_pack "m", "AA==\n", ["\0"] end assert('["\0\0"].pack("m")') do - ary = "\0\0" - str = "AAA=\n" - [ary].pack("m") == str and - str.unpack("m") == [ary] + assert_pack "m", "AAA=\n", ["\0\0"] end assert('["\0\0\0"].pack("m")') do - ary = "\0\0\0" - str = "AAAA\n" - [ary].pack("m") == str and - str.unpack("m") == [ary] + assert_pack "m", "AAAA\n", ["\0\0\0"] end assert('["abc..xyzABC..XYZ"].pack("m")') do - ["abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"].pack("m") == "YWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXpBQkNERUZHSElKS0xNTk9QUVJT\nVFVWV1hZWg==\n" + assert_pack "m", "YWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXpBQkNERUZHSElKS0xNTk9QUVJT\nVFVWV1hZWg==\n", ["abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"] end assert('"YWJ...".unpack("m") should "abc..xyzABC..XYZ"') do - str = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" - "YWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXpBQkNERUZHSElKS0xNTk9QUVJT\nVFVWV1hZWg==\n".unpack("m") == [str] and - "YWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXpBQkNERUZHSElKS0xNTk9QUVJTVFVWV1hZWg==\n".unpack("m") == [str] + ary = ["abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"] + assert_equal ary, "YWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXpBQkNERUZHSElKS0xNTk9QUVJT\nVFVWV1hZWg==\n".unpack("m") + assert_equal ary, "YWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXpBQkNERUZHSElKS0xNTk9QUVJTVFVWV1hZWg==\n".unpack("m") end # pack & unpack 'H' assert('["3031"].pack("H*")') do - ary = "3031" - str = "01" - [ary].pack("H*") == str and - str.unpack("H*") == [ary] + assert_pack "H*", "01", ["3031"] end assert('["10"].pack("H*")') do - ary = "10" - str = "\020" - [ary].pack("H*") == str and - str.unpack("H*") == [ary] + assert_pack "H*", "\020", ["10"] end assert('[0,1,127,128,255].pack("C*")') do - ary = [ 0, 1, 127, 128, 255 ] - str = "\x00\x01\x7F\x80\xFF" - ary.pack("C*") == str and str.unpack("C*") == ary + assert_pack "C*", "\x00\x01\x7F\x80\xFF", [0, 1, 127, 128, 255] end # pack "a" assert('["abc"].pack("a")') do - ["abc"].pack("a") == "a" and - ["abc"].pack("a*") == "abc" and - ["abc"].pack("a4") == "abc\0" + assert_equal "a", ["abc"].pack("a") + assert_equal "abc", ["abc"].pack("a*") + assert_equal "abc\0", ["abc"].pack("a4") end # upack "a" assert('["abc"].pack("a")') do - "abc\0".unpack("a4") == ["abc\0"] and - "abc ".unpack("a4") == ["abc "] + assert_equal ["abc\0"], "abc\0".unpack("a4") + assert_equal ["abc "], "abc ".unpack("a4") end # pack "A" assert('["abc"].pack("A")') do - ["abc"].pack("A") == "a" and - ["abc"].pack("A*") == "abc" and - ["abc"].pack("A4") == "abc " + assert_equal "a", ["abc"].pack("A") + assert_equal "abc", ["abc"].pack("A*") + assert_equal "abc ", ["abc"].pack("A4") end # upack "A" assert('["abc"].pack("A")') do - "abc\0".unpack("A4") == ["abc"] and - "abc ".unpack("A4") == ["abc"] + assert_equal ["abc"], "abc\0".unpack("A4") + assert_equal ["abc"], "abc ".unpack("A4") end # regression tests assert('issue #1') do - [1, 2].pack("nn") == "\000\001\000\002" + assert_equal "\000\001\000\002", [1, 2].pack("nn") end -def assert_pack tmpl, packed, unpacked - assert_equal packed, unpacked.pack(tmpl) - assert_equal unpacked, packed.unpack(tmpl) -end - -PACK_IS_LITTLE_ENDIAN = "\x01\00".unpack('S')[0] == 0x01 - assert 'pack float' do assert_pack 'e', "\x00\x00@@", [3.0] assert_pack 'g', "@@\x00\x00", [3.0] -- cgit v1.2.3 From 2b81ea7ec1c7645b13b097e5b249cbc99f374da7 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Tue, 28 May 2019 10:44:18 +0900 Subject: Add `mrb_alloca` again; ref #4470 This time, the allocated memory comes from the string object, which is referenced from GC arena. The memory region will be reclaimed when the C function called from VM is terminated, or the GC arena is restored. --- include/mruby.h | 2 ++ src/gc.c | 7 +++++++ 2 files changed, 9 insertions(+) diff --git a/include/mruby.h b/include/mruby.h index 5d5c759dd..3ef399716 100644 --- a/include/mruby.h +++ b/include/mruby.h @@ -1246,6 +1246,8 @@ MRB_API void mrb_pool_close(struct mrb_pool*); MRB_API void* mrb_pool_alloc(struct mrb_pool*, size_t); MRB_API void* mrb_pool_realloc(struct mrb_pool*, void*, size_t oldlen, size_t newlen); MRB_API mrb_bool mrb_pool_can_realloc(struct mrb_pool*, void*, size_t); +/* temporary memory allocation, only effective while GC arena is kept */ +MRB_API void* mrb_alloca(mrb_state *mrb, size_t); MRB_API void mrb_state_atexit(mrb_state *mrb, mrb_atexit_func func); diff --git a/src/gc.c b/src/gc.c index 6dc8e373b..94068c0f9 100644 --- a/src/gc.c +++ b/src/gc.c @@ -277,6 +277,13 @@ mrb_free(mrb_state *mrb, void *p) (mrb->allocf)(mrb, p, 0, mrb->allocf_ud); } +MRB_API void* +mrb_alloca(mrb_state *mrb, size_t size) +{ + mrb_value str = mrb_str_new(mrb, NULL, size); + return RSTRING_PTR(str); +} + static mrb_bool heap_p(mrb_gc *gc, struct RBasic *object) { -- cgit v1.2.3 From 855f2cdeea5c305e71721ef3c146eaa6472815b8 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Wed, 29 May 2019 11:49:21 +0900 Subject: Slightly simplify `Rational#==`; ref #4475 --- mrbgems/mruby-rational/mrblib/rational.rb | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/mrbgems/mruby-rational/mrblib/rational.rb b/mrbgems/mruby-rational/mrblib/rational.rb index 54d9a955f..93af72b96 100644 --- a/mrbgems/mruby-rational/mrblib/rational.rb +++ b/mrbgems/mruby-rational/mrblib/rational.rb @@ -64,11 +64,10 @@ class Rational < Numeric end def ==(rhs) - if rhs.is_a?(Integral) - return numerator == rhs if denominator == 1 - rhs = Rational(rhs) + return true if self.equal?(rhs) + if rhs.is_a?(Integral) && denominator == 1 + return numerator == rhs end - if rhs.is_a?(Rational) numerator * rhs.denominator == denominator * rhs.numerator else -- cgit v1.2.3 From 03fce2e206128d6ae7fc5b7e3c66826446a5bad1 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Wed, 29 May 2019 15:57:18 +0900 Subject: `Kernel#itself` should not be a module function --- mrbgems/mruby-object-ext/src/object.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/mrbgems/mruby-object-ext/src/object.c b/mrbgems/mruby-object-ext/src/object.c index d3e7a9c50..85db75b28 100644 --- a/mrbgems/mruby-object-ext/src/object.c +++ b/mrbgems/mruby-object-ext/src/object.c @@ -118,7 +118,8 @@ mrb_mruby_object_ext_gem_init(mrb_state* mrb) mrb_define_method(mrb, n, "to_f", nil_to_f, MRB_ARGS_NONE()); #endif mrb_define_method(mrb, n, "to_i", nil_to_i, MRB_ARGS_NONE()); - mrb_define_module_function(mrb, mrb->kernel_module, "itself", mrb_f_itself, MRB_ARGS_NONE()); + + mrb_define_method(mrb, mrb->kernel_module, "itself", mrb_f_itself, MRB_ARGS_NONE()); mrb_define_method(mrb, mrb_class_get(mrb, "BasicObject"), "instance_exec", mrb_obj_instance_exec, MRB_ARGS_ANY() | MRB_ARGS_BLOCK()); } -- cgit v1.2.3 From 729931a06c0eebb8c1eaa471f2a1d16192deca9f Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Thu, 30 May 2019 12:33:41 +0900 Subject: Fix inverted compilation condition; fix #4478 --- src/numeric.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/numeric.c b/src/numeric.c index 608b4f289..0d1c23589 100644 --- a/src/numeric.c +++ b/src/numeric.c @@ -1347,7 +1347,7 @@ mrb_num_minus(mrb_state *mrb, mrb_value x, mrb_value y) if (mrb_fixnum_p(x)) { return fixnum_minus(mrb, x, y); } -#ifdef MRB_WITHOUT_FLOAT +#ifndef MRB_WITHOUT_FLOAT if (mrb_float_p(x)) { return mrb_float_value(mrb, mrb_float(x) - mrb_to_flo(mrb, y)); } -- cgit v1.2.3 From 05056ddac4096d1500c975d32f545ff01b3ec5d6 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Thu, 30 May 2019 21:42:01 +0900 Subject: Fix missing assertions in `mruby-fiber` test --- mrbgems/mruby-fiber/test/fiber.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mrbgems/mruby-fiber/test/fiber.rb b/mrbgems/mruby-fiber/test/fiber.rb index d063a0a62..b6ecb798c 100644 --- a/mrbgems/mruby-fiber/test/fiber.rb +++ b/mrbgems/mruby-fiber/test/fiber.rb @@ -76,7 +76,7 @@ assert('Fiber iteration') do end assert('Fiber with splat in the block argument list') { - Fiber.new{|*x|x}.resume(1) == [1] + assert_equal([1], Fiber.new{|*x|x}.resume(1)) } assert('Fiber raises on resume when dead') do -- cgit v1.2.3 From c1e6f324c29d16014a8c6c27b9e27cf9af9fc1d5 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Fri, 31 May 2019 20:50:54 +0900 Subject: Comment out the empty `Array#bsearch_index` test --- mrbgems/mruby-array-ext/test/array.rb | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/mrbgems/mruby-array-ext/test/array.rb b/mrbgems/mruby-array-ext/test/array.rb index 853554bcc..82f09297a 100644 --- a/mrbgems/mruby-array-ext/test/array.rb +++ b/mrbgems/mruby-array-ext/test/array.rb @@ -268,9 +268,9 @@ assert("Array#bsearch") do end end -assert("Array#bsearch_index") do - # tested through Array#bsearch -end +# tested through Array#bsearch +#assert("Array#bsearch_index") do +#end assert("Array#delete_if") do a = [1, 2, 3, 4, 5] -- cgit v1.2.3 From 92f00d3e58e91d513a483f87e0ee9eb17147d516 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Sun, 2 Jun 2019 19:15:20 +0900 Subject: Fix missing assertions in `mruby-objectspace` test --- mrbgems/mruby-objectspace/test/objectspace.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mrbgems/mruby-objectspace/test/objectspace.rb b/mrbgems/mruby-objectspace/test/objectspace.rb index 8db89eeaf..9c44c2157 100644 --- a/mrbgems/mruby-objectspace/test/objectspace.rb +++ b/mrbgems/mruby-objectspace/test/objectspace.rb @@ -56,5 +56,5 @@ assert('ObjectSpace.each_object') do end assert 'Check class pointer of ObjectSpace.each_object.' do - ObjectSpace.each_object { |obj| !obj } + assert_nothing_raised { ObjectSpace.each_object { |obj| !obj } } end -- cgit v1.2.3 From c75402a57b0f06dcdb62fc176ffa533c6eb6e73d Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Tue, 4 Jun 2019 10:45:13 +0900 Subject: Fix typo in `mrblib/range.rb` [ci skip] --- mrblib/range.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mrblib/range.rb b/mrblib/range.rb index 5bd2521e8..392cc2274 100644 --- a/mrblib/range.rb +++ b/mrblib/range.rb @@ -26,7 +26,7 @@ class Range return self end - if val.kind_of?(String) && last.kind_of?(String) # fixnums are special + if val.kind_of?(String) && last.kind_of?(String) # strings are special if val.respond_to? :upto return val.upto(last, exclude_end?, &block) else -- cgit v1.2.3 From 81ea89f10ee60ef67284bd8d92adc4292d217c3f Mon Sep 17 00:00:00 2001 From: dearblue Date: Tue, 4 Jun 2019 21:41:40 +0900 Subject: Need explicit cast for C++ --- include/mruby/data.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/mruby/data.h b/include/mruby/data.h index d85edeb3a..54466dcd6 100644 --- a/include/mruby/data.h +++ b/include/mruby/data.h @@ -41,7 +41,7 @@ MRB_API struct RData *mrb_data_object_alloc(mrb_state *mrb, struct RClass* klass #define Data_Make_Struct(mrb,klass,strct,type,sval,data_obj) do { \ (data_obj) = Data_Wrap_Struct(mrb,klass,type,NULL);\ - (sval) = mrb_malloc(mrb, sizeof(strct)); \ + (sval) = (strct *)mrb_malloc(mrb, sizeof(strct)); \ { static const strct zero = { 0 }; *(sval) = zero; };\ (data_obj)->data = (sval);\ } while (0) -- cgit v1.2.3 From dc1905e1bd8af679c639a67a6787fc41a2612603 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Wed, 5 Jun 2019 18:59:48 +0900 Subject: Fix missing assertions in `test/t/module.rb` --- test/t/module.rb | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/test/t/module.rb b/test/t/module.rb index f4999019a..3bb9735df 100644 --- a/test/t/module.rb +++ b/test/t/module.rb @@ -684,8 +684,8 @@ assert('Issue 1467') do include M1 end - C1.new - C2.new + assert_kind_of(M1, C1.new) + assert_kind_of(M1, C2.new) end assert('clone Module') do @@ -699,7 +699,7 @@ assert('clone Module') do include M1.clone end - B.new.foo + assert_true(B.new.foo) end assert('Module#module_function') do -- cgit v1.2.3 From 97e999c409fbbe46fd4154e4be292f182f42b771 Mon Sep 17 00:00:00 2001 From: dearblue Date: Sun, 2 Jun 2019 10:43:54 +0900 Subject: Fix memory leak in `Complex` method by `RData` If `Data_Wrap_Struct()` raises a `NoMemoryError` exception, it will leak memory if it does `mrb_malloc()` first. --- mrbgems/mruby-complex/src/complex.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/mrbgems/mruby-complex/src/complex.c b/mrbgems/mruby-complex/src/complex.c index 5371332cd..a727eb604 100644 --- a/mrbgems/mruby-complex/src/complex.c +++ b/mrbgems/mruby-complex/src/complex.c @@ -40,12 +40,13 @@ complex_new(mrb_state *mrb, mrb_float real, mrb_float imaginary) { struct RClass *c = mrb_class_get(mrb, "Complex"); struct mrb_complex *p; + struct RData *d; - p = (struct mrb_complex*)mrb_malloc(mrb, sizeof(struct mrb_complex)); + Data_Make_Struct(mrb, c, struct mrb_complex, &mrb_complex_type, p, d); p->real = real; p->imaginary = imaginary; - return mrb_obj_value(Data_Wrap_Struct(mrb, c, &mrb_complex_type, p)); + return mrb_obj_value(d); } static struct mrb_complex* -- cgit v1.2.3 From 82831c6acd116852e918094e940266152897056e Mon Sep 17 00:00:00 2001 From: dearblue Date: Sun, 2 Jun 2019 11:05:53 +0900 Subject: Fix not frozen in `Complex` method by `RData` Object allocation was separated, and initialization was made common. --- mrbgems/mruby-complex/src/complex.c | 42 +++++++++++++++++++++---------------- 1 file changed, 24 insertions(+), 18 deletions(-) diff --git a/mrbgems/mruby-complex/src/complex.c b/mrbgems/mruby-complex/src/complex.c index a727eb604..8a0569d68 100644 --- a/mrbgems/mruby-complex/src/complex.c +++ b/mrbgems/mruby-complex/src/complex.c @@ -15,18 +15,15 @@ struct mrb_complex { #define complex_ptr(mrb, v) (struct mrb_complex*)mrb_istruct_ptr(v) -static mrb_value -complex_new(mrb_state *mrb, mrb_float real, mrb_float imaginary) +static struct RBasic* +complex_alloc(mrb_state *mrb, struct RClass *c, struct mrb_complex **p) { - struct RClass *c = mrb_class_get(mrb, "Complex"); - struct RIStruct *s = (struct RIStruct*)mrb_obj_alloc(mrb, MRB_TT_ISTRUCT, c); - mrb_value comp = mrb_obj_value(s); - struct mrb_complex *p = complex_ptr(mrb, comp); - p->real = real; - p->imaginary = imaginary; - MRB_SET_FROZEN_FLAG(s); + struct RIStruct *s; + + s = (struct RIStruct*)mrb_obj_alloc(mrb, MRB_TT_ISTRUCT, c); + *p = (struct mrb_complex*)s->inline_data; - return comp; + return (struct RBasic*)s; } #else @@ -35,18 +32,14 @@ complex_new(mrb_state *mrb, mrb_float real, mrb_float imaginary) static const struct mrb_data_type mrb_complex_type = {"Complex", mrb_free}; -static mrb_value -complex_new(mrb_state *mrb, mrb_float real, mrb_float imaginary) +static struct RBasic* +complex_alloc(mrb_state *mrb, struct RClass *c, struct mrb_complex **p) { - struct RClass *c = mrb_class_get(mrb, "Complex"); - struct mrb_complex *p; struct RData *d; - Data_Make_Struct(mrb, c, struct mrb_complex, &mrb_complex_type, p, d); - p->real = real; - p->imaginary = imaginary; + Data_Make_Struct(mrb, c, struct mrb_complex, &mrb_complex_type, *p, d); - return mrb_obj_value(d); + return (struct RBasic*)d; } static struct mrb_complex* @@ -62,6 +55,19 @@ complex_ptr(mrb_state *mrb, mrb_value v) } #endif +static mrb_value +complex_new(mrb_state *mrb, mrb_float real, mrb_float imaginary) +{ + struct RClass *c = mrb_class_get(mrb, "Complex"); + struct mrb_complex *p; + struct RBasic *comp = complex_alloc(mrb, c, &p); + p->real = real; + p->imaginary = imaginary; + MRB_SET_FROZEN_FLAG(comp); + + return mrb_obj_value(comp); +} + static mrb_value complex_real(mrb_state *mrb, mrb_value self) { -- cgit v1.2.3 From 5e69760d919dd468ea8c8285f0f24affb52d3045 Mon Sep 17 00:00:00 2001 From: dearblue Date: Sun, 2 Jun 2019 17:21:33 +0900 Subject: Fix build error if `struct mrb_rational` is bigger than `RIStruct` In that case, to be switched implementation with `RData`. It is based to "complex". --- mrbgems/mruby-rational/src/rational.c | 69 ++++++++++++++++++++++++++++------- 1 file changed, 55 insertions(+), 14 deletions(-) diff --git a/mrbgems/mruby-rational/src/rational.c b/mrbgems/mruby-rational/src/rational.c index fa061c0b8..db9a8fbb9 100644 --- a/mrbgems/mruby-rational/src/rational.c +++ b/mrbgems/mruby-rational/src/rational.c @@ -1,30 +1,71 @@ #include #include #include -#include struct mrb_rational { mrb_int numerator; mrb_int denominator; }; +#if MRB_INT_MAX <= INTPTR_MAX + +#define RATIONAL_USE_ISTRUCT +/* use TT_ISTRUCT */ +#include + +#define rational_ptr(mrb, v) (struct mrb_rational*)mrb_istruct_ptr(v) + +static struct RBasic* +rational_alloc(mrb_state *mrb, struct RClass *c, struct mrb_rational **p) +{ + struct RIStruct *s; + + s = (struct RIStruct*)mrb_obj_alloc(mrb, MRB_TT_ISTRUCT, c); + *p = (struct mrb_rational*)s->inline_data; + + return (struct RBasic*)s; +} + +#else +/* use TT_DATA */ +#include + +static const struct mrb_data_type mrb_rational_type = {"Rational", mrb_free}; + +static struct RBasic* +rational_alloc(mrb_state *mrb, struct RClass *c, struct mrb_rational **p) +{ + struct RData *d; + + Data_Make_Struct(mrb, c, struct mrb_rational, &mrb_rational_type, *p, d); + + return (struct RBasic*)d; +} + static struct mrb_rational* -rational_ptr(mrb_value v) +rational_ptr(mrb_state *mrb, mrb_value v) { - return (struct mrb_rational*)mrb_istruct_ptr(v); + struct mrb_rational *p; + + p = DATA_GET_PTR(mrb, v, &mrb_rational_type, struct mrb_rational); + if (!p) { + mrb_raise(mrb, E_ARGUMENT_ERROR, "uninitialized rational"); + } + return p; } +#endif static mrb_value rational_numerator(mrb_state *mrb, mrb_value self) { - struct mrb_rational *p = rational_ptr(self); + struct mrb_rational *p = rational_ptr(mrb, self); return mrb_fixnum_value(p->numerator); } static mrb_value rational_denominator(mrb_state *mrb, mrb_value self) { - struct mrb_rational *p = rational_ptr(self); + struct mrb_rational *p = rational_ptr(mrb, self); return mrb_fixnum_value(p->denominator); } @@ -32,13 +73,12 @@ static mrb_value rational_new(mrb_state *mrb, mrb_int numerator, mrb_int denominator) { struct RClass *c = mrb_class_get(mrb, "Rational"); - struct RIStruct *s = (struct RIStruct*)mrb_obj_alloc(mrb, MRB_TT_ISTRUCT, c); - mrb_value rat = mrb_obj_value(s); - struct mrb_rational *p = rational_ptr(rat); + struct mrb_rational *p; + struct RBasic *rat = rational_alloc(mrb, c, &p); p->numerator = numerator; p->denominator = denominator; - MRB_SET_FROZEN_FLAG(s); - return rat; + MRB_SET_FROZEN_FLAG(rat); + return mrb_obj_value(rat); } static mrb_value @@ -54,7 +94,7 @@ rational_s_new(mrb_state *mrb, mrb_value self) static mrb_value rational_to_f(mrb_state *mrb, mrb_value self) { - struct mrb_rational *p = rational_ptr(self); + struct mrb_rational *p = rational_ptr(mrb, self); mrb_float f = (mrb_float)p->numerator / (mrb_float)p->denominator; return mrb_float_value(mrb, f); @@ -64,7 +104,7 @@ rational_to_f(mrb_state *mrb, mrb_value self) static mrb_value rational_to_i(mrb_state *mrb, mrb_value self) { - struct mrb_rational *p = rational_ptr(self); + struct mrb_rational *p = rational_ptr(mrb, self); return mrb_fixnum_value(p->numerator / p->denominator); } @@ -77,7 +117,7 @@ rational_to_r(mrb_state *mrb, mrb_value self) static mrb_value rational_negative_p(mrb_state *mrb, mrb_value self) { - struct mrb_rational *p = rational_ptr(self); + struct mrb_rational *p = rational_ptr(mrb, self); if (p->numerator < 0) { return mrb_true_value(); } @@ -94,9 +134,10 @@ void mrb_mruby_rational_gem_init(mrb_state *mrb) { struct RClass *rat; +#ifdef COMPLEX_USE_RATIONAL mrb_assert(sizeof(struct mrb_rational) < ISTRUCT_DATA_SIZE); +#endif rat = mrb_define_class(mrb, "Rational", mrb_class_get(mrb, "Numeric")); - MRB_SET_INSTANCE_TT(rat, MRB_TT_ISTRUCT); 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()); -- cgit v1.2.3 From 64b3d452ec1cc3d5547da9ca37179f0e4406cc92 Mon Sep 17 00:00:00 2001 From: dearblue Date: Sun, 2 Jun 2019 18:00:54 +0900 Subject: Drop precisions for rational when big numbers --- mrbgems/mruby-rational/src/rational.c | 49 +++++++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) diff --git a/mrbgems/mruby-rational/src/rational.c b/mrbgems/mruby-rational/src/rational.c index db9a8fbb9..31471e934 100644 --- a/mrbgems/mruby-rational/src/rational.c +++ b/mrbgems/mruby-rational/src/rational.c @@ -1,6 +1,7 @@ #include #include #include +#include struct mrb_rational { mrb_int numerator; @@ -86,7 +87,52 @@ rational_s_new(mrb_state *mrb, mrb_value self) { mrb_int numerator, denominator; +#ifdef MRB_WITHOUT_FLOAT mrb_get_args(mrb, "ii", &numerator, &denominator); +#else + +#define DROP_PRECISION(cond, num, denom) \ + do { \ + while (cond) { \ + num /= 2; \ + denom /= 2; \ + } \ + } while (0) + + mrb_value numv, denomv; + + mrb_get_args(mrb, "oo", &numv, &denomv); + if (mrb_fixnum_p(numv)) { + numerator = mrb_fixnum(numv); + + if (mrb_fixnum_p(denomv)) { + denominator = mrb_fixnum(denomv); + } + else { + mrb_float denomf = mrb_to_flo(mrb, denomv); + + DROP_PRECISION(denomf < MRB_INT_MIN || denomf > MRB_INT_MAX, numerator, denomf); + denominator = denomf; + } + } + else { + mrb_float numf = mrb_to_flo(mrb, numv); + + if (mrb_fixnum_p(denomv)) { + denominator = mrb_fixnum(denomv); + } + else { + mrb_float denomf = mrb_to_flo(mrb, denomv); + + DROP_PRECISION(denomf < MRB_INT_MIN || denomf > MRB_INT_MAX, numf, denomf); + denominator = denomf; + } + + DROP_PRECISION(numf < MRB_INT_MIN || numf > MRB_INT_MAX, numf, denominator); + numerator = numf; + } +#endif + return rational_new(mrb, numerator, denominator); } @@ -105,6 +151,9 @@ static mrb_value rational_to_i(mrb_state *mrb, mrb_value self) { struct mrb_rational *p = rational_ptr(mrb, self); + if (p->denominator == 0) { + mrb_raise(mrb, mrb_exc_get(mrb, "StandardError"), "divided by 0"); + } return mrb_fixnum_value(p->numerator / p->denominator); } -- cgit v1.2.3 From 05493e651db15dd5c870b47556b4f9b54dfccee3 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Thu, 6 Jun 2019 20:21:40 +0900 Subject: Clarify `mruby-(kernel|object)-ext` gem summary; ref 8e637bdd [ci skip] --- mrbgems/mruby-kernel-ext/mrbgem.rake | 2 +- mrbgems/mruby-object-ext/mrbgem.rake | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/mrbgems/mruby-kernel-ext/mrbgem.rake b/mrbgems/mruby-kernel-ext/mrbgem.rake index fcb3a83b0..e52c63a55 100644 --- a/mrbgems/mruby-kernel-ext/mrbgem.rake +++ b/mrbgems/mruby-kernel-ext/mrbgem.rake @@ -1,5 +1,5 @@ MRuby::Gem::Specification.new('mruby-kernel-ext') do |spec| spec.license = 'MIT' spec.author = 'mruby developers' - spec.summary = 'Kernel module extension' + spec.summary = 'extensional function-like methods' end diff --git a/mrbgems/mruby-object-ext/mrbgem.rake b/mrbgems/mruby-object-ext/mrbgem.rake index 6d14b4a51..1aea2c8cd 100644 --- a/mrbgems/mruby-object-ext/mrbgem.rake +++ b/mrbgems/mruby-object-ext/mrbgem.rake @@ -1,5 +1,5 @@ MRuby::Gem::Specification.new('mruby-object-ext') do |spec| spec.license = 'MIT' spec.author = 'mruby developers' - spec.summary = 'Object class extension' + spec.summary = 'extensional methods shared by all objects' end -- cgit v1.2.3 From 4b83fe8b04f61e62d851648c0fe95e8e575181d5 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Fri, 7 Jun 2019 22:02:43 +0900 Subject: Remove `Kernel#global_variables` from core This method is defined in `mruby-metaprog` gem. --- mrbgems/mruby-metaprog/src/metaprog.c | 2 +- mrbgems/mruby-metaprog/test/metaprog.rb | 12 ++++++++++++ src/kernel.c | 1 - test/t/kernel.rb | 15 --------------- 4 files changed, 13 insertions(+), 17 deletions(-) diff --git a/mrbgems/mruby-metaprog/src/metaprog.c b/mrbgems/mruby-metaprog/src/metaprog.c index e57d10d8d..43d27f4dc 100644 --- a/mrbgems/mruby-metaprog/src/metaprog.c +++ b/mrbgems/mruby-metaprog/src/metaprog.c @@ -686,7 +686,7 @@ mrb_mruby_metaprog_gem_init(mrb_state* mrb) struct RClass *krn = mrb->kernel_module; struct RClass *mod = mrb->module_class; - mrb_define_method(mrb, krn, "global_variables", mrb_f_global_variables, MRB_ARGS_NONE()); /* 15.3.1.2.4 */ + mrb_define_method(mrb, krn, "global_variables", mrb_f_global_variables, MRB_ARGS_NONE()); /* 15.3.1.3.14 (15.3.1.2.4) */ mrb_define_method(mrb, krn, "local_variables", mrb_local_variables, MRB_ARGS_NONE()); /* 15.3.1.3.28 */ mrb_define_method(mrb, krn, "singleton_class", mrb_singleton_class, MRB_ARGS_NONE()); diff --git a/mrbgems/mruby-metaprog/test/metaprog.rb b/mrbgems/mruby-metaprog/test/metaprog.rb index 3aa1d8732..329580abc 100644 --- a/mrbgems/mruby-metaprog/test/metaprog.rb +++ b/mrbgems/mruby-metaprog/test/metaprog.rb @@ -99,6 +99,18 @@ assert('Kernel#singleton_methods', '15.3.1.3.45') do assert_equal singleton_methods.class, Array end +assert('Kernel.global_variables', '15.3.1.2.4') do + assert_equal Array, Kernel.global_variables.class +end + +assert('Kernel#global_variables', '15.3.1.3.14') do + variables = global_variables + assert_equal Array, variables.class + 1.upto(9) do |i| + assert_equal variables.include?(:"$#{i}"), true + end +end + assert('Kernel.local_variables', '15.3.1.2.7') do a, b = 0, 1 a += b diff --git a/src/kernel.c b/src/kernel.c index 349e71cb8..a3c2d2ec6 100644 --- a/src/kernel.c +++ b/src/kernel.c @@ -783,7 +783,6 @@ mrb_init_kernel(mrb_state *mrb) mrb_define_method(mrb, krn, "extend", mrb_obj_extend_m, MRB_ARGS_ANY()); /* 15.3.1.3.13 */ mrb_define_method(mrb, krn, "freeze", mrb_obj_freeze, MRB_ARGS_NONE()); mrb_define_method(mrb, krn, "frozen?", mrb_obj_frozen, MRB_ARGS_NONE()); - mrb_define_method(mrb, krn, "global_variables", mrb_f_global_variables, MRB_ARGS_NONE()); /* 15.3.1.3.14 */ mrb_define_method(mrb, krn, "hash", mrb_obj_hash, MRB_ARGS_NONE()); /* 15.3.1.3.15 */ mrb_define_method(mrb, krn, "initialize_copy", mrb_obj_init_copy, MRB_ARGS_REQ(1)); /* 15.3.1.3.16 */ mrb_define_method(mrb, krn, "inspect", mrb_obj_inspect, MRB_ARGS_NONE()); /* 15.3.1.3.17 */ diff --git a/test/t/kernel.rb b/test/t/kernel.rb index bf7dbe94c..7f6e6c58d 100644 --- a/test/t/kernel.rb +++ b/test/t/kernel.rb @@ -31,10 +31,6 @@ end # Kernel.eval is provided by the mruby-gem mrbgem. '15.3.1.2.3' -assert('Kernel.global_variables', '15.3.1.2.4') do - assert_equal Array, Kernel.global_variables.class -end - assert('Kernel.iterator?', '15.3.1.2.5') do assert_false Kernel.iterator? end @@ -266,10 +262,6 @@ assert('Kernel#frozen?') do assert_true 0.0.frozen? end -assert('Kernel#global_variables', '15.3.1.3.14') do - assert_equal Array, global_variables.class -end - assert('Kernel#hash', '15.3.1.3.15') do assert_equal hash, hash end @@ -488,13 +480,6 @@ assert('Kernel#respond_to_missing?') do assert_false Test4RespondToMissing.new.respond_to?(:no_method) end -assert('Kernel#global_variables') do - variables = global_variables - 1.upto(9) do |i| - assert_equal variables.include?(:"$#{i}"), true - end -end - assert('stack extend') do def recurse(count, stop) return count if count > stop -- cgit v1.2.3 From f8f75fc9c66d834fa81632b113dad5713e2b42b4 Mon Sep 17 00:00:00 2001 From: dearblue Date: Fri, 7 Jun 2019 22:54:03 +0900 Subject: Replace obsolete macros --- mrbgems/mruby-io/src/file_test.c | 2 +- mrbgems/mruby-io/src/io.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/mrbgems/mruby-io/src/file_test.c b/mrbgems/mruby-io/src/file_test.c index 5d5ecb93f..85a221ff9 100644 --- a/mrbgems/mruby-io/src/file_test.c +++ b/mrbgems/mruby-io/src/file_test.c @@ -44,7 +44,7 @@ mrb_stat0(mrb_state *mrb, mrb_value obj, struct stat *st, int do_lstat) { if (mrb_obj_is_kind_of(mrb, obj, mrb_class_get(mrb, "IO"))) { struct mrb_io *fptr; - fptr = (struct mrb_io *)mrb_get_datatype(mrb, obj, &mrb_io_type); + fptr = (struct mrb_io *)mrb_data_get_ptr(mrb, obj, &mrb_io_type); if (fptr && fptr->fd >= 0) { return fstat(fptr->fd, st); diff --git a/mrbgems/mruby-io/src/io.c b/mrbgems/mruby-io/src/io.c index e5b83e923..99441f16b 100644 --- a/mrbgems/mruby-io/src/io.c +++ b/mrbgems/mruby-io/src/io.c @@ -79,7 +79,7 @@ io_get_open_fptr(mrb_state *mrb, mrb_value self) { struct mrb_io *fptr; - fptr = (struct mrb_io *)mrb_get_datatype(mrb, self, &mrb_io_type); + fptr = (struct mrb_io *)mrb_data_get_ptr(mrb, self, &mrb_io_type); if (fptr == NULL) { mrb_raise(mrb, E_IO_ERROR, "uninitialized stream."); } @@ -955,7 +955,7 @@ mrb_value mrb_io_closed(mrb_state *mrb, mrb_value io) { struct mrb_io *fptr; - fptr = (struct mrb_io *)mrb_get_datatype(mrb, io, &mrb_io_type); + fptr = (struct mrb_io *)mrb_data_get_ptr(mrb, io, &mrb_io_type); if (fptr == NULL || fptr->fd >= 0) { return mrb_false_value(); } -- cgit v1.2.3 From 2e160f53dbd69598ec6a3ee8a15f85b4cf5168cf Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Sat, 8 Jun 2019 22:32:19 +0900 Subject: Remove "Check the usage of a NUL character" test Because there is not assertion in this test and NUL character literal is used in other tests. --- test/t/string.rb | 4 ---- 1 file changed, 4 deletions(-) diff --git a/test/t/string.rb b/test/t/string.rb index e5b001366..9817dd188 100644 --- a/test/t/string.rb +++ b/test/t/string.rb @@ -694,10 +694,6 @@ assert('String interpolation (mrb_str_concat for shared strings)') do assert_equal "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA:", "#{a}:" end -assert('Check the usage of a NUL character') do - "qqq\0ppp" -end - assert('String#bytes') do str1 = "hello" bytes1 = [104, 101, 108, 108, 111] -- cgit v1.2.3 From ffb700dea0a23930e4f620cf5ff9855efa709f9c Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Sun, 9 Jun 2019 18:27:28 +0900 Subject: Fix missing assertions in `test/t/syntax.rb` --- test/t/syntax.rb | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/test/t/syntax.rb b/test/t/syntax.rb index 603547c7c..afb735e7f 100644 --- a/test/t/syntax.rb +++ b/test/t/syntax.rb @@ -423,10 +423,11 @@ assert('parenthesed do-block in cmdarg') do end assert('method definition in cmdarg') do - if false + result = class MethodDefinitionInCmdarg + def self.bar(arg); arg end bar def foo; self.each do end end end - true + assert_equal(:foo, result) end assert('optional argument in the rhs default expressions') do -- cgit v1.2.3 From 38f1da6f26bde5185612b66a1b1fc94f78654d78 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Mon, 10 Jun 2019 18:46:57 +0900 Subject: `Kernel#global_variables` should not include undefined `$1`-`$9` - They are not include in Ruby. - Appear in duplicate when `$1`-`$9` are defined. --- mrbgems/mruby-metaprog/test/metaprog.rb | 13 ++++++++----- src/variable.c | 8 -------- 2 files changed, 8 insertions(+), 13 deletions(-) diff --git a/mrbgems/mruby-metaprog/test/metaprog.rb b/mrbgems/mruby-metaprog/test/metaprog.rb index 329580abc..685fdf196 100644 --- a/mrbgems/mruby-metaprog/test/metaprog.rb +++ b/mrbgems/mruby-metaprog/test/metaprog.rb @@ -104,11 +104,14 @@ assert('Kernel.global_variables', '15.3.1.2.4') do end assert('Kernel#global_variables', '15.3.1.3.14') do - variables = global_variables - assert_equal Array, variables.class - 1.upto(9) do |i| - assert_equal variables.include?(:"$#{i}"), true - end + variables1 = global_variables + assert_equal Array, variables1.class + assert_not_include(variables1, :$kernel_global_variables_test) + + $kernel_global_variables_test = nil + variables2 = global_variables + assert_include(variables2, :$kernel_global_variables_test) + assert_equal(1, variables2.size - variables1.size) end assert('Kernel.local_variables', '15.3.1.2.7') do diff --git a/src/variable.c b/src/variable.c index ee21a3b96..779f206dc 100644 --- a/src/variable.c +++ b/src/variable.c @@ -965,16 +965,8 @@ mrb_f_global_variables(mrb_state *mrb, mrb_value self) { iv_tbl *t = mrb->globals; mrb_value ary = mrb_ary_new(mrb); - size_t i; - char buf[3]; iv_foreach(mrb, t, gv_i, &ary); - buf[0] = '$'; - buf[2] = 0; - for (i = 1; i <= 9; ++i) { - buf[1] = (char)(i + '0'); - mrb_ary_push(mrb, ary, mrb_symbol_value(mrb_intern(mrb, buf, 2))); - } return ary; } -- cgit v1.2.3 From 3b9b326d3ccd21e45f498272c8bb8d3f338ccd60 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Tue, 11 Jun 2019 18:55:39 +0900 Subject: Remove redundant colon in `Proc#inspect` (`mruby-proc-ext`) Before this patch: $ bin/mruby -e 'p proc{}' #=> # After this patch: $ bin/mruby -e 'p proc{}' #=> # --- mrbgems/mruby-proc-ext/src/proc.c | 4 ++-- mrbgems/mruby-proc-ext/test/proc.rb | 26 +++++++++++++++++++++----- 2 files changed, 23 insertions(+), 7 deletions(-) diff --git a/mrbgems/mruby-proc-ext/src/proc.c b/mrbgems/mruby-proc-ext/src/proc.c index 17884e3c6..c9041ec75 100644 --- a/mrbgems/mruby-proc-ext/src/proc.c +++ b/mrbgems/mruby-proc-ext/src/proc.c @@ -38,7 +38,7 @@ mrb_proc_inspect(mrb_state *mrb, mrb_value self) { struct RProc *p = mrb_proc_ptr(self); mrb_value str = mrb_str_new_lit(mrb, "#body.irep; @@ -52,7 +52,7 @@ mrb_proc_inspect(mrb_state *mrb, mrb_value self) line = mrb_debug_get_line(mrb, irep, 0); if (line != -1) { - str = mrb_format(mrb, "%S:%S", str, mrb_fixnum_value(line)); + mrb_str_concat(mrb, str, mrb_fixnum_value(line)); } else { mrb_str_cat_lit(mrb, str, "-"); diff --git a/mrbgems/mruby-proc-ext/test/proc.rb b/mrbgems/mruby-proc-ext/test/proc.rb index 1220841c8..a6321d371 100644 --- a/mrbgems/mruby-proc-ext/test/proc.rb +++ b/mrbgems/mruby-proc-ext/test/proc.rb @@ -1,16 +1,32 @@ ## # Proc(Ext) Test +def enable_debug_info? + return @enable_debug_info unless @enable_debug_info == nil + begin + raise + rescue => e + @enable_debug_info = !e.backtrace.empty? + end +end + assert('Proc#source_location') do - loc = Proc.new {}.source_location - next true if loc.nil? - assert_equal loc[0][-7, 7], 'proc.rb' - assert_equal loc[1], 5 + skip unless enable_debug_info? + file, line = Proc.new{}.source_location + assert_equal __FILE__, file + assert_equal __LINE__ - 2, line end assert('Proc#inspect') do ins = Proc.new{}.inspect - assert_kind_of String, ins + if enable_debug_info? + metas = %w(\\ * ? [ ] { }) + file = __FILE__.split("").map{|c| metas.include?(c) ? "\\#{c}" : c}.join + line = __LINE__ - 4 + else + file = line = "-" + end + assert_match "#", ins end assert('Proc#parameters') do -- cgit v1.2.3 From ee955b58f7818248626e3aa66a6bff17dbd6060f Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Wed, 12 Jun 2019 18:52:58 +0900 Subject: Adjust allocation size in `mrb_id_attrset()` (`mruby-struct`) --- mrbgems/mruby-struct/src/struct.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/mrbgems/mruby-struct/src/struct.c b/mrbgems/mruby-struct/src/struct.c index 1df135a9f..6edc5444b 100644 --- a/mrbgems/mruby-struct/src/struct.c +++ b/mrbgems/mruby-struct/src/struct.c @@ -129,10 +129,9 @@ mrb_id_attrset(mrb_state *mrb, mrb_sym id) mrb_sym mid; name = mrb_sym2name_len(mrb, id, &len); - buf = (char *)mrb_malloc(mrb, (size_t)len+2); + buf = (char *)mrb_malloc(mrb, (size_t)len+1); memcpy(buf, name, (size_t)len); buf[len] = '='; - buf[len+1] = '\0'; mid = mrb_intern(mrb, buf, len+1); mrb_free(mrb, buf); -- cgit v1.2.3 From db3e6f6ac66c258cb23ecbbbcaa7dc32bdfe4759 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Wed, 12 Jun 2019 20:45:27 +0900 Subject: Fix typo in `String#setbyte` error message --- mrbgems/mruby-string-ext/src/string.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mrbgems/mruby-string-ext/src/string.c b/mrbgems/mruby-string-ext/src/string.c index 85180516c..d9ebb7392 100644 --- a/mrbgems/mruby-string-ext/src/string.c +++ b/mrbgems/mruby-string-ext/src/string.c @@ -29,7 +29,7 @@ mrb_str_setbyte(mrb_state *mrb, mrb_value str) len = RSTRING_LEN(str); if (pos < -len || len <= pos) - mrb_raisef(mrb, E_INDEX_ERROR, "index %S is out of array", mrb_fixnum_value(pos)); + mrb_raisef(mrb, E_INDEX_ERROR, "index %S out of string", mrb_fixnum_value(pos)); if (pos < 0) pos += len; -- cgit v1.2.3 From 9bd692bc67ee302bcbc359d0841458339c440fb4 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Thu, 13 Jun 2019 21:24:48 +0900 Subject: Fix class name validation in `Struct.new` Before this patch: $ bin/mruby -e 'p Struct.new("A-")' #=> Struct::"A-" After this patch: $ bin/mruby -e 'p Struct.new("A-")' #=> NameError: identifier A- needs to be constant --- include/mruby/class.h | 1 + mrbgems/mruby-struct/src/struct.c | 2 +- mrbgems/mruby-struct/test/struct.rb | 4 ++++ src/class.c | 14 +++++++------- 4 files changed, 13 insertions(+), 8 deletions(-) diff --git a/include/mruby/class.h b/include/mruby/class.h index a68724538..c79a487b5 100644 --- a/include/mruby/class.h +++ b/include/mruby/class.h @@ -88,6 +88,7 @@ MRB_API struct RClass* mrb_class_real(struct RClass* cl); mrb_value mrb_instance_new(mrb_state *mrb, mrb_value cv); void mrb_class_name_class(mrb_state*, struct RClass*, struct RClass*, mrb_sym); +mrb_bool mrb_const_name_p(mrb_state*, const char*, mrb_int); mrb_value mrb_class_find_path(mrb_state*, struct RClass*); void mrb_gc_mark_mt(mrb_state*, struct RClass*); size_t mrb_gc_mark_mt_size(mrb_state*, struct RClass*); diff --git a/mrbgems/mruby-struct/src/struct.c b/mrbgems/mruby-struct/src/struct.c index 1df135a9f..539127bf8 100644 --- a/mrbgems/mruby-struct/src/struct.c +++ b/mrbgems/mruby-struct/src/struct.c @@ -212,7 +212,7 @@ make_struct(mrb_state *mrb, mrb_value name, mrb_value members, struct RClass *kl /* old style: should we warn? */ mrb_to_str(mrb, name); id = mrb_obj_to_sym(mrb, name); - if (!is_const_id(mrb, mrb_sym2name_len(mrb, id, NULL))) { + if (!mrb_const_name_p(mrb, RSTRING_PTR(name), RSTRING_LEN(name))) { mrb_name_error(mrb, id, "identifier %S needs to be constant", name); } if (mrb_const_defined_at(mrb, mrb_obj_value(klass), id)) { diff --git a/mrbgems/mruby-struct/test/struct.rb b/mrbgems/mruby-struct/test/struct.rb index 91e8cecc6..9f2ff1cdc 100644 --- a/mrbgems/mruby-struct/test/struct.rb +++ b/mrbgems/mruby-struct/test/struct.rb @@ -181,6 +181,10 @@ assert("Struct.new does not allow array") do end end +assert("Struct.new does not allow invalid class name") do + assert_raise(NameError) { Struct.new("Test-", :a) } +end + assert("Struct.new generates subclass of Struct") do begin original_struct = Struct diff --git a/src/class.c b/src/class.c index 6ceaa0cfa..373f2aec7 100644 --- a/src/class.c +++ b/src/class.c @@ -77,6 +77,12 @@ mrb_class_name_class(mrb_state *mrb, struct RClass *outer, struct RClass *c, mrb mrb_obj_iv_set_force(mrb, (struct RObject*)c, nsym, name); } +mrb_bool +mrb_const_name_p(mrb_state *mrb, const char *name, mrb_int len) +{ + return len > 0 && ISUPPER(name[0]) && mrb_ident_p(name+1, len-1); +} + static void setup_class(mrb_state *mrb, struct RClass *outer, struct RClass *c, mrb_sym id) { @@ -1852,18 +1858,12 @@ mrb_mod_undef(mrb_state *mrb, mrb_value mod) return mrb_nil_value(); } -static mrb_bool -const_name_p(mrb_state *mrb, const char *name, mrb_int len) -{ - return len > 0 && ISUPPER(name[0]) && mrb_ident_p(name+1, len-1); -} - static void check_const_name_sym(mrb_state *mrb, mrb_sym id) { mrb_int len; const char *name = mrb_sym2name_len(mrb, id, &len); - if (!const_name_p(mrb, name, len)) { + if (!mrb_const_name_p(mrb, name, len)) { mrb_name_error(mrb, id, "wrong constant name %S", mrb_sym2str(mrb, id)); } } -- cgit v1.2.3 From 6084048b28a3c256ceeaa2885d17fc42e238e4a6 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Fri, 14 Jun 2019 10:26:19 +0900 Subject: Remove a meaningless branch condition in `mruby-struct` The following branch condition is always true: // mrbgems/mruby-struct/src/struct.c:187 in make_struct_define_accessors() if (is_local_id(mrb, name) || is_const_id(mrb, name)) { --- mrbgems/mruby-struct/src/struct.c | 36 +++++++++--------------------------- 1 file changed, 9 insertions(+), 27 deletions(-) diff --git a/mrbgems/mruby-struct/src/struct.c b/mrbgems/mruby-struct/src/struct.c index 539127bf8..40914acc9 100644 --- a/mrbgems/mruby-struct/src/struct.c +++ b/mrbgems/mruby-struct/src/struct.c @@ -158,20 +158,6 @@ mrb_struct_set_m(mrb_state *mrb, mrb_value obj) return val; } -static mrb_bool -is_local_id(mrb_state *mrb, const char *name) -{ - if (!name) return FALSE; - return !ISUPPER(name[0]); -} - -static mrb_bool -is_const_id(mrb_state *mrb, const char *name) -{ - if (!name) return FALSE; - return ISUPPER(name[0]); -} - static void make_struct_define_accessors(mrb_state *mrb, mrb_value members, struct RClass *c) { @@ -182,19 +168,15 @@ make_struct_define_accessors(mrb_state *mrb, mrb_value members, struct RClass *c for (i=0; i Date: Sat, 15 Jun 2019 19:41:04 +0900 Subject: Fix index in error message of `Struct#[]` Before this patch: $ bin/mruby -e 'Struct.new(:a,:b).new[-3]' #=> offset -1 too small for struct(size:2) (IndexError) After this patch (same as Ruby): $ bin/mruby -e 'Struct.new(:a,:b).new[-3]' #=> offset -3 too small for struct(size:2) (IndexError) --- mrbgems/mruby-struct/src/struct.c | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/mrbgems/mruby-struct/src/struct.c b/mrbgems/mruby-struct/src/struct.c index 40914acc9..939033d74 100644 --- a/mrbgems/mruby-struct/src/struct.c +++ b/mrbgems/mruby-struct/src/struct.c @@ -385,16 +385,17 @@ struct_aref_sym(mrb_state *mrb, mrb_value obj, mrb_sym id) static mrb_value struct_aref_int(mrb_state *mrb, mrb_value s, mrb_int i) { - if (i < 0) i = RSTRUCT_LEN(s) + i; - if (i < 0) - mrb_raisef(mrb, E_INDEX_ERROR, - "offset %S too small for struct(size:%S)", - mrb_fixnum_value(i), mrb_fixnum_value(RSTRUCT_LEN(s))); - if (RSTRUCT_LEN(s) <= i) + mrb_int idx = i < 0 ? RSTRUCT_LEN(s) + i : i; + + if (idx < 0) + mrb_raisef(mrb, E_INDEX_ERROR, + "offset %S too small for struct(size:%S)", + mrb_fixnum_value(i), mrb_fixnum_value(RSTRUCT_LEN(s))); + if (RSTRUCT_LEN(s) <= idx) mrb_raisef(mrb, E_INDEX_ERROR, "offset %S too large for struct(size:%S)", mrb_fixnum_value(i), mrb_fixnum_value(RSTRUCT_LEN(s))); - return RSTRUCT_PTR(s)[i]; + return RSTRUCT_PTR(s)[idx]; } /* 15.2.18.4.2 */ -- cgit v1.2.3 From 030dd6655e47dad4af4b48a74646712c00684698 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Sun, 16 Jun 2019 20:43:23 +0900 Subject: Fix cvar, ivar, const and method can be removed to frozen object --- mrbgems/mruby-metaprog/src/metaprog.c | 1 + mrbgems/mruby-metaprog/test/metaprog.rb | 8 ++++++-- src/variable.c | 1 + test/t/kernel.rb | 1 + test/t/module.rb | 1 + 5 files changed, 10 insertions(+), 2 deletions(-) diff --git a/mrbgems/mruby-metaprog/src/metaprog.c b/mrbgems/mruby-metaprog/src/metaprog.c index 43d27f4dc..0d207ef41 100644 --- a/mrbgems/mruby-metaprog/src/metaprog.c +++ b/mrbgems/mruby-metaprog/src/metaprog.c @@ -641,6 +641,7 @@ mrb_mod_remove_method(mrb_state *mrb, mrb_value mod) mrb_value *argv; mrb_get_args(mrb, "*", &argv, &argc); + mrb_check_frozen(mrb, mrb_obj_ptr(mod)); while (argc--) { remove_method(mrb, mod, mrb_obj_to_sym(mrb, *argv)); argv++; diff --git a/mrbgems/mruby-metaprog/test/metaprog.rb b/mrbgems/mruby-metaprog/test/metaprog.rb index 685fdf196..46b98d0ed 100644 --- a/mrbgems/mruby-metaprog/test/metaprog.rb +++ b/mrbgems/mruby-metaprog/test/metaprog.rb @@ -298,6 +298,9 @@ assert('Module#remove_class_variable', '15.2.2.4.39') do assert_raise(NameError) do Test4RemoveClassVariable.remove_class_variable(:@v) end + assert_raise(FrozenError) do + Test4RemoveClassVariable.freeze.remove_class_variable(:@@cv) + end end assert('Module#remove_method', '15.2.2.4.41') do @@ -305,9 +308,9 @@ assert('Module#remove_method', '15.2.2.4.41') do class Parent def hello end - end + end - class Child < Parent + class Child < Parent def hello end end @@ -317,6 +320,7 @@ assert('Module#remove_method', '15.2.2.4.41') do assert_same klass, klass.class_eval{ remove_method :hello } assert_true klass.instance_methods.include? :hello assert_false klass.instance_methods(false).include? :hello + assert_raise(FrozenError) { klass.freeze.remove_method :m } end assert('Module.nesting', '15.2.2.2.2') do diff --git a/src/variable.c b/src/variable.c index 779f206dc..23d900b7d 100644 --- a/src/variable.c +++ b/src/variable.c @@ -521,6 +521,7 @@ mrb_obj_iv_inspect(mrb_state *mrb, struct RObject *obj) MRB_API mrb_value mrb_iv_remove(mrb_state *mrb, mrb_value obj, mrb_sym sym) { + mrb_check_frozen(mrb, mrb_obj_ptr(obj)); if (obj_iv_p(obj)) { iv_tbl *t = mrb_obj_ptr(obj)->iv; mrb_value val; diff --git a/test/t/kernel.rb b/test/t/kernel.rb index 7f6e6c58d..950442351 100644 --- a/test/t/kernel.rb +++ b/test/t/kernel.rb @@ -404,6 +404,7 @@ assert('Kernel#remove_instance_variable', '15.3.1.3.41') do assert_equal nil, tri.var assert_raise(NameError) { tri.remove } assert_raise(NameError) { tri.remove_instance_variable(:var) } + assert_raise(FrozenError) { tri.freeze.remove } end # Kernel#require is defined in mruby-require. '15.3.1.3.42' diff --git a/test/t/module.rb b/test/t/module.rb index 3bb9735df..571f4759d 100644 --- a/test/t/module.rb +++ b/test/t/module.rb @@ -262,6 +262,7 @@ assert('Module#remove_const', '15.2.2.4.40') do %i[x X!].each do |n| assert_raise(NameError) { Test4RemoveConst.remove_const(n) } end + assert_raise(FrozenError) { Test4RemoveConst.freeze.remove_const(:A) } end assert('Module#const_missing', '15.2.2.4.22') do -- cgit v1.2.3 From d895c5fe5aa8e65f7e98b79494602a0f0d442a30 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Sat, 15 Jun 2019 10:02:49 +0900 Subject: Fixed wrong behavior on `..` at the beginning of the line. --- mrbgems/mruby-compiler/core/parse.y | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/mrbgems/mruby-compiler/core/parse.y b/mrbgems/mruby-compiler/core/parse.y index 37d4d1bf1..baa69b556 100644 --- a/mrbgems/mruby-compiler/core/parse.y +++ b/mrbgems/mruby-compiler/core/parse.y @@ -4758,8 +4758,7 @@ parser_yylex(parser_state *p) space_seen = 1; break; case '.': - if ((c = nextc(p)) != '.') { - pushback(p, c); + if (!peek(p, '.')) { pushback(p, '.'); goto retry; } -- cgit v1.2.3 From 4124047ccec9c299002902750fcb4b6534bbbdca Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Sat, 15 Jun 2019 10:04:47 +0900 Subject: Support `&.` at the beginning of the line. --- mrbgems/mruby-compiler/core/parse.y | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/mrbgems/mruby-compiler/core/parse.y b/mrbgems/mruby-compiler/core/parse.y index baa69b556..ff4016d8b 100644 --- a/mrbgems/mruby-compiler/core/parse.y +++ b/mrbgems/mruby-compiler/core/parse.y @@ -4762,6 +4762,15 @@ parser_yylex(parser_state *p) pushback(p, '.'); goto retry; } + pushback(p, c); + goto normal_newline; + case '&': + if (peek(p, '.')) { + pushback(p, '&'); + goto retry; + } + pushback(p, c); + goto normal_newline; case -1: /* EOF */ case -2: /* end of a file */ goto normal_newline; -- cgit v1.2.3 From 4296c77e29b67e72399dde8295dd6fa4a10cc321 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Sat, 15 Jun 2019 12:52:57 +0900 Subject: Allow newlines and comments between method calls. --- mrbgems/mruby-compiler/core/parse.y | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/mrbgems/mruby-compiler/core/parse.y b/mrbgems/mruby-compiler/core/parse.y index ff4016d8b..6ab91ce91 100644 --- a/mrbgems/mruby-compiler/core/parse.y +++ b/mrbgems/mruby-compiler/core/parse.y @@ -4757,6 +4757,14 @@ parser_yylex(parser_state *p) case '\13': /* '\v' */ space_seen = 1; break; + case '#': /* comment as a whitespace */ + pushback(p, '#'); + goto retry; + case '\n': /* consecutive newlines */ + p->lineno++; + p->column = 0; + pushback(p, '\n'); + goto retry; case '.': if (!peek(p, '.')) { pushback(p, '.'); -- cgit v1.2.3 From 0fba50082642fa4a6e0468f4e41192de095258f4 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Sat, 15 Jun 2019 12:58:30 +0900 Subject: Fixed indentation in parse.y --- mrbgems/mruby-compiler/core/parse.y | 106 ++++++++++++++++++------------------ 1 file changed, 53 insertions(+), 53 deletions(-) diff --git a/mrbgems/mruby-compiler/core/parse.y b/mrbgems/mruby-compiler/core/parse.y index 6ab91ce91..96a9453b6 100644 --- a/mrbgems/mruby-compiler/core/parse.y +++ b/mrbgems/mruby-compiler/core/parse.y @@ -4729,68 +4729,68 @@ parser_yylex(parser_state *p) /* fall through */ case -2: /* end of a file */ case '\n': - maybe_heredoc: + maybe_heredoc: heredoc_treat_nextline(p); - switch (p->lstate) { - case EXPR_BEG: - case EXPR_FNAME: - case EXPR_DOT: - case EXPR_CLASS: - case EXPR_VALUE: - p->lineno++; - p->column = 0; - if (p->parsing_heredoc != NULL) { - if (p->lex_strterm) { - return parse_string(p); - } - } - goto retry; - default: - break; - } - if (p->parsing_heredoc != NULL) { - return '\n'; - } - while ((c = nextc(p))) { - switch (c) { - case ' ': case '\t': case '\f': case '\r': - case '\13': /* '\v' */ - space_seen = 1; - break; - case '#': /* comment as a whitespace */ - pushback(p, '#'); - goto retry; - case '\n': /* consecutive newlines */ + switch (p->lstate) { + case EXPR_BEG: + case EXPR_FNAME: + case EXPR_DOT: + case EXPR_CLASS: + case EXPR_VALUE: p->lineno++; p->column = 0; - pushback(p, '\n'); + if (p->parsing_heredoc != NULL) { + if (p->lex_strterm) { + return parse_string(p); + } + } goto retry; - case '.': - if (!peek(p, '.')) { - pushback(p, '.'); + default: + break; + } + if (p->parsing_heredoc != NULL) { + return '\n'; + } + while ((c = nextc(p))) { + switch (c) { + case ' ': case '\t': case '\f': case '\r': + case '\13': /* '\v' */ + space_seen = 1; + break; + case '#': /* comment as a whitespace */ + pushback(p, '#'); goto retry; - } - pushback(p, c); - goto normal_newline; - case '&': - if (peek(p, '.')) { - pushback(p, '&'); + case '\n': /* consecutive newlines */ + p->lineno++; + p->column = 0; + pushback(p, '\n'); goto retry; + case '.': + if (!peek(p, '.')) { + pushback(p, '.'); + goto retry; + } + pushback(p, c); + goto normal_newline; + case '&': + if (peek(p, '.')) { + pushback(p, '&'); + goto retry; + } + pushback(p, c); + goto normal_newline; + case -1: /* EOF */ + case -2: /* end of a file */ + goto normal_newline; + default: + pushback(p, c); + goto normal_newline; } - pushback(p, c); - goto normal_newline; - case -1: /* EOF */ - case -2: /* end of a file */ - goto normal_newline; - default: - pushback(p, c); - goto normal_newline; } - } normal_newline: - p->cmd_start = TRUE; - p->lstate = EXPR_BEG; - return '\n'; + p->cmd_start = TRUE; + p->lstate = EXPR_BEG; + return '\n'; case '*': if ((c = nextc(p)) == '*') { -- cgit v1.2.3 From faec8331b7805c810b83b94785323ed239a05cb7 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Mon, 17 Jun 2019 21:46:30 +0900 Subject: Remove unneeded `mrb_str_dup()` in `Module#name` `mrb_class_path()` always returns a new string or `nil`. --- mrbgems/mruby-class-ext/src/class.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/mrbgems/mruby-class-ext/src/class.c b/mrbgems/mruby-class-ext/src/class.c index 705db9949..fdd56bcc3 100644 --- a/mrbgems/mruby-class-ext/src/class.c +++ b/mrbgems/mruby-class-ext/src/class.c @@ -5,8 +5,7 @@ static mrb_value mrb_mod_name(mrb_state *mrb, mrb_value self) { - mrb_value name = mrb_class_path(mrb, mrb_class_ptr(self)); - return mrb_nil_p(name)? name : mrb_str_dup(mrb, name); + return mrb_class_path(mrb, mrb_class_ptr(self)); } static mrb_value -- cgit v1.2.3 From eeb7d3a04f9380d64c20b77d428d1de5ecafbb33 Mon Sep 17 00:00:00 2001 From: Ryan Lopopolo Date: Mon, 17 Jun 2019 21:42:19 +0100 Subject: Support parsing a Regexp literal with 'o' option CRuby supports a 'o' `Regexp` option for `Regexp` literals, e.g. `/foo/o` that disables multiple interpolation passes. This commit adds support for parsing such literals. Nothing is done with the option, it is consumed and ignored by the parser. --- mrbgems/mruby-compiler/core/parse.y | 1 + 1 file changed, 1 insertion(+) diff --git a/mrbgems/mruby-compiler/core/parse.y b/mrbgems/mruby-compiler/core/parse.y index 96a9453b6..5e4889978 100644 --- a/mrbgems/mruby-compiler/core/parse.y +++ b/mrbgems/mruby-compiler/core/parse.y @@ -4526,6 +4526,7 @@ parse_string(parser_state *p) case 'm': f |= 4; break; case 'u': f |= 16; break; case 'n': f |= 32; break; + case 'o': break; default: tokadd(p, re_opt); break; } } -- cgit v1.2.3 From b630bf59ef9db340f727d18ac5d091790b88d6ce Mon Sep 17 00:00:00 2001 From: Hiroshi Mimaki Date: Tue, 18 Jun 2019 13:27:16 +0900 Subject: Fix path of `error.h`. --- mrbgems/mruby-pack/src/pack.c | 2 +- mrbgems/mruby-socket/src/socket.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/mrbgems/mruby-pack/src/pack.c b/mrbgems/mruby-pack/src/pack.c index 75a447d6c..46c0cc1fe 100644 --- a/mrbgems/mruby-pack/src/pack.c +++ b/mrbgems/mruby-pack/src/pack.c @@ -3,7 +3,7 @@ */ #include "mruby.h" -#include "error.h" +#include "mruby/error.h" #include "mruby/array.h" #include "mruby/class.h" #include "mruby/numeric.h" diff --git a/mrbgems/mruby-socket/src/socket.c b/mrbgems/mruby-socket/src/socket.c index 8515a6057..9b06274dc 100644 --- a/mrbgems/mruby-socket/src/socket.c +++ b/mrbgems/mruby-socket/src/socket.c @@ -41,7 +41,7 @@ #include "mruby/numeric.h" #include "mruby/string.h" #include "mruby/variable.h" -#include "error.h" +#include "mruby/error.h" #include "mruby/ext/io.h" -- cgit v1.2.3 From 81828f8b08aa79bb9ead5b846958a087ddcf5b1f Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Tue, 18 Jun 2019 18:17:03 +0900 Subject: Fix `struct RRange` overflow on 32-bit CPU with `MRB_NAN_BOXING` --- include/mruby/range.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/mruby/range.h b/include/mruby/range.h index ee6eb8d1d..500a941d5 100644 --- a/include/mruby/range.h +++ b/include/mruby/range.h @@ -14,7 +14,7 @@ */ MRB_BEGIN_DECL -#if defined(MRB_NAN_BOXING) || defined(MRB_WORD_BOXING) +#if defined(MRB_NAN_BOXING) && defined(MRB_64BIT) || defined(MRB_WORD_BOXING) # define MRB_RANGE_EMBED #endif -- cgit v1.2.3 From 4d9d6faf0d5890eca2b6407fe53531ea19450b3d Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Wed, 19 Jun 2019 17:50:20 +0900 Subject: Remove unneeded statement in `SET_OBJ_VALUE` with `boxing_word.h` `(r).value.bp` and `v` have the same value due to assignment of the line preceding the removed line. --- include/mruby/boxing_word.h | 1 - 1 file changed, 1 deletion(-) diff --git a/include/mruby/boxing_word.h b/include/mruby/boxing_word.h index 2fb84052a..f16968a1f 100644 --- a/include/mruby/boxing_word.h +++ b/include/mruby/boxing_word.h @@ -141,7 +141,6 @@ mrb_type(mrb_value o) #define SET_OBJ_VALUE(r,v) do { \ (r).w = 0; \ (r).value.p = (v); \ - if ((r).value.bp) (r).value.bp->tt = ((struct RObject*)(v))->tt; \ } while (0) #endif /* MRUBY_BOXING_WORD_H */ -- cgit v1.2.3 From 77996e6adc753e3e407fefa0d282ea66762d5699 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Thu, 20 Jun 2019 19:59:27 +0900 Subject: Add ISO section number to `Kernel.#local_variables` [ci skip] --- mrbgems/mruby-metaprog/src/metaprog.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/mrbgems/mruby-metaprog/src/metaprog.c b/mrbgems/mruby-metaprog/src/metaprog.c index 0d207ef41..62daa5227 100644 --- a/mrbgems/mruby-metaprog/src/metaprog.c +++ b/mrbgems/mruby-metaprog/src/metaprog.c @@ -117,6 +117,7 @@ mrb_obj_ivar_set(mrb_state *mrb, mrb_value self) } /* 15.3.1.2.7 */ +/* 15.3.1.3.28 */ /* * call-seq: * local_variables -> array @@ -688,7 +689,7 @@ mrb_mruby_metaprog_gem_init(mrb_state* mrb) struct RClass *mod = mrb->module_class; mrb_define_method(mrb, krn, "global_variables", mrb_f_global_variables, MRB_ARGS_NONE()); /* 15.3.1.3.14 (15.3.1.2.4) */ - mrb_define_method(mrb, krn, "local_variables", mrb_local_variables, MRB_ARGS_NONE()); /* 15.3.1.3.28 */ + mrb_define_method(mrb, krn, "local_variables", mrb_local_variables, MRB_ARGS_NONE()); /* 15.3.1.3.28 (15.3.1.2.7) */ mrb_define_method(mrb, krn, "singleton_class", mrb_singleton_class, MRB_ARGS_NONE()); mrb_define_method(mrb, krn, "instance_variable_defined?", mrb_obj_ivar_defined, MRB_ARGS_REQ(1)); /* 15.3.1.3.20 */ -- cgit v1.2.3 From c43ff6fa4063d22db391ab1818b121110ca520bf Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Fri, 21 Jun 2019 22:02:29 +0900 Subject: Move `Kernel#__send__` test to core from `mruby-metaprog` --- mrbgems/mruby-metaprog/test/metaprog.rb | 14 -------------- test/t/kernel.rb | 14 ++++++++++++++ 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/mrbgems/mruby-metaprog/test/metaprog.rb b/mrbgems/mruby-metaprog/test/metaprog.rb index 46b98d0ed..1e1d4ff26 100644 --- a/mrbgems/mruby-metaprog/test/metaprog.rb +++ b/mrbgems/mruby-metaprog/test/metaprog.rb @@ -1,17 +1,3 @@ -assert('Kernel#__send__', '15.3.1.3.4') do - # test with block - l = __send__(:lambda) do - true - end - - assert_true l.call - assert_equal Proc, l.class - # test with argument - assert_true __send__(:respond_to?, :nil?) - # test without argument and without block - assert_equal String, __send__(:to_s).class -end - assert('Kernel#send', '15.3.1.3.44') do # test with block l = send(:lambda) do diff --git a/test/t/kernel.rb b/test/t/kernel.rb index 950442351..103660f53 100644 --- a/test/t/kernel.rb +++ b/test/t/kernel.rb @@ -88,6 +88,20 @@ assert('Kernel#__id__', '15.3.1.3.3') do assert_equal Fixnum, __id__.class end +assert('Kernel#__send__', '15.3.1.3.4') do + # test with block + l = __send__(:lambda) do + true + end + + assert_true l.call + assert_equal Proc, l.class + # test with argument + assert_true __send__(:respond_to?, :nil?) + # test without argument and without block + assert_equal String, __send__(:to_s).class +end + assert('Kernel#block_given?', '15.3.1.3.6') do def bg_try(&b) if block_given? -- cgit v1.2.3 From a76da32567f9c6f8aea5c697f3ec68f31b99fb16 Mon Sep 17 00:00:00 2001 From: dearblue Date: Sat, 18 Aug 2018 11:44:44 +0900 Subject: Use stack memory for small name of Struct members --- mrbgems/mruby-struct/src/struct.c | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/mrbgems/mruby-struct/src/struct.c b/mrbgems/mruby-struct/src/struct.c index 44822a03e..e1f64df55 100644 --- a/mrbgems/mruby-struct/src/struct.c +++ b/mrbgems/mruby-struct/src/struct.c @@ -123,18 +123,29 @@ mrb_struct_ref(mrb_state *mrb, mrb_value obj) static mrb_sym mrb_id_attrset(mrb_state *mrb, mrb_sym id) { +#define STACKED_ALLOC_MAX 32 +#define STACKED_STRING_MAX (STACKED_ALLOC_MAX - 1) /* '=' character */ + const char *name; char *buf; mrb_int len; mrb_sym mid; + char stacked[STACKED_ALLOC_MAX]; name = mrb_sym2name_len(mrb, id, &len); - buf = (char *)mrb_malloc(mrb, (size_t)len+1); + if (len > STACKED_STRING_MAX) { + buf = (char *)mrb_malloc(mrb, (size_t)len+1); + } + else { + buf = stacked; + } memcpy(buf, name, (size_t)len); buf[len] = '='; mid = mrb_intern(mrb, buf, len+1); - mrb_free(mrb, buf); + if (buf != stacked) { + mrb_free(mrb, buf); + } return mid; } -- cgit v1.2.3 From 758353902940e43530dbbbab0d9ce6ded5884923 Mon Sep 17 00:00:00 2001 From: dearblue Date: Sat, 22 Jun 2019 16:48:22 +0900 Subject: Fix potential overflow in `utf8len()` For example on 32 bit mode, when `p = 0xfffffffd`, `e = 0xfffffffe` and `len = 4`, the sum of `p` and `len` can be to `1`, and comparison with `e` will to be false. As a result, a segmentation fault occurs by referring to address 0. --- src/string.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/string.c b/src/string.c index bfe73b359..ed58c484b 100644 --- a/src/string.c +++ b/src/string.c @@ -234,7 +234,7 @@ utf8len(const char* p, const char* e) mrb_int i; len = utf8len_codepage[(unsigned char)*p]; - if (p + len > e) return 1; + if (len > e - p) return 1; for (i = 1; i < len; ++i) if ((p[i] & 0xc0) != 0x80) return 1; -- cgit v1.2.3 From 28de6b0da195e1ebf8f6ce30de462f44fb761b8b Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Sat, 22 Jun 2019 19:05:42 +0900 Subject: Refine `Hash#rehash` example [ci skip] Previous example doesn't work because string key (frozen) can't be modified. --- src/hash.c | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/src/hash.c b/src/hash.c index a9367a426..b4d96251c 100644 --- a/src/hash.c +++ b/src/hash.c @@ -1378,10 +1378,21 @@ mrb_hash_merge(mrb_state *mrb, mrb_value hash1, mrb_value hash2) * values of key objects have changed since they were inserted, this * method will reindex hsh. * - * h = {"AAA" => "b"} - * h.keys[0].chop! - * h.rehash #=> {"AA"=>"b"} - * h["AA"] #=> "b" + * keys = (1..17).map{|n| [n]} + * k = keys[0] + * h = {} + * keys.each{|key| h[key] = key[0]} + * h #=> { [1]=> 1, [2]=> 2, [3]=> 3, [4]=> 4, [5]=> 5, [6]=> 6, [7]=> 7, + * [8]=> 8, [9]=> 9,[10]=>10,[11]=>11,[12]=>12,[13]=>13,[14]=>14, + * [15]=>15,[16]=>16,[17]=>17} + * h[k] #=> 1 + * k[0] = keys.size + 1 + * h #=> {[18]=> 1, [2]=> 2, [3]=> 3, [4]=> 4, [5]=> 5, [6]=> 6, [7]=> 7, + * [8]=> 8, [9]=> 9,[10]=>10,[11]=>11,[12]=>12,[13]=>13,[14]=>14, + * [15]=>15,[16]=>16,[17]=>17} + * h[k] #=> nil + * h.rehash + * h[k] #=> 1 */ static mrb_value mrb_hash_rehash(mrb_state *mrb, mrb_value self) -- cgit v1.2.3 From 0f516bbe1dd61759faf2609970bd5cd855931221 Mon Sep 17 00:00:00 2001 From: Ryan Lopopolo Date: Sat, 22 Jun 2019 12:07:21 +0100 Subject: Add paragraph mode to String#each_line in mrblib mruby/mruby#4511 demonstrated an infinite loop in `String#each_line` when given an empty string separator. In MRI, an empty separator places String#each_line in paragraph mode, where the String is separated on successive runs of newlines. In paragraph mode, the String `"abc\n\n\ndef\nxyz"` is split into `["abc\n\n\n", "def\nxyz"]`. This commit makes the String#each_line implementation as close to ruby/spec compliant as possible given the limitations of mruby core. With this patch, the following specs fail for `String#each_line`: - uses `$/` as the separator when none is given (can be fixed by aliasing and redefining the method to use $/ as the default value of separator in mruby-io) - when no block is given returned Enumerator size should return nil (`Enumerator#size` is not supported on mruby) - tries to convert the separator to a string using to_str (`String#to_str` is not implemented on mruby) This patch has similar memory consumption compared to the prior implementation and is takes 4x the time the prior implementation takes to execute: ```console /usr/bin/time -l ./bin/mruby -e '("aaa\n\nbbbbb\n\n\n\n\ncccc" * 100000).each_line("\n") { }'; ``` --- mrblib/string.rb | 67 ++++++++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 56 insertions(+), 11 deletions(-) diff --git a/mrblib/string.rb b/mrblib/string.rb index b0fe4033e..adf19d00c 100644 --- a/mrblib/string.rb +++ b/mrblib/string.rb @@ -11,18 +11,63 @@ class String # and pass the respective line. # # ISO 15.2.10.5.15 - def each_line(rs = "\n", &block) - return to_enum(:each_line, rs, &block) unless block - return block.call(self) if rs.nil? - rs.__to_str - offset = 0 - rs_len = rs.length - this = dup - while pos = this.index(rs, offset) - block.call(this[offset, pos + rs_len - offset]) - offset = pos + rs_len + def each_line(separator = "\n", getline_args = nil) + return to_enum(:each_line, separator, getline_args) unless block_given? + + if separator.nil? + yield self + return self + end + raise TypeError unless separator.is_a?(String) + + start = 0 + pointer = 0 + string = dup + + if separator.empty? + matched_newlines = 0 + while pointer < string.length + c = string[pointer] + if c == "\n" + matched_newlines += 1 + elsif matched_newlines > 1 && self.class == String + yield string[start...pointer] + matched_newlines = 0 + start = pointer + elsif matched_newlines > 1 + yield self.class.new(string[start...pointer]) + matched_newlines = 0 + start = pointer + else + matched_newlines = 0 + end + pointer += 1 + end + else + matched_length = 0 + separator_length = separator.length + while pointer < string.length + c = string[pointer] + pointer += 1 + matched_length += 1 if c == separator[matched_length] + next unless matched_length == separator_length + + if self.class == String + yield string[start...pointer] + else + yield self.class.new(string[start...pointer]) + end + matched_length = 0 + start = pointer + end + end + return self if start == string.length + + if self.class == String + yield string[start..-1] + else + yield self.class.new(string[start..-1]) end - block.call(this[offset, this.size - offset]) if this.size > offset self end -- cgit v1.2.3 From a932b8c96a4312753993ce0b98d2e9eedec17de0 Mon Sep 17 00:00:00 2001 From: Ryan Lopopolo Date: Sat, 22 Jun 2019 12:55:02 +0100 Subject: Speed up base case by 2x Make non-paragraph mode twice as fast. Performance is within a factor of 2 of the original implementation. --- mrblib/string.rb | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/mrblib/string.rb b/mrblib/string.rb index adf19d00c..0bac52a20 100644 --- a/mrblib/string.rb +++ b/mrblib/string.rb @@ -44,20 +44,13 @@ class String pointer += 1 end else - matched_length = 0 - separator_length = separator.length - while pointer < string.length - c = string[pointer] - pointer += 1 - matched_length += 1 if c == separator[matched_length] - next unless matched_length == separator_length - + while (pointer = string.index(separator, start)) + pointer += separator.length if self.class == String yield string[start...pointer] else yield self.class.new(string[start...pointer]) end - matched_length = 0 start = pointer end end -- cgit v1.2.3 From 7c6d6effaea6ec3cbac01cffc4f094744d53d8b9 Mon Sep 17 00:00:00 2001 From: dearblue Date: Sat, 22 Jun 2019 16:30:36 +0900 Subject: Replacement to function for string reversing --- src/string.c | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/src/string.c b/src/string.c index bfe73b359..282f8d776 100644 --- a/src/string.c +++ b/src/string.c @@ -1671,6 +1671,18 @@ mrb_ptr_to_str(mrb_state *mrb, void *p) return mrb_obj_value(p_str); } +static inline void +str_reverse(char *p, char *e) +{ + char c; + + while (p < e) { + c = *p; + *p++ = *e; + *e-- = c; + } +} + /* 15.2.10.5.30 */ /* * call-seq: @@ -1714,17 +1726,12 @@ mrb_str_reverse_bang(mrb_state *mrb, mrb_value str) { struct RString *s = mrb_str_ptr(str); char *p, *e; - char c; mrb_str_modify(mrb, s); if (RSTR_LEN(s) > 1) { p = RSTR_PTR(s); e = p + RSTR_LEN(s) - 1; - while (p < e) { - c = *p; - *p++ = *e; - *e-- = c; - } + str_reverse(p, e); } return str; } -- cgit v1.2.3 From bd2c93c2dfbb944f57b10b7b9c056caf852a5053 Mon Sep 17 00:00:00 2001 From: dearblue Date: Sat, 22 Jun 2019 16:32:17 +0900 Subject: Change to UTF-8 string reversing with in place MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reverses UTF-8 strings without allocated heap for working memory. 1. String before reversing: ``` "!yburmの界世" # byte unit [33, 121, 98, 117, 114, 109, 227, 129, 174, 231, 149, 140, 228, 184, 150] ``` 2. Reverse the byte order of each character: ``` [33, 121, 98, 117, 114, 109, 174, 129, 227, 140, 149, 231, 150, 184, 228] ``` 3. Reverse the whole byte order and complete: ``` [228, 184, 150, 231, 149, 140, 227, 129, 174, 109, 114, 117, 98, 121, 33] # string "世界のmruby!" ``` --- src/string.c | 28 ++++++++-------------------- 1 file changed, 8 insertions(+), 20 deletions(-) diff --git a/src/string.c b/src/string.c index 282f8d776..6d01b773c 100644 --- a/src/string.c +++ b/src/string.c @@ -1693,40 +1693,28 @@ str_reverse(char *p, char *e) static mrb_value mrb_str_reverse_bang(mrb_state *mrb, mrb_value str) { + struct RString *s = mrb_str_ptr(str); + char *p, *e; + #ifdef MRB_UTF8_STRING mrb_int utf8_len = RSTRING_CHAR_LEN(str); - mrb_int len = RSTRING_LEN(str); + mrb_int len = RSTR_LEN(s); if (utf8_len == len) goto bytes; if (utf8_len > 1) { - char *buf; - char *p, *e, *r; - - mrb_str_modify(mrb, mrb_str_ptr(str)); - len = RSTRING_LEN(str); - buf = (char*)mrb_malloc(mrb, (size_t)len); - p = buf; - e = buf + len; - - memcpy(buf, RSTRING_PTR(str), len); - r = RSTRING_PTR(str) + len; - + mrb_str_modify(mrb, s); + p = RSTR_PTR(s); + e = p + RSTR_LEN(s); while (p 1) { p = RSTR_PTR(s); -- cgit v1.2.3 From 5af8a9777be82838b65c5b84bb2758f5395df998 Mon Sep 17 00:00:00 2001 From: dearblue Date: Sat, 22 Jun 2019 22:58:08 +0900 Subject: Add test for one UTF-8 charactor --- test/t/string.rb | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/test/t/string.rb b/test/t/string.rb index 9817dd188..7ef236dbe 100644 --- a/test/t/string.rb +++ b/test/t/string.rb @@ -479,6 +479,7 @@ assert('String#reverse(UTF-8)', '15.2.10.5.29') do assert_equal 'こんにちは世界!', a assert_equal '!界世はちにんこ', 'こんにちは世界!'.reverse + assert_equal 'あ', 'あ'.reverse end if UTF8STRING assert('String#reverse!', '15.2.10.5.30') do @@ -495,6 +496,10 @@ assert('String#reverse!(UTF-8)', '15.2.10.5.30') do assert_equal '!界世はちにんこ', a assert_equal '!界世はちにんこ', 'こんにちは世界!'.reverse! + + b = 'あ' + b.reverse! + assert_equal 'あ', b end if UTF8STRING assert('String#rindex', '15.2.10.5.31') do -- cgit v1.2.3 From 567075aab939dd262e816832195cb11594abade9 Mon Sep 17 00:00:00 2001 From: dearblue Date: Sat, 22 Jun 2019 22:58:18 +0900 Subject: Fix string brakes for one UTF-8 charactor --- src/string.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/string.c b/src/string.c index 6d01b773c..a35262eb4 100644 --- a/src/string.c +++ b/src/string.c @@ -1700,8 +1700,8 @@ mrb_str_reverse_bang(mrb_state *mrb, mrb_value str) mrb_int utf8_len = RSTRING_CHAR_LEN(str); mrb_int len = RSTR_LEN(s); - if (utf8_len == len) goto bytes; - if (utf8_len > 1) { + if (utf8_len < 2) return str; + if (utf8_len < len) { mrb_str_modify(mrb, s); p = RSTR_PTR(s); e = p + RSTR_LEN(s); @@ -1711,8 +1711,6 @@ mrb_str_reverse_bang(mrb_state *mrb, mrb_value str) p += clen; } } - - bytes: #endif { mrb_str_modify(mrb, s); -- cgit v1.2.3 From ec03e3f54af55af8c461a19b2f7cf0a984282997 Mon Sep 17 00:00:00 2001 From: dearblue Date: Sat, 22 Jun 2019 23:02:29 +0900 Subject: Delete the unnecessary block brace in `mrb_str_reverse_bang` --- src/string.c | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/src/string.c b/src/string.c index a35262eb4..2cfdc337e 100644 --- a/src/string.c +++ b/src/string.c @@ -1712,15 +1712,14 @@ mrb_str_reverse_bang(mrb_state *mrb, mrb_value str) } } #endif - { - mrb_str_modify(mrb, s); - if (RSTR_LEN(s) > 1) { - p = RSTR_PTR(s); - e = p + RSTR_LEN(s) - 1; - str_reverse(p, e); - } - return str; + + mrb_str_modify(mrb, s); + if (RSTR_LEN(s) > 1) { + p = RSTR_PTR(s); + e = p + RSTR_LEN(s) - 1; + str_reverse(p, e); } + return str; } /* ---------------------------------- */ -- cgit v1.2.3 From 11e09dc5dbd6ddaabf145bbee62741f4191eca79 Mon Sep 17 00:00:00 2001 From: dearblue Date: Sat, 22 Jun 2019 23:09:36 +0900 Subject: Fix the unnecessary `mrb_str_modify()` call Now to be calls `mrb_str_modify()` only once when 2 or more characters. --- src/string.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/string.c b/src/string.c index 2cfdc337e..2d9d176d4 100644 --- a/src/string.c +++ b/src/string.c @@ -1710,11 +1710,13 @@ mrb_str_reverse_bang(mrb_state *mrb, mrb_value str) str_reverse(p, p + clen - 1); p += clen; } + goto bytes; } #endif - mrb_str_modify(mrb, s); if (RSTR_LEN(s) > 1) { + mrb_str_modify(mrb, s); + bytes: p = RSTR_PTR(s); e = p + RSTR_LEN(s) - 1; str_reverse(p, e); -- cgit v1.2.3 From 8ea45b862aa9ff358b3642ac14b03304fcd6846e Mon Sep 17 00:00:00 2001 From: Ryan Lopopolo Date: Sun, 23 Jun 2019 03:29:47 +0100 Subject: Optimize String#each_line --- mrblib/string.rb | 31 +++++++++++++++++-------------- 1 file changed, 17 insertions(+), 14 deletions(-) diff --git a/mrblib/string.rb b/mrblib/string.rb index 0bac52a20..60129a845 100644 --- a/mrblib/string.rb +++ b/mrblib/string.rb @@ -11,7 +11,7 @@ class String # and pass the respective line. # # ISO 15.2.10.5.15 - def each_line(separator = "\n", getline_args = nil) + def each_line(separator = "\n") return to_enum(:each_line, separator, getline_args) unless block_given? if separator.nil? @@ -20,22 +20,25 @@ class String end raise TypeError unless separator.is_a?(String) - start = 0 pointer = 0 + start = 0 string = dup + self_len = length + sep_len = separator.length + should_yield_subclass_instances = self.class != String if separator.empty? matched_newlines = 0 - while pointer < string.length + while pointer < self_len c = string[pointer] if c == "\n" matched_newlines += 1 - elsif matched_newlines > 1 && self.class == String - yield string[start...pointer] + elsif matched_newlines > 1 && should_yield_subclass_instances + yield self.class.new(string[start, pointer - start]) matched_newlines = 0 start = pointer elsif matched_newlines > 1 - yield self.class.new(string[start...pointer]) + yield string[start, pointer - start] matched_newlines = 0 start = pointer else @@ -45,21 +48,21 @@ class String end else while (pointer = string.index(separator, start)) - pointer += separator.length - if self.class == String - yield string[start...pointer] + pointer += sep_len + if should_yield_subclass_instances + yield self.class.new(string[start, pointer - start]) else - yield self.class.new(string[start...pointer]) + yield string[start, pointer - start] end start = pointer end end - return self if start == string.length + return self if start == self_len - if self.class == String - yield string[start..-1] + if should_yield_subclass_instances + yield self.class.new(string[start, self_len - start]) else - yield self.class.new(string[start..-1]) + yield string[start, self_len - start] end self end -- cgit v1.2.3 From 6b92acf361c8f1979dcda95c41324cccc8d767a9 Mon Sep 17 00:00:00 2001 From: Ryan Lopopolo Date: Sun, 23 Jun 2019 03:40:39 +0100 Subject: Use explicit block parameter --- mrblib/string.rb | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/mrblib/string.rb b/mrblib/string.rb index 60129a845..f1c7f3ba4 100644 --- a/mrblib/string.rb +++ b/mrblib/string.rb @@ -11,11 +11,11 @@ class String # and pass the respective line. # # ISO 15.2.10.5.15 - def each_line(separator = "\n") - return to_enum(:each_line, separator, getline_args) unless block_given? + def each_line(separator = "\n", &block) + return to_enum(:each_line, separator) unless block if separator.nil? - yield self + block.call(self) return self end raise TypeError unless separator.is_a?(String) @@ -34,11 +34,11 @@ class String if c == "\n" matched_newlines += 1 elsif matched_newlines > 1 && should_yield_subclass_instances - yield self.class.new(string[start, pointer - start]) + block.call(self.class.new(string[start, pointer - start])) matched_newlines = 0 start = pointer elsif matched_newlines > 1 - yield string[start, pointer - start] + block.call(string[start, pointer - start]) matched_newlines = 0 start = pointer else @@ -50,9 +50,9 @@ class String while (pointer = string.index(separator, start)) pointer += sep_len if should_yield_subclass_instances - yield self.class.new(string[start, pointer - start]) + block.call(self.class.new(string[start, pointer - start])) else - yield string[start, pointer - start] + block.call(string[start, pointer - start]) end start = pointer end @@ -60,9 +60,9 @@ class String return self if start == self_len if should_yield_subclass_instances - yield self.class.new(string[start, self_len - start]) + block.call(self.class.new(string[start, self_len - start])) else - yield string[start, self_len - start] + block.call(string[start, self_len - start]) end self end -- cgit v1.2.3 From 1fd08aee15942c3b3e3133f8cc92d4025df024a8 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Sun, 23 Jun 2019 20:01:33 +0900 Subject: Fix argument specs to `Array` --- mrbgems/mruby-array-ext/src/array.c | 2 +- src/array.c | 58 ++++++++++++++++++------------------- 2 files changed, 30 insertions(+), 30 deletions(-) diff --git a/mrbgems/mruby-array-ext/src/array.c b/mrbgems/mruby-array-ext/src/array.c index 20c771a97..cb4798d49 100644 --- a/mrbgems/mruby-array-ext/src/array.c +++ b/mrbgems/mruby-array-ext/src/array.c @@ -194,7 +194,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, "slice!", mrb_ary_slice_bang, MRB_ARGS_ANY()); + mrb_define_method(mrb, a, "slice!", mrb_ary_slice_bang, MRB_ARGS_ARG(1,1)); } void diff --git a/src/array.c b/src/array.c index bd9b4d358..8cf813743 100644 --- a/src/array.c +++ b/src/array.c @@ -1262,39 +1262,39 @@ mrb_init_array(mrb_state *mrb) { struct RClass *a; - mrb->array_class = a = mrb_define_class(mrb, "Array", mrb->object_class); /* 15.2.12 */ + mrb->array_class = a = mrb_define_class(mrb, "Array", mrb->object_class); /* 15.2.12 */ MRB_SET_INSTANCE_TT(a, MRB_TT_ARRAY); - mrb_define_class_method(mrb, a, "[]", mrb_ary_s_create, MRB_ARGS_ANY()); /* 15.2.12.4.1 */ - - mrb_define_method(mrb, a, "+", mrb_ary_plus, MRB_ARGS_REQ(1)); /* 15.2.12.5.1 */ - mrb_define_method(mrb, a, "*", mrb_ary_times, MRB_ARGS_REQ(1)); /* 15.2.12.5.2 */ - mrb_define_method(mrb, a, "<<", mrb_ary_push_m, MRB_ARGS_REQ(1)); /* 15.2.12.5.3 */ - mrb_define_method(mrb, a, "[]", mrb_ary_aget, MRB_ARGS_ANY()); /* 15.2.12.5.4 */ - mrb_define_method(mrb, a, "[]=", mrb_ary_aset, MRB_ARGS_ANY()); /* 15.2.12.5.5 */ - mrb_define_method(mrb, a, "clear", mrb_ary_clear_m, MRB_ARGS_NONE()); /* 15.2.12.5.6 */ - mrb_define_method(mrb, a, "concat", mrb_ary_concat_m, MRB_ARGS_REQ(1)); /* 15.2.12.5.8 */ - mrb_define_method(mrb, a, "delete_at", mrb_ary_delete_at, MRB_ARGS_REQ(1)); /* 15.2.12.5.9 */ - mrb_define_method(mrb, a, "empty?", mrb_ary_empty_p, MRB_ARGS_NONE()); /* 15.2.12.5.12 */ - mrb_define_method(mrb, a, "first", mrb_ary_first, MRB_ARGS_OPT(1)); /* 15.2.12.5.13 */ - mrb_define_method(mrb, a, "index", mrb_ary_index_m, MRB_ARGS_REQ(1)); /* 15.2.12.5.14 */ - mrb_define_method(mrb, a, "initialize_copy", mrb_ary_replace_m, MRB_ARGS_REQ(1)); /* 15.2.12.5.16 */ - mrb_define_method(mrb, a, "join", mrb_ary_join_m, MRB_ARGS_ANY()); /* 15.2.12.5.17 */ - mrb_define_method(mrb, a, "last", mrb_ary_last, MRB_ARGS_ANY()); /* 15.2.12.5.18 */ - mrb_define_method(mrb, a, "length", mrb_ary_size, MRB_ARGS_NONE()); /* 15.2.12.5.19 */ - mrb_define_method(mrb, a, "pop", mrb_ary_pop, MRB_ARGS_NONE()); /* 15.2.12.5.21 */ - mrb_define_method(mrb, a, "push", mrb_ary_push_m, MRB_ARGS_ANY()); /* 15.2.12.5.22 */ - mrb_define_method(mrb, a, "replace", mrb_ary_replace_m, MRB_ARGS_REQ(1)); /* 15.2.12.5.23 */ - mrb_define_method(mrb, a, "reverse", mrb_ary_reverse, MRB_ARGS_NONE()); /* 15.2.12.5.24 */ - mrb_define_method(mrb, a, "reverse!", mrb_ary_reverse_bang, MRB_ARGS_NONE()); /* 15.2.12.5.25 */ - mrb_define_method(mrb, a, "rindex", mrb_ary_rindex_m, MRB_ARGS_REQ(1)); /* 15.2.12.5.26 */ - mrb_define_method(mrb, a, "shift", mrb_ary_shift, MRB_ARGS_NONE()); /* 15.2.12.5.27 */ - mrb_define_method(mrb, a, "size", mrb_ary_size, MRB_ARGS_NONE()); /* 15.2.12.5.28 */ - mrb_define_method(mrb, a, "slice", mrb_ary_aget, MRB_ARGS_ANY()); /* 15.2.12.5.29 */ - mrb_define_method(mrb, a, "unshift", mrb_ary_unshift_m, MRB_ARGS_ANY()); /* 15.2.12.5.30 */ + mrb_define_class_method(mrb, a, "[]", mrb_ary_s_create, MRB_ARGS_ANY()); /* 15.2.12.4.1 */ + + mrb_define_method(mrb, a, "+", mrb_ary_plus, MRB_ARGS_REQ(1)); /* 15.2.12.5.1 */ + mrb_define_method(mrb, a, "*", mrb_ary_times, MRB_ARGS_REQ(1)); /* 15.2.12.5.2 */ + mrb_define_method(mrb, a, "<<", mrb_ary_push_m, MRB_ARGS_REQ(1)); /* 15.2.12.5.3 */ + mrb_define_method(mrb, a, "[]", mrb_ary_aget, MRB_ARGS_ARG(1,1)); /* 15.2.12.5.4 */ + mrb_define_method(mrb, a, "[]=", mrb_ary_aset, MRB_ARGS_ARG(2,1)); /* 15.2.12.5.5 */ + mrb_define_method(mrb, a, "clear", mrb_ary_clear_m, MRB_ARGS_NONE()); /* 15.2.12.5.6 */ + mrb_define_method(mrb, a, "concat", mrb_ary_concat_m, MRB_ARGS_REQ(1)); /* 15.2.12.5.8 */ + mrb_define_method(mrb, a, "delete_at", mrb_ary_delete_at, MRB_ARGS_REQ(1)); /* 15.2.12.5.9 */ + mrb_define_method(mrb, a, "empty?", mrb_ary_empty_p, MRB_ARGS_NONE()); /* 15.2.12.5.12 */ + mrb_define_method(mrb, a, "first", mrb_ary_first, MRB_ARGS_OPT(1)); /* 15.2.12.5.13 */ + mrb_define_method(mrb, a, "index", mrb_ary_index_m, MRB_ARGS_REQ(1)); /* 15.2.12.5.14 */ + mrb_define_method(mrb, a, "initialize_copy", mrb_ary_replace_m, MRB_ARGS_REQ(1)); /* 15.2.12.5.16 */ + mrb_define_method(mrb, a, "join", mrb_ary_join_m, MRB_ARGS_OPT(1)); /* 15.2.12.5.17 */ + mrb_define_method(mrb, a, "last", mrb_ary_last, MRB_ARGS_OPT(1)); /* 15.2.12.5.18 */ + mrb_define_method(mrb, a, "length", mrb_ary_size, MRB_ARGS_NONE()); /* 15.2.12.5.19 */ + mrb_define_method(mrb, a, "pop", mrb_ary_pop, MRB_ARGS_NONE()); /* 15.2.12.5.21 */ + mrb_define_method(mrb, a, "push", mrb_ary_push_m, MRB_ARGS_ANY()); /* 15.2.12.5.22 */ + mrb_define_method(mrb, a, "replace", mrb_ary_replace_m, MRB_ARGS_REQ(1)); /* 15.2.12.5.23 */ + mrb_define_method(mrb, a, "reverse", mrb_ary_reverse, MRB_ARGS_NONE()); /* 15.2.12.5.24 */ + mrb_define_method(mrb, a, "reverse!", mrb_ary_reverse_bang, MRB_ARGS_NONE()); /* 15.2.12.5.25 */ + mrb_define_method(mrb, a, "rindex", mrb_ary_rindex_m, MRB_ARGS_REQ(1)); /* 15.2.12.5.26 */ + mrb_define_method(mrb, a, "shift", mrb_ary_shift, MRB_ARGS_NONE()); /* 15.2.12.5.27 */ + mrb_define_method(mrb, a, "size", mrb_ary_size, MRB_ARGS_NONE()); /* 15.2.12.5.28 */ + mrb_define_method(mrb, a, "slice", mrb_ary_aget, MRB_ARGS_ARG(1,1)); /* 15.2.12.5.29 */ + mrb_define_method(mrb, a, "unshift", mrb_ary_unshift_m, MRB_ARGS_ANY()); /* 15.2.12.5.30 */ mrb_define_method(mrb, a, "__ary_eq", mrb_ary_eq, MRB_ARGS_REQ(1)); mrb_define_method(mrb, a, "__ary_cmp", mrb_ary_cmp, MRB_ARGS_REQ(1)); - mrb_define_method(mrb, a, "__ary_index", mrb_ary_index_m, MRB_ARGS_REQ(1)); /* kept for mruby-array-ext */ + mrb_define_method(mrb, a, "__ary_index", mrb_ary_index_m, MRB_ARGS_REQ(1)); /* kept for mruby-array-ext */ mrb_define_method(mrb, a, "__svalue", mrb_ary_svalue, MRB_ARGS_NONE()); } -- cgit v1.2.3 From f71270df7736e9cd53845c45d1eb369227c853ea Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Mon, 24 Jun 2019 18:55:05 +0900 Subject: Compare obj pointer directly instead of using mrb_obj_eq in mrb_gc_unregister Because immediate values are not registered. --- src/gc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gc.c b/src/gc.c index 94068c0f9..b05d929a1 100644 --- a/src/gc.c +++ b/src/gc.c @@ -506,7 +506,7 @@ mrb_gc_unregister(mrb_state *mrb, mrb_value obj) a = mrb_ary_ptr(table); mrb_ary_modify(mrb, a); for (i = 0; i < ARY_LEN(a); i++) { - if (mrb_obj_eq(mrb, ARY_PTR(a)[i], obj)) { + if (mrb_ptr(ARY_PTR(a)[i]) == mrb_ptr(obj)) { mrb_int len = ARY_LEN(a)-1; mrb_value *ptr = ARY_PTR(a); -- cgit v1.2.3 From 46c972f746f37a26104b1e9f317ce5a02daa9f40 Mon Sep 17 00:00:00 2001 From: Ryan Lopopolo Date: Tue, 25 Jun 2019 00:01:51 +0200 Subject: Unify loops to minimize bytecode size --- mrblib/string.rb | 42 +++++++++++++----------------------------- 1 file changed, 13 insertions(+), 29 deletions(-) diff --git a/mrblib/string.rb b/mrblib/string.rb index f1c7f3ba4..d72002209 100644 --- a/mrblib/string.rb +++ b/mrblib/string.rb @@ -20,42 +20,26 @@ class String end raise TypeError unless separator.is_a?(String) - pointer = 0 + paragraph_mode = false + if separator.empty? + paragraph_mode = true + separator = "\n\n" + end start = 0 string = dup self_len = length sep_len = separator.length should_yield_subclass_instances = self.class != String - if separator.empty? - matched_newlines = 0 - while pointer < self_len - c = string[pointer] - if c == "\n" - matched_newlines += 1 - elsif matched_newlines > 1 && should_yield_subclass_instances - block.call(self.class.new(string[start, pointer - start])) - matched_newlines = 0 - start = pointer - elsif matched_newlines > 1 - block.call(string[start, pointer - start]) - matched_newlines = 0 - start = pointer - else - matched_newlines = 0 - end - pointer += 1 - end - else - while (pointer = string.index(separator, start)) - pointer += sep_len - if should_yield_subclass_instances - block.call(self.class.new(string[start, pointer - start])) - else - block.call(string[start, pointer - start]) - end - start = pointer + while (pointer = string.index(separator, start)) + pointer += sep_len + pointer += 1 while paragraph_mode && string[pointer] == "\n" + if should_yield_subclass_instances + block.call(self.class.new(string[start, pointer - start])) + else + block.call(string[start, pointer - start]) end + start = pointer end return self if start == self_len -- cgit v1.2.3 From ace0c76a69600816e583adac3a37df8cb4bb75ff Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Tue, 25 Jun 2019 18:05:03 +0900 Subject: Renamed `stacked` to `onstack`; ref #4523 --- mrbgems/mruby-struct/src/struct.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/mrbgems/mruby-struct/src/struct.c b/mrbgems/mruby-struct/src/struct.c index e1f64df55..e04fe13ad 100644 --- a/mrbgems/mruby-struct/src/struct.c +++ b/mrbgems/mruby-struct/src/struct.c @@ -123,27 +123,27 @@ mrb_struct_ref(mrb_state *mrb, mrb_value obj) static mrb_sym mrb_id_attrset(mrb_state *mrb, mrb_sym id) { -#define STACKED_ALLOC_MAX 32 -#define STACKED_STRING_MAX (STACKED_ALLOC_MAX - 1) /* '=' character */ +#define ONSTACK_ALLOC_MAX 32 +#define ONSTACK_STRLEN_MAX (ONSTACK_ALLOC_MAX - 1) /* '=' character */ const char *name; char *buf; mrb_int len; mrb_sym mid; - char stacked[STACKED_ALLOC_MAX]; + char onstack[ONSTACK_ALLOC_MAX]; name = mrb_sym2name_len(mrb, id, &len); - if (len > STACKED_STRING_MAX) { + if (len > ONSTACK_STRLEN_MAX) { buf = (char *)mrb_malloc(mrb, (size_t)len+1); } else { - buf = stacked; + buf = onstack; } memcpy(buf, name, (size_t)len); buf[len] = '='; mid = mrb_intern(mrb, buf, len+1); - if (buf != stacked) { + if (buf != onstack) { mrb_free(mrb, buf); } return mid; -- cgit v1.2.3 From dc21024ec795bcfcd3018825fa3c272731439a7e Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Tue, 25 Jun 2019 18:05:33 +0900 Subject: Fix `mrb_str_to_str()` to handle symbols. --- src/string.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/string.c b/src/string.c index ed58c484b..856e908af 100644 --- a/src/string.c +++ b/src/string.c @@ -973,6 +973,8 @@ mrb_str_to_str(mrb_state *mrb, mrb_value str) switch (mrb_type(str)) { case MRB_TT_STRING: return str; + case MRB_TT_SYMBOL: + return mrb_sym2str(mrb, mrb_symbol(str)); case MRB_TT_FIXNUM: return mrb_fixnum_to_str(mrb, str, 10); case MRB_TT_CLASS: -- cgit v1.2.3 From 6724416d5c6289a1e7bd8e0fd0be7d86b6166f93 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Tue, 25 Jun 2019 18:06:39 +0900 Subject: Fixed a bug caused by `to_s` that returns `nil`; fix 4504 --- mrbgems/mruby-method/src/method.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/mrbgems/mruby-method/src/method.c b/mrbgems/mruby-method/src/method.c index 9f1134227..d94db1cb2 100644 --- a/mrbgems/mruby-method/src/method.c +++ b/mrbgems/mruby-method/src/method.c @@ -270,16 +270,16 @@ method_to_s(mrb_state *mrb, mrb_value self) mrb_str_cat_lit(mrb, str, ": "); rklass = mrb_class_ptr(klass); if (mrb_class_ptr(owner) == rklass) { - mrb_str_cat_str(mrb, str, mrb_funcall(mrb, owner, "to_s", 0)); + mrb_str_cat_str(mrb, str, mrb_str_to_str(mrb, owner)); mrb_str_cat_lit(mrb, str, "#"); - mrb_str_cat_str(mrb, str, mrb_funcall(mrb, name, "to_s", 0)); + mrb_str_cat_str(mrb, str, mrb_str_to_str(mrb, name)); } else { mrb_str_cat_cstr(mrb, str, mrb_class_name(mrb, rklass)); mrb_str_cat_lit(mrb, str, "("); - mrb_str_cat_str(mrb, str, mrb_funcall(mrb, owner, "to_s", 0)); + mrb_str_cat_str(mrb, str, mrb_str_to_str(mrb, owner)); mrb_str_cat_lit(mrb, str, ")#"); - mrb_str_cat_str(mrb, str, mrb_funcall(mrb, name, "to_s", 0)); + mrb_str_cat_str(mrb, str, mrb_str_to_str(mrb, name)); } mrb_str_cat_lit(mrb, str, ">"); return str; -- cgit v1.2.3 From 63d8b5e1e32cbbeb2368b06b3efa7723bf0677d2 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Tue, 25 Jun 2019 18:41:17 +0900 Subject: Fixed `mrb_iv_remove` with immediate objects; fix #4519 The #4520 tried to address the issue, but it changes the type of `mrb_check_frozen` argument; close #4520 --- src/variable.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/variable.c b/src/variable.c index 23d900b7d..e6f2f397e 100644 --- a/src/variable.c +++ b/src/variable.c @@ -521,11 +521,11 @@ mrb_obj_iv_inspect(mrb_state *mrb, struct RObject *obj) MRB_API mrb_value mrb_iv_remove(mrb_state *mrb, mrb_value obj, mrb_sym sym) { - mrb_check_frozen(mrb, mrb_obj_ptr(obj)); if (obj_iv_p(obj)) { iv_tbl *t = mrb_obj_ptr(obj)->iv; mrb_value val; + mrb_check_frozen(mrb, mrb_obj_ptr(obj)); if (iv_del(mrb, t, sym, &val)) { return val; } -- cgit v1.2.3 From 75df13a97334c162b2cf743c3e37c4933a4b0d1c Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Tue, 25 Jun 2019 22:58:21 +0900 Subject: Fix `String#byteslice` with `MRB_UTF8_STRING` and some edge cases MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Example: $ bin/mruby -e ' p "あa".byteslice(1) p "bar".byteslice(3) p "bar".byteslice(4..0) ' Before this patch: "a" "" RangeError (4..0 out of range) After this patch (same as Ruby): "\x81" nil nil --- include/mruby/string.h | 3 ++ mrbgems/mruby-string-ext/src/string.c | 58 +++++++++++++-------------------- mrbgems/mruby-string-ext/test/string.rb | 51 +++++++++++++++++++++++++++++ src/string.c | 49 ++++++++++++++-------------- 4 files changed, 102 insertions(+), 59 deletions(-) diff --git a/include/mruby/string.h b/include/mruby/string.h index 22445f654..b563541cb 100644 --- a/include/mruby/string.h +++ b/include/mruby/string.h @@ -438,6 +438,9 @@ mrb_value mrb_str_inspect(mrb_state *mrb, mrb_value str); #define mrb_str_buf_cat(mrb, str, ptr, len) mrb_str_cat(mrb, str, ptr, len) #define mrb_str_buf_append(mrb, str, str2) mrb_str_cat_str(mrb, str, str2) +mrb_bool mrb_str_beg_len(mrb_int str_len, mrb_int *begp, mrb_int *lenp); +mrb_value mrb_str_byte_subseq(mrb_state *mrb, mrb_value str, mrb_int beg, mrb_int len); + #ifdef MRB_UTF8_STRING mrb_int mrb_utf8_len(const char *str, mrb_int byte_len); #endif diff --git a/mrbgems/mruby-string-ext/src/string.c b/mrbgems/mruby-string-ext/src/string.c index d9ebb7392..50a4e5582 100644 --- a/mrbgems/mruby-string-ext/src/string.c +++ b/mrbgems/mruby-string-ext/src/string.c @@ -42,44 +42,32 @@ mrb_str_setbyte(mrb_state *mrb, mrb_value str) static mrb_value mrb_str_byteslice(mrb_state *mrb, mrb_value str) { - mrb_value a1; - mrb_int len; - - if (mrb_get_argc(mrb) == 2) { - mrb_int pos; - mrb_get_args(mrb, "ii", &pos, &len); - return mrb_str_substr(mrb, str, pos, len); + mrb_value a1, a2; + mrb_int str_len = RSTRING_LEN(str), beg, len; + mrb_bool empty = TRUE; + + if (mrb_get_args(mrb, "o|o", &a1, &a2) == 2) { + beg = mrb_fixnum(mrb_to_int(mrb, a1)); + len = mrb_fixnum(mrb_to_int(mrb, a2)); + goto subseq; } - mrb_get_args(mrb, "o|i", &a1, &len); - switch (mrb_type(a1)) { - case MRB_TT_RANGE: - { - mrb_int beg; - - len = RSTRING_LEN(str); - switch (mrb_range_beg_len(mrb, a1, &beg, &len, len, TRUE)) { - case MRB_RANGE_TYPE_MISMATCH: - break; - case MRB_RANGE_OK: - return mrb_str_substr(mrb, str, beg, len); - case MRB_RANGE_OUT: - mrb_raisef(mrb, E_RANGE_ERROR, "%S out of range", a1); - break; - } - return mrb_nil_value(); + if (mrb_type(a1) == MRB_TT_RANGE) { + if (mrb_range_beg_len(mrb, a1, &beg, &len, str_len, TRUE) == MRB_RANGE_OK) { + goto subseq; } -#ifndef MRB_WITHOUT_FLOAT - case MRB_TT_FLOAT: - a1 = mrb_fixnum_value((mrb_int)mrb_float(a1)); - /* fall through */ -#endif - case MRB_TT_FIXNUM: - return mrb_str_substr(mrb, str, mrb_fixnum(a1), 1); - default: - mrb_raise(mrb, E_TYPE_ERROR, "wrong type of argument"); + return mrb_nil_value(); + } + + beg = mrb_fixnum(mrb_to_int(mrb, a1)); + len = 1; + empty = FALSE; +subseq: + if (mrb_str_beg_len(str_len, &beg, &len) && (empty || len != 0)) { + return mrb_str_byte_subseq(mrb, str, beg, len); + } + else { + return mrb_nil_value(); } - /* not reached */ - return mrb_nil_value(); } /* diff --git a/mrbgems/mruby-string-ext/test/string.rb b/mrbgems/mruby-string-ext/test/string.rb index 02777e594..bf633bcef 100644 --- a/mrbgems/mruby-string-ext/test/string.rb +++ b/mrbgems/mruby-string-ext/test/string.rb @@ -26,10 +26,61 @@ end assert('String#byteslice') do str1 = "hello" + str2 = "\u3042ab" # "\xE3\x81\x82ab" + + assert_equal("h", str1.byteslice(0)) assert_equal("e", str1.byteslice(1)) + assert_equal(nil, str1.byteslice(5)) assert_equal("o", str1.byteslice(-1)) + assert_equal(nil, str1.byteslice(-6)) + assert_equal("\xE3", str2.byteslice(0)) + assert_equal("\x81", str2.byteslice(1)) + assert_equal(nil, str2.byteslice(5)) + assert_equal("b", str2.byteslice(-1)) + assert_equal(nil, str2.byteslice(-6)) + + assert_equal("", str1.byteslice(0, 0)) + assert_equal(str1, str1.byteslice(0, 6)) + assert_equal("el", str1.byteslice(1, 2)) + assert_equal("", str1.byteslice(5, 1)) + assert_equal("o", str1.byteslice(-1, 6)) + assert_equal(nil, str1.byteslice(-6, 1)) + assert_equal(nil, str1.byteslice(0, -1)) + assert_equal("", str2.byteslice(0, 0)) + assert_equal(str2, str2.byteslice(0, 6)) + assert_equal("\x81\x82", str2.byteslice(1, 2)) + assert_equal("", str2.byteslice(5, 1)) + assert_equal("b", str2.byteslice(-1, 6)) + assert_equal(nil, str2.byteslice(-6, 1)) + assert_equal(nil, str2.byteslice(0, -1)) + assert_equal("ell", str1.byteslice(1..3)) assert_equal("el", str1.byteslice(1...3)) + assert_equal("h", str1.byteslice(0..0)) + assert_equal("", str1.byteslice(5..0)) + assert_equal("o", str1.byteslice(4..5)) + assert_equal(nil, str1.byteslice(6..0)) + assert_equal("", str1.byteslice(-1..0)) + assert_equal("llo", str1.byteslice(-3..5)) + assert_equal("\x81\x82a", str2.byteslice(1..3)) + assert_equal("\x81\x82", str2.byteslice(1...3)) + assert_equal("\xE3", str2.byteslice(0..0)) + assert_equal("", str2.byteslice(5..0)) + assert_equal("b", str2.byteslice(4..5)) + assert_equal(nil, str2.byteslice(6..0)) + assert_equal("", str2.byteslice(-1..0)) + assert_equal("\x82ab", str2.byteslice(-3..5)) + + assert_raise(ArgumentError) { str1.byteslice } + assert_raise(ArgumentError) { str1.byteslice(1, 2, 3) } + assert_raise(TypeError) { str1.byteslice("1") } + assert_raise(TypeError) { str1.byteslice("1", 2) } + assert_raise(TypeError) { str1.byteslice(1, "2") } + assert_raise(TypeError) { str1.byteslice(1..2, 3) } + + skip unless Object.const_defined?(:Float) + assert_equal("o", str1.byteslice(4.0)) + assert_equal("\x82ab", str2.byteslice(2.0, 3.0)) end assert('String#dump') do diff --git a/src/string.c b/src/string.c index ed58c484b..f5fb936a6 100644 --- a/src/string.c +++ b/src/string.c @@ -410,8 +410,8 @@ str_make_shared(mrb_state *mrb, struct RString *orig, struct RString *s) } } -static mrb_value -byte_subseq(mrb_state *mrb, mrb_value str, mrb_int beg, mrb_int len) +mrb_value +mrb_str_byte_subseq(mrb_state *mrb, mrb_value str, mrb_int beg, mrb_int len) { struct RString *orig, *s; @@ -434,32 +434,33 @@ str_subseq(mrb_state *mrb, mrb_value str, mrb_int beg, mrb_int len) beg = chars2bytes(str, 0, beg); len = chars2bytes(str, beg, len); - return byte_subseq(mrb, str, beg, len); + return mrb_str_byte_subseq(mrb, str, beg, len); } #else -#define str_subseq(mrb, str, beg, len) byte_subseq(mrb, str, beg, len) +#define str_subseq(mrb, str, beg, len) mrb_str_byte_subseq(mrb, str, beg, len) #endif -static mrb_value -str_substr(mrb_state *mrb, mrb_value str, mrb_int beg, mrb_int len) +mrb_bool +mrb_str_beg_len(mrb_int str_len, mrb_int *begp, mrb_int *lenp) { - mrb_int clen = RSTRING_CHAR_LEN(str); - - if (len < 0) return mrb_nil_value(); - if (clen == 0) { - len = 0; + if (str_len < *begp || *lenp < 0) return FALSE; + if (*begp < 0) { + *begp += str_len; + if (*begp < 0) return FALSE; } - if (beg > clen) return mrb_nil_value(); - if (beg < 0) { - beg += clen; - if (beg < 0) return mrb_nil_value(); + if (*lenp > str_len - *begp) + *lenp = str_len - *begp; + if (*lenp <= 0) { + *lenp = 0; } - if (len > clen - beg) - len = clen - beg; - if (len <= 0) { - len = 0; - } - return str_subseq(mrb, str, beg, len); + return TRUE; +} + +static mrb_value +str_substr(mrb_state *mrb, mrb_value str, mrb_int beg, mrb_int len) +{ + return mrb_str_beg_len(RSTRING_CHAR_LEN(str), &beg, &len) ? + str_subseq(mrb, str, beg, len) : mrb_nil_value(); } MRB_API mrb_int @@ -1917,7 +1918,7 @@ mrb_str_split_m(mrb_state *mrb, mrb_value str) } } else if (ISSPACE(c)) { - mrb_ary_push(mrb, result, byte_subseq(mrb, str, beg, end-beg)); + mrb_ary_push(mrb, result, mrb_str_byte_subseq(mrb, str, beg, end-beg)); mrb_gc_arena_restore(mrb, ai); skip = TRUE; beg = idx; @@ -1942,7 +1943,7 @@ mrb_str_split_m(mrb_state *mrb, mrb_value str) else { end = chars2bytes(str, idx, 1); } - mrb_ary_push(mrb, result, byte_subseq(mrb, str, idx, end)); + mrb_ary_push(mrb, result, mrb_str_byte_subseq(mrb, str, idx, end)); mrb_gc_arena_restore(mrb, ai); idx += end + pat_len; if (lim_p && lim <= ++i) break; @@ -1954,7 +1955,7 @@ mrb_str_split_m(mrb_state *mrb, mrb_value str) tmp = mrb_str_new_empty(mrb, str); } else { - tmp = byte_subseq(mrb, str, beg, RSTRING_LEN(str)-beg); + tmp = mrb_str_byte_subseq(mrb, str, beg, RSTRING_LEN(str)-beg); } mrb_ary_push(mrb, result, tmp); } -- cgit v1.2.3 From 28c510cf41767ee40dbea9b0b1f165a28da956d1 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Wed, 26 Jun 2019 15:38:20 +0900 Subject: Silence unused label warnings from gcc; ref #4524 mruby/mruby/src/string.c:1722:4: warning: label 'bytes' defined but not used [-Wunused-label] bytes: ^~~~~ --- src/string.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/string.c b/src/string.c index b980ee760..c8a9e61ec 100644 --- a/src/string.c +++ b/src/string.c @@ -1719,12 +1719,15 @@ mrb_str_reverse_bang(mrb_state *mrb, mrb_value str) if (RSTR_LEN(s) > 1) { mrb_str_modify(mrb, s); - bytes: - p = RSTR_PTR(s); - e = p + RSTR_LEN(s) - 1; - str_reverse(p, e); + goto bytes; } return str; + + bytes: + p = RSTR_PTR(s); + e = p + RSTR_LEN(s) - 1; + str_reverse(p, e); + return str; } /* ---------------------------------- */ -- cgit v1.2.3 From 23783a44300a39efbbc312a6ca22fe61d94db857 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Thu, 27 Jun 2019 09:34:40 +0900 Subject: Skip copying delete keys in a hash; fix #4534 --- src/hash.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/hash.c b/src/hash.c index b4d96251c..ac6a7cd56 100644 --- a/src/hash.c +++ b/src/hash.c @@ -240,7 +240,7 @@ ht_compact(mrb_state *mrb, htable *t) if (!seg->next && i >= t->last_len) { goto exit; } - if (mrb_undef_p(k)) { /* found delete key */ + if (mrb_undef_p(k)) { /* found deleted key */ if (seg2 == NULL) { seg2 = seg; i2 = i; @@ -543,6 +543,7 @@ ht_copy(mrb_state *mrb, htable *t) mrb_value key = seg->e[i].key; mrb_value val = seg->e[i].val; + if (mrb_undef_p(key)) continue; /* skip deleted key */ if ((seg->next == NULL) && (i >= t->last_len)) { return t2; } -- cgit v1.2.3 From ad8473bd66c0dd622146e226f281909248b47305 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Thu, 27 Jun 2019 18:47:48 +0900 Subject: Add modification tests for immediate value --- mrbgems/mruby-metaprog/test/metaprog.rb | 4 ++++ test/t/kernel.rb | 1 + 2 files changed, 5 insertions(+) diff --git a/mrbgems/mruby-metaprog/test/metaprog.rb b/mrbgems/mruby-metaprog/test/metaprog.rb index 1e1d4ff26..30b75bd60 100644 --- a/mrbgems/mruby-metaprog/test/metaprog.rb +++ b/mrbgems/mruby-metaprog/test/metaprog.rb @@ -44,6 +44,8 @@ assert('Kernel#instance_variable_set', '15.3.1.3.22') do %w[@6 @% @@a @ a].each do |n| assert_raise(NameError) { o.instance_variable_set(n, 1) } end + assert_raise(FrozenError) { o.freeze.instance_variable_set(:@a, 2) } + assert_raise(FrozenError, ArgumentError) { nil.instance_variable_set(:@a, 2) } end assert('Kernel#instance_variables', '15.3.1.3.23') do @@ -121,6 +123,8 @@ assert('Kernel#define_singleton_method') do end assert_equal :test_method, ret assert_equal :singleton_method_ok, o.test_method + assert_raise(TypeError) { 2.define_singleton_method(:f){} } + assert_raise(FrozenError) { [].freeze.define_singleton_method(:f){} } end assert('Kernel#singleton_class') do diff --git a/test/t/kernel.rb b/test/t/kernel.rb index 103660f53..1e48069f2 100644 --- a/test/t/kernel.rb +++ b/test/t/kernel.rb @@ -419,6 +419,7 @@ assert('Kernel#remove_instance_variable', '15.3.1.3.41') do assert_raise(NameError) { tri.remove } assert_raise(NameError) { tri.remove_instance_variable(:var) } assert_raise(FrozenError) { tri.freeze.remove } + assert_raise(FrozenError, NameError) { :a.remove_instance_variable(:@v) } end # Kernel#require is defined in mruby-require. '15.3.1.3.42' -- cgit v1.2.3 From 5727d3a30cd9fd39103e06186c12058cb8d3407b Mon Sep 17 00:00:00 2001 From: Yasuhiro Horimoto Date: Thu, 27 Jun 2019 22:31:25 +0900 Subject: Fix broken links for mruby.org A part of a fix for issue mruby/mruby.github.io#50 --- README.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 2acc8de1a..863560ebc 100644 --- a/README.md +++ b/README.md @@ -38,7 +38,7 @@ We don't have a mailing list, but you can use [GitHub issues](https://github.com ## How to compile and install (mruby and gems) -See the [doc/guides/compile.md](doc/guides/compile.md) file. +See the [compile.md](https://github.com/mruby/mruby/blob/master/doc/guides/compile.md) file. ## Running Tests @@ -54,12 +54,12 @@ Or mruby contains a package manager called *mrbgems*. To create extensions in C and/or Ruby you should create a *GEM*. For a documentation of how to -use mrbgems consult the file [doc/guides/mrbgems.md](doc/guides/mrbgems.md). For example code of -how to use mrbgems look into the folder *examples/mrbgems/*. +use mrbgems consult the file [mrbgems.md](https://github.com/mruby/mruby/blob/master/doc/guides/mrbgems.md). +For example code of how to use mrbgems look into the folder *examples/mrbgems/*. ## License -mruby is released under the [MIT License](LICENSE). +mruby is released under the [MIT License](https://github.com/mruby/mruby/blob/master/LICENSE). ## Note for License @@ -88,5 +88,5 @@ file in your pull request. [ISO-standard]: http://www.iso.org/iso/iso_catalogue/catalogue_tc/catalogue_detail.htm?csnumber=59579 [build-status-img]: https://travis-ci.org/mruby/mruby.svg?branch=master -[contribution-guidelines]: CONTRIBUTING.md +[contribution-guidelines]: https://github.com/mruby/mruby/blob/master/CONTRIBUTING.md [travis-ci]: https://travis-ci.org/mruby/mruby -- cgit v1.2.3 From bc3176da630e3e055d58aa065ff897aec66df280 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Fri, 28 Jun 2019 19:26:29 +0900 Subject: Use `__ENCODING__` in tests It cannot be used for `String#size` test if judging whether or not `MRB_UTF8_STRING` is defined by result of `String#size`. --- mrbgems/mruby-string-ext/test/string.rb | 2 +- mrbgems/mruby-symbol-ext/test/symbol.rb | 2 +- test/t/string.rb | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/mrbgems/mruby-string-ext/test/string.rb b/mrbgems/mruby-string-ext/test/string.rb index bf633bcef..9a324c46d 100644 --- a/mrbgems/mruby-string-ext/test/string.rb +++ b/mrbgems/mruby-string-ext/test/string.rb @@ -2,7 +2,7 @@ ## # String(Ext) Test -UTF8STRING = ("\343\201\202".size == 1) +UTF8STRING = __ENCODING__ == "UTF-8" assert('String#getbyte') do str1 = "hello" diff --git a/mrbgems/mruby-symbol-ext/test/symbol.rb b/mrbgems/mruby-symbol-ext/test/symbol.rb index 61ecad247..db686e5f4 100644 --- a/mrbgems/mruby-symbol-ext/test/symbol.rb +++ b/mrbgems/mruby-symbol-ext/test/symbol.rb @@ -14,7 +14,7 @@ end assert("Symbol##{n}") do assert_equal 5, :hello.__send__(n) assert_equal 4, :"aA\0b".__send__(n) - if "あ".size == 1 # enable MRB_UTF8_STRING? + if __ENCODING__ == "UTF-8" assert_equal 8, :"こんにちは世界!".__send__(n) assert_equal 4, :"aあ\0b".__send__(n) else diff --git a/test/t/string.rb b/test/t/string.rb index 7ef236dbe..81699f17e 100644 --- a/test/t/string.rb +++ b/test/t/string.rb @@ -2,7 +2,7 @@ ## # String ISO Test -UTF8STRING = ("\343\201\202".size == 1) +UTF8STRING = __ENCODING__ == "UTF-8" assert('String', '15.2.10') do assert_equal Class, String.class -- cgit v1.2.3 From c9a3867ff22a1158b88c1f9119ce3c9e08085e98 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Fri, 28 Jun 2019 19:27:58 +0900 Subject: Remove unnecessary backticks in `src/range.c`; ref #2858 --- src/range.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/range.c b/src/range.c index 9036ef093..c9dfb2b3c 100644 --- a/src/range.c +++ b/src/range.c @@ -92,7 +92,7 @@ range_ptr_init(mrb_state *mrb, struct RRange *r, mrb_value beg, mrb_value end, m if (r) { if (RANGE_INITIALIZED_P(r)) { /* Ranges are immutable, so that they should be initialized only once. */ - mrb_name_error(mrb, mrb_intern_lit(mrb, "initialize"), "`initialize' called twice"); + mrb_name_error(mrb, mrb_intern_lit(mrb, "initialize"), "'initialize' called twice"); } else { range_ptr_alloc_edges(mrb, r); -- cgit v1.2.3 From 5f9034e4283ccaa99c929a36e2cfbb465e8b31b4 Mon Sep 17 00:00:00 2001 From: dearblue Date: Thu, 6 Jun 2019 22:24:58 +0900 Subject: Nested `assert` for mrbtest When nesting `assert` used in test, it is indented and displayed. Assertion numbers are concatenated by `"-"` at this time. The purpose is to match the apparent numbers when failing with `assert_mruby` which is defined by `mrbgems/mruby-bin-mruby/bintest/mruby.rb` for example. Child assertions "skip" and "info" are reported as parent assertions "info" and `$ok_test += 1`. The child assertions "ko" and "crash" are reported as the parent assertion "ko" and `$ko_test += 1`. When child assertions are mixed, "ko" takes precedence. Incompatibility: - `$mrbtest_assert_idx` takes `nil` or an integer array object. So far it was `nil` or an integer. - `$asserts` points to the top of the internal stack in the `assert`. - `$mrbtest_assert` points to the top of the internal stack in `assert`. --- test/assert.rb | 93 +++++++++++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 82 insertions(+), 11 deletions(-) diff --git a/test/assert.rb b/test/assert.rb index 5e2e104b3..c493cbbc0 100644 --- a/test/assert.rb +++ b/test/assert.rb @@ -15,6 +15,36 @@ unless RUBY_ENGINE == "mruby" end end +class Array + def _assertion_join + join("-") + end +end + +class String + def _assertion_indent(indent) + indent = indent.to_s + off = 0 + str = self + while nl = index("\n", off) + nl += 1 + nl += 1 while slice(nl) == "\n" + break if nl >= size + str = indent.dup if off == 0 + str += slice(off, nl - off) + indent + off = nl + end + + if off == 0 + str = indent + self + else + str += slice(off..-1) + end + + str + end +end + ## # Create the assertion in a readable way def assertion_string(err, str, iso=nil, e=nil, bt=nil) @@ -22,14 +52,14 @@ def assertion_string(err, str, iso=nil, e=nil, bt=nil) msg += " [#{iso}]" if iso && !iso.empty? msg += " => #{e}" if e && !e.to_s.empty? msg += " (#{GEMNAME == 'mruby-test' ? 'core' : "mrbgems: #{GEMNAME}"})" - if $mrbtest_assert && $mrbtest_assert.size > 0 + if $mrbtest_assert $mrbtest_assert.each do |idx, assert_msg, diff| msg += "\n - Assertion[#{idx}]" msg += " #{assert_msg}." if assert_msg && !assert_msg.empty? msg += "\n#{diff}" if diff && !diff.empty? end end - msg += "\nbacktrace:\n\t#{bt.join("\n\t")}" if bt + msg += "\nbacktrace:\n #{bt.join("\n ")}" if bt msg end @@ -44,13 +74,35 @@ end def assert(str = 'Assertion failed', iso = '') t_print(str, (iso != '' ? " [#{iso}]" : ''), ' : ') if $mrbtest_verbose begin + $mrbtest_child_noassert ||= [0] + $mrbtest_child_noassert << 0 + parent_asserts = $asserts + $asserts = [] + parent_mrbtest_assert = $mrbtest_assert $mrbtest_assert = [] - $mrbtest_assert_idx = 0 + + if $mrbtest_assert_idx && !$mrbtest_assert_idx.empty? + $mrbtest_assert_idx[-1] += 1 + $mrbtest_assert_idx << 0 + else + $mrbtest_assert_idx = [0] + class << $mrbtest_assert_idx + alias to_s _assertion_join + end + end + yield - if($mrbtest_assert.size > 0) - $asserts.push(assertion_string('Fail: ', str, iso)) - $ko_test += 1 - t_print('F') + if $mrbtest_assert.size > 0 + if $mrbtest_assert.size == $mrbtest_child_noassert[-1] + $asserts.push(assertion_string('Info: ', str, iso)) + $mrbtest_child_noassert[-2] += 1 + $ok_test += 1 + t_print('.') + else + $asserts.push(assertion_string('Fail: ', str, iso)) + $ko_test += 1 + t_print('F') + end else $ok_test += 1 t_print('.') @@ -58,6 +110,7 @@ def assert(str = 'Assertion failed', iso = '') rescue MRubyTestSkip => e $asserts.push(assertion_string('Skip: ', str, iso, e)) $skip_test += 1 + $mrbtest_child_noassert[-2] += 1 t_print('?') rescue Exception => e bt = e.backtrace if $mrbtest_verbose @@ -65,7 +118,25 @@ def assert(str = 'Assertion failed', iso = '') $kill_test += 1 t_print('X') ensure - $mrbtest_assert = nil + if $mrbtest_assert_idx.size > 1 + $asserts.each do |mesg| + idx = $mrbtest_assert_idx[0..-2]._assertion_join + mesg = mesg._assertion_indent(" ") + + # Give `mesg` as a `diff` argument to avoid adding extra periods. + parent_mrbtest_assert << [idx, nil, mesg] + end + else + parent_asserts.concat $asserts + end + $asserts = parent_asserts + + $mrbtest_assert = parent_mrbtest_assert + $mrbtest_assert_idx.pop + $mrbtest_assert_idx = nil if $mrbtest_assert_idx.empty? + $mrbtest_child_noassert.pop + + nil end t_print("\n") if $mrbtest_verbose end @@ -76,11 +147,11 @@ def assertion_diff(exp, act) end def assert_true(obj, msg = nil, diff = nil) - if $mrbtest_assert - $mrbtest_assert_idx += 1 + if $mrbtest_assert_idx && $mrbtest_assert_idx.size > 0 + $mrbtest_assert_idx[-1] += 1 unless obj == true diff ||= " Expected #{obj.inspect} to be true." - $mrbtest_assert.push([$mrbtest_assert_idx, msg, diff]) + $mrbtest_assert.push([$mrbtest_assert_idx.to_s, msg, diff]) end end obj -- cgit v1.2.3 From 1b9f949f3662ffaf39145638e15d628e0e94661e Mon Sep 17 00:00:00 2001 From: dearblue Date: Fri, 28 Jun 2019 23:17:25 +0900 Subject: Use a normal method instead of a lambda Ref commit 35319bed01d58c785f73ce03e67d4e58be30f4b5 --- mrbgems/mruby-io/test/io.rb | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/mrbgems/mruby-io/test/io.rb b/mrbgems/mruby-io/test/io.rb index 5004d0042..ef0b49643 100644 --- a/mrbgems/mruby-io/test/io.rb +++ b/mrbgems/mruby-io/test/io.rb @@ -4,7 +4,7 @@ MRubyIOTestUtil.io_test_setup $cr, $crlf, $cmd = MRubyIOTestUtil.win? ? [1, "\r\n", "cmd /c "] : [0, "\n", ""] -assert_io_open = ->(meth) do +def assert_io_open(meth) fd = IO.sysopen($mrbtest_io_rfname) assert_equal Fixnum, fd.class io1 = IO.__send__(meth, fd) @@ -38,7 +38,7 @@ assert('IO.ancestors', '15.2.20.3') do end assert('IO.open', '15.2.20.4.1') do - assert_io_open.(:open) + assert_io_open(:open) end assert('IO#close', '15.2.20.5.1') do @@ -224,11 +224,11 @@ assert('IO#dup for writable') do end assert('IO.for_fd') do - assert_io_open.(:for_fd) + assert_io_open(:for_fd) end assert('IO.new') do - assert_io_open.(:new) + assert_io_open(:new) end assert('IO gc check') do -- cgit v1.2.3 From a215292b6ad4315a5a0edef49a1df65e3f27b46a Mon Sep 17 00:00:00 2001 From: dearblue Date: Fri, 28 Jun 2019 23:13:29 +0900 Subject: Use nested `assert` --- mrbgems/mruby-bin-mruby/bintest/mruby.rb | 8 +++++--- mrbgems/mruby-complex/test/complex.rb | 6 ++++-- mrbgems/mruby-io/test/io.rb | 32 +++++++++++++++++--------------- mrbgems/mruby-pack/test/pack.rb | 6 ++++-- mrbgems/mruby-rational/test/rational.rb | 20 ++++++++++++-------- 5 files changed, 42 insertions(+), 30 deletions(-) diff --git a/mrbgems/mruby-bin-mruby/bintest/mruby.rb b/mrbgems/mruby-bin-mruby/bintest/mruby.rb index 09350ff49..5dbbc5592 100644 --- a/mrbgems/mruby-bin-mruby/bintest/mruby.rb +++ b/mrbgems/mruby-bin-mruby/bintest/mruby.rb @@ -3,9 +3,11 @@ require 'open3' def assert_mruby(exp_out, exp_err, exp_success, args) out, err, stat = Open3.capture3(cmd("mruby"), *args) - assert_operator(exp_out, :===, out, "standard output") - assert_operator(exp_err, :===, err, "standard error") - assert_equal(exp_success, stat.success?, "exit success?") + assert do + assert_operator(exp_out, :===, out, "standard output") + assert_operator(exp_err, :===, err, "standard error") + assert_equal(exp_success, stat.success?, "exit success?") + end end assert('regression for #1564') do diff --git a/mrbgems/mruby-complex/test/complex.rb b/mrbgems/mruby-complex/test/complex.rb index 6996eb214..ab882664e 100644 --- a/mrbgems/mruby-complex/test/complex.rb +++ b/mrbgems/mruby-complex/test/complex.rb @@ -1,6 +1,8 @@ def assert_complex(real, exp) - assert_float real.real, exp.real - assert_float real.imaginary, exp.imaginary + assert do + assert_float real.real, exp.real + assert_float real.imaginary, exp.imaginary + end end assert 'Complex' do diff --git a/mrbgems/mruby-io/test/io.rb b/mrbgems/mruby-io/test/io.rb index ef0b49643..1491a4cfe 100644 --- a/mrbgems/mruby-io/test/io.rb +++ b/mrbgems/mruby-io/test/io.rb @@ -5,24 +5,26 @@ MRubyIOTestUtil.io_test_setup $cr, $crlf, $cmd = MRubyIOTestUtil.win? ? [1, "\r\n", "cmd /c "] : [0, "\n", ""] def assert_io_open(meth) - fd = IO.sysopen($mrbtest_io_rfname) - assert_equal Fixnum, fd.class - io1 = IO.__send__(meth, fd) - begin - assert_equal IO, io1.class - assert_equal $mrbtest_io_msg, io1.read - ensure - io1.close - end + assert do + fd = IO.sysopen($mrbtest_io_rfname) + assert_equal Fixnum, fd.class + io1 = IO.__send__(meth, fd) + begin + assert_equal IO, io1.class + assert_equal $mrbtest_io_msg, io1.read + ensure + io1.close + end - io2 = IO.__send__(meth, IO.sysopen($mrbtest_io_rfname))do |io| - if meth == :open - assert_equal $mrbtest_io_msg, io.read - else - flunk "IO.#{meth} does not take block" + io2 = IO.__send__(meth, IO.sysopen($mrbtest_io_rfname))do |io| + if meth == :open + assert_equal $mrbtest_io_msg, io.read + else + flunk "IO.#{meth} does not take block" + end end + io2.close unless meth == :open end - io2.close unless meth == :open end assert('IO.class', '15.2.20') do diff --git a/mrbgems/mruby-pack/test/pack.rb b/mrbgems/mruby-pack/test/pack.rb index 110aee5db..eb24e8d1f 100644 --- a/mrbgems/mruby-pack/test/pack.rb +++ b/mrbgems/mruby-pack/test/pack.rb @@ -2,8 +2,10 @@ PACK_IS_LITTLE_ENDIAN = "\x01\00".unpack('S')[0] == 0x01 def assert_pack tmpl, packed, unpacked t = tmpl.inspect - assert_equal packed, unpacked.pack(tmpl), "#{unpacked.inspect}.pack(#{t})" - assert_equal unpacked, packed.unpack(tmpl), "#{packed.inspect}.unpack(#{t})" + assert do + assert_equal packed, unpacked.pack(tmpl), "#{unpacked.inspect}.pack(#{t})" + assert_equal unpacked, packed.unpack(tmpl), "#{packed.inspect}.unpack(#{t})" + end end # pack & unpack 'm' (base64) diff --git a/mrbgems/mruby-rational/test/rational.rb b/mrbgems/mruby-rational/test/rational.rb index 5e9d9ea48..11737034b 100644 --- a/mrbgems/mruby-rational/test/rational.rb +++ b/mrbgems/mruby-rational/test/rational.rb @@ -23,17 +23,21 @@ class ComplexLikeNumeric < UserDefinedNumeric end def assert_rational(exp, real) - assert_float exp.numerator, real.numerator - assert_float exp.denominator, real.denominator + assert do + assert_float exp.numerator, real.numerator + assert_float exp.denominator, real.denominator + end end def assert_equal_rational(exp, o1, o2) - if exp - assert_operator(o1, :==, o2) - assert_not_operator(o1, :!=, o2) - else - assert_not_operator(o1, :==, o2) - assert_operator(o1, :!=, o2) + assert do + if exp + assert_operator(o1, :==, o2) + assert_not_operator(o1, :!=, o2) + else + assert_not_operator(o1, :==, o2) + assert_operator(o1, :!=, o2) + end end end -- cgit v1.2.3 From 40030a5dbc2b76bbd9563cdfc6389ab672312b70 Mon Sep 17 00:00:00 2001 From: dearblue Date: Tue, 21 May 2019 21:58:53 +0900 Subject: Add test for `String#[]=` --- test/t/string.rb | 50 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) diff --git a/test/t/string.rb b/test/t/string.rb index 81699f17e..87d60ed72 100644 --- a/test/t/string.rb +++ b/test/t/string.rb @@ -209,6 +209,56 @@ assert('String#[]=') do assert_raise(TypeError) { 'a'[0, 1] = 1 } end +assert('String[]=(UTF-8)') do + a = "➀➁➂➃➄" + a[3] = "⚃" + assert_equal "➀➁➂⚃➄", a + + b = "➀➁➂➃➄" + b[3, 0] = "⛄" + assert_equal "➀➁➂⛄➃➄", b + + c = "➀➁➂➃➄" + c[3, 2] = "⚃⚄" + assert_equal "➀➁➂⚃⚄", c + + d = "➀➁➂➃➄" + d[5] = "⛄" + assert_equal "➀➁➂➃➄⛄", d + + e = "➀➁➂➃➄" + e[5, 0] = "⛄" + assert_equal "➀➁➂➃➄⛄", e + + f = "➀➁➂➃➄" + f[5, 2] = "⛄" + assert_equal "➀➁➂➃➄⛄", f + + g = "➀➁➂➃➄" + assert_raise(IndexError) { g[6] = "⛄" } + + h = "➀➁➂➃➄" + assert_raise(IndexError) { h[6, 0] = "⛄" } + + i = "➀➁➂➃➄" + assert_raise(IndexError) { i[6, 2] = "⛄" } + + j = "➀➁➂➃➄" + j["➃"] = "⚃" + assert_equal "➀➁➂⚃➄", j + + k = "➀➁➂➃➄" + assert_raise(IndexError) { k["⛄"] = "⛇" } + + l = "➀➁➂➃➄" + assert_nothing_raised { l["➂"] = "" } + assert_equal "➀➁➃➄", l + + m = "➀➁➂➃➄" + assert_raise(TypeError) { m["➂"] = nil } + assert_equal "➀➁➂➃➄", m +end if UTF8STRING + assert('String#capitalize', '15.2.10.5.7') do a = 'abc' a.capitalize -- cgit v1.2.3 From 0d452073f46fc46496200db610ce785e514cdb65 Mon Sep 17 00:00:00 2001 From: dearblue Date: Tue, 21 May 2019 22:02:11 +0900 Subject: Replace `String#[]=` method by C implements The purpose is to eliminate string objects that are temporarily created during processing. --- mrblib/string.rb | 54 ----------------- src/string.c | 176 ++++++++++++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 173 insertions(+), 57 deletions(-) diff --git a/mrblib/string.rb b/mrblib/string.rb index b0fe4033e..c26cdb1e2 100644 --- a/mrblib/string.rb +++ b/mrblib/string.rb @@ -177,60 +177,6 @@ class String self end - ## - # Modify +self+ by replacing the content of +self+. - # The portion of the string affected is determined using the same criteria as +String#[]+. - def []=(*args) - anum = args.size - if anum == 2 - pos, value = args[0], args[1].__to_str - case pos - when String - posnum = self.index(pos) - if posnum - b = self[0, posnum] - a = self[(posnum + pos.length)..-1] - self.replace([b, value, a].join('')) - else - raise IndexError, "string not matched" - end - when Range - head = pos.begin - tail = pos.end - tail += self.length if tail < 0 - unless pos.exclude_end? - tail += 1 - end - return self[head, tail-head]=value - else - pos = pos.__to_int - pos += self.length if pos < 0 - if pos < 0 || pos > self.length - raise IndexError, "index #{args[0]} out of string" - end - b = self[0, pos] - a = self[pos + 1..-1] - self.replace([b, value, a].join('')) - end - return value - elsif anum == 3 - pos, len, value = args[0].__to_int, args[1].__to_int, args[2].__to_str - pos += self.length if pos < 0 - if pos < 0 || pos > self.length - raise IndexError, "index #{args[0]} out of string" - end - if len < 0 - raise IndexError, "negative length #{len}" - end - b = self[0, pos] - a = self[pos + len..-1] - self.replace([b, value, a].join('')) - return value - else - raise ArgumentError, "wrong number of arguments (#{anum} for 2..3)" - end - end - # those two methods requires Regexp that is optional in mruby ## # ISO 15.2.10.5.3 diff --git a/src/string.c b/src/string.c index c8a9e61ec..43bf8a841 100644 --- a/src/string.c +++ b/src/string.c @@ -427,13 +427,18 @@ mrb_str_byte_subseq(mrb_state *mrb, mrb_value str, mrb_int beg, mrb_int len) } 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) { - beg = chars2bytes(str, 0, beg); - len = chars2bytes(str, beg, len); - + str_range_to_bytes(str, &beg, &len); return mrb_str_byte_subseq(mrb, str, beg, len); } #else @@ -1010,6 +1015,68 @@ mrb_str_dup(mrb_state *mrb, mrb_value str) return str_replace(mrb, dup, s); } +enum str_convert_range { + /* `beg` and `len` are byte unit in `0 ... str.bytesize` */ + STR_BYTE_RANGE_CORRECTED = 1, + + /* `beg` and `len` are char unit in any range */ + STR_CHAR_RANGE = 2, + + /* `beg` and `len` are char unit in `0 ... str.size` */ + STR_CHAR_RANGE_CORRECTED = 3, + + /* `beg` is out of range */ + STR_OUT_OF_RANGE = -1 +}; + +static enum str_convert_range +str_convert_range(mrb_state *mrb, mrb_value str, mrb_value indx, mrb_value alen, mrb_int *beg, mrb_int *len) +{ + if (!mrb_undef_p(alen)) { + *beg = mrb_int(mrb, indx); + *len = mrb_int(mrb, alen); + return STR_CHAR_RANGE; + } + else { + switch (mrb_type(indx)) { + case MRB_TT_FIXNUM: + *beg = mrb_fixnum(indx); + *len = 1; + return STR_CHAR_RANGE; + + case MRB_TT_STRING: + *beg = str_index_str(mrb, str, indx, 0); + if (*beg < 0) { break; } + *len = RSTRING_LEN(indx); + return STR_BYTE_RANGE_CORRECTED; + + case MRB_TT_RANGE: + goto range_arg; + + default: + indx = mrb_to_int(mrb, indx); + if (mrb_fixnum_p(indx)) { + *beg = mrb_fixnum(indx); + *len = 1; + return STR_CHAR_RANGE; + } +range_arg: + *len = RSTRING_CHAR_LEN(str); + switch (mrb_range_beg_len(mrb, indx, beg, len, *len, TRUE)) { + case MRB_RANGE_OK: + return STR_CHAR_RANGE_CORRECTED; + case MRB_RANGE_OUT: + return STR_OUT_OF_RANGE; + default: + break; + } + + mrb_raise(mrb, E_TYPE_ERROR, "can't convert to Fixnum"); + } + } + return STR_OUT_OF_RANGE; +} + static mrb_value mrb_str_aref(mrb_state *mrb, mrb_value str, mrb_value indx) { @@ -1113,6 +1180,108 @@ mrb_str_aref_m(mrb_state *mrb, mrb_value str) return mrb_str_aref(mrb, str, a1); } +static mrb_noreturn void +str_out_of_index(mrb_state *mrb, mrb_value index) +{ + mrb_raisef(mrb, E_INDEX_ERROR, "index %S out of string", index); +} + +static mrb_value +str_replace_partial(mrb_state *mrb, mrb_value src, mrb_int pos, mrb_int end, mrb_value rep) +{ + const mrb_int shrink_threshold = 256; + struct RString *str = mrb_str_ptr(src); + mrb_int len = RSTR_LEN(str); + mrb_int replen, newlen; + char *strp; + + if (end > len) { end = len; } + + if (pos < 0 || pos > len) { + str_out_of_index(mrb, mrb_fixnum_value(pos)); + } + + replen = (mrb_nil_p(rep) ? 0 : RSTRING_LEN(rep)); + newlen = replen + len - (end - pos); + + if (newlen >= MRB_INT_MAX || newlen < replen /* overflowed */) { + mrb_raise(mrb, E_RUNTIME_ERROR, "string size too big"); + } + + mrb_str_modify(mrb, str); + + if (len < newlen || len - newlen >= shrink_threshold) { + resize_capa(mrb, str, newlen); + } + + strp = RSTR_PTR(str); + + memmove(strp + newlen - (len - end), strp + end, len - end); + if (!mrb_nil_p(rep)) { + memcpy(strp + pos, RSTRING_PTR(rep), replen); + } + RSTR_SET_LEN(str, newlen); + strp[newlen] = '\0'; + + return src; +} + +static void +mrb_str_aset(mrb_state *mrb, mrb_value str, mrb_value indx, mrb_value alen, mrb_value replace) +{ + mrb_int beg, len, charlen; + + replace = mrb_to_str(mrb, replace); + + switch (str_convert_range(mrb, str, indx, alen, &beg, &len)) { + case STR_OUT_OF_RANGE: + default: + mrb_raise(mrb, E_INDEX_ERROR, "string not matched"); + case STR_CHAR_RANGE: + if (len < 0) { + mrb_raisef(mrb, E_INDEX_ERROR, "negative length %S", alen); + } + charlen = RSTRING_CHAR_LEN(str); + if (beg < 0) { beg += charlen; } + 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); + /* fall through */ + case STR_BYTE_RANGE_CORRECTED: + str_replace_partial(mrb, str, beg, beg + len, replace); + } +} + +/* + * call-seq: + * str[fixnum] = replace + * str[fixnum, fixnum] = replace + * str[range] = replace + * str[regexp] = replace + * str[regexp, fixnum] = replace + * str[other_str] = replace + * + * Modify +self+ by replacing the content of +self+. + * The portion of the string affected is determined using the same criteria as +String#[]+. + */ +static mrb_value +mrb_str_aset_m(mrb_state *mrb, mrb_value str) +{ + mrb_value indx, alen, replace; + + switch (mrb_get_args(mrb, "oo|S!", &indx, &alen, &replace)) { + case 2: + replace = alen; + alen = mrb_undef_value(); + break; + case 3: + break; + } + mrb_str_aset(mrb, str, indx, alen, replace); + return str; +} + /* 15.2.10.5.8 */ /* * call-seq: @@ -2678,6 +2847,7 @@ mrb_init_string(mrb_state *mrb) mrb_define_method(mrb, s, "+", mrb_str_plus_m, MRB_ARGS_REQ(1)); /* 15.2.10.5.4 */ mrb_define_method(mrb, s, "*", mrb_str_times, MRB_ARGS_REQ(1)); /* 15.2.10.5.5 */ mrb_define_method(mrb, s, "[]", mrb_str_aref_m, MRB_ARGS_ANY()); /* 15.2.10.5.6 */ + mrb_define_method(mrb, s, "[]=", mrb_str_aset_m, MRB_ARGS_ANY()); mrb_define_method(mrb, s, "capitalize", mrb_str_capitalize, MRB_ARGS_NONE()); /* 15.2.10.5.7 */ mrb_define_method(mrb, s, "capitalize!", mrb_str_capitalize_bang, MRB_ARGS_NONE()); /* 15.2.10.5.8 */ mrb_define_method(mrb, s, "chomp", mrb_str_chomp, MRB_ARGS_ANY()); /* 15.2.10.5.9 */ -- cgit v1.2.3 From 0ad1cacff30c744fcf07869990cbab7bc51c4c68 Mon Sep 17 00:00:00 2001 From: dearblue Date: Thu, 27 Jun 2019 20:46:49 +0900 Subject: Simplify `mrb_str_aref_m()` and `mrb_str_aref()` It is integration with part of argument parsing used in `mrb_str_aset_m()`. --- src/string.c | 66 ++++++++++++++++++------------------------------------------ 1 file changed, 20 insertions(+), 46 deletions(-) diff --git a/src/string.c b/src/string.c index 43bf8a841..6938418fb 100644 --- a/src/string.c +++ b/src/string.c @@ -1078,50 +1078,28 @@ range_arg: } static mrb_value -mrb_str_aref(mrb_state *mrb, mrb_value str, mrb_value indx) +mrb_str_aref(mrb_state *mrb, mrb_value str, mrb_value indx, mrb_value alen) { - mrb_int idx; + mrb_int beg, len; - switch (mrb_type(indx)) { - case MRB_TT_FIXNUM: - idx = mrb_fixnum(indx); - -num_index: - str = str_substr(mrb, str, idx, 1); - if (!mrb_nil_p(str) && RSTRING_LEN(str) == 0) return mrb_nil_value(); + switch (str_convert_range(mrb, str, indx, alen, &beg, &len)) { + case STR_CHAR_RANGE_CORRECTED: + return str_subseq(mrb, str, beg, len); + case STR_CHAR_RANGE: + str = str_substr(mrb, str, beg, len); + if (mrb_undef_p(alen) && !mrb_nil_p(str) && RSTRING_LEN(str) == 0) return mrb_nil_value(); return str; - - case MRB_TT_STRING: - if (str_index_str(mrb, str, indx, 0) != -1) + case STR_BYTE_RANGE_CORRECTED: + if (mrb_string_p(indx)) { return mrb_str_dup(mrb, indx); - return mrb_nil_value(); - - case MRB_TT_RANGE: - goto range_arg; - - default: - indx = mrb_Integer(mrb, indx); - if (mrb_nil_p(indx)) { - range_arg: - { - mrb_int beg, len; - - len = RSTRING_CHAR_LEN(str); - switch (mrb_range_beg_len(mrb, indx, &beg, &len, len, TRUE)) { - case MRB_RANGE_OK: - return str_subseq(mrb, str, beg, len); - case MRB_RANGE_OUT: - return mrb_nil_value(); - default: - break; - } - } - mrb_raise(mrb, E_TYPE_ERROR, "can't convert to Fixnum"); } - idx = mrb_fixnum(indx); - goto num_index; + else { + return mrb_str_byte_subseq(mrb, str, beg, len); + } + case STR_OUT_OF_RANGE: + default: + return mrb_nil_value(); } - return mrb_nil_value(); /* not reached */ } /* 15.2.10.5.6 */ @@ -1168,16 +1146,12 @@ static mrb_value mrb_str_aref_m(mrb_state *mrb, mrb_value str) { mrb_value a1, a2; - mrb_int argc; - argc = mrb_get_args(mrb, "o|o", &a1, &a2); - if (argc == 2) { - mrb_int n1, n2; - - mrb_get_args(mrb, "ii", &n1, &n2); - return str_substr(mrb, str, n1, n2); + if (mrb_get_args(mrb, "o|o", &a1, &a2) == 1) { + a2 = mrb_undef_value(); } - return mrb_str_aref(mrb, str, a1); + + return mrb_str_aref(mrb, str, a1, a2); } static mrb_noreturn void -- cgit v1.2.3 From 97c9e6b00032cd8a7132b43911c05e44732a4c56 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Sun, 30 Jun 2019 14:46:38 +0900 Subject: Fix `include`, `prepend` and `extend` to frozen object --- src/class.c | 5 +++-- test/t/kernel.rb | 3 +++ test/t/module.rb | 27 +++++++++++++++++++++++++++ 3 files changed, 33 insertions(+), 2 deletions(-) diff --git a/src/class.c b/src/class.c index 373f2aec7..1064870a8 100644 --- a/src/class.c +++ b/src/class.c @@ -1070,8 +1070,8 @@ include_module_at(mrb_state *mrb, struct RClass *c, struct RClass *ins_pos, stru MRB_API void mrb_include_module(mrb_state *mrb, struct RClass *c, struct RClass *m) { - int changed = include_module_at(mrb, c, find_origin(c), m, 1); - if (changed < 0) { + mrb_check_frozen(mrb, c); + if (include_module_at(mrb, c, find_origin(c), m, 1) < 0) { mrb_raise(mrb, E_ARGUMENT_ERROR, "cyclic include detected"); } } @@ -1082,6 +1082,7 @@ mrb_prepend_module(mrb_state *mrb, struct RClass *c, struct RClass *m) struct RClass *origin; int changed = 0; + mrb_check_frozen(mrb, c); if (!(c->flags & MRB_FL_CLASS_IS_PREPENDED)) { origin = (struct RClass*)mrb_obj_alloc(mrb, MRB_TT_ICLASS, c); origin->flags |= MRB_FL_CLASS_IS_ORIGIN | MRB_FL_CLASS_IS_INHERITED; diff --git a/test/t/kernel.rb b/test/t/kernel.rb index 1e48069f2..ecfb863a8 100644 --- a/test/t/kernel.rb +++ b/test/t/kernel.rb @@ -240,6 +240,9 @@ assert('Kernel#extend', '15.3.1.3.13') do assert_true a.respond_to?(:test_method) assert_false b.respond_to?(:test_method) + + assert_raise(FrozenError) { Object.new.freeze.extend(Test4ExtendModule) } + assert_raise(FrozenError, TypeError) { :sym.extend(Test4ExtendModule) } end assert('Kernel#extend works on toplevel', '15.3.1.3.13') do diff --git a/test/t/module.rb b/test/t/module.rb index 571f4759d..7f869bf1f 100644 --- a/test/t/module.rb +++ b/test/t/module.rb @@ -59,6 +59,7 @@ assert('Module#append_features', '15.2.2.4.10') do end assert_equal Test4AppendFeatures2, Test4AppendFeatures2.const_get(:Const4AppendFeatures2) + assert_raise(FrozenError) { Module.new.append_features Class.new.freeze } end assert('Module#attr NameError') do @@ -275,6 +276,18 @@ assert('Module#const_missing', '15.2.2.4.22') do assert_equal 42, Test4ConstMissing.const_get(:ConstDoesntExist) end +assert('Module#extend_object', '15.2.2.4.25') do + cls = Class.new + mod = Module.new { def foo; end } + a = cls.new + b = cls.new + mod.extend_object(b) + assert_false a.respond_to?(:foo) + assert_true b.respond_to?(:foo) + assert_raise(FrozenError) { mod.extend_object(cls.new.freeze) } + assert_raise(FrozenError, TypeError) { mod.extend_object(1) } +end + assert('Module#include', '15.2.2.4.27') do module Test4Include Const4Include = 42 @@ -288,6 +301,7 @@ assert('Module#include', '15.2.2.4.27') do assert_equal 42, Test4Include2.const_get(:Const4Include) assert_equal Test4Include2, Test4Include2.include_result + assert_raise(FrozenError) { Module.new.freeze.include Test4Include } end assert('Module#include?', '15.2.2.4.28') do @@ -398,6 +412,15 @@ assert('Module#define_method') do end end +assert 'Module#prepend_features' do + mod = Module.new { def m; :mod end } + cls = Class.new { def m; :cls end } + assert_equal :cls, cls.new.m + mod.prepend_features(cls) + assert_equal :mod, cls.new.m + assert_raise(FrozenError) { Module.new.prepend_features(Class.new.freeze) } +end + # @!group prepend assert('Module#prepend') do module M0 @@ -632,6 +655,10 @@ end # end # end; #end + + assert 'Module#prepend to frozen class' do + assert_raise(FrozenError) { Class.new.freeze.prepend Module.new } + end # @!endgroup prepend assert('Module#to_s') do -- cgit v1.2.3 From 7e3a8b7a7520b101d8cc3453cf7ca5e3c7700772 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Mon, 1 Jul 2019 12:29:02 +0900 Subject: Remove unused C header file from `src/etc.c` --- src/etc.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/etc.c b/src/etc.c index ac1540f92..37717a6f2 100644 --- a/src/etc.c +++ b/src/etc.c @@ -1,5 +1,5 @@ /* -** etc.c - +** etc.c ** ** See Copyright Notice in mruby.h */ @@ -8,8 +8,6 @@ #include #include #include -#include -#include MRB_API struct RData* mrb_data_object_alloc(mrb_state *mrb, struct RClass *klass, void *ptr, const mrb_data_type *type) -- cgit v1.2.3 From 0d54dbb2644b468e255564cfdbb5c435e1e3686f Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Tue, 2 Jul 2019 19:41:40 +0900 Subject: Fix and refine error message in `mrb_obj_to_sym()` Before this patch: $ bin/mruby -e '1.respond_to?(2)' #=> nil is not a symbol After this patch (same as Ruby): $ bin/mruby -e '1.respond_to?(2)' #=> 2 is not a symbol nor a string --- src/etc.c | 22 ++++------------------ 1 file changed, 4 insertions(+), 18 deletions(-) diff --git a/src/etc.c b/src/etc.c index 37717a6f2..18d2839d9 100644 --- a/src/etc.c +++ b/src/etc.c @@ -65,24 +65,10 @@ mrb_data_get_ptr(mrb_state *mrb, mrb_value obj, const mrb_data_type *type) MRB_API mrb_sym mrb_obj_to_sym(mrb_state *mrb, mrb_value name) { - mrb_sym id; - - switch (mrb_type(name)) { - default: - name = mrb_check_string_type(mrb, name); - if (mrb_nil_p(name)) { - name = mrb_inspect(mrb, name); - mrb_raisef(mrb, E_TYPE_ERROR, "%S is not a symbol", name); - /* not reached */ - } - /* fall through */ - case MRB_TT_STRING: - name = mrb_str_intern(mrb, name); - /* fall through */ - case MRB_TT_SYMBOL: - id = mrb_symbol(name); - } - return id; + if (mrb_symbol_p(name)) return mrb_symbol(name); + if (mrb_string_p(name)) return mrb_intern_str(mrb, name); + mrb_raisef(mrb, E_TYPE_ERROR, "%S is not a symbol nor a string", mrb_inspect(mrb, name)); + return 0; /* not reached */ } MRB_API mrb_int -- cgit v1.2.3 From d915261590d646a8788b2200342228804cb1754f Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Wed, 3 Jul 2019 20:36:04 +0900 Subject: Refine document to mrb_get_args()` [ci skip] --- include/mruby.h | 12 +++++++----- src/class.c | 16 ++++++++-------- 2 files changed, 15 insertions(+), 13 deletions(-) diff --git a/include/mruby.h b/include/mruby.h index 3ef399716..7deb3cbe2 100644 --- a/include/mruby.h +++ b/include/mruby.h @@ -836,15 +836,17 @@ MRB_API struct RClass * mrb_define_module_under(mrb_state *mrb, struct RClass *o * | `S` | {String} | {mrb_value} | when `!` follows, the value may be `nil` | * | `A` | {Array} | {mrb_value} | when `!` follows, the value may be `nil` | * | `H` | {Hash} | {mrb_value} | when `!` follows, the value may be `nil` | - * | `s` | {String} | char *, {mrb_int} | Receive two arguments; `s!` gives (`NULL`,`0`) for `nil` | + * | `s` | {String} | char *, {mrb_int} | Receive two arguments; `s!` gives (`NULL`,`0`) for `nil` | * | `z` | {String} | char * | `NULL` terminated string; `z!` gives `NULL` for `nil` | * | `a` | {Array} | {mrb_value} *, {mrb_int} | Receive two arguments; `a!` gives (`NULL`,`0`) for `nil` | - * | `f` | {Float} | {mrb_float} | | - * | `i` | {Integer} | {mrb_int} | | + * | `f` | {Fixnum}/{Float} | {mrb_float} | | + * | `i` | {Fixnum}/{Float} | {mrb_int} | | * | `b` | boolean | {mrb_bool} | | - * | `n` | {Symbol} | {mrb_sym} | | + * | `n` | {String}/{Symbol} | {mrb_sym} | | + * | `d` | data | void *, {mrb_data_type} const | 2nd argument will be used to check data type so it won't be modified; when `!` follows, the value may be `nil` | + * | `I` | inline struct | void * | | * | `&` | block | {mrb_value} | &! raises exception if no block given. | - * | `*` | rest arguments | {mrb_value} *, {mrb_int} | Receive the rest of arguments as an array; *! avoid copy of the stack. | + * | `*` | rest arguments | {mrb_value} *, {mrb_int} | Receive the rest of arguments as an array; `*!` avoid copy of the stack. | * | | | optional | | After this spec following specs would be optional. | * | `?` | optional given | {mrb_bool} | `TRUE` if preceding argument is given. Used to check optional argument is given. | * diff --git a/src/class.c b/src/class.c index 1064870a8..edee95678 100644 --- a/src/class.c +++ b/src/class.c @@ -573,20 +573,20 @@ mrb_get_argv(mrb_state *mrb) string mruby type C type note ---------------------------------------------------------------------------------------------- o: Object [mrb_value] - C: class/module [mrb_value] + C: Class/Module [mrb_value] S: String [mrb_value] when ! follows, the value may be nil A: Array [mrb_value] when ! follows, the value may be nil H: Hash [mrb_value] when ! follows, the value may be nil s: String [char*,mrb_int] Receive two arguments; s! gives (NULL,0) for nil z: String [char*] NUL terminated string; z! gives NULL for nil a: Array [mrb_value*,mrb_int] Receive two arguments; a! gives (NULL,0) for nil - f: Float [mrb_float] - i: Integer [mrb_int] - b: Boolean [mrb_bool] - n: Symbol [mrb_sym] - d: Data [void*,mrb_data_type const] 2nd argument will be used to check data type so it won't be modified - I: Inline struct [void*] - &: Block [mrb_value] &! raises exception if no block given + f: Fixnum/Float [mrb_float] + i: Fixnum/Float [mrb_int] + b: boolean [mrb_bool] + n: String/Symbol [mrb_sym] + d: data [void*,mrb_data_type const] 2nd argument will be used to check data type so it won't be modified; when ! follows, the value may be nil + I: inline struct [void*] + &: block [mrb_value] &! raises exception if no block given *: rest argument [mrb_value*,mrb_int] The rest of the arguments as an array; *! avoid copy of the stack |: optional Following arguments are optional ?: optional given [mrb_bool] true if preceding argument (optional) is given -- cgit v1.2.3 From 2bb30481b6d6aed0f869dd089a56ebe24e8e2349 Mon Sep 17 00:00:00 2001 From: dearblue Date: Thu, 4 Jul 2019 21:49:07 +0900 Subject: Fix heap buffer overflow; ref #4549 This patch is showed in #4549. --- src/string.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/string.c b/src/string.c index 6938418fb..7a094b3a7 100644 --- a/src/string.c +++ b/src/string.c @@ -1184,7 +1184,7 @@ str_replace_partial(mrb_state *mrb, mrb_value src, mrb_int pos, mrb_int end, mrb mrb_str_modify(mrb, str); - if (len < newlen || len - newlen >= shrink_threshold) { + if (len < newlen) { resize_capa(mrb, str, newlen); } @@ -1197,6 +1197,10 @@ str_replace_partial(mrb_state *mrb, mrb_value src, mrb_int pos, mrb_int end, mrb RSTR_SET_LEN(str, newlen); strp[newlen] = '\0'; + if (len - newlen >= shrink_threshold) { + resize_capa(mrb, str, newlen); + } + return src; } -- cgit v1.2.3 From 991bdd4ed7b0aa6fd6bee4fa5c62283365dcf15d Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Thu, 4 Jul 2019 23:01:16 +0900 Subject: Rename `MRB_STR_NO_UTF` to 'MRB_STR_ASCII`; close #4550 In #4550, @shuuji proposed the name name `MRB_STR_NO_MULTI_BYTE` for more precise description. Although I agree that the name name is correct, but the flag means the string does not contain multi byte UTF-8 characters, i.e. all characters fit in the range of ASCII. --- include/mruby/string.h | 2 +- src/string.c | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/include/mruby/string.h b/include/mruby/string.h index b563541cb..9484e20d7 100644 --- a/include/mruby/string.h +++ b/include/mruby/string.h @@ -87,7 +87,7 @@ MRB_API mrb_int mrb_str_strlen(mrb_state*, struct RString*); #define MRB_STR_FSHARED 2 #define MRB_STR_NOFREE 4 #define MRB_STR_POOL 8 -#define MRB_STR_NO_UTF 16 +#define MRB_STR_ASCII 16 #define MRB_STR_EMBED 32 #define MRB_STR_EMBED_LEN_MASK 0x7c0 #define MRB_STR_EMBED_LEN_SHIFT 6 diff --git a/src/string.c b/src/string.c index 7a094b3a7..805cf01dc 100644 --- a/src/string.c +++ b/src/string.c @@ -260,12 +260,12 @@ utf8_strlen(mrb_value str) { mrb_int byte_len = RSTRING_LEN(str); - if (RSTRING(str)->flags & MRB_STR_NO_UTF) { + if (RSTRING(str)->flags & MRB_STR_ASCII) { return byte_len; } else { mrb_int utf8_len = mrb_utf8_len(RSTRING_PTR(str), byte_len); - if (byte_len == utf8_len) RSTRING(str)->flags |= MRB_STR_NO_UTF; + if (byte_len == utf8_len) RSTRING(str)->flags |= MRB_STR_ASCII; return utf8_len; } } @@ -512,8 +512,8 @@ str_replace(mrb_state *mrb, struct RString *s1, struct RString *s2) mrb_check_frozen(mrb, s1); if (s1 == s2) return mrb_obj_value(s1); - s1->flags &= ~MRB_STR_NO_UTF; - s1->flags |= s2->flags&MRB_STR_NO_UTF; + s1->flags &= ~MRB_STR_ASCII; + s1->flags |= s2->flags&MRB_STR_ASCII; len = RSTR_LEN(s2); if (RSTR_SHARED_P(s1)) { str_decref(mrb, s1->as.heap.aux.shared); @@ -651,7 +651,7 @@ MRB_API void mrb_str_modify(mrb_state *mrb, struct RString *s) { mrb_check_frozen(mrb, s); - s->flags &= ~MRB_STR_NO_UTF; + s->flags &= ~MRB_STR_ASCII; if (RSTR_SHARED_P(s)) { mrb_shared_string *shared = s->as.heap.aux.shared; -- cgit v1.2.3 From 8294ce9fd458a0a1acf8fcdcb6161b4a020866ad Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Thu, 4 Jul 2019 23:11:57 +0900 Subject: It was too early to check `key` for `undef`; ref #4534 --- src/hash.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hash.c b/src/hash.c index ac6a7cd56..2a0a19363 100644 --- a/src/hash.c +++ b/src/hash.c @@ -543,10 +543,10 @@ ht_copy(mrb_state *mrb, htable *t) mrb_value key = seg->e[i].key; mrb_value val = seg->e[i].val; - if (mrb_undef_p(key)) continue; /* skip deleted key */ if ((seg->next == NULL) && (i >= t->last_len)) { return t2; } + if (mrb_undef_p(key)) continue; /* skip deleted key */ ht_put(mrb, t2, key, val); } seg = seg->next; -- cgit v1.2.3 From f9bf2d9d8e2531b2bfebb5a80362b43ab559b56f Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Fri, 5 Jul 2019 20:37:59 +0900 Subject: Read/write `MRB_STR_ASCII` flag only when `MRB_UTF8_STRING` is defined --- include/mruby/string.h | 14 ++++++++++++++ src/string.c | 14 +++++++------- 2 files changed, 21 insertions(+), 7 deletions(-) diff --git a/include/mruby/string.h b/include/mruby/string.h index 9484e20d7..d648d856c 100644 --- a/include/mruby/string.h +++ b/include/mruby/string.h @@ -68,6 +68,20 @@ struct RString { #define RSTR_SET_NOFREE_FLAG(s) ((s)->flags |= MRB_STR_NOFREE) #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)) +#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 +#endif + #define RSTR_POOL_P(s) ((s)->flags & MRB_STR_POOL) #define RSTR_SET_POOL_FLAG(s) ((s)->flags |= MRB_STR_POOL) diff --git a/src/string.c b/src/string.c index 805cf01dc..078c028d8 100644 --- a/src/string.c +++ b/src/string.c @@ -258,14 +258,15 @@ mrb_utf8_len(const char *str, mrb_int byte_len) static mrb_int utf8_strlen(mrb_value str) { - mrb_int byte_len = RSTRING_LEN(str); + struct RString *s = mrb_str_ptr(str); + mrb_int byte_len = RSTR_LEN(s); - if (RSTRING(str)->flags & MRB_STR_ASCII) { + if (RSTR_ASCII_P(s)) { return byte_len; } else { - mrb_int utf8_len = mrb_utf8_len(RSTRING_PTR(str), byte_len); - if (byte_len == utf8_len) RSTRING(str)->flags |= MRB_STR_ASCII; + mrb_int utf8_len = mrb_utf8_len(RSTR_PTR(s), byte_len); + if (byte_len == utf8_len) RSTR_SET_ASCII_FLAG(s); return utf8_len; } } @@ -512,8 +513,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); - s1->flags &= ~MRB_STR_ASCII; - s1->flags |= s2->flags&MRB_STR_ASCII; + RSTR_COPY_ASCII_FLAG(s1, s2); len = RSTR_LEN(s2); if (RSTR_SHARED_P(s1)) { str_decref(mrb, s1->as.heap.aux.shared); @@ -651,7 +651,7 @@ MRB_API void mrb_str_modify(mrb_state *mrb, struct RString *s) { mrb_check_frozen(mrb, s); - s->flags &= ~MRB_STR_ASCII; + RSTR_UNSET_ASCII_FLAG(s); if (RSTR_SHARED_P(s)) { mrb_shared_string *shared = s->as.heap.aux.shared; -- cgit v1.2.3 From df1f1002d9fe8466e0d621818febf465e03b9016 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Sat, 6 Jul 2019 19:55:37 +0900 Subject: Fix missing `#ifndef MRB_ENABLE_ALL_SYMBOLS` --- src/symbol.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/symbol.c b/src/symbol.c index b26f2b1fd..5eeb28045 100644 --- a/src/symbol.c +++ b/src/symbol.c @@ -503,9 +503,11 @@ mrb_sym2str(mrb_state *mrb, mrb_sym sym) const char *name = mrb_sym2name_len(mrb, sym, &len); if (!name) return mrb_undef_value(); /* can't happen */ +#ifndef MRB_ENABLE_ALL_SYMBOLS if (sym&1) { /* inline symbol */ return mrb_str_new(mrb, name, len); } +#endif return mrb_str_new_static(mrb, name, len); } @@ -521,12 +523,12 @@ mrb_sym2name(mrb_state *mrb, mrb_sym sym) } else { mrb_value str; - if (sym&1) { /* inline symbol */ +#ifndef MRB_ENABLE_ALL_SYMBOLS + if (sym&1) /* inline symbol */ str = mrb_str_new(mrb, name, len); - } - else { + else +#endif str = mrb_str_new_static(mrb, name, len); - } str = mrb_str_dump(mrb, str); return RSTRING_PTR(str); } -- cgit v1.2.3 From 32c2aa10c79e37c53411b1d693c6c8d010fba7bb Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Sun, 7 Jul 2019 22:10:32 +0900 Subject: Fix `Numeric#step` to infinity; ref. #4555 --- mrblib/numeric.rb | 8 ++--- test/t/numeric.rb | 88 ++++++++++++++++++++++++++++++++++++++++--------------- 2 files changed, 69 insertions(+), 27 deletions(-) diff --git a/mrblib/numeric.rb b/mrblib/numeric.rb index 5a3c5eb58..5926518d5 100644 --- a/mrblib/numeric.rb +++ b/mrblib/numeric.rb @@ -105,14 +105,14 @@ module Integral return to_enum(:step, num, step) unless block i = __coerce_step_counter(num, step) - if num == nil + if num == self || step.infinite? + block.call(i) if step > 0 && i <= (num||i) || step < 0 && i >= (num||-i) + elsif num == nil while true block.call(i) i += step end - return self - end - if step > 0 + elsif step > 0 while i <= num block.call(i) i += step diff --git a/test/t/numeric.rb b/test/t/numeric.rb index d73dfdb61..bb95f8ef3 100644 --- a/test/t/numeric.rb +++ b/test/t/numeric.rb @@ -1,6 +1,19 @@ ## # Numeric ISO Test +def assert_step(exp, receiver, args, inf: false) + act = [] + ret = receiver.step(*args) do |i| + act << i + break if inf && exp.size == act.size + end + expr = "#{receiver.inspect}.step(#{args.map(&:inspect).join(', ')})" + assert do + assert_true(exp.eql?(act), "#{expr}: counters", assertion_diff(exp, act)) + assert_same(receiver, ret, "#{expr}: return value") unless inf + end +end + assert('Numeric', '15.2.7') do assert_equal(Class, Numeric.class) end @@ -42,31 +55,60 @@ assert('Numeric#**') do end assert('Numeric#step') do - assert_step = ->(exp, receiver, args) do - inf = !args[0] - act = [] - ret = receiver.step(*args) do |i| - act << i - break if inf && exp.size == act.size - end - expr = "#{receiver.inspect}.step(#{args.map(&:inspect).join(', ')})" - assert_true(exp.eql?(act), "#{expr}: counters", assertion_diff(exp, act)) - assert_same(receiver, ret, "#{expr}: return value") unless inf - end - assert_raise(ArgumentError) { 1.step(2, 0) { break } } - assert_step.([2, 3, 4], 2, [4]) - assert_step.([10, 8, 6, 4, 2], 10, [1, -2]) - assert_step.([], 2, [1, 3]) - assert_step.([], -2, [-1, -3]) - assert_step.([10, 11, 12, 13], 10, []) - assert_step.([10, 7, 4], 10, [nil, -3]) + assert_step([2, 3, 4], 2, [4]) + assert_step([10, 8, 6, 4, 2], 10, [1, -2]) + assert_step([], 2, [1, 3]) + assert_step([], -2, [-1, -3]) + assert_step([10, 11, 12, 13], 10, [], inf: true) + assert_step([10, 7, 4], 10, [nil, -3], inf: true) skip unless Object.const_defined?(:Float) + inf = Float::INFINITY assert_raise(ArgumentError) { 1.step(2, 0.0) { break } } - assert_step.([2.0, 3.0, 4.0], 2, [4.0]) - assert_step.([7.0, 4.0, 1.0, -2.0], 7, [-4, -3.0]) - assert_step.([2.0, 3.0, 4.0], 2.0, [4]) - assert_step.([10.0, 11.0, 12.0, 13.0], 10.0, []) - assert_step.([10.0, 7.0, 4.0], 10, [nil, -3.0]) + assert_step([2.0, 3.0, 4.0], 2, [4.0]) + assert_step([7.0, 4.0, 1.0, -2.0], 7, [-4, -3.0]) + assert_step([2.0, 3.0, 4.0], 2.0, [4]) + assert_step([10.0, 11.0, 12.0, 13.0], 10.0, [], inf: true) + assert_step([10.0, 7.0, 4.0], 10, [nil, -3.0], inf: true) + assert_step([1.0], 1, [nil, inf]) + assert_step([1.0], 1, [nil, -inf]) + assert_step([1.0], 1, [3, inf]) + assert_step([], 1, [-3, inf]) + assert_step([], 1, [3, -inf]) + assert_step([1.0], 1, [-3, -inf]) + assert_step([1.0], 1, [inf, inf]) + assert_step([], 1, [inf, -inf]) + assert_step([], 1, [-inf, inf]) + assert_step([1.0], 1, [-inf, -inf]) + assert_step([], inf, [2]) + assert_step([], inf, [-2]) + assert_step([], inf, [2, 3]) + assert_step([inf, inf, inf], inf, [2, -3], inf: true) + assert_step([], inf, [2, inf]) + assert_step([inf], inf, [2, -inf]) + assert_step([], inf, [-2, inf]) + assert_step([inf], inf, [-2, -inf]) + assert_step([], inf, [-2, 3]) + assert_step([inf, inf, inf], inf, [-2, -3], inf: true) + assert_step([inf], inf, [inf]) + assert_step([], inf, [-inf]) + assert_step([inf], inf, [inf, inf]) + assert_step([inf], inf, [inf, -inf]) + assert_step([inf], inf, [-inf, -inf]) + assert_step([-inf, -inf, -inf], -inf, [2], inf: true) + assert_step([-inf, -inf, -inf], -inf, [-2], inf: true) + assert_step([-inf, -inf, -inf], -inf, [2, 3], inf: true) + assert_step([], -inf, [2, -3]) + assert_step([-inf], -inf, [2, inf]) + assert_step([], -inf, [2, -inf]) + assert_step([-inf], -inf, [-2, inf]) + assert_step([], -inf, [-2, -inf]) + assert_step([-inf, -inf, -inf], -inf, [-2, 3], inf: true) + assert_step([], -inf, [-2, -3]) + assert_step([-inf, -inf, -inf], -inf, [inf], inf: true) + assert_step([-inf], -inf, [-inf]) + assert_step([-inf], -inf, [inf, inf]) + assert_step([], -inf, [inf, -inf]) + assert_step([-inf], -inf, [-inf, -inf]) end -- cgit v1.2.3 From 0a79486380d6991cf6adc015de65d9758d1584e3 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Mon, 8 Jul 2019 22:14:23 +0900 Subject: Add macros for inline symbol for readability --- src/symbol.c | 65 ++++++++++++++++++++++++++++++------------------------------ 1 file changed, 33 insertions(+), 32 deletions(-) diff --git a/src/symbol.c b/src/symbol.c index 5eeb28045..38843c71f 100644 --- a/src/symbol.c +++ b/src/symbol.c @@ -20,6 +20,22 @@ typedef struct symbol_name { const char *name; } symbol_name; +#define SYMBOL_INLINE_BIT 1 +#define SYMBOL_INLINE_LOWER_BIT 2 +#define SYMBOL_INLINE (1 << (SYMBOL_INLINE_BIT - 1)) +#define SYMBOL_INLINE_LOWER (1 << (SYMBOL_INLINE_LOWER_BIT - 1)) +#define SYMBOL_NORMAL_SHIFT SYMBOL_INLINE_BIT +#define SYMBOL_INLINE_SHIFT SYMBOL_INLINE_LOWER_BIT +#ifdef MRB_ENABLE_ALL_SYMBOLS +# define SYMBOL_INLINE_P(sym) FALSE +# define SYMBOL_INLINE_LOWER_P(sym) FALSE +# define sym_inline_pack(name, len) 0 +# define sym_inline_unpack(sym, buf, lenp) NULL +#else +# define SYMBOL_INLINE_P(sym) ((sym) & SYMBOL_INLINE) +# define SYMBOL_INLINE_LOWER_P(sym) ((sym) & SYMBOL_INLINE_LOWER) +#endif + static void sym_validate_len(mrb_state *mrb, size_t len) { @@ -41,7 +57,7 @@ sym_inline_pack(const char *name, uint16_t len) const char *p; int i; mrb_sym sym = 0; - int lower = 1; + mrb_bool lower = TRUE; if (len > lower_length_max) return 0; /* too long */ for (i=0; i 27) lower = 0; + if (bits > 27) lower = FALSE; if (i >= mix_length_max) break; - sym |= bits<<(i*6+2); + sym |= bits<<(i*6+SYMBOL_INLINE_SHIFT); } if (lower) { sym = 0; @@ -64,24 +80,24 @@ sym_inline_pack(const char *name, uint16_t len) c = name[i]; p = strchr(pack_table, (int)c); bits = (uint32_t)(p - pack_table)+1; - sym |= bits<<(i*5+2); + sym |= bits<<(i*5+SYMBOL_INLINE_SHIFT); } - return sym | 3; + return sym | SYMBOL_INLINE | SYMBOL_INLINE_LOWER; } if (len > mix_length_max) return 0; - return sym | 1; + return sym | SYMBOL_INLINE; } static const char* sym_inline_unpack(mrb_sym sym, char *buf, mrb_int *lenp) { - int bit_per_char = sym&2 ? 5 : 6; /* all lower case if `sym&2` is true */ + int bit_per_char = SYMBOL_INLINE_LOWER_P(sym) ? 5 : 6; int i; - mrb_assert(sym&1); + mrb_assert(SYMBOL_INLINE_P(sym)); for (i=0; i<30/bit_per_char; i++) { - uint32_t bits = sym>>(i*bit_per_char+2) & ((1<>(i*bit_per_char+SYMBOL_INLINE_SHIFT) & ((1< 0) return i; -#endif i = mrb->symhash[hash]; if (i == 0) return 0; do { sname = &mrb->symtbl[i]; if (sname->len == len && memcmp(sname->name, name, len) == 0) { - return i<<1; + return i<prev == 0xff) { i -= 0xff; sname = &mrb->symtbl[i]; while (mrb->symtbl < sname) { if (sname->len == len && memcmp(sname->name, name, len) == 0) { - return (mrb_sym)(sname - mrb->symtbl)<<1; + return (mrb_sym)(sname - mrb->symtbl)<symhash[hash] = sym; - return sym<<1; + return sym<>= 1; + sym >>= SYMBOL_NORMAL_SHIFT; if (sym == 0 || mrb->symidx < sym) { if (lenp) *lenp = 0; return NULL; @@ -503,11 +513,7 @@ mrb_sym2str(mrb_state *mrb, mrb_sym sym) const char *name = mrb_sym2name_len(mrb, sym, &len); if (!name) return mrb_undef_value(); /* can't happen */ -#ifndef MRB_ENABLE_ALL_SYMBOLS - if (sym&1) { /* inline symbol */ - return mrb_str_new(mrb, name, len); - } -#endif + if (SYMBOL_INLINE_P(sym)) return mrb_str_new(mrb, name, len); return mrb_str_new_static(mrb, name, len); } @@ -522,13 +528,8 @@ mrb_sym2name(mrb_state *mrb, mrb_sym sym) return name; } else { - mrb_value str; -#ifndef MRB_ENABLE_ALL_SYMBOLS - if (sym&1) /* inline symbol */ - str = mrb_str_new(mrb, name, len); - else -#endif - str = mrb_str_new_static(mrb, name, len); + mrb_value str = SYMBOL_INLINE_P(sym) ? + mrb_str_new(mrb, name, len) : mrb_str_new_static(mrb, name, len); str = mrb_str_dump(mrb, str); return RSTRING_PTR(str); } -- cgit v1.2.3 From c8a7d0ab9541a4297d3885842c5fc1343fe5ea99 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Tue, 9 Jul 2019 13:13:13 +0900 Subject: Fix the order of "expected" and "actual" in `test/t/range.rb` --- test/t/range.rb | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/test/t/range.rb b/test/t/range.rb index d71fe8946..106c2866e 100644 --- a/test/t/range.rb +++ b/test/t/range.rb @@ -101,12 +101,12 @@ end assert('Range#dup') do r = (1..3).dup - assert_equal r.begin, 1 - assert_equal r.end, 3 + assert_equal 1, r.begin + assert_equal 3, r.end assert_false r.exclude_end? r = ("a"..."z").dup - assert_equal r.begin, "a" - assert_equal r.end, "z" + assert_equal "a", r.begin + assert_equal "z", r.end assert_true r.exclude_end? end -- cgit v1.2.3 From f7d59dfe23b6fed5a6dc0720144eeaebb407efbb Mon Sep 17 00:00:00 2001 From: Ryan Lopopolo Date: Mon, 8 Jul 2019 20:10:24 -0700 Subject: Add tests for Range#max and Range#min --- test/t/range.rb | 42 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/test/t/range.rb b/test/t/range.rb index d71fe8946..7ce4a7a94 100644 --- a/test/t/range.rb +++ b/test/t/range.rb @@ -110,3 +110,45 @@ assert('Range#dup') do assert_equal r.end, "z" assert_true r.exclude_end? end + +assert('Range#max') do + assert_equal 10, (1..10).max + assert_equal 9, (1...10).max + assert_equal nil, (10..1).max + assert_equal nil, (10...1).max + + # equal endpoints + assert_equal 5, (5..5).max + assert_equal nil, (5...5).max + + # block overrides comparison + assert_equal(10, (1..10).max { |a, b| a <=> b }) + assert_equal(9, (1...10).max { |a, b| a <=> b }) + assert_equal(nil, (10..1).max { |a, b| a <=> b }) + assert_equal(nil, (10...1).max { |a, b| a <=> b }) + assert_equal(1, (1..10).max { |a, b| b <=> a }) + assert_equal(1, (1...10).max { |a, b| b <=> a }) + assert_equal(nil, (10..1).max { |a, b| b <=> a }) + assert_equal(nil, (10...1).max { |a, b| b <=> a }) +end + +assert('Range#min') do + assert_equal 1, (1..10).min + assert_equal 1, (1...10).min + assert_equal nil, (10..1).min + assert_equal nil, (10...1).min + + # equal endpoints + assert_equal 7, (7..7).min + assert_equal nil, (7...7).min + + # block overrides comparison + assert_equal(1, (1..10).min { |a, b| a <=> b }) + assert_equal(1, (1...10).min { |a, b| a <=> b }) + assert_equal(nil, (10..1).min { |a, b| a <=> b }) + assert_equal(nil, (10...1).min { |a, b| a <=> b }) + assert_equal(10, (1..10).min { |a, b| b <=> a }) + assert_equal(9, (1...10).min { |a, b| b <=> a }) + assert_equal(nil, (10..1).min { |a, b| b <=> a }) + assert_equal(nil, (10...1).min { |a, b| b <=> a }) +end -- cgit v1.2.3 From 469c6261c69999aab9e0d19cea6ac8e03f7847e3 Mon Sep 17 00:00:00 2001 From: Ryan Lopopolo Date: Mon, 8 Jul 2019 22:35:12 -0700 Subject: Add tests for String Ranges Range#each depends on String#upto which is implemented in mruby-string-ext which is why these tests live there. --- mrbgems/mruby-string-ext/test/range.rb | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 mrbgems/mruby-string-ext/test/range.rb diff --git a/mrbgems/mruby-string-ext/test/range.rb b/mrbgems/mruby-string-ext/test/range.rb new file mode 100644 index 000000000..4b42cd3a6 --- /dev/null +++ b/mrbgems/mruby-string-ext/test/range.rb @@ -0,0 +1,12 @@ +assert('Range#max') do + # string Range depends on String#upto + assert_equal 'l', ('f'..'l').max + assert_equal 'e', ('a'...'f').max + assert_equal nil, ('z'..'l').max +end + +assert('Range#min') do + # string Range depends on String#upto + assert_equal 'f', ('f'..'l').min + assert_equal nil, ('z'..'l').min +end -- cgit v1.2.3 From 4085709ae1736fb755955d3d52b6b73c15853506 Mon Sep 17 00:00:00 2001 From: Ryan Lopopolo Date: Mon, 8 Jul 2019 19:23:24 -0700 Subject: Specialize Enumerable#max and Enumerable#min for Range This patch prevents a hang for pathalogical (large) Ranges when computing max and min. Range inherits its implementation of max and min from Enumerable. Enumerable implements max and min by calling each. For Range objects, this is unnecessary since we know the max and the min by the end and begin attributes. It is also very slow. This code hangs unnecessarily: (0..2**32).max # ... hang (0..2**32).min # ... hang This patch overrides max and min after including enumerable to yield based on the begin and end methods. --- mrblib/range.rb | 66 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 65 insertions(+), 1 deletion(-) diff --git a/mrblib/range.rb b/mrblib/range.rb index 392cc2274..746cb322c 100644 --- a/mrblib/range.rb +++ b/mrblib/range.rb @@ -15,7 +15,8 @@ class Range val = self.first last = self.last - if val.kind_of?(Fixnum) && last.kind_of?(Fixnum) # fixnums are special + # numerics are special + if (val.kind_of?(Fixnum) || val.kind_of?(Float)) && (last.kind_of?(Fixnum) || last.kind_of?(Float)) lim = last lim += 1 unless exclude_end? i = val @@ -64,4 +65,67 @@ end # ISO 15.2.14.3 class Range include Enumerable + + def max(&block) + val = self.first + last = self.last + # numerics are special + if (val.kind_of?(Fixnum) || val.kind_of?(Float)) && (last.kind_of?(Fixnum) || last.kind_of?(Float)) + return nil if val > last + return nil if val == last && exclude_end? + + max = last + max -= 1 if exclude_end? + max = val if block && block.call(val, last) > 0 + return max + end + + max = nil + each do |item| + max = + if max.nil? + item + elsif block && block.call(max, item) > 0 + item + elsif item > max + item + else + max + end + end + max + end + + def min(&block) + val = self.first + last = self.last + + # numerics are special + if (val.kind_of?(Fixnum) || val.kind_of?(Float)) && (last.kind_of?(Fixnum) || last.kind_of?(Float)) + return nil if val > last + return nil if val == last && exclude_end? + + min = val + if block && block.call(val, last) > 0 + min = last + min -= 1 if exclude_end? + end + return min + end + + min = nil + each do |item| + min = + if min.nil? + item + elsif block && block.call(min, item) < 0 + item + elsif item < min + item + else + min + end + end + min + end end -- cgit v1.2.3 From d9c530379343ef0dd0f314c982ddeedea8eb1a60 Mon Sep 17 00:00:00 2001 From: Ryan Lopopolo Date: Tue, 9 Jul 2019 01:40:44 -0700 Subject: Remove attempt at spec-compliant Range#max and Range#min from core --- mrblib/range.rb | 63 --------------------------------------------------------- test/t/range.rb | 42 -------------------------------------- 2 files changed, 105 deletions(-) diff --git a/mrblib/range.rb b/mrblib/range.rb index 746cb322c..3e6dbfb24 100644 --- a/mrblib/range.rb +++ b/mrblib/range.rb @@ -65,67 +65,4 @@ end # ISO 15.2.14.3 class Range include Enumerable - - def max(&block) - val = self.first - last = self.last - # numerics are special - if (val.kind_of?(Fixnum) || val.kind_of?(Float)) && (last.kind_of?(Fixnum) || last.kind_of?(Float)) - return nil if val > last - return nil if val == last && exclude_end? - - max = last - max -= 1 if exclude_end? - max = val if block && block.call(val, last) > 0 - return max - end - - max = nil - each do |item| - max = - if max.nil? - item - elsif block && block.call(max, item) > 0 - item - elsif item > max - item - else - max - end - end - max - end - - def min(&block) - val = self.first - last = self.last - - # numerics are special - if (val.kind_of?(Fixnum) || val.kind_of?(Float)) && (last.kind_of?(Fixnum) || last.kind_of?(Float)) - return nil if val > last - return nil if val == last && exclude_end? - - min = val - if block && block.call(val, last) > 0 - min = last - min -= 1 if exclude_end? - end - return min - end - - min = nil - each do |item| - min = - if min.nil? - item - elsif block && block.call(min, item) < 0 - item - elsif item < min - item - else - min - end - end - min - end end diff --git a/test/t/range.rb b/test/t/range.rb index 7ce4a7a94..d71fe8946 100644 --- a/test/t/range.rb +++ b/test/t/range.rb @@ -110,45 +110,3 @@ assert('Range#dup') do assert_equal r.end, "z" assert_true r.exclude_end? end - -assert('Range#max') do - assert_equal 10, (1..10).max - assert_equal 9, (1...10).max - assert_equal nil, (10..1).max - assert_equal nil, (10...1).max - - # equal endpoints - assert_equal 5, (5..5).max - assert_equal nil, (5...5).max - - # block overrides comparison - assert_equal(10, (1..10).max { |a, b| a <=> b }) - assert_equal(9, (1...10).max { |a, b| a <=> b }) - assert_equal(nil, (10..1).max { |a, b| a <=> b }) - assert_equal(nil, (10...1).max { |a, b| a <=> b }) - assert_equal(1, (1..10).max { |a, b| b <=> a }) - assert_equal(1, (1...10).max { |a, b| b <=> a }) - assert_equal(nil, (10..1).max { |a, b| b <=> a }) - assert_equal(nil, (10...1).max { |a, b| b <=> a }) -end - -assert('Range#min') do - assert_equal 1, (1..10).min - assert_equal 1, (1...10).min - assert_equal nil, (10..1).min - assert_equal nil, (10...1).min - - # equal endpoints - assert_equal 7, (7..7).min - assert_equal nil, (7...7).min - - # block overrides comparison - assert_equal(1, (1..10).min { |a, b| a <=> b }) - assert_equal(1, (1...10).min { |a, b| a <=> b }) - assert_equal(nil, (10..1).min { |a, b| a <=> b }) - assert_equal(nil, (10...1).min { |a, b| a <=> b }) - assert_equal(10, (1..10).min { |a, b| b <=> a }) - assert_equal(9, (1...10).min { |a, b| b <=> a }) - assert_equal(nil, (10..1).min { |a, b| b <=> a }) - assert_equal(nil, (10...1).min { |a, b| b <=> a }) -end -- cgit v1.2.3 From eab07daf92c9a8a2836923656d9e8f58583a52ba Mon Sep 17 00:00:00 2001 From: Ryan Lopopolo Date: Tue, 9 Jul 2019 01:41:10 -0700 Subject: Add Range#max and Range#min tests from Ruby Spec --- mrbgems/mruby-range-ext/test/range.rb | 101 +++++++++++++++++++++++++++++++++ mrbgems/mruby-string-ext/test/range.rb | 18 +++++- 2 files changed, 117 insertions(+), 2 deletions(-) diff --git a/mrbgems/mruby-range-ext/test/range.rb b/mrbgems/mruby-range-ext/test/range.rb index efcbdabe4..6b135aeff 100644 --- a/mrbgems/mruby-range-ext/test/range.rb +++ b/mrbgems/mruby-range-ext/test/range.rb @@ -30,3 +30,104 @@ assert('Range#size') do assert_equal Float::INFINITY, (0..Float::INFINITY).size assert_nil ('a'..'z').size end + +assert('Range#max') do + # returns the maximum value in the range when called with no arguments + assert_equal 10, (1..10).max + assert_equal 9, (1...10).max + assert_equal 4294967295, (0...2**32).max + + # returns the maximum value in the Float range when called with no arguments + assert_equal 908.1111, (303.20..908.1111).max + + # raises TypeError when called on an exclusive range and a non Integer value + assert_raise(TypeError) { (303.20...908.1111).max } + + # returns nil when the endpoint is less than the start point + assert_equal nil, (100..10).max + + # returns nil when the endpoint equals the start point and the range is exclusive + assert_equal nil, (5...5).max + + # returns the endpoint when the endpoint equals the start point and the range is inclusive + assert_equal 5, (5..5).max + + # returns nil when the endpoint is less than the start point in a Float range + assert_equal nil, (3003.20..908.1111).max +end + +assert('Range#max given a block') do + # passes each pair of values in the range to the block + acc = [] + (1..10).max do |a, b| + acc << a + acc << b + a + end + (1..10).each do |value| + assert_true acc.include?(value) + end + + # passes each pair of elements to the block in reversed order + acc = [] + (1..5).max do |a, b| + acc << [a, b] + a + end + assert_equal [[2, 1], [3, 2], [4, 3], [5, 4]], acc + + # returns the element the block determines to be the maximum + assert_equal 1, ((1..3).max { |_a, _b| -3 }) + + # returns nil when the endpoint is less than the start point + assert_equal nil, ((100..10).max { |x, y| x <=> y }) + assert_equal nil, ((5...5).max { |x, y| x <=> y }) +end + +assert('Range#min') do + # returns the minimum value in the range when called with no arguments + assert_equal 1, (1..10).min + + # returns the minimum value in the Float range when called with no arguments + assert_equal 303.20, (303.20..908.1111).min + + # returns nil when the start point is greater than the endpoint + assert_equal nil, (100..10).min + + # returns nil when the endpoint equals the start point and the range is exclusive + assert_equal nil, (5...5).max + + # returns the endpoint when the endpoint equals the start point and the range is inclusive + assert_equal 5, (5..5).max + + # returns nil when the start point is greater than the endpoint in a Float range + assert_equal nil, (3003.20..908.1111).max +end + +assert('Range#min given a block') do + # passes each pair of values in the range to the block + acc = [] + (1..10).min do |a, b| + acc << a + acc << b + a + end + (1..10).each do |value| + assert_true acc.include?(value) + end + + # passes each pair of elements to the block in reversed order + acc = [] + (1..5).min do |a, b| + acc << [a, b] + a + end + assert_equal [[2, 1], [3, 1], [4, 1], [5, 1]], acc + + # returns the element the block determines to be the minimum + assert_equal 3, ((1..3).min { |_a, _b| -3 }) + + # returns nil when the start point is greater than the endpoint + assert_equal nil, ((100..10).min { |x, y| x <=> y }) + assert_equal nil, ((5...5).min { |x, y| x <=> y }) +end diff --git a/mrbgems/mruby-string-ext/test/range.rb b/mrbgems/mruby-string-ext/test/range.rb index 4b42cd3a6..80c286850 100644 --- a/mrbgems/mruby-string-ext/test/range.rb +++ b/mrbgems/mruby-string-ext/test/range.rb @@ -1,12 +1,26 @@ assert('Range#max') do - # string Range depends on String#upto + # returns the maximum value in the range when called with no arguments assert_equal 'l', ('f'..'l').max assert_equal 'e', ('a'...'f').max + + # returns nil when the endpoint is less than the start point assert_equal nil, ('z'..'l').max end +assert('Range#max given a block') do + # returns nil when the endpoint is less than the start point + assert_equal nil, (('z'..'l').max { |x, y| x <=> y }) +end + assert('Range#min') do - # string Range depends on String#upto + # returns the minimum value in the range when called with no arguments assert_equal 'f', ('f'..'l').min + + # returns nil when the start point is greater than the endpoint assert_equal nil, ('z'..'l').min end + +assert('Range#min given a block') do + # returns nil when the start point is greater than the endpoint + assert_equal nil, (('z'..'l').min { |x, y| x <=> y }) +end -- cgit v1.2.3 From 0ad5ba7a0f819cff87460d9b6f5691656ea75ade Mon Sep 17 00:00:00 2001 From: Ryan Lopopolo Date: Tue, 9 Jul 2019 01:42:40 -0700 Subject: Add a fast path for Float and Fixnum ranges for Range#max and Range#min If no block is given and the Range has Fixnum or Float endpoints, do not iterate with each and instead compare the endpoints directly. This implementation passes all of the applicable specs from Ruby Spec. --- mrbgems/mruby-range-ext/mrblib/range.rb | 40 +++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/mrbgems/mruby-range-ext/mrblib/range.rb b/mrbgems/mruby-range-ext/mrblib/range.rb index de7925ba7..e09b2d096 100644 --- a/mrbgems/mruby-range-ext/mrblib/range.rb +++ b/mrbgems/mruby-range-ext/mrblib/range.rb @@ -25,4 +25,44 @@ class Range end ary end + + def max(&block) + val = self.first + last = self.last + return super if block + + # fast path for numerics + if (val.kind_of?(Fixnum) || val.kind_of?(Float)) && (last.kind_of?(Fixnum) || last.kind_of?(Float)) + raise TypeError if exclude_end? && !last.kind_of?(Fixnum) + return nil if val > last + return nil if val == last && exclude_end? + + max = last + max -= 1 if exclude_end? + return max + end + + # delegate to Enumerable + super + end + + def min(&block) + val = self.first + last = self.last + return super if block + + # fast path for numerics + if (val.kind_of?(Fixnum) || val.kind_of?(Float)) && (last.kind_of?(Fixnum) || last.kind_of?(Float)) + raise TypeError if exclude_end? && !last.kind_of?(Fixnum) + return nil if val > last + return nil if val == last && exclude_end? + + min = val + min -= 1 if exclude_end? + return min + end + + # delegate to Enumerable + super + end end -- cgit v1.2.3 From 56929362f58ba5ad3ebe4131a6cc4259e6479dc0 Mon Sep 17 00:00:00 2001 From: Ryan Lopopolo Date: Tue, 9 Jul 2019 01:48:15 -0700 Subject: Fix Range#min fast path with exclusive range --- mrbgems/mruby-range-ext/mrblib/range.rb | 1 - mrbgems/mruby-range-ext/test/range.rb | 1 + 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/mrbgems/mruby-range-ext/mrblib/range.rb b/mrbgems/mruby-range-ext/mrblib/range.rb index e09b2d096..a149a57dc 100644 --- a/mrbgems/mruby-range-ext/mrblib/range.rb +++ b/mrbgems/mruby-range-ext/mrblib/range.rb @@ -58,7 +58,6 @@ class Range return nil if val == last && exclude_end? min = val - min -= 1 if exclude_end? return min end diff --git a/mrbgems/mruby-range-ext/test/range.rb b/mrbgems/mruby-range-ext/test/range.rb index 6b135aeff..b56d6b58e 100644 --- a/mrbgems/mruby-range-ext/test/range.rb +++ b/mrbgems/mruby-range-ext/test/range.rb @@ -87,6 +87,7 @@ end assert('Range#min') do # returns the minimum value in the range when called with no arguments assert_equal 1, (1..10).min + assert_equal 1, (1...10).min # returns the minimum value in the Float range when called with no arguments assert_equal 303.20, (303.20..908.1111).min -- cgit v1.2.3 From 3b77b5fd394f9c9ba841e7bea8ea62dc6e8a3a1b Mon Sep 17 00:00:00 2001 From: Ryan Lopopolo Date: Tue, 9 Jul 2019 02:08:14 -0700 Subject: Revert Float dependency in Range#each --- mrblib/range.rb | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/mrblib/range.rb b/mrblib/range.rb index 3e6dbfb24..392cc2274 100644 --- a/mrblib/range.rb +++ b/mrblib/range.rb @@ -15,8 +15,7 @@ class Range val = self.first last = self.last - # numerics are special - if (val.kind_of?(Fixnum) || val.kind_of?(Float)) && (last.kind_of?(Fixnum) || last.kind_of?(Float)) + if val.kind_of?(Fixnum) && last.kind_of?(Fixnum) # fixnums are special lim = last lim += 1 unless exclude_end? i = val -- cgit v1.2.3 From 23fc3339eedf685e358c9389b4f6b8bd068bcad2 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Tue, 9 Jul 2019 18:59:00 +0900 Subject: Set `MRB_STR_ASCII` flag when an inline symbol is stringized --- src/symbol.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/symbol.c b/src/symbol.c index 38843c71f..53f4f6e1d 100644 --- a/src/symbol.c +++ b/src/symbol.c @@ -494,7 +494,7 @@ sym_inspect(mrb_state *mrb, mrb_value sym) name = mrb_sym2name_len(mrb, id, &len); str = mrb_str_new(mrb, 0, len+1); sp = RSTRING_PTR(str); - RSTRING_PTR(str)[0] = ':'; + sp[0] = ':'; memcpy(sp+1, name, len); mrb_assert_int_fit(mrb_int, len, size_t, SIZE_MAX); if (!symname_p(name) || strlen(name) != (size_t)len) { @@ -503,6 +503,9 @@ sym_inspect(mrb_state *mrb, mrb_value sym) sp[0] = ':'; sp[1] = '"'; } +#ifdef MRB_UTF8_STRING + if (SYMBOL_INLINE_P(id)) RSTR_SET_ASCII_FLAG(mrb_str_ptr(str)); +#endif return str; } @@ -513,7 +516,11 @@ mrb_sym2str(mrb_state *mrb, mrb_sym sym) const char *name = mrb_sym2name_len(mrb, sym, &len); if (!name) return mrb_undef_value(); /* can't happen */ - if (SYMBOL_INLINE_P(sym)) return mrb_str_new(mrb, name, len); + if (SYMBOL_INLINE_P(sym)) { + mrb_value str = mrb_str_new(mrb, name, len); + RSTR_SET_ASCII_FLAG(mrb_str_ptr(str)); + return str; + } return mrb_str_new_static(mrb, name, len); } -- cgit v1.2.3 From 80f78ca196790e2900b89f447c5ab83433d69d89 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Wed, 10 Jul 2019 21:53:17 +0900 Subject: Remove an unused argument of `str_with_class()` --- src/string.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/string.c b/src/string.c index 078c028d8..3ef86eb53 100644 --- a/src/string.c +++ b/src/string.c @@ -83,7 +83,7 @@ str_new(mrb_state *mrb, const char *p, size_t len) } static inline void -str_with_class(mrb_state *mrb, struct RString *s, mrb_value obj) +str_with_class(struct RString *s, mrb_value obj) { s->c = mrb_str_ptr(obj)->c; } @@ -93,7 +93,7 @@ mrb_str_new_empty(mrb_state *mrb, mrb_value str) { struct RString *s = str_new(mrb, 0, 0); - str_with_class(mrb, s, str); + str_with_class(s, str); return mrb_obj_value(s); } @@ -830,7 +830,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); + str_with_class(str2, self); p = RSTR_PTR(str2); if (len > 0) { n = RSTRING_LEN(self); @@ -1011,7 +1011,7 @@ mrb_str_dup(mrb_state *mrb, mrb_value str) struct RString *s = mrb_str_ptr(str); struct RString *dup = str_new(mrb, 0, 0); - str_with_class(mrb, dup, str); + str_with_class(dup, str); return str_replace(mrb, dup, s); } @@ -2561,7 +2561,7 @@ mrb_str_dump(mrb_state *mrb, mrb_value str) } result = str_new(mrb, 0, len); - str_with_class(mrb, result, str); + str_with_class(result, str); p = RSTRING_PTR(str); pend = p + RSTRING_LEN(str); q = RSTR_PTR(result); *q++ = '"'; -- cgit v1.2.3 From 8c0d9ba1a363683bbeab8cb7c22acdb07621352d Mon Sep 17 00:00:00 2001 From: dearblue Date: Thu, 11 Jul 2019 21:52:05 +0900 Subject: Improve performance `String#index` with UTF-8 Based on Boyer-Moore-Horspool algorithm (Quick Search algorithm). As a side effect, the correct position is returned even if an invalid UTF-8 string is given. ```console % ./mruby@master -e 'p ("\xd1" * 100 + "#").index("#")' 50 % ./mruby@improve-index -e 'p ("\xd1" * 100 + "#").index("#")' 100 ``` The other behavior should be the same as the current implementation. --- src/string.c | 68 +++++++++++++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 63 insertions(+), 5 deletions(-) diff --git a/src/string.c b/src/string.c index 3ef86eb53..0700f81fa 100644 --- a/src/string.c +++ b/src/string.c @@ -304,12 +304,73 @@ bytes2chars(char *p, mrb_int bi) return i; } +static mrb_int +str_index_str_by_char_search(mrb_state *mrb, const char *p, const char *pend, const char *s, const mrb_int slen, mrb_int off) +{ + /* Based on Quick Search algorithm (Boyer-Moore-Horspool algorithm) */ + + ptrdiff_t qstable[1 << CHAR_BIT]; + + /* Preprocessing */ + { + size_t i; + + 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); + } + } + + /* Searching */ + if (p < pend && pend - p >= slen) { + for (;;) { + const char *pivot; + + if (memcmp(p, s, slen) == 0) { + return off; + } + + pivot = p + qstable[(unsigned char)p[slen - 1]]; + if (pivot > pend || pivot < p /* overflowed */) { return -1; } + + do { + p += 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) +{ + 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 += 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, bi) (bi) #define BYTES_ALIGN_CHECK(pos) +#define str_index_str_by_char(mrb, str, sub, pos) str_index_str(mrb, str, sub, pos) #endif static inline mrb_int @@ -1680,15 +1741,13 @@ mrb_str_index_m(mrb_state *mrb, mrb_value str) else sub = mrb_nil_value(); } - clen = RSTRING_CHAR_LEN(str); if (pos < 0) { + clen = RSTRING_CHAR_LEN(str); pos += clen; if (pos < 0) { return mrb_nil_value(); } } - if (pos > clen) return mrb_nil_value(); - pos = chars2bytes(str, 0, pos); switch (mrb_type(sub)) { default: { @@ -1702,12 +1761,11 @@ mrb_str_index_m(mrb_state *mrb, mrb_value str) } /* fall through */ case MRB_TT_STRING: - pos = str_index_str(mrb, str, sub, pos); + pos = str_index_str_by_char(mrb, str, sub, pos); break; } if (pos == -1) return mrb_nil_value(); - pos = bytes2chars(RSTRING_PTR(str), pos); BYTES_ALIGN_CHECK(pos); return mrb_fixnum_value(pos); } -- cgit v1.2.3 From e4249b1b9e1c568546865287bf367e4501c263de Mon Sep 17 00:00:00 2001 From: dearblue Date: Thu, 11 Jul 2019 22:00:01 +0900 Subject: Add UTF-8 test for `String#index` --- test/t/string.rb | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/test/t/string.rb b/test/t/string.rb index 87d60ed72..cf145f97e 100644 --- a/test/t/string.rb +++ b/test/t/string.rb @@ -468,6 +468,17 @@ assert('String#index', '15.2.10.5.22') do assert_equal nil, "hello".index("", 6) end +assert('String#index(UTF-8)', '15.2.10.5.22') do + assert_equal 0, '⓿➊➋➌➍➎'.index('⓿') + assert_nil '⓿➊➋➌➍➎'.index('➓') + assert_equal 6, '⓿➊➋➌➍➎⓿➊➋➌➍➎'.index('⓿', 1) + assert_equal 6, "⓿➊➋➌➍➎".index("", 6) + assert_equal nil, "⓿➊➋➌➍➎".index("", 7) + assert_equal 0, '⓿➊➋➌➍➎'.index("\xe2") + assert_equal nil, '⓿➊➋➌➍➎'.index("\xe3") + assert_equal 6, "\xd1\xd1\xd1\xd1\xd1\xd1⓿➊➋➌➍➎".index('⓿') +end if UTF8STRING + assert('String#initialize', '15.2.10.5.23') do a = '' a.initialize('abc') -- cgit v1.2.3 From 66909dfe8650e242ed96c26e576498d290ece347 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Thu, 11 Jul 2019 23:56:45 +0900 Subject: Consider `-MP` flag specified when parsing `.d` file `-MP` flag is used in `tasks/toolchains/android.rake`. --- lib/mruby/build/command.rb | 35 +++++++++++++++++++++++++++++++---- 1 file changed, 31 insertions(+), 4 deletions(-) diff --git a/lib/mruby/build/command.rb b/lib/mruby/build/command.rb index 0f18e0e62..d4354225e 100644 --- a/lib/mruby/build/command.rb +++ b/lib/mruby/build/command.rb @@ -127,13 +127,40 @@ module MRuby end private + + # + # === Example of +.d+ file + # + # ==== Without -MP compiler flag + # + # /build/host/src/array.o: \ + # /src/array.c \ + # /include/mruby/common.h \ + # /include/mruby/value.h \ + # /src/value_array.h + # + # ==== With -MP compiler flag + # + # /build/host/src/array.o: \ + # /src/array.c \ + # /include/mruby/common.h \ + # /include/mruby/value.h \ + # /src/value_array.h + # + # /include/mruby/common.h: + # + # /include/mruby/value.h: + # + # /src/value_array.h: + # def get_dependencies(file) file = file.ext('d') unless File.extname(file) == '.d' + deps = [] if File.exist?(file) - File.read(file).gsub("\\\n ", "").scan(/^\S+:\s+(.+)$/).flatten.map {|s| s.split(' ') }.flatten - else - [] - end + [ MRUBY_CONFIG ] + File.foreach(file){|line| deps << $1 if /^ +(.*?)(?: *\\)?$/ =~ line} + deps.uniq! + end + deps << MRUBY_CONFIG end end -- cgit v1.2.3 From 16e4657acdacfd99bd649d50b44a748d86a31861 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Fri, 12 Jul 2019 18:35:20 +0900 Subject: Lazy load `tasks/toolchains/*.rake` --- lib/mruby/build.rb | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/lib/mruby/build.rb b/lib/mruby/build.rb index 887a5518e..d9d52948b 100644 --- a/lib/mruby/build.rb +++ b/lib/mruby/build.rb @@ -22,7 +22,6 @@ module MRuby def initialize(name, &block) @name, @initializer = name.to_s, block - MRuby::Toolchain.toolchains ||= {} MRuby::Toolchain.toolchains[@name] = self end @@ -30,13 +29,8 @@ module MRuby conf.instance_exec(conf, params, &@initializer) end - def self.load - Dir.glob("#{MRUBY_ROOT}/tasks/toolchains/*.rake").each do |file| - Kernel.load file - end - end + self.toolchains = {} end - Toolchain.load class Build class << self @@ -196,10 +190,15 @@ EOS end def toolchain(name, params={}) - tc = Toolchain.toolchains[name.to_s] - fail "Unknown #{name} toolchain" unless tc + name = name.to_s + tc = Toolchain.toolchains[name] || begin + path = "#{MRUBY_ROOT}/tasks/toolchains/#{name}.rake" + fail "Unknown #{name} toolchain" unless File.exist?(path) + load path + Toolchain.toolchains[name] + end tc.setup(self, params) - @toolchains.unshift name.to_s + @toolchains.unshift name end def primary_toolchain -- cgit v1.2.3 From bde2f35a9f2d894ec88ad693633e89279b0560b9 Mon Sep 17 00:00:00 2001 From: dearblue Date: Fri, 12 Jul 2019 21:23:55 +0900 Subject: Fix heap buffer overflow; fix #4569 --- src/string.c | 24 +++++++++++------------- 1 file changed, 11 insertions(+), 13 deletions(-) diff --git a/src/string.c b/src/string.c index 0700f81fa..056348921 100644 --- a/src/string.c +++ b/src/string.c @@ -324,22 +324,20 @@ str_index_str_by_char_search(mrb_state *mrb, const char *p, const char *pend, co } /* Searching */ - if (p < pend && pend - p >= slen) { - for (;;) { - const char *pivot; + while (p < pend && pend - p >= slen) { + const char *pivot; - if (memcmp(p, s, slen) == 0) { - return off; - } + if (memcmp(p, s, slen) == 0) { + return off; + } - pivot = p + qstable[(unsigned char)p[slen - 1]]; - if (pivot > pend || pivot < p /* overflowed */) { return -1; } + pivot = p + qstable[(unsigned char)p[slen - 1]]; + if (pivot > pend || pivot < p /* overflowed */) { return -1; } - do { - p += utf8len(p, pend); - off ++; - } while (p < pivot); - } + do { + p += utf8len(p, pend); + off ++; + } while (p < pivot); } return -1; -- cgit v1.2.3 From 6b1cc6e2fe4eab30e265d8209a208e0bf942c54d Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Mon, 8 Jul 2019 18:40:13 +0900 Subject: Avoid `mrb_funcall()` if possible using `mrb_Float()`; ref #4555 --- src/numeric.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/numeric.c b/src/numeric.c index 0d1c23589..4288df44a 100644 --- a/src/numeric.c +++ b/src/numeric.c @@ -172,17 +172,17 @@ integral_div(mrb_state *mrb, mrb_value x) static mrb_value integral_coerce_step_counter(mrb_state *mrb, mrb_value self) { - mrb_value counter = self, num, step; + mrb_value num, step; mrb_get_args(mrb, "oo", &num, &step); #ifndef MRB_WITHOUT_FLOAT if (mrb_float_p(self) || mrb_float_p(num) || mrb_float_p(step)) { - counter = mrb_funcall(mrb, counter, "to_f", 0); + return mrb_Float(mrb, self); } #endif - return counter; + return self; } #ifndef MRB_WITHOUT_FLOAT -- cgit v1.2.3 From 9741df100bb84a858725dba58705a908e5bdca4c Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Sat, 13 Jul 2019 13:13:21 +0900 Subject: Change type of a variable for signedness mismatch; ref #4573 --- src/string.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/string.c b/src/string.c index 056348921..a6aa9d906 100644 --- a/src/string.c +++ b/src/string.c @@ -313,7 +313,7 @@ str_index_str_by_char_search(mrb_state *mrb, const char *p, const char *pend, co /* Preprocessing */ { - size_t i; + mrb_int i; for (i = 0; i < 1 << CHAR_BIT; i ++) { qstable[i] = slen; -- cgit v1.2.3 From a9fd2e646492699894d33eaf3de7336356ce6726 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Sat, 13 Jul 2019 13:16:30 +0900 Subject: Resolve ambiguous argument warning. --- mrbgems/mruby-complex/test/complex.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mrbgems/mruby-complex/test/complex.rb b/mrbgems/mruby-complex/test/complex.rb index ab882664e..5b7c3bfa4 100644 --- a/mrbgems/mruby-complex/test/complex.rb +++ b/mrbgems/mruby-complex/test/complex.rb @@ -50,7 +50,7 @@ assert 'Complex#-' do end assert 'Complex#-@' do - assert_complex -Complex(1, 2), (-1 - 2i) + assert_complex(-Complex(1, 2), (-1 - 2i)) end assert 'Complex#/' do -- cgit v1.2.3 From b4cdced22fe1f25d8cf6fc499a2e2c9875f17e9e Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Sat, 13 Jul 2019 18:05:01 +0900 Subject: `Enumerable#detect` {and `#find`} should call `ifnone`; fix #4484 It's an error in ISO specification; 15.3.2.2.4 and 15.3.2.2.7 --- mrblib/enum.rb | 16 +++++++--------- test/t/enumerable.rb | 4 ++-- 2 files changed, 9 insertions(+), 11 deletions(-) diff --git a/mrblib/enum.rb b/mrblib/enum.rb index 9bd74e1c4..fe40b4d27 100644 --- a/mrblib/enum.rb +++ b/mrblib/enum.rb @@ -65,22 +65,20 @@ module Enumerable end ## - # Call the given block for each element - # which is yield by +each+. Return - # +ifnone+ if no block value was true. - # Otherwise return the first block value - # which had was true. + # Return the first element for which + # value from the block is true. If no + # object matches, calls +ifnone+ and + # returns its result. Otherwise returns + # +nil+. # # ISO 15.3.2.2.4 def detect(ifnone=nil, &block) - ret = ifnone self.each{|*val| if block.call(*val) - ret = val.__svalue - break + return val.__svalue end } - ret + ifnone.call unless ifnone.nil? end ## diff --git a/test/t/enumerable.rb b/test/t/enumerable.rb index 652c304da..9e7602db7 100644 --- a/test/t/enumerable.rb +++ b/test/t/enumerable.rb @@ -45,7 +45,7 @@ end assert('Enumerable#detect', '15.3.2.2.4') do assert_equal 1, [1,2,3].detect() { true } - assert_equal 'a', [1,2,3].detect("a") { false } + assert_equal 'a', [1,2,3].detect(->{"a"}) { false } end assert('Array#each_with_index', '15.3.2.2.5') do @@ -64,7 +64,7 @@ end assert('Enumerable#find', '15.3.2.2.7') do assert_equal 1, [1,2,3].find() { true } - assert_equal 'a', [1,2,3].find("a") { false } + assert_equal 'a', [1,2,3].find(->{"a"}) { false } end assert('Enumerable#find_all', '15.3.2.2.8') do -- cgit v1.2.3 From e8a84d663f7ae76fc98920ae7e08882d129496bc Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Sat, 13 Jul 2019 20:41:56 +0900 Subject: Add `mruby-method` gem to `default.gembox` [ci skip] --- mrbgems/default.gembox | 3 +++ 1 file changed, 3 insertions(+) diff --git a/mrbgems/default.gembox b/mrbgems/default.gembox index 23e65fcee..9859c7d52 100644 --- a/mrbgems/default.gembox +++ b/mrbgems/default.gembox @@ -86,6 +86,9 @@ MRuby::GemBox.new do |conf| # Use class/module extension conf.gem :core => "mruby-class-ext" + # Use Method/UnboundMethod class + conf.gem :core => "mruby-method" + # Use mruby-compiler to build other mrbgems conf.gem :core => "mruby-compiler" end -- cgit v1.2.3 From c417c16788524c5918d2ac9b9180f2837442d4e5 Mon Sep 17 00:00:00 2001 From: dearblue Date: Sat, 13 Jul 2019 23:04:12 +0900 Subject: Use stack memory for small name of attr accessors Also integrated the common parts of `mrb_mod_attr_reader()` and `mrb_mod_attr_writer()` functions. --- src/class.c | 113 +++++++++++++++++++++++++++++++++--------------------------- 1 file changed, 63 insertions(+), 50 deletions(-) diff --git a/src/class.c b/src/class.c index edee95678..2961284f5 100644 --- a/src/class.c +++ b/src/class.c @@ -1363,15 +1363,52 @@ mrb_method_search(mrb_state *mrb, struct RClass* c, mrb_sym mid) return m; } +#define ONSTACK_ALLOC_MAX 32 + +static mrb_sym +prepare_name_common(mrb_state *mrb, mrb_sym sym, const char *prefix, const char *suffix) +{ + char onstack[ONSTACK_ALLOC_MAX]; + mrb_int sym_len; + const char *sym_str = mrb_sym2name_len(mrb, sym, &sym_len); + size_t prefix_len = prefix ? strlen(prefix) : 0; + size_t suffix_len = suffix ? strlen(suffix) : 0; + size_t name_len = sym_len + prefix_len + suffix_len; + char *buf = name_len > sizeof(onstack) ? (char *)mrb_alloca(mrb, name_len) : onstack; + char *p = buf; + + if (prefix_len > 0) { + memcpy(p, prefix, prefix_len); + p += prefix_len; + } + + memcpy(p, sym_str, sym_len); + p += sym_len; + + if (suffix_len > 0) { + memcpy(p, suffix, suffix_len); + p += suffix_len; + } + + return mrb_intern(mrb, buf, name_len); +} + static mrb_value -attr_reader(mrb_state *mrb, mrb_value obj) +prepare_ivar_name(mrb_state *mrb, mrb_sym sym) { - mrb_value name = mrb_proc_cfunc_env_get(mrb, 0); - return mrb_iv_get(mrb, obj, to_sym(mrb, name)); + sym = prepare_name_common(mrb, sym, "@", NULL); + mrb_iv_name_sym_check(mrb, sym); + return mrb_symbol_value(sym); +} + +static mrb_sym +prepare_writer_name(mrb_state *mrb, mrb_sym sym) +{ + return prepare_name_common(mrb, sym, NULL, "="); } static mrb_value -mrb_mod_attr_reader(mrb_state *mrb, mrb_value mod) +mod_attr_define(mrb_state *mrb, mrb_value mod, mrb_value (*accessor)(mrb_state *, mrb_value), mrb_sym (*access_name)(mrb_state *, mrb_sym)) { struct RClass *c = mrb_class_ptr(mod); mrb_value *argv; @@ -1381,20 +1418,18 @@ mrb_mod_attr_reader(mrb_state *mrb, mrb_value mod) mrb_get_args(mrb, "*", &argv, &argc); ai = mrb_gc_arena_save(mrb); for (i=0; i Date: Mon, 15 Jul 2019 11:19:22 +0900 Subject: Fix pack/unpack for base64; ref #4556 The pack/unpack "m" directive should be treated as a length rather than an element count. --- mrbgems/mruby-pack/src/pack.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/mrbgems/mruby-pack/src/pack.c b/mrbgems/mruby-pack/src/pack.c index 46c0cc1fe..894c4555f 100644 --- a/mrbgems/mruby-pack/src/pack.c +++ b/mrbgems/mruby-pack/src/pack.c @@ -1002,7 +1002,7 @@ alias: case 'm': dir = PACK_DIR_BASE64; type = PACK_TYPE_STRING; - flags |= PACK_FLAG_WIDTH; + flags |= PACK_FLAG_WIDTH | PACK_FLAG_COUNT2; break; case 'N': /* = "L>" */ dir = PACK_DIR_LONG; @@ -1196,7 +1196,7 @@ mrb_pack_pack(mrb_state *mrb, mrb_value ary) default: break; } - if (dir == PACK_DIR_STR) { /* always consumes 1 entry */ + if (dir == PACK_DIR_STR || dir == PACK_DIR_BASE64) { /* always consumes 1 entry */ aidx++; break; } @@ -1249,6 +1249,9 @@ pack_unpack(mrb_state *mrb, mrb_value str, int single) case PACK_DIR_STR: srcidx += unpack_a(mrb, sptr, srclen - srcidx, result, count, flags); break; + case PACK_DIR_BASE64: + srcidx += unpack_m(mrb, sptr, srclen - srcidx, result, flags); + break; } continue; } @@ -1275,9 +1278,6 @@ pack_unpack(mrb_state *mrb, mrb_value str, int single) case PACK_DIR_QUAD: srcidx += unpack_q(mrb, sptr, srclen - srcidx, result, flags); break; - case PACK_DIR_BASE64: - srcidx += unpack_m(mrb, sptr, srclen - srcidx, result, flags); - break; #ifndef MRB_WITHOUT_FLOAT case PACK_DIR_FLOAT: srcidx += unpack_float(mrb, sptr, srclen - srcidx, result, flags); -- cgit v1.2.3 From fd899481643feeed874c95060fa50cb75f9d993a Mon Sep 17 00:00:00 2001 From: dearblue Date: Mon, 15 Jul 2019 11:23:50 +0900 Subject: Fix empty array refers; ref #4556 For example, `"".unpack("")` evaluates to `[]`. --- mrbgems/mruby-pack/src/pack.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/mrbgems/mruby-pack/src/pack.c b/mrbgems/mruby-pack/src/pack.c index 894c4555f..9f091194b 100644 --- a/mrbgems/mruby-pack/src/pack.c +++ b/mrbgems/mruby-pack/src/pack.c @@ -1299,7 +1299,12 @@ pack_unpack(mrb_state *mrb, mrb_value str, int single) if (single) break; } - if (single) return RARRAY_PTR(result)[0]; + if (single) { + if (RARRAY_LEN(result) > 0) { + return RARRAY_PTR(result)[0]; + } + return mrb_nil_value(); + } return result; } -- cgit v1.2.3 From 7b260d9c2de4436d6e8b09ba4fd524782934153f Mon Sep 17 00:00:00 2001 From: dearblue Date: Sun, 14 Jul 2019 18:55:38 +0900 Subject: Improve `utf8len()` performance with UTF-8 --- src/string.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/string.c b/src/string.c index a6aa9d906..be623deda 100644 --- a/src/string.c +++ b/src/string.c @@ -233,7 +233,9 @@ utf8len(const char* p, const char* e) mrb_int len; mrb_int i; + if ((unsigned char)*p < 0x80) return 1; len = utf8len_codepage[(unsigned char)*p]; + if (len == 1) return 1; if (len > e - p) return 1; for (i = 1; i < len; ++i) if ((p[i] & 0xc0) != 0x80) -- cgit v1.2.3 From 380805ece257147275bbed3eb83277f374296d9a Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Sun, 14 Jul 2019 19:13:19 +0900 Subject: Keep `MRB_STR_ASCII` flag in some methods of `String` --- include/mruby/string.h | 9 ++++++++- src/string.c | 15 +++++++-------- 2 files changed, 15 insertions(+), 9 deletions(-) diff --git a/include/mruby/string.h b/include/mruby/string.h index d648d856c..4615b4384 100644 --- a/include/mruby/string.h +++ b/include/mruby/string.h @@ -107,7 +107,6 @@ MRB_API mrb_int mrb_str_strlen(mrb_state*, struct RString*); #define MRB_STR_EMBED_LEN_SHIFT 6 void mrb_gc_free_str(mrb_state*, struct RString*); -MRB_API void mrb_str_modify(mrb_state*, struct RString*); /* * Finds the index of a substring in a string @@ -454,6 +453,14 @@ mrb_value mrb_str_inspect(mrb_state *mrb, mrb_value str); mrb_bool mrb_str_beg_len(mrb_int str_len, mrb_int *begp, mrb_int *lenp); mrb_value mrb_str_byte_subseq(mrb_state *mrb, mrb_value str, mrb_int beg, mrb_int len); +void mrb_str_modify_keep_ascii(mrb_state *mrb, struct RString *s); + +MRB_INLINE void +mrb_str_modify(mrb_state *mrb, struct RString *s) +{ + mrb_str_modify_keep_ascii(mrb, s); + RSTR_UNSET_ASCII_FLAG(s); +} #ifdef MRB_UTF8_STRING mrb_int mrb_utf8_len(const char *str, mrb_int byte_len); diff --git a/src/string.c b/src/string.c index a6aa9d906..8706bfd1b 100644 --- a/src/string.c +++ b/src/string.c @@ -706,11 +706,10 @@ mrb_locale_from_utf8(const char *utf8, int len) } #endif -MRB_API void -mrb_str_modify(mrb_state *mrb, struct RString *s) +void +mrb_str_modify_keep_ascii(mrb_state *mrb, struct RString *s) { mrb_check_frozen(mrb, s); - RSTR_UNSET_ASCII_FLAG(s); if (RSTR_SHARED_P(s)) { mrb_shared_string *shared = s->as.heap.aux.shared; @@ -1339,7 +1338,7 @@ mrb_str_capitalize_bang(mrb_state *mrb, mrb_value str) mrb_bool modify = FALSE; struct RString *s = mrb_str_ptr(str); - mrb_str_modify(mrb, s); + mrb_str_modify_keep_ascii(mrb, 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)) { @@ -1398,7 +1397,7 @@ mrb_str_chomp_bang(mrb_state *mrb, mrb_value str) struct RString *s = mrb_str_ptr(str); argc = mrb_get_args(mrb, "|S", &rs); - mrb_str_modify(mrb, s); + mrb_str_modify_keep_ascii(mrb, s); len = RSTR_LEN(s); if (argc == 0) { if (len == 0) return mrb_nil_value(); @@ -1497,7 +1496,7 @@ mrb_str_chop_bang(mrb_state *mrb, mrb_value str) { struct RString *s = mrb_str_ptr(str); - mrb_str_modify(mrb, s); + mrb_str_modify_keep_ascii(mrb, s); if (RSTR_LEN(s) > 0) { mrb_int len; #ifdef MRB_UTF8_STRING @@ -1566,7 +1565,7 @@ mrb_str_downcase_bang(mrb_state *mrb, mrb_value str) mrb_bool modify = FALSE; struct RString *s = mrb_str_ptr(str); - mrb_str_modify(mrb, s); + mrb_str_modify_keep_ascii(mrb, s); p = RSTR_PTR(s); pend = RSTR_PTR(s) + RSTR_LEN(s); while (p < pend) { @@ -2536,7 +2535,7 @@ mrb_str_upcase_bang(mrb_state *mrb, mrb_value str) char *p, *pend; mrb_bool modify = FALSE; - mrb_str_modify(mrb, s); + mrb_str_modify_keep_ascii(mrb, s); p = RSTRING_PTR(str); pend = RSTRING_END(str); while (p < pend) { -- cgit v1.2.3 From 9093f3403f76b0a70d2b29b6c04ca7f203c242e6 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Mon, 15 Jul 2019 07:39:57 +0900 Subject: Add `MRB_API` to `mrb_str_modify_keep_ascii()` --- include/mruby/string.h | 3 ++- src/string.c | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/include/mruby/string.h b/include/mruby/string.h index 4615b4384..77f6becf6 100644 --- a/include/mruby/string.h +++ b/include/mruby/string.h @@ -108,6 +108,8 @@ MRB_API mrb_int mrb_str_strlen(mrb_state*, struct RString*); void mrb_gc_free_str(mrb_state*, struct RString*); +MRB_API void mrb_str_modify_keep_ascii(mrb_state *mrb, struct RString *s); + /* * Finds the index of a substring in a string */ @@ -453,7 +455,6 @@ mrb_value mrb_str_inspect(mrb_state *mrb, mrb_value str); mrb_bool mrb_str_beg_len(mrb_int str_len, mrb_int *begp, mrb_int *lenp); mrb_value mrb_str_byte_subseq(mrb_state *mrb, mrb_value str, mrb_int beg, mrb_int len); -void mrb_str_modify_keep_ascii(mrb_state *mrb, struct RString *s); MRB_INLINE void mrb_str_modify(mrb_state *mrb, struct RString *s) diff --git a/src/string.c b/src/string.c index 8706bfd1b..c1a001634 100644 --- a/src/string.c +++ b/src/string.c @@ -706,7 +706,7 @@ mrb_locale_from_utf8(const char *utf8, int len) } #endif -void +MRB_API void mrb_str_modify_keep_ascii(mrb_state *mrb, struct RString *s) { mrb_check_frozen(mrb, s); -- cgit v1.2.3 From acad9567c16317a86d7e246d6093a43d3a58c758 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Mon, 15 Jul 2019 23:03:41 +0900 Subject: Unify type of line number to `uint16_t` --- include/mruby/compile.h | 6 +++--- mrbgems/mruby-compiler/core/parse.y | 2 +- mrbgems/mruby-eval/src/eval.c | 2 +- src/backtrace.c | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/include/mruby/compile.h b/include/mruby/compile.h index 8f8f2ebd7..3b25ff526 100644 --- a/include/mruby/compile.h +++ b/include/mruby/compile.h @@ -24,7 +24,7 @@ typedef struct mrbc_context { mrb_sym *syms; int slen; char *filename; - short lineno; + uint16_t lineno; int (*partial_hook)(struct mrb_parser_state*); void *partial_data; struct RClass *target_class; @@ -67,7 +67,7 @@ enum mrb_lex_state_enum { /* saved error message */ struct mrb_parser_message { - int lineno; + uint16_t lineno; int column; char* message; }; @@ -119,7 +119,7 @@ struct mrb_parser_state { #endif mrbc_context *cxt; mrb_sym filename_sym; - int lineno; + uint16_t lineno; int column; enum mrb_lex_state_enum lstate; diff --git a/mrbgems/mruby-compiler/core/parse.y b/mrbgems/mruby-compiler/core/parse.y index 96a9453b6..ac59a8b0b 100644 --- a/mrbgems/mruby-compiler/core/parse.y +++ b/mrbgems/mruby-compiler/core/parse.y @@ -233,7 +233,7 @@ parser_strdup(parser_state *p, const char *s) #define strdup(s) parser_strdup(p, s) static void -dump_int(short i, char *s) +dump_int(uint16_t i, char *s) { char *p = s; char *t = s; diff --git a/mrbgems/mruby-eval/src/eval.c b/mrbgems/mruby-eval/src/eval.c index a3b211ba2..30534aaec 100644 --- a/mrbgems/mruby-eval/src/eval.c +++ b/mrbgems/mruby-eval/src/eval.c @@ -235,7 +235,7 @@ create_proc_from_string(mrb_state *mrb, char *s, mrb_int len, mrb_value binding, } cxt = mrbc_context_new(mrb); - cxt->lineno = (short)line; + cxt->lineno = (uint16_t)line; mrbc_filename(mrb, cxt, file ? file : "(eval)"); cxt->capture_errors = TRUE; diff --git a/src/backtrace.c b/src/backtrace.c index e4f5a3064..991a67d00 100644 --- a/src/backtrace.c +++ b/src/backtrace.c @@ -16,7 +16,7 @@ #include struct backtrace_location { - int lineno; + int32_t lineno; mrb_sym method_id; const char *filename; }; -- cgit v1.2.3 From 31492a177c34485e9bcc441e74c208366920f7b2 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Tue, 16 Jul 2019 21:56:58 +0900 Subject: Copy receiver's `MRB_STR_ASCII` flag in some methods of `String` --- src/string.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/string.c b/src/string.c index 39b3515a3..6b7cced13 100644 --- a/src/string.c +++ b/src/string.c @@ -487,6 +487,7 @@ mrb_str_byte_subseq(mrb_state *mrb, mrb_value str, mrb_int beg, mrb_int len) s->as.heap.ptr += beg; s->as.heap.len = len; } + RSTR_COPY_ASCII_FLAG(s, orig); return mrb_obj_value(s); } @@ -902,6 +903,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)); return mrb_obj_value(str2); } @@ -2837,6 +2839,7 @@ mrb_str_inspect(mrb_state *mrb, mrb_value str) } } mrb_str_cat_lit(mrb, result, "\""); + RSTR_COPY_ASCII_FLAG(mrb_str_ptr(result), mrb_str_ptr(str)); return result; } -- cgit v1.2.3 From 2add8641648e00717c97b730be8762aece80029e Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Tue, 16 Jul 2019 12:39:30 +0900 Subject: Allow `mruby-range-ext` to work with `MRB_WITHOUT_FLOAT`; ref #4576 --- mrbgems/mruby-range-ext/src/range.c | 27 +++++++++++++++++++++++---- 1 file changed, 23 insertions(+), 4 deletions(-) diff --git a/mrbgems/mruby-range-ext/src/range.c b/mrbgems/mruby-range-ext/src/range.c index fb76fe0d8..b8c76b796 100644 --- a/mrbgems/mruby-range-ext/src/range.c +++ b/mrbgems/mruby-range-ext/src/range.c @@ -1,7 +1,3 @@ -#ifdef MRB_WITHOUT_FLOAT -# error Conflict 'MRB_WITHOUT_FLOAT' configuration in your 'build_config.rb' -#endif - #include #include #include @@ -110,6 +106,7 @@ range_last(mrb_state *mrb, mrb_value range) * ('a'..'z').size #=> nil */ +#ifndef MRB_WITHOUT_FLOAT static mrb_value range_size(mrb_state *mrb, mrb_value range) { @@ -162,6 +159,28 @@ range_size(mrb_state *mrb, mrb_value range) } return mrb_nil_value(); } +#else +static mrb_value +range_size(mrb_state *mrb, mrb_value range) +{ + struct RRange *r = mrb_range_ptr(mrb, range); + mrb_value beg, end; + mrb_int excl; + + beg = RANGE_BEG(r); + end = RANGE_END(r); + excl = RANGE_EXCL(r) ? 0 : 1; + + if (mrb_fixnum_p(beg) && mrb_fixnum_p(end)) { + mrb_int a = mrb_fixnum(beg); + mrb_int b = mrb_fixnum(end); + mrb_int c = b - a + excl; + + return mrb_fixnum_value(c); + } + return mrb_nil_value(); +} +#endif /* MRB_WITHOUT_FLOAT */ void mrb_mruby_range_ext_gem_init(mrb_state* mrb) -- cgit v1.2.3 From b22bde6596ece6f9e3ef245bbab13a9f664907a8 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Wed, 17 Jul 2019 00:29:33 +0900 Subject: Avoid `MRB_INLINE` for `mrb_str_modify()`; ref #4579 Functions that are called infrequently need not to be inline. --- include/mruby/string.h | 9 ++------- src/string.c | 7 +++++++ 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/include/mruby/string.h b/include/mruby/string.h index 77f6becf6..d17ac1c1d 100644 --- a/include/mruby/string.h +++ b/include/mruby/string.h @@ -108,6 +108,8 @@ MRB_API mrb_int mrb_str_strlen(mrb_state*, struct RString*); void mrb_gc_free_str(mrb_state*, struct RString*); +MRB_API void mrb_str_modify(mrb_state *mrb, struct RString *s); +/* mrb_str_modify() with keeping ASCII flag if set */ MRB_API void mrb_str_modify_keep_ascii(mrb_state *mrb, struct RString *s); /* @@ -456,13 +458,6 @@ mrb_value mrb_str_inspect(mrb_state *mrb, mrb_value str); mrb_bool mrb_str_beg_len(mrb_int str_len, mrb_int *begp, mrb_int *lenp); mrb_value mrb_str_byte_subseq(mrb_state *mrb, mrb_value str, mrb_int beg, mrb_int len); -MRB_INLINE void -mrb_str_modify(mrb_state *mrb, struct RString *s) -{ - mrb_str_modify_keep_ascii(mrb, s); - RSTR_UNSET_ASCII_FLAG(s); -} - #ifdef MRB_UTF8_STRING mrb_int mrb_utf8_len(const char *str, mrb_int byte_len); #endif diff --git a/src/string.c b/src/string.c index 6b7cced13..de8a15ba9 100644 --- a/src/string.c +++ b/src/string.c @@ -770,6 +770,13 @@ mrb_str_modify_keep_ascii(mrb_state *mrb, struct RString *s) } } +MRB_API void +mrb_str_modify(mrb_state *mrb, struct RString *s) +{ + mrb_str_modify_keep_ascii(mrb, s); + RSTR_UNSET_ASCII_FLAG(s); +} + MRB_API mrb_value mrb_str_resize(mrb_state *mrb, mrb_value str, mrb_int len) { -- cgit v1.2.3 From d5939879ccae40ba4623fce05b8f67dd05a465d7 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Wed, 17 Jul 2019 10:39:17 +0900 Subject: Fixed a bug in #4034 --- mrblib/hash.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mrblib/hash.rb b/mrblib/hash.rb index 0e2da62e1..b49e987c7 100644 --- a/mrblib/hash.rb +++ b/mrblib/hash.rb @@ -196,7 +196,7 @@ class Hash i=0 while i" + self[k]._inspect) + ary<<(k._inspect(recur_list) + "=>" + self[k]._inspect(recur_list)) i+=1 end "{"+ary.join(", ")+"}" -- cgit v1.2.3 From 8cb37804c16b1506d019081bb5d366b078b0b42a Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Wed, 17 Jul 2019 18:58:21 +0900 Subject: Allow `mruby-range-ext` to work with `MRB_WITHOUT_FLOAT`; ref 2add8641 --- mrbgems/mruby-range-ext/mrblib/range.rb | 4 ++-- mrbgems/mruby-range-ext/test/range.rb | 28 ++++++++++++++++++---------- 2 files changed, 20 insertions(+), 12 deletions(-) diff --git a/mrbgems/mruby-range-ext/mrblib/range.rb b/mrbgems/mruby-range-ext/mrblib/range.rb index a149a57dc..7c5787fac 100644 --- a/mrbgems/mruby-range-ext/mrblib/range.rb +++ b/mrbgems/mruby-range-ext/mrblib/range.rb @@ -32,7 +32,7 @@ class Range return super if block # fast path for numerics - if (val.kind_of?(Fixnum) || val.kind_of?(Float)) && (last.kind_of?(Fixnum) || last.kind_of?(Float)) + if val.kind_of?(Numeric) && last.kind_of?(Numeric) raise TypeError if exclude_end? && !last.kind_of?(Fixnum) return nil if val > last return nil if val == last && exclude_end? @@ -52,7 +52,7 @@ class Range return super if block # fast path for numerics - if (val.kind_of?(Fixnum) || val.kind_of?(Float)) && (last.kind_of?(Fixnum) || last.kind_of?(Float)) + if val.kind_of?(Numeric) && last.kind_of?(Numeric) raise TypeError if exclude_end? && !last.kind_of?(Fixnum) return nil if val > last return nil if val == last && exclude_end? diff --git a/mrbgems/mruby-range-ext/test/range.rb b/mrbgems/mruby-range-ext/test/range.rb index b56d6b58e..e2c549d04 100644 --- a/mrbgems/mruby-range-ext/test/range.rb +++ b/mrbgems/mruby-range-ext/test/range.rb @@ -10,6 +10,8 @@ end assert('Range#first') do assert_equal 10, (10..20).first assert_equal [10, 11, 12], (10..20).first(3) + + skip unless Object.const_defined?(:Float) assert_equal [0, 1, 2], (0..Float::INFINITY).first(3) end @@ -23,12 +25,14 @@ end assert('Range#size') do assert_equal 42, (1..42).size assert_equal 41, (1...42).size + assert_nil ('a'..'z').size + + skip unless Object.const_defined?(:Float) assert_equal 6, (1...6.3).size assert_equal 5, (1...6.0).size assert_equal 5, (1.1...6).size assert_equal 15, (1.0..15.9).size assert_equal Float::INFINITY, (0..Float::INFINITY).size - assert_nil ('a'..'z').size end assert('Range#max') do @@ -37,12 +41,6 @@ assert('Range#max') do assert_equal 9, (1...10).max assert_equal 4294967295, (0...2**32).max - # returns the maximum value in the Float range when called with no arguments - assert_equal 908.1111, (303.20..908.1111).max - - # raises TypeError when called on an exclusive range and a non Integer value - assert_raise(TypeError) { (303.20...908.1111).max } - # returns nil when the endpoint is less than the start point assert_equal nil, (100..10).max @@ -52,6 +50,14 @@ assert('Range#max') do # returns the endpoint when the endpoint equals the start point and the range is inclusive assert_equal 5, (5..5).max + skip unless Object.const_defined?(:Float) + + # returns the maximum value in the Float range when called with no arguments + assert_equal 908.1111, (303.20..908.1111).max + + # raises TypeError when called on an exclusive range and a non Integer value + assert_raise(TypeError) { (303.20...908.1111).max } + # returns nil when the endpoint is less than the start point in a Float range assert_equal nil, (3003.20..908.1111).max end @@ -89,9 +95,6 @@ assert('Range#min') do assert_equal 1, (1..10).min assert_equal 1, (1...10).min - # returns the minimum value in the Float range when called with no arguments - assert_equal 303.20, (303.20..908.1111).min - # returns nil when the start point is greater than the endpoint assert_equal nil, (100..10).min @@ -101,6 +104,11 @@ assert('Range#min') do # returns the endpoint when the endpoint equals the start point and the range is inclusive assert_equal 5, (5..5).max + skip unless Object.const_defined?(:Float) + + # returns the minimum value in the Float range when called with no arguments + assert_equal 303.20, (303.20..908.1111).min + # returns nil when the start point is greater than the endpoint in a Float range assert_equal nil, (3003.20..908.1111).max end -- cgit v1.2.3 From 1b7516a4ae144bfdc36356294e93b8af9c4a0a3f Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Wed, 17 Jul 2019 19:16:44 +0900 Subject: Fix `(fixnum_value ... float_value).min` with `mruby-range-ext` Before this patch: $ bin/mruby -e 'p (2...4.0).min' #=> TypeError After this patch (same as CRuby and without `mruby-range-ext`): $ bin/mruby -e 'p (2...4.0).min' #=> 2 --- mrbgems/mruby-range-ext/mrblib/range.rb | 1 - 1 file changed, 1 deletion(-) diff --git a/mrbgems/mruby-range-ext/mrblib/range.rb b/mrbgems/mruby-range-ext/mrblib/range.rb index a149a57dc..da2fff67a 100644 --- a/mrbgems/mruby-range-ext/mrblib/range.rb +++ b/mrbgems/mruby-range-ext/mrblib/range.rb @@ -53,7 +53,6 @@ class Range # fast path for numerics if (val.kind_of?(Fixnum) || val.kind_of?(Float)) && (last.kind_of?(Fixnum) || last.kind_of?(Float)) - raise TypeError if exclude_end? && !last.kind_of?(Fixnum) return nil if val > last return nil if val == last && exclude_end? -- cgit v1.2.3 From e38ba3d58c4fc5edd9e04f0f32dfd1afe0e85a64 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Wed, 17 Jul 2019 19:49:58 +0900 Subject: Revert #4300 Originally, it was not necessary to change. I made mistake. --- mrbgems/mruby-compiler/core/parse.y | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mrbgems/mruby-compiler/core/parse.y b/mrbgems/mruby-compiler/core/parse.y index ac59a8b0b..b7a7d315d 100644 --- a/mrbgems/mruby-compiler/core/parse.y +++ b/mrbgems/mruby-compiler/core/parse.y @@ -5419,7 +5419,7 @@ parser_yylex(parser_state *p) tokfix(p); if (is_float) { #ifdef MRB_WITHOUT_FLOAT - yywarning(p, "floating point numbers are not supported"); + yywarning_s(p, "floating point numbers are not supported", tok(p)); pylval.nd = new_int(p, "0", 10, 0); return tINTEGER; #else -- cgit v1.2.3 From 9d2272ec2ca00e8951a61e2e1f287de04ee7f1c6 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Wed, 17 Jul 2019 20:09:37 +0900 Subject: Fix `String#[]` test --- test/t/string.rb | 47 +++++++++++++++-------------------------------- 1 file changed, 15 insertions(+), 32 deletions(-) diff --git a/test/t/string.rb b/test/t/string.rb index cf145f97e..af944b359 100644 --- a/test/t/string.rb +++ b/test/t/string.rb @@ -45,44 +45,27 @@ assert('String#*', '15.2.10.5.5') do assert_raise(TypeError) { 'a' * '1' } assert_raise(TypeError) { 'a' * nil } end + assert('String#[]', '15.2.10.5.6') do # length of args is 1 - a = 'abc'[0] - b = 'abc'[-1] - c = 'abc'[10] - d = 'abc'[-10] - e = 'abc'[1.1] + assert_equal 'a', 'abc'[0] + assert_equal 'c', 'abc'[-1] + assert_nil 'abc'[10] + assert_nil 'abc'[-10] + assert_equal 'b', 'abc'[1.1] if Object.const_defined?(:Float) # length of args is 2 - a1 = 'abc'[0, -1] - b1 = 'abc'[10, 0] - c1 = 'abc'[-10, 0] - d1 = 'abc'[0, 0] - e1 = 'abc'[1, 2] - - # args is RegExp - # It will be tested in mrbgems. + assert_nil 'abc'[0, -1] + assert_nil 'abc'[10, 0] + assert_nil 'abc'[-10, 0] + assert_equal '', 'abc'[0, 0] + assert_equal 'bc', 'abc'[1, 2] # args is String - a3 = 'abc'['bc'] - b3 = 'abc'['XX'] - - assert_equal 'a', 'a' - # assert_equal 'c', b - # assert_nil c - # assert_nil d - # assert_equal 'b', e - # assert_nil a1 - # assert_nil b1 - # assert_nil c1 - # assert_equal '', d1 - # assert_equal 'bc', e1 - # assert_equal 'bc', a3 - # assert_nil b3 - - # assert_raise(TypeError) do - # a[nil] - # end + assert_equal 'bc', 'abc'['bc'] + assert_nil 'abc'['XX'] + + assert_raise(TypeError) { 'abc'[nil] } end assert('String#[](UTF-8)', '15.2.10.5.6') do -- cgit v1.2.3 From 2a410c0e1b33083402c02d8d8ae3fc99082ec8c3 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Thu, 18 Jul 2019 00:34:08 +0900 Subject: Avoid making top-level `env` in initialization code; ref #4581 --- mrbgems/mruby-complex/mrblib/complex.rb | 22 ++++++++--------- mrbgems/mruby-rational/mrblib/rational.rb | 41 ++++++++++++++++--------------- 2 files changed, 32 insertions(+), 31 deletions(-) diff --git a/mrbgems/mruby-complex/mrblib/complex.rb b/mrbgems/mruby-complex/mrblib/complex.rb index 0299e7675..1a6f7e92e 100644 --- a/mrbgems/mruby-complex/mrblib/complex.rb +++ b/mrbgems/mruby-complex/mrblib/complex.rb @@ -104,18 +104,18 @@ class Complex < Numeric end alias_method :imag, :imaginary -end -[Fixnum, Float].each do |cls| - [:+, :-, :*, :/, :==].each do |op| - cls.instance_exec do - original_operator_name = "__original_operator_#{op}_complex" - alias_method original_operator_name, op - define_method op do |rhs| - if rhs.is_a? Complex - Complex(self).send(op, rhs) - else - send(original_operator_name, rhs) + [Fixnum, Float].each do |cls| + [:+, :-, :*, :/, :==].each do |op| + cls.instance_exec do + original_operator_name = "__original_operator_#{op}_complex" + alias_method original_operator_name, op + define_method op do |rhs| + if rhs.is_a? Complex + Complex(self).send(op, rhs) + else + send(original_operator_name, rhs) + end end end end diff --git a/mrbgems/mruby-rational/mrblib/rational.rb b/mrbgems/mruby-rational/mrblib/rational.rb index 93af72b96..c0b16a6ae 100644 --- a/mrbgems/mruby-rational/mrblib/rational.rb +++ b/mrbgems/mruby-rational/mrblib/rational.rb @@ -89,28 +89,29 @@ module Kernel a, b = b, a % b until b == 0 Rational._new(numerator.div(a), denominator.div(a)) end -end -[:+, :-, :*, :/, :<=>, :==, :<, :<=, :>, :>=].each do |op| - Fixnum.instance_eval do - original_operator_name = "__original_operator_#{op}_rational" - alias_method original_operator_name, op - define_method op do |rhs| - if rhs.is_a? Rational - Rational(self).__send__(op, rhs) - else - __send__(original_operator_name, rhs) + [:+, :-, :*, :/, :<=>, :==, :<, :<=, :>, :>=].each do |op| + Fixnum.instance_eval do + original_operator_name = "__original_operator_#{op}_rational" + alias_method original_operator_name, op + define_method op do |rhs| + if rhs.is_a? Rational + Rational(self).__send__(op, rhs) + else + __send__(original_operator_name, rhs) + end end end - end - Float.instance_eval do - original_operator_name = "__original_operator_#{op}_rational" - alias_method original_operator_name, op - define_method op do |rhs| - if rhs.is_a? Rational - rhs = rhs.to_f + Float.instance_eval do + original_operator_name = "__original_operator_#{op}_rational" + alias_method original_operator_name, op + define_method op do |rhs| + if rhs.is_a? Rational + rhs = rhs.to_f + end + __send__(original_operator_name, rhs) end - __send__(original_operator_name, rhs) - end - end if Object.const_defined?(:Float) + end if Object.const_defined?(:Float) + end end + -- cgit v1.2.3 From 94a1f488a6b7209dc4b70a04df30ad69ebdc00de Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Thu, 18 Jul 2019 00:35:21 +0900 Subject: Clear `env` before top-level execution; fix #4581 --- src/vm.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/vm.c b/src/vm.c index 0a6d4af8d..86262650e 100644 --- a/src/vm.c +++ b/src/vm.c @@ -2834,6 +2834,7 @@ mrb_top_run(mrb_state *mrb, struct RProc *proc, mrb_value self, unsigned int sta return mrb_vm_run(mrb, proc, self, stack_keep); } if (mrb->c->ci == mrb->c->cibase) { + mrb->c->ci->env = NULL; return mrb_vm_run(mrb, proc, self, stack_keep); } ci = cipush(mrb); -- cgit v1.2.3 From 9873d5e0b9f1d3be9b2c97a21789ccdbd500e039 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Thu, 18 Jul 2019 17:51:02 +0900 Subject: Fix `String#*` test with `MRB_WITHOUT_FLOAT` --- test/t/string.rb | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/test/t/string.rb b/test/t/string.rb index af944b359..46cbe6e2a 100644 --- a/test/t/string.rb +++ b/test/t/string.rb @@ -37,13 +37,15 @@ end assert('String#*', '15.2.10.5.5') do assert_equal 'aaaaa', 'a' * 5 assert_equal '', 'a' * 0 - assert_equal 'aa', 'a' * 2.1 assert_raise(ArgumentError) { 'a' * -1 } + assert_raise(TypeError) { 'a' * '1' } + assert_raise(TypeError) { 'a' * nil } + + skip unless Object.const_defined?(:Float) + assert_equal 'aa', 'a' * 2.1 assert_raise(RangeError) { '' * 1e30 } assert_raise(RangeError) { '' * Float::INFINITY } assert_raise(RangeError) { '' * Float::NAN } - assert_raise(TypeError) { 'a' * '1' } - assert_raise(TypeError) { 'a' * nil } end assert('String#[]', '15.2.10.5.6') do -- cgit v1.2.3 From 8ab846b5b92dcbe7c9ad927af99e6f06143b18af Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Fri, 19 Jul 2019 21:34:25 +0900 Subject: Refine `String#chr` test and separate `Fixnum#chr` test --- mrbgems/mruby-string-ext/test/fixnum.rb | 3 +++ mrbgems/mruby-string-ext/test/string.rb | 9 +++------ 2 files changed, 6 insertions(+), 6 deletions(-) create mode 100644 mrbgems/mruby-string-ext/test/fixnum.rb diff --git a/mrbgems/mruby-string-ext/test/fixnum.rb b/mrbgems/mruby-string-ext/test/fixnum.rb new file mode 100644 index 000000000..9036b1a06 --- /dev/null +++ b/mrbgems/mruby-string-ext/test/fixnum.rb @@ -0,0 +1,3 @@ +assert('Fixnum#chr') do + assert_equal "a", 97.chr +end diff --git a/mrbgems/mruby-string-ext/test/string.rb b/mrbgems/mruby-string-ext/test/string.rb index 9a324c46d..2eb35f840 100644 --- a/mrbgems/mruby-string-ext/test/string.rb +++ b/mrbgems/mruby-string-ext/test/string.rb @@ -298,12 +298,6 @@ assert('String#oct') do assert_equal (-8), "-10".oct end -assert('String#chr') do - assert_equal "a", "abcde".chr - # test Fixnum#chr as well - assert_equal "a", 97.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 @@ -681,8 +675,11 @@ assert('String#ord(UTF-8)') do end if UTF8STRING assert('String#chr') do + assert_equal "a", "abcde".chr assert_equal "h", "hello!".chr + assert_equal "", "".chr end + assert('String#chr(UTF-8)') do assert_equal "こ", "こんにちは世界!".chr end if UTF8STRING -- cgit v1.2.3 From 7675fcb5d3e8e19964b46df7c1547e27f4a2bbde Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Sat, 20 Jul 2019 22:39:48 +0900 Subject: Fix `Module#dup` to frozen module Before this patch: $ bin/mruby -e 'p Module.new.freeze.dup.frozen?' #=> true After this patch (same as Ruby): $ bin/mruby -e 'p Module.new.freeze.dup.frozen?' #=> false --- src/class.c | 9 +++++++++ src/kernel.c | 1 - test/t/module.rb | 23 +++++++++++++++++++++++ 3 files changed, 32 insertions(+), 1 deletion(-) diff --git a/src/class.c b/src/class.c index 2961284f5..65d21ad4f 100644 --- a/src/class.c +++ b/src/class.c @@ -2077,6 +2077,14 @@ mrb_mod_eqq(mrb_state *mrb, mrb_value mod) return mrb_bool_value(eqq); } +static mrb_value +mrb_mod_dup(mrb_state *mrb, mrb_value self) +{ + mrb_value mod = mrb_obj_clone(mrb, self); + MRB_UNSET_FROZEN_FLAG(mrb_obj_ptr(mod)); + return mod; +} + static mrb_value mrb_mod_module_function(mrb_state *mrb, mrb_value mod) { @@ -2207,6 +2215,7 @@ mrb_init_class(mrb_state *mrb) mrb_define_method(mrb, mod, "method_defined?", mrb_mod_method_defined, MRB_ARGS_REQ(1)); /* 15.2.2.4.34 */ mrb_define_method(mrb, mod, "define_method", mod_define_method, MRB_ARGS_ARG(1,1)); mrb_define_method(mrb, mod, "===", mrb_mod_eqq, MRB_ARGS_REQ(1)); /* 15.2.2.4.7 */ + mrb_define_method(mrb, mod, "dup", mrb_mod_dup, MRB_ARGS_NONE()); mrb_undef_method(mrb, cls, "append_features"); mrb_undef_method(mrb, cls, "extend_object"); diff --git a/src/kernel.c b/src/kernel.c index a3c2d2ec6..f223be9fc 100644 --- a/src/kernel.c +++ b/src/kernel.c @@ -805,5 +805,4 @@ mrb_init_kernel(mrb_state *mrb) mrb_define_method(mrb, krn, "__to_str", mrb_to_str, MRB_ARGS_NONE()); /* internal */ mrb_include_module(mrb, mrb->object_class, mrb->kernel_module); - mrb_define_alias(mrb, mrb->module_class, "dup", "clone"); /* XXX */ } diff --git a/test/t/module.rb b/test/t/module.rb index 7f869bf1f..0155ec190 100644 --- a/test/t/module.rb +++ b/test/t/module.rb @@ -400,6 +400,29 @@ end # Not ISO specified +assert('Module#dup') do + module TestModuleDup + @@cvar = :cvar + class << self + attr_accessor :cattr + def cmeth; :cmeth end + end + def cvar; @@cvar end + def imeth; :imeth end + self.cattr = :cattr + end + + m = TestModuleDup.dup + o = Object.include(m).new + assert_equal(:cattr, m.cattr) + assert_equal(:cmeth, m.cmeth) + assert_equal(:cvar, o.cvar) + assert_equal(:imeth, o.imeth) + assert_match("#", m.to_s) + assert_not_predicate(m, :frozen?) + assert_not_predicate(TestModuleDup.freeze.dup, :frozen?) +end + assert('Module#define_method') do c = Class.new { define_method(:m1) { :ok } -- cgit v1.2.3 From c980fe279266448cf5ac8faa646d57d0f8561b10 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Sun, 21 Jul 2019 22:59:41 +0900 Subject: Integrate `Integral#chr` (`Fixnum#chr`) to `mruby-string-ext` Because they're defined in both `mruby-string-ext` and `mruby-numeric-ext` (they seem more natural to define in N, but `mruby-string-ext` depends on `Integral#chr`). --- mrbgems/mruby-numeric-ext/src/numeric_ext.c | 27 --------------------------- mrbgems/mruby-numeric-ext/test/numeric.rb | 8 -------- mrbgems/mruby-string-ext/src/string.c | 8 ++++---- mrbgems/mruby-string-ext/test/fixnum.rb | 3 --- mrbgems/mruby-string-ext/test/numeric.rb | 5 +++++ 5 files changed, 9 insertions(+), 42 deletions(-) delete mode 100644 mrbgems/mruby-string-ext/test/fixnum.rb create mode 100644 mrbgems/mruby-string-ext/test/numeric.rb diff --git a/mrbgems/mruby-numeric-ext/src/numeric_ext.c b/mrbgems/mruby-numeric-ext/src/numeric_ext.c index cd8bbf187..86c384a87 100644 --- a/mrbgems/mruby-numeric-ext/src/numeric_ext.c +++ b/mrbgems/mruby-numeric-ext/src/numeric_ext.c @@ -8,32 +8,6 @@ to_int(mrb_state *mrb, mrb_value x) return mrb_fixnum(x); } -/* - * Document-method: Integer#chr - * call-seq: - * int.chr -> string - * - * Returns a string containing the character represented by the +int+'s value - * according to +encoding+. - * - * 65.chr #=> "A" - * 230.chr #=> "\xE6" - */ -static mrb_value -mrb_int_chr(mrb_state *mrb, mrb_value x) -{ - mrb_int chr; - char c; - - chr = to_int(mrb, x); - if (chr >= (1 << CHAR_BIT)) { - mrb_raisef(mrb, E_RANGE_ERROR, "%S out of char range", x); - } - c = (char)chr; - - return mrb_str_new(mrb, &c, 1); -} - /* * call-seq: * int.allbits?(mask) -> true or false @@ -87,7 +61,6 @@ mrb_mruby_numeric_ext_gem_init(mrb_state* mrb) { struct RClass *i = mrb_module_get(mrb, "Integral"); - mrb_define_method(mrb, i, "chr", mrb_int_chr, MRB_ARGS_NONE()); mrb_define_method(mrb, i, "allbits?", mrb_int_allbits, MRB_ARGS_REQ(1)); mrb_define_method(mrb, i, "anybits?", mrb_int_anybits, MRB_ARGS_REQ(1)); mrb_define_method(mrb, i, "nobits?", mrb_int_nobits, MRB_ARGS_REQ(1)); diff --git a/mrbgems/mruby-numeric-ext/test/numeric.rb b/mrbgems/mruby-numeric-ext/test/numeric.rb index c85cb61f2..efdf25a34 100644 --- a/mrbgems/mruby-numeric-ext/test/numeric.rb +++ b/mrbgems/mruby-numeric-ext/test/numeric.rb @@ -1,14 +1,6 @@ ## # Numeric(Ext) Test -assert('Integer#chr') do - assert_equal("A", 65.chr) - assert_equal("B", 0x42.chr) - - # multibyte encoding (not support yet) - assert_raise(RangeError) { 256.chr } -end - assert('Integer#div') do assert_equal 52, 365.div(7) end diff --git a/mrbgems/mruby-string-ext/src/string.c b/mrbgems/mruby-string-ext/src/string.c index 50a4e5582..ab9919650 100644 --- a/mrbgems/mruby-string-ext/src/string.c +++ b/mrbgems/mruby-string-ext/src/string.c @@ -125,7 +125,7 @@ mrb_str_swapcase(mrb_state *mrb, mrb_value self) return str; } -static mrb_value mrb_fixnum_chr(mrb_state *mrb, mrb_value num); +static mrb_value mrb_int_chr(mrb_state *mrb, mrb_value num); /* * call-seq: @@ -149,7 +149,7 @@ mrb_str_concat_m(mrb_state *mrb, mrb_value self) mrb_get_args(mrb, "o", &str); if (mrb_fixnum_p(str)) - str = mrb_fixnum_chr(mrb, str); + str = mrb_int_chr(mrb, str); else str = mrb_ensure_string_type(mrb, str); mrb_str_concat(mrb, self, str); @@ -837,7 +837,7 @@ mrb_str_chr(mrb_state *mrb, mrb_value self) } static mrb_value -mrb_fixnum_chr(mrb_state *mrb, mrb_value num) +mrb_int_chr(mrb_state *mrb, mrb_value num) { mrb_int cp = mrb_fixnum(num); #ifdef MRB_UTF8_STRING @@ -1219,7 +1219,7 @@ mrb_mruby_string_ext_gem_init(mrb_state* mrb) mrb_define_method(mrb, s, "delete_suffix", mrb_str_del_suffix, MRB_ARGS_REQ(1)); mrb_define_method(mrb, s, "__lines", mrb_str_lines, MRB_ARGS_NONE()); - mrb_define_method(mrb, mrb->fixnum_class, "chr", mrb_fixnum_chr, MRB_ARGS_NONE()); + mrb_define_method(mrb, mrb_module_get(mrb, "Integral"), "chr", mrb_int_chr, MRB_ARGS_NONE()); } void diff --git a/mrbgems/mruby-string-ext/test/fixnum.rb b/mrbgems/mruby-string-ext/test/fixnum.rb deleted file mode 100644 index 9036b1a06..000000000 --- a/mrbgems/mruby-string-ext/test/fixnum.rb +++ /dev/null @@ -1,3 +0,0 @@ -assert('Fixnum#chr') do - assert_equal "a", 97.chr -end diff --git a/mrbgems/mruby-string-ext/test/numeric.rb b/mrbgems/mruby-string-ext/test/numeric.rb new file mode 100644 index 000000000..cae562fc1 --- /dev/null +++ b/mrbgems/mruby-string-ext/test/numeric.rb @@ -0,0 +1,5 @@ +assert('Integer#chr') do + assert_equal("A", 65.chr) + assert_equal("B", 0x42.chr) + assert_raise(RangeError) { -1.chr } +end -- cgit v1.2.3 From 6f67fddb87bc1bb098431fa23cbf39f5fedea43e Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Sat, 20 Jul 2019 02:56:17 +0900 Subject: Fix `FIXABLE_FLOAT()` on `MRB_INT64`; ref #4566 Normal `TYPED_FIXABLE(f,mrb_float)` does not work on 64bit int from casting problems. The new approach works well, but assumes two's complement and IEEE-754 floating point numbers. --- include/mruby/numeric.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/include/mruby/numeric.h b/include/mruby/numeric.h index 34707e441..07266aa10 100644 --- a/include/mruby/numeric.h +++ b/include/mruby/numeric.h @@ -23,8 +23,12 @@ MRB_BEGIN_DECL #define NEGFIXABLE(f) TYPED_NEGFIXABLE(f,mrb_int) #define FIXABLE(f) TYPED_FIXABLE(f,mrb_int) #ifndef MRB_WITHOUT_FLOAT +#ifdef MRB_INT64 +#define FIXABLE_FLOAT(f) ((f)>=-9223372036854775808.0 && (f)<9223372036854775808.0) +#else #define FIXABLE_FLOAT(f) TYPED_FIXABLE(f,mrb_float) #endif +#endif #ifndef MRB_WITHOUT_FLOAT MRB_API mrb_value mrb_flo_to_fixnum(mrb_state *mrb, mrb_value val); -- cgit v1.2.3 From 277be410f31efc1dfa6e2d4bcc56b9c21b300bc6 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Sat, 20 Jul 2019 02:57:36 +0900 Subject: No rounding needed if 'ndigits` is bigger than `DBL_DIG+2`; fix #4566 --- src/numeric.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/numeric.c b/src/numeric.c index 4288df44a..a1299a74f 100644 --- a/src/numeric.c +++ b/src/numeric.c @@ -702,6 +702,7 @@ flo_round(mrb_state *mrb, mrb_value num) f = 1.0; i = ndigits >= 0 ? ndigits : -ndigits; + if (ndigits > DBL_DIG+2) return num; while (--i >= 0) f = f*10.0; -- cgit v1.2.3 From f99e9963b2145812b6f2bd7f0dd3d8228c503c82 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Mon, 22 Jul 2019 15:49:59 +0900 Subject: Switch random generator from Mersenne Twister to Xorshit128. Now `rand` can be used with `MRB_WITHOUT_FLOAT`; ref #4576 --- mrbgems/mruby-random/src/mt19937ar.c | 224 ---------------------------------- mrbgems/mruby-random/src/mt19937ar.h | 80 ------------- mrbgems/mruby-random/src/random.c | 226 +++++++++++++++++------------------ 3 files changed, 108 insertions(+), 422 deletions(-) delete mode 100644 mrbgems/mruby-random/src/mt19937ar.c delete mode 100644 mrbgems/mruby-random/src/mt19937ar.h diff --git a/mrbgems/mruby-random/src/mt19937ar.c b/mrbgems/mruby-random/src/mt19937ar.c deleted file mode 100644 index 405bd5c20..000000000 --- a/mrbgems/mruby-random/src/mt19937ar.c +++ /dev/null @@ -1,224 +0,0 @@ -/* -** mt19937ar.c - MT Random functions -** -** Copyright (C) 1997 - 2016, Makoto Matsumoto and Takuji Nishimura, -** All rights reserved. -** -** Permission is hereby granted, free of charge, to any person obtaining -** a copy of this software and associated documentation files (the -** "Software"), to deal in the Software without restriction, including -** without limitation the rights to use, copy, modify, merge, publish, -** distribute, sublicense, and/or sell copies of the Software, and to -** permit persons to whom the Software is furnished to do so, subject to -** the following conditions: -** -** The above copyright notice and this permission notice shall be -** included in all copies or substantial portions of the Software. -** -** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. -** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY -** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, -** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE -** SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -** -** [ MIT license: http://www.opensource.org/licenses/mit-license.php ] -** -** Any feedback is very welcome. -** http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/emt.html -** email: m-mat @ math.sci.hiroshima-u.ac.jp (remove space) -** -** This version is modified by mruby developers. If you see any problem, -** contact us first at https://github.com/mruby/mruby/issues -*/ - -#include -#include "mt19937ar.h" - -/* Period parameters */ -/* #define N 624 */ -#define M 397 -#define MATRIX_A 0x9908b0dfUL /* constant vector a */ -#define UPPER_MASK 0x80000000UL /* most significant w-r bits */ -#define LOWER_MASK 0x7fffffffUL /* least significant r bits */ - -#if 0 /* dead_code */ -static unsigned long mt[N]; /* the array for the state vector */ -static int mti=N+1; /* mti==N+1 means mt[N] is not initialized */ -#endif /* dead_code */ - -void mrb_random_init_genrand(mt_state *t, unsigned long s) -{ - t->mt[0]= s & 0xffffffffUL; - for (t->mti=1; t->mtimti++) { - t->mt[t->mti] = (1812433253UL * (t->mt[t->mti-1] ^ (t->mt[t->mti-1] >> 30)) + t->mti); - t->mt[t->mti] &= 0xffffffffUL; - } -} - -unsigned long mrb_random_genrand_int32(mt_state *t) -{ - unsigned long y; - static const unsigned long mag01[2]={0x0UL, MATRIX_A}; - /* mag01[x] = x * MATRIX_A for x=0,1 */ - - if (t->mti >= N) { /* generate N words at one time */ - int kk; - - if (t->mti == N+1) /* if init_genrand() has not been called, */ - mrb_random_init_genrand(t, 5489UL); /* a default initial seed is used */ - - for (kk=0;kkmt[kk]&UPPER_MASK)|(t->mt[kk+1]&LOWER_MASK); - t->mt[kk] = t->mt[kk+M] ^ (y >> 1) ^ mag01[y & 0x1UL]; - } - for (;kkmt[kk]&UPPER_MASK)|(t->mt[kk+1]&LOWER_MASK); - t->mt[kk] = t->mt[kk+(M-N)] ^ (y >> 1) ^ mag01[y & 0x1UL]; - } - y = (t->mt[N-1]&UPPER_MASK)|(t->mt[0]&LOWER_MASK); - t->mt[N-1] = t->mt[M-1] ^ (y >> 1) ^ mag01[y & 0x1UL]; - - t->mti = 0; - } - - y = t->mt[t->mti++]; - - /* Tempering */ - y ^= (y >> 11); - y ^= (y << 7) & 0x9d2c5680UL; - y ^= (y << 15) & 0xefc60000UL; - y ^= (y >> 18); - - t->gen.int_ = y; - - return y; -} - -double mrb_random_genrand_real1(mt_state *t) -{ - mrb_random_genrand_int32(t); - t->gen.double_ = t->gen.int_*(1.0/4294967295.0); - return t->gen.double_; - /* divided by 2^32-1 */ -} - -#if 0 /* dead_code */ -/* initializes mt[N] with a seed */ -void init_genrand(unsigned long s) -{ - mt[0]= s & 0xffffffffUL; - for (mti=1; mti> 30)) + mti); - /* See Knuth TAOCP Vol2. 3rd Ed. P.106 for multiplier. */ - /* In the previous versions, MSBs of the seed affect */ - /* only MSBs of the array mt[]. */ - /* 2002/01/09 modified by Makoto Matsumoto */ - mt[mti] &= 0xffffffffUL; - /* for >32 bit machines */ - } -} - -/* initialize by an array with array-length */ -/* init_key is the array for initializing keys */ -/* key_length is its length */ -/* slight change for C++, 2004/2/26 */ -void init_by_array(unsigned long init_key[], int key_length) -{ - int i, j, k; - init_genrand(19650218UL); - i=1; j=0; - k = (N>key_length ? N : key_length); - for (; k; k--) { - mt[i] = (mt[i] ^ ((mt[i-1] ^ (mt[i-1] >> 30)) * 1664525UL)) - + init_key[j] + j; /* non linear */ - mt[i] &= 0xffffffffUL; /* for WORDSIZE > 32 machines */ - i++; j++; - if (i>=N) { mt[0] = mt[N-1]; i=1; } - if (j>=key_length) j=0; - } - for (k=N-1; k; k--) { - mt[i] = (mt[i] ^ ((mt[i-1] ^ (mt[i-1] >> 30)) * 1566083941UL)) - - i; /* non linear */ - mt[i] &= 0xffffffffUL; /* for WORDSIZE > 32 machines */ - i++; - if (i>=N) { mt[0] = mt[N-1]; i=1; } - } - - mt[0] = 0x80000000UL; /* MSB is 1; assuring non-zero initial array */ -} - -/* generates a random number on [0,0xffffffff]-interval */ -unsigned long genrand_int32(void) -{ - unsigned long y; - static const unsigned long mag01[2]={0x0UL, MATRIX_A}; - /* mag01[x] = x * MATRIX_A for x=0,1 */ - - if (mti >= N) { /* generate N words at one time */ - int kk; - - if (mti == N+1) /* if init_genrand() has not been called, */ - init_genrand(5489UL); /* a default initial seed is used */ - - for (kk=0;kk> 1) ^ mag01[y & 0x1UL]; - } - for (;kk> 1) ^ mag01[y & 0x1UL]; - } - y = (mt[N-1]&UPPER_MASK)|(mt[0]&LOWER_MASK); - mt[N-1] = mt[M-1] ^ (y >> 1) ^ mag01[y & 0x1UL]; - - mti = 0; - } - - y = mt[mti++]; - - /* Tempering */ - y ^= (y >> 11); - y ^= (y << 7) & 0x9d2c5680UL; - y ^= (y << 15) & 0xefc60000UL; - y ^= (y >> 18); - - return y; -} - -/* generates a random number on [0,0x7fffffff]-interval */ -long genrand_int31(void) -{ - return (long)(genrand_int32()>>1); -} - -/* generates a random number on [0,1]-real-interval */ -double genrand_real1(void) -{ - return genrand_int32()*(1.0/4294967295.0); - /* divided by 2^32-1 */ -} - -/* generates a random number on [0,1)-real-interval */ -double genrand_real2(void) -{ - return genrand_int32()*(1.0/4294967296.0); - /* divided by 2^32 */ -} - -/* generates a random number on (0,1)-real-interval */ -double genrand_real3(void) -{ - return (((double)genrand_int32()) + 0.5)*(1.0/4294967296.0); - /* divided by 2^32 */ -} - -/* generates a random number on [0,1) with 53-bit resolution*/ -double genrand_res53(void) -{ - unsigned long a=genrand_int32()>>5, b=genrand_int32()>>6; - return(a*67108864.0+b)*(1.0/9007199254740992.0); -} -/* These real versions are due to Isaku Wada, 2002/01/09 added */ -#endif /* dead_code */ diff --git a/mrbgems/mruby-random/src/mt19937ar.h b/mrbgems/mruby-random/src/mt19937ar.h deleted file mode 100644 index 7d382320d..000000000 --- a/mrbgems/mruby-random/src/mt19937ar.h +++ /dev/null @@ -1,80 +0,0 @@ -/* -** mt19937ar.h - MT Random functions -** -** Copyright (C) 1997 - 2016, Makoto Matsumoto and Takuji Nishimura, -** All rights reserved. -** -** Permission is hereby granted, free of charge, to any person obtaining -** a copy of this software and associated documentation files (the -** "Software"), to deal in the Software without restriction, including -** without limitation the rights to use, copy, modify, merge, publish, -** distribute, sublicense, and/or sell copies of the Software, and to -** permit persons to whom the Software is furnished to do so, subject to -** the following conditions: -** -** The above copyright notice and this permission notice shall be -** included in all copies or substantial portions of the Software. -** -** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. -** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY -** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, -** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE -** SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -** -** [ MIT license: http://www.opensource.org/licenses/mit-license.php ] -** -** Any feedback is very welcome. -** http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/emt.html -** email: m-mat @ math.sci.hiroshima-u.ac.jp (remove space) -** -** This version is modified by mruby developers. If you see any problem, -** contact us first at https://github.com/mruby/mruby/issues -*/ - -#define N 624 - -typedef struct { - unsigned long mt[N]; - int mti; - union { - unsigned long int_; - double double_; - } gen; - - mrb_int seed; - mrb_bool has_seed : 1; -} mt_state; - -void mrb_random_init_genrand(mt_state *, unsigned long); -unsigned long mrb_random_genrand_int32(mt_state *); -double mrb_random_genrand_real1(mt_state *t); - -/* initializes mt[N] with a seed */ -void init_genrand(unsigned long s); - -/* initialize by an array with array-length */ -/* init_key is the array for initializing keys */ -/* key_length is its length */ -/* slight change for C++, 2004/2/26 */ -void init_by_array(unsigned long init_key[], int key_length); - -/* generates a random number on [0,0xffffffff]-interval */ -unsigned long genrand_int32(void); - -/* generates a random number on [0,0x7fffffff]-interval */ -long genrand_int31(void); - -/* These real versions are due to Isaku Wada, 2002/01/09 added */ -/* generates a random number on [0,1]-real-interval */ -double genrand_real1(void); - -/* generates a random number on [0,1)-real-interval */ -double genrand_real2(void); - -/* generates a random number on (0,1)-real-interval */ -double genrand_real3(void); - -/* generates a random number on [0,1) with 53-bit resolution*/ -double genrand_res53(void); diff --git a/mrbgems/mruby-random/src/random.c b/mrbgems/mruby-random/src/random.c index 99f2b02e4..bca565b17 100644 --- a/mrbgems/mruby-random/src/random.c +++ b/mrbgems/mruby-random/src/random.c @@ -4,71 +4,86 @@ ** See Copyright Notice in mruby.h */ -#ifdef MRB_WITHOUT_FLOAT -# error Conflict 'MRB_WITHOUT_FLOAT' configuration in your 'build_config.rb' -#endif - #include #include #include #include #include -#include "mt19937ar.h" #include -static char const MT_STATE_KEY[] = "$mrb_i_mt_state"; +static char const RAND_STATE_KEY[] = "$mrb_i_rand_state"; -static const struct mrb_data_type mt_state_type = { - MT_STATE_KEY, mrb_free, +static const struct mrb_data_type rand_state_type = { + RAND_STATE_KEY, mrb_free, }; -static mrb_value mrb_random_rand(mrb_state *mrb, mrb_value self); -static mrb_value mrb_random_srand(mrb_state *mrb, mrb_value self); +typedef struct rand_state { + uint32_t seed[4]; +} rand_state; static void -mt_srand(mt_state *t, unsigned long seed) +rand_init(rand_state *t) { - mrb_random_init_genrand(t, seed); + t->seed[0] = 123456789; + t->seed[1] = 362436069; + t->seed[2] = 521288629; + t->seed[3] = 88675123; } -static unsigned long -mt_rand(mt_state *t) +static uint32_t +rand_seed(rand_state *t, uint32_t seed) { - return mrb_random_genrand_int32(t); + uint32_t old_seed = t->seed[3]; + rand_init(t); + t->seed[3] = seed; + return old_seed; } -static double -mt_rand_real(mt_state *t) +static uint32_t +rand_uint32(rand_state *state) { - return mrb_random_genrand_real1(t); + uint32_t *seed = state->seed; + uint32_t x = seed[0]; + uint32_t y = seed[1]; + uint32_t z = seed[2]; + uint32_t w = seed[3]; + uint32_t t; + + t = x ^ (x << 11); + x = y; y = z; z = w; + w = (w ^ (w >> 19)) ^ (t ^ (t >> 8)); + seed[0] = x; + seed[1] = y; + seed[2] = z; + seed[3] = w; + + return w; } -static mrb_value -mrb_random_mt_srand(mrb_state *mrb, mt_state *t, mrb_value seed) +#ifndef MRB_WITHOUT_FLOAT +static double +rand_real(rand_state *t) { - if (mrb_nil_p(seed)) { - seed = mrb_fixnum_value((mrb_int)(time(NULL) + mt_rand(t))); - if (mrb_fixnum(seed) < 0) { - seed = mrb_fixnum_value(0 - mrb_fixnum(seed)); - } - } - - mt_srand(t, (unsigned) mrb_fixnum(seed)); - - return seed; + uint32_t x = rand_uint32(t); + return x*(1.0/4294967295.0); } +#endif static mrb_value -mrb_random_mt_rand(mrb_state *mrb, mt_state *t, mrb_value max) +random_rand(mrb_state *mrb, rand_state *t, mrb_value max) { mrb_value value; if (mrb_fixnum(max) == 0) { - value = mrb_float_value(mrb, mt_rand_real(t)); +#ifndef MRB_WITHOUT_FLOAT + value = mrb_float_value(mrb, rand_real(t)); +#else + mrb_raise(mrb, E_ARGUMENT_ERROR, "Float not supported"); +#endif } else { - value = mrb_fixnum_value(mt_rand(t) % mrb_fixnum(max)); + value = mrb_fixnum_value(rand_uint32(t) % mrb_fixnum(max)); } return value; @@ -95,105 +110,70 @@ get_opt(mrb_state* mrb) } static mrb_value -get_random(mrb_state *mrb) { +random_default(mrb_state *mrb) { return mrb_const_get(mrb, mrb_obj_value(mrb_class_get(mrb, "Random")), mrb_intern_lit(mrb, "DEFAULT")); } -static mt_state * -get_random_state(mrb_state *mrb) -{ - mrb_value random_val = get_random(mrb); - return DATA_GET_PTR(mrb, random_val, &mt_state_type, mt_state); -} - -static mrb_value -mrb_random_g_rand(mrb_state *mrb, mrb_value self) -{ - mrb_value random = get_random(mrb); - return mrb_random_rand(mrb, random); -} - -static mrb_value -mrb_random_g_srand(mrb_state *mrb, mrb_value self) +static rand_state * +random_state(mrb_state *mrb) { - mrb_value random = get_random(mrb); - return mrb_random_srand(mrb, random); + mrb_value random_val = random_default(mrb); + return DATA_GET_PTR(mrb, random_val, &rand_state_type, rand_state); } static mrb_value -mrb_random_init(mrb_state *mrb, mrb_value self) +random_m_init(mrb_state *mrb, mrb_value self) { mrb_value seed; - mt_state *t; + rand_state *t; seed = get_opt(mrb); - /* avoid memory leaks */ - t = (mt_state*)DATA_PTR(self); - if (t) { - mrb_free(mrb, t); + t = (rand_state*)DATA_PTR(self); + if (t == NULL) { + t = (rand_state *)mrb_malloc(mrb, sizeof(rand_state)); + mrb_data_init(self, t, &rand_state_type); } - mrb_data_init(self, NULL, &mt_state_type); - - t = (mt_state *)mrb_malloc(mrb, sizeof(mt_state)); - t->mti = N + 1; - - seed = mrb_random_mt_srand(mrb, t, seed); if (mrb_nil_p(seed)) { - t->has_seed = FALSE; + rand_init(t); } else { - mrb_assert(mrb_fixnum_p(seed)); - t->has_seed = TRUE; - t->seed = mrb_fixnum(seed); + rand_seed(t, (uint32_t)mrb_fixnum(seed)); } - mrb_data_init(self, t, &mt_state_type); - return self; } -static void -mrb_random_rand_seed(mrb_state *mrb, mt_state *t) -{ - if (!t->has_seed) { - mrb_random_mt_srand(mrb, t, mrb_nil_value()); - } -} - static mrb_value -mrb_random_rand(mrb_state *mrb, mrb_value self) +random_m_rand(mrb_state *mrb, mrb_value self) { mrb_value max; - mt_state *t = DATA_GET_PTR(mrb, self, &mt_state_type, mt_state); + rand_state *t = DATA_GET_PTR(mrb, self, &rand_state_type, rand_state); max = get_opt(mrb); - mrb_random_rand_seed(mrb, t); - return mrb_random_mt_rand(mrb, t, max); + return random_rand(mrb, t, max); } static mrb_value -mrb_random_srand(mrb_state *mrb, mrb_value self) +random_m_srand(mrb_state *mrb, mrb_value self) { - mrb_value seed; - mrb_value old_seed; - mt_state *t = DATA_GET_PTR(mrb, self, &mt_state_type, mt_state); - - seed = get_opt(mrb); - seed = mrb_random_mt_srand(mrb, t, seed); - old_seed = t->has_seed? mrb_fixnum_value(t->seed) : mrb_nil_value(); - if (mrb_nil_p(seed)) { - t->has_seed = FALSE; + uint32_t seed; + uint32_t old_seed; + mrb_value sv; + rand_state *t = DATA_GET_PTR(mrb, self, &rand_state_type, rand_state); + + sv = get_opt(mrb); + if (mrb_nil_p(sv)) { + seed = (uint32_t)time(NULL) + rand_uint32(t); } else { - mrb_assert(mrb_fixnum_p(seed)); - t->has_seed = TRUE; - t->seed = mrb_fixnum(seed); + seed = (uint32_t)mrb_fixnum(sv); } + old_seed = rand_seed(t, seed); - return old_seed; + return mrb_fixnum_value((mrb_int)old_seed); } /* @@ -207,25 +187,23 @@ static mrb_value mrb_ary_shuffle_bang(mrb_state *mrb, mrb_value ary) { mrb_int i; - mt_state *random = NULL; + mrb_value max; + rand_state *random = NULL; if (RARRAY_LEN(ary) > 1) { - mrb_get_args(mrb, "|d", &random, &mt_state_type); + mrb_get_args(mrb, "|d", &random, &rand_state_type); if (random == NULL) { - random = get_random_state(mrb); + random = random_state(mrb); } - mrb_random_rand_seed(mrb, random); - mrb_ary_modify(mrb, mrb_ary_ptr(ary)); - + max = mrb_fixnum_value(RARRAY_LEN(ary)); for (i = RARRAY_LEN(ary) - 1; i > 0; i--) { mrb_int j; mrb_value *ptr = RARRAY_PTR(ary); mrb_value tmp; - - j = mrb_fixnum(mrb_random_mt_rand(mrb, random, mrb_fixnum_value(RARRAY_LEN(ary)))); + j = mrb_fixnum(random_rand(mrb, random, max)); tmp = ptr[i]; ptr[i] = ptr[j]; @@ -272,15 +250,13 @@ mrb_ary_sample(mrb_state *mrb, mrb_value ary) { mrb_int n = 0; mrb_bool given; - mt_state *random = NULL; + rand_state *random = NULL; mrb_int len; - mrb_get_args(mrb, "|i?d", &n, &given, &random, &mt_state_type); + mrb_get_args(mrb, "|i?d", &n, &given, &random, &rand_state_type); if (random == NULL) { - random = get_random_state(mrb); + random = random_state(mrb); } - mrb_random_rand_seed(mrb, random); - mt_rand(random); len = RARRAY_LEN(ary); if (!given) { /* pick one element */ switch (len) { @@ -289,7 +265,7 @@ mrb_ary_sample(mrb_state *mrb, mrb_value ary) case 1: return RARRAY_PTR(ary)[0]; default: - return RARRAY_PTR(ary)[mt_rand(random) % len]; + return RARRAY_PTR(ary)[rand_uint32(random) % len]; } } else { @@ -304,7 +280,7 @@ mrb_ary_sample(mrb_state *mrb, mrb_value ary) for (;;) { retry: - r = mt_rand(random) % len; + r = (mrb_int)rand_uint32(random) % len; for (j=0; jarray_class; - mrb_define_method(mrb, mrb->kernel_module, "rand", mrb_random_g_rand, MRB_ARGS_OPT(1)); - mrb_define_method(mrb, mrb->kernel_module, "srand", mrb_random_g_srand, MRB_ARGS_OPT(1)); + mrb_define_method(mrb, mrb->kernel_module, "rand", random_f_rand, MRB_ARGS_OPT(1)); + mrb_define_method(mrb, mrb->kernel_module, "srand", random_f_srand, MRB_ARGS_OPT(1)); random = mrb_define_class(mrb, "Random", mrb->object_class); MRB_SET_INSTANCE_TT(random, MRB_TT_DATA); - mrb_define_class_method(mrb, random, "rand", mrb_random_g_rand, MRB_ARGS_OPT(1)); - mrb_define_class_method(mrb, random, "srand", mrb_random_g_srand, MRB_ARGS_OPT(1)); + mrb_define_class_method(mrb, random, "rand", random_f_rand, MRB_ARGS_OPT(1)); + mrb_define_class_method(mrb, random, "srand", random_f_srand, MRB_ARGS_OPT(1)); - mrb_define_method(mrb, random, "initialize", mrb_random_init, MRB_ARGS_OPT(1)); - mrb_define_method(mrb, random, "rand", mrb_random_rand, MRB_ARGS_OPT(1)); - mrb_define_method(mrb, random, "srand", mrb_random_srand, MRB_ARGS_OPT(1)); + mrb_define_method(mrb, random, "initialize", random_m_init, MRB_ARGS_OPT(1)); + mrb_define_method(mrb, random, "rand", random_m_rand, MRB_ARGS_OPT(1)); + mrb_define_method(mrb, random, "srand", random_m_srand, MRB_ARGS_OPT(1)); mrb_define_method(mrb, array, "shuffle", mrb_ary_shuffle, MRB_ARGS_OPT(1)); mrb_define_method(mrb, array, "shuffle!", mrb_ary_shuffle_bang, MRB_ARGS_OPT(1)); -- cgit v1.2.3 From fe8b463c4ee84a89c116102a86181b2e7084e038 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Mon, 22 Jul 2019 19:39:25 +0900 Subject: Set `MRB_STR_ASCII` flag in `String#inspect` `String#inspect` can set `MRB_STR_ASCII` flag to receiver and return value because it checks character byte length. --- src/string.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/string.c b/src/string.c index de8a15ba9..ecbe21a22 100644 --- a/src/string.c +++ b/src/string.c @@ -2789,6 +2789,9 @@ mrb_str_inspect(mrb_state *mrb, mrb_value str) const char *p, *pend; char buf[CHAR_ESC_LEN + 1]; mrb_value result = mrb_str_new_lit(mrb, "\""); +#ifdef MRB_UTF8_STRING + uint32_t ascii_flag = MRB_STR_ASCII; +#endif p = RSTRING_PTR(str); pend = RSTRING_END(str); for (;p < pend; p++) { @@ -2805,6 +2808,7 @@ mrb_str_inspect(mrb_state *mrb, mrb_value str) } mrb_str_cat(mrb, result, buf, clen); p += clen-1; + ascii_flag = 0; continue; } #endif @@ -2846,7 +2850,10 @@ mrb_str_inspect(mrb_state *mrb, mrb_value str) } } mrb_str_cat_lit(mrb, result, "\""); - RSTR_COPY_ASCII_FLAG(mrb_str_ptr(result), mrb_str_ptr(str)); +#ifdef MRB_UTF8_STRING + mrb_str_ptr(str)->flags |= ascii_flag; + mrb_str_ptr(result)->flags |= ascii_flag; +#endif return result; } -- cgit v1.2.3 From 949f6f53248c1679bb14229777a064c0fe383b6a Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Mon, 22 Jul 2019 20:19:01 +0900 Subject: Check conflicts with `Complex` and `MRB_WITHOUT_FLOAT`; ref #4576 The Complex class needs `mrb_float` so that it does not work with `MRB_WITHOUT_FLOAT` anyway. --- mrbgems/mruby-complex/src/complex.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/mrbgems/mruby-complex/src/complex.c b/mrbgems/mruby-complex/src/complex.c index 8a0569d68..d6414a5e1 100644 --- a/mrbgems/mruby-complex/src/complex.c +++ b/mrbgems/mruby-complex/src/complex.c @@ -2,6 +2,10 @@ #include #include +#ifdef MRB_WITHOUT_FLOAT +# error Complex conflicts 'MRB_WITHOUT_FLOAT' configuration in your 'build_config.rb' +#endif + struct mrb_complex { mrb_float real; mrb_float imaginary; @@ -91,7 +95,6 @@ complex_s_rect(mrb_state *mrb, mrb_value self) return complex_new(mrb, real, imaginary); } -#ifndef MRB_WITHOUT_FLOAT static mrb_value complex_to_f(mrb_state *mrb, mrb_value self) { @@ -103,7 +106,6 @@ complex_to_f(mrb_state *mrb, mrb_value self) return mrb_float_value(mrb, p->real); } -#endif static mrb_value complex_to_i(mrb_state *mrb, mrb_value self) @@ -137,9 +139,7 @@ void mrb_mruby_complex_gem_init(mrb_state *mrb) mrb_define_method(mrb, mrb->kernel_module, "Complex", complex_s_rect, MRB_ARGS_REQ(1)|MRB_ARGS_OPT(1)); mrb_define_method(mrb, comp, "real", complex_real, MRB_ARGS_NONE()); mrb_define_method(mrb, comp, "imaginary", complex_imaginary, MRB_ARGS_NONE()); -#ifndef MRB_WITHOUT_FLOAT mrb_define_method(mrb, comp, "to_f", complex_to_f, MRB_ARGS_NONE()); -#endif mrb_define_method(mrb, comp, "to_i", complex_to_i, MRB_ARGS_NONE()); mrb_define_method(mrb, comp, "to_c", complex_to_c, MRB_ARGS_NONE()); } -- cgit v1.2.3 From 87d1b2a910afd6c1eb60427fac9a7d0b01335c48 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Mon, 22 Jul 2019 20:21:30 +0900 Subject: Improve conflict error message of `Time` and `Math`; ref #4576 --- mrbgems/mruby-math/src/math.c | 2 +- mrbgems/mruby-time/src/time.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/mrbgems/mruby-math/src/math.c b/mrbgems/mruby-math/src/math.c index 35fcd0fa6..c6d4ca414 100644 --- a/mrbgems/mruby-math/src/math.c +++ b/mrbgems/mruby-math/src/math.c @@ -5,7 +5,7 @@ */ #ifdef MRB_WITHOUT_FLOAT -# error Conflict 'MRB_WITHOUT_FLOAT' configuration in your 'build_config.rb' +# error Math conflicts 'MRB_WITHOUT_FLOAT' configuration in your 'build_config.rb' #endif #include diff --git a/mrbgems/mruby-time/src/time.c b/mrbgems/mruby-time/src/time.c index 4f0afd6c6..933689426 100644 --- a/mrbgems/mruby-time/src/time.c +++ b/mrbgems/mruby-time/src/time.c @@ -5,7 +5,7 @@ */ #ifdef MRB_WITHOUT_FLOAT -# error Conflict 'MRB_WITHOUT_FLOAT' configuration in your 'build_config.rb' +# error Time conflicts 'MRB_WITHOUT_FLOAT' configuration in your 'build_config.rb' #endif #include -- cgit v1.2.3 From d74355061bffe9762dabd2e303525002d3e6a585 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Mon, 22 Jul 2019 21:34:37 +0900 Subject: Fix `mruby-time` to work with `MRB_WITHOUT_FLOAT`; ref #4576 As a side effect, `mrb_time_at()` now takes `mrb_int` instead of `double` as time arguments. --- mrbgems/mruby-time/include/mruby/time.h | 2 +- mrbgems/mruby-time/src/time.c | 91 +++++++++++++++++++++------------ 2 files changed, 59 insertions(+), 34 deletions(-) diff --git a/mrbgems/mruby-time/include/mruby/time.h b/mrbgems/mruby-time/include/mruby/time.h index d71f4ccd3..9b1cdfacd 100644 --- a/mrbgems/mruby-time/include/mruby/time.h +++ b/mrbgems/mruby-time/include/mruby/time.h @@ -18,7 +18,7 @@ typedef enum mrb_timezone { MRB_TIMEZONE_LAST = 3 } mrb_timezone; -MRB_API mrb_value mrb_time_at(mrb_state *mrb, double sec, double usec, mrb_timezone timezone); +MRB_API mrb_value mrb_time_at(mrb_state *mrb, mrb_int sec, mrb_int usec, mrb_timezone timezone); MRB_END_DECL diff --git a/mrbgems/mruby-time/src/time.c b/mrbgems/mruby-time/src/time.c index 933689426..3c0ab6ca0 100644 --- a/mrbgems/mruby-time/src/time.c +++ b/mrbgems/mruby-time/src/time.c @@ -4,10 +4,6 @@ ** See Copyright Notice in mruby.h */ -#ifdef MRB_WITHOUT_FLOAT -# error Time conflicts 'MRB_WITHOUT_FLOAT' configuration in your 'build_config.rb' -#endif - #include #include #include @@ -202,6 +198,18 @@ struct mrb_time { static const struct mrb_data_type mrb_time_type = { "Time", mrb_free }; +#ifndef MRB_WITHOUT_FLOAT +void mrb_check_num_exact(mrb_state *mrb, mrb_float num); +typedef mrb_float mrb_sec; +#define time_sec_args(mrb, v) mrb_get_args(mrb, "f", v); +#define mrb_sec_value(mrb, sec) mrb_float_value(mrb, sec) +#else +#define mrb_check_num_exact(mrb, num) +typedef mrb_int mrb_sec; +#define time_sec_args(mrb, v) mrb_get_args(mrb, "i", v); +#define mrb_sec_value(mrb, sec) mrb_fixnum_value(sec) +#endif + /** Updates the datetime of a mrb_time based on it's timezone and seconds setting. Returns self on success, NULL of failure. if `dealloc` is set `true`, it frees `self` on error. */ @@ -218,10 +226,10 @@ time_update_datetime(mrb_state *mrb, struct mrb_time *self, int dealloc) aid = localtime_r(&t, &self->datetime); } if (!aid) { - mrb_float sec = (mrb_float)t; + mrb_sec sec = (mrb_sec)t; if (dealloc) mrb_free(mrb, self); - mrb_raisef(mrb, E_ARGUMENT_ERROR, "%S out of Time range", mrb_float_value(mrb, sec)); + mrb_raisef(mrb, E_ARGUMENT_ERROR, "%S out of Time range", mrb_sec_value(mrb, sec)); /* not reached */ return NULL; } @@ -238,36 +246,33 @@ mrb_time_wrap(mrb_state *mrb, struct RClass *tc, struct mrb_time *tm) return mrb_obj_value(Data_Wrap_Struct(mrb, tc, &mrb_time_type, tm)); } -void mrb_check_num_exact(mrb_state *mrb, mrb_float num); - /* Allocates a mrb_time object and initializes it. */ static struct mrb_time* -time_alloc(mrb_state *mrb, double sec, double usec, enum mrb_timezone timezone) +time_alloc(mrb_state *mrb, mrb_sec sec, mrb_int usec, enum mrb_timezone timezone) { struct mrb_time *tm; time_t tsec = 0; - mrb_check_num_exact(mrb, (mrb_float)sec); - mrb_check_num_exact(mrb, (mrb_float)usec); + mrb_check_num_exact(mrb, sec); #ifndef MRB_TIME_T_UINT - if (sizeof(time_t) == 4 && (sec > (double)INT32_MAX || (double)INT32_MIN > sec)) { + if (sizeof(time_t) == 4 && (sec > (mrb_sec)INT32_MAX || (mrb_sec)INT32_MIN > sec)) { goto out_of_range; } - if (sizeof(time_t) == 8 && (sec > (double)INT64_MAX || (double)INT64_MIN > sec)) { + if (sizeof(time_t) == 8 && (sec > (mrb_sec)INT64_MAX || (mrb_sec)INT64_MIN > sec)) { goto out_of_range; } #else - if (sizeof(time_t) == 4 && (sec > (double)UINT32_MAX || (double)0 > sec)) { + if (sizeof(time_t) == 4 && (sec > (mrb_sec)UINT32_MAX || (mrb_sec)0 > sec)) { goto out_of_range; } - if (sizeof(time_t) == 8 && (sec > (double)UINT64_MAX || (double)0 > sec)) { + if (sizeof(time_t) == 8 && (sec > (mrb_sec)UINT64_MAX || (mrb_sec)0 > sec)) { goto out_of_range; } #endif tsec = (time_t)sec; - if ((sec > 0 && tsec < 0) || (sec < 0 && (double)tsec > sec)) { + if ((sec > 0 && tsec < 0) || (sec < 0 && (mrb_sec)tsec > sec)) { out_of_range: - mrb_raisef(mrb, E_ARGUMENT_ERROR, "%S out of Time range", mrb_float_value(mrb, sec)); + mrb_raisef(mrb, E_ARGUMENT_ERROR, "%S out of Time range", mrb_sec_value(mrb, sec)); } tm = (struct mrb_time *)mrb_malloc(mrb, sizeof(struct mrb_time)); tm->sec = tsec; @@ -289,7 +294,7 @@ time_alloc(mrb_state *mrb, double sec, double usec, enum mrb_timezone timezone) } static mrb_value -mrb_time_make(mrb_state *mrb, struct RClass *c, double sec, double usec, enum mrb_timezone timezone) +mrb_time_make(mrb_state *mrb, struct RClass *c, mrb_sec sec, mrb_int usec, enum mrb_timezone timezone) { return mrb_time_wrap(mrb, c, time_alloc(mrb, sec, usec, timezone)); } @@ -351,7 +356,7 @@ mrb_time_now(mrb_state *mrb, mrb_value self) } MRB_API mrb_value -mrb_time_at(mrb_state *mrb, double sec, double usec, enum mrb_timezone zone) +mrb_time_at(mrb_state *mrb, mrb_int sec, mrb_int usec, enum mrb_timezone zone) { return mrb_time_make(mrb, mrb_class_get(mrb, "Time"), sec, usec, zone); } @@ -361,10 +366,16 @@ mrb_time_at(mrb_state *mrb, double sec, double usec, enum mrb_timezone zone) static mrb_value mrb_time_at_m(mrb_state *mrb, mrb_value self) { - mrb_float f, f2 = 0; + mrb_sec sec; + mrb_int usec = 0; - mrb_get_args(mrb, "f|f", &f, &f2); - return mrb_time_make(mrb, mrb_class_ptr(self), f, f2, MRB_TIMEZONE_LOCAL); +#ifndef MRB_WITHOUT_FLOAT + mrb_get_args(mrb, "f|i", &sec, &usec); +#else + mrb_get_args(mrb, "i|i", &sec, &usec); +#endif + + return mrb_time_make(mrb, mrb_class_ptr(self), sec, usec, MRB_TIMEZONE_LOCAL); } static struct mrb_time* @@ -401,7 +412,7 @@ time_mktime(mrb_state *mrb, mrb_int ayear, mrb_int amonth, mrb_int aday, mrb_raise(mrb, E_ARGUMENT_ERROR, "Not a valid time."); } - return time_alloc(mrb, (double)nowsecs, (double)ausec, timezone); + return time_alloc(mrb, (mrb_sec)nowsecs, ausec, timezone); } /* 15.2.19.6.2 */ @@ -487,18 +498,18 @@ mrb_time_cmp(mrb_state *mrb, mrb_value self) static mrb_value mrb_time_plus(mrb_state *mrb, mrb_value self) { - mrb_float f; + mrb_sec f; struct mrb_time *tm; - mrb_get_args(mrb, "f", &f); + time_sec_args(mrb, &f); tm = time_get_ptr(mrb, self); - return mrb_time_make(mrb, mrb_obj_class(mrb, self), (double)tm->sec+f, (double)tm->usec, tm->timezone); + return mrb_time_make(mrb, mrb_obj_class(mrb, self), (mrb_sec)tm->sec+f, (mrb_int)tm->usec, tm->timezone); } static mrb_value mrb_time_minus(mrb_state *mrb, mrb_value self) { - mrb_float f; + mrb_sec f; mrb_value other; struct mrb_time *tm, *tm2; @@ -506,13 +517,19 @@ mrb_time_minus(mrb_state *mrb, mrb_value self) tm = time_get_ptr(mrb, self); tm2 = DATA_CHECK_GET_PTR(mrb, other, &mrb_time_type, struct mrb_time); if (tm2) { - f = (mrb_float)(tm->sec - tm2->sec) - + (mrb_float)(tm->usec - tm2->usec) / 1.0e6; +#ifndef MRB_WITHOUT_FLOAT + f = (mrb_sec)(tm->sec - tm2->sec) + + (mrb_sec)(tm->usec - tm2->usec) / 1.0e6; return mrb_float_value(mrb, f); +#else + f = tm->sec - tm2->sec; + if (tm->usec < tm2->usec) f--; + return mrb_fixnum_value(f); +#endif } else { - mrb_get_args(mrb, "f", &f); - return mrb_time_make(mrb, mrb_obj_class(mrb, self), (double)tm->sec-f, (double)tm->usec, tm->timezone); + time_sec_args(mrb, &f); + return mrb_time_make(mrb, mrb_obj_class(mrb, self), (mrb_sec)tm->sec-f, (mrb_int)tm->usec, tm->timezone); } } @@ -769,6 +786,7 @@ mrb_time_sec(mrb_state *mrb, mrb_value self) return mrb_fixnum_value(tm->datetime.tm_sec); } +#ifndef MRB_WITHOUT_FLOAT /* 15.2.19.7.24 */ /* Returns a Float with the time since the epoch in seconds. */ static mrb_value @@ -779,32 +797,37 @@ mrb_time_to_f(mrb_state *mrb, mrb_value self) tm = time_get_ptr(mrb, self); return mrb_float_value(mrb, (mrb_float)tm->sec + (mrb_float)tm->usec/1.0e6); } +#endif /* 15.2.19.7.25 */ -/* Returns a Fixnum with the time since the epoch in seconds. */ +/* Returns an Integer with the time since the epoch in seconds. */ static mrb_value mrb_time_to_i(mrb_state *mrb, mrb_value self) { struct mrb_time *tm; tm = time_get_ptr(mrb, self); +#ifndef MRB_WITHOUT_FLOAT if (tm->sec > MRB_INT_MAX || tm->sec < MRB_INT_MIN) { return mrb_float_value(mrb, (mrb_float)tm->sec); } +#endif return mrb_fixnum_value((mrb_int)tm->sec); } /* 15.2.19.7.26 */ -/* Returns a Float with the time since the epoch in microseconds. */ +/* Returns an Integer with the time since the epoch in microseconds. */ static mrb_value mrb_time_usec(mrb_state *mrb, mrb_value self) { struct mrb_time *tm; tm = time_get_ptr(mrb, self); +#ifndef MRB_WITHOUT_FLOAT if (tm->usec > MRB_INT_MAX || tm->usec < MRB_INT_MIN) { return mrb_float_value(mrb, (mrb_float)tm->usec); } +#endif return mrb_fixnum_value((mrb_int)tm->usec); } @@ -882,7 +905,9 @@ mrb_mruby_time_gem_init(mrb_state* mrb) mrb_define_method(mrb, tc, "sec" , mrb_time_sec, MRB_ARGS_NONE()); /* 15.2.19.7.23 */ mrb_define_method(mrb, tc, "to_i", mrb_time_to_i, MRB_ARGS_NONE()); /* 15.2.19.7.25 */ +#ifndef MRB_WITHOUT_FLOAT mrb_define_method(mrb, tc, "to_f", mrb_time_to_f, MRB_ARGS_NONE()); /* 15.2.19.7.24 */ +#endif mrb_define_method(mrb, tc, "usec", mrb_time_usec, MRB_ARGS_NONE()); /* 15.2.19.7.26 */ mrb_define_method(mrb, tc, "utc" , mrb_time_utc, MRB_ARGS_NONE()); /* 15.2.19.7.27 */ mrb_define_method(mrb, tc, "utc?", mrb_time_utc_p,MRB_ARGS_NONE()); /* 15.2.19.7.28 */ -- cgit v1.2.3 From e86aa61f203ec1589d37798ceb8b40385c7f85e0 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Tue, 23 Jul 2019 20:16:46 +0900 Subject: Add encoding argument to `Integral#chr` MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently, `Integral#chr` in mruby changes behavior by `MRB_UTF8_STRING` setting. before this patch: $ bin/mruby -e 'p 171.chr' #=> "\xab" (`MRB_UTF8_STRING` is disabled) $ bin/mruby -e 'p 171.chr' #=> "«" (`MRB_UTF8_STRING` is enabled) This behavior is incompatible with Ruby, and a little inconvenient because it can't be interpreted as ASCII-8BIT with `MRB_UTF8_STRING`, I think. So add encoding argument according to Ruby. after this patch: $ bin/mruby -e 'p 171.chr' #=> "\xab" $ bin/mruby -e 'p 171.chr("ASCII-8BIT")' #=> "\xab" $ bin/mruby -e 'p 171.chr("UTF-8")' #=> "«" Allow only `String` for encoding because mruby doesn't have `Encoding` class, and `"ASCII-8BIT"` (`"BINARY"`) and `"UTF-8"` (only with `MRB_UTF8_STRING`) are valid value (default is `"ASCII-8BIT"`). --- mrbgems/mruby-string-ext/mrblib/string.rb | 2 +- mrbgems/mruby-string-ext/src/string.c | 166 ++++++++++++++++++++++-------- mrbgems/mruby-string-ext/test/numeric.rb | 24 +++++ mrbgems/mruby-string-ext/test/string.rb | 9 +- 4 files changed, 156 insertions(+), 45 deletions(-) diff --git a/mrbgems/mruby-string-ext/mrblib/string.rb b/mrbgems/mruby-string-ext/mrblib/string.rb index fdaf2f960..e57d75355 100644 --- a/mrbgems/mruby-string-ext/mrblib/string.rb +++ b/mrbgems/mruby-string-ext/mrblib/string.rb @@ -414,7 +414,7 @@ class String e = max.ord while c <= e break if exclusive and c == e - yield c.chr + yield c.chr(__ENCODING__) c += 1 end return self diff --git a/mrbgems/mruby-string-ext/src/string.c b/mrbgems/mruby-string-ext/src/string.c index ab9919650..036a0a463 100644 --- a/mrbgems/mruby-string-ext/src/string.c +++ b/mrbgems/mruby-string-ext/src/string.c @@ -5,6 +5,91 @@ #include #include +#define ENC_ASCII_8BIT "ASCII-8BIT" +#define ENC_BINARY "BINARY" +#define ENC_UTF8 "UTF-8" + +#define ENC_COMP_P(enc, enc_lit) \ + str_casecmp_p(RSTRING_PTR(enc), RSTRING_LEN(enc), enc_lit, sizeof(enc_lit"")-1) + +#ifdef MRB_WITHOUT_FLOAT +# define mrb_float_p(o) FALSE +#endif + +static mrb_bool +str_casecmp_p(const char *s1, mrb_int len1, const char *s2, mrb_int len2) +{ + const char *e1, *e2; + + if (len1 != len2) return FALSE; + e1 = s1 + len1; + e2 = s2 + len2; + while (s1 < e1 && s2 < e2) { + if (*s1 != *s2 && TOUPPER(*s1) != TOUPPER(*s2)) return FALSE; + ++s1; + ++s2; + } + return TRUE; +} + +static mrb_value +int_chr_binary(mrb_state *mrb, mrb_value num) +{ + mrb_int cp = mrb_int(mrb, num); + char c; + mrb_value str; + + if (cp < 0 || 0xff < cp) { + mrb_raisef(mrb, E_RANGE_ERROR, "%S out of char range", num); + } + c = (char)cp; + str = mrb_str_new(mrb, &c, 1); + RSTR_SET_ASCII_FLAG(mrb_str_ptr(str)); + return str; +} + +#ifdef MRB_UTF8_STRING +static mrb_value +int_chr_utf8(mrb_state *mrb, mrb_value num) +{ + mrb_int cp = mrb_int(mrb, num); + char utf8[4]; + mrb_int len; + mrb_value str; + uint32_t ascii_flag = 0; + + if (cp < 0 || 0x10FFFF < cp) { + mrb_raisef(mrb, E_RANGE_ERROR, "%S out of char range", num); + } + if (cp < 0x80) { + utf8[0] = (char)cp; + len = 1; + ascii_flag = MRB_STR_ASCII; + } + else if (cp < 0x800) { + utf8[0] = (char)(0xC0 | (cp >> 6)); + utf8[1] = (char)(0x80 | (cp & 0x3F)); + len = 2; + } + else if (cp < 0x10000) { + utf8[0] = (char)(0xE0 | (cp >> 12)); + utf8[1] = (char)(0x80 | ((cp >> 6) & 0x3F)); + utf8[2] = (char)(0x80 | ( cp & 0x3F)); + len = 3; + } + else { + utf8[0] = (char)(0xF0 | (cp >> 18)); + utf8[1] = (char)(0x80 | ((cp >> 12) & 0x3F)); + utf8[2] = (char)(0x80 | ((cp >> 6) & 0x3F)); + utf8[3] = (char)(0x80 | ( cp & 0x3F)); + len = 4; + } + str = mrb_str_new(mrb, utf8, len); + mrb_str_ptr(str)->flags |= ascii_flag; + return str; +} +#endif + static mrb_value mrb_str_getbyte(mrb_state *mrb, mrb_value str) { @@ -125,8 +210,6 @@ mrb_str_swapcase(mrb_state *mrb, mrb_value self) return str; } -static mrb_value mrb_int_chr(mrb_state *mrb, mrb_value num); - /* * call-seq: * str << integer -> str @@ -136,7 +219,8 @@ static mrb_value mrb_int_chr(mrb_state *mrb, mrb_value num); * * Append---Concatenates the given object to str. If the object is a * Integer, it is considered as a codepoint, and is converted - * to a character before concatenation. + * to a character before concatenation + * (equivalent to str.concat(integer.chr(__ENCODING__))). * * a = "hello " * a << "world" #=> "hello world" @@ -148,8 +232,12 @@ mrb_str_concat_m(mrb_state *mrb, mrb_value self) mrb_value str; mrb_get_args(mrb, "o", &str); - if (mrb_fixnum_p(str)) - str = mrb_int_chr(mrb, str); + if (mrb_fixnum_p(str) || mrb_float_p(str)) +#ifdef MRB_UTF8_STRING + str = int_chr_utf8(mrb, str); +#else + str = int_chr_binary(mrb, str); +#endif else str = mrb_ensure_string_type(mrb, str); mrb_str_concat(mrb, self, str); @@ -800,7 +888,7 @@ mrb_str_count(mrb_state *mrb, mrb_value str) tr_parse_pattern(mrb, &pat, v_pat, TRUE); tr_compile_pattern(&pat, v_pat, bitmap); tr_free_pattern(mrb, &pat); - + s = RSTRING_PTR(str); len = RSTRING_LEN(str); for (i = 0; i < len; i++) { @@ -836,49 +924,40 @@ mrb_str_chr(mrb_state *mrb, mrb_value self) return mrb_str_substr(mrb, self, 0, 1); } +/* + * call-seq: + * int.chr([encoding]) -> string + * + * Returns a string containing the character represented by the +int+'s value + * according to +encoding+. +"ASCII-8BIT"+ (+"BINARY"+) and +"UTF-8"+ (only + * with +MRB_UTF8_STRING+) can be specified as +encoding+ (default is + * +"ASCII-8BIT"+). + * + * 65.chr #=> "A" + * 230.chr #=> "\xE6" + * 230.chr("ASCII-8BIT") #=> "\xE6" + * 230.chr("UTF-8") #=> "\u00E6" + */ static mrb_value mrb_int_chr(mrb_state *mrb, mrb_value num) { - mrb_int cp = mrb_fixnum(num); -#ifdef MRB_UTF8_STRING - char utf8[4]; - mrb_int len; - - if (cp < 0 || 0x10FFFF < cp) { - mrb_raisef(mrb, E_RANGE_ERROR, "%S out of char range", num); - } - if (cp < 0x80) { - utf8[0] = (char)cp; - len = 1; + mrb_value enc; + mrb_bool enc_given; + + mrb_get_args(mrb, "|S?", &enc, &enc_given); + if (!enc_given || + ENC_COMP_P(enc, ENC_ASCII_8BIT) || + ENC_COMP_P(enc, ENC_BINARY)) { + return int_chr_binary(mrb, num); } - else if (cp < 0x800) { - utf8[0] = (char)(0xC0 | (cp >> 6)); - utf8[1] = (char)(0x80 | (cp & 0x3F)); - len = 2; - } - else if (cp < 0x10000) { - utf8[0] = (char)(0xE0 | (cp >> 12)); - utf8[1] = (char)(0x80 | ((cp >> 6) & 0x3F)); - utf8[2] = (char)(0x80 | ( cp & 0x3F)); - len = 3; +#ifdef MRB_UTF8_STRING + else if (ENC_COMP_P(enc, ENC_UTF8)) { + return int_chr_utf8(mrb, num); } +#endif else { - utf8[0] = (char)(0xF0 | (cp >> 18)); - utf8[1] = (char)(0x80 | ((cp >> 12) & 0x3F)); - utf8[2] = (char)(0x80 | ((cp >> 6) & 0x3F)); - utf8[3] = (char)(0x80 | ( cp & 0x3F)); - len = 4; - } - return mrb_str_new(mrb, utf8, len); -#else - char c; - - if (cp < 0 || 0xff < cp) { - mrb_raisef(mrb, E_RANGE_ERROR, "%S out of char range", num); + mrb_raisef(mrb, E_ARGUMENT_ERROR, "unknown encoding name - %S", enc); } - c = (char)cp; - return mrb_str_new(mrb, &c, 1); -#endif } /* @@ -1219,7 +1298,8 @@ mrb_mruby_string_ext_gem_init(mrb_state* mrb) mrb_define_method(mrb, s, "delete_suffix", mrb_str_del_suffix, MRB_ARGS_REQ(1)); mrb_define_method(mrb, s, "__lines", mrb_str_lines, MRB_ARGS_NONE()); - mrb_define_method(mrb, mrb_module_get(mrb, "Integral"), "chr", mrb_int_chr, MRB_ARGS_NONE()); + + mrb_define_method(mrb, mrb_module_get(mrb, "Integral"), "chr", mrb_int_chr, MRB_ARGS_OPT(1)); } void diff --git a/mrbgems/mruby-string-ext/test/numeric.rb b/mrbgems/mruby-string-ext/test/numeric.rb index cae562fc1..dfcb9ebf4 100644 --- a/mrbgems/mruby-string-ext/test/numeric.rb +++ b/mrbgems/mruby-string-ext/test/numeric.rb @@ -1,5 +1,29 @@ +# coding: utf-8 + assert('Integer#chr') do assert_equal("A", 65.chr) assert_equal("B", 0x42.chr) + assert_equal("\xab", 171.chr) assert_raise(RangeError) { -1.chr } + assert_raise(RangeError) { 256.chr } + + assert_equal("A", 65.chr("ASCII-8BIT")) + assert_equal("B", 0x42.chr("BINARY")) + assert_equal("\xab", 171.chr("ascii-8bit")) + assert_raise(RangeError) { -1.chr("binary") } + assert_raise(RangeError) { 256.chr("Ascii-8bit") } + assert_raise(ArgumentError) { 65.chr("ASCII") } + assert_raise(ArgumentError) { 65.chr("ASCII-8BIT", 2) } + assert_raise(TypeError) { 65.chr(:BINARY) } + + if __ENCODING__ == "ASCII-8BIT" + assert_raise(ArgumentError) { 65.chr("UTF-8") } + else + assert_equal("A", 65.chr("UTF-8")) + assert_equal("B", 0x42.chr("UTF-8")) + assert_equal("«", 171.chr("utf-8")) + assert_equal("あ", 12354.chr("Utf-8")) + assert_raise(RangeError) { -1.chr("utf-8") } + assert_raise(RangeError) { 0x110000.chr.chr("UTF-8") } + end end diff --git a/mrbgems/mruby-string-ext/test/string.rb b/mrbgems/mruby-string-ext/test/string.rb index 2eb35f840..8f1d25f29 100644 --- a/mrbgems/mruby-string-ext/test/string.rb +++ b/mrbgems/mruby-string-ext/test/string.rb @@ -167,8 +167,15 @@ end assert('String#concat') do assert_equal "Hello World!", "Hello " << "World" << 33 assert_equal "Hello World!", "Hello ".concat("World").concat(33) - assert_raise(TypeError) { "".concat(Object.new) } + + if UTF8STRING + assert_equal "H«", "H" << 0xab + assert_equal "Hは", "H" << 12399 + else + assert_equal "H\xab", "H" << 0xab + assert_raise(RangeError) { "H" << 12399 } + end end assert('String#casecmp') do -- cgit v1.2.3 From a57a9bce79b7512f1e0e08149c0a328a993b3e1b Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Wed, 24 Jul 2019 10:43:24 +0900 Subject: Call `MRB_SET_INSTANCE_TT` for `Complex` and `Rational`. --- mrbgems/mruby-complex/src/complex.c | 6 +++++- mrbgems/mruby-rational/src/rational.c | 7 +++++-- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/mrbgems/mruby-complex/src/complex.c b/mrbgems/mruby-complex/src/complex.c index d6414a5e1..aa2afc2ce 100644 --- a/mrbgems/mruby-complex/src/complex.c +++ b/mrbgems/mruby-complex/src/complex.c @@ -132,7 +132,11 @@ void mrb_mruby_complex_gem_init(mrb_state *mrb) mrb_assert(sizeof(struct mrb_complex) < ISTRUCT_DATA_SIZE); #endif comp = mrb_define_class(mrb, "Complex", mrb_class_get(mrb, "Numeric")); - //MRB_SET_INSTANCE_TT(comp, MRB_TT_ISTRUCT); +#ifdef COMPLEX_USE_ISTRUCT + MRB_SET_INSTANCE_TT(comp, MRB_TT_ISTRUCT); +#else + MRB_SET_INSTANCE_TT(comp, MRB_TT_DATA); +#endif mrb_undef_class_method(mrb, comp, "new"); mrb_define_class_method(mrb, comp, "rectangular", complex_s_rect, MRB_ARGS_REQ(1)|MRB_ARGS_OPT(1)); mrb_define_class_method(mrb, comp, "rect", complex_s_rect, MRB_ARGS_REQ(1)|MRB_ARGS_OPT(1)); diff --git a/mrbgems/mruby-rational/src/rational.c b/mrbgems/mruby-rational/src/rational.c index 31471e934..09bd68003 100644 --- a/mrbgems/mruby-rational/src/rational.c +++ b/mrbgems/mruby-rational/src/rational.c @@ -183,10 +183,13 @@ void mrb_mruby_rational_gem_init(mrb_state *mrb) { struct RClass *rat; -#ifdef COMPLEX_USE_RATIONAL + rat = mrb_define_class(mrb, "Rational", mrb_class_get(mrb, "Numeric")); +#ifdef RATIONAL_USE_ISTRUCT + MRB_SET_INSTANCE_TT(rat, MRB_TT_ISTRUCT); mrb_assert(sizeof(struct mrb_rational) < ISTRUCT_DATA_SIZE); +#else + MRB_SET_INSTANCE_TT(rat, MRB_TT_DATA); #endif - rat = mrb_define_class(mrb, "Rational", mrb_class_get(mrb, "Numeric")); 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()); -- cgit v1.2.3 From 866a9e6481ef94c43163d44013894b83953d0457 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Wed, 24 Jul 2019 10:43:57 +0900 Subject: Use `MRB_TT_ISTRUCT` for `Random` to reduce memory. When the size of Xorshift128 seed (`sizeof(uint32)*4`) is bigger than ISTRUCT_DATA_SIZE, `Random` uses Xorshift96 instead. --- mrbgems/mruby-random/src/random.c | 109 ++++++++++++++++++++++++++------------ 1 file changed, 74 insertions(+), 35 deletions(-) diff --git a/mrbgems/mruby-random/src/random.c b/mrbgems/mruby-random/src/random.c index bca565b17..a970e65a3 100644 --- a/mrbgems/mruby-random/src/random.c +++ b/mrbgems/mruby-random/src/random.c @@ -9,17 +9,19 @@ #include #include #include +#include +#if INT32_MAX <= INTPTR_MAX +# define XORSHIFT96 +# define NSEEDS 3 +#else +# define NSEEDS 4 +#endif +#define LASTSEED (NSEEDS-1) #include -static char const RAND_STATE_KEY[] = "$mrb_i_rand_state"; - -static const struct mrb_data_type rand_state_type = { - RAND_STATE_KEY, mrb_free, -}; - typedef struct rand_state { - uint32_t seed[4]; + uint32_t seed[NSEEDS]; } rand_state; static void @@ -28,18 +30,39 @@ rand_init(rand_state *t) t->seed[0] = 123456789; t->seed[1] = 362436069; t->seed[2] = 521288629; +#ifndef XORSHIFT96 t->seed[3] = 88675123; +#endif } static uint32_t rand_seed(rand_state *t, uint32_t seed) { - uint32_t old_seed = t->seed[3]; + uint32_t old_seed = t->seed[LASTSEED]; rand_init(t); - t->seed[3] = seed; + t->seed[LASTSEED] = seed; return old_seed; } +#ifdef XORSHIFT96 +static uint32_t +rand_uint32(rand_state *state) +{ + uint32_t *seed = state->seed; + uint32_t x = seed[0]; + uint32_t y = seed[1]; + uint32_t z = seed[2]; + uint32_t t; + + t = (x ^ (x << 3)) ^ (y ^ (y >> 19)) ^ (z ^ (z << 6)); + x = y; y = z; z = t; + seed[0] = x; + seed[1] = y; + seed[2] = z; + + return z; +} +#else /* XORSHIFT96 */ static uint32_t rand_uint32(rand_state *state) { @@ -60,6 +83,7 @@ rand_uint32(rand_state *state) return w; } +#endif /* XORSHIFT96 */ #ifndef MRB_WITHOUT_FLOAT static double @@ -109,19 +133,26 @@ get_opt(mrb_state* mrb) return arg; } +static void +random_check(mrb_state *mrb, mrb_value random) { + struct RClass *c = mrb_class_get(mrb, "Random"); + if (!mrb_obj_is_kind_of(mrb, random, c) || mrb_type(random) != MRB_TT_ISTRUCT) { + mrb_raise(mrb, E_TYPE_ERROR, "Random instance required"); + } +} + static mrb_value random_default(mrb_state *mrb) { - return mrb_const_get(mrb, - mrb_obj_value(mrb_class_get(mrb, "Random")), - mrb_intern_lit(mrb, "DEFAULT")); + struct RClass *c = mrb_class_get(mrb, "Random"); + mrb_value d = mrb_const_get(mrb, mrb_obj_value(c), mrb_intern_lit(mrb, "DEFAULT")); + if (!mrb_obj_is_kind_of(mrb, d, c)) { + mrb_raise(mrb, E_TYPE_ERROR, "Random::DEFAULT replaced"); + } + return d; } -static rand_state * -random_state(mrb_state *mrb) -{ - mrb_value random_val = random_default(mrb); - return DATA_GET_PTR(mrb, random_val, &rand_state_type, rand_state); -} +#define random_ptr(v) (rand_state*)mrb_istruct_ptr(v) +#define random_default_state(mrb) random_ptr(random_default(mrb)) static mrb_value random_m_init(mrb_state *mrb, mrb_value self) @@ -131,11 +162,7 @@ random_m_init(mrb_state *mrb, mrb_value self) seed = get_opt(mrb); /* avoid memory leaks */ - t = (rand_state*)DATA_PTR(self); - if (t == NULL) { - t = (rand_state *)mrb_malloc(mrb, sizeof(rand_state)); - mrb_data_init(self, t, &rand_state_type); - } + t = random_ptr(self); if (mrb_nil_p(seed)) { rand_init(t); } @@ -150,7 +177,7 @@ static mrb_value random_m_rand(mrb_state *mrb, mrb_value self) { mrb_value max; - rand_state *t = DATA_GET_PTR(mrb, self, &rand_state_type, rand_state); + rand_state *t = random_ptr(self); max = get_opt(mrb); return random_rand(mrb, t, max); @@ -162,7 +189,7 @@ random_m_srand(mrb_state *mrb, mrb_value self) uint32_t seed; uint32_t old_seed; mrb_value sv; - rand_state *t = DATA_GET_PTR(mrb, self, &rand_state_type, rand_state); + rand_state *t = random_ptr(self); sv = get_opt(mrb); if (mrb_nil_p(sv)) { @@ -188,13 +215,18 @@ mrb_ary_shuffle_bang(mrb_state *mrb, mrb_value ary) { mrb_int i; mrb_value max; - rand_state *random = NULL; + mrb_value r = mrb_nil_value(); + rand_state *random; if (RARRAY_LEN(ary) > 1) { - mrb_get_args(mrb, "|d", &random, &rand_state_type); + mrb_get_args(mrb, "|o", &r); - if (random == NULL) { - random = random_state(mrb); + if (mrb_nil_p(r)) { + random = random_default_state(mrb); + } + else { + random_check(mrb, r); + random = random_ptr(r); } mrb_ary_modify(mrb, mrb_ary_ptr(ary)); max = mrb_fixnum_value(RARRAY_LEN(ary)); @@ -250,12 +282,17 @@ mrb_ary_sample(mrb_state *mrb, mrb_value ary) { mrb_int n = 0; mrb_bool given; - rand_state *random = NULL; + mrb_value r = mrb_nil_value(); + rand_state *random; mrb_int len; - mrb_get_args(mrb, "|i?d", &n, &given, &random, &rand_state_type); - if (random == NULL) { - random = random_state(mrb); + mrb_get_args(mrb, "|i?o", &n, &given, &r); + if (mrb_nil_p(r)) { + random = random_default_state(mrb); + } + else { + random_check(mrb, r); + random = random_ptr(r); } len = RARRAY_LEN(ary); if (!given) { /* pick one element */ @@ -301,7 +338,7 @@ mrb_ary_sample(mrb_state *mrb, mrb_value ary) static mrb_value random_f_rand(mrb_state *mrb, mrb_value self) { - rand_state *t = random_state(mrb); + rand_state *t = random_default_state(mrb); return random_rand(mrb, t, get_opt(mrb)); } @@ -318,11 +355,13 @@ void mrb_mruby_random_gem_init(mrb_state *mrb) struct RClass *random; struct RClass *array = mrb->array_class; + mrb_assert(sizeof(rand_state) < ISTRUCT_DATA_SIZE); + mrb_define_method(mrb, mrb->kernel_module, "rand", random_f_rand, MRB_ARGS_OPT(1)); mrb_define_method(mrb, mrb->kernel_module, "srand", random_f_srand, MRB_ARGS_OPT(1)); random = mrb_define_class(mrb, "Random", mrb->object_class); - MRB_SET_INSTANCE_TT(random, MRB_TT_DATA); + MRB_SET_INSTANCE_TT(random, MRB_TT_ISTRUCT); mrb_define_class_method(mrb, random, "rand", random_f_rand, MRB_ARGS_OPT(1)); mrb_define_class_method(mrb, random, "srand", random_f_srand, MRB_ARGS_OPT(1)); -- cgit v1.2.3 From 5779464ec3035e24ac2c9b21bef87ed08e2cdfc4 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Wed, 24 Jul 2019 10:50:22 +0900 Subject: Add `return` to silence a warning; ref #4593 --- mrbgems/mruby-string-ext/src/string.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/mrbgems/mruby-string-ext/src/string.c b/mrbgems/mruby-string-ext/src/string.c index 036a0a463..80b277444 100644 --- a/mrbgems/mruby-string-ext/src/string.c +++ b/mrbgems/mruby-string-ext/src/string.c @@ -958,6 +958,8 @@ mrb_int_chr(mrb_state *mrb, mrb_value num) else { mrb_raisef(mrb, E_ARGUMENT_ERROR, "unknown encoding name - %S", enc); } + /* not reached */ + return mrb_nil_value(); } /* -- cgit v1.2.3 From 2d520eaf6f60e1bb5224b56f433fc9187b10c6cf Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Wed, 24 Jul 2019 20:13:26 +0900 Subject: Move `NilClass#to_h` to `mruby-object-ext` from `mruby-enum-ext` --- mrbgems/mruby-enum-ext/mrblib/enum.rb | 4 ---- mrbgems/mruby-enum-ext/test/enum.rb | 3 --- mrbgems/mruby-object-ext/src/object.c | 15 +++++++++++++++ mrbgems/mruby-object-ext/test/nil.rb | 4 ++++ 4 files changed, 19 insertions(+), 7 deletions(-) diff --git a/mrbgems/mruby-enum-ext/mrblib/enum.rb b/mrbgems/mruby-enum-ext/mrblib/enum.rb index 99b9cddba..b427bd67e 100644 --- a/mrbgems/mruby-enum-ext/mrblib/enum.rb +++ b/mrbgems/mruby-enum-ext/mrblib/enum.rb @@ -811,10 +811,6 @@ module Enumerable h end - def nil.to_h - {} - end - def uniq(&block) hash = {} if block diff --git a/mrbgems/mruby-enum-ext/test/enum.rb b/mrbgems/mruby-enum-ext/test/enum.rb index 64b1bbda9..6929d8ddc 100644 --- a/mrbgems/mruby-enum-ext/test/enum.rb +++ b/mrbgems/mruby-enum-ext/test/enum.rb @@ -186,8 +186,5 @@ assert("Enumerable#to_h") do 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 - assert_equal({1=>4,3=>8}, c.new.to_h{|k,v|[k,v*2]}) end diff --git a/mrbgems/mruby-object-ext/src/object.c b/mrbgems/mruby-object-ext/src/object.c index 85db75b28..0aedc9a73 100644 --- a/mrbgems/mruby-object-ext/src/object.c +++ b/mrbgems/mruby-object-ext/src/object.c @@ -1,6 +1,7 @@ #include #include #include +#include #include /* @@ -31,6 +32,19 @@ nil_to_f(mrb_state *mrb, mrb_value obj) } #endif +/* + * call-seq: + * nil.to_h -> {} + * + * Always returns an empty hash. + */ + +static mrb_value +nil_to_h(mrb_state *mrb, mrb_value obj) +{ + return mrb_hash_new(mrb); +} + /* * call-seq: * nil.to_i -> 0 @@ -117,6 +131,7 @@ mrb_mruby_object_ext_gem_init(mrb_state* mrb) #ifndef MRB_WITHOUT_FLOAT mrb_define_method(mrb, n, "to_f", nil_to_f, MRB_ARGS_NONE()); #endif + 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", mrb_f_itself, MRB_ARGS_NONE()); diff --git a/mrbgems/mruby-object-ext/test/nil.rb b/mrbgems/mruby-object-ext/test/nil.rb index fbff20629..9975e785a 100644 --- a/mrbgems/mruby-object-ext/test/nil.rb +++ b/mrbgems/mruby-object-ext/test/nil.rb @@ -7,6 +7,10 @@ assert('NilClass#to_f') do assert_equal 0.0, nil.to_f end +assert('NilClass#to_h') do + assert_equal Hash.new, nil.to_h +end + assert('NilClass#to_i') do assert_equal 0, nil.to_i end -- cgit v1.2.3 From 87cc58ba3d851651ba90947df475388a3dc7ded8 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Thu, 25 Jul 2019 22:31:54 +0900 Subject: Refine `Array#(permutation|combination) test` - No guarantees about the order in which the permutations/combinations are yielded. - Drop dependency on `Enumerator`. --- mrbgems/mruby-array-ext/test/array.rb | 46 ++++++++++++++++++++--------------- 1 file changed, 26 insertions(+), 20 deletions(-) diff --git a/mrbgems/mruby-array-ext/test/array.rb b/mrbgems/mruby-array-ext/test/array.rb index 82f09297a..4fad42518 100644 --- a/mrbgems/mruby-array-ext/test/array.rb +++ b/mrbgems/mruby-array-ext/test/array.rb @@ -1,6 +1,20 @@ ## # Array(Ext) Test +def assert_permutation_combination(exp, receiver, meth, *args) + act = [] + receiver.__send__(meth, *args) { |v| act << v } + assert_equal(exp, act.sort) +end + +def assert_permutation(exp, receiver, *args) + assert_permutation_combination(exp, receiver, :permutation, *args) +end + +def assert_combination(exp, receiver, *args) + assert_permutation_combination(exp, receiver, :combination, *args) +end + assert("Array#assoc") do s1 = [ "colors", "red", "blue", "green" ] s2 = [ "letters", "a", "b", "c" ] @@ -369,30 +383,22 @@ end assert("Array#permutation") do a = [1, 2, 3] - assert_equal([[1,2,3],[1,3,2],[2,1,3],[2,3,1],[3,1,2],[3,2,1]], - a.permutation.to_a) - assert_equal([[1],[2],[3]], - a.permutation(1).to_a) - assert_equal([[1,2],[1,3],[2,1],[2,3],[3,1],[3,2]], - a.permutation(2).to_a) - assert_equal([[1,2,3],[1,3,2],[2,1,3],[2,3,1],[3,1,2],[3,2,1]], - a.permutation(3).to_a) - assert_equal([[]], a.permutation(0).to_a) - assert_equal([], a.permutation(4).to_a) + assert_permutation([[1,2,3],[1,3,2],[2,1,3],[2,3,1],[3,1,2],[3,2,1]], a) + assert_permutation([[1],[2],[3]], a, 1) + assert_permutation([[1,2],[1,3],[2,1],[2,3],[3,1],[3,2]], a, 2) + assert_permutation([[1,2,3],[1,3,2],[2,1,3],[2,3,1],[3,1,2],[3,2,1]], a, 3) + assert_permutation([[]], a, 0) + assert_permutation([], a, 4) end assert("Array#combination") do a = [1, 2, 3, 4] - assert_equal([[1],[2],[3],[4]], - a.combination(1).to_a) - assert_equal([[1,2],[1,3],[1,4],[2,3],[2,4],[3,4]], - a.combination(2).to_a) - assert_equal([[1,2,3],[1,2,4],[1,3,4],[2,3,4]], - a.combination(3).to_a) - assert_equal([[1,2,3,4]], - a.combination(4).to_a) - assert_equal([[]], a.combination(0).to_a) - assert_equal([], a.combination(5).to_a) + assert_combination([[1],[2],[3],[4]], a, 1) + assert_combination([[1,2],[1,3],[1,4],[2,3],[2,4],[3,4]], a, 2) + assert_combination([[1,2,3],[1,2,4],[1,3,4],[2,3,4]], a, 3) + assert_combination([[1,2,3,4]], a, 4) + assert_combination([[]], a, 0) + assert_combination([], a, 5) end assert('Array#transpose') do -- cgit v1.2.3 From 778310260ca51b91125bd6deeb836c5032fa837e Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Fri, 26 Jul 2019 11:48:53 +0900 Subject: Drop dependency from `mruby-array-ext` to `mruby-enum-ext` --- mrbgems/mruby-array-ext/mrbgem.rake | 1 - mrbgems/mruby-array-ext/mrblib/array.rb | 4 ++-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/mrbgems/mruby-array-ext/mrbgem.rake b/mrbgems/mruby-array-ext/mrbgem.rake index 58d4428d4..882caf1ab 100644 --- a/mrbgems/mruby-array-ext/mrbgem.rake +++ b/mrbgems/mruby-array-ext/mrbgem.rake @@ -2,5 +2,4 @@ MRuby::Gem::Specification.new('mruby-array-ext') do |spec| spec.license = 'MIT' spec.author = 'mruby developers' spec.summary = 'Array class extension' - spec.add_test_dependency 'mruby-enumerator', core: 'mruby-enumerator' end diff --git a/mrbgems/mruby-array-ext/mrblib/array.rb b/mrbgems/mruby-array-ext/mrblib/array.rb index 59b6087d2..1cd1eb643 100644 --- a/mrbgems/mruby-array-ext/mrblib/array.rb +++ b/mrbgems/mruby-array-ext/mrblib/array.rb @@ -903,8 +903,8 @@ class Array column_count = nil self.each do |row| raise TypeError unless row.is_a?(Array) - column_count ||= row.count - raise IndexError, 'element size differs' unless column_count == row.count + column_count ||= row.size + raise IndexError, 'element size differs' unless column_count == row.size end Array.new(column_count) do |column_index| -- cgit v1.2.3 From 1467c14adcd45ce6acaa684b377cf66323b0c312 Mon Sep 17 00:00:00 2001 From: dearblue Date: Sat, 27 Jul 2019 14:42:37 +0900 Subject: Fix mruby-time with `MRB_WITHOUT_FLOAT`; ref d74355061 --- mrbgems/mruby-time/src/time.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/mrbgems/mruby-time/src/time.c b/mrbgems/mruby-time/src/time.c index 3c0ab6ca0..b8b4c5a0d 100644 --- a/mrbgems/mruby-time/src/time.c +++ b/mrbgems/mruby-time/src/time.c @@ -4,7 +4,10 @@ ** See Copyright Notice in mruby.h */ +#ifndef MRB_WITHOUT_FLOAT #include +#endif + #include #include #include @@ -26,8 +29,10 @@ double round(double x) { } #endif -#if !defined(__MINGW64__) && defined(_WIN32) -# define llround(x) round(x) +#ifdef MRB_WITHOUT_FLOAT +# if !defined(__MINGW64__) && defined(_WIN32) +# define llround(x) round(x) +# endif #endif #if defined(__MINGW64__) || defined(__MINGW32__) @@ -276,7 +281,11 @@ time_alloc(mrb_state *mrb, mrb_sec sec, mrb_int usec, enum mrb_timezone timezone } tm = (struct mrb_time *)mrb_malloc(mrb, sizeof(struct mrb_time)); tm->sec = tsec; +#ifdef MRB_WITHOUT_FLOAT + tm->usec = (time_t)usec; +#else tm->usec = (time_t)llround((sec - tm->sec) * 1.0e6 + usec); +#endif if (tm->usec < 0) { long sec2 = (long)NDIV(tm->usec,1000000); /* negative div */ tm->usec -= sec2 * 1000000; -- cgit v1.2.3 From b58f769c96462fb8b3b2453ba2aae8c83932f84b Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Sat, 27 Jul 2019 14:49:57 +0900 Subject: Fix line number bug; fix #4513 Also fix the misfeature introduced in 23783a4, that ignores newlines between method chains. --- mrbgems/mruby-compiler/core/parse.y | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/mrbgems/mruby-compiler/core/parse.y b/mrbgems/mruby-compiler/core/parse.y index b7a7d315d..f6d543c5d 100644 --- a/mrbgems/mruby-compiler/core/parse.y +++ b/mrbgems/mruby-compiler/core/parse.y @@ -4731,6 +4731,7 @@ parser_yylex(parser_state *p) case '\n': maybe_heredoc: heredoc_treat_nextline(p); + p->column = 0; switch (p->lstate) { case EXPR_BEG: case EXPR_FNAME: @@ -4738,7 +4739,6 @@ parser_yylex(parser_state *p) case EXPR_CLASS: case EXPR_VALUE: p->lineno++; - p->column = 0; if (p->parsing_heredoc != NULL) { if (p->lex_strterm) { return parse_string(p); @@ -4759,15 +4759,12 @@ parser_yylex(parser_state *p) break; case '#': /* comment as a whitespace */ pushback(p, '#'); - goto retry; - case '\n': /* consecutive newlines */ p->lineno++; - p->column = 0; - pushback(p, '\n'); goto retry; case '.': if (!peek(p, '.')) { pushback(p, '.'); + p->lineno++; goto retry; } pushback(p, c); @@ -4775,6 +4772,7 @@ parser_yylex(parser_state *p) case '&': if (peek(p, '.')) { pushback(p, '&'); + p->lineno++; goto retry; } pushback(p, c); -- cgit v1.2.3 From fe9a58c193f73c85d79de214152b2444b7cfe483 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Sat, 27 Jul 2019 20:45:14 +0900 Subject: Drop dependency from `mruby-enum-chain` to `mruby-enum-ext` --- mrbgems/mruby-enum-chain/mrblib/chain.rb | 5 ++++- mrbgems/mruby-enum-chain/test/enum_chain.rb | 24 +++++++++++++++++------- 2 files changed, 21 insertions(+), 8 deletions(-) diff --git a/mrbgems/mruby-enum-chain/mrblib/chain.rb b/mrbgems/mruby-enum-chain/mrblib/chain.rb index 98515ea14..52f5f0656 100644 --- a/mrbgems/mruby-enum-chain/mrblib/chain.rb +++ b/mrbgems/mruby-enum-chain/mrblib/chain.rb @@ -40,8 +40,11 @@ class Enumerator end def rewind - @enums.reverse_each do |e| + i = @enums.size - 1 + while 0 <= i + e = @enums[i] e.rewind if e.respond_to?(:rewind) + i -= 1 end self diff --git a/mrbgems/mruby-enum-chain/test/enum_chain.rb b/mrbgems/mruby-enum-chain/test/enum_chain.rb index 4dd59bd37..9aea783b9 100644 --- a/mrbgems/mruby-enum-chain/test/enum_chain.rb +++ b/mrbgems/mruby-enum-chain/test/enum_chain.rb @@ -14,7 +14,7 @@ end assert("Enumerable#+") do a = [].each - b = {}.reverse_each + b = {}.each c = Object.new # not has #each method assert_kind_of Enumerator::Chain, a + b @@ -46,13 +46,13 @@ assert("Enumerator::Chain#each") do assert_kind_of Enumerator, aa.each assert_equal [1, 2, 3, 1, 2, 3], aa.each.to_a - aa = a.chain(a.reverse_each) + aa = a.chain(6..9) assert_kind_of Enumerator, aa.each - assert_equal [1, 2, 3, 3, 2, 1], aa.each.to_a + assert_equal [1, 2, 3, 6, 7, 8, 9], aa.each.to_a - aa = a.chain(a.reverse_each, a) + aa = a.chain((-3..-2).each_with_index, a) assert_kind_of Enumerator, aa.each - assert_equal [1, 2, 3, 3, 2, 1, 1, 2, 3], aa.each.to_a + assert_equal [1, 2, 3, [-3, 0], [-2, 1], 1, 2, 3], aa.each.to_a aa = a.chain(Object.new) assert_kind_of Enumerator, aa.each @@ -65,12 +65,22 @@ assert("Enumerator::Chain#size") do aa = a.chain(a) assert_equal 6, aa.size - aa = a.chain(a.reverse_each) + aa = a.chain(3..4) assert_nil aa.size - aa = a.chain(a.reverse_each, a) + aa = a.chain(3..4, a) assert_nil aa.size aa = a.chain(Object.new) assert_nil aa.size end + +assert("Enumerator::Chain#rewind") do + rewound = [] + e1 = [1, 2] + e2 = (4..6) + (class << e1; self end).define_method(:rewind) { rewound << __id__ } + (class << e2; self end).define_method(:rewind) { rewound << __id__ } + c = e1.chain(e2).each{}.rewind + assert_equal [e2.__id__, e1.__id__], rewound +end -- cgit v1.2.3 From fda5c0c073a0b7a2bbcfb37ddf735a2f04f9ea08 Mon Sep 17 00:00:00 2001 From: dearblue Date: Sat, 27 Jul 2019 18:49:22 +0900 Subject: Fix the lack of precision for `Time`; ref d74355061 - `Time.local` and `Time.utc` are able to use with `MRB_INT16 + MRB_WITHOUT_FLOAT`. - `time_t` is converted directly from the Ruby object. - `time + sec` and` time - sec` are not affected by the precision of `mrb_float`. Similarly, calculations are possible with `MRB_INT16 + MRB_WITHOUT_FLOAT`. --- mrbgems/mruby-time/include/mruby/time.h | 3 +- mrbgems/mruby-time/src/time.c | 160 ++++++++++++++++++++++---------- 2 files changed, 112 insertions(+), 51 deletions(-) diff --git a/mrbgems/mruby-time/include/mruby/time.h b/mrbgems/mruby-time/include/mruby/time.h index 9b1cdfacd..1adcfd49c 100644 --- a/mrbgems/mruby-time/include/mruby/time.h +++ b/mrbgems/mruby-time/include/mruby/time.h @@ -8,6 +8,7 @@ #define MRUBY_TIME_H #include "mruby/common.h" +#include MRB_BEGIN_DECL @@ -18,7 +19,7 @@ typedef enum mrb_timezone { MRB_TIMEZONE_LAST = 3 } mrb_timezone; -MRB_API mrb_value mrb_time_at(mrb_state *mrb, mrb_int sec, mrb_int usec, mrb_timezone timezone); +MRB_API mrb_value mrb_time_at(mrb_state *mrb, time_t sec, time_t usec, mrb_timezone timezone); MRB_END_DECL diff --git a/mrbgems/mruby-time/src/time.c b/mrbgems/mruby-time/src/time.c index b8b4c5a0d..18010476b 100644 --- a/mrbgems/mruby-time/src/time.c +++ b/mrbgems/mruby-time/src/time.c @@ -8,7 +8,6 @@ #include #endif -#include #include #include #include @@ -206,15 +205,85 @@ static const struct mrb_data_type mrb_time_type = { "Time", mrb_free }; #ifndef MRB_WITHOUT_FLOAT void mrb_check_num_exact(mrb_state *mrb, mrb_float num); typedef mrb_float mrb_sec; -#define time_sec_args(mrb, v) mrb_get_args(mrb, "f", v); #define mrb_sec_value(mrb, sec) mrb_float_value(mrb, sec) #else -#define mrb_check_num_exact(mrb, num) typedef mrb_int mrb_sec; -#define time_sec_args(mrb, v) mrb_get_args(mrb, "i", v); #define mrb_sec_value(mrb, sec) mrb_fixnum_value(sec) #endif +static time_t +mrb_to_time_t(mrb_state *mrb, mrb_value obj, time_t *usec) +{ + time_t t; + + switch (mrb_type(obj)) { +#ifndef MRB_WITHOUT_FLOAT + case MRB_TT_FLOAT: + { + mrb_float f = mrb_float(obj); + + mrb_check_num_exact(mrb, f); +# ifndef MRB_TIME_T_UINT + if (sizeof(time_t) == 4 && (f > (mrb_float)INT32_MAX || (mrb_float)INT32_MIN > f)) { + goto out_of_range; + } + if (sizeof(time_t) == 8 && (f > (mrb_float)INT64_MAX || (mrb_float)INT64_MIN > f)) { + goto out_of_range; + } +# else + if (sizeof(time_t) == 4 && (f > (mrb_float)UINT32_MAX || (mrb_float)0 > f)) { + goto out_of_range; + } + if (sizeof(time_t) == 8 && (f > (mrb_float)UINT64_MAX || (mrb_float)0 > f)) { + goto out_of_range; + } +# endif + + if (usec) { + t = (time_t)f; + *usec = (time_t)llround((f - t) * 1.0e+6); + } + else { + t = (time_t)llround(f); + } + } + break; +#endif /* MRB_WITHOUT_FLOAT */ + default: + case MRB_TT_FIXNUM: + { + mrb_int i = mrb_int(mrb, obj); + +#ifndef MRB_TIME_T_UINT + if (sizeof(time_t) == 4 && (i > INT32_MAX || INT32_MIN > i)) { + goto out_of_range; + } + if (sizeof(time_t) == 8 && (i > INT64_MAX || INT64_MIN > i)) { + goto out_of_range; + } +#else + if (sizeof(time_t) == 4 && (i > UINT32_MAX || 0 > i)) { + goto out_of_range; + } + if (sizeof(time_t) == 8 && (i > UINT64_MAX || 0 > i)) { + goto out_of_range; + } +#endif + + t = (time_t)i; + if (usec) { *usec = 0; } + } + break; + } + + return t; + +out_of_range: + mrb_raisef(mrb, E_ARGUMENT_ERROR, "%S out of Time range", obj); + + return 0; /* suppress compiler warnings */ +} + /** Updates the datetime of a mrb_time based on it's timezone and seconds setting. Returns self on success, NULL of failure. if `dealloc` is set `true`, it frees `self` on error. */ @@ -253,39 +322,13 @@ mrb_time_wrap(mrb_state *mrb, struct RClass *tc, struct mrb_time *tm) /* Allocates a mrb_time object and initializes it. */ static struct mrb_time* -time_alloc(mrb_state *mrb, mrb_sec sec, mrb_int usec, enum mrb_timezone timezone) +time_alloc_time(mrb_state *mrb, time_t sec, time_t usec, enum mrb_timezone timezone) { struct mrb_time *tm; - time_t tsec = 0; - mrb_check_num_exact(mrb, sec); -#ifndef MRB_TIME_T_UINT - if (sizeof(time_t) == 4 && (sec > (mrb_sec)INT32_MAX || (mrb_sec)INT32_MIN > sec)) { - goto out_of_range; - } - if (sizeof(time_t) == 8 && (sec > (mrb_sec)INT64_MAX || (mrb_sec)INT64_MIN > sec)) { - goto out_of_range; - } -#else - if (sizeof(time_t) == 4 && (sec > (mrb_sec)UINT32_MAX || (mrb_sec)0 > sec)) { - goto out_of_range; - } - if (sizeof(time_t) == 8 && (sec > (mrb_sec)UINT64_MAX || (mrb_sec)0 > sec)) { - goto out_of_range; - } -#endif - tsec = (time_t)sec; - if ((sec > 0 && tsec < 0) || (sec < 0 && (mrb_sec)tsec > sec)) { - out_of_range: - mrb_raisef(mrb, E_ARGUMENT_ERROR, "%S out of Time range", mrb_sec_value(mrb, sec)); - } tm = (struct mrb_time *)mrb_malloc(mrb, sizeof(struct mrb_time)); - tm->sec = tsec; -#ifdef MRB_WITHOUT_FLOAT - tm->usec = (time_t)usec; -#else - tm->usec = (time_t)llround((sec - tm->sec) * 1.0e6 + usec); -#endif + tm->sec = sec; + tm->usec = usec; if (tm->usec < 0) { long sec2 = (long)NDIV(tm->usec,1000000); /* negative div */ tm->usec -= sec2 * 1000000; @@ -302,8 +345,25 @@ time_alloc(mrb_state *mrb, mrb_sec sec, mrb_int usec, enum mrb_timezone timezone return tm; } +static struct mrb_time* +time_alloc(mrb_state *mrb, mrb_value sec, mrb_value usec, enum mrb_timezone timezone) +{ + time_t tsec, tusec; + + tsec = mrb_to_time_t(mrb, sec, &tusec); + tusec += mrb_to_time_t(mrb, usec, NULL); + + return time_alloc_time(mrb, tsec, tusec, timezone); +} + static mrb_value -mrb_time_make(mrb_state *mrb, struct RClass *c, mrb_sec sec, mrb_int usec, enum mrb_timezone timezone) +mrb_time_make_time(mrb_state *mrb, struct RClass *c, time_t sec, time_t usec, enum mrb_timezone timezone) +{ + return mrb_time_wrap(mrb, c, time_alloc_time(mrb, sec, usec, timezone)); +} + +static mrb_value +mrb_time_make(mrb_state *mrb, struct RClass *c, mrb_value sec, mrb_value usec, enum mrb_timezone timezone) { return mrb_time_wrap(mrb, c, time_alloc(mrb, sec, usec, timezone)); } @@ -365,9 +425,9 @@ mrb_time_now(mrb_state *mrb, mrb_value self) } MRB_API mrb_value -mrb_time_at(mrb_state *mrb, mrb_int sec, mrb_int usec, enum mrb_timezone zone) +mrb_time_at(mrb_state *mrb, time_t sec, time_t usec, enum mrb_timezone zone) { - return mrb_time_make(mrb, mrb_class_get(mrb, "Time"), sec, usec, zone); + return mrb_time_make_time(mrb, mrb_class_get(mrb, "Time"), sec, usec, zone); } /* 15.2.19.6.1 */ @@ -375,14 +435,10 @@ mrb_time_at(mrb_state *mrb, mrb_int sec, mrb_int usec, enum mrb_timezone zone) static mrb_value mrb_time_at_m(mrb_state *mrb, mrb_value self) { - mrb_sec sec; - mrb_int usec = 0; + mrb_value sec; + mrb_value usec = mrb_fixnum_value(0); -#ifndef MRB_WITHOUT_FLOAT - mrb_get_args(mrb, "f|i", &sec, &usec); -#else - mrb_get_args(mrb, "i|i", &sec, &usec); -#endif + mrb_get_args(mrb, "o|o", &sec, &usec); return mrb_time_make(mrb, mrb_class_ptr(self), sec, usec, MRB_TIMEZONE_LOCAL); } @@ -421,7 +477,7 @@ time_mktime(mrb_state *mrb, mrb_int ayear, mrb_int amonth, mrb_int aday, mrb_raise(mrb, E_ARGUMENT_ERROR, "Not a valid time."); } - return time_alloc(mrb, (mrb_sec)nowsecs, ausec, timezone); + return time_alloc_time(mrb, nowsecs, ausec, timezone); } /* 15.2.19.6.2 */ @@ -507,18 +563,19 @@ mrb_time_cmp(mrb_state *mrb, mrb_value self) static mrb_value mrb_time_plus(mrb_state *mrb, mrb_value self) { - mrb_sec f; + mrb_value o; struct mrb_time *tm; + time_t sec, usec; - time_sec_args(mrb, &f); + mrb_get_args(mrb, "o", &o); tm = time_get_ptr(mrb, self); - return mrb_time_make(mrb, mrb_obj_class(mrb, self), (mrb_sec)tm->sec+f, (mrb_int)tm->usec, tm->timezone); + sec = mrb_to_time_t(mrb, o, &usec); + return mrb_time_make_time(mrb, mrb_obj_class(mrb, self), tm->sec+sec, tm->usec+usec, tm->timezone); } static mrb_value mrb_time_minus(mrb_state *mrb, mrb_value self) { - mrb_sec f; mrb_value other; struct mrb_time *tm, *tm2; @@ -527,18 +584,21 @@ mrb_time_minus(mrb_state *mrb, mrb_value self) tm2 = DATA_CHECK_GET_PTR(mrb, other, &mrb_time_type, struct mrb_time); if (tm2) { #ifndef MRB_WITHOUT_FLOAT + mrb_float f; f = (mrb_sec)(tm->sec - tm2->sec) + (mrb_sec)(tm->usec - tm2->usec) / 1.0e6; return mrb_float_value(mrb, f); #else + mrb_int f; f = tm->sec - tm2->sec; if (tm->usec < tm2->usec) f--; return mrb_fixnum_value(f); #endif } else { - time_sec_args(mrb, &f); - return mrb_time_make(mrb, mrb_obj_class(mrb, self), (mrb_sec)tm->sec-f, (mrb_int)tm->usec, tm->timezone); + time_t sec, usec; + sec = mrb_to_time_t(mrb, other, &usec); + return mrb_time_make_time(mrb, mrb_obj_class(mrb, self), tm->sec-sec, tm->usec-usec, tm->timezone); } } -- cgit v1.2.3 From a70107d7255cce1f34f90eca205af56aefe50b57 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Sun, 28 Jul 2019 13:08:11 +0900 Subject: Drop dependency from `mruby-enumerator` to `mruby-enum-ext` --- mrbgems/mruby-enumerator/mrbgem.rake | 1 - mrbgems/mruby-enumerator/test/enumerator.rb | 15 +++++++++++++-- 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/mrbgems/mruby-enumerator/mrbgem.rake b/mrbgems/mruby-enumerator/mrbgem.rake index 8757a15ea..abcc54e7a 100644 --- a/mrbgems/mruby-enumerator/mrbgem.rake +++ b/mrbgems/mruby-enumerator/mrbgem.rake @@ -2,6 +2,5 @@ MRuby::Gem::Specification.new('mruby-enumerator') do |spec| spec.license = 'MIT' spec.author = 'mruby developers' spec.add_dependency('mruby-fiber', :core => 'mruby-fiber') - spec.add_dependency 'mruby-enum-ext', :core => 'mruby-enum-ext' spec.summary = 'Enumerator class' end diff --git a/mrbgems/mruby-enumerator/test/enumerator.rb b/mrbgems/mruby-enumerator/test/enumerator.rb index d609cadb5..dce0c2cf2 100644 --- a/mrbgems/mruby-enumerator/test/enumerator.rb +++ b/mrbgems/mruby-enumerator/test/enumerator.rb @@ -6,6 +6,17 @@ class << @obj end end +def assert_take(exp, enumerator) + result = [] + n = exp.size + enumerator.each do |v| + break if n == 0 + result << v + n -= 1 + end + assert_equal exp, result +end + assert 'Enumerator.class' do assert_equal Class, Enumerator.class end @@ -19,7 +30,7 @@ assert 'Enumerator.new' do assert_equal [:x,:y,:z], [:x,:y,:z].each.map{|i| i}.sort assert_equal [[:x,1],[:y,2]], {x:1, y:2}.each.map{|i| i}.sort assert_equal [1,2,3], @obj.to_enum(:foo, 1,2,3).to_a - assert_equal [1,2,3], Enumerator.new { |y| i = 0; loop { y << (i += 1) } }.take(3) + assert_take [1,2,3], Enumerator.new { |y| i = 0; loop { y << (i += 1) } } assert_raise(ArgumentError) { Enumerator.new } # examples @@ -30,7 +41,7 @@ assert 'Enumerator.new' do a, b = b, a + b end end - assert_equal [1,1,2,3,5,8,13,21,34,55], fib.take(10) + assert_take [1,1,2,3,5,8,13,21,34,55], fib end assert 'Enumerator#initialize_copy' do -- cgit v1.2.3 From 27e3d92a305576befda7eff927c19e176288daf5 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Sun, 28 Jul 2019 22:12:02 +0900 Subject: Remove `Enumerator::Chain#initialize_copy` I think `Enumerator::Chain#initialize_copy` is unnecessary because CRuby doesn't clone elements. --- mrbgems/mruby-enum-chain/mrblib/chain.rb | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/mrbgems/mruby-enum-chain/mrblib/chain.rb b/mrbgems/mruby-enum-chain/mrblib/chain.rb index 52f5f0656..562620165 100644 --- a/mrbgems/mruby-enum-chain/mrblib/chain.rb +++ b/mrbgems/mruby-enum-chain/mrblib/chain.rb @@ -20,10 +20,6 @@ class Enumerator @enums = args end - def initialize_copy(orig) - @enums = orig.__copy_enums - end - def each(&block) return to_enum unless block_given? @@ -53,11 +49,5 @@ class Enumerator def inspect "#<#{self.class}: #{@enums.inspect}>" end - - def __copy_enums - @enums.each_with_object([]) do |e, a| - a << e.clone - end - end end end -- cgit v1.2.3 From 7f80a5f73cb3823e562f37c12a25d6d43d9b512d Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Sun, 28 Jul 2019 22:52:24 +0900 Subject: Define `#+` to `Enumerator` and `Enumerator#Chain` instead of `Enumerable` --- mrbgems/mruby-enum-chain/mrblib/chain.rb | 10 +++++++--- mrbgems/mruby-enum-chain/test/enum_chain.rb | 15 +++++++++++++-- 2 files changed, 20 insertions(+), 5 deletions(-) diff --git a/mrbgems/mruby-enum-chain/mrblib/chain.rb b/mrbgems/mruby-enum-chain/mrblib/chain.rb index 52f5f0656..03acfb7ef 100644 --- a/mrbgems/mruby-enum-chain/mrblib/chain.rb +++ b/mrbgems/mruby-enum-chain/mrblib/chain.rb @@ -6,13 +6,13 @@ module Enumerable def chain(*args) Enumerator::Chain.new(self, *args) end +end +class Enumerator def +(other) - Enumerator::Chain.new(self, other) + Chain.new(self, other) end -end -class Enumerator class Chain include Enumerable @@ -50,6 +50,10 @@ class Enumerator self end + def +(other) + self.class.new(self, other) + end + def inspect "#<#{self.class}: #{@enums.inspect}>" end diff --git a/mrbgems/mruby-enum-chain/test/enum_chain.rb b/mrbgems/mruby-enum-chain/test/enum_chain.rb index 9aea783b9..1d3d691ca 100644 --- a/mrbgems/mruby-enum-chain/test/enum_chain.rb +++ b/mrbgems/mruby-enum-chain/test/enum_chain.rb @@ -12,7 +12,7 @@ assert("Enumerable#chain") do assert_raise(NoMethodError) { c.chain } end -assert("Enumerable#+") do +assert("Enumerator#+") do a = [].each b = {}.each c = Object.new # not has #each method @@ -24,7 +24,7 @@ assert("Enumerable#+") do assert_raise(NoMethodError) { c + a } end -assert("Enumerator.new") do +assert("Enumerator::Chain.new") do a = [] b = {} c = Object.new # not has #each method @@ -84,3 +84,14 @@ assert("Enumerator::Chain#rewind") do c = e1.chain(e2).each{}.rewind assert_equal [e2.__id__, e1.__id__], rewound end + +assert("Enumerator::Chain#+") do + a = [].chain + b = {}.chain + c = Object.new # not has #each method + + assert_kind_of Enumerator::Chain, a + b + assert_kind_of Enumerator::Chain, a + c + assert_kind_of Enumerator::Chain, b + a + assert_kind_of Enumerator::Chain, b + c +end -- cgit v1.2.3 From cd8fc9bcb81a8e9e7e76413f3132b0515c8bd218 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Mon, 29 Jul 2019 01:02:03 +0900 Subject: Resolved conflicts in #4320 --- mrbgems/mruby-test/driver.c | 1 + test/assert.rb | 20 +++++++++++++------- 2 files changed, 14 insertions(+), 7 deletions(-) diff --git a/mrbgems/mruby-test/driver.c b/mrbgems/mruby-test/driver.c index 602b76c79..b6c9fab35 100644 --- a/mrbgems/mruby-test/driver.c +++ b/mrbgems/mruby-test/driver.c @@ -258,6 +258,7 @@ mrb_t_pass_result(mrb_state *mrb_dst, mrb_state *mrb_src) TEST_COUNT_PASS(ok_test); TEST_COUNT_PASS(ko_test); TEST_COUNT_PASS(kill_test); + TEST_COUNT_PASS(warning_test); TEST_COUNT_PASS(skip_test); #undef TEST_COUNT_PASS diff --git a/test/assert.rb b/test/assert.rb index c493cbbc0..4641e6657 100644 --- a/test/assert.rb +++ b/test/assert.rb @@ -2,6 +2,7 @@ $undefined = Object.new $ok_test = 0 $ko_test = 0 $kill_test = 0 +$warning_test = 0 $skip_test = 0 $asserts = [] $test_start = Time.now if Object.const_defined?(:Time) @@ -103,6 +104,10 @@ def assert(str = 'Assertion failed', iso = '') $ko_test += 1 t_print('F') end + elsif $mrbtest_assert_idx == 0 + $asserts.push(assertion_string('Warn: ', str, iso, 'no assertion')) + $warning_test += 1 + t_print('W') else $ok_test += 1 t_print('.') @@ -332,17 +337,18 @@ def report t_print("#{msg}\n") end - $total_test = $ok_test + $ko_test + $kill_test + $skip_test - t_print("Total: #{$total_test}\n") + $total_test = $ok_test + $ko_test + $kill_test + $warning_test + $skip_test + t_print(" Total: #{$total_test}\n") - t_print(" OK: #{$ok_test}\n") - t_print(" KO: #{$ko_test}\n") - t_print("Crash: #{$kill_test}\n") - t_print(" Skip: #{$skip_test}\n") + t_print(" OK: #{$ok_test}\n") + t_print(" KO: #{$ko_test}\n") + t_print(" Crash: #{$kill_test}\n") + t_print("Warning: #{$warning_test}\n") + t_print(" Skip: #{$skip_test}\n") if Object.const_defined?(:Time) t_time = Time.now - $test_start - t_print(" Time: #{t_time.round(2)} seconds\n") + t_print(" Time: #{t_time.round(2)} seconds\n") end $ko_test == 0 && $kill_test == 0 -- cgit v1.2.3 From ff43b2b97c77812abbcbfe14da4582c6c209be9b Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Mon, 29 Jul 2019 01:25:58 +0900 Subject: Fixed a conflict between #4407 and #4540 --- test/assert.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/assert.rb b/test/assert.rb index b2d5011ad..58ee4b913 100644 --- a/test/assert.rb +++ b/test/assert.rb @@ -329,7 +329,7 @@ def assert_raise_with_message_pattern(*args, &block) end def _assert_raise_with_message(type, exc, exp_msg, msg = nil, &block) e = msg ? assert_raise(exc, msg, &block) : assert_raise(exc, &block) - e ? ($mrbtest_assert_idx -= 1) : (return e) + e ? ($mrbtest_assert_idx[-1]-=1) : (return e) err_msg = e.message unless ret = type == :pattern ? _str_match?(exp_msg, err_msg) : exp_msg == err_msg -- cgit v1.2.3 From effae4ae55772bd464d5010353e88236ce1ee494 Mon Sep 17 00:00:00 2001 From: Sutou Kouhei Date: Mon, 29 Jul 2019 18:03:51 +0900 Subject: Fix Time#to_s encoding on Windows strftime() on Windows returns locale encoding time zone for "%z" even if MSDN says "%z" is "The offset from UTC in ISO 8601 format; no characters if time zone is unknown" in MSDN: https://docs.microsoft.com/en-us/cpp/c-runtime-library/reference/strftime-wcsftime-strftime-l-wcsftime-l?view=vs-2019 So we need to convert encoding of string from strftime(). --- mrbgems/mruby-time/src/time.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/mrbgems/mruby-time/src/time.c b/mrbgems/mruby-time/src/time.c index 18010476b..e3b5d3fe7 100644 --- a/mrbgems/mruby-time/src/time.c +++ b/mrbgems/mruby-time/src/time.c @@ -19,6 +19,8 @@ #include #endif +#include + #define NDIV(x,y) (-(-((x)+1)/(y))-1) #define TO_S_FMT "%Y-%m-%d %H:%M:%S " @@ -931,7 +933,13 @@ mrb_time_to_s(mrb_state *mrb, mrb_value self) struct mrb_time *tm = time_get_ptr(mrb, self); const char *fmt = tm->timezone == MRB_TIMEZONE_UTC ? TO_S_FMT "UTC" : TO_S_FMT "%z"; size_t len = strftime(buf, sizeof(buf), fmt, &tm->datetime); - return mrb_str_new(mrb, buf, len); + char *utf8; + mrb_value mrb_string; + buf[len] = '\0'; + utf8 = mrb_utf8_from_locale(buf, (int)len); + mrb_string = mrb_str_new_cstr(mrb, utf8); + mrb_utf8_free(utf8); + return mrb_string; } void -- cgit v1.2.3 From 5091d047c0b965c4860e8d47cb95f72687b37a7f Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Mon, 29 Jul 2019 21:40:58 +0900 Subject: Fix "Warn if assertion is missing inside `assert`"; ref ff43b2b9 --- test/assert.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/assert.rb b/test/assert.rb index 58ee4b913..a63e626cf 100644 --- a/test/assert.rb +++ b/test/assert.rb @@ -108,7 +108,7 @@ def assert(str = 'Assertion failed', iso = '') $ko_test += 1 t_print('F') end - elsif $mrbtest_assert_idx == 0 + elsif $mrbtest_assert_idx[-1] == 0 $asserts.push(assertion_string('Warn: ', str, iso, 'no assertion')) $warning_test += 1 t_print('W') -- cgit v1.2.3 From 44381f0a0c306a8c778f546926d3febfdf981b45 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Tue, 30 Jul 2019 12:46:24 +0900 Subject: Refine message to `skip` in nested `assert` - I think "Info" is used only to `skip`, so change to "Skip". - Changed the default value of `assert` and specify the argument explicitly at the caller of `assert` because it is unnatural "Assertion failed" is output even though the assertion doesn't fail. == Example: def assert_foo(exp, act) assert do assert_equal exp[0], act[0] assert_equal exp[1], act[1] end end def assert_bar(exp, act) assert do skip end end def assert_baz(exp, act) assert do assert_equal exp, act assert_bar exp, act end end assert 'test#skip_in_nested_assert' do assert_baz 1, 1 end === Before this patch: ?.. Info: test#skip_in_nested_assert (core) - Assertion[1] Info: Assertion failed (core) - Assertion[1-2] Skip: Assertion failed (core) Total: 3 OK: 2 KO: 0 Crash: 0 Warning: 0 Skip: 1 === After this patch: ??? Skip: test#skip_in_nested_assert (core) - Assertion[1] Skip: assert (core) - Assertion[1-2] Skip: assert (core) Total: 3 OK: 0 KO: 0 Crash: 0 Warning: 0 Skip: 3 --- mrbgems/mruby-bin-mruby/bintest/mruby.rb | 2 +- mrbgems/mruby-complex/test/complex.rb | 2 +- mrbgems/mruby-io/test/io.rb | 2 +- mrbgems/mruby-pack/test/pack.rb | 2 +- mrbgems/mruby-rational/test/rational.rb | 4 ++-- test/assert.rb | 8 ++++---- test/t/numeric.rb | 2 +- 7 files changed, 11 insertions(+), 11 deletions(-) diff --git a/mrbgems/mruby-bin-mruby/bintest/mruby.rb b/mrbgems/mruby-bin-mruby/bintest/mruby.rb index 5dbbc5592..e032ff79a 100644 --- a/mrbgems/mruby-bin-mruby/bintest/mruby.rb +++ b/mrbgems/mruby-bin-mruby/bintest/mruby.rb @@ -3,7 +3,7 @@ require 'open3' def assert_mruby(exp_out, exp_err, exp_success, args) out, err, stat = Open3.capture3(cmd("mruby"), *args) - assert do + assert "assert_mruby" do assert_operator(exp_out, :===, out, "standard output") assert_operator(exp_err, :===, err, "standard error") assert_equal(exp_success, stat.success?, "exit success?") diff --git a/mrbgems/mruby-complex/test/complex.rb b/mrbgems/mruby-complex/test/complex.rb index 5b7c3bfa4..4ae80515b 100644 --- a/mrbgems/mruby-complex/test/complex.rb +++ b/mrbgems/mruby-complex/test/complex.rb @@ -1,5 +1,5 @@ def assert_complex(real, exp) - assert do + assert "assert_complex" do assert_float real.real, exp.real assert_float real.imaginary, exp.imaginary end diff --git a/mrbgems/mruby-io/test/io.rb b/mrbgems/mruby-io/test/io.rb index 1491a4cfe..3aaa109a8 100644 --- a/mrbgems/mruby-io/test/io.rb +++ b/mrbgems/mruby-io/test/io.rb @@ -5,7 +5,7 @@ MRubyIOTestUtil.io_test_setup $cr, $crlf, $cmd = MRubyIOTestUtil.win? ? [1, "\r\n", "cmd /c "] : [0, "\n", ""] def assert_io_open(meth) - assert do + assert "assert_io_open" do fd = IO.sysopen($mrbtest_io_rfname) assert_equal Fixnum, fd.class io1 = IO.__send__(meth, fd) diff --git a/mrbgems/mruby-pack/test/pack.rb b/mrbgems/mruby-pack/test/pack.rb index 68ef4165f..6832adcc7 100644 --- a/mrbgems/mruby-pack/test/pack.rb +++ b/mrbgems/mruby-pack/test/pack.rb @@ -2,7 +2,7 @@ PACK_IS_LITTLE_ENDIAN = "\x01\00".unpack('S')[0] == 0x01 def assert_pack tmpl, packed, unpacked t = tmpl.inspect - assert do + assert "assert_pack" do assert_equal packed, unpacked.pack(tmpl), "#{unpacked.inspect}.pack(#{t})" assert_equal unpacked, packed.unpack(tmpl), "#{packed.inspect}.unpack(#{t})" end diff --git a/mrbgems/mruby-rational/test/rational.rb b/mrbgems/mruby-rational/test/rational.rb index 11737034b..a8ebb8ea2 100644 --- a/mrbgems/mruby-rational/test/rational.rb +++ b/mrbgems/mruby-rational/test/rational.rb @@ -23,14 +23,14 @@ class ComplexLikeNumeric < UserDefinedNumeric end def assert_rational(exp, real) - assert do + assert "assert_rational" do assert_float exp.numerator, real.numerator assert_float exp.denominator, real.denominator end end def assert_equal_rational(exp, o1, o2) - assert do + assert "assert_equal_rational" do if exp assert_operator(o1, :==, o2) assert_not_operator(o1, :!=, o2) diff --git a/test/assert.rb b/test/assert.rb index 58ee4b913..5ae46ca70 100644 --- a/test/assert.rb +++ b/test/assert.rb @@ -76,7 +76,7 @@ end # iso : The ISO reference code of the feature # which will be tested by this # assertion -def assert(str = 'Assertion failed', iso = '') +def assert(str = 'assert', iso = '') t_print(str, (iso != '' ? " [#{iso}]" : ''), ' : ') if $mrbtest_verbose begin $mrbtest_child_noassert ||= [0] @@ -99,10 +99,10 @@ def assert(str = 'Assertion failed', iso = '') yield if $mrbtest_assert.size > 0 if $mrbtest_assert.size == $mrbtest_child_noassert[-1] - $asserts.push(assertion_string('Info: ', str, iso)) + $asserts.push(assertion_string('Skip: ', str, iso)) $mrbtest_child_noassert[-2] += 1 - $ok_test += 1 - t_print('.') + $skip_test += 1 + t_print('?') else $asserts.push(assertion_string('Fail: ', str, iso)) $ko_test += 1 diff --git a/test/t/numeric.rb b/test/t/numeric.rb index bb95f8ef3..5b1e79153 100644 --- a/test/t/numeric.rb +++ b/test/t/numeric.rb @@ -8,7 +8,7 @@ def assert_step(exp, receiver, args, inf: false) break if inf && exp.size == act.size end expr = "#{receiver.inspect}.step(#{args.map(&:inspect).join(', ')})" - assert do + assert "assert_step" do assert_true(exp.eql?(act), "#{expr}: counters", assertion_diff(exp, act)) assert_same(receiver, ret, "#{expr}: return value") unless inf end -- cgit v1.2.3 From 5900b29fb47f443287228f0b37bb60403758120c Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Tue, 30 Jul 2019 23:13:30 +0900 Subject: Fixed integer overflow in `lshift`. --- src/numeric.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/numeric.c b/src/numeric.c index a1299a74f..db851b06a 100644 --- a/src/numeric.c +++ b/src/numeric.c @@ -1119,7 +1119,7 @@ lshift(mrb_state *mrb, mrb_int val, mrb_int width) } else { if ((width > NUMERIC_SHIFT_WIDTH_MAX) || - (val < (MRB_INT_MIN >> width))) { + (val <= (MRB_INT_MIN >> width))) { #ifdef MRB_WITHOUT_FLOAT return mrb_fixnum_value(0); #else -- cgit v1.2.3 From 8175d92b4bd8c641ac45fa10417e60da930164dd Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Wed, 31 Jul 2019 00:54:39 +0900 Subject: Use `NULL` instead of `0` for null pointers. --- src/numeric.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/numeric.c b/src/numeric.c index db851b06a..744426c67 100644 --- a/src/numeric.c +++ b/src/numeric.c @@ -904,7 +904,7 @@ fix_mod(mrb_state *mrb, mrb_value x) return mrb_float_value(mrb, NAN); #endif } - fixdivmod(mrb, a, b, 0, &mod); + fixdivmod(mrb, a, b, NULL, &mod); return mrb_fixnum_value(mod); } #ifdef MRB_WITHOUT_FLOAT @@ -913,7 +913,7 @@ fix_mod(mrb_state *mrb, mrb_value x) else { mrb_float mod; - flodivmod(mrb, (mrb_float)a, mrb_to_flo(mrb, y), 0, &mod); + flodivmod(mrb, (mrb_float)a, mrb_to_flo(mrb, y), NULL, &mod); return mrb_float_value(mrb, mod); } #endif -- cgit v1.2.3 From 28405d26b09c9f9b233b56221eeca1adcaa2822a Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Wed, 31 Jul 2019 00:55:31 +0900 Subject: Should return +/- infinity for float division by zero. --- src/numeric.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/numeric.c b/src/numeric.c index 744426c67..92e98a8a7 100644 --- a/src/numeric.c +++ b/src/numeric.c @@ -901,6 +901,8 @@ fix_mod(mrb_state *mrb, mrb_value x) /* ZeroDivisionError */ return mrb_fixnum_value(0); #else + if (a > 0) return mrb_float_value(mrb, INFINITY); + if (a < 0) return mrb_float_value(mrb, INFINITY); return mrb_float_value(mrb, NAN); #endif } -- cgit v1.2.3 From c31e1ea798f9a67917258147ba2cd33cf1ca851a Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Wed, 31 Jul 2019 00:57:00 +0900 Subject: Normalize floating point negative zero to positive zero in `flodivmod'. --- src/numeric.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/numeric.c b/src/numeric.c index 92e98a8a7..6cddcdada 100644 --- a/src/numeric.c +++ b/src/numeric.c @@ -320,6 +320,8 @@ flodivmod(mrb_state *mrb, double x, double y, mrb_float *divp, mrb_float *modp) div = (x - mod) / y; if (modp && divp) div = round(div); } + if (div == 0) div = 0.0; + if (mod == 0) mod = 0.0; if (y*mod < 0) { mod += y; div -= 1.0; -- cgit v1.2.3 From 96ac49b75b5981c7b286da8ef60236de5412d342 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Wed, 31 Jul 2019 00:58:12 +0900 Subject: Avoid `MRB_INT_MIN` to apply `fixdivmod`. `MRB_INT_MIN` is the only integer value that has no corresponding positive integer value (i.e. `-MRB_INT_MIN` = `MRB_INT_MIN`). --- src/numeric.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/numeric.c b/src/numeric.c index 6cddcdada..b143b2f67 100644 --- a/src/numeric.c +++ b/src/numeric.c @@ -891,14 +891,14 @@ static mrb_value fix_mod(mrb_state *mrb, mrb_value x) { mrb_value y; - mrb_int a; + mrb_int a, b; mrb_get_args(mrb, "o", &y); a = mrb_fixnum(x); - if (mrb_fixnum_p(y)) { - mrb_int b, mod; + if (mrb_fixnum_p(y) && a != MRB_INT_MIN && (b=mrb_fixnum(y)) != MRB_INT_MIN) { + mrb_int mod; - if ((b=mrb_fixnum(y)) == 0) { + if (b == 0) { #ifdef MRB_WITHOUT_FLOAT /* ZeroDivisionError */ return mrb_fixnum_value(0); -- cgit v1.2.3 From 5116789aa0abcf731aaad883ea99d79844b66a85 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Wed, 31 Jul 2019 19:20:03 +0900 Subject: Fix UTC offset representation in `Time#to_s` on some environments; ref #4604 Use own implementation to calculate UTC offset on Visual Studio 2015 or earlier or MinGW because `strftime("%z")` on these environments does not conform C99. --- mrbgems/mruby-time/src/time.c | 43 ++++++++++++++++++++++++++++++++--------- mrbgems/mruby-time/test/time.rb | 3 ++- 2 files changed, 36 insertions(+), 10 deletions(-) diff --git a/mrbgems/mruby-time/src/time.c b/mrbgems/mruby-time/src/time.c index e3b5d3fe7..0d144c4e7 100644 --- a/mrbgems/mruby-time/src/time.c +++ b/mrbgems/mruby-time/src/time.c @@ -926,20 +926,45 @@ mrb_time_utc_p(mrb_state *mrb, mrb_value self) return mrb_bool_value(tm->timezone == MRB_TIMEZONE_UTC); } +static size_t +time_to_s_utc(mrb_state *mrb, struct mrb_time *tm, char *buf, size_t buf_len) +{ + return strftime(buf, buf_len, TO_S_FMT "UTC", &tm->datetime); +} + +static size_t +time_to_s_local(mrb_state *mrb, struct mrb_time *tm, char *buf, size_t buf_len) +{ +#if defined(_MSC_VER) && _MSC_VER < 1900 || defined(__MINGW64__) || defined(__MINGW32__) + struct tm datetime = {0}; + time_t utc_sec = timegm(&tm->datetime); + size_t len; + int offset; + + if (utc_sec == (time_t)-1) { + mrb_raise(mrb, E_ARGUMENT_ERROR, "Not a valid time."); + } + offset = abs((int)(utc_sec - tm->sec) / 60); + datetime.tm_year = 100; + datetime.tm_hour = offset / 60; + datetime.tm_min = offset % 60; + len = strftime(buf, buf_len, TO_S_FMT, &tm->datetime); + buf[len++] = utc_sec < tm->sec ? '-' : '+'; + + return len + strftime(buf + len, buf_len - len, "%H%M", &datetime); +#else + return strftime(buf, buf_len, TO_S_FMT "%z", &tm->datetime); +#endif +} + static mrb_value mrb_time_to_s(mrb_state *mrb, mrb_value self) { char buf[64]; struct mrb_time *tm = time_get_ptr(mrb, self); - const char *fmt = tm->timezone == MRB_TIMEZONE_UTC ? TO_S_FMT "UTC" : TO_S_FMT "%z"; - size_t len = strftime(buf, sizeof(buf), fmt, &tm->datetime); - char *utf8; - mrb_value mrb_string; - buf[len] = '\0'; - utf8 = mrb_utf8_from_locale(buf, (int)len); - mrb_string = mrb_str_new_cstr(mrb, utf8); - mrb_utf8_free(utf8); - return mrb_string; + mrb_bool utc = tm->timezone == MRB_TIMEZONE_UTC; + size_t len = (utc ? time_to_s_utc : time_to_s_local)(mrb, tm, buf, sizeof(buf)); + return mrb_str_new(mrb, buf, len); } void diff --git a/mrbgems/mruby-time/test/time.rb b/mrbgems/mruby-time/test/time.rb index f59e27bc1..be1de7bc6 100644 --- a/mrbgems/mruby-time/test/time.rb +++ b/mrbgems/mruby-time/test/time.rb @@ -239,7 +239,8 @@ assert('Time#to_s') do end assert('Time#inspect') do - assert_match("2013-10-28 16:27:48 [^U]*", Time.local(2013,10,28,16,27,48).inspect) + assert_match("2013-10-28 16:27:48 [+-][0-9][0-9][0-9][0-9]", + Time.local(2013,10,28,16,27,48).inspect) end assert('day of week methods') do -- cgit v1.2.3 From eea42e06af745f0a7ae68d0d364a8f71d72823fe Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Thu, 1 Aug 2019 13:13:32 +0900 Subject: Add new specifiers/modifiers to format string of `mrb_vfromat()` Format sequence syntax: %[modifier]specifier Modifiers: ----------+------------------------------------------------------------ Modifier | Meaning ----------+------------------------------------------------------------ ! | Convert to string by corresponding `inspect` instead of | corresponding `to_s`. ----------+------------------------------------------------------------ Specifiers: ----------+----------------+-------------------------------------------- Specifier | Argument Type | Note ----------+----------------+-------------------------------------------- c | char | d,i | mrb_int | f | mrb_float | l | char*, mrb_int | Arguments are string and length. n | mrb_sym | s | char* | Argument is NUL terminated string. t | mrb_value | Convert to type (class) of object. v,S | mrb_value | C | struct RClass* | T | mrb_value | Convert to real type (class) of object. Y | mrb_value | Same as `!v` if argument is `true`, `false` | | or `nil`, otherwise same as `T`. % | - | Convert to percent sign itself (no argument | | taken). ----------+----------------+-------------------------------------------- This change will increase the binary size, but replacing all format strings with new specifiers/modifiers will decrease the size because it reduces inline expansion of `mrb_obj_value()`, etc. at the caller. --- mrbgems/mruby-test/driver.c | 3 + mrbgems/mruby-test/mrbgem.rake | 7 +- mrbgems/mruby-test/vformat.c | 186 +++++++++++++++++++++++++++++++++++++++++ src/error.c | 162 ++++++++++++++++++++++++++--------- test/t/vformat.rb | 88 +++++++++++++++++++ 5 files changed, 404 insertions(+), 42 deletions(-) create mode 100644 mrbgems/mruby-test/vformat.c create mode 100644 test/t/vformat.rb diff --git a/mrbgems/mruby-test/driver.c b/mrbgems/mruby-test/driver.c index b6c9fab35..a5f723927 100644 --- a/mrbgems/mruby-test/driver.c +++ b/mrbgems/mruby-test/driver.c @@ -21,6 +21,7 @@ extern const uint8_t mrbtest_assert_irep[]; void mrbgemtest_init(mrb_state* mrb); +void mrb_init_test_vformat(mrb_state* mrb); /* Print a short remark for the user */ static void @@ -231,6 +232,8 @@ mrb_init_test_driver(mrb_state *mrb, mrb_bool verbose) #endif #endif + mrb_init_test_vformat(mrb); + if (verbose) { mrb_gv_set(mrb, mrb_intern_lit(mrb, "$mrbtest_verbose"), mrb_true_value()); } diff --git a/mrbgems/mruby-test/mrbgem.rake b/mrbgems/mruby-test/mrbgem.rake index dcb7bb719..bf90e0791 100644 --- a/mrbgems/mruby-test/mrbgem.rake +++ b/mrbgems/mruby-test/mrbgem.rake @@ -15,8 +15,9 @@ MRuby::Gem::Specification.new('mruby-test') do |spec| mrbtest_lib = libfile("#{build_dir}/mrbtest") mrbtest_objs = [] - driver_obj = objfile("#{build_dir}/driver") - # driver = "#{spec.dir}/driver.c" + driver_objs = Dir.glob("#{dir}/*.{c,cpp,cxx,cc,m,asm,s,S}").map do |f| + objfile(f.relative_path_from(dir).to_s.pathmap("#{build_dir}/%X")) + end assert_c = "#{build_dir}/assert.c" assert_rb = "#{MRUBY_ROOT}/test/assert.rb" @@ -133,7 +134,7 @@ MRuby::Gem::Specification.new('mruby-test') do |spec| end unless build.build_mrbtest_lib_only? - file exec => [driver_obj, mlib, mrbtest_lib, build.libmruby_static] do |t| + file exec => [*driver_objs, mlib, mrbtest_lib, build.libmruby_static] do |t| gem_flags = build.gems.map { |g| g.linker.flags } gem_flags_before_libraries = build.gems.map { |g| g.linker.flags_before_libraries } gem_flags_after_libraries = build.gems.map { |g| g.linker.flags_after_libraries } diff --git a/mrbgems/mruby-test/vformat.c b/mrbgems/mruby-test/vformat.c new file mode 100644 index 000000000..a10e49b08 --- /dev/null +++ b/mrbgems/mruby-test/vformat.c @@ -0,0 +1,186 @@ +#include +#include +#include +#include +#include + +#define NATIVE_TYPES \ + char c; \ + mrb_float f; \ + mrb_int i; \ + mrb_sym n; \ + char *s; \ + struct RClass *C + +typedef enum { + ARG_c, + ARG_f, + ARG_i, + ARG_n, + ARG_s, + ARG_C, + ARG_v, +} VFArgumentType; + +typedef struct { + VFArgumentType type; + union { NATIVE_TYPES; }; +} VFNative; + +typedef struct { + VFArgumentType type; + union { + NATIVE_TYPES; + mrb_value v; + }; +} VFArgument; + +static void +native_free(mrb_state *mrb, void *data) +{ + VFNative *native = (VFNative*)data; + if (native->type == ARG_s) mrb_free(mrb, native->s); + mrb_free(mrb, native); +} + +static const struct mrb_data_type native_data_type = { + "TestVFormat::Native", native_free +}; + +static mrb_value +native_initialize(mrb_state *mrb, mrb_value self) +{ + VFNative data, *datap; + mrb_value obj; + + mrb_get_args(mrb, "o", &obj); + switch (mrb_type(obj)) { + case MRB_TT_FLOAT: + data.f = mrb_float(obj); + data.type = ARG_f; + break; + case MRB_TT_FIXNUM: + data.i = mrb_fixnum(obj); + data.type = ARG_i; + break; + case MRB_TT_SYMBOL: + data.n = mrb_symbol(obj); + data.type = ARG_n; + break; + case MRB_TT_CLASS: case MRB_TT_SCLASS: case MRB_TT_MODULE: + data.C = mrb_class_ptr(obj); + data.type = ARG_C; + break; + case MRB_TT_STRING: { + mrb_int len = RSTRING_LEN(obj); + const char *s = RSTRING_PTR(obj); + if (len == 1) { + /* one byte string is considered char */ + data.c = s[0]; + data.type = ARG_c; + } + else { + data.s = (char*)mrb_malloc(mrb, len + 1); + memcpy(data.s, s, len); + data.s[len] = '\0'; + data.type = ARG_s; + } + break; + } + default: { + mrb_value msg = mrb_str_new_cstr(mrb, "native type for "); + mrb_str_cat_cstr(mrb, msg, mrb_class_name(mrb, mrb_class(mrb, obj))); + mrb_str_cat_cstr(mrb, msg, " is unknown"); + mrb_raise(mrb, E_ARGUMENT_ERROR, RSTRING_PTR(msg)); + } + } + + datap = (VFNative*)mrb_malloc(mrb, sizeof(VFNative)); + *datap = data; + mrb_data_init(self, datap, &native_data_type); + return self; +} + +static VFArgument* +arg_from_obj(mrb_state *mrb, mrb_value obj, struct RClass *native_class, + VFArgument *vf_arg) +{ + if (mrb_obj_is_instance_of(mrb, obj, native_class)) { + const VFNative *native = (VFNative*)DATA_PTR(obj); + *(VFNative*)vf_arg = *native; + } + else { + vf_arg->v = obj; + vf_arg->type = ARG_v; + } + return vf_arg; +} + +#define VF_FORMAT_INIT(klass) \ + struct RClass *vf_native_class = \ + mrb_class_get_under(mrb, mrb_class_ptr(klass), "Native"); \ + VFArgument vf_args[2]; + +#define VF_ARG(args, idx) \ + arg_from_obj(mrb, args[idx], vf_native_class, &vf_args[idx]) + +#define VF_FORMAT0(fmt) mrb_format(mrb, fmt); +#define VF_FORMAT1(fmt, args) \ + (VF_ARG(args, 0), VF_FORMAT_TYPED(fmt, 1, vf_args, NULL)) +#define VF_FORMAT2(fmt, args) ( \ + VF_ARG(args, 0), VF_ARG(args, 1), \ + VF_FORMAT2_COND_EXPR(fmt, vf_args, vf_args+1, c) : \ + VF_FORMAT2_COND_EXPR(fmt, vf_args, vf_args+1, f) : \ + VF_FORMAT2_COND_EXPR(fmt, vf_args, vf_args+1, i) : \ + VF_FORMAT2_COND_EXPR(fmt, vf_args, vf_args+1, n) : \ + VF_FORMAT2_COND_EXPR(fmt, vf_args, vf_args+1, s) : \ + VF_FORMAT2_COND_EXPR(fmt, vf_args, vf_args+1, C) : \ + VF_FORMAT2_COND_EXPR(fmt, vf_args, vf_args+1, v) : \ + mrb_nil_value() /* not reached */ \ +) +#define VF_FORMAT2_COND_EXPR(fmt, a1, a2, t) \ + a1->type == ARG_##t ? VF_FORMAT_TYPED(fmt, 2, a2, (a1)->t) +#define VF_FORMAT_TYPED(fmt, n_arg, type_a, v1) \ + VF_FORMAT_TYPED_COND_EXPR(fmt, n_arg, type_a, v1, c) : \ + VF_FORMAT_TYPED_COND_EXPR(fmt, n_arg, type_a, v1, f) : \ + VF_FORMAT_TYPED_COND_EXPR(fmt, n_arg, type_a, v1, i) : \ + VF_FORMAT_TYPED_COND_EXPR(fmt, n_arg, type_a, v1, n) : \ + VF_FORMAT_TYPED_COND_EXPR(fmt, n_arg, type_a, v1, s) : \ + VF_FORMAT_TYPED_COND_EXPR(fmt, n_arg, type_a, v1, C) : \ + VF_FORMAT_TYPED_COND_EXPR(fmt, n_arg, type_a, v1, v) : \ + mrb_nil_value() /* not reached */ +#define VF_FORMAT_TYPED_COND_EXPR(fmt, n_arg, type_a, v1, t) \ + (type_a)->type == ARG_##t ? n_arg == 1 ? \ + mrb_format(mrb, fmt, (type_a)->t) : mrb_format(mrb, fmt, v1, (type_a)->t) + +static mrb_value +vf_s_format(mrb_state *mrb, mrb_value klass) +{ + mrb_value fmt_str, args[2]; + mrb_int argc = mrb_get_args(mrb, "S|oo", &fmt_str, args, args+1); + const char *fmt = mrb_string_value_cstr(mrb, &fmt_str); + + VF_FORMAT_INIT(klass); + + switch (argc) { + case 1: return VF_FORMAT0(fmt); + case 2: return VF_FORMAT1(fmt, args); + case 3: return VF_FORMAT2(fmt, args); + default: return mrb_nil_value(); /* not reached */ + } +} + +void +mrb_init_test_vformat(mrb_state *mrb) +{ + struct RClass *vf, *n; + + vf = mrb_define_module(mrb, "TestVFormat"); + mrb_define_class_method(mrb, vf, "format", vf_s_format, MRB_ARGS_ARG(1,2)); + + n = mrb_define_class_under(mrb, vf, "Native", mrb->object_class); + MRB_SET_INSTANCE_TT(n, MRB_TT_DATA); + mrb_define_method(mrb, n, "initialize", native_initialize, MRB_ARGS_REQ(1)); + mrb_singleton_class(mrb, mrb_obj_value(n)); + mrb_define_alias(mrb, n->c, "[]", "new"); +} diff --git a/src/error.c b/src/error.c index 4c1b67c99..d8224622b 100644 --- a/src/error.c +++ b/src/error.c @@ -260,59 +260,143 @@ mrb_raise(mrb_state *mrb, struct RClass *c, const char *msg) mrb_exc_raise(mrb, mrb_exc_new_str(mrb, c, mrb_str_new_cstr(mrb, msg))); } +/* + * vsprintf like formatting. + * + * The syntax of a format sequence is as follows. + * + * %[modifier]specifier + * + * The modifiers are: + * + * ----------+------------------------------------------------------------ + * Modifier | Meaning + * ----------+------------------------------------------------------------ + * ! | Convert to string by corresponding `inspect` instead of + * | corresponding `to_s`. + * ----------+------------------------------------------------------------ + * + * The specifiers are: + * + * ----------+----------------+-------------------------------------------- + * Specifier | Argument Type | Note + * ----------+----------------+-------------------------------------------- + * c | char | + * d,i | mrb_int | + * f | mrb_float | + * l | char*, mrb_int | Arguments are string and length. + * n | mrb_sym | + * s | char* | Argument is NUL terminated string. + * t | mrb_value | Convert to type (class) of object. + * v,S | mrb_value | + * C | struct RClass* | + * T | mrb_value | Convert to real type (class) of object. + * Y | mrb_value | Same as `!v` if argument is `true`, `false` + * | | or `nil`, otherwise same as `T`. + * % | - | Convert to percent sign itself (no argument + * | | taken). + * ----------+----------------+-------------------------------------------- + */ MRB_API mrb_value mrb_vformat(mrb_state *mrb, const char *format, va_list ap) { - const char *p = format; - const char *b = p; - ptrdiff_t size; - int ai0 = mrb_gc_arena_save(mrb); - mrb_value ary = mrb_ary_new_capa(mrb, 4); + const char *chars, *p = format, *b = format, *e; + char ch; + struct RClass *cls; + mrb_int len; + mrb_bool inspect = FALSE; + mrb_value result = mrb_str_new_capa(mrb, 128), obj, str; int ai = mrb_gc_arena_save(mrb); while (*p) { const char c = *p++; - + e = p; if (c == '%') { - if (*p == 'S') { - mrb_value val; - - size = p - b - 1; - mrb_ary_push(mrb, ary, mrb_str_new(mrb, b, size)); - val = va_arg(ap, mrb_value); - mrb_ary_push(mrb, ary, mrb_obj_as_string(mrb, val)); - b = p + 1; + if (*p == '!') { + inspect = TRUE; + ++p; } - } - else if (c == '\\') { - if (*p) { - size = p - b - 1; - mrb_ary_push(mrb, ary, mrb_str_new(mrb, b, size)); - mrb_ary_push(mrb, ary, mrb_str_new(mrb, p, 1)); - b = ++p; - } - else { - break; + if (!*p) break; + switch (*p) { + case 'c': + ch = (char)va_arg(ap, int); + chars = &ch; + len = 1; + goto L_cat; + case 'd': case 'i': + obj = mrb_fixnum_value(va_arg(ap, mrb_int)); + goto L_cat_obj; + case 'f': + obj = mrb_float_value(mrb, va_arg(ap, mrb_float)); + goto L_cat_obj; + case 'l': + chars = va_arg(ap, char*); + len = va_arg(ap, mrb_int); + L_cat: + if (inspect) { + obj = mrb_str_new(mrb, chars, len); + goto L_cat_obj; + } + mrb_str_cat(mrb, result, b, e - b - 1); + mrb_str_cat(mrb, result, chars, len); + b = ++p; + mrb_gc_arena_restore(mrb, ai); + break; + case 'n': + obj = mrb_symbol_value(va_arg(ap, mrb_sym)); + goto L_cat_obj; + case 's': + chars = va_arg(ap, char*); + len = strlen(chars); + goto L_cat; + case 't': + cls = mrb_class(mrb, va_arg(ap, mrb_value)); + goto L_cat_class; + case 'v': case 'S': + obj = va_arg(ap, mrb_value); + L_cat_obj: + str = (inspect ? mrb_inspect : mrb_obj_as_string)(mrb, obj); + chars = RSTRING_PTR(str); + len = RSTRING_LEN(str); + inspect = FALSE; + goto L_cat; + case 'C': + cls = va_arg(ap, struct RClass*); + L_cat_class: + obj = mrb_obj_value(cls); + goto L_cat_obj; + case 'T': + obj = va_arg(ap, mrb_value); + L_cat_real_class_of: + cls = mrb_obj_class(mrb, obj); + goto L_cat_class; + case 'Y': + obj = va_arg(ap, mrb_value); + if (!mrb_test(obj) || mrb_true_p(obj)) { + inspect = TRUE; + goto L_cat_obj; + } + else { + goto L_cat_real_class_of; + } + case '%': + L_cat_current: + chars = p; + len = 1; + goto L_cat; + default: + mrb_raisef(mrb, E_ARGUMENT_ERROR, "malformed format string - %%%c", *p); } } - mrb_gc_arena_restore(mrb, ai); - } - if (b == format) { - mrb_gc_arena_restore(mrb, ai0); - return mrb_str_new_cstr(mrb, format); - } - else { - mrb_value val; + else if (c == '\\') { + if (!*p) break; + goto L_cat_current; - size = p - b; - if (size > 0) { - mrb_ary_push(mrb, ary, mrb_str_new(mrb, b, size)); } - val = mrb_ary_join(mrb, ary, mrb_nil_value()); - mrb_gc_arena_restore(mrb, ai0); - mrb_gc_protect(mrb, val); - return val; } + + mrb_str_cat(mrb, result, b, p - b); + return result; } MRB_API mrb_value diff --git a/test/t/vformat.rb b/test/t/vformat.rb new file mode 100644 index 000000000..2270d6490 --- /dev/null +++ b/test/t/vformat.rb @@ -0,0 +1,88 @@ +def assert_format(exp, args) + assert_equal(exp, TestVFormat.format(*args)) +end + +def assert_format_pattern(exp_pattern, args) + assert_match(exp_pattern, TestVFormat.format(*args)) +end + +# Pass if ArgumentError is raised or return value is +exp+. +def assert_implementation_dependent(exp, args) + begin + ret = TestVFormat.format(*args) + rescue ArgumentError + return pass + end + if ret == exp + pass + else + flunk "", "Expected ArgumentError is raised or #{ret.inspect} to be #{exp}." + end +end + +def sclass(v) + class << v + self + end +end + +assert('mrb_vformat') do + n = TestVFormat::Native + assert_format '', [''] + assert_format 'No specifier!', ['No specifier!'] + assert_format '`c`: C', ['`c`: %c', n[?C]] + assert_format '`d`: 123', ['`d`: %d', n[123]] + assert_format '`i`: -83', ['`i`: %i', n[-83]] + assert_format '`f`: 0.0125', ['`f`: %f', n[0.0125]] + assert_format '`t`: NilClass', ['`t`: %t', nil] + assert_format '`t`: FalseClass', ['`t`: %t', false] + assert_format '`t`: TrueClass', ['`t`: %t', true] + assert_format '`t`: Fixnum', ['`t`: %t', 0] + assert_format '`t`: Hash', ['`t`: %t', k: "value"] + assert_format_pattern '#>>', ['%t', sclass({})] + assert_format '-Infinity', ['%f', n[-Float::INFINITY]] + assert_format 'NaN: Not a Number', ['%f: Not a Number', n[Float::NAN]] + assert_format 'string and length', ['string %l length', n['andante'], n[3]] + assert_format '`n`: sym', ['`n`: %n', n[:sym]] + assert_format '%C文字列%', ['%s', n['%C文字列%']] + assert_format '`C`: Kernel module', ['`C`: %C module', n[Kernel]] + assert_format '`C`: NilClass', ['`C`: %C', n[nil.class]] + assert_format_pattern '#>', ['%C', n[sclass("")]] + assert_format '`T`: NilClass', ['`T`: %T', nil] + assert_format '`T`: FalseClass', ['`T`: %T', false] + assert_format '`T`: TrueClass', ['`T`: %T', true] + assert_format '`T`: Fixnum', ['`T`: %T', 0] + assert_format '`T`: Hash', ['`T`: %T', k: "value"] + assert_format_pattern 'Class', ['%T', sclass({})] + assert_format '`Y`: nil', ['`Y`: %Y', nil] + assert_format '`Y`: false', ['`Y`: %Y', false] + assert_format '`Y`: true', ['`Y`: %Y', true] + assert_format '`Y`: Fixnum', ['`Y`: %Y', 0] + assert_format '`Y`: Hash', ['`Y`: %Y', k: "value"] + assert_format 'Class', ['%Y', sclass({})] + assert_format_pattern '#>', ['%v', sclass("")] + assert_format '`v`: 1...3', ['`v`: %v', 1...3] + assert_format '`S`: {:a=>1, "b"=>"c"}', ['`S`: %S', a: 1, "b" => ?c] + assert_format 'percent: %', ['percent: %%'] + assert_format '"I": inspect char', ['%!c: inspect char', n[?I]] + assert_format '709: inspect mrb_int', ['%!d: inspect mrb_int', n[709]] + assert_format '"a\x00b\xff"', ['%!l', n["a\000b\xFFc\000d"], n[4]] + assert_format ':"&.": inspect symbol', ['%!n: inspect symbol', n['&.'.to_sym]] + assert_format 'inspect "String"', ['inspect %!v', 'String'] + assert_format 'inspect Array: [1, :x, {}]', ['inspect Array: %!v', [1,:x,{}]] + assert_format_pattern '`!C`: #', ['`!C`: %!C', n[Class.new]] + assert_format 'to_s -> to_s: ab,cd', ['to_s -> to_s: %n,%v', n[:ab], 'cd'] + assert_format 'to_s -> inspect: x:y', ['to_s -> inspect: %v%!v', 'x', :y] + assert_format 'inspect -> to_s: "a"b', ['inspect -> to_s: %!v%n', 'a', n[:b]] + assert_format 'Y -> to_s: nile', ['Y -> to_s: %Y%v', nil, "e"] + assert_format '"abc":Z', ['%!s%!n', n['abc'], n[:Z]] + assert_format 'escape: \\%a,b,c,d', ['escape: \\\\\%a,b,\c%v', ',d'] + + assert_implementation_dependent 'unknown specifier: %^', + ['unknown specifier: %^'] + assert_implementation_dependent 'unknown specifier with modifier: %!^', + ['unknown specifier with modifier: %!^'] + assert_implementation_dependent 'termination is \\', ['termination is \\'] + assert_implementation_dependent 'termination is %', ['termination is %'] + assert_implementation_dependent 'termination is %!', ['termination is %!'] +end -- cgit v1.2.3 From d1817e77910a2747d2bc602964a5f51a1490a252 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Fri, 2 Aug 2019 17:15:34 +0900 Subject: Change the `mrb_vformat` specifier `%d` for `int` It potentially breaks, for example, in the case of `mrb_int` is 64-bit and more smaller type is passed by `%d`. In fact, the problem could become apparent when I used `%d` to `backtrace_location::lineno` in `src/backtrace.c:mrb_unpack_backtrace()` on AppVeyor. Therefore, change `%d` for `int` (not `mrb_int`) so that it can be used mostly without casting. --- mrbgems/mruby-test/vformat.c | 90 ++++++++++++++++++++++---------------------- src/error.c | 8 ++-- test/t/vformat.rb | 42 +++++++++++---------- 3 files changed, 73 insertions(+), 67 deletions(-) diff --git a/mrbgems/mruby-test/vformat.c b/mrbgems/mruby-test/vformat.c index a10e49b08..e6581d6be 100644 --- a/mrbgems/mruby-test/vformat.c +++ b/mrbgems/mruby-test/vformat.c @@ -6,14 +6,28 @@ #define NATIVE_TYPES \ char c; \ + int d; \ mrb_float f; \ mrb_int i; \ mrb_sym n; \ char *s; \ struct RClass *C +#define NATIVE_DEFINE_TYPE_FUNC(t) \ + static mrb_value \ + native_s_##t(mrb_state *mrb, mrb_value klass) \ + { \ + mrb_value obj, type = mrb_fixnum_value(ARG_##t); \ + mrb_get_args(mrb, "o", &obj); \ + return mrb_funcall(mrb, klass, "new", 2, type, obj); \ + } + +#define NATIVE_DEFINE_TYPE_METHOD(t) \ + mrb_define_class_method(mrb, n, #t, native_s_##t, MRB_ARGS_REQ(1)) + typedef enum { ARG_c, + ARG_d, ARG_f, ARG_i, ARG_n, @@ -51,56 +65,37 @@ static mrb_value native_initialize(mrb_state *mrb, mrb_value self) { VFNative data, *datap; + mrb_int type; mrb_value obj; - mrb_get_args(mrb, "o", &obj); - switch (mrb_type(obj)) { - case MRB_TT_FLOAT: - data.f = mrb_float(obj); - data.type = ARG_f; - break; - case MRB_TT_FIXNUM: - data.i = mrb_fixnum(obj); - data.type = ARG_i; - break; - case MRB_TT_SYMBOL: - data.n = mrb_symbol(obj); - data.type = ARG_n; - break; - case MRB_TT_CLASS: case MRB_TT_SCLASS: case MRB_TT_MODULE: - data.C = mrb_class_ptr(obj); - data.type = ARG_C; - break; - case MRB_TT_STRING: { - mrb_int len = RSTRING_LEN(obj); - const char *s = RSTRING_PTR(obj); - if (len == 1) { - /* one byte string is considered char */ - data.c = s[0]; - data.type = ARG_c; - } - else { - data.s = (char*)mrb_malloc(mrb, len + 1); - memcpy(data.s, s, len); - data.s[len] = '\0'; - data.type = ARG_s; - } - break; - } - default: { - mrb_value msg = mrb_str_new_cstr(mrb, "native type for "); - mrb_str_cat_cstr(mrb, msg, mrb_class_name(mrb, mrb_class(mrb, obj))); - mrb_str_cat_cstr(mrb, msg, " is unknown"); - mrb_raise(mrb, E_ARGUMENT_ERROR, RSTRING_PTR(msg)); - } + mrb_get_args(mrb, "io", &type, &obj); + data.type = (VFArgumentType)type; + switch (data.type) { + case ARG_c: data.c = RSTRING_PTR(obj)[0]; break; + case ARG_d: data.d = (int)mrb_fixnum(obj); break; + case ARG_f: data.f = mrb_float(obj); break; + case ARG_i: data.i = mrb_fixnum(obj); break; + case ARG_n: data.n = mrb_symbol(obj); break; + case ARG_s: data.s = (char*)mrb_malloc(mrb, RSTRING_LEN(obj) + 1); + memcpy(data.s, RSTRING_PTR(obj), RSTRING_LEN(obj)); + data.s[RSTRING_LEN(obj)] = '\0'; break; + case ARG_C: data.C = mrb_class_ptr(obj); break; + default: mrb_raise(mrb, E_ARGUMENT_ERROR, "unknown type"); } - datap = (VFNative*)mrb_malloc(mrb, sizeof(VFNative)); *datap = data; mrb_data_init(self, datap, &native_data_type); return self; } +NATIVE_DEFINE_TYPE_FUNC(c) +NATIVE_DEFINE_TYPE_FUNC(d) +NATIVE_DEFINE_TYPE_FUNC(f) +NATIVE_DEFINE_TYPE_FUNC(i) +NATIVE_DEFINE_TYPE_FUNC(n) +NATIVE_DEFINE_TYPE_FUNC(s) +NATIVE_DEFINE_TYPE_FUNC(C) + static VFArgument* arg_from_obj(mrb_state *mrb, mrb_value obj, struct RClass *native_class, VFArgument *vf_arg) @@ -130,6 +125,7 @@ arg_from_obj(mrb_state *mrb, mrb_value obj, struct RClass *native_class, #define VF_FORMAT2(fmt, args) ( \ VF_ARG(args, 0), VF_ARG(args, 1), \ VF_FORMAT2_COND_EXPR(fmt, vf_args, vf_args+1, c) : \ + VF_FORMAT2_COND_EXPR(fmt, vf_args, vf_args+1, d) : \ VF_FORMAT2_COND_EXPR(fmt, vf_args, vf_args+1, f) : \ VF_FORMAT2_COND_EXPR(fmt, vf_args, vf_args+1, i) : \ VF_FORMAT2_COND_EXPR(fmt, vf_args, vf_args+1, n) : \ @@ -142,6 +138,7 @@ arg_from_obj(mrb_state *mrb, mrb_value obj, struct RClass *native_class, a1->type == ARG_##t ? VF_FORMAT_TYPED(fmt, 2, a2, (a1)->t) #define VF_FORMAT_TYPED(fmt, n_arg, type_a, v1) \ VF_FORMAT_TYPED_COND_EXPR(fmt, n_arg, type_a, v1, c) : \ + VF_FORMAT_TYPED_COND_EXPR(fmt, n_arg, type_a, v1, d) : \ VF_FORMAT_TYPED_COND_EXPR(fmt, n_arg, type_a, v1, f) : \ VF_FORMAT_TYPED_COND_EXPR(fmt, n_arg, type_a, v1, i) : \ VF_FORMAT_TYPED_COND_EXPR(fmt, n_arg, type_a, v1, n) : \ @@ -180,7 +177,12 @@ mrb_init_test_vformat(mrb_state *mrb) n = mrb_define_class_under(mrb, vf, "Native", mrb->object_class); MRB_SET_INSTANCE_TT(n, MRB_TT_DATA); - mrb_define_method(mrb, n, "initialize", native_initialize, MRB_ARGS_REQ(1)); - mrb_singleton_class(mrb, mrb_obj_value(n)); - mrb_define_alias(mrb, n->c, "[]", "new"); + NATIVE_DEFINE_TYPE_METHOD(c); + NATIVE_DEFINE_TYPE_METHOD(d); + NATIVE_DEFINE_TYPE_METHOD(f); + NATIVE_DEFINE_TYPE_METHOD(i); + NATIVE_DEFINE_TYPE_METHOD(n); + NATIVE_DEFINE_TYPE_METHOD(s); + NATIVE_DEFINE_TYPE_METHOD(C); + mrb_define_method(mrb, n, "initialize", native_initialize, MRB_ARGS_REQ(2)); } diff --git a/src/error.c b/src/error.c index d8224622b..6e7c3763a 100644 --- a/src/error.c +++ b/src/error.c @@ -282,8 +282,9 @@ mrb_raise(mrb_state *mrb, struct RClass *c, const char *msg) * Specifier | Argument Type | Note * ----------+----------------+-------------------------------------------- * c | char | - * d,i | mrb_int | + * d | int | * f | mrb_float | + * i | mrb_int | * l | char*, mrb_int | Arguments are string and length. * n | mrb_sym | * s | char* | Argument is NUL terminated string. @@ -303,7 +304,7 @@ mrb_vformat(mrb_state *mrb, const char *format, va_list ap) const char *chars, *p = format, *b = format, *e; char ch; struct RClass *cls; - mrb_int len; + mrb_int len, i; mrb_bool inspect = FALSE; mrb_value result = mrb_str_new_capa(mrb, 128), obj, str; int ai = mrb_gc_arena_save(mrb); @@ -324,7 +325,8 @@ mrb_vformat(mrb_state *mrb, const char *format, va_list ap) len = 1; goto L_cat; case 'd': case 'i': - obj = mrb_fixnum_value(va_arg(ap, mrb_int)); + i = *p == 'd' ? (mrb_int)va_arg(ap, int) : va_arg(ap, mrb_int); + obj = mrb_fixnum_value(i); goto L_cat_obj; case 'f': obj = mrb_float_value(mrb, va_arg(ap, mrb_float)); diff --git a/test/t/vformat.rb b/test/t/vformat.rb index 2270d6490..d124e92b2 100644 --- a/test/t/vformat.rb +++ b/test/t/vformat.rb @@ -30,24 +30,26 @@ assert('mrb_vformat') do n = TestVFormat::Native assert_format '', [''] assert_format 'No specifier!', ['No specifier!'] - assert_format '`c`: C', ['`c`: %c', n[?C]] - assert_format '`d`: 123', ['`d`: %d', n[123]] - assert_format '`i`: -83', ['`i`: %i', n[-83]] - assert_format '`f`: 0.0125', ['`f`: %f', n[0.0125]] + assert_format '`c`: C', ['`c`: %c', n.c(?C)] + assert_format '`d`: 123', ['`d`: %d', n.d(123)] + assert_format '`d`: -79', ['`d`: %d', n.d(-79)] + assert_format '`i`: 514', ['`i`: %i', n.i(514)] + assert_format '`i`: -83', ['`i`: %i', n.i(-83)] + assert_format '`f`: 0.0125', ['`f`: %f', n.f(0.0125)] assert_format '`t`: NilClass', ['`t`: %t', nil] assert_format '`t`: FalseClass', ['`t`: %t', false] assert_format '`t`: TrueClass', ['`t`: %t', true] assert_format '`t`: Fixnum', ['`t`: %t', 0] assert_format '`t`: Hash', ['`t`: %t', k: "value"] assert_format_pattern '#>>', ['%t', sclass({})] - assert_format '-Infinity', ['%f', n[-Float::INFINITY]] - assert_format 'NaN: Not a Number', ['%f: Not a Number', n[Float::NAN]] - assert_format 'string and length', ['string %l length', n['andante'], n[3]] - assert_format '`n`: sym', ['`n`: %n', n[:sym]] - assert_format '%C文字列%', ['%s', n['%C文字列%']] - assert_format '`C`: Kernel module', ['`C`: %C module', n[Kernel]] - assert_format '`C`: NilClass', ['`C`: %C', n[nil.class]] - assert_format_pattern '#>', ['%C', n[sclass("")]] + assert_format '-Infinity', ['%f', n.f(-Float::INFINITY)] + assert_format 'NaN: Not a Number', ['%f: Not a Number', n.f(Float::NAN)] + assert_format 'string and length', ['string %l length', n.s('andante'), n.i(3)] + assert_format '`n`: sym', ['`n`: %n', n.n(:sym)] + assert_format '%C文字列%', ['%s', n.s('%C文字列%')] + assert_format '`C`: Kernel module', ['`C`: %C module', n.C(Kernel)] + assert_format '`C`: NilClass', ['`C`: %C', n.C(nil.class)] + assert_format_pattern '#>', ['%C', n.C(sclass(""))] assert_format '`T`: NilClass', ['`T`: %T', nil] assert_format '`T`: FalseClass', ['`T`: %T', false] assert_format '`T`: TrueClass', ['`T`: %T', true] @@ -64,18 +66,18 @@ assert('mrb_vformat') do assert_format '`v`: 1...3', ['`v`: %v', 1...3] assert_format '`S`: {:a=>1, "b"=>"c"}', ['`S`: %S', a: 1, "b" => ?c] assert_format 'percent: %', ['percent: %%'] - assert_format '"I": inspect char', ['%!c: inspect char', n[?I]] - assert_format '709: inspect mrb_int', ['%!d: inspect mrb_int', n[709]] - assert_format '"a\x00b\xff"', ['%!l', n["a\000b\xFFc\000d"], n[4]] - assert_format ':"&.": inspect symbol', ['%!n: inspect symbol', n['&.'.to_sym]] + assert_format '"I": inspect char', ['%!c: inspect char', n.c(?I)] + assert_format '709: inspect mrb_int', ['%!d: inspect mrb_int', n.i(709)] + assert_format '"a\x00b\xff"', ['%!l', n.s("a\000b\xFFc\000d"), n.i(4)] + assert_format ':"&.": inspect symbol', ['%!n: inspect symbol', n.n(:'&.')] assert_format 'inspect "String"', ['inspect %!v', 'String'] assert_format 'inspect Array: [1, :x, {}]', ['inspect Array: %!v', [1,:x,{}]] - assert_format_pattern '`!C`: #', ['`!C`: %!C', n[Class.new]] - assert_format 'to_s -> to_s: ab,cd', ['to_s -> to_s: %n,%v', n[:ab], 'cd'] + assert_format_pattern '`!C`: #', ['`!C`: %!C', n.C(Class.new)] + assert_format 'to_s -> to_s: ab,cd', ['to_s -> to_s: %n,%v', n.n(:ab), 'cd'] assert_format 'to_s -> inspect: x:y', ['to_s -> inspect: %v%!v', 'x', :y] - assert_format 'inspect -> to_s: "a"b', ['inspect -> to_s: %!v%n', 'a', n[:b]] + assert_format 'inspect -> to_s: "a"b', ['inspect -> to_s: %!v%n', 'a', n.n(:b)] assert_format 'Y -> to_s: nile', ['Y -> to_s: %Y%v', nil, "e"] - assert_format '"abc":Z', ['%!s%!n', n['abc'], n[:Z]] + assert_format '"abc":Z', ['%!s%!n', n.s('abc'), n.n('Z'.to_sym)] assert_format 'escape: \\%a,b,c,d', ['escape: \\\\\%a,b,\c%v', ',d'] assert_implementation_dependent 'unknown specifier: %^', -- cgit v1.2.3 From 07308a2fc9f01a1abfe2a4f464f8509ca4697cf8 Mon Sep 17 00:00:00 2001 From: dearblue Date: Sat, 3 Aug 2019 10:35:39 +0900 Subject: Suppress compiler warnings for mruby-time; fix #4600 Warnings: - If `MRB_TIME_T_UINT` is defined, the compiler issues a warning with an integer comparison of different signs. - It is mentioned that the `usec` variable passed to the `mrb_to_time_t()` function may not be initialized --- mrbgems/mruby-time/src/time.c | 42 +++++++++++++++--------------------------- 1 file changed, 15 insertions(+), 27 deletions(-) diff --git a/mrbgems/mruby-time/src/time.c b/mrbgems/mruby-time/src/time.c index 0d144c4e7..16461095c 100644 --- a/mrbgems/mruby-time/src/time.c +++ b/mrbgems/mruby-time/src/time.c @@ -213,6 +213,16 @@ typedef mrb_int mrb_sec; #define mrb_sec_value(mrb, sec) mrb_fixnum_value(sec) #endif +#ifdef MRB_TIME_T_UINT +typedef uint64_t mrb_time_int; +# define MRB_TIME_MIN 0 +# define MRB_TIME_MAX (sizeof(time_t) <= 4 ? UINT32_MAX : UINT64_MAX) +#else +typedef int64_t mrb_time_int; +# define MRB_TIME_MIN (sizeof(time_t) <= 4 ? INT32_MIN : INT64_MIN) +# define MRB_TIME_MAX (sizeof(time_t) <= 4 ? INT32_MAX : INT64_MAX) +#endif + static time_t mrb_to_time_t(mrb_state *mrb, mrb_value obj, time_t *usec) { @@ -225,21 +235,9 @@ mrb_to_time_t(mrb_state *mrb, mrb_value obj, time_t *usec) mrb_float f = mrb_float(obj); mrb_check_num_exact(mrb, f); -# ifndef MRB_TIME_T_UINT - if (sizeof(time_t) == 4 && (f > (mrb_float)INT32_MAX || (mrb_float)INT32_MIN > f)) { - goto out_of_range; - } - if (sizeof(time_t) == 8 && (f > (mrb_float)INT64_MAX || (mrb_float)INT64_MIN > f)) { - goto out_of_range; - } -# else - if (sizeof(time_t) == 4 && (f > (mrb_float)UINT32_MAX || (mrb_float)0 > f)) { - goto out_of_range; - } - if (sizeof(time_t) == 8 && (f > (mrb_float)UINT64_MAX || (mrb_float)0 > f)) { + if (f > (mrb_float)MRB_TIME_MAX || (mrb_float)MRB_TIME_MIN > f) { goto out_of_range; } -# endif if (usec) { t = (time_t)f; @@ -256,21 +254,9 @@ mrb_to_time_t(mrb_state *mrb, mrb_value obj, time_t *usec) { mrb_int i = mrb_int(mrb, obj); -#ifndef MRB_TIME_T_UINT - if (sizeof(time_t) == 4 && (i > INT32_MAX || INT32_MIN > i)) { - goto out_of_range; - } - if (sizeof(time_t) == 8 && (i > INT64_MAX || INT64_MIN > i)) { - goto out_of_range; - } -#else - if (sizeof(time_t) == 4 && (i > UINT32_MAX || 0 > i)) { - goto out_of_range; - } - if (sizeof(time_t) == 8 && (i > UINT64_MAX || 0 > i)) { + if ((mrb_time_int)i > MRB_TIME_MAX || MRB_TIME_MIN > i) { goto out_of_range; } -#endif t = (time_t)i; if (usec) { *usec = 0; } @@ -283,7 +269,9 @@ mrb_to_time_t(mrb_state *mrb, mrb_value obj, time_t *usec) out_of_range: mrb_raisef(mrb, E_ARGUMENT_ERROR, "%S out of Time range", obj); - return 0; /* suppress compiler warnings */ + /* not reached */ + if (usec) { *usec = 0; } + return 0; } /** Updates the datetime of a mrb_time based on it's timezone and -- cgit v1.2.3 From a4243360a2f8248dbf23b46ca14a7a59c0479b32 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Sat, 3 Aug 2019 11:54:45 +0900 Subject: Fix `mrb_vformat("%f")` with `MRB_USE_FLOAT` It potentially not work when `mrb_float` is `float` because `float` variable in variable length arguments is promoted to `double`. Also I fixed build with `MRB_WITHOUT_FLOAT`. --- mrbgems/mruby-test/vformat.c | 5 +++++ src/error.c | 4 +++- test/t/vformat.rb | 8 +++++--- 3 files changed, 13 insertions(+), 4 deletions(-) diff --git a/mrbgems/mruby-test/vformat.c b/mrbgems/mruby-test/vformat.c index e6581d6be..e02383f77 100644 --- a/mrbgems/mruby-test/vformat.c +++ b/mrbgems/mruby-test/vformat.c @@ -4,6 +4,11 @@ #include #include +#ifdef MRB_WITHOUT_FLOAT +typedef mrb_int mrb_float; +#define mrb_float(o) mrb_fixnum(o) +#endif + #define NATIVE_TYPES \ char c; \ int d; \ diff --git a/src/error.c b/src/error.c index 6e7c3763a..3ee137c95 100644 --- a/src/error.c +++ b/src/error.c @@ -328,9 +328,11 @@ mrb_vformat(mrb_state *mrb, const char *format, va_list ap) i = *p == 'd' ? (mrb_int)va_arg(ap, int) : va_arg(ap, mrb_int); obj = mrb_fixnum_value(i); goto L_cat_obj; +#ifndef MRB_WITHOUT_FLOAT case 'f': - obj = mrb_float_value(mrb, va_arg(ap, mrb_float)); + obj = mrb_float_value(mrb, (mrb_float)va_arg(ap, double)); goto L_cat_obj; +#endif case 'l': chars = va_arg(ap, char*); len = va_arg(ap, mrb_int); diff --git a/test/t/vformat.rb b/test/t/vformat.rb index d124e92b2..e99616064 100644 --- a/test/t/vformat.rb +++ b/test/t/vformat.rb @@ -35,15 +35,12 @@ assert('mrb_vformat') do assert_format '`d`: -79', ['`d`: %d', n.d(-79)] assert_format '`i`: 514', ['`i`: %i', n.i(514)] assert_format '`i`: -83', ['`i`: %i', n.i(-83)] - assert_format '`f`: 0.0125', ['`f`: %f', n.f(0.0125)] assert_format '`t`: NilClass', ['`t`: %t', nil] assert_format '`t`: FalseClass', ['`t`: %t', false] assert_format '`t`: TrueClass', ['`t`: %t', true] assert_format '`t`: Fixnum', ['`t`: %t', 0] assert_format '`t`: Hash', ['`t`: %t', k: "value"] assert_format_pattern '#>>', ['%t', sclass({})] - assert_format '-Infinity', ['%f', n.f(-Float::INFINITY)] - assert_format 'NaN: Not a Number', ['%f: Not a Number', n.f(Float::NAN)] assert_format 'string and length', ['string %l length', n.s('andante'), n.i(3)] assert_format '`n`: sym', ['`n`: %n', n.n(:sym)] assert_format '%C文字列%', ['%s', n.s('%C文字列%')] @@ -87,4 +84,9 @@ assert('mrb_vformat') do assert_implementation_dependent 'termination is \\', ['termination is \\'] assert_implementation_dependent 'termination is %', ['termination is %'] assert_implementation_dependent 'termination is %!', ['termination is %!'] + + skip unless Object.const_defined?(:Float) + assert_format '`f`: 0.0125', ['`f`: %f', n.f(0.0125)] + assert_format '-Infinity', ['%f', n.f(-Float::INFINITY)] + assert_format 'NaN: Not a Number', ['%f: Not a Number', n.f(Float::NAN)] end -- cgit v1.2.3 From 1e9cb74cc6dd2fbe1b68edf3b73c7acfe7fc7831 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Sat, 3 Aug 2019 17:46:11 +0900 Subject: Change second argument to `%l` of `mrb_vformat()` to `size_t` from `mrb_int` - `size_t` is more commonly used. - `len` argument of `mrb_str_new()` is `size_t`. NOTE: The test for `%l` is temporarily disabled because adding a new type to `mrbgems/mruby-test/vformat.c` causes an error (memory error?) on Visual Studio 2017 in AppVeyor. --- mrbgems/mruby-test/vformat.c | 7 +++++++ src/error.c | 7 ++++--- tasks/toolchains/visualcpp.rake | 2 +- test/t/vformat.rb | 4 ++-- 4 files changed, 14 insertions(+), 6 deletions(-) diff --git a/mrbgems/mruby-test/vformat.c b/mrbgems/mruby-test/vformat.c index e02383f77..6e0c2887f 100644 --- a/mrbgems/mruby-test/vformat.c +++ b/mrbgems/mruby-test/vformat.c @@ -14,6 +14,7 @@ typedef mrb_int mrb_float; int d; \ mrb_float f; \ mrb_int i; \ +/* size_t l; */\ mrb_sym n; \ char *s; \ struct RClass *C @@ -35,6 +36,7 @@ typedef enum { ARG_d, ARG_f, ARG_i, +/* ARG_l,*/ ARG_n, ARG_s, ARG_C, @@ -80,6 +82,7 @@ native_initialize(mrb_state *mrb, mrb_value self) case ARG_d: data.d = (int)mrb_fixnum(obj); break; case ARG_f: data.f = mrb_float(obj); break; case ARG_i: data.i = mrb_fixnum(obj); break; +/* case ARG_l: data.l = (size_t)mrb_fixnum(obj); break;*/ case ARG_n: data.n = mrb_symbol(obj); break; case ARG_s: data.s = (char*)mrb_malloc(mrb, RSTRING_LEN(obj) + 1); memcpy(data.s, RSTRING_PTR(obj), RSTRING_LEN(obj)); @@ -97,6 +100,7 @@ NATIVE_DEFINE_TYPE_FUNC(c) NATIVE_DEFINE_TYPE_FUNC(d) NATIVE_DEFINE_TYPE_FUNC(f) NATIVE_DEFINE_TYPE_FUNC(i) +/*NATIVE_DEFINE_TYPE_FUNC(l)*/ NATIVE_DEFINE_TYPE_FUNC(n) NATIVE_DEFINE_TYPE_FUNC(s) NATIVE_DEFINE_TYPE_FUNC(C) @@ -133,6 +137,7 @@ arg_from_obj(mrb_state *mrb, mrb_value obj, struct RClass *native_class, VF_FORMAT2_COND_EXPR(fmt, vf_args, vf_args+1, d) : \ VF_FORMAT2_COND_EXPR(fmt, vf_args, vf_args+1, f) : \ VF_FORMAT2_COND_EXPR(fmt, vf_args, vf_args+1, i) : \ +/* VF_FORMAT2_COND_EXPR(fmt, vf_args, vf_args+1, l) : */\ VF_FORMAT2_COND_EXPR(fmt, vf_args, vf_args+1, n) : \ VF_FORMAT2_COND_EXPR(fmt, vf_args, vf_args+1, s) : \ VF_FORMAT2_COND_EXPR(fmt, vf_args, vf_args+1, C) : \ @@ -146,6 +151,7 @@ arg_from_obj(mrb_state *mrb, mrb_value obj, struct RClass *native_class, VF_FORMAT_TYPED_COND_EXPR(fmt, n_arg, type_a, v1, d) : \ VF_FORMAT_TYPED_COND_EXPR(fmt, n_arg, type_a, v1, f) : \ VF_FORMAT_TYPED_COND_EXPR(fmt, n_arg, type_a, v1, i) : \ +/* VF_FORMAT_TYPED_COND_EXPR(fmt, n_arg, type_a, v1, l) : */\ VF_FORMAT_TYPED_COND_EXPR(fmt, n_arg, type_a, v1, n) : \ VF_FORMAT_TYPED_COND_EXPR(fmt, n_arg, type_a, v1, s) : \ VF_FORMAT_TYPED_COND_EXPR(fmt, n_arg, type_a, v1, C) : \ @@ -186,6 +192,7 @@ mrb_init_test_vformat(mrb_state *mrb) NATIVE_DEFINE_TYPE_METHOD(d); NATIVE_DEFINE_TYPE_METHOD(f); NATIVE_DEFINE_TYPE_METHOD(i); +/* NATIVE_DEFINE_TYPE_METHOD(l);*/ NATIVE_DEFINE_TYPE_METHOD(n); NATIVE_DEFINE_TYPE_METHOD(s); NATIVE_DEFINE_TYPE_METHOD(C); diff --git a/src/error.c b/src/error.c index 3ee137c95..0ca7f5917 100644 --- a/src/error.c +++ b/src/error.c @@ -285,7 +285,7 @@ mrb_raise(mrb_state *mrb, struct RClass *c, const char *msg) * d | int | * f | mrb_float | * i | mrb_int | - * l | char*, mrb_int | Arguments are string and length. + * l | char*, size_t | Arguments are string and length. * n | mrb_sym | * s | char* | Argument is NUL terminated string. * t | mrb_value | Convert to type (class) of object. @@ -303,8 +303,9 @@ mrb_vformat(mrb_state *mrb, const char *format, va_list ap) { const char *chars, *p = format, *b = format, *e; char ch; + size_t len; + mrb_int i; struct RClass *cls; - mrb_int len, i; mrb_bool inspect = FALSE; mrb_value result = mrb_str_new_capa(mrb, 128), obj, str; int ai = mrb_gc_arena_save(mrb); @@ -335,7 +336,7 @@ mrb_vformat(mrb_state *mrb, const char *format, va_list ap) #endif case 'l': chars = va_arg(ap, char*); - len = va_arg(ap, mrb_int); + len = va_arg(ap, size_t); L_cat: if (inspect) { obj = mrb_str_new(mrb, chars, len); diff --git a/tasks/toolchains/visualcpp.rake b/tasks/toolchains/visualcpp.rake index 6275059bb..9bf0f085e 100644 --- a/tasks/toolchains/visualcpp.rake +++ b/tasks/toolchains/visualcpp.rake @@ -2,7 +2,7 @@ MRuby::Toolchain.new(:visualcpp) do |conf, _params| conf.cc do |cc| 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.flags = [ENV['CFLAGS'] || %w(/c /nologo /W3 /we4013 /Zi /Zm2000 /MD /O2 /D_CRT_SECURE_NO_WARNINGS)] cc.defines = %w(MRB_STACK_EXTEND_DOUBLING) cc.option_include_path = '/I%s' cc.option_define = '/D%s' diff --git a/test/t/vformat.rb b/test/t/vformat.rb index e99616064..679f30407 100644 --- a/test/t/vformat.rb +++ b/test/t/vformat.rb @@ -41,7 +41,7 @@ assert('mrb_vformat') do assert_format '`t`: Fixnum', ['`t`: %t', 0] assert_format '`t`: Hash', ['`t`: %t', k: "value"] assert_format_pattern '#>>', ['%t', sclass({})] - assert_format 'string and length', ['string %l length', n.s('andante'), n.i(3)] +# assert_format 'string and length', ['string %l length', n.s('andante'), n.l(3)] assert_format '`n`: sym', ['`n`: %n', n.n(:sym)] assert_format '%C文字列%', ['%s', n.s('%C文字列%')] assert_format '`C`: Kernel module', ['`C`: %C module', n.C(Kernel)] @@ -65,7 +65,7 @@ assert('mrb_vformat') do assert_format 'percent: %', ['percent: %%'] assert_format '"I": inspect char', ['%!c: inspect char', n.c(?I)] assert_format '709: inspect mrb_int', ['%!d: inspect mrb_int', n.i(709)] - assert_format '"a\x00b\xff"', ['%!l', n.s("a\000b\xFFc\000d"), n.i(4)] +# assert_format '"a\x00b\xff"', ['%!l', n.s("a\000b\xFFc\000d"), n.l(4)] assert_format ':"&.": inspect symbol', ['%!n: inspect symbol', n.n(:'&.')] assert_format 'inspect "String"', ['inspect %!v', 'String'] assert_format 'inspect Array: [1, :x, {}]', ['inspect Array: %!v', [1,:x,{}]] -- cgit v1.2.3 From eb8634013948021f163d2f4c2ee53c394c0a143c Mon Sep 17 00:00:00 2001 From: dearblue Date: Sat, 3 Aug 2019 11:38:00 +0900 Subject: Add constants for floating point number --- include/mruby/numeric.h | 30 +++++++++++++++++++++++++++++ mrbgems/mruby-numeric-ext/src/numeric_ext.c | 14 ++++++++++++++ 2 files changed, 44 insertions(+) diff --git a/include/mruby/numeric.h b/include/mruby/numeric.h index 07266aa10..39f6773d9 100644 --- a/include/mruby/numeric.h +++ b/include/mruby/numeric.h @@ -160,6 +160,36 @@ mrb_int_mul_overflow(mrb_int multiplier, mrb_int multiplicand, mrb_int *product) #endif +#ifndef MRB_WITHOUT_FLOAT +# include +# include + +# define MRB_FLT_RADIX FLT_RADIX + +# ifdef MRB_USE_FLOAT +# define MRB_FLT_MANT_DIG FLT_MANT_DIG +# define MRB_FLT_EPSILON FLT_EPSILON +# define MRB_FLT_DIG FLT_DIG +# define MRB_FLT_MIN_EXP FLT_MIN_EXP +# define MRB_FLT_MIN FLT_MIN +# define MRB_FLT_MIN_10_EXP FLT_MIN_10_EXP +# define MRB_FLT_MAX_EXP FLT_MAX_EXP +# define MRB_FLT_MAX FLT_MAX +# define MRB_FLT_MAX_10_EXP FLT_MAX_10_EXP + +# else /* not MRB_USE_FLOAT */ +# define MRB_FLT_MANT_DIG DBL_MANT_DIG +# define MRB_FLT_EPSILON DBL_EPSILON +# define MRB_FLT_DIG DBL_DIG +# define MRB_FLT_MIN_EXP DBL_MIN_EXP +# define MRB_FLT_MIN DBL_MIN +# define MRB_FLT_MIN_10_EXP DBL_MIN_10_EXP +# define MRB_FLT_MAX_EXP DBL_MAX_EXP +# define MRB_FLT_MAX DBL_MAX +# define MRB_FLT_MAX_10_EXP DBL_MAX_10_EXP +# endif /* MRB_USE_FLOAT */ +#endif /* MRB_WITHOUT_FLOAT */ + MRB_END_DECL #endif /* MRUBY_NUMERIC_H */ diff --git a/mrbgems/mruby-numeric-ext/src/numeric_ext.c b/mrbgems/mruby-numeric-ext/src/numeric_ext.c index 86c384a87..16560fe86 100644 --- a/mrbgems/mruby-numeric-ext/src/numeric_ext.c +++ b/mrbgems/mruby-numeric-ext/src/numeric_ext.c @@ -1,5 +1,6 @@ #include #include +#include static inline mrb_int to_int(mrb_state *mrb, mrb_value x) @@ -64,6 +65,19 @@ mrb_mruby_numeric_ext_gem_init(mrb_state* mrb) mrb_define_method(mrb, i, "allbits?", mrb_int_allbits, MRB_ARGS_REQ(1)); mrb_define_method(mrb, i, "anybits?", mrb_int_anybits, MRB_ARGS_REQ(1)); mrb_define_method(mrb, i, "nobits?", mrb_int_nobits, MRB_ARGS_REQ(1)); + +#ifndef MRB_WITHOUT_FLOAT + mrb_define_const(mrb, mrb->float_class, "RADIX", mrb_fixnum_value(MRB_FLT_RADIX)); + mrb_define_const(mrb, mrb->float_class, "MANT_DIG", mrb_fixnum_value(MRB_FLT_MANT_DIG)); + mrb_define_const(mrb, mrb->float_class, "EPSILON", mrb_float_value(mrb, MRB_FLT_EPSILON)); + mrb_define_const(mrb, mrb->float_class, "DIG", mrb_fixnum_value(MRB_FLT_DIG)); + mrb_define_const(mrb, mrb->float_class, "MIN_EXP", mrb_fixnum_value(MRB_FLT_MIN_EXP)); + mrb_define_const(mrb, mrb->float_class, "MIN", mrb_float_value(mrb, MRB_FLT_MIN)); + mrb_define_const(mrb, mrb->float_class, "MIN_10_EXP", mrb_fixnum_value(MRB_FLT_MIN_10_EXP)); + mrb_define_const(mrb, mrb->float_class, "MAX_EXP", mrb_fixnum_value(MRB_FLT_MAX_EXP)); + mrb_define_const(mrb, mrb->float_class, "MAX", mrb_float_value(mrb, MRB_FLT_MAX)); + mrb_define_const(mrb, mrb->float_class, "MAX_10_EXP", mrb_fixnum_value(MRB_FLT_MAX_10_EXP)); +#endif /* MRB_WITHOUT_FLOAT */ } void -- cgit v1.2.3 From d599e35aa4adcf25aeaa434c60138a33b91ed88a Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Sun, 4 Aug 2019 22:02:39 +0900 Subject: Use `mrb_int()` instead of `to_int()` in `mruby-numeric-ext` --- mrbgems/mruby-numeric-ext/src/numeric_ext.c | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/mrbgems/mruby-numeric-ext/src/numeric_ext.c b/mrbgems/mruby-numeric-ext/src/numeric_ext.c index 86c384a87..e54239365 100644 --- a/mrbgems/mruby-numeric-ext/src/numeric_ext.c +++ b/mrbgems/mruby-numeric-ext/src/numeric_ext.c @@ -1,13 +1,6 @@ #include #include -static inline mrb_int -to_int(mrb_state *mrb, mrb_value x) -{ - x = mrb_to_int(mrb, x); - return mrb_fixnum(x); -} - /* * call-seq: * int.allbits?(mask) -> true or false @@ -20,7 +13,7 @@ mrb_int_allbits(mrb_state *mrb, mrb_value self) mrb_int n, m; mrb_get_args(mrb, "i", &m); - n = to_int(mrb, self); + n = mrb_int(mrb, self); return mrb_bool_value((n & m) == m); } @@ -36,7 +29,7 @@ mrb_int_anybits(mrb_state *mrb, mrb_value self) mrb_int n, m; mrb_get_args(mrb, "i", &m); - n = to_int(mrb, self); + n = mrb_int(mrb, self); return mrb_bool_value((n & m) != 0); } @@ -52,7 +45,7 @@ mrb_int_nobits(mrb_state *mrb, mrb_value self) mrb_int n, m; mrb_get_args(mrb, "i", &m); - n = to_int(mrb, self); + n = mrb_int(mrb, self); return mrb_bool_value((n & m) == 0); } -- cgit v1.2.3 From 334afb167c0a1fa478a53c3844f37c0f1fd866dd Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Mon, 5 Aug 2019 12:41:15 +0900 Subject: Use new specifiers/modifiers of `mrb_vfromat()` The binary sizes (gems are only `mruby-bin-mruby`) are reduced slightly in my environment than before the introduction of new specifiers/modifiers (5116789a) with this change. ------------+-------------------+-------------------+-------- BINARY | BEFORE (5116789a) | AFTER (This PR) | RATIO ------------+-------------------+-------------------+-------- mruby | 593416 bytes | 593208 bytes | -0.04% libmruby.a | 769048 bytes | 767264 bytes | -0.23% ------------+-------------------+-------------------+-------- BTW, I accidentally changed `tasks/toolchains/visualcpp.rake` at #4613, so I put it back. --- mrbgems/mruby-compiler/core/codegen.c | 2 +- mrbgems/mruby-compiler/core/parse.y | 2 +- mrbgems/mruby-complex/src/complex.c | 4 +-- mrbgems/mruby-eval/src/eval.c | 14 ++++----- mrbgems/mruby-io/src/file.c | 6 ++-- mrbgems/mruby-io/src/io.c | 20 +++++-------- mrbgems/mruby-io/test/mruby_io_test.c | 6 ++-- mrbgems/mruby-kernel-ext/src/kernel.c | 13 ++++---- mrbgems/mruby-math/src/math.c | 3 +- mrbgems/mruby-metaprog/src/metaprog.c | 11 +++---- mrbgems/mruby-method/src/method.c | 12 ++------ mrbgems/mruby-pack/src/pack.c | 13 ++++---- mrbgems/mruby-socket/src/socket.c | 8 ++--- mrbgems/mruby-sprintf/src/sprintf.c | 36 +++++++++++----------- mrbgems/mruby-string-ext/src/string.c | 11 ++++--- mrbgems/mruby-struct/src/struct.c | 28 ++++++++---------- mrbgems/mruby-time/src/time.c | 4 +-- src/array.c | 10 +++---- src/backtrace.c | 4 +-- src/class.c | 56 +++++++++++++++-------------------- src/error.c | 11 ++++--- src/etc.c | 12 ++++---- src/gc.c | 2 +- src/kernel.c | 8 ++--- src/numeric.c | 8 ++--- src/object.c | 37 ++++++----------------- src/proc.c | 4 +-- src/range.c | 2 +- src/string.c | 20 ++++++------- src/variable.c | 5 ++-- src/vm.c | 14 ++++----- tasks/toolchains/visualcpp.rake | 2 +- 32 files changed, 163 insertions(+), 225 deletions(-) diff --git a/mrbgems/mruby-compiler/core/codegen.c b/mrbgems/mruby-compiler/core/codegen.c index ed8fc3150..5cade970c 100644 --- a/mrbgems/mruby-compiler/core/codegen.c +++ b/mrbgems/mruby-compiler/core/codegen.c @@ -2373,7 +2373,7 @@ codegen(codegen_scope *s, node *tree, int val) mrb_value str; int sym; - str = mrb_format(mrb, "$%S", mrb_fixnum_value(nint(tree))); + str = mrb_format(mrb, "$%d", nint(tree)); sym = new_sym(s, mrb_intern_str(mrb, str)); genop_2(s, OP_GETGV, cursp(), sym); push(); diff --git a/mrbgems/mruby-compiler/core/parse.y b/mrbgems/mruby-compiler/core/parse.y index f6d543c5d..3a55c8e70 100644 --- a/mrbgems/mruby-compiler/core/parse.y +++ b/mrbgems/mruby-compiler/core/parse.y @@ -3831,7 +3831,7 @@ backref_error(parser_state *p, node *n) yyerror_c(p, "can't set variable $", (char)intn(n->cdr)); } else { - mrb_bug(p->mrb, "Internal error in backref_error() : n=>car == %S", mrb_fixnum_value(c)); + mrb_bug(p->mrb, "Internal error in backref_error() : n=>car == %d", c); } } diff --git a/mrbgems/mruby-complex/src/complex.c b/mrbgems/mruby-complex/src/complex.c index aa2afc2ce..a87b95dea 100644 --- a/mrbgems/mruby-complex/src/complex.c +++ b/mrbgems/mruby-complex/src/complex.c @@ -101,7 +101,7 @@ complex_to_f(mrb_state *mrb, mrb_value self) struct mrb_complex *p = complex_ptr(mrb, self); if (p->imaginary != 0) { - mrb_raisef(mrb, E_RANGE_ERROR, "can't convert %S into Float", self); + mrb_raisef(mrb, E_RANGE_ERROR, "can't convert %v into Float", self); } return mrb_float_value(mrb, p->real); @@ -113,7 +113,7 @@ complex_to_i(mrb_state *mrb, mrb_value self) struct mrb_complex *p = complex_ptr(mrb, self); if (p->imaginary != 0) { - mrb_raisef(mrb, E_RANGE_ERROR, "can't convert %S into Float", self); + mrb_raisef(mrb, E_RANGE_ERROR, "can't convert %v into Float", self); } return mrb_int_value(mrb, p->real); } diff --git a/mrbgems/mruby-eval/src/eval.c b/mrbgems/mruby-eval/src/eval.c index 30534aaec..e8f1d3e95 100644 --- a/mrbgems/mruby-eval/src/eval.c +++ b/mrbgems/mruby-eval/src/eval.c @@ -254,15 +254,15 @@ create_proc_from_string(mrb_state *mrb, char *s, mrb_int len, mrb_value binding, mrb_value str; if (file) { - str = mrb_format(mrb, " file %S line %S: %S", - mrb_str_new_cstr(mrb, file), - mrb_fixnum_value(p->error_buffer[0].lineno), - mrb_str_new_cstr(mrb, p->error_buffer[0].message)); + str = mrb_format(mrb, "file %s line %d: %s", + file, + p->error_buffer[0].lineno, + p->error_buffer[0].message); } else { - str = mrb_format(mrb, " line %S: %S", - mrb_fixnum_value(p->error_buffer[0].lineno), - mrb_str_new_cstr(mrb, p->error_buffer[0].message)); + str = mrb_format(mrb, "line %d: %s", + p->error_buffer[0].lineno, + p->error_buffer[0].message); } mrb_parser_free(p); mrbc_context_free(mrb, cxt); diff --git a/mrbgems/mruby-io/src/file.c b/mrbgems/mruby-io/src/file.c index 243f634b4..5e6c849f0 100644 --- a/mrbgems/mruby-io/src/file.c +++ b/mrbgems/mruby-io/src/file.c @@ -146,7 +146,7 @@ mrb_file_s_rename(mrb_state *mrb, mrb_value obj) #endif mrb_locale_free(src); mrb_locale_free(dst); - mrb_sys_fail(mrb, RSTRING_PTR(mrb_format(mrb, "(%S, %S)", from, to))); + mrb_sys_fail(mrb, RSTRING_PTR(mrb_format(mrb, "(%v, %v)", from, to))); } mrb_locale_free(src); mrb_locale_free(dst); @@ -307,7 +307,7 @@ mrb_file__gethome(mrb_state *mrb, mrb_value klass) } home = pwd->pw_dir; if (!mrb_file_is_absolute_path(home)) { - mrb_raisef(mrb, E_ARGUMENT_ERROR, "non-absolute home of ~%S", username); + mrb_raisef(mrb, E_ARGUMENT_ERROR, "non-absolute home of ~%v", username); } } home = mrb_locale_from_utf8(home, -1); @@ -398,7 +398,7 @@ mrb_file_s_symlink(mrb_state *mrb, mrb_value klass) if (symlink(src, dst) == -1) { mrb_locale_free(src); mrb_locale_free(dst); - mrb_sys_fail(mrb, mrb_str_to_cstr(mrb, mrb_format(mrb, "(%S, %S)", from, to))); + mrb_sys_fail(mrb, RSTRING_PTR(mrb_format(mrb, "(%v, %v)", from, to))); } mrb_locale_free(src); mrb_locale_free(dst); diff --git a/mrbgems/mruby-io/src/io.c b/mrbgems/mruby-io/src/io.c index 99441f16b..a0b6c6780 100644 --- a/mrbgems/mruby-io/src/io.c +++ b/mrbgems/mruby-io/src/io.c @@ -127,7 +127,7 @@ mrb_io_modestr_to_flags(mrb_state *mrb, const char *mode) flags |= FMODE_WRITABLE | FMODE_APPEND | FMODE_CREATE; break; default: - mrb_raisef(mrb, E_ARGUMENT_ERROR, "illegal access mode %S", mrb_str_new_cstr(mrb, mode)); + mrb_raisef(mrb, E_ARGUMENT_ERROR, "illegal access mode %s", mode); } while (*m) { @@ -141,7 +141,7 @@ mrb_io_modestr_to_flags(mrb_state *mrb, const char *mode) case ':': /* XXX: PASSTHROUGH*/ default: - mrb_raisef(mrb, E_ARGUMENT_ERROR, "illegal access mode %S", mrb_str_new_cstr(mrb, mode)); + mrb_raisef(mrb, E_ARGUMENT_ERROR, "illegal access mode %s", mode); } } @@ -191,8 +191,7 @@ mrb_fd_cloexec(mrb_state *mrb, int fd) flags = fcntl(fd, F_GETFD); if (flags == -1) { - mrb_bug(mrb, "mrb_fd_cloexec: fcntl(%S, F_GETFD) failed: %S", - mrb_fixnum_value(fd), mrb_fixnum_value(errno)); + mrb_bug(mrb, "mrb_fd_cloexec: fcntl(%d, F_GETFD) failed: %d", fd, errno); } if (fd <= 2) { flags2 = flags & ~FD_CLOEXEC; /* Clear CLOEXEC for standard file descriptors: 0, 1, 2. */ @@ -202,8 +201,7 @@ mrb_fd_cloexec(mrb_state *mrb, int fd) } if (flags != flags2) { if (fcntl(fd, F_SETFD, flags2) == -1) { - mrb_bug(mrb, "mrb_fd_cloexec: fcntl(%S, F_SETFD, %S) failed: %S", - mrb_fixnum_value(fd), mrb_fixnum_value(flags2), mrb_fixnum_value(errno)); + mrb_bug(mrb, "mrb_fd_cloexec: fcntl(%d, F_SETFD, %d) failed: %d", fd, flags2, errno); } } #endif @@ -381,7 +379,7 @@ mrb_io_s_popen(mrb_state *mrb, mrb_value klass) CloseHandle(ifd[1]); CloseHandle(ofd[0]); CloseHandle(ofd[1]); - mrb_raisef(mrb, E_IO_ERROR, "command not found: %S", cmd); + mrb_raisef(mrb, E_IO_ERROR, "command not found: %v", cmd); } CloseHandle(pi.hThread); CloseHandle(ifd[0]); @@ -494,7 +492,7 @@ mrb_io_s_popen(mrb_state *mrb, mrb_value klass) close(fd); } mrb_proc_exec(pname); - mrb_raisef(mrb, E_IO_ERROR, "command not found: %S", cmd); + mrb_raisef(mrb, E_IO_ERROR, "command not found: %v", cmd); _exit(127); } result = mrb_nil_value(); @@ -783,9 +781,7 @@ reopen: } } - emsg = mrb_format(mrb, "open %S", mrb_str_new_cstr(mrb, pathname)); - mrb_str_modify(mrb, mrb_str_ptr(emsg)); - mrb_sys_fail(mrb, RSTRING_PTR(emsg)); + mrb_sys_fail(mrb, RSTRING_PTR(mrb_format(mrb, "open %s", pathname))); } mrb_locale_free(fname); @@ -1068,7 +1064,7 @@ mrb_io_s_select(mrb_state *mrb, mrb_value klass) mrb_get_args(mrb, "*", &argv, &argc); if (argc < 1 || argc > 4) { - mrb_raisef(mrb, E_ARGUMENT_ERROR, "wrong number of arguments (%S for 1..4)", mrb_fixnum_value(argc)); + mrb_raisef(mrb, E_ARGUMENT_ERROR, "wrong number of arguments (%i for 1..4)", argc); } timeout = mrb_nil_value(); diff --git a/mrbgems/mruby-io/test/mruby_io_test.c b/mrbgems/mruby-io/test/mruby_io_test.c index 3312d6c7e..2c8a75fc9 100644 --- a/mrbgems/mruby-io/test/mruby_io_test.c +++ b/mrbgems/mruby-io/test/mruby_io_test.c @@ -136,9 +136,9 @@ mrb_io_test_io_setup(mrb_state *mrb, mrb_value self) sun0.sun_family = AF_UNIX; snprintf(sun0.sun_path, sizeof(sun0.sun_path), "%s", socketname); if (bind(fd3, (struct sockaddr *)&sun0, sizeof(sun0)) == -1) { - mrb_raisef(mrb, E_RUNTIME_ERROR, "can't bind AF_UNIX socket to %S: %S", - mrb_str_new_cstr(mrb, sun0.sun_path), - mrb_fixnum_value(errno)); + mrb_raisef(mrb, E_RUNTIME_ERROR, "can't bind AF_UNIX socket to %s: %d", + sun0.sun_path, + errno); } close(fd3); #endif diff --git a/mrbgems/mruby-kernel-ext/src/kernel.c b/mrbgems/mruby-kernel-ext/src/kernel.c index 8e7e03c56..376751e10 100644 --- a/mrbgems/mruby-kernel-ext/src/kernel.c +++ b/mrbgems/mruby-kernel-ext/src/kernel.c @@ -31,22 +31,21 @@ mrb_f_caller(mrb_state *mrb, mrb_value self) } } else { - v = mrb_to_int(mrb, v); - lev = mrb_fixnum(v); + lev = mrb_int(mrb, v); if (lev < 0) { - mrb_raisef(mrb, E_ARGUMENT_ERROR, "negative level (%S)", v); + mrb_raisef(mrb, E_ARGUMENT_ERROR, "negative level (%v)", v); } n = bt_len - lev; } break; case 2: - lev = mrb_fixnum(mrb_to_int(mrb, v)); - n = mrb_fixnum(mrb_to_int(mrb, length)); + lev = mrb_int(mrb, v); + n = mrb_int(mrb, length); if (lev < 0) { - mrb_raisef(mrb, E_ARGUMENT_ERROR, "negative level (%S)", v); + mrb_raisef(mrb, E_ARGUMENT_ERROR, "negative level (%v)", v); } if (n < 0) { - mrb_raisef(mrb, E_ARGUMENT_ERROR, "negative size (%S)", length); + mrb_raisef(mrb, E_ARGUMENT_ERROR, "negative size (%v)", length); } break; default: diff --git a/mrbgems/mruby-math/src/math.c b/mrbgems/mruby-math/src/math.c index c6d4ca414..88b33771b 100644 --- a/mrbgems/mruby-math/src/math.c +++ b/mrbgems/mruby-math/src/math.c @@ -18,8 +18,7 @@ domain_error(mrb_state *mrb, const char *func) { struct RClass *math = mrb_module_get(mrb, "Math"); struct RClass *domainerror = mrb_class_get_under(mrb, math, "DomainError"); - mrb_value str = mrb_str_new_cstr(mrb, func); - mrb_raisef(mrb, domainerror, "Numerical argument is out of domain - %S", str); + mrb_raisef(mrb, domainerror, "Numerical argument is out of domain - %s", func); } /* math functions not provided by Microsoft Visual C++ 2012 or older */ diff --git a/mrbgems/mruby-metaprog/src/metaprog.c b/mrbgems/mruby-metaprog/src/metaprog.c index 62daa5227..97f53051f 100644 --- a/mrbgems/mruby-metaprog/src/metaprog.c +++ b/mrbgems/mruby-metaprog/src/metaprog.c @@ -414,7 +414,7 @@ check_cv_name_sym(mrb_state *mrb, mrb_sym id) mrb_int len; const char *name = mrb_sym2name_len(mrb, id, &len); if (!cv_name_p(mrb, name, len)) { - mrb_name_error(mrb, id, "'%S' is not allowed as a class variable name", mrb_sym2str(mrb, id)); + mrb_name_error(mrb, id, "'%n' is not allowed as a class variable name", id); } } @@ -454,12 +454,10 @@ mrb_mod_remove_cvar(mrb_state *mrb, mrb_value mod) if (!mrb_undef_p(val)) return val; if (mrb_cv_defined(mrb, mod, id)) { - mrb_name_error(mrb, id, "cannot remove %S for %S", - mrb_sym2str(mrb, id), mod); + mrb_name_error(mrb, id, "cannot remove %n for %v", id, mod); } - mrb_name_error(mrb, id, "class variable %S not defined for %S", - mrb_sym2str(mrb, id), mod); + mrb_name_error(mrb, id, "class variable %n not defined for %v", id, mod); /* not reached */ return mrb_nil_value(); @@ -622,8 +620,7 @@ remove_method(mrb_state *mrb, mrb_value mod, mrb_sym mid) } } - mrb_name_error(mrb, mid, "method '%S' not defined in %S", - mrb_sym2str(mrb, mid), mod); + mrb_name_error(mrb, mid, "method '%n' not defined in %v", mid, mod); } /* 15.2.2.4.41 */ diff --git a/mrbgems/mruby-method/src/method.c b/mrbgems/mruby-method/src/method.c index d94db1cb2..b5050368d 100644 --- a/mrbgems/mruby-method/src/method.c +++ b/mrbgems/mruby-method/src/method.c @@ -29,8 +29,7 @@ unbound_method_bind(mrb_state *mrb, mrb_value self) if (mrb_type(owner) == MRB_TT_SCLASS) { mrb_raise(mrb, E_TYPE_ERROR, "singleton method called for a different object"); } else { - const char *s = mrb_class_name(mrb, mrb_class_ptr(owner)); - mrb_raisef(mrb, E_TYPE_ERROR, "bind argument must be an instance of %S", mrb_str_new_static(mrb, s, strlen(s))); + mrb_raisef(mrb, E_TYPE_ERROR, "bind argument must be an instance of %v", owner); } } me = method_object_alloc(mrb, mrb_class_get(mrb, "Method")); @@ -289,7 +288,6 @@ static void mrb_search_method_owner(mrb_state *mrb, struct RClass *c, mrb_value obj, mrb_sym name, struct RClass **owner, struct RProc **proc, mrb_bool unbound) { mrb_value ret; - const char *s; *owner = c; *proc = method_search_vm(mrb, owner, name); @@ -313,13 +311,7 @@ mrb_search_method_owner(mrb_state *mrb, struct RClass *c, mrb_value obj, mrb_sym return; name_error: - s = mrb_class_name(mrb, c); - mrb_raisef( - mrb, E_NAME_ERROR, - "undefined method '%S' for class '%S'", - mrb_sym2str(mrb, name), - mrb_str_new_static(mrb, s, strlen(s)) - ); + mrb_raisef(mrb, E_NAME_ERROR, "undefined method '%n' for class '%C'", name, c); } static mrb_value diff --git a/mrbgems/mruby-pack/src/pack.c b/mrbgems/mruby-pack/src/pack.c index 9f091194b..159ba09ac 100644 --- a/mrbgems/mruby-pack/src/pack.c +++ b/mrbgems/mruby-pack/src/pack.c @@ -529,8 +529,8 @@ utf8_to_uv(mrb_state *mrb, const char *p, long *lenp) mrb_raise(mrb, E_ARGUMENT_ERROR, "malformed UTF-8 character"); } if (n > *lenp) { - mrb_raisef(mrb, E_ARGUMENT_ERROR, "malformed UTF-8 character (expected %S bytes, given %S bytes)", - mrb_fixnum_value(n), mrb_fixnum_value(*lenp)); + mrb_raisef(mrb, E_ARGUMENT_ERROR, "malformed UTF-8 character (expected %d bytes, given %d bytes)", + n, *lenp); } *lenp = n--; if (n != 0) { @@ -976,7 +976,7 @@ alias: case 4: t = 'L'; goto alias; case 8: t = 'Q'; goto alias; default: - mrb_raisef(mrb, E_RUNTIME_ERROR, "mruby-pack does not support sizeof(int) == %S", mrb_fixnum_value(sizeof(int))); + mrb_raisef(mrb, E_RUNTIME_ERROR, "mruby-pack does not support sizeof(int) == %d", (int)sizeof(int)); } break; case 'i': @@ -985,7 +985,7 @@ alias: case 4: t = 'l'; goto alias; case 8: t = 'q'; goto alias; default: - mrb_raisef(mrb, E_RUNTIME_ERROR, "mruby-pack does not support sizeof(int) == %S", mrb_fixnum_value(sizeof(int))); + mrb_raisef(mrb, E_RUNTIME_ERROR, "mruby-pack does not support sizeof(int) == %d", (int)sizeof(int)); } break; case 'L': @@ -1086,8 +1086,7 @@ alias: count = -1; } else if (ch == '_' || ch == '!' || ch == '<' || ch == '>') { if (strchr("sSiIlLqQ", (int)t) == NULL) { - char ch_str = (char)ch; - mrb_raisef(mrb, E_ARGUMENT_ERROR, "'%S' allowed only after types sSiIlLqQ", mrb_str_new(mrb, &ch_str, 1)); + mrb_raisef(mrb, E_ARGUMENT_ERROR, "'%c' allowed only after types sSiIlLqQ", ch); } if (ch == '_' || ch == '!') { flags |= PACK_FLAG_s; @@ -1156,7 +1155,7 @@ mrb_pack_pack(mrb_state *mrb, mrb_value ary) #endif else if (type == PACK_TYPE_STRING) { if (!mrb_string_p(o)) { - mrb_raisef(mrb, E_TYPE_ERROR, "can't convert %S into String", mrb_class_path(mrb, mrb_obj_class(mrb, o))); + mrb_raisef(mrb, E_TYPE_ERROR, "can't convert %T into String", o); } } diff --git a/mrbgems/mruby-socket/src/socket.c b/mrbgems/mruby-socket/src/socket.c index 9b06274dc..eaca27779 100644 --- a/mrbgems/mruby-socket/src/socket.c +++ b/mrbgems/mruby-socket/src/socket.c @@ -171,7 +171,7 @@ mrb_addrinfo_getaddrinfo(mrb_state *mrb, mrb_value klass) error = getaddrinfo(hostname, servname, &hints, &res0); if (error) { - mrb_raisef(mrb, E_SOCKET_ERROR, "getaddrinfo: %S", mrb_str_new_cstr(mrb, gai_strerror(error))); + mrb_raisef(mrb, E_SOCKET_ERROR, "getaddrinfo: %s", gai_strerror(error)); } mrb_cv_set(mrb, klass, mrb_intern_lit(mrb, "_lastai"), mrb_cptr_value(mrb, res0)); @@ -206,7 +206,7 @@ mrb_addrinfo_getnameinfo(mrb_state *mrb, mrb_value self) } error = getnameinfo((struct sockaddr *)RSTRING_PTR(sastr), (socklen_t)RSTRING_LEN(sastr), RSTRING_PTR(host), NI_MAXHOST, RSTRING_PTR(serv), NI_MAXSERV, (int)flags); if (error) { - mrb_raisef(mrb, E_SOCKET_ERROR, "getnameinfo: %S", mrb_str_new_cstr(mrb, gai_strerror(error))); + mrb_raisef(mrb, E_SOCKET_ERROR, "getnameinfo: %s", gai_strerror(error)); } ary = mrb_ary_new_capa(mrb, 2); mrb_str_resize(mrb, host, strlen(RSTRING_PTR(host))); @@ -476,7 +476,7 @@ mrb_basicsocket_setsockopt(mrb_state *mrb, mrb_value self) optname = mrb_fixnum(mrb_funcall(mrb, so, "optname", 0)); optval = mrb_funcall(mrb, so, "data", 0); } else { - mrb_raisef(mrb, E_ARGUMENT_ERROR, "wrong number of arguments (%S for 3)", mrb_fixnum_value(argc)); + mrb_raisef(mrb, E_ARGUMENT_ERROR, "wrong number of arguments (%i for 3)", argc); } s = socket_fd(mrb, self); @@ -702,7 +702,7 @@ mrb_socket_sockaddr_un(mrb_state *mrb, mrb_value klass) mrb_get_args(mrb, "S", &path); if ((size_t)RSTRING_LEN(path) > sizeof(sunp->sun_path) - 1) { - mrb_raisef(mrb, E_ARGUMENT_ERROR, "too long unix socket path (max: %S bytes)", mrb_fixnum_value(sizeof(sunp->sun_path) - 1)); + mrb_raisef(mrb, E_ARGUMENT_ERROR, "too long unix socket path (max: %d bytes)", (int)sizeof(sunp->sun_path) - 1); } s = mrb_str_buf_new(mrb, sizeof(struct sockaddr_un)); sunp = (struct sockaddr_un *)RSTRING_PTR(s); diff --git a/mrbgems/mruby-sprintf/src/sprintf.c b/mrbgems/mruby-sprintf/src/sprintf.c index 985ffe276..c8d51962e 100644 --- a/mrbgems/mruby-sprintf/src/sprintf.c +++ b/mrbgems/mruby-sprintf/src/sprintf.c @@ -81,7 +81,7 @@ mrb_fix2binstr(mrb_state *mrb, mrb_value x, int base) char d; if (base != 2) { - mrb_raisef(mrb, E_ARGUMENT_ERROR, "invalid radix %S", mrb_fixnum_value(base)); + mrb_raisef(mrb, E_ARGUMENT_ERROR, "invalid radix %d", base); } if (val == 0) { return mrb_str_new_lit(mrb, "0"); @@ -144,10 +144,10 @@ check_next_arg(mrb_state *mrb, int posarg, int nextarg) { switch (posarg) { case -1: - mrb_raisef(mrb, E_ARGUMENT_ERROR, "unnumbered(%S) mixed with numbered", mrb_fixnum_value(nextarg)); + mrb_raisef(mrb, E_ARGUMENT_ERROR, "unnumbered(%d) mixed with numbered", nextarg); break; case -2: - mrb_raisef(mrb, E_ARGUMENT_ERROR, "unnumbered(%S) mixed with named", mrb_fixnum_value(nextarg)); + mrb_raisef(mrb, E_ARGUMENT_ERROR, "unnumbered(%d) mixed with named", nextarg); break; default: break; @@ -158,26 +158,26 @@ static void check_pos_arg(mrb_state *mrb, mrb_int posarg, mrb_int n) { if (posarg > 0) { - mrb_raisef(mrb, E_ARGUMENT_ERROR, "numbered(%S) after unnumbered(%S)", - mrb_fixnum_value(n), mrb_fixnum_value(posarg)); + mrb_raisef(mrb, E_ARGUMENT_ERROR, "numbered(%i) after unnumbered(%i)", + n, posarg); } if (posarg == -2) { - mrb_raisef(mrb, E_ARGUMENT_ERROR, "numbered(%S) after named", mrb_fixnum_value(n)); + mrb_raisef(mrb, E_ARGUMENT_ERROR, "numbered(%i) after named", n); } if (n < 1) { - mrb_raisef(mrb, E_ARGUMENT_ERROR, "invalid index - %S$", mrb_fixnum_value(n)); + mrb_raisef(mrb, E_ARGUMENT_ERROR, "invalid index - %i$", n); } } static void -check_name_arg(mrb_state *mrb, int posarg, const char *name, mrb_int len) +check_name_arg(mrb_state *mrb, int posarg, const char *name, size_t len) { if (posarg > 0) { - mrb_raisef(mrb, E_ARGUMENT_ERROR, "named%S after unnumbered(%S)", - mrb_str_new(mrb, (name), (len)), mrb_fixnum_value(posarg)); + mrb_raisef(mrb, E_ARGUMENT_ERROR, "named%l after unnumbered(%d)", + name, len, posarg); } if (posarg == -1) { - mrb_raisef(mrb, E_ARGUMENT_ERROR, "named%S after numbered", mrb_str_new(mrb, (name), (len))); + mrb_raisef(mrb, E_ARGUMENT_ERROR, "named%l after numbered", name, len); } } @@ -580,7 +580,7 @@ mrb_str_format(mrb_state *mrb, mrb_int argc, const mrb_value *argv, mrb_value fm retry: switch (*p) { default: - mrb_raisef(mrb, E_ARGUMENT_ERROR, "malformed format string - \\%%S", mrb_str_new(mrb, p, 1)); + mrb_raisef(mrb, E_ARGUMENT_ERROR, "malformed format string - %%%c", *p); break; case ' ': @@ -619,7 +619,7 @@ retry: GETNUM(n, width); if (*p == '$') { if (!mrb_undef_p(nextvalue)) { - mrb_raisef(mrb, E_ARGUMENT_ERROR, "value given twice - %S$", mrb_fixnum_value(n)); + mrb_raisef(mrb, E_ARGUMENT_ERROR, "value given twice - %i$", n); } nextvalue = GETPOSARG(n); p++; @@ -639,14 +639,14 @@ retry: for (; p < end && *p != term; ) p++; if (id) { - mrb_raisef(mrb, E_ARGUMENT_ERROR, "name%S after <%S>", - mrb_str_new(mrb, start, p - start + 1), mrb_sym2str(mrb, id)); + mrb_raisef(mrb, E_ARGUMENT_ERROR, "name%l after <%n>", + start, p - start + 1, id); } symname = mrb_str_new(mrb, start + 1, p - start - 1); id = mrb_intern_str(mrb, symname); - nextvalue = GETNAMEARG(mrb_symbol_value(id), start, (mrb_int)(p - start + 1)); + nextvalue = GETNAMEARG(mrb_symbol_value(id), start, p - start + 1); if (mrb_undef_p(nextvalue)) { - mrb_raisef(mrb, E_KEY_ERROR, "key%S not found", mrb_str_new(mrb, start, p - start + 1)); + mrb_raisef(mrb, E_KEY_ERROR, "key%l not found", start, p - start + 1); } if (term == '}') goto format_s; p++; @@ -1089,7 +1089,7 @@ retry: if (posarg >= 0 && nextarg < argc) { const char *mesg = "too many arguments for format string"; if (mrb_test(ruby_debug)) mrb_raise(mrb, E_ARGUMENT_ERROR, mesg); - if (mrb_test(ruby_verbose)) mrb_warn(mrb, "%S", mrb_str_new_cstr(mrb, mesg)); + if (mrb_test(ruby_verbose)) mrb_warn(mrb, "%s", mesg); } #endif mrb_str_resize(mrb, result, blen); diff --git a/mrbgems/mruby-string-ext/src/string.c b/mrbgems/mruby-string-ext/src/string.c index 80b277444..a946140dd 100644 --- a/mrbgems/mruby-string-ext/src/string.c +++ b/mrbgems/mruby-string-ext/src/string.c @@ -40,7 +40,7 @@ int_chr_binary(mrb_state *mrb, mrb_value num) mrb_value str; if (cp < 0 || 0xff < cp) { - mrb_raisef(mrb, E_RANGE_ERROR, "%S out of char range", num); + mrb_raisef(mrb, E_RANGE_ERROR, "%v out of char range", num); } c = (char)cp; str = mrb_str_new(mrb, &c, 1); @@ -59,7 +59,7 @@ int_chr_utf8(mrb_state *mrb, mrb_value num) uint32_t ascii_flag = 0; if (cp < 0 || 0x10FFFF < cp) { - mrb_raisef(mrb, E_RANGE_ERROR, "%S out of char range", num); + mrb_raisef(mrb, E_RANGE_ERROR, "%v out of char range", num); } if (cp < 0x80) { utf8[0] = (char)cp; @@ -114,7 +114,7 @@ mrb_str_setbyte(mrb_state *mrb, mrb_value str) len = RSTRING_LEN(str); if (pos < -len || len <= pos) - mrb_raisef(mrb, E_INDEX_ERROR, "index %S out of string", mrb_fixnum_value(pos)); + mrb_raisef(mrb, E_INDEX_ERROR, "index %i out of string", pos); if (pos < 0) pos += len; @@ -583,8 +583,7 @@ str_tr(mrb_state *mrb, mrb_value str, mrb_value p1, mrb_value p2, mrb_bool squee continue; } if (c > 0x80) { - mrb_raisef(mrb, E_ARGUMENT_ERROR, "character (%S) out of range", - mrb_fixnum_value((mrb_int)c)); + mrb_raisef(mrb, E_ARGUMENT_ERROR, "character (%i) out of range", c); } lastch = c; s[i] = (char)c; @@ -956,7 +955,7 @@ mrb_int_chr(mrb_state *mrb, mrb_value num) } #endif else { - mrb_raisef(mrb, E_ARGUMENT_ERROR, "unknown encoding name - %S", enc); + mrb_raisef(mrb, E_ARGUMENT_ERROR, "unknown encoding name - %v", enc); } /* not reached */ return mrb_nil_value(); diff --git a/mrbgems/mruby-struct/src/struct.c b/mrbgems/mruby-struct/src/struct.c index e04fe13ad..ebe711ed3 100644 --- a/mrbgems/mruby-struct/src/struct.c +++ b/mrbgems/mruby-struct/src/struct.c @@ -66,8 +66,8 @@ struct_members(mrb_state *mrb, mrb_value s) } else { mrb_raisef(mrb, E_TYPE_ERROR, - "struct size differs (%S required %S given)", - mrb_fixnum_value(RARRAY_LEN(members)), mrb_fixnum_value(RSTRUCT_LEN(s))); + "struct size differs (%i required %i given)", + RARRAY_LEN(members), RSTRUCT_LEN(s)); } } return members; @@ -205,10 +205,10 @@ make_struct(mrb_state *mrb, mrb_value name, mrb_value members, struct RClass *kl mrb_to_str(mrb, name); id = mrb_obj_to_sym(mrb, name); if (!mrb_const_name_p(mrb, RSTRING_PTR(name), RSTRING_LEN(name))) { - mrb_name_error(mrb, id, "identifier %S needs to be constant", name); + mrb_name_error(mrb, id, "identifier %v needs to be constant", name); } if (mrb_const_defined_at(mrb, mrb_obj_value(klass), id)) { - mrb_warn(mrb, "redefining constant Struct::%S", name); + mrb_warn(mrb, "redefining constant Struct::%v", name); mrb_const_remove(mrb, mrb_obj_value(klass), id); } c = mrb_define_class_under(mrb, klass, RSTRING_PTR(name), klass); @@ -388,7 +388,7 @@ struct_aref_sym(mrb_state *mrb, mrb_value obj, mrb_sym id) return ptr[i]; } } - mrb_name_error(mrb, id, "no member '%S' in struct", mrb_sym2str(mrb, id)); + mrb_name_error(mrb, id, "no member '%n' in struct", id); return mrb_nil_value(); /* not reached */ } @@ -399,12 +399,10 @@ struct_aref_int(mrb_state *mrb, mrb_value s, mrb_int i) if (idx < 0) mrb_raisef(mrb, E_INDEX_ERROR, - "offset %S too small for struct(size:%S)", - mrb_fixnum_value(i), mrb_fixnum_value(RSTRUCT_LEN(s))); + "offset %i too small for struct(size:%i)", i, RSTRUCT_LEN(s)); if (RSTRUCT_LEN(s) <= idx) mrb_raisef(mrb, E_INDEX_ERROR, - "offset %S too large for struct(size:%S)", - mrb_fixnum_value(i), mrb_fixnum_value(RSTRUCT_LEN(s))); + "offset %i too large for struct(size:%i)", i, RSTRUCT_LEN(s)); return RSTRUCT_PTR(s)[idx]; } @@ -437,7 +435,7 @@ mrb_struct_aref(mrb_state *mrb, mrb_value s) mrb_value sym = mrb_check_intern_str(mrb, idx); if (mrb_nil_p(sym)) { - mrb_name_error(mrb, mrb_intern_str(mrb, idx), "no member '%S' in struct", idx); + mrb_name_error(mrb, mrb_intern_str(mrb, idx), "no member '%v' in struct", idx); } idx = sym; } @@ -465,7 +463,7 @@ mrb_struct_aset_sym(mrb_state *mrb, mrb_value s, mrb_sym id, mrb_value val) return val; } } - mrb_name_error(mrb, id, "no member '%S' in struct", mrb_sym2str(mrb, id)); + mrb_name_error(mrb, id, "no member '%n' in struct", id); return val; /* not reach */ } @@ -504,7 +502,7 @@ mrb_struct_aset(mrb_state *mrb, mrb_value s) mrb_value sym = mrb_check_intern_str(mrb, idx); if (mrb_nil_p(sym)) { - mrb_name_error(mrb, mrb_intern_str(mrb, idx), "no member '%S' in struct", idx); + mrb_name_error(mrb, mrb_intern_str(mrb, idx), "no member '%v' in struct", idx); } idx = sym; } @@ -516,13 +514,11 @@ mrb_struct_aset(mrb_state *mrb, mrb_value s) if (i < 0) i = RSTRUCT_LEN(s) + i; if (i < 0) { mrb_raisef(mrb, E_INDEX_ERROR, - "offset %S too small for struct(size:%S)", - mrb_fixnum_value(i), mrb_fixnum_value(RSTRUCT_LEN(s))); + "offset %i too small for struct(size:%i)", i, RSTRUCT_LEN(s)); } if (RSTRUCT_LEN(s) <= i) { mrb_raisef(mrb, E_INDEX_ERROR, - "offset %S too large for struct(size:%S)", - mrb_fixnum_value(i), mrb_fixnum_value(RSTRUCT_LEN(s))); + "offset %i too large for struct(size:%i)", i, RSTRUCT_LEN(s)); } mrb_struct_modify(mrb, s); return RSTRUCT_PTR(s)[i] = val; diff --git a/mrbgems/mruby-time/src/time.c b/mrbgems/mruby-time/src/time.c index 16461095c..9b0549bea 100644 --- a/mrbgems/mruby-time/src/time.c +++ b/mrbgems/mruby-time/src/time.c @@ -267,7 +267,7 @@ mrb_to_time_t(mrb_state *mrb, mrb_value obj, time_t *usec) return t; out_of_range: - mrb_raisef(mrb, E_ARGUMENT_ERROR, "%S out of Time range", obj); + mrb_raisef(mrb, E_ARGUMENT_ERROR, "%v out of Time range", obj); /* not reached */ if (usec) { *usec = 0; } @@ -293,7 +293,7 @@ time_update_datetime(mrb_state *mrb, struct mrb_time *self, int dealloc) mrb_sec sec = (mrb_sec)t; if (dealloc) mrb_free(mrb, self); - mrb_raisef(mrb, E_ARGUMENT_ERROR, "%S out of Time range", mrb_sec_value(mrb, sec)); + mrb_raisef(mrb, E_ARGUMENT_ERROR, "%v out of Time range", mrb_sec_value(mrb, sec)); /* not reached */ return NULL; } diff --git a/src/array.c b/src/array.c index 8cf813743..06c23dcd3 100644 --- a/src/array.c +++ b/src/array.c @@ -668,7 +668,7 @@ mrb_ary_set(mrb_state *mrb, mrb_value ary, mrb_int n, mrb_value val) if (n < 0) { n += len; if (n < 0) { - mrb_raisef(mrb, E_INDEX_ERROR, "index %S out of array", mrb_fixnum_value(n - len)); + mrb_raisef(mrb, E_INDEX_ERROR, "index %i out of array", n - len); } } if (len <= n) { @@ -700,7 +700,7 @@ mrb_ary_splice(mrb_state *mrb, mrb_value ary, mrb_int head, mrb_int len, mrb_val ary_modify(mrb, a); /* len check */ - if (len < 0) mrb_raisef(mrb, E_INDEX_ERROR, "negative length (%S)", mrb_fixnum_value(len)); + if (len < 0) mrb_raisef(mrb, E_INDEX_ERROR, "negative length (%i)", len); /* range check */ if (head < 0) { @@ -734,7 +734,7 @@ mrb_ary_splice(mrb_state *mrb, mrb_value ary, mrb_int head, mrb_int len, mrb_val } if (head >= alen) { if (head > ARY_MAX_SIZE - argc) { - mrb_raisef(mrb, E_INDEX_ERROR, "index %S too big", mrb_fixnum_value(head)); + mrb_raisef(mrb, E_INDEX_ERROR, "index %i too big", head); } len = head + argc; if (len > ARY_CAPA(a)) { @@ -750,7 +750,7 @@ mrb_ary_splice(mrb_state *mrb, mrb_value ary, mrb_int head, mrb_int len, mrb_val mrb_int newlen; if (alen - len > ARY_MAX_SIZE - argc) { - mrb_raisef(mrb, E_INDEX_ERROR, "index %S too big", mrb_fixnum_value(alen + argc - len)); + mrb_raisef(mrb, E_INDEX_ERROR, "index %i too big", alen + argc - len); } newlen = alen + argc - len; if (newlen > ARY_CAPA(a)) { @@ -934,7 +934,7 @@ mrb_ary_aset(mrb_state *mrb, mrb_value self) mrb_ary_splice(mrb, self, i, len, v2); break; case MRB_RANGE_OUT: - mrb_raisef(mrb, E_RANGE_ERROR, "%S out of range", v1); + mrb_raisef(mrb, E_RANGE_ERROR, "%v out of range", v1); break; } return v2; diff --git a/src/backtrace.c b/src/backtrace.c index 991a67d00..c9a223e07 100644 --- a/src/backtrace.c +++ b/src/backtrace.c @@ -246,9 +246,7 @@ mrb_unpack_backtrace(mrb_state *mrb, mrb_value backtrace) mrb_value btline; if (entry->filename == NULL) continue; - btline = mrb_format(mrb, "%S:%S", - mrb_str_new_cstr(mrb, entry->filename), - mrb_fixnum_value(entry->lineno)); + btline = mrb_format(mrb, "%s:%d", entry->filename, entry->lineno); if (entry->method_id != 0) { mrb_str_cat_lit(mrb, btline, ":in "); mrb_str_cat_cstr(mrb, btline, mrb_sym2name(mrb, entry->method_id)); diff --git a/src/class.c b/src/class.c index 65d21ad4f..ff55de0e6 100644 --- a/src/class.c +++ b/src/class.c @@ -177,7 +177,7 @@ static void check_if_class_or_module(mrb_state *mrb, mrb_value obj) { if (!class_ptr_p(obj)) { - mrb_raisef(mrb, E_TYPE_ERROR, "%S is not a class/module", mrb_inspect(mrb, obj)); + mrb_raisef(mrb, E_TYPE_ERROR, "%!v is not a class/module", obj); } } @@ -215,7 +215,7 @@ mrb_vm_define_module(mrb_state *mrb, mrb_value outer, mrb_sym id) mrb_value old = mrb_const_get(mrb, outer, id); if (mrb_type(old) != MRB_TT_MODULE) { - mrb_raisef(mrb, E_TYPE_ERROR, "%S is not a module", mrb_inspect(mrb, old)); + mrb_raisef(mrb, E_TYPE_ERROR, "%!v is not a module", old); } return mrb_class_ptr(old); } @@ -248,9 +248,8 @@ define_class(mrb_state *mrb, mrb_sym name, struct RClass *super, struct RClass * c = class_from_sym(mrb, outer, name); MRB_CLASS_ORIGIN(c); if (super && mrb_class_real(c->super) != super) { - mrb_raisef(mrb, E_TYPE_ERROR, "superclass mismatch for Class %S (%S not %S)", - mrb_sym2str(mrb, name), - mrb_obj_value(c->super), mrb_obj_value(super)); + mrb_raisef(mrb, E_TYPE_ERROR, "superclass mismatch for Class %n (%C not %C)", + name, c->super, super); } return c; } @@ -265,7 +264,7 @@ MRB_API struct RClass* mrb_define_class_id(mrb_state *mrb, mrb_sym name, struct RClass *super) { if (!super) { - mrb_warn(mrb, "no super class for '%S', Object assumed", mrb_sym2str(mrb, name)); + mrb_warn(mrb, "no super class for '%n', Object assumed", name); } return define_class(mrb, name, super, mrb->object_class); } @@ -313,8 +312,7 @@ mrb_vm_define_class(mrb_state *mrb, mrb_value outer, mrb_value super, mrb_sym id if (!mrb_nil_p(super)) { if (mrb_type(super) != MRB_TT_CLASS) { - mrb_raisef(mrb, E_TYPE_ERROR, "superclass must be a Class (%S given)", - mrb_inspect(mrb, super)); + mrb_raisef(mrb, E_TYPE_ERROR, "superclass must be a Class (%!v given)", super); } s = mrb_class_ptr(super); } @@ -326,13 +324,13 @@ mrb_vm_define_class(mrb_state *mrb, mrb_value outer, mrb_value super, mrb_sym id mrb_value old = mrb_const_get(mrb, outer, id); if (mrb_type(old) != MRB_TT_CLASS) { - mrb_raisef(mrb, E_TYPE_ERROR, "%S is not a class", mrb_inspect(mrb, old)); + mrb_raisef(mrb, E_TYPE_ERROR, "%!v is not a class", old); } c = mrb_class_ptr(old); if (s) { /* check super class */ if (mrb_class_real(c->super) != s) { - mrb_raisef(mrb, E_TYPE_ERROR, "superclass mismatch for class %S", old); + mrb_raisef(mrb, E_TYPE_ERROR, "superclass mismatch for class %v", old); } } return c; @@ -431,8 +429,7 @@ mrb_define_class_under(mrb_state *mrb, struct RClass *outer, const char *name, s #if 0 if (!super) { - mrb_warn(mrb, "no super class for '%S::%S', Object assumed", - mrb_obj_value(outer), mrb_sym2str(mrb, id)); + mrb_warn(mrb, "no super class for '%C::%n', Object assumed", outer, id); } #endif c = define_class(mrb, id, super, outer); @@ -489,8 +486,7 @@ mrb_notimplement(mrb_state *mrb) mrb_callinfo *ci = mrb->c->ci; if (ci->mid) { - mrb_value str = mrb_sym2str(mrb, ci->mid); - mrb_raisef(mrb, E_NOTIMP_ERROR, "%S() function is unimplemented on this machine", str); + mrb_raisef(mrb, E_NOTIMP_ERROR, "%n() function is unimplemented on this machine", ci->mid); } } @@ -505,7 +501,7 @@ mrb_notimplement_m(mrb_state *mrb, mrb_value self) #define CHECK_TYPE(mrb, val, t, c) do { \ if (mrb_type(val) != (t)) {\ - mrb_raisef(mrb, E_TYPE_ERROR, "expected %S", mrb_str_new_lit(mrb, c));\ + mrb_raisef(mrb, E_TYPE_ERROR, "expected %l", c, sizeof(c "")-1);\ }\ } while (0) @@ -669,7 +665,7 @@ mrb_get_args(mrb_state *mrb, const char *format, ...) ss = ARGV[arg_i++]; if (!class_ptr_p(ss)) { - mrb_raisef(mrb, E_TYPE_ERROR, "%S is not class/module", ss); + mrb_raisef(mrb, E_TYPE_ERROR, "%v is not class/module", ss); } *p = ss; i++; @@ -816,7 +812,7 @@ mrb_get_args(mrb_state *mrb, const char *format, ...) ss = ARGV[arg_i]; if (mrb_type(ss) != MRB_TT_ISTRUCT) { - mrb_raisef(mrb, E_TYPE_ERROR, "%S is not inline struct", ss); + mrb_raisef(mrb, E_TYPE_ERROR, "%v is not inline struct", ss); } *p = mrb_istruct_ptr(ss); arg_i++; @@ -964,7 +960,7 @@ mrb_get_args(mrb_state *mrb, const char *format, ...) } break; default: - mrb_raisef(mrb, E_ARGUMENT_ERROR, "invalid argument specifier %S", mrb_str_new(mrb, &c, 1)); + mrb_raisef(mrb, E_ARGUMENT_ERROR, "invalid argument specifier %c", c); break; } } @@ -1357,8 +1353,7 @@ mrb_method_search(mrb_state *mrb, struct RClass* c, mrb_sym mid) if (mrb_string_p(inspect) && RSTRING_LEN(inspect) > 64) { inspect = mrb_any_to_s(mrb, mrb_obj_value(c)); } - mrb_name_error(mrb, mid, "undefined method '%S' for class %S", - mrb_sym2str(mrb, mid), inspect); + mrb_name_error(mrb, mid, "undefined method '%n' for class %v", mid, inspect); } return m; } @@ -1479,7 +1474,7 @@ mrb_instance_alloc(mrb_state *mrb, mrb_value cv) if (ttype == 0) ttype = MRB_TT_OBJECT; if (ttype <= MRB_TT_CPTR) { - mrb_raisef(mrb, E_TYPE_ERROR, "can't create instance of %S", cv); + mrb_raisef(mrb, E_TYPE_ERROR, "can't create instance of %v", cv); } o = (struct RObject*)mrb_obj_alloc(mrb, ttype, c); return mrb_obj_value(o); @@ -1706,7 +1701,7 @@ static void mrb_check_inheritable(mrb_state *mrb, struct RClass *super) { if (super->tt != MRB_TT_CLASS) { - mrb_raisef(mrb, E_TYPE_ERROR, "superclass must be a Class (%S given)", mrb_obj_value(super)); + mrb_raisef(mrb, E_TYPE_ERROR, "superclass must be a Class (%C given)", super); } if (super->tt == MRB_TT_SCLASS) { mrb_raise(mrb, E_TYPE_ERROR, "can't make subclass of singleton class"); @@ -1835,7 +1830,7 @@ void mrb_undef_method_id(mrb_state *mrb, struct RClass *c, mrb_sym a) { if (!mrb_obj_respond_to(mrb, c, a)) { - mrb_name_error(mrb, a, "undefined method '%S' for class '%S'", mrb_sym2str(mrb, a), mrb_obj_value(c)); + mrb_name_error(mrb, a, "undefined method '%n' for class '%C'", a, c); } else { mrb_method_t m; @@ -1878,7 +1873,7 @@ check_const_name_sym(mrb_state *mrb, mrb_sym id) mrb_int len; const char *name = mrb_sym2name_len(mrb, id, &len); if (!mrb_const_name_p(mrb, name, len)) { - mrb_name_error(mrb, id, "wrong constant name %S", mrb_sym2str(mrb, id)); + mrb_name_error(mrb, id, "wrong constant name %n", id); } } @@ -1935,7 +1930,7 @@ mrb_mod_const_get(mrb_state *mrb, mrb_value mod) else { off = end + 2; if (off == len) { /* trailing "::" */ - mrb_name_error(mrb, id, "wrong constant name '%S'", path); + mrb_name_error(mrb, id, "wrong constant name '%v'", path); } } } @@ -1965,7 +1960,7 @@ mrb_mod_remove_const(mrb_state *mrb, mrb_value mod) check_const_name_sym(mrb, id); val = mrb_iv_remove(mrb, mod, id); if (mrb_undef_p(val)) { - mrb_name_error(mrb, id, "constant %S not defined", mrb_sym2str(mrb, id)); + mrb_name_error(mrb, id, "constant %n not defined", id); } return val; } @@ -1978,13 +1973,10 @@ mrb_mod_const_missing(mrb_state *mrb, mrb_value mod) mrb_get_args(mrb, "n", &sym); if (mrb_class_real(mrb_class_ptr(mod)) != mrb->object_class) { - mrb_name_error(mrb, sym, "uninitialized constant %S::%S", - mod, - mrb_sym2str(mrb, sym)); + mrb_name_error(mrb, sym, "uninitialized constant %v::%n", mod, sym); } else { - mrb_name_error(mrb, sym, "uninitialized constant %S", - mrb_sym2str(mrb, sym)); + mrb_name_error(mrb, sym, "uninitialized constant %n", sym); } /* not reached */ return mrb_nil_value(); @@ -2045,7 +2037,7 @@ mod_define_method(mrb_state *mrb, mrb_value self) /* ignored */ break; default: - mrb_raisef(mrb, E_TYPE_ERROR, "wrong argument type %S (expected Proc)", mrb_obj_value(mrb_obj_class(mrb, proc))); + mrb_raisef(mrb, E_TYPE_ERROR, "wrong argument type %T (expected Proc)", proc); break; } if (mrb_nil_p(blk)) { diff --git a/src/error.c b/src/error.c index 0ca7f5917..664da3fd6 100644 --- a/src/error.c +++ b/src/error.c @@ -151,14 +151,14 @@ exc_inspect(mrb_state *mrb, mrb_value exc) str = mrb_str_new_cstr(mrb, cname); if (mrb_string_p(file) && mrb_fixnum_p(line)) { if (append_mesg) { - str = mrb_format(mrb, "%S:%S: %S (%S)", file, line, mesg, str); + str = mrb_format(mrb, "%v:%v: %v (%v)", file, line, mesg, str); } else { - str = mrb_format(mrb, "%S:%S: %S", file, line, str); + str = mrb_format(mrb, "%v:%v: %v", file, line, str); } } else if (append_mesg) { - str = mrb_format(mrb, "%S: %S", str, mesg); + str = mrb_format(mrb, "%v: %v", str, mesg); } return str; } @@ -523,7 +523,7 @@ exception_call: break; default: - mrb_raisef(mrb, E_ARGUMENT_ERROR, "wrong number of arguments (%S for 0..3)", mrb_fixnum_value(argc)); + mrb_raisef(mrb, E_ARGUMENT_ERROR, "wrong number of arguments (%i for 0..3)", argc); break; } if (argc > 0) { @@ -576,8 +576,7 @@ mrb_no_method_error(mrb_state *mrb, mrb_sym id, mrb_value args, char const* fmt, MRB_API mrb_noreturn void mrb_frozen_error(mrb_state *mrb, void *frozen_obj) { - mrb_raisef(mrb, E_FROZEN_ERROR, "can't modify frozen %S", - mrb_obj_value(mrb_class(mrb, mrb_obj_value(frozen_obj)))); + mrb_raisef(mrb, E_FROZEN_ERROR, "can't modify frozen %t", mrb_obj_value(frozen_obj)); } void diff --git a/src/etc.c b/src/etc.c index 18d2839d9..bf6586748 100644 --- a/src/etc.c +++ b/src/etc.c @@ -31,14 +31,12 @@ mrb_data_check_type(mrb_state *mrb, mrb_value obj, const mrb_data_type *type) const mrb_data_type *t2 = DATA_TYPE(obj); if (t2) { - mrb_raisef(mrb, E_TYPE_ERROR, "wrong argument type %S (expected %S)", - mrb_str_new_cstr(mrb, t2->struct_name), mrb_str_new_cstr(mrb, type->struct_name)); + mrb_raisef(mrb, E_TYPE_ERROR, "wrong argument type %s (expected %s)", + t2->struct_name, type->struct_name); } else { - struct RClass *c = mrb_class(mrb, obj); - - mrb_raisef(mrb, E_TYPE_ERROR, "uninitialized %S (expected %S)", - mrb_obj_value(c), mrb_str_new_cstr(mrb, type->struct_name)); + mrb_raisef(mrb, E_TYPE_ERROR, "uninitialized %t (expected %s)", + obj, type->struct_name); } } } @@ -67,7 +65,7 @@ mrb_obj_to_sym(mrb_state *mrb, mrb_value name) { if (mrb_symbol_p(name)) return mrb_symbol(name); if (mrb_string_p(name)) return mrb_intern_str(mrb, name); - mrb_raisef(mrb, E_TYPE_ERROR, "%S is not a symbol nor a string", mrb_inspect(mrb, name)); + mrb_raisef(mrb, E_TYPE_ERROR, "%!v is not a symbol nor a string", name); return 0; /* not reached */ } diff --git a/src/gc.c b/src/gc.c index b05d929a1..a7a67ebfa 100644 --- a/src/gc.c +++ b/src/gc.c @@ -542,7 +542,7 @@ mrb_obj_alloc(mrb_state *mrb, enum mrb_vtype ttype, struct RClass *cls) ttype != MRB_TT_ICLASS && ttype != MRB_TT_ENV && ttype != tt) { - mrb_raisef(mrb, E_TYPE_ERROR, "allocation failure of %S", mrb_obj_value(cls)); + mrb_raisef(mrb, E_TYPE_ERROR, "allocation failure of %C", cls); } } diff --git a/src/kernel.c b/src/kernel.c index f223be9fc..f0935a2f8 100644 --- a/src/kernel.c +++ b/src/kernel.c @@ -325,7 +325,7 @@ mrb_obj_clone(mrb_state *mrb, mrb_value self) mrb_value clone; if (mrb_immediate_p(self)) { - mrb_raisef(mrb, E_TYPE_ERROR, "can't clone %S", self); + mrb_raisef(mrb, E_TYPE_ERROR, "can't clone %v", self); } if (mrb_type(self) == MRB_TT_SCLASS) { mrb_raise(mrb, E_TYPE_ERROR, "can't clone singleton class"); @@ -366,7 +366,7 @@ mrb_obj_dup(mrb_state *mrb, mrb_value obj) mrb_value dup; if (mrb_immediate_p(obj)) { - mrb_raisef(mrb, E_TYPE_ERROR, "can't dup %S", obj); + mrb_raisef(mrb, E_TYPE_ERROR, "can't dup %v", obj); } if (mrb_type(obj) == MRB_TT_SCLASS) { mrb_raise(mrb, E_TYPE_ERROR, "can't dup singleton class"); @@ -641,7 +641,7 @@ mrb_obj_remove_instance_variable(mrb_state *mrb, mrb_value self) mrb_iv_name_sym_check(mrb, sym); val = mrb_iv_remove(mrb, self, sym); if (mrb_undef_p(val)) { - mrb_name_error(mrb, sym, "instance variable %S not defined", mrb_sym2str(mrb, sym)); + mrb_name_error(mrb, sym, "instance variable %n not defined", sym); } return val; } @@ -649,7 +649,7 @@ mrb_obj_remove_instance_variable(mrb_state *mrb, mrb_value self) void mrb_method_missing(mrb_state *mrb, mrb_sym name, mrb_value self, mrb_value args) { - mrb_no_method_error(mrb, name, args, "undefined method '%S'", mrb_sym2str(mrb, name)); + mrb_no_method_error(mrb, name, args, "undefined method '%n'", name); } /* 15.3.1.3.30 */ diff --git a/src/numeric.c b/src/numeric.c index b143b2f67..f96498106 100644 --- a/src/numeric.c +++ b/src/numeric.c @@ -1257,7 +1257,7 @@ mrb_flo_to_fixnum(mrb_state *mrb, mrb_value x) z = (mrb_int)d; } else { - mrb_raisef(mrb, E_RANGE_ERROR, "number (%S) too big for integer", x); + mrb_raisef(mrb, E_RANGE_ERROR, "number (%v) too big for integer", x); } } return mrb_fixnum_value(z); @@ -1389,7 +1389,7 @@ mrb_fixnum_to_str(mrb_state *mrb, mrb_value x, mrb_int base) mrb_int val = mrb_fixnum(x); if (base < 2 || 36 < base) { - mrb_raisef(mrb, E_ARGUMENT_ERROR, "invalid radix %S", mrb_fixnum_value(base)); + mrb_raisef(mrb, E_ARGUMENT_ERROR, "invalid radix %i", base); } if (val == 0) { @@ -1501,9 +1501,7 @@ integral_cmp(mrb_state *mrb, mrb_value self) static void cmperr(mrb_state *mrb, mrb_value v1, mrb_value v2) { - mrb_raisef(mrb, E_ARGUMENT_ERROR, "comparison of %S with %S failed", - mrb_obj_value(mrb_class(mrb, v1)), - mrb_obj_value(mrb_class(mrb, v2))); + mrb_raisef(mrb, E_ARGUMENT_ERROR, "comparison of %t with %t failed", v1, v2); } static mrb_value diff --git a/src/object.c b/src/object.c index 7c1879019..ee36da320 100644 --- a/src/object.c +++ b/src/object.c @@ -296,17 +296,6 @@ mrb_init_object(mrb_state *mrb) mrb_define_method(mrb, f, "inspect", false_to_s, MRB_ARGS_NONE()); } -static mrb_value -inspect_type(mrb_state *mrb, mrb_value val) -{ - if (mrb_type(val) == MRB_TT_FALSE || mrb_type(val) == MRB_TT_TRUE) { - return mrb_inspect(mrb, val); - } - else { - return mrb_str_new_cstr(mrb, mrb_obj_classname(mrb, val)); - } -} - static mrb_value convert_type(mrb_state *mrb, mrb_value val, const char *tname, const char *method, mrb_bool raise) { @@ -315,7 +304,7 @@ convert_type(mrb_state *mrb, mrb_value val, const char *tname, const char *metho m = mrb_intern_cstr(mrb, method); if (!mrb_respond_to(mrb, val, m)) { if (raise) { - mrb_raisef(mrb, E_TYPE_ERROR, "can't convert %S into %S", inspect_type(mrb, val), mrb_str_new_cstr(mrb, tname)); + mrb_raisef(mrb, E_TYPE_ERROR, "can't convert %Y into %s", val, tname); } return mrb_nil_value(); } @@ -330,8 +319,7 @@ mrb_convert_type(mrb_state *mrb, mrb_value val, enum mrb_vtype type, const char if (mrb_type(val) == type) return val; v = convert_type(mrb, val, tname, method, TRUE); if (mrb_type(v) != type) { - mrb_raisef(mrb, E_TYPE_ERROR, "%S cannot be converted to %S by #%S", val, - mrb_str_new_cstr(mrb, tname), mrb_str_new_cstr(mrb, method)); + mrb_raisef(mrb, E_TYPE_ERROR, "%v cannot be converted to %s by #%s", val, tname, method); } return v; } @@ -405,13 +393,12 @@ mrb_check_type(mrb_state *mrb, mrb_value x, enum mrb_vtype t) else { etype = mrb_obj_classname(mrb, x); } - mrb_raisef(mrb, E_TYPE_ERROR, "wrong argument type %S (expected %S)", - mrb_str_new_cstr(mrb, etype), mrb_str_new_cstr(mrb, type->name)); + mrb_raisef(mrb, E_TYPE_ERROR, "wrong argument type %s (expected %s)", + etype, type->name); } type++; } - mrb_raisef(mrb, E_TYPE_ERROR, "unknown type %S (%S given)", - mrb_fixnum_value(t), mrb_fixnum_value(mrb_type(x))); + mrb_raisef(mrb, E_TYPE_ERROR, "unknown type %d (%d given)", t, mrb_type(x)); } } @@ -499,15 +486,12 @@ mrb_to_int(mrb_state *mrb, mrb_value val) { if (!mrb_fixnum_p(val)) { - mrb_value type; - #ifndef MRB_WITHOUT_FLOAT if (mrb_float_p(val)) { return mrb_flo_to_fixnum(mrb, val); } #endif - type = inspect_type(mrb, val); - mrb_raisef(mrb, E_TYPE_ERROR, "can't convert %S to Integer", type); + mrb_raisef(mrb, E_TYPE_ERROR, "can't convert %Y to Integer", val); } return val; } @@ -598,8 +582,7 @@ MRB_API mrb_value mrb_ensure_string_type(mrb_state *mrb, mrb_value str) { if (!mrb_string_p(str)) { - mrb_raisef(mrb, E_TYPE_ERROR, "%S cannot be converted to String", - inspect_type(mrb, str)); + mrb_raisef(mrb, E_TYPE_ERROR, "%Y cannot be converted to String", str); } return str; } @@ -615,8 +598,7 @@ MRB_API mrb_value mrb_ensure_array_type(mrb_state *mrb, mrb_value ary) { if (!mrb_array_p(ary)) { - mrb_raisef(mrb, E_TYPE_ERROR, "%S cannot be converted to Array", - inspect_type(mrb, ary)); + mrb_raisef(mrb, E_TYPE_ERROR, "%Y cannot be converted to Array", ary); } return ary; } @@ -632,8 +614,7 @@ MRB_API mrb_value mrb_ensure_hash_type(mrb_state *mrb, mrb_value hash) { if (!mrb_hash_p(hash)) { - mrb_raisef(mrb, E_TYPE_ERROR, "%S cannot be converted to Hash", - inspect_type(mrb, hash)); + mrb_raisef(mrb, E_TYPE_ERROR, "%Y cannot be converted to Hash", hash); } return hash; } diff --git a/src/proc.c b/src/proc.c index 094fff816..a0edf22bc 100644 --- a/src/proc.c +++ b/src/proc.c @@ -153,8 +153,8 @@ mrb_proc_cfunc_env_get(mrb_state *mrb, mrb_int idx) mrb_raise(mrb, E_TYPE_ERROR, "Can't get cfunc env from cfunc Proc without REnv."); } if (idx < 0 || MRB_ENV_STACK_LEN(e) <= idx) { - mrb_raisef(mrb, E_INDEX_ERROR, "Env index out of range: %S (expected: 0 <= index < %S)", - mrb_fixnum_value(idx), mrb_fixnum_value(MRB_ENV_STACK_LEN(e))); + mrb_raisef(mrb, E_INDEX_ERROR, "Env index out of range: %i (expected: 0 <= index < %i)", + idx, MRB_ENV_STACK_LEN(e)); } return e->stack[idx]; diff --git a/src/range.c b/src/range.c index c9dfb2b3c..28862d779 100644 --- a/src/range.c +++ b/src/range.c @@ -363,7 +363,7 @@ mrb_get_values_at(mrb_state *mrb, mrb_value obj, mrb_int olen, mrb_int argc, con } } else { - mrb_raisef(mrb, E_TYPE_ERROR, "invalid values selector: %S", argv[i]); + mrb_raisef(mrb, E_TYPE_ERROR, "invalid values selector: %v", argv[i]); } } diff --git a/src/string.c b/src/string.c index ecbe21a22..71c6e126e 100644 --- a/src/string.c +++ b/src/string.c @@ -1226,7 +1226,7 @@ mrb_str_aref_m(mrb_state *mrb, mrb_value str) static mrb_noreturn void str_out_of_index(mrb_state *mrb, mrb_value index) { - mrb_raisef(mrb, E_INDEX_ERROR, "index %S out of string", index); + mrb_raisef(mrb, E_INDEX_ERROR, "index %v out of string", index); } static mrb_value @@ -1286,7 +1286,7 @@ mrb_str_aset(mrb_state *mrb, mrb_value str, mrb_value indx, mrb_value alen, mrb_ mrb_raise(mrb, E_INDEX_ERROR, "string not matched"); case STR_CHAR_RANGE: if (len < 0) { - mrb_raisef(mrb, E_INDEX_ERROR, "negative length %S", alen); + mrb_raisef(mrb, E_INDEX_ERROR, "negative length %v", alen); } charlen = RSTRING_CHAR_LEN(str); if (beg < 0) { beg += charlen; } @@ -1763,7 +1763,7 @@ mrb_str_index_m(mrb_state *mrb, mrb_value str) tmp = mrb_check_string_type(mrb, sub); if (mrb_nil_p(tmp)) { - mrb_raisef(mrb, E_TYPE_ERROR, "type mismatch: %S given", sub); + mrb_raisef(mrb, E_TYPE_ERROR, "type mismatch: %v given", sub); } sub = tmp; } @@ -2014,7 +2014,7 @@ mrb_str_rindex(mrb_state *mrb, mrb_value str) tmp = mrb_check_string_type(mrb, sub); if (mrb_nil_p(tmp)) { - mrb_raisef(mrb, E_TYPE_ERROR, "type mismatch: %S given", sub); + mrb_raisef(mrb, E_TYPE_ERROR, "type mismatch: %v given", sub); } sub = tmp; } @@ -2265,7 +2265,7 @@ mrb_str_len_to_inum(mrb_state *mrb, const char *str, mrb_int len, mrb_int base, break; default: if (base < 2 || 36 < base) { - mrb_raisef(mrb, E_ARGUMENT_ERROR, "illegal radix %S", mrb_fixnum_value(base)); + mrb_raisef(mrb, E_ARGUMENT_ERROR, "illegal radix %i", base); } break; } /* end of switch (base) { */ @@ -2325,8 +2325,7 @@ mrb_str_len_to_inum(mrb_state *mrb, const char *str, mrb_int len, mrb_int base, else #endif { - mrb_raisef(mrb, E_RANGE_ERROR, "string (%S) too big for integer", - mrb_str_new(mrb, str, pend-str)); + mrb_raisef(mrb, E_RANGE_ERROR, "string (%l) too big for integer", str, pend-str); } } } @@ -2342,8 +2341,7 @@ mrb_str_len_to_inum(mrb_state *mrb, const char *str, mrb_int len, mrb_int base, mrb_raise(mrb, E_ARGUMENT_ERROR, "string contains null byte"); /* not reached */ bad: - mrb_raisef(mrb, E_ARGUMENT_ERROR, "invalid string for number(%S)", - mrb_inspect(mrb, mrb_str_new(mrb, str, pend-str))); + mrb_raisef(mrb, E_ARGUMENT_ERROR, "invalid string for number(%!l)", str, pend-str); /* not reached */ return mrb_fixnum_value(0); } @@ -2419,7 +2417,7 @@ mrb_str_to_i(mrb_state *mrb, mrb_value self) mrb_get_args(mrb, "|i", &base); if (base < 0) { - mrb_raisef(mrb, E_ARGUMENT_ERROR, "illegal radix %S", mrb_fixnum_value(base)); + mrb_raisef(mrb, E_ARGUMENT_ERROR, "illegal radix %i", base); } return mrb_str_to_inum(mrb, self, base, FALSE); } @@ -2444,7 +2442,7 @@ mrb_cstr_to_dbl(mrb_state *mrb, const char * p, mrb_bool badcheck) if (p == end) { if (badcheck) { bad: - mrb_raisef(mrb, E_ARGUMENT_ERROR, "invalid string for float(%S)", mrb_str_new_cstr(mrb, p)); + mrb_raisef(mrb, E_ARGUMENT_ERROR, "invalid string for float(%s)", p); /* not reached */ } return d; diff --git a/src/variable.c b/src/variable.c index e6f2f397e..32416da4e 100644 --- a/src/variable.c +++ b/src/variable.c @@ -446,7 +446,7 @@ MRB_API void mrb_iv_name_sym_check(mrb_state *mrb, mrb_sym iv_name) { if (!mrb_iv_name_sym_p(mrb, iv_name)) { - mrb_name_error(mrb, iv_name, "'%S' is not allowed as an instance variable name", mrb_sym2str(mrb, iv_name)); + mrb_name_error(mrb, iv_name, "'%n' is not allowed as an instance variable name", iv_name); } } @@ -654,8 +654,7 @@ mrb_mod_cv_get(mrb_state *mrb, struct RClass *c, mrb_sym sym) if (given) return v; } } - mrb_name_error(mrb, sym, "uninitialized class variable %S in %S", - mrb_sym2str(mrb, sym), mrb_obj_value(cls)); + mrb_name_error(mrb, sym, "uninitialized class variable %n in %C", sym, cls); /* not reached */ return mrb_nil_value(); } diff --git a/src/vm.c b/src/vm.c index 86262650e..12805a8e4 100644 --- a/src/vm.c +++ b/src/vm.c @@ -461,7 +461,7 @@ mrb_funcall_with_block(mrb_state *mrb, mrb_value self, mrb_sym mid, mrb_int argc stack_init(mrb); } if (argc < 0) { - mrb_raisef(mrb, E_ARGUMENT_ERROR, "negative argc for funcall (%S)", mrb_fixnum_value(argc)); + mrb_raisef(mrb, E_ARGUMENT_ERROR, "negative argc for funcall (%i)", argc); } c = mrb_class(mrb, self); m = mrb_method_search_vm(mrb, &c, mid); @@ -878,13 +878,11 @@ argnum_error(mrb_state *mrb, mrb_int num) } } if (mrb->c->ci->mid) { - str = mrb_format(mrb, "'%S': wrong number of arguments (%S for %S)", - mrb_sym2str(mrb, mrb->c->ci->mid), - mrb_fixnum_value(argc), mrb_fixnum_value(num)); + str = mrb_format(mrb, "'%n': wrong number of arguments (%i for %i)", + mrb->c->ci->mid, argc, num); } else { - str = mrb_format(mrb, "wrong number of arguments (%S for %S)", - mrb_fixnum_value(argc), mrb_fixnum_value(num)); + str = mrb_format(mrb, "wrong number of arguments (%i for %i)", argc, num); } exc = mrb_exc_new_str(mrb, E_ARGUMENT_ERROR, str); mrb_exc_set(mrb, exc); @@ -1868,7 +1866,7 @@ RETRY_TRY_BLOCK: mrb_value kdict = regs[mrb->c->ci->argc]; if (!mrb_hash_p(kdict) || !mrb_hash_key_p(mrb, kdict, k)) { - mrb_value str = mrb_format(mrb, "missing keyword: %S", k); + mrb_value str = mrb_format(mrb, "missing keyword: %v", k); mrb_exc_set(mrb, mrb_exc_new_str(mrb, E_ARGUMENT_ERROR, str)); goto L_RAISE; } @@ -1895,7 +1893,7 @@ RETRY_TRY_BLOCK: if (mrb_hash_p(kdict) && !mrb_hash_empty_p(mrb, kdict)) { mrb_value keys = mrb_hash_keys(mrb, kdict); mrb_value key1 = RARRAY_PTR(keys)[0]; - mrb_value str = mrb_format(mrb, "unknown keyword: %S", key1); + mrb_value str = mrb_format(mrb, "unknown keyword: %v", key1); mrb_exc_set(mrb, mrb_exc_new_str(mrb, E_ARGUMENT_ERROR, str)); goto L_RAISE; } diff --git a/tasks/toolchains/visualcpp.rake b/tasks/toolchains/visualcpp.rake index 9bf0f085e..6275059bb 100644 --- a/tasks/toolchains/visualcpp.rake +++ b/tasks/toolchains/visualcpp.rake @@ -2,7 +2,7 @@ MRuby::Toolchain.new(:visualcpp) do |conf, _params| conf.cc do |cc| cc.command = ENV['CC'] || 'cl.exe' # C4013: implicit function declaration - cc.flags = [ENV['CFLAGS'] || %w(/c /nologo /W3 /we4013 /Zi /Zm2000 /MD /O2 /D_CRT_SECURE_NO_WARNINGS)] + cc.flags = [ENV['CFLAGS'] || %w(/c /nologo /W3 /we4013 /Zi /MD /O2 /D_CRT_SECURE_NO_WARNINGS)] cc.defines = %w(MRB_STACK_EXTEND_DOUBLING) cc.option_include_path = '/I%s' cc.option_define = '/D%s' -- cgit v1.2.3 From 3dc8d9d7b3d0be2f91fa050a13e3b422500df628 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Tue, 6 Aug 2019 20:47:35 +0900 Subject: Should have cleared `mrb->globals` in `mrb_gc_free_gv`; fix #4618 --- src/variable.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/variable.c b/src/variable.c index 32416da4e..ab3bea327 100644 --- a/src/variable.c +++ b/src/variable.c @@ -268,8 +268,10 @@ mrb_gc_mark_gv(mrb_state *mrb) void mrb_gc_free_gv(mrb_state *mrb) { - if (mrb->globals) + if (mrb->globals) { iv_free(mrb, mrb->globals); + mrb->globals = NULL; + } } void -- cgit v1.2.3 From 2ba8399ac81516ad6fa26195790469655ffaf96c Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Tue, 6 Aug 2019 20:50:26 +0900 Subject: Removed an unused local variable; ref #4615 --- mrbgems/mruby-io/src/io.c | 1 - 1 file changed, 1 deletion(-) diff --git a/mrbgems/mruby-io/src/io.c b/mrbgems/mruby-io/src/io.c index a0b6c6780..a43ebcb91 100644 --- a/mrbgems/mruby-io/src/io.c +++ b/mrbgems/mruby-io/src/io.c @@ -758,7 +758,6 @@ mrb_io_s_sysclose(mrb_state *mrb, mrb_value klass) int mrb_cloexec_open(mrb_state *mrb, const char *pathname, mrb_int flags, mrb_int mode) { - mrb_value emsg; int fd, retry = FALSE; char* fname = mrb_locale_from_utf8(pathname, -1); -- cgit v1.2.3 From 6e2edd8ed27d94b6ed8b4668c7124ee8b8d33eee Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Tue, 6 Aug 2019 23:04:40 +0900 Subject: Add `mrb_noreturn` to `cmperr()` in `src/numeric.c` --- src/numeric.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/numeric.c b/src/numeric.c index f96498106..18b8ff461 100644 --- a/src/numeric.c +++ b/src/numeric.c @@ -1498,7 +1498,7 @@ integral_cmp(mrb_state *mrb, mrb_value self) return mrb_fixnum_value(n); } -static void +static mrb_noreturn void cmperr(mrb_state *mrb, mrb_value v1, mrb_value v2) { mrb_raisef(mrb, E_ARGUMENT_ERROR, "comparison of %t with %t failed", v1, v2); -- cgit v1.2.3 From eceaa80de7ecb6648e3829a9258e1349679e5805 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Wed, 7 Aug 2019 08:49:36 +0900 Subject: `RUBY_PLATFORM` may not contain `mswin` or `mingw`; Add `msys` --- mrbgems/mruby-io/mrbgem.rake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mrbgems/mruby-io/mrbgem.rake b/mrbgems/mruby-io/mrbgem.rake index d79964590..e4f0b7bb6 100644 --- a/mrbgems/mruby-io/mrbgem.rake +++ b/mrbgems/mruby-io/mrbgem.rake @@ -6,7 +6,7 @@ MRuby::Gem::Specification.new('mruby-io') do |spec| spec.cc.include_paths << "#{build.root}/src" case RUBY_PLATFORM - when /mingw|mswin/ + when /mingw|mswin|msys/ spec.linker.libraries += ['Ws2_32'] #spec.cc.include_paths += ["C:/Windows/system/include"] spec.linker.library_paths += ["C:/Windows/system"] -- cgit v1.2.3 From 2e73fe5ea1ef5cb6cb73be8a5b14c620378e2c27 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Wed, 7 Aug 2019 15:00:36 +0900 Subject: Replace i.e. (means "that is") with e.g. (means "for example"). --- doc/guides/compile.md | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/doc/guides/compile.md b/doc/guides/compile.md index 2aaf6f1fe..b01e89ff2 100644 --- a/doc/guides/compile.md +++ b/doc/guides/compile.md @@ -6,11 +6,11 @@ binaries. ## Prerequisites To compile mruby out of the source code you need the following tools: -* C Compiler (i.e. ```gcc```) -* Linker (i.e. ```gcc```) -* Archive utility (i.e. ```ar```) -* Parser generator (i.e. ```bison```) -* Ruby 1.8 or 1.9 (i.e. ```ruby``` or ```jruby```) +* C Compiler (e.g. ```gcc```) +* Linker (e.g. ```gcc```) +* Archive utility (e.g. ```ar```) +* Parser generator (e.g. ```bison```) +* Ruby 1.8 or 1.9 (e.g. ```ruby``` or ```jruby```) Optional: * GIT (to update mruby source and integrate mrbgems easier) @@ -463,7 +463,7 @@ linking with *build/i386/lib/libmruby_core.a* ### Minimal Library To build a minimal mruby library you need to use the Cross Compiling -feature due to the reason that there are functions (i.e. stdio) which +feature due to the reason that there are functions (e.g. stdio) which can't be disabled for the main build. ```ruby @@ -477,7 +477,7 @@ end This configuration defines a cross compile build called 'Minimal' which is using the GCC and compiles for the host machine. It also disables -all usages of stdio and doesn't compile any binaries (i.e. mrbc). +all usages of stdio and doesn't compile any binaries (e.g. mrbc). ## Test Environment -- cgit v1.2.3 From b8a87bd1115bc7f89e2e6caadb70d868d59b3a81 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Wed, 7 Aug 2019 15:03:16 +0900 Subject: Update required Ruby version to 2.0 or later. --- doc/guides/compile.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/guides/compile.md b/doc/guides/compile.md index b01e89ff2..4c8378946 100644 --- a/doc/guides/compile.md +++ b/doc/guides/compile.md @@ -10,7 +10,7 @@ To compile mruby out of the source code you need the following tools: * Linker (e.g. ```gcc```) * Archive utility (e.g. ```ar```) * Parser generator (e.g. ```bison```) -* Ruby 1.8 or 1.9 (e.g. ```ruby``` or ```jruby```) +* Ruby 2.0 or later (e.g. ```ruby``` or ```jruby```) Optional: * GIT (to update mruby source and integrate mrbgems easier) -- cgit v1.2.3 From 98fc887cb3d9458313cc275c4176d16e95c7c0c2 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Wed, 7 Aug 2019 15:40:44 +0900 Subject: Reorganize `mrb_string_value_cstr` and related functions. `mrb_string_value_cstr` and `mrb_string_value_len`: obsolete `mrb_string_cstr`: new function to retrieve NULL terminated C string `RSTRING_CSTR`: wrapper macro of `mrb_string_cstr` --- include/mruby/string.h | 16 +++++++--------- mrbgems/mruby-io/src/file.c | 20 ++++++++++---------- mrbgems/mruby-io/src/file_test.c | 2 +- mrbgems/mruby-io/src/io.c | 16 ++++++++-------- mrbgems/mruby-socket/src/socket.c | 4 ++-- mrbgems/mruby-test/vformat.c | 2 +- src/class.c | 2 +- src/string.c | 28 +++++++++++++++++++--------- 8 files changed, 49 insertions(+), 41 deletions(-) diff --git a/include/mruby/string.h b/include/mruby/string.h index d17ac1c1d..7266c9084 100644 --- a/include/mruby/string.h +++ b/include/mruby/string.h @@ -96,6 +96,7 @@ struct RString { #define RSTRING_CAPA(s) RSTR_CAPA(RSTRING(s)) #define RSTRING_END(s) (RSTRING_PTR(s) + RSTRING_LEN(s)) MRB_API mrb_int mrb_str_strlen(mrb_state*, struct RString*); +#define RSTRING_CSTR(mrb,s) mrb_string_cstr(mrb, s) #define MRB_STR_SHARED 1 #define MRB_STR_FSHARED 2 @@ -337,16 +338,13 @@ MRB_API mrb_value mrb_string_type(mrb_state *mrb, mrb_value str); MRB_API mrb_value mrb_str_new_capa(mrb_state *mrb, size_t capa); MRB_API mrb_value mrb_str_buf_new(mrb_state *mrb, size_t capa); -MRB_API const char *mrb_string_value_cstr(mrb_state *mrb, mrb_value *ptr); +/* NULL terminated C string from mrb_value */ +MRB_API const char *mrb_string_cstr(mrb_state *mrb, mrb_value str); +/* NULL terminated C string from mrb_value; `str` will be updated */ +MRB_API const char *mrb_string_value_cstr(mrb_state *mrb, mrb_value *str); +/* obslete: use RSTRING_PTR() */ MRB_API const char *mrb_string_value_ptr(mrb_state *mrb, mrb_value str); -/* - * Returns the length of the Ruby string. - * - * - * @param [mrb_state] mrb The current mruby state. - * @param [mrb_value] str Ruby string. - * @return [mrb_int] The length of the passed in Ruby string. - */ +/* obslete: use RSTRING_LEN() */ MRB_API mrb_int mrb_string_value_len(mrb_state *mrb, mrb_value str); /* diff --git a/mrbgems/mruby-io/src/file.c b/mrbgems/mruby-io/src/file.c index 5e6c849f0..2fbda90af 100644 --- a/mrbgems/mruby-io/src/file.c +++ b/mrbgems/mruby-io/src/file.c @@ -116,7 +116,7 @@ mrb_file_s_unlink(mrb_state *mrb, mrb_value obj) for (i = 0; i < argc; i++) { const char *utf8_path; pathv = mrb_ensure_string_type(mrb, argv[i]); - utf8_path = mrb_string_value_cstr(mrb, &pathv); + utf8_path = RSTRING_CSTR(mrb, pathv); path = mrb_locale_from_utf8(utf8_path, -1); if (UNLINK(path) < 0) { mrb_locale_free(path); @@ -134,8 +134,8 @@ mrb_file_s_rename(mrb_state *mrb, mrb_value obj) char *src, *dst; mrb_get_args(mrb, "SS", &from, &to); - src = mrb_locale_from_utf8(mrb_string_value_cstr(mrb, &from), -1); - dst = mrb_locale_from_utf8(mrb_string_value_cstr(mrb, &to), -1); + src = mrb_locale_from_utf8(RSTRING_CSTR(mrb, from), -1); + dst = mrb_locale_from_utf8(RSTRING_CSTR(mrb, to), -1); if (rename(src, dst) < 0) { #if defined(_WIN32) || defined(_WIN64) if (CHMOD(dst, 0666) == 0 && UNLINK(dst) == 0 && rename(src, dst) == 0) { @@ -146,7 +146,7 @@ mrb_file_s_rename(mrb_state *mrb, mrb_value obj) #endif mrb_locale_free(src); mrb_locale_free(dst); - mrb_sys_fail(mrb, RSTRING_PTR(mrb_format(mrb, "(%v, %v)", from, to))); + mrb_sys_fail(mrb, RSTRING_CSTR(mrb, mrb_format(mrb, "(%v, %v)", from, to))); } mrb_locale_free(src); mrb_locale_free(dst); @@ -248,7 +248,7 @@ mrb_file_realpath(mrb_state *mrb, mrb_value klass) s = mrb_str_append(mrb, s, pathname); pathname = s; } - cpath = mrb_locale_from_utf8(mrb_string_value_cstr(mrb, &pathname), -1); + cpath = mrb_locale_from_utf8(RSTRING_CSTR(mrb, pathname), -1); result = mrb_str_buf_new(mrb, PATH_MAX); if (realpath(cpath, RSTRING_PTR(result)) == NULL) { mrb_locale_free(cpath); @@ -300,7 +300,7 @@ mrb_file__gethome(mrb_state *mrb, mrb_value klass) mrb_raise(mrb, E_ARGUMENT_ERROR, "non-absolute home"); } } else { - const char *cuser = mrb_string_value_cstr(mrb, &username); + const char *cuser = RSTRING_CSTR(mrb, username); struct passwd *pwd = getpwnam(cuser); if (pwd == NULL) { return mrb_nil_value(); @@ -393,12 +393,12 @@ mrb_file_s_symlink(mrb_state *mrb, mrb_value klass) int ai = mrb_gc_arena_save(mrb); mrb_get_args(mrb, "SS", &from, &to); - src = mrb_locale_from_utf8(mrb_string_value_cstr(mrb, &from), -1); - dst = mrb_locale_from_utf8(mrb_string_value_cstr(mrb, &to), -1); + src = mrb_locale_from_utf8(RSTRING_CSTR(mrb, from), -1); + dst = mrb_locale_from_utf8(RSTRING_CSTR(mrb, to), -1); if (symlink(src, dst) == -1) { mrb_locale_free(src); mrb_locale_free(dst); - mrb_sys_fail(mrb, RSTRING_PTR(mrb_format(mrb, "(%v, %v)", from, to))); + mrb_sys_fail(mrb, RSTRING_CSTR(mrb, mrb_format(mrb, "(%v, %v)", from, to))); } mrb_locale_free(src); mrb_locale_free(dst); @@ -416,7 +416,7 @@ mrb_file_s_chmod(mrb_state *mrb, mrb_value klass) { mrb_get_args(mrb, "i*", &mode, &filenames, &argc); for (i = 0; i < argc; i++) { - const char *utf8_path = mrb_string_value_cstr(mrb, &filenames[i]); + const char *utf8_path = RSTRING_CSTR(mrb, filenames[i]); char *path = mrb_locale_from_utf8(utf8_path, -1); if (CHMOD(path, mode) == -1) { mrb_locale_free(path); diff --git a/mrbgems/mruby-io/src/file_test.c b/mrbgems/mruby-io/src/file_test.c index 85a221ff9..445bafde9 100644 --- a/mrbgems/mruby-io/src/file_test.c +++ b/mrbgems/mruby-io/src/file_test.c @@ -54,7 +54,7 @@ mrb_stat0(mrb_state *mrb, mrb_value obj, struct stat *st, int do_lstat) return -1; } else { - char *path = mrb_locale_from_utf8(mrb_string_value_cstr(mrb, &obj), -1); + char *path = mrb_locale_from_utf8(RSTRING_CSTR(mrb, obj), -1); int ret; if (do_lstat) { ret = LSTAT(path, st); diff --git a/mrbgems/mruby-io/src/io.c b/mrbgems/mruby-io/src/io.c index a43ebcb91..eb9c4097b 100644 --- a/mrbgems/mruby-io/src/io.c +++ b/mrbgems/mruby-io/src/io.c @@ -332,8 +332,8 @@ mrb_io_s_popen(mrb_state *mrb, mrb_value klass) mrb_get_args(mrb, "S|SH", &cmd, &mode, &opt); io = mrb_obj_value(mrb_data_object_alloc(mrb, mrb_class_ptr(klass), NULL, &mrb_io_type)); - pname = mrb_string_value_cstr(mrb, &cmd); - flags = mrb_io_modestr_to_flags(mrb, mrb_string_value_cstr(mrb, &mode)); + pname = RSTRING_CSTR(mrb, cmd); + flags = mrb_io_modestr_to_flags(mrb, RSTRING_CSTR(mrb, mode)); doexec = (strcmp("-", pname) != 0); opt_in = option_to_fd(mrb, opt, "in"); @@ -428,8 +428,8 @@ mrb_io_s_popen(mrb_state *mrb, mrb_value klass) mrb_get_args(mrb, "S|SH", &cmd, &mode, &opt); io = mrb_obj_value(mrb_data_object_alloc(mrb, mrb_class_ptr(klass), NULL, &mrb_io_type)); - pname = mrb_string_value_cstr(mrb, &cmd); - flags = mrb_io_modestr_to_flags(mrb, mrb_string_value_cstr(mrb, &mode)); + pname = RSTRING_CSTR(mrb, cmd); + flags = mrb_io_modestr_to_flags(mrb, RSTRING_CSTR(mrb, mode)); doexec = (strcmp("-", pname) != 0); opt_in = option_to_fd(mrb, opt, "in"); @@ -626,7 +626,7 @@ mrb_io_initialize(mrb_state *mrb, mrb_value io) opt = mrb_hash_new(mrb); } - flags = mrb_io_modestr_to_flags(mrb, mrb_string_value_cstr(mrb, &mode)); + flags = mrb_io_modestr_to_flags(mrb, RSTRING_CSTR(mrb, mode)); mrb_iv_set(mrb, io, mrb_intern_cstr(mrb, "@buf"), mrb_str_new_cstr(mrb, "")); @@ -780,7 +780,7 @@ reopen: } } - mrb_sys_fail(mrb, RSTRING_PTR(mrb_format(mrb, "open %s", pathname))); + mrb_sys_fail(mrb, RSTRING_CSTR(mrb, mrb_format(mrb, "open %s", pathname))); } mrb_locale_free(fname); @@ -807,8 +807,8 @@ mrb_io_s_sysopen(mrb_state *mrb, mrb_value klass) perm = 0666; } - pat = mrb_string_value_cstr(mrb, &path); - flags = mrb_io_modestr_to_flags(mrb, mrb_string_value_cstr(mrb, &mode)); + pat = RSTRING_CSTR(mrb, path); + flags = mrb_io_modestr_to_flags(mrb, RSTRING_CSTR(mrb, mode)); modenum = mrb_io_flags_to_modenum(mrb, flags); fd = mrb_cloexec_open(mrb, pat, modenum, perm); return mrb_fixnum_value(fd); diff --git a/mrbgems/mruby-socket/src/socket.c b/mrbgems/mruby-socket/src/socket.c index eaca27779..53f761617 100644 --- a/mrbgems/mruby-socket/src/socket.c +++ b/mrbgems/mruby-socket/src/socket.c @@ -131,7 +131,7 @@ mrb_addrinfo_getaddrinfo(mrb_state *mrb, mrb_value klass) mrb_get_args(mrb, "oo|oooi", &nodename, &service, &family, &socktype, &protocol, &flags); if (mrb_string_p(nodename)) { - hostname = mrb_string_value_cstr(mrb, &nodename); + hostname = RSTRING_CSTR(mrb, nodename); } else if (mrb_nil_p(nodename)) { hostname = NULL; } else { @@ -139,7 +139,7 @@ mrb_addrinfo_getaddrinfo(mrb_state *mrb, mrb_value klass) } if (mrb_string_p(service)) { - servname = mrb_string_value_cstr(mrb, &service); + servname = RSTRING_CSTR(mrb, service); } else if (mrb_fixnum_p(service)) { servname = RSTRING_PTR(mrb_fixnum_to_str(mrb, service, 10)); } else if (mrb_nil_p(service)) { diff --git a/mrbgems/mruby-test/vformat.c b/mrbgems/mruby-test/vformat.c index 6e0c2887f..6984aaeb1 100644 --- a/mrbgems/mruby-test/vformat.c +++ b/mrbgems/mruby-test/vformat.c @@ -166,7 +166,7 @@ vf_s_format(mrb_state *mrb, mrb_value klass) { mrb_value fmt_str, args[2]; mrb_int argc = mrb_get_args(mrb, "S|oo", &fmt_str, args, args+1); - const char *fmt = mrb_string_value_cstr(mrb, &fmt_str); + const char *fmt = RSTRING_CSTR(mrb, fmt_str); VF_FORMAT_INIT(klass); diff --git a/src/class.c b/src/class.c index ff55de0e6..5b190d28b 100644 --- a/src/class.c +++ b/src/class.c @@ -770,7 +770,7 @@ mrb_get_args(mrb_state *mrb, const char *format, ...) } if (i < argc) { ss = to_str(mrb, ARGV[arg_i++]); - *ps = mrb_string_value_cstr(mrb, &ss); + *ps = RSTRING_CSTR(mrb, ss); i++; } } diff --git a/src/string.c b/src/string.c index 71c6e126e..50c283593 100644 --- a/src/string.c +++ b/src/string.c @@ -1060,6 +1060,7 @@ mrb_str_to_str(mrb_state *mrb, mrb_value str) } } +/* obslete: use RSTRING_PTR() */ MRB_API const char* mrb_string_value_ptr(mrb_state *mrb, mrb_value str) { @@ -1067,6 +1068,7 @@ mrb_string_value_ptr(mrb_state *mrb, mrb_value str) return RSTRING_PTR(str); } +/* obslete: use RSTRING_LEN() */ MRB_API mrb_int mrb_string_value_len(mrb_state *mrb, mrb_value ptr) { @@ -2352,6 +2354,7 @@ mrb_cstr_to_inum(mrb_state *mrb, const char *str, mrb_int base, mrb_bool badchec return mrb_str_len_to_inum(mrb, str, strlen(str), base, badcheck); } +/* obslete: use RSTRING_CSTR() or mrb_string_cstr() */ MRB_API const char* mrb_string_value_cstr(mrb_state *mrb, mrb_value *ptr) { @@ -2366,16 +2369,23 @@ mrb_string_value_cstr(mrb_state *mrb, mrb_value *ptr) if (p[len] == '\0') { return p; } + if (MRB_FROZEN_P(ps) || RSTR_CAPA(ps) == len) { + ps = str_new(mrb, NULL, len+1); + memcpy(RSTR_PTR(ps), p, len); + RSTR_SET_LEN(ps, len); + *ptr = mrb_obj_value(ps); + } else { - if (MRB_FROZEN_P(ps)) { - ps = str_new(mrb, p, len); - *ptr = mrb_obj_value(ps); - } - else { - mrb_str_modify(mrb, ps); - } - return RSTR_PTR(ps); + mrb_str_modify(mrb, ps); } + RSTR_PTR(ps)[len] = '\0'; + return RSTR_PTR(ps); +} + +MRB_API const char* +mrb_string_cstr(mrb_state *mrb, mrb_value str) +{ + return mrb_string_value_cstr(mrb, &str); } MRB_API mrb_value @@ -2489,7 +2499,7 @@ bad: MRB_API double mrb_str_to_dbl(mrb_state *mrb, mrb_value str, mrb_bool badcheck) { - return mrb_cstr_to_dbl(mrb, mrb_string_value_cstr(mrb, &str), badcheck); + return mrb_cstr_to_dbl(mrb, RSTRING_CSTR(mrb, str), badcheck); } /* 15.2.10.5.39 */ -- cgit v1.2.3 From b377b7d58062d555cc45249ae038c8b2875eec9e Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Wed, 7 Aug 2019 16:20:40 +0900 Subject: Update `mrb_to_str` and related functions. Contrary to the name, `mrb_to_str` just checks type, no conversion. --- include/mruby.h | 1 + src/class.c | 23 +++++------------------ src/string.c | 5 +++-- 3 files changed, 9 insertions(+), 20 deletions(-) diff --git a/include/mruby.h b/include/mruby.h index 7deb3cbe2..55505a213 100644 --- a/include/mruby.h +++ b/include/mruby.h @@ -1186,6 +1186,7 @@ MRB_API void mrb_gc_unregister(mrb_state *mrb, mrb_value obj); MRB_API mrb_value mrb_to_int(mrb_state *mrb, mrb_value val); #define mrb_int(mrb, val) mrb_fixnum(mrb_to_int(mrb, val)) +/* string type checking (contrary to the name, it doesn't convert) */ MRB_API mrb_value mrb_to_str(mrb_state *mrb, mrb_value val); MRB_API void mrb_check_type(mrb_state *mrb, mrb_value x, enum mrb_vtype t); diff --git a/src/class.c b/src/class.c index 5b190d28b..f66c5794d 100644 --- a/src/class.c +++ b/src/class.c @@ -499,30 +499,17 @@ mrb_notimplement_m(mrb_state *mrb, mrb_value self) return mrb_nil_value(); } -#define CHECK_TYPE(mrb, val, t, c) do { \ - if (mrb_type(val) != (t)) {\ - mrb_raisef(mrb, E_TYPE_ERROR, "expected %l", c, sizeof(c "")-1);\ - }\ -} while (0) - -static mrb_value -to_str(mrb_state *mrb, mrb_value val) -{ - CHECK_TYPE(mrb, val, MRB_TT_STRING, "String"); - return val; -} - static mrb_value to_ary(mrb_state *mrb, mrb_value val) { - CHECK_TYPE(mrb, val, MRB_TT_ARRAY, "Array"); + mrb_check_type(mrb, val, MRB_TT_ARRAY); return val; } static mrb_value to_hash(mrb_state *mrb, mrb_value val) { - CHECK_TYPE(mrb, val, MRB_TT_HASH, "Hash"); + mrb_check_type(mrb, val, MRB_TT_HASH); return val; } @@ -686,7 +673,7 @@ mrb_get_args(mrb_state *mrb, const char *format, ...) } } if (i < argc) { - *p = to_str(mrb, ARGV[arg_i++]); + *p = mrb_to_str(mrb, ARGV[arg_i++]); i++; } } @@ -747,7 +734,7 @@ mrb_get_args(mrb_state *mrb, const char *format, ...) } } if (i < argc) { - ss = to_str(mrb, ARGV[arg_i++]); + ss = mrb_to_str(mrb, ARGV[arg_i++]); *ps = RSTRING_PTR(ss); *pl = RSTRING_LEN(ss); i++; @@ -769,7 +756,7 @@ mrb_get_args(mrb_state *mrb, const char *format, ...) } } if (i < argc) { - ss = to_str(mrb, ARGV[arg_i++]); + ss = mrb_to_str(mrb, ARGV[arg_i++]); *ps = RSTRING_CSTR(mrb, ss); i++; } diff --git a/src/string.c b/src/string.c index 50c283593..daf293368 100644 --- a/src/string.c +++ b/src/string.c @@ -1280,7 +1280,7 @@ mrb_str_aset(mrb_state *mrb, mrb_value str, mrb_value indx, mrb_value alen, mrb_ { mrb_int beg, len, charlen; - replace = mrb_to_str(mrb, replace); + mrb_to_str(mrb, replace); switch (str_convert_range(mrb, str, indx, alen, &beg, &len)) { case STR_OUT_OF_RANGE: @@ -2394,7 +2394,8 @@ mrb_str_to_inum(mrb_state *mrb, mrb_value str, mrb_int base, mrb_bool badcheck) const char *s; mrb_int len; - s = mrb_string_value_ptr(mrb, str); + mrb_to_str(mrb, str); + s = RSTRING_PTR(str); len = RSTRING_LEN(str); return mrb_str_len_to_inum(mrb, s, len, base, badcheck); } -- cgit v1.2.3 From 7e42b6ad3f449cb49568dcd5b7439f7ba3908dae Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Wed, 7 Aug 2019 21:50:22 +0900 Subject: Improve MiniRake rule enhancement for Rake compatibility Support pathmap notation, recursive dependencies search, and so on. --- minirake | 38 +++++++++++++++++++++++++++----------- 1 file changed, 27 insertions(+), 11 deletions(-) diff --git a/minirake b/minirake index cd2d85854..8df395e97 100755 --- a/minirake +++ b/minirake @@ -206,25 +206,41 @@ module MiniRake # task with the prerequisites and actions from the rule. Set the # source attribute of the task appropriately for the rule. Return # the enhanced task or nil of no rule was found. - def enhance_with_matching_rule(task_name) + def enhance_with_matching_rule(task_name, level=0) + fail "Rule Recursion Too Deep: #{task_name}" if level >= 16 RULES.each do |pattern, extensions, block| - if pattern.match(task_name) - ext = extensions.first - deps = extensions[1..-1] + next unless pattern && pattern.match(task_name) + sources = extensions.flat_map do |ext| case ext + when /%/ + task_name.pathmap(ext) + when %r{/} + ext + when /^\./ + source = task_name.sub(pattern, ext) + source == ext ? task_name.ext(ext) : source when String - source = task_name.sub(/\.[^.]*$/, ext) - when Proc - source = ext.call(task_name) + ext + when Proc, Method + ext.arity == 1 ? ext.call(task_name) : ext.call else fail "Don't know how to handle rule dependent: #{ext.inspect}" end - if File.exist?(source) - task = FileTask.define_task({task_name => [source]+deps}, &block) - task.source = source - return task + end + prereqs = sources.map do |source| + if File.exist?(source) || TASKS[source] + source + elsif parent = enhance_with_matching_rule(source, level + 1) + parent.name + else + break nil end end + if prereqs + task = FileTask.define_task(task_name => prereqs, &block) + task.source = prereqs.first + return task + end end nil end -- cgit v1.2.3 From 1868fd453d70009fd4a895b09c236fb8fc653d6c Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Thu, 8 Aug 2019 22:12:25 +0900 Subject: Remove monkey patches for Ruby 1.9 or earlier --- lib/mruby-core-ext.rb | 39 --------------------------------------- 1 file changed, 39 deletions(-) diff --git a/lib/mruby-core-ext.rb b/lib/mruby-core-ext.rb index 08e6f6148..8c985f147 100644 --- a/lib/mruby-core-ext.rb +++ b/lib/mruby-core-ext.rb @@ -16,45 +16,6 @@ class String def relative_path relative_path_from(Dir.pwd) end - - # Compatible with 1.9 on 1.8 - unless (sprintf("%{a}", :a => 1) rescue false) - def %(params) - if params.is_a?(Hash) - str = self.clone - params.each do |k, v| - str.gsub!("%{#{k}}") { v } - end - str - else - if params.is_a?(Array) - sprintf(self, *params) - else - sprintf(self, params) - end - end - end - end -end - -class Symbol - # Compatible with 1.9 on 1.8 - unless method_defined?(:to_proc) - def to_proc - proc { |obj, *args| obj.send(self, *args) } - end - end -end - -module Enumerable - # Compatible with 1.9 on 1.8 - unless method_defined?(:each_with_object) - def each_with_object(memo) - return to_enum :each_with_object, memo unless block_given? - each { |obj| yield obj, memo } - memo - end - end end $pp_show = true -- cgit v1.2.3 From c181d1e7fa80b1cc0551f8fbd85ab6f7419b7887 Mon Sep 17 00:00:00 2001 From: Ray Chason Date: Thu, 8 Aug 2019 23:59:25 -0400 Subject: Implement Complex#abs in terms of Math.hypot Math.hypot avoids premature overflow and underflow --- mrbgems/mruby-complex/mrblib/complex.rb | 2 +- mrbgems/mruby-complex/test/complex.rb | 8 ++++++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/mrbgems/mruby-complex/mrblib/complex.rb b/mrbgems/mruby-complex/mrblib/complex.rb index 1a6f7e92e..1025e975e 100644 --- a/mrbgems/mruby-complex/mrblib/complex.rb +++ b/mrbgems/mruby-complex/mrblib/complex.rb @@ -62,7 +62,7 @@ class Complex < Numeric end def abs - Math.sqrt(abs2) + Math.hypot imaginary, real end alias_method :magnitude, :abs diff --git a/mrbgems/mruby-complex/test/complex.rb b/mrbgems/mruby-complex/test/complex.rb index 4ae80515b..dcc0f3bef 100644 --- a/mrbgems/mruby-complex/test/complex.rb +++ b/mrbgems/mruby-complex/test/complex.rb @@ -70,6 +70,14 @@ end assert 'Complex#abs' do assert_float Complex(-1).abs, 1 assert_float Complex(3.0, -4.0).abs, 5.0 + if 1e39.infinite? then + # MRB_USE_FLOAT in effect + exp = 125 + else + exp = 1021 + end + assert_true Complex(3.0*2**exp, 4.0*2**exp).abs.finite? + assert_float Complex(3.0*2**exp, 4.0*2**exp).abs, 5.0*2**exp end assert 'Complex#abs2' do -- cgit v1.2.3 From 1cd0ff0d42ea4fb385288d3bd2c440a1f46e08af Mon Sep 17 00:00:00 2001 From: Ray Chason Date: Fri, 9 Aug 2019 00:08:36 -0400 Subject: Avoid overflow and underflow in Complex#/ --- mrbgems/mruby-complex/mrblib/complex.rb | 3 +- mrbgems/mruby-complex/src/complex.c | 95 +++++++++++++++++++++++++++++++++ mrbgems/mruby-complex/test/complex.rb | 13 ++++- 3 files changed, 107 insertions(+), 4 deletions(-) diff --git a/mrbgems/mruby-complex/mrblib/complex.rb b/mrbgems/mruby-complex/mrblib/complex.rb index 1025e975e..f32b84c8b 100644 --- a/mrbgems/mruby-complex/mrblib/complex.rb +++ b/mrbgems/mruby-complex/mrblib/complex.rb @@ -45,8 +45,7 @@ class Complex < Numeric def /(rhs) if rhs.is_a? Complex - div = rhs.real * rhs.real + rhs.imaginary * rhs.imaginary - Complex((real * rhs.real + imaginary * rhs.imaginary) / div, (rhs.real * imaginary - real * rhs.imaginary) / div) + __div__(rhs) elsif rhs.is_a? Numeric Complex(real / rhs, imaginary / rhs) end diff --git a/mrbgems/mruby-complex/src/complex.c b/mrbgems/mruby-complex/src/complex.c index a87b95dea..10fa42a2c 100644 --- a/mrbgems/mruby-complex/src/complex.c +++ b/mrbgems/mruby-complex/src/complex.c @@ -1,6 +1,7 @@ #include #include #include +#include #ifdef MRB_WITHOUT_FLOAT # error Complex conflicts 'MRB_WITHOUT_FLOAT' configuration in your 'build_config.rb' @@ -11,6 +12,12 @@ struct mrb_complex { mrb_float imaginary; }; +#ifdef MRB_USE_FLOAT +#define F(x) x##f +#else +#define F(x) x +#endif + #if defined(MRB_64BIT) || defined(MRB_USE_FLOAT) #define COMPLEX_USE_ISTRUCT @@ -124,6 +131,93 @@ complex_to_c(mrb_state *mrb, mrb_value self) return self; } +/* Arithmetic on (significand, exponent) pairs avoids premature overflow in + complex division */ +struct float_pair { + mrb_float s; + int x; +}; + +static void +add_pair(struct float_pair *s, struct float_pair const *a, + struct float_pair const *b) +{ + if (b->s == 0.0F) { + *s = *a; + } else if (a->s == 0.0F) { + *s = *b; + } else if (a->x >= b->x) { + s->s = a->s + F(ldexp)(b->s, b->x - a->x); + s->x = a->x; + } else { + s->s = F(ldexp)(a->s, a->x - b->x) + b->s; + s->x = b->x; + } +} + +static void +mul_pair(struct float_pair *p, struct float_pair const *a, + struct float_pair const *b) +{ + p->s = a->s * b->s; + p->x = a->x + b->x; +} + +static void +div_pair(struct float_pair *q, struct float_pair const *a, + struct float_pair const *b) +{ + q->s = a->s / b->s; + q->x = a->x - b->x; +} + +static mrb_value +complex_div(mrb_state *mrb, mrb_value self) +{ + mrb_value rhs; + struct mrb_complex *a, *b; + struct float_pair ar, ai, br, bi; + struct float_pair br2, bi2; + struct float_pair div; + struct float_pair ar_br, ai_bi; + struct float_pair ai_br, ar_bi; + struct float_pair zr, zi; + + mrb_get_args(mrb, "o", &rhs); + a = complex_ptr(mrb, self); + b = complex_ptr(mrb, rhs); + + /* Split floating point components into significand and exponent */ + ar.s = F(frexp)(a->real, &ar.x); + ai.s = F(frexp)(a->imaginary, &ai.x); + br.s = F(frexp)(b->real, &br.x); + bi.s = F(frexp)(b->imaginary, &bi.x); + + /* Perform arithmetic on (significand, exponent) pairs to produce + the result: */ + + /* the divisor */ + mul_pair(&br2, &br, &br); + mul_pair(&bi2, &bi, &bi); + add_pair(&div, &br2, &bi2); + + /* real component */ + mul_pair(&ar_br, &ar, &br); + mul_pair(&ai_bi, &ai, &bi); + add_pair(&zr, &ar_br, &ai_bi); + div_pair(&zr, &zr, &div); + + /* imaginary component */ + mul_pair(&ai_br, &ai, &br); + mul_pair(&ar_bi, &ar, &bi); + ar_bi.s = -ar_bi.s; + add_pair(&zi, &ai_br, &ar_bi); + div_pair(&zi, &zi, &div); + + /* assemble the result */ + return complex_new(mrb, F(ldexp)(zr.s, zr.x), F(ldexp)(zi.s, zi.x)); +} + void mrb_mruby_complex_gem_init(mrb_state *mrb) { struct RClass *comp; @@ -146,6 +240,7 @@ void mrb_mruby_complex_gem_init(mrb_state *mrb) mrb_define_method(mrb, comp, "to_f", complex_to_f, MRB_ARGS_NONE()); mrb_define_method(mrb, comp, "to_i", complex_to_i, MRB_ARGS_NONE()); mrb_define_method(mrb, comp, "to_c", complex_to_c, MRB_ARGS_NONE()); + mrb_define_method(mrb, comp, "__div__", complex_div, MRB_ARGS_REQ(1)); } void diff --git a/mrbgems/mruby-complex/test/complex.rb b/mrbgems/mruby-complex/test/complex.rb index dcc0f3bef..d996e8277 100644 --- a/mrbgems/mruby-complex/test/complex.rb +++ b/mrbgems/mruby-complex/test/complex.rb @@ -59,6 +59,15 @@ assert 'Complex#/' do assert_complex Complex(-2, 9) / Complex(-9, 2), ((36 / 85) - (77i / 85)) assert_complex Complex(9, 8) / 4 , ((9 / 4) + 2i) assert_complex Complex(20, 9) / 9.8 , (2.0408163265306123 + 0.9183673469387754i) + if 1e39.infinite? then + # MRB_USE_FLOAT in effect + ten = 1e21 + one = 1e20 + else + ten = 1e201 + one = 1e200 + end + assert_complex Complex(ten, ten) / Complex(one, one), Complex(10.0, 0.0) end assert 'Complex#==' do @@ -76,8 +85,8 @@ assert 'Complex#abs' do else exp = 1021 end - assert_true Complex(3.0*2**exp, 4.0*2**exp).abs.finite? - assert_float Complex(3.0*2**exp, 4.0*2**exp).abs, 5.0*2**exp + assert_true Complex(3.0*2.0**exp, 4.0*2.0**exp).abs.finite? + assert_float Complex(3.0*2.0**exp, 4.0*2.0**exp).abs, 5.0*2.0**exp end assert 'Complex#abs2' do -- cgit v1.2.3 From 9f18aced9f4d3c39ba6a5e10c6856c7fc9009714 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Sat, 10 Aug 2019 22:18:54 +0900 Subject: `Enumerable#reject`, etc. should return `Enumerable` without block --- mrblib/enum.rb | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/mrblib/enum.rb b/mrblib/enum.rb index fe40b4d27..15687e159 100644 --- a/mrblib/enum.rb +++ b/mrblib/enum.rb @@ -73,6 +73,8 @@ module Enumerable # # ISO 15.3.2.2.4 def detect(ifnone=nil, &block) + return to_enum :detect, ifnone unless block + self.each{|*val| if block.call(*val) return val.__svalue @@ -282,6 +284,8 @@ module Enumerable # # ISO 15.3.2.2.16 def partition(&block) + return to_enum :partition unless block + ary_T = [] ary_F = [] self.each{|*val| @@ -302,6 +306,8 @@ module Enumerable # # ISO 15.3.2.2.17 def reject(&block) + return to_enum :reject unless block + ary = [] self.each{|*val| ary.push(val.__svalue) unless block.call(*val) -- cgit v1.2.3 From 450684ab33f3b13bde520f831f857fe1e7dc5fd6 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Sun, 11 Aug 2019 20:48:37 +0900 Subject: `mrb_str_modify_keep_ascii` can embed one more byte The condition to make an embedded string was incorrect. Because there were several similar codes, extracted into `RSTR_EMBEDDABLE_P` macro. --- include/mruby/string.h | 2 ++ src/string.c | 12 ++++++------ 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/include/mruby/string.h b/include/mruby/string.h index 7266c9084..aacbdbfc0 100644 --- a/include/mruby/string.h +++ b/include/mruby/string.h @@ -52,6 +52,8 @@ struct RString { } while (0) #define RSTR_EMBED_LEN(s)\ (mrb_int)(((s)->flags & MRB_STR_EMBED_LEN_MASK) >> MRB_STR_EMBED_LEN_SHIFT) +#define RSTR_EMBEDDABLE_P(len) ((len) <= RSTRING_EMBED_LEN_MAX) + #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) diff --git a/src/string.c b/src/string.c index daf293368..a6031b0ef 100644 --- a/src/string.c +++ b/src/string.c @@ -60,7 +60,7 @@ str_new(mrb_state *mrb, const char *p, size_t len) return str_new_static(mrb, p, len); } s = mrb_obj_alloc_string(mrb); - if (len <= RSTRING_EMBED_LEN_MAX) { + if (RSTR_EMBEDDABLE_P(len)) { RSTR_SET_EMBED_FLAG(s); RSTR_SET_EMBED_LEN(s, len); if (p) { @@ -135,7 +135,7 @@ resize_capa(mrb_state *mrb, struct RString *s, size_t capacity) mrb_assert(capacity < MRB_INT_MAX); #endif if (RSTR_EMBED_P(s)) { - if (RSTRING_EMBED_LEN_MAX < capacity) { + if (!RSTR_EMBEDDABLE_P(capacity)) { char *const tmp = (char *)mrb_malloc(mrb, capacity+1); const mrb_int len = RSTR_EMBED_LEN(s); memcpy(tmp, s->as.ary, len); @@ -478,7 +478,7 @@ mrb_str_byte_subseq(mrb_state *mrb, mrb_value str, mrb_int beg, mrb_int len) struct RString *orig, *s; orig = mrb_str_ptr(str); - if (RSTR_EMBED_P(orig) || RSTR_LEN(orig) == 0 || len <= RSTRING_EMBED_LEN_MAX) { + if (RSTR_EMBED_P(orig) || RSTR_LEN(orig) == 0 || RSTR_EMBEDDABLE_P(len)) { s = str_new(mrb, RSTR_PTR(orig)+beg, len); } else { @@ -588,7 +588,7 @@ str_replace(mrb_state *mrb, struct RString *s1, struct RString *s2) RSTR_UNSET_FSHARED_FLAG(s1); RSTR_UNSET_NOFREE_FLAG(s1); - if (len <= RSTRING_EMBED_LEN_MAX) { + if (RSTR_EMBEDDABLE_P(len)) { RSTR_UNSET_SHARED_FLAG(s1); RSTR_UNSET_FSHARED_FLAG(s1); RSTR_SET_EMBED_FLAG(s1); @@ -728,7 +728,7 @@ mrb_str_modify_keep_ascii(mrb_state *mrb, struct RString *s) p = RSTR_PTR(s); len = s->as.heap.len; - if (len < RSTRING_EMBED_LEN_MAX) { + if (RSTR_EMBEDDABLE_P(len)) { RSTR_SET_EMBED_FLAG(s); RSTR_SET_EMBED_LEN(s, len); ptr = RSTR_PTR(s); @@ -754,7 +754,7 @@ mrb_str_modify_keep_ascii(mrb_state *mrb, struct RString *s) RSTR_UNSET_FSHARED_FLAG(s); RSTR_UNSET_NOFREE_FLAG(s); RSTR_UNSET_FSHARED_FLAG(s); - if (len < RSTRING_EMBED_LEN_MAX) { + if (RSTR_EMBEDDABLE_P(len)) { RSTR_SET_EMBED_FLAG(s); RSTR_SET_EMBED_LEN(s, len); } -- cgit v1.2.3 From 70b53f91c258e23fc5d68dd8f9c7cf5b8e0290f6 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Sun, 11 Aug 2019 21:53:23 +0900 Subject: Add `NUL` always to short strings; ref 98fc887 --- src/string.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/string.c b/src/string.c index daf293368..0abc07000 100644 --- a/src/string.c +++ b/src/string.c @@ -594,6 +594,7 @@ str_replace(mrb_state *mrb, struct RString *s1, struct RString *s2) RSTR_SET_EMBED_FLAG(s1); memcpy(s1->as.ary, RSTR_PTR(s2), len); RSTR_SET_EMBED_LEN(s1, len); + RSTR_PTR(s1)[len] = '\0'; } else { str_make_shared(mrb, s2, s1); -- cgit v1.2.3 From 037638335430de0d35d377af3e393c2aeab9451c Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Sun, 11 Aug 2019 22:10:51 +0900 Subject: Reorder finalization to avoid potential crash; ref #4618 `mrb_gc_destroy` may call other mruby API functions from the finalizers. So call that function first. --- src/state.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/state.c b/src/state.c index c42df71ba..e5e0161bf 100644 --- a/src/state.c +++ b/src/state.c @@ -221,10 +221,10 @@ mrb_close(mrb_state *mrb) } /* free */ - mrb_gc_free_gv(mrb); + mrb_gc_destroy(mrb, &mrb->gc); mrb_free_context(mrb, mrb->root_c); + mrb_gc_free_gv(mrb); mrb_free_symtbl(mrb); - mrb_gc_destroy(mrb, &mrb->gc); mrb_free(mrb, mrb); } -- cgit v1.2.3 From 472dba19ea13e8403667f530ce40e16dcd1bdee1 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Sun, 11 Aug 2019 22:13:46 +0900 Subject: Revert "Should have cleared `mrb->globals` in `mrb_gc_free_gv`; fix #4618" This reverts commit 3dc8d9d7b3d0be2f91fa050a13e3b422500df628. --- src/variable.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/variable.c b/src/variable.c index ab3bea327..32416da4e 100644 --- a/src/variable.c +++ b/src/variable.c @@ -268,10 +268,8 @@ mrb_gc_mark_gv(mrb_state *mrb) void mrb_gc_free_gv(mrb_state *mrb) { - if (mrb->globals) { + if (mrb->globals) iv_free(mrb, mrb->globals); - mrb->globals = NULL; - } } void -- cgit v1.2.3 From 285ce9d8aa9ecfd7b749ae02784a2ba68290293a Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Mon, 12 Aug 2019 16:51:01 +0900 Subject: Replacing region may overwrap with the target region; fix #4627 --- src/string.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/string.c b/src/string.c index 0abc07000..1d2f0dec0 100644 --- a/src/string.c +++ b/src/string.c @@ -1264,7 +1264,7 @@ str_replace_partial(mrb_state *mrb, mrb_value src, mrb_int pos, mrb_int end, mrb memmove(strp + newlen - (len - end), strp + end, len - end); if (!mrb_nil_p(rep)) { - memcpy(strp + pos, RSTRING_PTR(rep), replen); + memmove(strp + pos, RSTRING_PTR(rep), replen); } RSTR_SET_LEN(str, newlen); strp[newlen] = '\0'; -- cgit v1.2.3 From f113fa2a4fad585521adf0b1d9e9b99836895ab4 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Mon, 12 Aug 2019 18:22:31 +0900 Subject: Remove unnecessary prototypes from 'keywords`; fix #4628 --- mrbgems/mruby-compiler/core/keywords | 3 - mrbgems/mruby-compiler/core/lex.def | 110 ++++++++++++++++------------------- 2 files changed, 51 insertions(+), 62 deletions(-) diff --git a/mrbgems/mruby-compiler/core/keywords b/mrbgems/mruby-compiler/core/keywords index 9cb86608c..a60ecd10a 100644 --- a/mrbgems/mruby-compiler/core/keywords +++ b/mrbgems/mruby-compiler/core/keywords @@ -1,8 +1,5 @@ %{ struct kwtable {const char *name; int id[2]; enum mrb_lex_state_enum state;}; -const struct kwtable *mrb_reserved_word(const char *, unsigned int); -static const struct kwtable *reserved_word(const char *, unsigned int); -#define mrb_reserved_word(str, len) reserved_word(str, len) %} struct kwtable; diff --git a/mrbgems/mruby-compiler/core/lex.def b/mrbgems/mruby-compiler/core/lex.def index 2ff266481..872bf40c1 100644 --- a/mrbgems/mruby-compiler/core/lex.def +++ b/mrbgems/mruby-compiler/core/lex.def @@ -1,4 +1,4 @@ -/* ANSI-C code produced by gperf version 3.0.4 */ +/* ANSI-C code produced by gperf version 3.1 */ /* Command-line: gperf -L ANSI-C -C -p -j1 -i 1 -g -o -t -N mrb_reserved_word -k'1,3,$' /home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords */ #if !((' ' == 32) && ('!' == 33) && ('"' == 34) && ('#' == 35) \ @@ -25,16 +25,13 @@ && ('w' == 119) && ('x' == 120) && ('y' == 121) && ('z' == 122) \ && ('{' == 123) && ('|' == 124) && ('}' == 125) && ('~' == 126)) /* The character set is not based on ISO-646. */ -#error "gperf generated tables don't work with this execution character set. Please report a bug to ." +#error "gperf generated tables don't work with this execution character set. Please report a bug to ." #endif #line 1 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords" struct kwtable {const char *name; int id[2]; enum mrb_lex_state_enum state;}; -const struct kwtable *mrb_reserved_word(const char *, unsigned int); -static const struct kwtable *reserved_word(const char *, unsigned int); -#define mrb_reserved_word(str, len) reserved_word(str, len) -#line 8 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords" +#line 5 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords" struct kwtable; #define TOTAL_KEYWORDS 40 @@ -52,7 +49,7 @@ inline #endif #endif static unsigned int -hash (const char *str, unsigned int len) +hash (register const char *str, register size_t len) { static const unsigned char asso_values[] = { @@ -83,7 +80,7 @@ hash (const char *str, unsigned int len) 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51 }; - int hval = len; + register unsigned int hval = len; switch (hval) { @@ -98,109 +95,103 @@ hash (const char *str, unsigned int len) return hval + asso_values[(unsigned char)str[len - 1]]; } -#ifdef __GNUC__ -__inline -#if defined __GNUC_STDC_INLINE__ || defined __GNUC_GNU_INLINE__ -__attribute__ ((__gnu_inline__)) -#endif -#endif const struct kwtable * -mrb_reserved_word (const char *str, unsigned int len) +mrb_reserved_word (register const char *str, register size_t len) { static const struct kwtable wordlist[] = { {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, -#line 18 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords" +#line 15 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords" {"break", {keyword_break, keyword_break}, EXPR_MID}, -#line 23 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords" +#line 20 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords" {"else", {keyword_else, keyword_else}, EXPR_BEG}, -#line 33 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords" +#line 30 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords" {"nil", {keyword_nil, keyword_nil}, EXPR_END}, -#line 26 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords" +#line 23 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords" {"ensure", {keyword_ensure, keyword_ensure}, EXPR_BEG}, -#line 25 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords" +#line 22 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords" {"end", {keyword_end, keyword_end}, EXPR_END}, -#line 42 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords" +#line 39 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords" {"then", {keyword_then, keyword_then}, EXPR_BEG}, -#line 34 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords" +#line 31 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords" {"not", {keyword_not, keyword_not}, EXPR_ARG}, -#line 27 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords" +#line 24 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords" {"false", {keyword_false, keyword_false}, EXPR_END}, -#line 40 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords" +#line 37 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords" {"self", {keyword_self, keyword_self}, EXPR_END}, -#line 24 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords" +#line 21 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords" {"elsif", {keyword_elsif, keyword_elsif}, EXPR_VALUE}, -#line 37 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords" +#line 34 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords" {"rescue", {keyword_rescue, modifier_rescue}, EXPR_MID}, -#line 43 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords" +#line 40 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords" {"true", {keyword_true, keyword_true}, EXPR_END}, -#line 46 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords" +#line 43 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords" {"until", {keyword_until, modifier_until}, EXPR_VALUE}, -#line 45 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords" +#line 42 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords" {"unless", {keyword_unless, modifier_unless}, EXPR_VALUE}, -#line 39 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords" +#line 36 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords" {"return", {keyword_return, keyword_return}, EXPR_MID}, -#line 21 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords" +#line 18 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords" {"def", {keyword_def, keyword_def}, EXPR_FNAME}, -#line 16 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords" +#line 13 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords" {"and", {keyword_and, keyword_and}, EXPR_VALUE}, -#line 22 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords" +#line 19 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords" {"do", {keyword_do, keyword_do}, EXPR_BEG}, -#line 49 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords" +#line 46 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords" {"yield", {keyword_yield, keyword_yield}, EXPR_ARG}, -#line 28 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords" +#line 25 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords" {"for", {keyword_for, keyword_for}, EXPR_VALUE}, -#line 44 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords" +#line 41 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords" {"undef", {keyword_undef, keyword_undef}, EXPR_FNAME}, -#line 35 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords" +#line 32 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords" {"or", {keyword_or, keyword_or}, EXPR_VALUE}, -#line 30 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords" +#line 27 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords" {"in", {keyword_in, keyword_in}, EXPR_VALUE}, -#line 47 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords" +#line 44 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords" {"when", {keyword_when, keyword_when}, EXPR_VALUE}, -#line 38 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords" +#line 35 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords" {"retry", {keyword_retry, keyword_retry}, EXPR_END}, -#line 29 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords" +#line 26 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords" {"if", {keyword_if, modifier_if}, EXPR_VALUE}, -#line 19 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords" +#line 16 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords" {"case", {keyword_case, keyword_case}, EXPR_VALUE}, -#line 36 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords" +#line 33 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords" {"redo", {keyword_redo, keyword_redo}, EXPR_END}, -#line 32 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords" +#line 29 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords" {"next", {keyword_next, keyword_next}, EXPR_MID}, -#line 41 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords" +#line 38 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords" {"super", {keyword_super, keyword_super}, EXPR_ARG}, -#line 31 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords" +#line 28 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords" {"module", {keyword_module, keyword_module}, EXPR_VALUE}, -#line 17 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords" +#line 14 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords" {"begin", {keyword_begin, keyword_begin}, EXPR_BEG}, -#line 12 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords" +#line 9 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords" {"__LINE__", {keyword__LINE__, keyword__LINE__}, EXPR_END}, -#line 11 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords" +#line 8 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords" {"__FILE__", {keyword__FILE__, keyword__FILE__}, EXPR_END}, -#line 10 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords" +#line 7 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords" {"__ENCODING__", {keyword__ENCODING__, keyword__ENCODING__}, EXPR_END}, -#line 14 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords" +#line 11 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords" {"END", {keyword_END, keyword_END}, EXPR_END}, -#line 15 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords" +#line 12 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords" {"alias", {keyword_alias, keyword_alias}, EXPR_FNAME}, -#line 13 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords" +#line 10 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords" {"BEGIN", {keyword_BEGIN, keyword_BEGIN}, EXPR_END}, {""}, -#line 20 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords" +#line 17 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords" {"class", {keyword_class, keyword_class}, EXPR_CLASS}, {""}, {""}, -#line 48 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords" +#line 45 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords" {"while", {keyword_while, modifier_while}, EXPR_VALUE} }; if (len <= MAX_WORD_LENGTH && len >= MIN_WORD_LENGTH) { - int key = hash (str, len); + register unsigned int key = hash (str, len); - if (key <= MAX_HASH_VALUE && key >= 0) + if (key <= MAX_HASH_VALUE) { - const char *s = wordlist[key].name; + register const char *s = wordlist[key].name; if (*str == *s && !strcmp (str + 1, s + 1)) return &wordlist[key]; @@ -208,4 +199,5 @@ mrb_reserved_word (const char *str, unsigned int len) } return 0; } -#line 50 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords" +#line 47 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords" + -- cgit v1.2.3 From dfb297e3c4a521fe360c9462dbfc7eafd826f6bf Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Mon, 12 Aug 2019 21:42:31 +0900 Subject: `mrb_str_pool` can embed one more byte; ref #4626 --- src/state.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/state.c b/src/state.c index e5e0161bf..69b069304 100644 --- a/src/state.c +++ b/src/state.c @@ -170,7 +170,7 @@ mrb_str_pool(mrb_state *mrb, mrb_value str) len = s->as.heap.len; } - if (len < RSTRING_EMBED_LEN_MAX) { + if (RSTR_EMBEDDABLE_P(len)) { RSTR_SET_EMBED_FLAG(ns); RSTR_SET_EMBED_LEN(ns, len); if (ptr) { -- cgit v1.2.3 From 7af0ee099de91214c9f98a019de0fb25b86f911f Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Tue, 13 Aug 2019 22:40:30 +0900 Subject: Extract `struct RString` initialization code to function --- src/string.c | 100 ++++++++++++++++++++++++++--------------------------------- 1 file changed, 44 insertions(+), 56 deletions(-) diff --git a/src/string.c b/src/string.c index 7d3480d2a..21a42a584 100644 --- a/src/string.c +++ b/src/string.c @@ -34,6 +34,33 @@ const char mrb_digitmap[] = "0123456789abcdefghijklmnopqrstuvwxyz"; #define mrb_obj_alloc_string(mrb) ((struct RString*)mrb_obj_alloc((mrb), MRB_TT_STRING, (mrb)->string_class)) +static void +str_init_normal_capa(mrb_state *mrb, struct RString *s, + const char *p, size_t len, size_t capa) +{ + char *dst = (char *)mrb_malloc(mrb, capa + 1); + if (p) memcpy(dst, p, len); + dst[len] = '\0'; + s->as.heap.ptr = dst; + s->as.heap.len = (mrb_int)len; + s->as.heap.aux.capa = (mrb_int)capa; +} + +static void +str_init_normal(mrb_state *mrb, struct RString *s, const char *p, size_t len) +{ + str_init_normal_capa(mrb, s, p, len, len); +} + +static void +str_init_embed(struct RString *s, const char *p, size_t len) +{ + if (p) memcpy(s->as.ary, p, len); + s->as.ary[len] = '\0'; + RSTR_SET_EMBED_FLAG(s); + RSTR_SET_EMBED_LEN(s, len); +} + static struct RString* str_new_static(mrb_state *mrb, const char *p, size_t len) { @@ -61,24 +88,14 @@ str_new(mrb_state *mrb, const char *p, size_t len) } s = mrb_obj_alloc_string(mrb); if (RSTR_EMBEDDABLE_P(len)) { - RSTR_SET_EMBED_FLAG(s); - RSTR_SET_EMBED_LEN(s, len); - if (p) { - memcpy(s->as.ary, p, len); - } + str_init_embed(s, p, len); + } + else if (len >= MRB_INT_MAX) { + mrb_raise(mrb, E_ARGUMENT_ERROR, "string size too big"); } else { - if (len >= MRB_INT_MAX) { - mrb_raise(mrb, E_ARGUMENT_ERROR, "string size too big"); - } - s->as.heap.ptr = (char *)mrb_malloc(mrb, len+1); - s->as.heap.len = (mrb_int)len; - s->as.heap.aux.capa = (mrb_int)len; - if (p) { - memcpy(s->as.heap.ptr, p, len); - } + str_init_normal(mrb, s, p, len); } - RSTR_PTR(s)[len] = '\0'; return s; } @@ -107,10 +124,7 @@ mrb_str_new_capa(mrb_state *mrb, size_t capa) if (capa >= MRB_INT_MAX) { mrb_raise(mrb, E_ARGUMENT_ERROR, "string capacity size too big"); } - s->as.heap.len = 0; - s->as.heap.aux.capa = (mrb_int)capa; - s->as.heap.ptr = (char *)mrb_malloc(mrb, capa+1); - RSTR_PTR(s)[0] = '\0'; + str_init_normal_capa(mrb, s, NULL, 0, capa); return mrb_obj_value(s); } @@ -136,13 +150,8 @@ resize_capa(mrb_state *mrb, struct RString *s, size_t capacity) #endif if (RSTR_EMBED_P(s)) { if (!RSTR_EMBEDDABLE_P(capacity)) { - char *const tmp = (char *)mrb_malloc(mrb, capacity+1); - const mrb_int len = RSTR_EMBED_LEN(s); - memcpy(tmp, s->as.ary, len); + str_init_normal_capa(mrb, s, s->as.ary, RSTR_EMBED_LEN(s), capacity); RSTR_UNSET_EMBED_FLAG(s); - s->as.heap.ptr = tmp; - s->as.heap.len = len; - s->as.heap.aux.capa = (mrb_int)capacity; } } else { @@ -571,12 +580,11 @@ str_index_str(mrb_state *mrb, mrb_value str, mrb_value str2, mrb_int offset) static mrb_value str_replace(mrb_state *mrb, struct RString *s1, struct RString *s2) { - mrb_int len; + size_t len; mrb_check_frozen(mrb, s1); if (s1 == s2) return mrb_obj_value(s1); RSTR_COPY_ASCII_FLAG(s1, s2); - len = RSTR_LEN(s2); if (RSTR_SHARED_P(s1)) { str_decref(mrb, s1->as.heap.aux.shared); RSTR_UNSET_SHARED_FLAG(s1); @@ -586,15 +594,12 @@ str_replace(mrb_state *mrb, struct RString *s1, struct RString *s2) mrb_free(mrb, s1->as.heap.ptr); } + len = (size_t)RSTR_LEN(s2); RSTR_UNSET_FSHARED_FLAG(s1); RSTR_UNSET_NOFREE_FLAG(s1); if (RSTR_EMBEDDABLE_P(len)) { RSTR_UNSET_SHARED_FLAG(s1); - RSTR_UNSET_FSHARED_FLAG(s1); - RSTR_SET_EMBED_FLAG(s1); - memcpy(s1->as.ary, RSTR_PTR(s2), len); - RSTR_SET_EMBED_LEN(s1, len); - RSTR_PTR(s1)[len] = '\0'; + str_init_embed(s1, RSTR_PTR(s2), len); } else { str_make_shared(mrb, s2, s1); @@ -724,25 +729,15 @@ mrb_str_modify_keep_ascii(mrb_state *mrb, struct RString *s) mrb_free(mrb, shared); } else { - char *ptr, *p; - mrb_int len; + char *p = RSTR_PTR(s); + size_t len = (size_t)s->as.heap.len; - p = RSTR_PTR(s); - len = s->as.heap.len; if (RSTR_EMBEDDABLE_P(len)) { - RSTR_SET_EMBED_FLAG(s); - RSTR_SET_EMBED_LEN(s, len); - ptr = RSTR_PTR(s); + str_init_embed(s, p, len); } else { - ptr = (char *)mrb_malloc(mrb, (size_t)len + 1); - s->as.heap.ptr = ptr; - s->as.heap.aux.capa = len; - } - if (p) { - memcpy(ptr, p, len); + str_init_normal(mrb, s, p, len); } - ptr[len] = '\0'; str_decref(mrb, shared); } RSTR_UNSET_SHARED_FLAG(s); @@ -750,23 +745,16 @@ mrb_str_modify_keep_ascii(mrb_state *mrb, struct RString *s) } if (RSTR_NOFREE_P(s) || RSTR_FSHARED_P(s)) { char *p = s->as.heap.ptr; - mrb_int len = s->as.heap.len; + size_t len = (size_t)s->as.heap.len; - RSTR_UNSET_FSHARED_FLAG(s); RSTR_UNSET_NOFREE_FLAG(s); RSTR_UNSET_FSHARED_FLAG(s); if (RSTR_EMBEDDABLE_P(len)) { - RSTR_SET_EMBED_FLAG(s); - RSTR_SET_EMBED_LEN(s, len); + str_init_embed(s, p, len); } else { - s->as.heap.ptr = (char *)mrb_malloc(mrb, (size_t)len+1); - s->as.heap.aux.capa = len; - } - if (p) { - memcpy(RSTR_PTR(s), p, len); + str_init_normal(mrb, s, p, len); } - RSTR_PTR(s)[len] = '\0'; return; } } -- cgit v1.2.3 From 9f6328d49930283ad6ad1201924ba296caf6e9f5 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Tue, 13 Aug 2019 17:43:43 +0900 Subject: Remove `MRB_API` from functions only called from `vm.c`. * `mrb_vm_define_class` * `mrb_vm_define_module` Only functions called from user code requires `MRB_API`. --- include/mruby/class.h | 4 ++-- src/class.c | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/include/mruby/class.h b/include/mruby/class.h index c79a487b5..169e1327b 100644 --- a/include/mruby/class.h +++ b/include/mruby/class.h @@ -75,8 +75,8 @@ mrb_class(mrb_state *mrb, mrb_value v) MRB_API struct RClass* mrb_define_class_id(mrb_state*, mrb_sym, struct RClass*); MRB_API struct RClass* mrb_define_module_id(mrb_state*, mrb_sym); -MRB_API struct RClass *mrb_vm_define_class(mrb_state*, mrb_value, mrb_value, mrb_sym); -MRB_API struct RClass *mrb_vm_define_module(mrb_state*, mrb_value, mrb_sym); +struct RClass *mrb_vm_define_class(mrb_state*, mrb_value, mrb_value, mrb_sym); +struct RClass *mrb_vm_define_module(mrb_state*, mrb_value, mrb_sym); MRB_API void mrb_define_method_raw(mrb_state*, struct RClass*, mrb_sym, mrb_method_t); MRB_API void mrb_define_method_id(mrb_state *mrb, struct RClass *c, mrb_sym mid, mrb_func_t func, mrb_aspec aspec); MRB_API void mrb_alias_method(mrb_state*, struct RClass *c, mrb_sym a, mrb_sym b); diff --git a/src/class.c b/src/class.c index f66c5794d..071b29901 100644 --- a/src/class.c +++ b/src/class.c @@ -207,7 +207,7 @@ mrb_define_module(mrb_state *mrb, const char *name) return define_module(mrb, mrb_intern_cstr(mrb, name), mrb->object_class); } -MRB_API struct RClass* +struct RClass* mrb_vm_define_module(mrb_state *mrb, mrb_value outer, mrb_sym id) { check_if_class_or_module(mrb, outer); @@ -304,7 +304,7 @@ mrb_class_inherited(mrb_state *mrb, struct RClass *super, struct RClass *klass) } } -MRB_API struct RClass* +struct RClass* mrb_vm_define_class(mrb_state *mrb, mrb_value outer, mrb_value super, mrb_sym id) { struct RClass *s; -- cgit v1.2.3 From 8ed15fd92e6d3ce7963db8c3162bdebee7b55e1b Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Wed, 14 Aug 2019 09:42:41 +0900 Subject: Small refactoring on #4630 --- src/string.c | 38 +++++++++++++++++--------------------- 1 file changed, 17 insertions(+), 21 deletions(-) diff --git a/src/string.c b/src/string.c index 21a42a584..2e0b1e301 100644 --- a/src/string.c +++ b/src/string.c @@ -61,6 +61,17 @@ str_init_embed(struct RString *s, const char *p, size_t len) RSTR_SET_EMBED_LEN(s, len); } +static void +str_init(mrb_state *mrb, struct RString *s, const char *p, size_t len) +{ + if (RSTR_EMBEDDABLE_P(len)) { + str_init_embed(s, p, len); + } + else { + str_init_normal(mrb, s, p, len); + } +} + static struct RString* str_new_static(mrb_state *mrb, const char *p, size_t len) { @@ -83,19 +94,14 @@ str_new(mrb_state *mrb, const char *p, size_t len) { struct RString *s; + if (len >= MRB_INT_MAX) { + mrb_raise(mrb, E_ARGUMENT_ERROR, "string size too big"); + } if (p && mrb_ro_data_p(p)) { return str_new_static(mrb, p, len); } s = mrb_obj_alloc_string(mrb); - if (RSTR_EMBEDDABLE_P(len)) { - str_init_embed(s, p, len); - } - else if (len >= MRB_INT_MAX) { - mrb_raise(mrb, E_ARGUMENT_ERROR, "string size too big"); - } - else { - str_init_normal(mrb, s, p, len); - } + str_init(mrb, s, p, len); return s; } @@ -732,12 +738,7 @@ mrb_str_modify_keep_ascii(mrb_state *mrb, struct RString *s) char *p = RSTR_PTR(s); size_t len = (size_t)s->as.heap.len; - if (RSTR_EMBEDDABLE_P(len)) { - str_init_embed(s, p, len); - } - else { - str_init_normal(mrb, s, p, len); - } + str_init(mrb, s, p, len); str_decref(mrb, shared); } RSTR_UNSET_SHARED_FLAG(s); @@ -749,12 +750,7 @@ mrb_str_modify_keep_ascii(mrb_state *mrb, struct RString *s) RSTR_UNSET_NOFREE_FLAG(s); RSTR_UNSET_FSHARED_FLAG(s); - if (RSTR_EMBEDDABLE_P(len)) { - str_init_embed(s, p, len); - } - else { - str_init_normal(mrb, s, p, len); - } + str_init(mrb, s, p, len); return; } } -- cgit v1.2.3 From 603005ba6508da59220a4c7385a0c98bda78a201 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Wed, 14 Aug 2019 14:09:56 +0900 Subject: Integrate `kazuho/mruby-class-new-fiber-safe` in the master. Avoid calling `initialize` via `mrb_funcall`, which cause `cross C boundary` error from Fibers started in the method. --- mrblib/00class.rb | 8 ++++++++ src/class.c | 1 + 2 files changed, 9 insertions(+) diff --git a/mrblib/00class.rb b/mrblib/00class.rb index 1811236f0..8fcfb1362 100644 --- a/mrblib/00class.rb +++ b/mrblib/00class.rb @@ -1,3 +1,11 @@ +class Class + def new(*args, &block) + obj = self.allocate + obj.initialize(*args, &block) + obj + end +end + class Module # 15.2.2.4.12 def attr_accessor(*names) diff --git a/src/class.c b/src/class.c index 071b29901..112257380 100644 --- a/src/class.c +++ b/src/class.c @@ -2159,6 +2159,7 @@ mrb_init_class(mrb_state *mrb) mrb_define_method(mrb, bob, "instance_eval", mrb_obj_instance_eval, MRB_ARGS_ANY()); /* 15.3.1.3.18 */ mrb_define_class_method(mrb, cls, "new", mrb_class_new_class, MRB_ARGS_OPT(1)); + mrb_define_method(mrb, cls, "allocate", mrb_instance_alloc, MRB_ARGS_NONE()); mrb_define_method(mrb, cls, "superclass", mrb_class_superclass, MRB_ARGS_NONE()); /* 15.2.3.3.4 */ mrb_define_method(mrb, cls, "new", mrb_instance_new, MRB_ARGS_ANY()); /* 15.2.3.3.3 */ mrb_define_method(mrb, cls, "initialize", mrb_class_initialize, MRB_ARGS_OPT(1)); /* 15.2.3.3.1 */ -- cgit v1.2.3 From d986b9ff7b360a0961410950b2387ee49b5ac3c7 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Wed, 14 Aug 2019 15:08:48 +0900 Subject: Avoid array copying in `mrb_instance_new`. --- src/class.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/class.c b/src/class.c index 112257380..8c790507e 100644 --- a/src/class.c +++ b/src/class.c @@ -1487,7 +1487,7 @@ mrb_instance_new(mrb_state *mrb, mrb_value cv) mrb_int argc; mrb_sym init; - mrb_get_args(mrb, "*&", &argv, &argc, &blk); + mrb_get_args(mrb, "*!&", &argv, &argc, &blk); obj = mrb_instance_alloc(mrb, cv); init = mrb_intern_lit(mrb, "initialize"); if (!mrb_func_basic_p(mrb, obj, init, mrb_bob_init)) { -- cgit v1.2.3 From af6724c2f6b012316cef4ffc2d0c9eec8bd2853c Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Wed, 14 Aug 2019 22:20:34 +0900 Subject: Extract initialization code of shared and fshared string to function --- src/string.c | 69 +++++++++++++++++++++++++++++++----------------------------- 1 file changed, 36 insertions(+), 33 deletions(-) diff --git a/src/string.c b/src/string.c index 2e0b1e301..d0547ba3f 100644 --- a/src/string.c +++ b/src/string.c @@ -61,6 +61,34 @@ str_init_embed(struct RString *s, const char *p, size_t len) RSTR_SET_EMBED_LEN(s, len); } +static void +str_init_shared(mrb_state *mrb, const struct RString *orig, struct RString *s, mrb_shared_string *shared) +{ + if (shared) { + shared->refcnt++; + } + else { + shared = (mrb_shared_string *)mrb_malloc(mrb, sizeof(mrb_shared_string)); + shared->refcnt = 2; + shared->nofree = !!RSTR_NOFREE_P(orig); + shared->ptr = orig->as.heap.ptr; + shared->len = orig->as.heap.len; + } + s->as.heap.ptr = orig->as.heap.ptr; + s->as.heap.len = orig->as.heap.len; + s->as.heap.aux.shared = shared; + RSTR_SET_SHARED_FLAG(s); +} + +static void +str_init_fshared(const struct RString *orig, struct RString *s, struct RString *fshared) +{ + s->as.heap.ptr = orig->as.heap.ptr; + s->as.heap.len = orig->as.heap.len; + s->as.heap.aux.fshared = fshared; + RSTR_SET_FSHARED_FLAG(s); +} + static void str_init(mrb_state *mrb, struct RString *s, const char *p, size_t len) { @@ -435,54 +463,29 @@ mrb_memsearch(const void *x0, mrb_int m, const void *y0, mrb_int n) static void str_make_shared(mrb_state *mrb, struct RString *orig, struct RString *s) { - mrb_shared_string *shared; mrb_int len = RSTR_LEN(orig); mrb_assert(!RSTR_EMBED_P(orig)); if (RSTR_SHARED_P(orig)) { - shared = orig->as.heap.aux.shared; - shared->refcnt++; - s->as.heap.ptr = orig->as.heap.ptr; - s->as.heap.len = len; - s->as.heap.aux.shared = shared; - RSTR_SET_SHARED_FLAG(s); + str_init_shared(mrb, orig, s, orig->as.heap.aux.shared); RSTR_UNSET_EMBED_FLAG(s); } else if (RSTR_FSHARED_P(orig)) { - struct RString *fs; - - fs = orig->as.heap.aux.fshared; - s->as.heap.ptr = orig->as.heap.ptr; - s->as.heap.len = len; - s->as.heap.aux.fshared = fs; - RSTR_SET_FSHARED_FLAG(s); + str_init_fshared(orig, s, orig->as.heap.aux.fshared); RSTR_UNSET_EMBED_FLAG(s); } else if (MRB_FROZEN_P(orig) && !RSTR_POOL_P(orig)) { - s->as.heap.ptr = orig->as.heap.ptr; - s->as.heap.len = len; - s->as.heap.aux.fshared = orig; - RSTR_SET_FSHARED_FLAG(s); + str_init_fshared(orig, s, orig); RSTR_UNSET_EMBED_FLAG(s); } else { - shared = (mrb_shared_string *)mrb_malloc(mrb, sizeof(mrb_shared_string)); - shared->refcnt = 2; - shared->nofree = !!RSTR_NOFREE_P(orig); - if (!shared->nofree && orig->as.heap.aux.capa > orig->as.heap.len) { - shared->ptr = (char *)mrb_realloc(mrb, orig->as.heap.ptr, len+1); - orig->as.heap.ptr = shared->ptr; - } - else { - shared->ptr = orig->as.heap.ptr; + if (!RSTR_NOFREE_P(orig) && orig->as.heap.aux.capa > orig->as.heap.len) { + orig->as.heap.ptr = (char *)mrb_realloc(mrb, orig->as.heap.ptr, len+1); } - orig->as.heap.aux.shared = shared; + str_init_shared(mrb, orig, s, NULL); + RSTR_UNSET_EMBED_FLAG(s); + orig->as.heap.aux.shared = s->as.heap.aux.shared; RSTR_SET_SHARED_FLAG(orig); - shared->len = len; - s->as.heap.aux.shared = shared; - s->as.heap.ptr = shared->ptr; - s->as.heap.len = len; - RSTR_SET_SHARED_FLAG(s); RSTR_UNSET_EMBED_FLAG(s); } } -- cgit v1.2.3 From 59844ddde0bbf9bfaf358ae6c19688e122db7d73 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Thu, 15 Aug 2019 12:18:33 +0900 Subject: Remove unneeded `#include` in `src/string.c` --- src/string.c | 1 - 1 file changed, 1 deletion(-) diff --git a/src/string.c b/src/string.c index d0547ba3f..241d7638d 100644 --- a/src/string.c +++ b/src/string.c @@ -21,7 +21,6 @@ #include #include #include -#include typedef struct mrb_shared_string { mrb_bool nofree : 1; -- cgit v1.2.3 From fa8515bc2c22ad1b1c7688cf0201022702f6a22f Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Fri, 16 Aug 2019 15:07:51 +0900 Subject: Stop raising exceptions from `undef` C API. Some `undef' functions may be called before initialization, thus causes infinite error recursion. --- src/class.c | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/src/class.c b/src/class.c index 8c790507e..fb6a8a124 100644 --- a/src/class.c +++ b/src/class.c @@ -1813,24 +1813,28 @@ mrb_mod_alias(mrb_state *mrb, mrb_value mod) return mod; } +static void +undef_method(mrb_state *mrb, struct RClass *c, mrb_sym a) +{ + mrb_method_t m; + + MRB_METHOD_FROM_PROC(m, NULL); + mrb_define_method_raw(mrb, c, a, m); +} + void mrb_undef_method_id(mrb_state *mrb, struct RClass *c, mrb_sym a) { if (!mrb_obj_respond_to(mrb, c, a)) { mrb_name_error(mrb, a, "undefined method '%n' for class '%C'", a, c); } - else { - mrb_method_t m; - - MRB_METHOD_FROM_PROC(m, NULL); - mrb_define_method_raw(mrb, c, a, m); - } + undef_method(mrb, c, a); } MRB_API void mrb_undef_method(mrb_state *mrb, struct RClass *c, const char *name) { - mrb_undef_method_id(mrb, c, mrb_intern_cstr(mrb, name)); + undef_method(mrb, c, mrb_intern_cstr(mrb, name)); } MRB_API void @@ -2161,7 +2165,6 @@ mrb_init_class(mrb_state *mrb) mrb_define_class_method(mrb, cls, "new", mrb_class_new_class, MRB_ARGS_OPT(1)); mrb_define_method(mrb, cls, "allocate", mrb_instance_alloc, MRB_ARGS_NONE()); mrb_define_method(mrb, cls, "superclass", mrb_class_superclass, MRB_ARGS_NONE()); /* 15.2.3.3.4 */ - mrb_define_method(mrb, cls, "new", mrb_instance_new, MRB_ARGS_ANY()); /* 15.2.3.3.3 */ mrb_define_method(mrb, cls, "initialize", mrb_class_initialize, MRB_ARGS_OPT(1)); /* 15.2.3.3.1 */ mrb_define_method(mrb, cls, "inherited", mrb_bob_init, MRB_ARGS_REQ(1)); -- cgit v1.2.3 From 06c7ff06662440a900c06cda5646b7090ab9d8c9 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Fri, 16 Aug 2019 16:36:13 +0900 Subject: Avoid creating unnecessary empty arrays on splat. But this changes requires `OP_ARYCAT` and `OP_ARYPUSH` to accept `nil` as their first operand. Alternative VMs (e.g. `mruby/c`) that understand mruby bytecode need to be updated. --- mrbgems/mruby-compiler/core/codegen.c | 7 ++++++- src/vm.c | 7 ++++++- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/mrbgems/mruby-compiler/core/codegen.c b/mrbgems/mruby-compiler/core/codegen.c index 5cade970c..d4031f6fd 100644 --- a/mrbgems/mruby-compiler/core/codegen.c +++ b/mrbgems/mruby-compiler/core/codegen.c @@ -956,7 +956,12 @@ gen_values(codegen_scope *s, node *t, int val, int extra) } else { pop_n(n); - genop_2(s, OP_ARRAY, cursp(), n); + if (n == 0 && is_splat) { + genop_1(s, OP_LOADNIL, cursp()); + } + else { + genop_2(s, OP_ARRAY, cursp(), n); + } push(); codegen(s, t->car, VAL); pop(); pop(); diff --git a/src/vm.c b/src/vm.c index 12805a8e4..458b9249e 100644 --- a/src/vm.c +++ b/src/vm.c @@ -2441,7 +2441,12 @@ RETRY_TRY_BLOCK: CASE(OP_ARYCAT, B) { mrb_value splat = mrb_ary_splat(mrb, regs[a+1]); - mrb_ary_concat(mrb, regs[a], splat); + if (mrb_nil_p(regs[a])) { + regs[a] = splat; + } + else { + mrb_ary_concat(mrb, regs[a], splat); + } mrb_gc_arena_restore(mrb, ai); NEXT; } -- cgit v1.2.3 From 9832e91304347a12e4a2fc53d38a0b1f2486b958 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Fri, 16 Aug 2019 22:05:58 +0900 Subject: SHARED/FSHARED string is not required when sharing NOFREE string I think the string buffer of NOFREE string always exists and does not need to be released, so it can be shared as another NOFREE string. Also changed the `mrb_shared_string` field order so that eliminate padding if `int` and `mrb_int` sizes are less than pointer size. --- src/gc.c | 2 +- src/string.c | 39 ++++++++++++++++++++++----------------- 2 files changed, 23 insertions(+), 18 deletions(-) diff --git a/src/gc.c b/src/gc.c index a7a67ebfa..211980b19 100644 --- a/src/gc.c +++ b/src/gc.c @@ -748,7 +748,7 @@ gc_mark_children(mrb_state *mrb, mrb_gc *gc, struct RBasic *obj) break; case MRB_TT_STRING: - if (RSTR_FSHARED_P(obj) && !RSTR_NOFREE_P(obj)) { + if (RSTR_FSHARED_P(obj)) { struct RString *s = (struct RString*)obj; mrb_gc_mark(mrb, (struct RBasic*)s->as.heap.aux.fshared); } diff --git a/src/string.c b/src/string.c index 241d7638d..2b9a5cfde 100644 --- a/src/string.c +++ b/src/string.c @@ -23,10 +23,9 @@ #include typedef struct mrb_shared_string { - mrb_bool nofree : 1; int refcnt; - char *ptr; mrb_int len; + char *ptr; } mrb_shared_string; const char mrb_digitmap[] = "0123456789abcdefghijklmnopqrstuvwxyz"; @@ -60,6 +59,15 @@ str_init_embed(struct RString *s, const char *p, size_t len) RSTR_SET_EMBED_LEN(s, len); } +static void +str_init_nofree(struct RString *s, const char *p, size_t len) +{ + s->as.heap.ptr = (char *)p; + s->as.heap.len = (mrb_int)len; + s->as.heap.aux.capa = 0; /* nofree */ + RSTR_SET_NOFREE_FLAG(s); +} + static void str_init_shared(mrb_state *mrb, const struct RString *orig, struct RString *s, mrb_shared_string *shared) { @@ -69,7 +77,6 @@ str_init_shared(mrb_state *mrb, const struct RString *orig, struct RString *s, m else { shared = (mrb_shared_string *)mrb_malloc(mrb, sizeof(mrb_shared_string)); shared->refcnt = 2; - shared->nofree = !!RSTR_NOFREE_P(orig); shared->ptr = orig->as.heap.ptr; shared->len = orig->as.heap.len; } @@ -108,10 +115,7 @@ str_new_static(mrb_state *mrb, const char *p, size_t len) mrb_raise(mrb, E_ARGUMENT_ERROR, "string size too big"); } s = mrb_obj_alloc_string(mrb); - s->as.heap.len = (mrb_int)len; - s->as.heap.aux.capa = 0; /* nofree */ - s->as.heap.ptr = (char *)p; - s->flags = MRB_STR_NOFREE; + str_init_nofree(s, p, len); return s; } @@ -229,9 +233,7 @@ str_decref(mrb_state *mrb, mrb_shared_string *shared) { shared->refcnt--; if (shared->refcnt == 0) { - if (!shared->nofree) { - mrb_free(mrb, shared->ptr); - } + mrb_free(mrb, shared->ptr); mrb_free(mrb, shared); } } @@ -465,7 +467,11 @@ str_make_shared(mrb_state *mrb, struct RString *orig, struct RString *s) mrb_int len = RSTR_LEN(orig); mrb_assert(!RSTR_EMBED_P(orig)); - if (RSTR_SHARED_P(orig)) { + if (RSTR_NOFREE_P(orig)) { + str_init_nofree(s, orig->as.heap.ptr, len); + RSTR_UNSET_EMBED_FLAG(s); + } + else if (RSTR_SHARED_P(orig)) { str_init_shared(mrb, orig, s, orig->as.heap.aux.shared); RSTR_UNSET_EMBED_FLAG(s); } @@ -478,7 +484,7 @@ str_make_shared(mrb_state *mrb, struct RString *orig, struct RString *s) RSTR_UNSET_EMBED_FLAG(s); } else { - if (!RSTR_NOFREE_P(orig) && orig->as.heap.aux.capa > orig->as.heap.len) { + if (orig->as.heap.aux.capa > orig->as.heap.len) { orig->as.heap.ptr = (char *)mrb_realloc(mrb, orig->as.heap.ptr, len+1); } str_init_shared(mrb, orig, s, NULL); @@ -495,11 +501,11 @@ mrb_str_byte_subseq(mrb_state *mrb, mrb_value str, mrb_int beg, mrb_int len) struct RString *orig, *s; orig = mrb_str_ptr(str); - if (RSTR_EMBED_P(orig) || RSTR_LEN(orig) == 0 || RSTR_EMBEDDABLE_P(len)) { - s = str_new(mrb, RSTR_PTR(orig)+beg, len); + s = mrb_obj_alloc_string(mrb); + if (RSTR_EMBEDDABLE_P(len)) { + str_init_embed(s, RSTR_PTR(orig)+beg, len); } else { - s = mrb_obj_alloc_string(mrb); str_make_shared(mrb, orig, s); s->as.heap.ptr += beg; s->as.heap.len = len; @@ -606,7 +612,6 @@ str_replace(mrb_state *mrb, struct RString *s1, struct RString *s2) RSTR_UNSET_FSHARED_FLAG(s1); RSTR_UNSET_NOFREE_FLAG(s1); if (RSTR_EMBEDDABLE_P(len)) { - RSTR_UNSET_SHARED_FLAG(s1); str_init_embed(s1, RSTR_PTR(s2), len); } else { @@ -730,7 +735,7 @@ mrb_str_modify_keep_ascii(mrb_state *mrb, struct RString *s) if (RSTR_SHARED_P(s)) { mrb_shared_string *shared = s->as.heap.aux.shared; - if (shared->nofree == 0 && shared->refcnt == 1 && s->as.heap.ptr == shared->ptr) { + if (shared->refcnt == 1 && s->as.heap.ptr == shared->ptr) { s->as.heap.ptr = shared->ptr; s->as.heap.aux.capa = shared->len; RSTR_PTR(s)[s->as.heap.len] = '\0'; -- cgit v1.2.3 From 61763129dbbac84e0c9a476ff3c88cc958cd3393 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Fri, 16 Aug 2019 22:30:03 +0900 Subject: Implement `Class#new` using inline mruby bytecode. --- mrblib/00class.rb | 8 -------- src/class.c | 39 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 39 insertions(+), 8 deletions(-) diff --git a/mrblib/00class.rb b/mrblib/00class.rb index 8fcfb1362..1811236f0 100644 --- a/mrblib/00class.rb +++ b/mrblib/00class.rb @@ -1,11 +1,3 @@ -class Class - def new(*args, &block) - obj = self.allocate - obj.initialize(*args, &block) - obj - end -end - class Module # 15.2.2.4.12 def attr_accessor(*names) diff --git a/src/class.c b/src/class.c index fb6a8a124..db9bef7b1 100644 --- a/src/class.c +++ b/src/class.c @@ -15,6 +15,7 @@ #include #include #include +#include KHASH_DEFINE(mt, mrb_sym, mrb_method_t, TRUE, kh_int_hash_func, kh_int_hash_equal) @@ -2116,6 +2117,42 @@ inspect_main(mrb_state *mrb, mrb_value mod) return mrb_str_new_lit(mrb, "main"); } +static mrb_code new_iseq[] = { + OP_ENTER, 0x0, 0x10, 0x1, /* OP_ENTER 0:0:1:0:0:0:1 */ + OP_LOADSELF, 0x4, /* OP_LOADSELF R4 */ + OP_SEND, 0x4, 0x0, 0x0, /* OP_SEND R4 :allocate 0 */ + OP_MOVE, 0x3, 0x4, /* OP_MOVE R0 R3 */ + OP_LOADNIL, 0x5, /* OP_LOADNIL R5 */ + OP_MOVE, 0x6, 0x1, /* OP_MOVE R6 R1 */ + OP_ARYCAT, 0x5, /* OP_ARYCAT R5 */ + OP_MOVE, 0x6, 0x2, /* OP_MOVE R6 R2 */ + OP_SENDVB, 0x4, 0x1, /* OP_SENDVB R4 :initialize */ + OP_RETURN, 0x3 /* OP_RETURN R0 */ +}; + +static void +init_class_new(mrb_state *mrb, struct RClass *cls) +{ + struct RProc *p; + mrb_method_t m; + mrb_irep *new_irep = (mrb_irep*)mrb_malloc(mrb, sizeof(mrb_irep)); + static const mrb_irep mrb_irep_zero = { 0 }; + + *new_irep = mrb_irep_zero; + new_irep->syms = (mrb_sym*)mrb_malloc(mrb, sizeof(mrb_sym)*2); + new_irep->syms[0] = mrb_intern_lit(mrb, "allocate"); + new_irep->syms[1] = mrb_intern_lit(mrb, "initialize"); + new_irep->slen = 2; + new_irep->flags = MRB_ISEQ_NO_FREE; + new_irep->iseq = new_iseq; + new_irep->ilen = sizeof(new_iseq); + new_irep->nregs = 7; + new_irep->nlocals = 4; + p = mrb_proc_new(mrb, new_irep); + MRB_METHOD_FROM_PROC(m, p); + mrb_define_method_raw(mrb, cls, mrb_intern_lit(mrb, "new"), m); +} + void mrb_init_class(mrb_state *mrb) { @@ -2168,6 +2205,8 @@ mrb_init_class(mrb_state *mrb) mrb_define_method(mrb, cls, "initialize", mrb_class_initialize, MRB_ARGS_OPT(1)); /* 15.2.3.3.1 */ mrb_define_method(mrb, cls, "inherited", mrb_bob_init, MRB_ARGS_REQ(1)); + init_class_new(mrb, cls); + MRB_SET_INSTANCE_TT(mod, MRB_TT_MODULE); mrb_define_method(mrb, mod, "extend_object", mrb_mod_extend_object, MRB_ARGS_REQ(1)); /* 15.2.2.4.25 */ mrb_define_method(mrb, mod, "extended", mrb_bob_init, MRB_ARGS_REQ(1)); /* 15.2.2.4.26 */ -- cgit v1.2.3 From 0923ff6313d870cc9ae3f09c3710e2b6ffa48edc Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Fri, 16 Aug 2019 22:37:30 +0900 Subject: Optimize bytecode for `Class#new`. --- src/class.c | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/src/class.c b/src/class.c index db9bef7b1..e4fda18fc 100644 --- a/src/class.c +++ b/src/class.c @@ -2119,17 +2119,15 @@ inspect_main(mrb_state *mrb, mrb_value mod) static mrb_code new_iseq[] = { OP_ENTER, 0x0, 0x10, 0x1, /* OP_ENTER 0:0:1:0:0:0:1 */ - OP_LOADSELF, 0x4, /* OP_LOADSELF R4 */ - OP_SEND, 0x4, 0x0, 0x0, /* OP_SEND R4 :allocate 0 */ - OP_MOVE, 0x3, 0x4, /* OP_MOVE R0 R3 */ - OP_LOADNIL, 0x5, /* OP_LOADNIL R5 */ - OP_MOVE, 0x6, 0x1, /* OP_MOVE R6 R1 */ - OP_ARYCAT, 0x5, /* OP_ARYCAT R5 */ - OP_MOVE, 0x6, 0x2, /* OP_MOVE R6 R2 */ - OP_SENDVB, 0x4, 0x1, /* OP_SENDVB R4 :initialize */ - OP_RETURN, 0x3 /* OP_RETURN R0 */ + OP_LOADSELF, 0x3, /* OP_LOADSELF R3 */ + OP_SEND, 0x3, 0x0, 0x0, /* OP_SEND R3 :allocate 0 */ + OP_MOVE, 0x0, 0x3, /* OP_MOVE R0 R3 */ + OP_MOVE, 0x4, 0x1, /* OP_MOVE R4 R1 */ + OP_MOVE, 0x5, 0x2, /* OP_MOVE R5 R2 */ + OP_SENDVB, 0x3, 0x1, /* OP_SENDVB R4 :initialize */ + OP_RETURN, 0x0 /* OP_RETURN R0 */ }; - + static void init_class_new(mrb_state *mrb, struct RClass *cls) { @@ -2146,8 +2144,8 @@ init_class_new(mrb_state *mrb, struct RClass *cls) new_irep->flags = MRB_ISEQ_NO_FREE; new_irep->iseq = new_iseq; new_irep->ilen = sizeof(new_iseq); - new_irep->nregs = 7; - new_irep->nlocals = 4; + new_irep->nregs = 6; + new_irep->nlocals = 3; p = mrb_proc_new(mrb, new_irep); MRB_METHOD_FROM_PROC(m, p); mrb_define_method_raw(mrb, cls, mrb_intern_lit(mrb, "new"), m); -- cgit v1.2.3 From c1a0a993097575ea121b676b65ca1e311b8e4e58 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Fri, 16 Aug 2019 22:48:39 +0900 Subject: Update `struct RArray` union to silence C++ warning. --- include/mruby/array.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/include/mruby/array.h b/include/mruby/array.h index 0c0a002f5..a58e0dcee 100644 --- a/include/mruby/array.h +++ b/include/mruby/array.h @@ -33,6 +33,7 @@ struct RArray { } aux; mrb_value *ptr; } heap; + mrb_value ary[MRB_ARY_EMBED_LEN_MAX]; } as; }; @@ -45,7 +46,7 @@ struct RArray { #define ARY_UNSET_EMBED_FLAG(a) ((a)->flags &= ~(MRB_ARY_EMBED_MASK)) #define ARY_EMBED_LEN(a) ((mrb_int)(((a)->flags & MRB_ARY_EMBED_MASK) - 1)) #define ARY_SET_EMBED_LEN(a,len) ((a)->flags = ((a)->flags&~MRB_ARY_EMBED_MASK) | ((uint32_t)(len) + 1)) -#define ARY_EMBED_PTR(a) ((mrb_value*)&(a)->as) +#define ARY_EMBED_PTR(a) (a)->as.ary #define ARY_LEN(a) (ARY_EMBED_P(a)?ARY_EMBED_LEN(a):(a)->as.heap.len) #define ARY_PTR(a) (ARY_EMBED_P(a)?ARY_EMBED_PTR(a):(a)->as.heap.ptr) -- cgit v1.2.3 From 0286a7f70954850d767d7708ee6ed8dc1d6de090 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Sat, 17 Aug 2019 09:02:47 +0900 Subject: Avoid `mrb_funcall` from `Class#new` when no overloading. --- src/class.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/class.c b/src/class.c index e4fda18fc..1aa1bf0e5 100644 --- a/src/class.c +++ b/src/class.c @@ -1537,7 +1537,10 @@ mrb_class_new_class(mrb_state *mrb, mrb_value cv) } new_class = mrb_obj_value(mrb_class_new(mrb, mrb_class_ptr(super))); mid = mrb_intern_lit(mrb, "initialize"); - if (!mrb_func_basic_p(mrb, new_class, mid, mrb_bob_init)) { + if (mrb_func_basic_p(mrb, new_class, mid, mrb_class_initialize)) { + mrb_class_initialize(mrb, new_class); + } + else { mrb_funcall_with_block(mrb, new_class, mid, n, &super, blk); } mrb_class_inherited(mrb, mrb_class_ptr(super), mrb_class_ptr(new_class)); -- cgit v1.2.3 From cf5f290fa0b062c8cb99e2aa85f2486f6601f116 Mon Sep 17 00:00:00 2001 From: dearblue Date: Sat, 10 Aug 2019 22:17:35 +0900 Subject: Fix `String#rindex` test for UTF-8 string --- test/t/string.rb | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/test/t/string.rb b/test/t/string.rb index 46cbe6e2a..1aa254cd0 100644 --- a/test/t/string.rb +++ b/test/t/string.rb @@ -557,10 +557,9 @@ end assert('String#rindex(UTF-8)', '15.2.10.5.31') do str = "こんにちは世界!\nこんにちは世界!" - assert_nil str.index('さ') - assert_equal 3, str.index('ち') - assert_equal 12, str.index('ち', 10) - assert_equal nil, str.index("さ") + assert_nil str.rindex('さ') + assert_equal 12, str.rindex('ち') + assert_equal 3, str.rindex('ち', 10) end if UTF8STRING # assert('String#scan', '15.2.10.5.32') do -- cgit v1.2.3 From 414ab682f37118288864f5298ea5eb2cd3791dd2 Mon Sep 17 00:00:00 2001 From: dearblue Date: Sat, 10 Aug 2019 22:18:23 +0900 Subject: Add `String#rindex` test for invalid UTF-8 string --- test/t/string.rb | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/test/t/string.rb b/test/t/string.rb index 1aa254cd0..7e3c327b1 100644 --- a/test/t/string.rb +++ b/test/t/string.rb @@ -560,6 +560,13 @@ assert('String#rindex(UTF-8)', '15.2.10.5.31') do assert_nil str.rindex('さ') assert_equal 12, str.rindex('ち') assert_equal 3, str.rindex('ち', 10) + + broken = "\xf0☀\xf1☁\xf2☂\xf3☃\xf0☀\xf1☁\xf2☂\xf3☃" + assert_nil broken.rindex("\x81") # "\x81" is a part of "☁" ("\xe2\x98\x81") + assert_equal 11, broken.rindex("☁") + assert_equal 11, broken.rindex("☁", 12) + assert_equal 11, broken.rindex("☁", 11) + assert_equal 3, broken.rindex("☁", 10) end if UTF8STRING # assert('String#scan', '15.2.10.5.32') do -- cgit v1.2.3 From e76c5aad3600a669583d5197783fd89de64f0378 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Sat, 17 Aug 2019 11:49:00 +0900 Subject: Stop using `mrb_to_str` as a converter (it is not). --- src/class.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/class.c b/src/class.c index 1aa1bf0e5..7e37973f6 100644 --- a/src/class.c +++ b/src/class.c @@ -674,7 +674,8 @@ mrb_get_args(mrb_state *mrb, const char *format, ...) } } if (i < argc) { - *p = mrb_to_str(mrb, ARGV[arg_i++]); + *p = ARGV[arg_i++]; + mrb_to_str(mrb, *p); i++; } } @@ -735,7 +736,8 @@ mrb_get_args(mrb_state *mrb, const char *format, ...) } } if (i < argc) { - ss = mrb_to_str(mrb, ARGV[arg_i++]); + ss = ARGV[arg_i++]; + mrb_to_str(mrb, ss); *ps = RSTRING_PTR(ss); *pl = RSTRING_LEN(ss); i++; @@ -757,7 +759,8 @@ mrb_get_args(mrb_state *mrb, const char *format, ...) } } if (i < argc) { - ss = mrb_to_str(mrb, ARGV[arg_i++]); + ss = ARGV[arg_i++]; + mrb_to_str(mrb, ss); *ps = RSTRING_CSTR(mrb, ss); i++; } -- cgit v1.2.3 From bc272730874b5f0e22f0b7126ec46bc761d335b1 Mon Sep 17 00:00:00 2001 From: dearblue Date: Sat, 10 Aug 2019 22:21:49 +0900 Subject: Fix `String#rindex` with invalid UTF-8 string MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Previously `String#rindex` returned the wrong index when given an invalid UTF-8 string. ```terminal % ruby26 -e 'str = "\xf0☀\xf1☁\xf2☂\xf3☃\xf0☀\xf1☁\xf2☂\xf3☃"; p str.rindex("☁")' 11 % ./mruby-head -e 'str = "\xf0☀\xf1☁\xf2☂\xf3☃\xf0☀\xf1☁\xf2☂\xf3☃"; p str.rindex("☁")' nil % ./mruby-patched -e 'str = "\xf0☀\xf1☁\xf2☂\xf3☃\xf0☀\xf1☁\xf2☂\xf3☃"; p str.rindex("☁")' 11 ``` --- src/string.c | 75 +++++++++++++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 64 insertions(+), 11 deletions(-) diff --git a/src/string.c b/src/string.c index 2b9a5cfde..9d2ff34ad 100644 --- a/src/string.c +++ b/src/string.c @@ -337,19 +337,69 @@ chars2bytes(mrb_value s, mrb_int off, mrb_int idx) /* map byte offset to character index */ static mrb_int -bytes2chars(char *p, mrb_int bi) +bytes2chars(char *p, mrb_int len, mrb_int bi) { - mrb_int i, b, n; + const char *e = p + (size_t)len; + const char *pivot = p + bi; + mrb_int i; - for (b=i=0; b beg || ptr < end) && (*ptr & 0xc0) == 0x80) { + const int utf8_adjust_max = 3; + const char *p; + + if (ptr - beg > utf8_adjust_max) { + beg = ptr - utf8_adjust_max; + } + + p = ptr; + while (p > beg) { + p --; + if ((*p & 0xc0) != 0x80) { + int clen = utf8len(p, end); + if (clen > ptr - p) return p; + break; + } + } + } + + return ptr; +} + +static const char * +char_backtrack(const char *ptr, const char *end) +{ + if (ptr < end) { + const int utf8_bytelen_max = 4; + const char *p; + + if (end - ptr > utf8_bytelen_max) { + ptr = end - utf8_bytelen_max; + } + + p = end; + while (p > ptr) { + p --; + if ((*p & 0xc0) != 0x80) { + int clen = utf8len_codepage[(unsigned char)*p]; + if (clen == end - p) { return p; } + break; + } + } + } + + return end - 1; +} + static mrb_int str_index_str_by_char_search(mrb_state *mrb, const char *p, const char *pend, const char *s, const mrb_int slen, mrb_int off) { @@ -412,7 +462,9 @@ str_index_str_by_char(mrb_state *mrb, mrb_value str, mrb_value sub, mrb_int pos) #else #define RSTRING_CHAR_LEN(s) RSTRING_LEN(s) #define chars2bytes(p, off, ci) (ci) -#define bytes2chars(p, bi) (bi) +#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 @@ -624,7 +676,7 @@ str_replace(mrb_state *mrb, struct RString *s1, struct RString *s2) static mrb_int str_rindex(mrb_state *mrb, mrb_value str, mrb_value sub, mrb_int pos) { - char *s, *sbeg, *t; + const char *s, *sbeg, *t; struct RString *ps = mrb_str_ptr(str); mrb_int len = RSTRING_LEN(sub); @@ -637,11 +689,12 @@ str_rindex(mrb_state *mrb, mrb_value str, mrb_value sub, mrb_int pos) s = RSTR_PTR(ps) + pos; t = RSTRING_PTR(sub); if (len) { + s = char_adjust(sbeg, sbeg + RSTR_LEN(ps), s); while (sbeg <= s) { if (memcmp(s, t, len) == 0) { return (mrb_int)(s - RSTR_PTR(ps)); } - s--; + s = char_backtrack(sbeg, s); } return -1; } @@ -2016,7 +2069,7 @@ mrb_str_rindex(mrb_state *mrb, mrb_value str) case MRB_TT_STRING: pos = str_rindex(mrb, str, sub, pos); if (pos >= 0) { - pos = bytes2chars(RSTRING_PTR(str), pos); + pos = bytes2chars(RSTRING_PTR(str), RSTRING_LEN(str), pos); BYTES_ALIGN_CHECK(pos); return mrb_fixnum_value(pos); } -- cgit v1.2.3 From 13eaff4f9f20955441612fd605ae1932039ec03e Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Sat, 17 Aug 2019 12:29:04 +0900 Subject: Remove unnecessary `OP_JMPNOT` for `unless` statement. --- mrbgems/mruby-compiler/core/codegen.c | 34 ++++++++++++++++++++++------------ 1 file changed, 22 insertions(+), 12 deletions(-) diff --git a/mrbgems/mruby-compiler/core/codegen.c b/mrbgems/mruby-compiler/core/codegen.c index d4031f6fd..f4dbe63a1 100644 --- a/mrbgems/mruby-compiler/core/codegen.c +++ b/mrbgems/mruby-compiler/core/codegen.c @@ -1578,18 +1578,17 @@ codegen(codegen_scope *s, node *tree, int val) } codegen(s, tree->car, VAL); pop(); - pos1 = genjmp2(s, OP_JMPNOT, cursp(), 0, val); - - codegen(s, tree->cdr->car, val); - if (elsepart) { - if (val) pop(); - pos2 = genjmp(s, OP_JMP, 0); - dispatch(s, pos1); - codegen(s, elsepart, val); - dispatch(s, pos2); - } - else { - if (val) { + if (tree->cdr->car) { + pos1 = genjmp2(s, OP_JMPNOT, cursp(), 0, val); + codegen(s, tree->cdr->car, val); + if (elsepart) { + if (val) pop(); + pos2 = genjmp(s, OP_JMP, 0); + dispatch(s, pos1); + codegen(s, elsepart, val); + dispatch(s, pos2); + } + else if (val) { pop(); pos2 = genjmp(s, OP_JMP, 0); dispatch(s, pos1); @@ -1601,6 +1600,17 @@ codegen(codegen_scope *s, node *tree, int val) dispatch(s, pos1); } } + else { /* empty then-part */ + if (elsepart) { + pos1 = genjmp2(s, OP_JMPIF, cursp(), 0, val); + codegen(s, elsepart, val); + dispatch(s, pos1); + } + else if (val) { + genop_1(s, OP_LOADNIL, cursp()); + push(); + } + } } break; -- cgit v1.2.3 From 5b1f25a4e0be7d1880f237b1c1bf5845af7b8588 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Sat, 17 Aug 2019 14:46:32 +0900 Subject: Implement `Array#each` using inline mruby bytecode. --- mrblib/array.rb | 18 +++++++++--------- src/array.c | 53 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 62 insertions(+), 9 deletions(-) diff --git a/mrblib/array.rb b/mrblib/array.rb index 2b080564c..6535d6d83 100644 --- a/mrblib/array.rb +++ b/mrblib/array.rb @@ -10,16 +10,16 @@ class Array # and pass the respective element. # # ISO 15.2.12.5.10 - def each(&block) - return to_enum :each unless block + # def each(&block) + # return to_enum :each unless block - idx = 0 - while idx < length - block.call(self[idx]) - idx += 1 - end - self - end + # idx = 0 + # while idx < length + # block.call(self[idx]) + # idx += 1 + # end + # self + # end ## # Calls the given block for each element of +self+ diff --git a/src/array.c b/src/array.c index 06c23dcd3..70e2fcab7 100644 --- a/src/array.c +++ b/src/array.c @@ -9,6 +9,8 @@ #include #include #include +#include +#include #include "value_array.h" #define ARY_DEFAULT_LEN 4 @@ -1257,6 +1259,55 @@ mrb_ary_svalue(mrb_state *mrb, mrb_value ary) } } +static mrb_code each_iseq[] = { + OP_ENTER, 0x0, 0x00, 0x1, /* OP_ENTER 0:0:0:0:0:0:1 */ + OP_JMPIF, 0x1, 0x0, 19, /* OP_JMPIF R1 19 */ + OP_LOADSELF, 0x3, /* OP_LOADSELF R3 */ + OP_LOADSYM, 0x4, 0x0, /* OP_LOADSYM R4 :each*/ + OP_SEND, 0x3, 0x1, 0x1, /* OP_SEND R3 :to_enum 1 */ + OP_RETURN, 0x3, /* OP_RETURN R3 */ + OP_LOADI_0, 0x2, /* OP_LOADI_0 R2 */ + OP_JMP, 0x0, 43, /* OP_JMP 49 */ + OP_MOVE, 0x3, 0x1, /* OP_MOVE R3 R1 */ + OP_LOADSELF, 0x4, /* OP_LOADSELF R4 */ + OP_MOVE, 0x5, 0x2, /* OP_MOVE R5 R2 */ + OP_SEND, 0x4, 0x2, 0x1, /* OP_SEND R4 :[] 1 */ + OP_SEND, 0x3, 0x3, 0x1, /* OP_SEND R3 :call 1 */ + OP_ADDI, 0x2, 1, /* OP_ADDI R3 1 */ + OP_MOVE, 0x3, 0x2, /* OP_MOVE R3 R2 */ + OP_LOADSELF, 0x4, /* OP_LOADSELF R4 */ + OP_SEND, 0x4, 0x4, 0x0, /* OP_SEND R4 :length 0 */ + OP_LT, 0x3, /* OP_LT R3 */ + OP_JMPIF, 0x3, 0x0, 24, /* OP_JMPIF R3 24 */ + OP_RETURN, 0x0 /* OP_RETURN R3 */ +}; + +static void +init_ary_each(mrb_state *mrb, struct RClass *ary) +{ + struct RProc *p; + mrb_method_t m; + mrb_irep *each_irep = (mrb_irep*)mrb_malloc(mrb, sizeof(mrb_irep)); + static const mrb_irep mrb_irep_zero = { 0 }; + + *each_irep = mrb_irep_zero; + each_irep->syms = (mrb_sym*)mrb_malloc(mrb, sizeof(mrb_sym)*5); + each_irep->syms[0] = mrb_intern_lit(mrb, "each"); + each_irep->syms[1] = mrb_intern_lit(mrb, "to_enum"); + each_irep->syms[2] = mrb_intern_lit(mrb, "[]"); + each_irep->syms[3] = mrb_intern_lit(mrb, "call"); + each_irep->syms[4] = mrb_intern_lit(mrb, "length"); + each_irep->slen = 5; + each_irep->flags = MRB_ISEQ_NO_FREE; + each_irep->iseq = each_iseq; + each_irep->ilen = sizeof(each_iseq); + each_irep->nregs = 7; + each_irep->nlocals = 3; + p = mrb_proc_new(mrb, each_irep); + MRB_METHOD_FROM_PROC(m, p); + mrb_define_method_raw(mrb, ary, mrb_intern_lit(mrb, "each"), m); +} + void mrb_init_array(mrb_state *mrb) { @@ -1297,4 +1348,6 @@ mrb_init_array(mrb_state *mrb) mrb_define_method(mrb, a, "__ary_cmp", mrb_ary_cmp, MRB_ARGS_REQ(1)); mrb_define_method(mrb, a, "__ary_index", mrb_ary_index_m, MRB_ARGS_REQ(1)); /* kept for mruby-array-ext */ mrb_define_method(mrb, a, "__svalue", mrb_ary_svalue, MRB_ARGS_NONE()); + + init_ary_each(mrb, a); } -- cgit v1.2.3 From b55e72b2d67c1042a5170f4cc9cac809f4ed2c90 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Sat, 17 Aug 2019 15:47:14 +0900 Subject: Resolve conflict between #4582 and C++ warning. --- include/mruby/array.h | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/include/mruby/array.h b/include/mruby/array.h index a58e0dcee..f8561d136 100644 --- a/include/mruby/array.h +++ b/include/mruby/array.h @@ -33,7 +33,9 @@ struct RArray { } aux; mrb_value *ptr; } heap; +#if defined(__cplusplus) mrb_value ary[MRB_ARY_EMBED_LEN_MAX]; +#endif } as; }; @@ -46,7 +48,11 @@ struct RArray { #define ARY_UNSET_EMBED_FLAG(a) ((a)->flags &= ~(MRB_ARY_EMBED_MASK)) #define ARY_EMBED_LEN(a) ((mrb_int)(((a)->flags & MRB_ARY_EMBED_MASK) - 1)) #define ARY_SET_EMBED_LEN(a,len) ((a)->flags = ((a)->flags&~MRB_ARY_EMBED_MASK) | ((uint32_t)(len) + 1)) +#if defined(__cplusplus) #define ARY_EMBED_PTR(a) (a)->as.ary +#else +#define ARY_EMBED_PTR(a) ((mrb_value*)(&(a)->as)) +#endif #define ARY_LEN(a) (ARY_EMBED_P(a)?ARY_EMBED_LEN(a):(a)->as.heap.len) #define ARY_PTR(a) (ARY_EMBED_P(a)?ARY_EMBED_PTR(a):(a)->as.heap.ptr) -- cgit v1.2.3 From caba5fef274ab7df91b7247182ecbf2483b853b8 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Sat, 17 Aug 2019 21:24:08 +0900 Subject: Refactor set/unset string type flags Introduce `RSTR_SET_TYPE_FLAG` macro to set the specified string type flag and clear the others. --- include/mruby/string.h | 14 ++++++++++---- src/string.c | 41 ++++++++++------------------------------- 2 files changed, 20 insertions(+), 35 deletions(-) diff --git a/include/mruby/string.h b/include/mruby/string.h index aacbdbfc0..51510457d 100644 --- a/include/mruby/string.h +++ b/include/mruby/string.h @@ -34,6 +34,9 @@ struct RString { } as; }; +#define RSTR_SET_TYPE_FLAG(s, type) (RSTR_UNSET_TYPE_FLAG(s), (s)->flags |= MRB_STR_##type) +#define RSTR_UNSET_TYPE_FLAG(s) ((s)->flags &= ~(MRB_STR_TYPE_MASK|MRB_STR_EMBED_LEN_MASK)) + #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)) @@ -103,11 +106,14 @@ MRB_API mrb_int mrb_str_strlen(mrb_state*, struct RString*); #define MRB_STR_SHARED 1 #define MRB_STR_FSHARED 2 #define MRB_STR_NOFREE 4 -#define MRB_STR_POOL 8 -#define MRB_STR_ASCII 16 -#define MRB_STR_EMBED 32 -#define MRB_STR_EMBED_LEN_MASK 0x7c0 +#define MRB_STR_EMBED 8 /* type flags up to here */ +#define MRB_STR_POOL 16 /* status flags from here */ +#define MRB_STR_ASCII 32 #define MRB_STR_EMBED_LEN_SHIFT 6 +#define MRB_STR_EMBED_LEN_BITSIZE 5 +#define MRB_STR_EMBED_LEN_MASK (((1 << MRB_STR_EMBED_LEN_BITSIZE) - 1) << MRB_STR_EMBED_LEN_SHIFT) +#define MRB_STR_TYPE_MASK (MRB_STR_POOL - 1) + void mrb_gc_free_str(mrb_state*, struct RString*); diff --git a/src/string.c b/src/string.c index 2b9a5cfde..34ab2a51a 100644 --- a/src/string.c +++ b/src/string.c @@ -42,6 +42,7 @@ str_init_normal_capa(mrb_state *mrb, struct RString *s, s->as.heap.ptr = dst; s->as.heap.len = (mrb_int)len; s->as.heap.aux.capa = (mrb_int)capa; + RSTR_UNSET_TYPE_FLAG(s); } static void @@ -55,7 +56,7 @@ str_init_embed(struct RString *s, const char *p, size_t len) { if (p) memcpy(s->as.ary, p, len); s->as.ary[len] = '\0'; - RSTR_SET_EMBED_FLAG(s); + RSTR_SET_TYPE_FLAG(s, EMBED); RSTR_SET_EMBED_LEN(s, len); } @@ -65,7 +66,7 @@ str_init_nofree(struct RString *s, const char *p, size_t len) s->as.heap.ptr = (char *)p; s->as.heap.len = (mrb_int)len; s->as.heap.aux.capa = 0; /* nofree */ - RSTR_SET_NOFREE_FLAG(s); + RSTR_SET_TYPE_FLAG(s, NOFREE); } static void @@ -83,7 +84,7 @@ str_init_shared(mrb_state *mrb, const struct RString *orig, struct RString *s, m s->as.heap.ptr = orig->as.heap.ptr; s->as.heap.len = orig->as.heap.len; s->as.heap.aux.shared = shared; - RSTR_SET_SHARED_FLAG(s); + RSTR_SET_TYPE_FLAG(s, SHARED); } static void @@ -92,7 +93,7 @@ str_init_fshared(const struct RString *orig, struct RString *s, struct RString * s->as.heap.ptr = orig->as.heap.ptr; s->as.heap.len = orig->as.heap.len; s->as.heap.aux.fshared = fshared; - RSTR_SET_FSHARED_FLAG(s); + RSTR_SET_TYPE_FLAG(s, FSHARED); } static void @@ -188,7 +189,6 @@ resize_capa(mrb_state *mrb, struct RString *s, size_t capacity) if (RSTR_EMBED_P(s)) { if (!RSTR_EMBEDDABLE_P(capacity)) { str_init_normal_capa(mrb, s, s->as.ary, RSTR_EMBED_LEN(s), capacity); - RSTR_UNSET_EMBED_FLAG(s); } } else { @@ -469,29 +469,23 @@ str_make_shared(mrb_state *mrb, struct RString *orig, struct RString *s) mrb_assert(!RSTR_EMBED_P(orig)); if (RSTR_NOFREE_P(orig)) { str_init_nofree(s, orig->as.heap.ptr, len); - RSTR_UNSET_EMBED_FLAG(s); } else if (RSTR_SHARED_P(orig)) { str_init_shared(mrb, orig, s, orig->as.heap.aux.shared); - RSTR_UNSET_EMBED_FLAG(s); } else if (RSTR_FSHARED_P(orig)) { str_init_fshared(orig, s, orig->as.heap.aux.fshared); - RSTR_UNSET_EMBED_FLAG(s); } else if (MRB_FROZEN_P(orig) && !RSTR_POOL_P(orig)) { str_init_fshared(orig, s, orig); - RSTR_UNSET_EMBED_FLAG(s); } else { if (orig->as.heap.aux.capa > orig->as.heap.len) { orig->as.heap.ptr = (char *)mrb_realloc(mrb, orig->as.heap.ptr, len+1); } str_init_shared(mrb, orig, s, NULL); - RSTR_UNSET_EMBED_FLAG(s); orig->as.heap.aux.shared = s->as.heap.aux.shared; - RSTR_SET_SHARED_FLAG(orig); - RSTR_UNSET_EMBED_FLAG(s); + RSTR_SET_TYPE_FLAG(orig, SHARED); } } @@ -601,7 +595,6 @@ str_replace(mrb_state *mrb, struct RString *s1, struct RString *s2) RSTR_COPY_ASCII_FLAG(s1, s2); if (RSTR_SHARED_P(s1)) { str_decref(mrb, s1->as.heap.aux.shared); - RSTR_UNSET_SHARED_FLAG(s1); } else if (!RSTR_EMBED_P(s1) && !RSTR_NOFREE_P(s1) && !RSTR_FSHARED_P(s1) && s1->as.heap.ptr) { @@ -609,8 +602,6 @@ str_replace(mrb_state *mrb, struct RString *s1, struct RString *s2) } len = (size_t)RSTR_LEN(s2); - RSTR_UNSET_FSHARED_FLAG(s1); - RSTR_UNSET_NOFREE_FLAG(s1); if (RSTR_EMBEDDABLE_P(len)) { str_init_embed(s1, RSTR_PTR(s2), len); } @@ -736,29 +727,17 @@ mrb_str_modify_keep_ascii(mrb_state *mrb, struct RString *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; - RSTR_PTR(s)[s->as.heap.len] = '\0'; + s->as.heap.ptr[s->as.heap.len] = '\0'; mrb_free(mrb, shared); } else { - char *p = RSTR_PTR(s); - size_t len = (size_t)s->as.heap.len; - - str_init(mrb, s, p, len); + str_init(mrb, s, s->as.heap.ptr, (size_t)s->as.heap.len); str_decref(mrb, shared); } - RSTR_UNSET_SHARED_FLAG(s); - return; } - if (RSTR_NOFREE_P(s) || RSTR_FSHARED_P(s)) { - char *p = s->as.heap.ptr; - size_t len = (size_t)s->as.heap.len; - - RSTR_UNSET_NOFREE_FLAG(s); - RSTR_UNSET_FSHARED_FLAG(s); - str_init(mrb, s, p, len); - return; + else if (RSTR_NOFREE_P(s) || RSTR_FSHARED_P(s)) { + str_init(mrb, s, s->as.heap.ptr, (size_t)s->as.heap.len); } } -- cgit v1.2.3 From 5345731b1d31a5be4f0f15bc7847e1ae34930294 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Sat, 17 Aug 2019 21:46:45 +0900 Subject: Fix wrong argument for `fprintf` in `mruby-bin-mrbc` --- mrbgems/mruby-bin-mrbc/tools/mrbc/mrbc.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/mrbgems/mruby-bin-mrbc/tools/mrbc/mrbc.c b/mrbgems/mruby-bin-mrbc/tools/mrbc/mrbc.c index 2fd9da77d..4c8c680cb 100644 --- a/mrbgems/mruby-bin-mrbc/tools/mrbc/mrbc.c +++ b/mrbgems/mruby-bin-mrbc/tools/mrbc/mrbc.c @@ -71,7 +71,6 @@ get_outfilename(mrb_state *mrb, char *infile, const char *ext) static int parse_args(mrb_state *mrb, int argc, char **argv, struct mrbc_args *args) { - char *outfile = NULL; static const struct mrbc_args args_zero = { 0 }; int i; @@ -86,7 +85,7 @@ parse_args(mrb_state *mrb, int argc, char **argv, struct mrbc_args *args) case 'o': if (args->outfile) { fprintf(stderr, "%s: an output file is already specified. (%s)\n", - args->prog, outfile); + args->prog, args->outfile); return -1; } if (argv[i][2] == '\0' && argv[i+1]) { -- cgit v1.2.3 From 8d70a9b1b547e6ae4dffe4e604a614fc6d5a1fb4 Mon Sep 17 00:00:00 2001 From: David Siaw Date: Sun, 18 Aug 2019 12:12:38 +0900 Subject: first bit of doc generation --- .gitignore | 1 + Doxyfile | 2428 +++++++++++++++++++++++++++++++++++++++++++ Makefile | 4 +- Makefile.doc | 14 + doc/mruby_logo_red_icon.png | Bin 0 -> 3755 bytes include/mruby/object.h | 10 +- 6 files changed, 2451 insertions(+), 6 deletions(-) create mode 100644 Doxyfile create mode 100644 Makefile.doc create mode 100644 doc/mruby_logo_red_icon.png diff --git a/.gitignore b/.gitignore index 400c77386..a1dbc6a3c 100644 --- a/.gitignore +++ b/.gitignore @@ -30,5 +30,6 @@ tags /benchmark/*.png /doc/api +/doxygen/ /src/y.tab.c diff --git a/Doxyfile b/Doxyfile new file mode 100644 index 000000000..74012fbb3 --- /dev/null +++ b/Doxyfile @@ -0,0 +1,2428 @@ +# Doxyfile 1.8.13 + +#--------------------------------------------------------------------------- +# Project related configuration options +#--------------------------------------------------------------------------- + +DOXYFILE_ENCODING = UTF-8 +PROJECT_NAME = "mruby" +PROJECT_NUMBER = 2.0.1 + +PROJECT_BRIEF = "mruby is the lightweight implementation of the Ruby language" + +PROJECT_LOGO = doc/mruby_logo_red_icon.png + +OUTPUT_DIRECTORY = doxygen + +USE_MDFILE_AS_MAINPAGE = README.md + +INPUT = README.md \ + src \ + include \ + include/mruby \ + mrblib \ + doc \ + doc/guides + +# Red for Ruby +HTML_COLORSTYLE_HUE = 359 + +# The following expansions +ENABLE_PREPROCESSING = YES +MACRO_EXPANSION = YES +EXPAND_ONLY_PREDEF = NO +PREDEFINED = +EXPAND_AS_DEFINED = +SKIP_FUNCTION_MACROS = NO + +# This tells doxygen to search the places that make sense +SEARCH_INCLUDES = YES +INCLUDE_PATH = include include/mruby +INCLUDE_FILE_PATTERNS = *.h + +CLANG_ASSISTED_PARSING = YES +CLANG_OPTIONS = -Iinclude + +# This thing creates documentation elements for everything, even when its not documented. Its a little ugly to do it right now because huge swathes of code aren't documented. +EXTRACT_ALL = NO + +#=========================================================================== +# BELOW THIS LINE IS CRUFT GENERATED BY doxygen -g +# If you edit anything below this, bring it up here so its easier to read. +#=========================================================================== + +# If the CREATE_SUBDIRS tag is set to YES then doxygen will create 4096 sub- +# directories (in 2 levels) under the output directory of each output format and +# will distribute the generated files over these directories. Enabling this +# option can be useful when feeding doxygen a huge amount of source files, where +# putting all generated files in the same directory would otherwise causes +# performance problems for the file system. +# The default value is: NO. + +CREATE_SUBDIRS = NO + +# If the ALLOW_UNICODE_NAMES tag is set to YES, doxygen will allow non-ASCII +# characters to appear in the names of generated files. If set to NO, non-ASCII +# characters will be escaped, for example _xE3_x81_x84 will be used for Unicode +# U+3044. +# The default value is: NO. + +ALLOW_UNICODE_NAMES = NO + +# The OUTPUT_LANGUAGE tag is used to specify the language in which all +# documentation generated by doxygen is written. Doxygen will use this +# information to generate all constant output in the proper language. +# Possible values are: Afrikaans, Arabic, Armenian, Brazilian, Catalan, Chinese, +# Chinese-Traditional, Croatian, Czech, Danish, Dutch, English (United States), +# Esperanto, Farsi (Persian), Finnish, French, German, Greek, Hungarian, +# Indonesian, Italian, Japanese, Japanese-en (Japanese with English messages), +# Korean, Korean-en (Korean with English messages), Latvian, Lithuanian, +# Macedonian, Norwegian, Persian (Farsi), Polish, Portuguese, Romanian, Russian, +# Serbian, Serbian-Cyrillic, Slovak, Slovene, Spanish, Swedish, Turkish, +# Ukrainian and Vietnamese. +# The default value is: English. + +OUTPUT_LANGUAGE = English + +# If the BRIEF_MEMBER_DESC tag is set to YES, doxygen will include brief member +# descriptions after the members that are listed in the file and class +# documentation (similar to Javadoc). Set to NO to disable this. +# The default value is: YES. + +BRIEF_MEMBER_DESC = YES + +# If the REPEAT_BRIEF tag is set to YES, doxygen will prepend the brief +# description of a member or function before the detailed description +# +# Note: If both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the +# brief descriptions will be completely suppressed. +# The default value is: YES. + +REPEAT_BRIEF = YES + +# This tag implements a quasi-intelligent brief description abbreviator that is +# used to form the text in various listings. Each string in this list, if found +# as the leading text of the brief description, will be stripped from the text +# and the result, after processing the whole list, is used as the annotated +# text. Otherwise, the brief description is used as-is. If left blank, the +# following values are used ($name is automatically replaced with the name of +# the entity):The $name class, The $name widget, The $name file, is, provides, +# specifies, contains, represents, a, an and the. + +ABBREVIATE_BRIEF = "The $name class" \ + "The $name widget" \ + "The $name file" \ + is \ + provides \ + specifies \ + contains \ + represents \ + a \ + an \ + the + +# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then +# doxygen will generate a detailed section even if there is only a brief +# description. +# The default value is: NO. + +ALWAYS_DETAILED_SEC = NO + +# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all +# inherited members of a class in the documentation of that class as if those +# members were ordinary class members. Constructors, destructors and assignment +# operators of the base classes will not be shown. +# The default value is: NO. + +INLINE_INHERITED_MEMB = NO + +# If the FULL_PATH_NAMES tag is set to YES, doxygen will prepend the full path +# before files name in the file list and in the header files. If set to NO the +# shortest path that makes the file name unique will be used +# The default value is: YES. + +FULL_PATH_NAMES = YES + +# The STRIP_FROM_PATH tag can be used to strip a user-defined part of the path. +# Stripping is only done if one of the specified strings matches the left-hand +# part of the path. The tag can be used to show relative paths in the file list. +# If left blank the directory from which doxygen is run is used as the path to +# strip. +# +# Note that you can specify absolute paths here, but also relative paths, which +# will be relative from the directory where doxygen is started. +# This tag requires that the tag FULL_PATH_NAMES is set to YES. + +STRIP_FROM_PATH = + +# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of the +# path mentioned in the documentation of a class, which tells the reader which +# header file to include in order to use a class. If left blank only the name of +# the header file containing the class definition is used. Otherwise one should +# specify the list of include paths that are normally passed to the compiler +# using the -I flag. + +STRIP_FROM_INC_PATH = + +# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter (but +# less readable) file names. This can be useful is your file systems doesn't +# support long names like on DOS, Mac, or CD-ROM. +# The default value is: NO. + +SHORT_NAMES = NO + +# If the JAVADOC_AUTOBRIEF tag is set to YES then doxygen will interpret the +# first line (until the first dot) of a Javadoc-style comment as the brief +# description. If set to NO, the Javadoc-style will behave just like regular Qt- +# style comments (thus requiring an explicit @brief command for a brief +# description.) +# The default value is: NO. + +JAVADOC_AUTOBRIEF = NO + +# If the QT_AUTOBRIEF tag is set to YES then doxygen will interpret the first +# line (until the first dot) of a Qt-style comment as the brief description. If +# set to NO, the Qt-style will behave just like regular Qt-style comments (thus +# requiring an explicit \brief command for a brief description.) +# The default value is: NO. + +QT_AUTOBRIEF = NO + +# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make doxygen treat a +# multi-line C++ special comment block (i.e. a block of //! or /// comments) as +# a brief description. This used to be the default behavior. The new default is +# to treat a multi-line C++ comment block as a detailed description. Set this +# tag to YES if you prefer the old behavior instead. +# +# Note that setting this tag to YES also means that rational rose comments are +# not recognized any more. +# The default value is: NO. + +MULTILINE_CPP_IS_BRIEF = NO + +# If the INHERIT_DOCS tag is set to YES then an undocumented member inherits the +# documentation from any documented member that it re-implements. +# The default value is: YES. + +INHERIT_DOCS = YES + +# If the SEPARATE_MEMBER_PAGES tag is set to YES then doxygen will produce a new +# page for each member. If set to NO, the documentation of a member will be part +# of the file/class/namespace that contains it. +# The default value is: NO. + +SEPARATE_MEMBER_PAGES = NO + +# The TAB_SIZE tag can be used to set the number of spaces in a tab. Doxygen +# uses this value to replace tabs by spaces in code fragments. +# Minimum value: 1, maximum value: 16, default value: 4. + +TAB_SIZE = 4 + +# This tag can be used to specify a number of aliases that act as commands in +# the documentation. An alias has the form: +# name=value +# For example adding +# "sideeffect=@par Side Effects:\n" +# will allow you to put the command \sideeffect (or @sideeffect) in the +# documentation, which will result in a user-defined paragraph with heading +# "Side Effects:". You can put \n's in the value part of an alias to insert +# newlines. + +ALIASES = + +# This tag can be used to specify a number of word-keyword mappings (TCL only). +# A mapping has the form "name=value". For example adding "class=itcl::class" +# will allow you to use the command class in the itcl::class meaning. + +TCL_SUBST = + +# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources +# only. Doxygen will then generate output that is more tailored for C. For +# instance, some of the names that are used will be different. The list of all +# members will be omitted, etc. +# The default value is: NO. + +OPTIMIZE_OUTPUT_FOR_C = NO + +# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java or +# Python sources only. Doxygen will then generate output that is more tailored +# for that language. For instance, namespaces will be presented as packages, +# qualified scopes will look different, etc. +# The default value is: NO. + +OPTIMIZE_OUTPUT_JAVA = NO + +# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran +# sources. Doxygen will then generate output that is tailored for Fortran. +# The default value is: NO. + +OPTIMIZE_FOR_FORTRAN = NO + +# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL +# sources. Doxygen will then generate output that is tailored for VHDL. +# The default value is: NO. + +OPTIMIZE_OUTPUT_VHDL = NO + +# Doxygen selects the parser to use depending on the extension of the files it +# parses. With this tag you can assign which parser to use for a given +# extension. Doxygen has a built-in mapping, but you can override or extend it +# using this tag. The format is ext=language, where ext is a file extension, and +# language is one of the parsers supported by doxygen: IDL, Java, Javascript, +# C#, C, C++, D, PHP, Objective-C, Python, Fortran (fixed format Fortran: +# FortranFixed, free formatted Fortran: FortranFree, unknown formatted Fortran: +# Fortran. In the later case the parser tries to guess whether the code is fixed +# or free formatted code, this is the default for Fortran type files), VHDL. For +# instance to make doxygen treat .inc files as Fortran files (default is PHP), +# and .f files as C (default is Fortran), use: inc=Fortran f=C. +# +# Note: For files without extension you can use no_extension as a placeholder. +# +# Note that for custom extensions you also need to set FILE_PATTERNS otherwise +# the files are not read by doxygen. + +EXTENSION_MAPPING = + +# If the MARKDOWN_SUPPORT tag is enabled then doxygen pre-processes all comments +# according to the Markdown format, which allows for more readable +# documentation. See http://daringfireball.net/projects/markdown/ for details. +# The output of markdown processing is further processed by doxygen, so you can +# mix doxygen, HTML, and XML commands with Markdown formatting. Disable only in +# case of backward compatibilities issues. +# The default value is: YES. + +MARKDOWN_SUPPORT = YES + +# When the TOC_INCLUDE_HEADINGS tag is set to a non-zero value, all headings up +# to that level are automatically included in the table of contents, even if +# they do not have an id attribute. +# Note: This feature currently applies only to Markdown headings. +# Minimum value: 0, maximum value: 99, default value: 0. +# This tag requires that the tag MARKDOWN_SUPPORT is set to YES. + +TOC_INCLUDE_HEADINGS = 0 + +# When enabled doxygen tries to link words that correspond to documented +# classes, or namespaces to their corresponding documentation. Such a link can +# be prevented in individual cases by putting a % sign in front of the word or +# globally by setting AUTOLINK_SUPPORT to NO. +# The default value is: YES. + +AUTOLINK_SUPPORT = YES + +# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want +# to include (a tag file for) the STL sources as input, then you should set this +# tag to YES in order to let doxygen match functions declarations and +# definitions whose arguments contain STL classes (e.g. func(std::string); +# versus func(std::string) {}). This also make the inheritance and collaboration +# diagrams that involve STL classes more complete and accurate. +# The default value is: NO. + +BUILTIN_STL_SUPPORT = NO + +# If you use Microsoft's C++/CLI language, you should set this option to YES to +# enable parsing support. +# The default value is: NO. + +CPP_CLI_SUPPORT = NO + +# Set the SIP_SUPPORT tag to YES if your project consists of sip (see: +# http://www.riverbankcomputing.co.uk/software/sip/intro) sources only. Doxygen +# will parse them like normal C++ but will assume all classes use public instead +# of private inheritance when no explicit protection keyword is present. +# The default value is: NO. + +SIP_SUPPORT = NO + +# For Microsoft's IDL there are propget and propput attributes to indicate +# getter and setter methods for a property. Setting this option to YES will make +# doxygen to replace the get and set methods by a property in the documentation. +# This will only work if the methods are indeed getting or setting a simple +# type. If this is not the case, or you want to show the methods anyway, you +# should set this option to NO. +# The default value is: YES. + +IDL_PROPERTY_SUPPORT = YES + +# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC +# tag is set to YES then doxygen will reuse the documentation of the first +# member in the group (if any) for the other members of the group. By default +# all members of a group must be documented explicitly. +# The default value is: NO. + +DISTRIBUTE_GROUP_DOC = NO + +# If one adds a struct or class to a group and this option is enabled, then also +# any nested class or struct is added to the same group. By default this option +# is disabled and one has to add nested compounds explicitly via \ingroup. +# The default value is: NO. + +GROUP_NESTED_COMPOUNDS = NO + +# Set the SUBGROUPING tag to YES to allow class member groups of the same type +# (for instance a group of public functions) to be put as a subgroup of that +# type (e.g. under the Public Functions section). Set it to NO to prevent +# subgrouping. Alternatively, this can be done per class using the +# \nosubgrouping command. +# The default value is: YES. + +SUBGROUPING = YES + +# When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and unions +# are shown inside the group in which they are included (e.g. using \ingroup) +# instead of on a separate page (for HTML and Man pages) or section (for LaTeX +# and RTF). +# +# Note that this feature does not work in combination with +# SEPARATE_MEMBER_PAGES. +# The default value is: NO. + +INLINE_GROUPED_CLASSES = NO + +# When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and unions +# with only public data fields or simple typedef fields will be shown inline in +# the documentation of the scope in which they are defined (i.e. file, +# namespace, or group documentation), provided this scope is documented. If set +# to NO, structs, classes, and unions are shown on a separate page (for HTML and +# Man pages) or section (for LaTeX and RTF). +# The default value is: NO. + +INLINE_SIMPLE_STRUCTS = NO + +# When TYPEDEF_HIDES_STRUCT tag is enabled, a typedef of a struct, union, or +# enum is documented as struct, union, or enum with the name of the typedef. So +# typedef struct TypeS {} TypeT, will appear in the documentation as a struct +# with name TypeT. When disabled the typedef will appear as a member of a file, +# namespace, or class. And the struct will be named TypeS. This can typically be +# useful for C code in case the coding convention dictates that all compound +# types are typedef'ed and only the typedef is referenced, never the tag name. +# The default value is: NO. + +TYPEDEF_HIDES_STRUCT = NO + +# The size of the symbol lookup cache can be set using LOOKUP_CACHE_SIZE. This +# cache is used to resolve symbols given their name and scope. Since this can be +# an expensive process and often the same symbol appears multiple times in the +# code, doxygen keeps a cache of pre-resolved symbols. If the cache is too small +# doxygen will become slower. If the cache is too large, memory is wasted. The +# cache size is given by this formula: 2^(16+LOOKUP_CACHE_SIZE). The valid range +# is 0..9, the default is 0, corresponding to a cache size of 2^16=65536 +# symbols. At the end of a run doxygen will report the cache usage and suggest +# the optimal cache size from a speed point of view. +# Minimum value: 0, maximum value: 9, default value: 0. + +LOOKUP_CACHE_SIZE = 0 + +#--------------------------------------------------------------------------- +# Build related configuration options +#--------------------------------------------------------------------------- + +# If the EXTRACT_ALL tag is set to YES, doxygen will assume all entities in +# documentation are documented, even if no documentation was available. Private +# class members and static file members will be hidden unless the +# EXTRACT_PRIVATE respectively EXTRACT_STATIC tags are set to YES. +# Note: This will also disable the warnings about undocumented members that are +# normally produced when WARNINGS is set to YES. +# The default value is: NO. + + +# If the EXTRACT_PRIVATE tag is set to YES, all private members of a class will +# be included in the documentation. +# The default value is: NO. + +EXTRACT_PRIVATE = NO + +# If the EXTRACT_PACKAGE tag is set to YES, all members with package or internal +# scope will be included in the documentation. +# The default value is: NO. + +EXTRACT_PACKAGE = NO + +# If the EXTRACT_STATIC tag is set to YES, all static members of a file will be +# included in the documentation. +# The default value is: NO. + +EXTRACT_STATIC = NO + +# If the EXTRACT_LOCAL_CLASSES tag is set to YES, classes (and structs) defined +# locally in source files will be included in the documentation. If set to NO, +# only classes defined in header files are included. Does not have any effect +# for Java sources. +# The default value is: YES. + +EXTRACT_LOCAL_CLASSES = YES + +# This flag is only useful for Objective-C code. If set to YES, local methods, +# which are defined in the implementation section but not in the interface are +# included in the documentation. If set to NO, only methods in the interface are +# included. +# The default value is: NO. + +EXTRACT_LOCAL_METHODS = NO + +# If this flag is set to YES, the members of anonymous namespaces will be +# extracted and appear in the documentation as a namespace called +# 'anonymous_namespace{file}', where file will be replaced with the base name of +# the file that contains the anonymous namespace. By default anonymous namespace +# are hidden. +# The default value is: NO. + +EXTRACT_ANON_NSPACES = NO + +# If the HIDE_UNDOC_MEMBERS tag is set to YES, doxygen will hide all +# undocumented members inside documented classes or files. If set to NO these +# members will be included in the various overviews, but no documentation +# section is generated. This option has no effect if EXTRACT_ALL is enabled. +# The default value is: NO. + +HIDE_UNDOC_MEMBERS = NO + +# If the HIDE_UNDOC_CLASSES tag is set to YES, doxygen will hide all +# undocumented classes that are normally visible in the class hierarchy. If set +# to NO, these classes will be included in the various overviews. This option +# has no effect if EXTRACT_ALL is enabled. +# The default value is: NO. + +HIDE_UNDOC_CLASSES = NO + +# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, doxygen will hide all friend +# (class|struct|union) declarations. If set to NO, these declarations will be +# included in the documentation. +# The default value is: NO. + +HIDE_FRIEND_COMPOUNDS = NO + +# If the HIDE_IN_BODY_DOCS tag is set to YES, doxygen will hide any +# documentation blocks found inside the body of a function. If set to NO, these +# blocks will be appended to the function's detailed documentation block. +# The default value is: NO. + +HIDE_IN_BODY_DOCS = NO + +# The INTERNAL_DOCS tag determines if documentation that is typed after a +# \internal command is included. If the tag is set to NO then the documentation +# will be excluded. Set it to YES to include the internal documentation. +# The default value is: NO. + +INTERNAL_DOCS = NO + +# If the CASE_SENSE_NAMES tag is set to NO then doxygen will only generate file +# names in lower-case letters. If set to YES, upper-case letters are also +# allowed. This is useful if you have classes or files whose names only differ +# in case and if your file system supports case sensitive file names. Windows +# and Mac users are advised to set this option to NO. +# The default value is: system dependent. + +CASE_SENSE_NAMES = YES + +# If the HIDE_SCOPE_NAMES tag is set to NO then doxygen will show members with +# their full class and namespace scopes in the documentation. If set to YES, the +# scope will be hidden. +# The default value is: NO. + +HIDE_SCOPE_NAMES = NO + +# If the HIDE_COMPOUND_REFERENCE tag is set to NO (default) then doxygen will +# append additional text to a page's title, such as Class Reference. If set to +# YES the compound reference will be hidden. +# The default value is: NO. + +HIDE_COMPOUND_REFERENCE= NO + +# If the SHOW_INCLUDE_FILES tag is set to YES then doxygen will put a list of +# the files that are included by a file in the documentation of that file. +# The default value is: YES. + +SHOW_INCLUDE_FILES = YES + +# If the SHOW_GROUPED_MEMB_INC tag is set to YES then Doxygen will add for each +# grouped member an include statement to the documentation, telling the reader +# which file to include in order to use the member. +# The default value is: NO. + +SHOW_GROUPED_MEMB_INC = NO + +# If the FORCE_LOCAL_INCLUDES tag is set to YES then doxygen will list include +# files with double quotes in the documentation rather than with sharp brackets. +# The default value is: NO. + +FORCE_LOCAL_INCLUDES = NO + +# If the INLINE_INFO tag is set to YES then a tag [inline] is inserted in the +# documentation for inline members. +# The default value is: YES. + +INLINE_INFO = YES + +# If the SORT_MEMBER_DOCS tag is set to YES then doxygen will sort the +# (detailed) documentation of file and class members alphabetically by member +# name. If set to NO, the members will appear in declaration order. +# The default value is: YES. + +SORT_MEMBER_DOCS = YES + +# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the brief +# descriptions of file, namespace and class members alphabetically by member +# name. If set to NO, the members will appear in declaration order. Note that +# this will also influence the order of the classes in the class list. +# The default value is: NO. + +SORT_BRIEF_DOCS = NO + +# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen will sort the +# (brief and detailed) documentation of class members so that constructors and +# destructors are listed first. If set to NO the constructors will appear in the +# respective orders defined by SORT_BRIEF_DOCS and SORT_MEMBER_DOCS. +# Note: If SORT_BRIEF_DOCS is set to NO this option is ignored for sorting brief +# member documentation. +# Note: If SORT_MEMBER_DOCS is set to NO this option is ignored for sorting +# detailed member documentation. +# The default value is: NO. + +SORT_MEMBERS_CTORS_1ST = NO + +# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the hierarchy +# of group names into alphabetical order. If set to NO the group names will +# appear in their defined order. +# The default value is: NO. + +SORT_GROUP_NAMES = NO + +# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be sorted by +# fully-qualified names, including namespaces. If set to NO, the class list will +# be sorted only by class name, not including the namespace part. +# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES. +# Note: This option applies only to the class list, not to the alphabetical +# list. +# The default value is: NO. + +SORT_BY_SCOPE_NAME = NO + +# If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to do proper +# type resolution of all parameters of a function it will reject a match between +# the prototype and the implementation of a member function even if there is +# only one candidate or it is obvious which candidate to choose by doing a +# simple string match. By disabling STRICT_PROTO_MATCHING doxygen will still +# accept a match between prototype and implementation in such cases. +# The default value is: NO. + +STRICT_PROTO_MATCHING = NO + +# The GENERATE_TODOLIST tag can be used to enable (YES) or disable (NO) the todo +# list. This list is created by putting \todo commands in the documentation. +# The default value is: YES. + +GENERATE_TODOLIST = YES + +# The GENERATE_TESTLIST tag can be used to enable (YES) or disable (NO) the test +# list. This list is created by putting \test commands in the documentation. +# The default value is: YES. + +GENERATE_TESTLIST = YES + +# The GENERATE_BUGLIST tag can be used to enable (YES) or disable (NO) the bug +# list. This list is created by putting \bug commands in the documentation. +# The default value is: YES. + +GENERATE_BUGLIST = YES + +# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or disable (NO) +# the deprecated list. This list is created by putting \deprecated commands in +# the documentation. +# The default value is: YES. + +GENERATE_DEPRECATEDLIST= YES + +# The ENABLED_SECTIONS tag can be used to enable conditional documentation +# sections, marked by \if ... \endif and \cond +# ... \endcond blocks. + +ENABLED_SECTIONS = + +# The MAX_INITIALIZER_LINES tag determines the maximum number of lines that the +# initial value of a variable or macro / define can have for it to appear in the +# documentation. If the initializer consists of more lines than specified here +# it will be hidden. Use a value of 0 to hide initializers completely. The +# appearance of the value of individual variables and macros / defines can be +# controlled using \showinitializer or \hideinitializer command in the +# documentation regardless of this setting. +# Minimum value: 0, maximum value: 10000, default value: 30. + +MAX_INITIALIZER_LINES = 30 + +# Set the SHOW_USED_FILES tag to NO to disable the list of files generated at +# the bottom of the documentation of classes and structs. If set to YES, the +# list will mention the files that were used to generate the documentation. +# The default value is: YES. + +SHOW_USED_FILES = YES + +# Set the SHOW_FILES tag to NO to disable the generation of the Files page. This +# will remove the Files entry from the Quick Index and from the Folder Tree View +# (if specified). +# The default value is: YES. + +SHOW_FILES = YES + +# Set the SHOW_NAMESPACES tag to NO to disable the generation of the Namespaces +# page. This will remove the Namespaces entry from the Quick Index and from the +# Folder Tree View (if specified). +# The default value is: YES. + +SHOW_NAMESPACES = YES + +# The FILE_VERSION_FILTER tag can be used to specify a program or script that +# doxygen should invoke to get the current version for each file (typically from +# the version control system). Doxygen will invoke the program by executing (via +# popen()) the command command input-file, where command is the value of the +# FILE_VERSION_FILTER tag, and input-file is the name of an input file provided +# by doxygen. Whatever the program writes to standard output is used as the file +# version. For an example see the documentation. + +FILE_VERSION_FILTER = + +# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed +# by doxygen. The layout file controls the global structure of the generated +# output files in an output format independent way. To create the layout file +# that represents doxygen's defaults, run doxygen with the -l option. You can +# optionally specify a file name after the option, if omitted DoxygenLayout.xml +# will be used as the name of the layout file. +# +# Note that if you run doxygen from a directory containing a file called +# DoxygenLayout.xml, doxygen will parse it automatically even if the LAYOUT_FILE +# tag is left empty. + +LAYOUT_FILE = + +# The CITE_BIB_FILES tag can be used to specify one or more bib files containing +# the reference definitions. This must be a list of .bib files. The .bib +# extension is automatically appended if omitted. This requires the bibtex tool +# to be installed. See also http://en.wikipedia.org/wiki/BibTeX for more info. +# For LaTeX the style of the bibliography can be controlled using +# LATEX_BIB_STYLE. To use this feature you need bibtex and perl available in the +# search path. See also \cite for info how to create references. + +CITE_BIB_FILES = + +#--------------------------------------------------------------------------- +# Configuration options related to warning and progress messages +#--------------------------------------------------------------------------- + +# The QUIET tag can be used to turn on/off the messages that are generated to +# standard output by doxygen. If QUIET is set to YES this implies that the +# messages are off. +# The default value is: NO. + +QUIET = NO + +# The WARNINGS tag can be used to turn on/off the warning messages that are +# generated to standard error (stderr) by doxygen. If WARNINGS is set to YES +# this implies that the warnings are on. +# +# Tip: Turn warnings on while writing the documentation. +# The default value is: YES. + +WARNINGS = YES + +# If the WARN_IF_UNDOCUMENTED tag is set to YES then doxygen will generate +# warnings for undocumented members. If EXTRACT_ALL is set to YES then this flag +# will automatically be disabled. +# The default value is: YES. + +WARN_IF_UNDOCUMENTED = YES + +# If the WARN_IF_DOC_ERROR tag is set to YES, doxygen will generate warnings for +# potential errors in the documentation, such as not documenting some parameters +# in a documented function, or documenting parameters that don't exist or using +# markup commands wrongly. +# The default value is: YES. + +WARN_IF_DOC_ERROR = YES + +# This WARN_NO_PARAMDOC option can be enabled to get warnings for functions that +# are documented, but have no documentation for their parameters or return +# value. If set to NO, doxygen will only warn about wrong or incomplete +# parameter documentation, but not about the absence of documentation. +# The default value is: NO. + +WARN_NO_PARAMDOC = NO + +# If the WARN_AS_ERROR tag is set to YES then doxygen will immediately stop when +# a warning is encountered. +# The default value is: NO. + +WARN_AS_ERROR = NO + +# The WARN_FORMAT tag determines the format of the warning messages that doxygen +# can produce. The string should contain the $file, $line, and $text tags, which +# will be replaced by the file and line number from which the warning originated +# and the warning text. Optionally the format may contain $version, which will +# be replaced by the version of the file (if it could be obtained via +# FILE_VERSION_FILTER) +# The default value is: $file:$line: $text. + +WARN_FORMAT = "$file:$line: $text" + +# The WARN_LOGFILE tag can be used to specify a file to which warning and error +# messages should be written. If left blank the output is written to standard +# error (stderr). + +WARN_LOGFILE = + +#--------------------------------------------------------------------------- +# Configuration options related to the input files +#--------------------------------------------------------------------------- + +# The INPUT tag is used to specify the files and/or directories that contain +# documented source files. You may enter file names like myfile.cpp or +# directories like /usr/src/myproject. Separate the files or directories with +# spaces. See also FILE_PATTERNS and EXTENSION_MAPPING +# Note: If this tag is empty the current directory is searched. + + +# This tag can be used to specify the character encoding of the source files +# that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses +# libiconv (or the iconv built into libc) for the transcoding. See the libiconv +# documentation (see: http://www.gnu.org/software/libiconv) for the list of +# possible encodings. +# The default value is: UTF-8. + +INPUT_ENCODING = UTF-8 + +# If the value of the INPUT tag contains directories, you can use the +# FILE_PATTERNS tag to specify one or more wildcard patterns (like *.cpp and +# *.h) to filter out the source-files in the directories. +# +# Note that for custom extensions or not directly supported extensions you also +# need to set EXTENSION_MAPPING for the extension otherwise the files are not +# read by doxygen. +# +# If left blank the following patterns are tested:*.c, *.cc, *.cxx, *.cpp, +# *.c++, *.java, *.ii, *.ixx, *.ipp, *.i++, *.inl, *.idl, *.ddl, *.odl, *.h, +# *.hh, *.hxx, *.hpp, *.h++, *.cs, *.d, *.php, *.php4, *.php5, *.phtml, *.inc, +# *.m, *.markdown, *.md, *.mm, *.dox, *.py, *.pyw, *.f90, *.f95, *.f03, *.f08, +# *.f, *.for, *.tcl, *.vhd, *.vhdl, *.ucf and *.qsf. + +FILE_PATTERNS = *.c \ + *.cc \ + *.cxx \ + *.cpp \ + *.c++ \ + *.java \ + *.ii \ + *.ixx \ + *.ipp \ + *.i++ \ + *.inl \ + *.idl \ + *.ddl \ + *.odl \ + *.h \ + *.hh \ + *.hxx \ + *.hpp \ + *.h++ \ + *.cs \ + *.d \ + *.php \ + *.php4 \ + *.php5 \ + *.phtml \ + *.inc \ + *.m \ + *.markdown \ + *.md \ + *.mm \ + *.dox \ + *.py \ + *.pyw \ + *.f90 \ + *.f95 \ + *.f03 \ + *.f08 \ + *.f \ + *.for \ + *.tcl \ + *.vhd \ + *.vhdl \ + *.ucf \ + *.qsf + +# The RECURSIVE tag can be used to specify whether or not subdirectories should +# be searched for input files as well. +# The default value is: NO. + +RECURSIVE = NO + +# The EXCLUDE tag can be used to specify files and/or directories that should be +# excluded from the INPUT source files. This way you can easily exclude a +# subdirectory from a directory tree whose root is specified with the INPUT tag. +# +# Note that relative paths are relative to the directory from which doxygen is +# run. + +EXCLUDE = + +# The EXCLUDE_SYMLINKS tag can be used to select whether or not files or +# directories that are symbolic links (a Unix file system feature) are excluded +# from the input. +# The default value is: NO. + +EXCLUDE_SYMLINKS = NO + +# If the value of the INPUT tag contains directories, you can use the +# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude +# certain files from those directories. +# +# Note that the wildcards are matched against the file with absolute path, so to +# exclude all test directories for example use the pattern */test/* + +EXCLUDE_PATTERNS = + +# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names +# (namespaces, classes, functions, etc.) that should be excluded from the +# output. The symbol name can be a fully qualified name, a word, or if the +# wildcard * is used, a substring. Examples: ANamespace, AClass, +# AClass::ANamespace, ANamespace::*Test +# +# Note that the wildcards are matched against the file with absolute path, so to +# exclude all test directories use the pattern */test/* + +EXCLUDE_SYMBOLS = + +# The EXAMPLE_PATH tag can be used to specify one or more files or directories +# that contain example code fragments that are included (see the \include +# command). + +EXAMPLE_PATH = + +# If the value of the EXAMPLE_PATH tag contains directories, you can use the +# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp and +# *.h) to filter out the source-files in the directories. If left blank all +# files are included. + +EXAMPLE_PATTERNS = * + +# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be +# searched for input files to be used with the \include or \dontinclude commands +# irrespective of the value of the RECURSIVE tag. +# The default value is: NO. + +EXAMPLE_RECURSIVE = NO + +# The IMAGE_PATH tag can be used to specify one or more files or directories +# that contain images that are to be included in the documentation (see the +# \image command). + +IMAGE_PATH = + +# The INPUT_FILTER tag can be used to specify a program that doxygen should +# invoke to filter for each input file. Doxygen will invoke the filter program +# by executing (via popen()) the command: +# +# +# +# where is the value of the INPUT_FILTER tag, and is the +# name of an input file. Doxygen will then use the output that the filter +# program writes to standard output. If FILTER_PATTERNS is specified, this tag +# will be ignored. +# +# Note that the filter must not add or remove lines; it is applied before the +# code is scanned, but not when the output code is generated. If lines are added +# or removed, the anchors will not be placed correctly. +# +# Note that for custom extensions or not directly supported extensions you also +# need to set EXTENSION_MAPPING for the extension otherwise the files are not +# properly processed by doxygen. + +INPUT_FILTER = + +# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern +# basis. Doxygen will compare the file name with each pattern and apply the +# filter if there is a match. The filters are a list of the form: pattern=filter +# (like *.cpp=my_cpp_filter). See INPUT_FILTER for further information on how +# filters are used. If the FILTER_PATTERNS tag is empty or if none of the +# patterns match the file name, INPUT_FILTER is applied. +# +# Note that for custom extensions or not directly supported extensions you also +# need to set EXTENSION_MAPPING for the extension otherwise the files are not +# properly processed by doxygen. + +FILTER_PATTERNS = + +# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using +# INPUT_FILTER) will also be used to filter the input files that are used for +# producing the source files to browse (i.e. when SOURCE_BROWSER is set to YES). +# The default value is: NO. + +FILTER_SOURCE_FILES = NO + +# The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file +# pattern. A pattern will override the setting for FILTER_PATTERN (if any) and +# it is also possible to disable source filtering for a specific pattern using +# *.ext= (so without naming a filter). +# This tag requires that the tag FILTER_SOURCE_FILES is set to YES. + +FILTER_SOURCE_PATTERNS = + +#--------------------------------------------------------------------------- +# Configuration options related to source browsing +#--------------------------------------------------------------------------- + +# If the SOURCE_BROWSER tag is set to YES then a list of source files will be +# generated. Documented entities will be cross-referenced with these sources. +# +# Note: To get rid of all source code in the generated output, make sure that +# also VERBATIM_HEADERS is set to NO. +# The default value is: NO. + +SOURCE_BROWSER = NO + +# Setting the INLINE_SOURCES tag to YES will include the body of functions, +# classes and enums directly into the documentation. +# The default value is: NO. + +INLINE_SOURCES = NO + +# Setting the STRIP_CODE_COMMENTS tag to YES will instruct doxygen to hide any +# special comment blocks from generated source code fragments. Normal C, C++ and +# Fortran comments will always remain visible. +# The default value is: YES. + +STRIP_CODE_COMMENTS = YES + +# If the REFERENCED_BY_RELATION tag is set to YES then for each documented +# function all documented functions referencing it will be listed. +# The default value is: NO. + +REFERENCED_BY_RELATION = NO + +# If the REFERENCES_RELATION tag is set to YES then for each documented function +# all documented entities called/used by that function will be listed. +# The default value is: NO. + +REFERENCES_RELATION = NO + +# If the REFERENCES_LINK_SOURCE tag is set to YES and SOURCE_BROWSER tag is set +# to YES then the hyperlinks from functions in REFERENCES_RELATION and +# REFERENCED_BY_RELATION lists will link to the source code. Otherwise they will +# link to the documentation. +# The default value is: YES. + +REFERENCES_LINK_SOURCE = YES + +# If SOURCE_TOOLTIPS is enabled (the default) then hovering a hyperlink in the +# source code will show a tooltip with additional information such as prototype, +# brief description and links to the definition and documentation. Since this +# will make the HTML file larger and loading of large files a bit slower, you +# can opt to disable this feature. +# The default value is: YES. +# This tag requires that the tag SOURCE_BROWSER is set to YES. + +SOURCE_TOOLTIPS = YES + +# If the USE_HTAGS tag is set to YES then the references to source code will +# point to the HTML generated by the htags(1) tool instead of doxygen built-in +# source browser. The htags tool is part of GNU's global source tagging system +# (see http://www.gnu.org/software/global/global.html). You will need version +# 4.8.6 or higher. +# +# To use it do the following: +# - Install the latest version of global +# - Enable SOURCE_BROWSER and USE_HTAGS in the config file +# - Make sure the INPUT points to the root of the source tree +# - Run doxygen as normal +# +# Doxygen will invoke htags (and that will in turn invoke gtags), so these +# tools must be available from the command line (i.e. in the search path). +# +# The result: instead of the source browser generated by doxygen, the links to +# source code will now point to the output of htags. +# The default value is: NO. +# This tag requires that the tag SOURCE_BROWSER is set to YES. + +USE_HTAGS = NO + +# If the VERBATIM_HEADERS tag is set the YES then doxygen will generate a +# verbatim copy of the header file for each class for which an include is +# specified. Set to NO to disable this. +# See also: Section \class. +# The default value is: YES. + +VERBATIM_HEADERS = YES + +# If the CLANG_ASSISTED_PARSING tag is set to YES then doxygen will use the +# clang parser (see: http://clang.llvm.org/) for more accurate parsing at the +# cost of reduced performance. This can be particularly helpful with template +# rich C++ code for which doxygen's built-in parser lacks the necessary type +# information. +# Note: The availability of this option depends on whether or not doxygen was +# generated with the -Duse-libclang=ON option for CMake. +# The default value is: NO. + + +# If clang assisted parsing is enabled you can provide the compiler with command +# line options that you would normally use when invoking the compiler. Note that +# the include paths will already be set by doxygen for the files and directories +# specified with INPUT and INCLUDE_PATH. +# This tag requires that the tag CLANG_ASSISTED_PARSING is set to YES. + + +#--------------------------------------------------------------------------- +# Configuration options related to the alphabetical class index +#--------------------------------------------------------------------------- + +# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index of all +# compounds will be generated. Enable this if the project contains a lot of +# classes, structs, unions or interfaces. +# The default value is: YES. + +ALPHABETICAL_INDEX = YES + +# The COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns in +# which the alphabetical index list will be split. +# Minimum value: 1, maximum value: 20, default value: 5. +# This tag requires that the tag ALPHABETICAL_INDEX is set to YES. + +COLS_IN_ALPHA_INDEX = 5 + +# In case all classes in a project start with a common prefix, all classes will +# be put under the same header in the alphabetical index. The IGNORE_PREFIX tag +# can be used to specify a prefix (or a list of prefixes) that should be ignored +# while generating the index headers. +# This tag requires that the tag ALPHABETICAL_INDEX is set to YES. + +IGNORE_PREFIX = + +#--------------------------------------------------------------------------- +# Configuration options related to the HTML output +#--------------------------------------------------------------------------- + +# If the GENERATE_HTML tag is set to YES, doxygen will generate HTML output +# The default value is: YES. + +GENERATE_HTML = YES + +# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. If a +# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of +# it. +# The default directory is: html. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_OUTPUT = html + +# The HTML_FILE_EXTENSION tag can be used to specify the file extension for each +# generated HTML page (for example: .htm, .php, .asp). +# The default value is: .html. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_FILE_EXTENSION = .html + +# The HTML_HEADER tag can be used to specify a user-defined HTML header file for +# each generated HTML page. If the tag is left blank doxygen will generate a +# standard header. +# +# To get valid HTML the header file that includes any scripts and style sheets +# that doxygen needs, which is dependent on the configuration options used (e.g. +# the setting GENERATE_TREEVIEW). It is highly recommended to start with a +# default header using +# doxygen -w html new_header.html new_footer.html new_stylesheet.css +# YourConfigFile +# and then modify the file new_header.html. See also section "Doxygen usage" +# for information on how to generate the default header that doxygen normally +# uses. +# Note: The header is subject to change so you typically have to regenerate the +# default header when upgrading to a newer version of doxygen. For a description +# of the possible markers and block names see the documentation. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_HEADER = + +# The HTML_FOOTER tag can be used to specify a user-defined HTML footer for each +# generated HTML page. If the tag is left blank doxygen will generate a standard +# footer. See HTML_HEADER for more information on how to generate a default +# footer and what special commands can be used inside the footer. See also +# section "Doxygen usage" for information on how to generate the default footer +# that doxygen normally uses. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_FOOTER = + +# The HTML_STYLESHEET tag can be used to specify a user-defined cascading style +# sheet that is used by each HTML page. It can be used to fine-tune the look of +# the HTML output. If left blank doxygen will generate a default style sheet. +# See also section "Doxygen usage" for information on how to generate the style +# sheet that doxygen normally uses. +# Note: It is recommended to use HTML_EXTRA_STYLESHEET instead of this tag, as +# it is more robust and this tag (HTML_STYLESHEET) will in the future become +# obsolete. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_STYLESHEET = + +# The HTML_EXTRA_STYLESHEET tag can be used to specify additional user-defined +# cascading style sheets that are included after the standard style sheets +# created by doxygen. Using this option one can overrule certain style aspects. +# This is preferred over using HTML_STYLESHEET since it does not replace the +# standard style sheet and is therefore more robust against future updates. +# Doxygen will copy the style sheet files to the output directory. +# Note: The order of the extra style sheet files is of importance (e.g. the last +# style sheet in the list overrules the setting of the previous ones in the +# list). For an example see the documentation. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_EXTRA_STYLESHEET = + +# The HTML_EXTRA_FILES tag can be used to specify one or more extra images or +# other source files which should be copied to the HTML output directory. Note +# that these files will be copied to the base HTML output directory. Use the +# $relpath^ marker in the HTML_HEADER and/or HTML_FOOTER files to load these +# files. In the HTML_STYLESHEET file, use the file name only. Also note that the +# files will be copied as-is; there are no commands or markers available. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_EXTRA_FILES = + +# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of the colors +# in the HTML output. For a value of 0 the output will use grayscales only. A +# value of 255 will produce the most vivid colors. +# Minimum value: 0, maximum value: 255, default value: 100. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_COLORSTYLE_SAT = 100 + +# The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to the +# luminance component of the colors in the HTML output. Values below 100 +# gradually make the output lighter, whereas values above 100 make the output +# darker. The value divided by 100 is the actual gamma applied, so 80 represents +# a gamma of 0.8, The value 220 represents a gamma of 2.2, and 100 does not +# change the gamma. +# Minimum value: 40, maximum value: 240, default value: 80. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_COLORSTYLE_GAMMA = 80 + +# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML +# page will contain the date and time when the page was generated. Setting this +# to YES can help to show when doxygen was last run and thus if the +# documentation is up to date. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_TIMESTAMP = NO + +# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML +# documentation will contain sections that can be hidden and shown after the +# page has loaded. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_DYNAMIC_SECTIONS = NO + +# With HTML_INDEX_NUM_ENTRIES one can control the preferred number of entries +# shown in the various tree structured indices initially; the user can expand +# and collapse entries dynamically later on. Doxygen will expand the tree to +# such a level that at most the specified number of entries are visible (unless +# a fully collapsed tree already exceeds this amount). So setting the number of +# entries 1 will produce a full collapsed tree by default. 0 is a special value +# representing an infinite number of entries and will result in a full expanded +# tree by default. +# Minimum value: 0, maximum value: 9999, default value: 100. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_INDEX_NUM_ENTRIES = 100 + +# If the GENERATE_DOCSET tag is set to YES, additional index files will be +# generated that can be used as input for Apple's Xcode 3 integrated development +# environment (see: http://developer.apple.com/tools/xcode/), introduced with +# OSX 10.5 (Leopard). To create a documentation set, doxygen will generate a +# Makefile in the HTML output directory. Running make will produce the docset in +# that directory and running make install will install the docset in +# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find it at +# startup. See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html +# for more information. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +GENERATE_DOCSET = NO + +# This tag determines the name of the docset feed. A documentation feed provides +# an umbrella under which multiple documentation sets from a single provider +# (such as a company or product suite) can be grouped. +# The default value is: Doxygen generated docs. +# This tag requires that the tag GENERATE_DOCSET is set to YES. + +DOCSET_FEEDNAME = "Doxygen generated docs" + +# This tag specifies a string that should uniquely identify the documentation +# set bundle. This should be a reverse domain-name style string, e.g. +# com.mycompany.MyDocSet. Doxygen will append .docset to the name. +# The default value is: org.doxygen.Project. +# This tag requires that the tag GENERATE_DOCSET is set to YES. + +DOCSET_BUNDLE_ID = org.doxygen.Project + +# The DOCSET_PUBLISHER_ID tag specifies a string that should uniquely identify +# the documentation publisher. This should be a reverse domain-name style +# string, e.g. com.mycompany.MyDocSet.documentation. +# The default value is: org.doxygen.Publisher. +# This tag requires that the tag GENERATE_DOCSET is set to YES. + +DOCSET_PUBLISHER_ID = org.doxygen.Publisher + +# The DOCSET_PUBLISHER_NAME tag identifies the documentation publisher. +# The default value is: Publisher. +# This tag requires that the tag GENERATE_DOCSET is set to YES. + +DOCSET_PUBLISHER_NAME = Publisher + +# If the GENERATE_HTMLHELP tag is set to YES then doxygen generates three +# additional HTML index files: index.hhp, index.hhc, and index.hhk. The +# index.hhp is a project file that can be read by Microsoft's HTML Help Workshop +# (see: http://www.microsoft.com/en-us/download/details.aspx?id=21138) on +# Windows. +# +# The HTML Help Workshop contains a compiler that can convert all HTML output +# generated by doxygen into a single compiled HTML file (.chm). Compiled HTML +# files are now used as the Windows 98 help format, and will replace the old +# Windows help format (.hlp) on all Windows platforms in the future. Compressed +# HTML files also contain an index, a table of contents, and you can search for +# words in the documentation. The HTML workshop also contains a viewer for +# compressed HTML files. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +GENERATE_HTMLHELP = NO + +# The CHM_FILE tag can be used to specify the file name of the resulting .chm +# file. You can add a path in front of the file if the result should not be +# written to the html output directory. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +CHM_FILE = + +# The HHC_LOCATION tag can be used to specify the location (absolute path +# including file name) of the HTML help compiler (hhc.exe). If non-empty, +# doxygen will try to run the HTML help compiler on the generated index.hhp. +# The file has to be specified with full path. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +HHC_LOCATION = + +# The GENERATE_CHI flag controls if a separate .chi index file is generated +# (YES) or that it should be included in the master .chm file (NO). +# The default value is: NO. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +GENERATE_CHI = NO + +# The CHM_INDEX_ENCODING is used to encode HtmlHelp index (hhk), content (hhc) +# and project file content. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +CHM_INDEX_ENCODING = + +# The BINARY_TOC flag controls whether a binary table of contents is generated +# (YES) or a normal table of contents (NO) in the .chm file. Furthermore it +# enables the Previous and Next buttons. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +BINARY_TOC = NO + +# The TOC_EXPAND flag can be set to YES to add extra items for group members to +# the table of contents of the HTML help documentation and to the tree view. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +TOC_EXPAND = NO + +# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and +# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated that +# can be used as input for Qt's qhelpgenerator to generate a Qt Compressed Help +# (.qch) of the generated HTML documentation. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +GENERATE_QHP = NO + +# If the QHG_LOCATION tag is specified, the QCH_FILE tag can be used to specify +# the file name of the resulting .qch file. The path specified is relative to +# the HTML output folder. +# This tag requires that the tag GENERATE_QHP is set to YES. + +QCH_FILE = + +# The QHP_NAMESPACE tag specifies the namespace to use when generating Qt Help +# Project output. For more information please see Qt Help Project / Namespace +# (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#namespace). +# The default value is: org.doxygen.Project. +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHP_NAMESPACE = org.doxygen.Project + +# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating Qt +# Help Project output. For more information please see Qt Help Project / Virtual +# Folders (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#virtual- +# folders). +# The default value is: doc. +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHP_VIRTUAL_FOLDER = doc + +# If the QHP_CUST_FILTER_NAME tag is set, it specifies the name of a custom +# filter to add. For more information please see Qt Help Project / Custom +# Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom- +# filters). +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHP_CUST_FILTER_NAME = + +# The QHP_CUST_FILTER_ATTRS tag specifies the list of the attributes of the +# custom filter to add. For more information please see Qt Help Project / Custom +# Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom- +# filters). +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHP_CUST_FILTER_ATTRS = + +# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this +# project's filter section matches. Qt Help Project / Filter Attributes (see: +# http://qt-project.org/doc/qt-4.8/qthelpproject.html#filter-attributes). +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHP_SECT_FILTER_ATTRS = + +# The QHG_LOCATION tag can be used to specify the location of Qt's +# qhelpgenerator. If non-empty doxygen will try to run qhelpgenerator on the +# generated .qhp file. +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHG_LOCATION = + +# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files will be +# generated, together with the HTML files, they form an Eclipse help plugin. To +# install this plugin and make it available under the help contents menu in +# Eclipse, the contents of the directory containing the HTML and XML files needs +# to be copied into the plugins directory of eclipse. The name of the directory +# within the plugins directory should be the same as the ECLIPSE_DOC_ID value. +# After copying Eclipse needs to be restarted before the help appears. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +GENERATE_ECLIPSEHELP = NO + +# A unique identifier for the Eclipse help plugin. When installing the plugin +# the directory name containing the HTML and XML files should also have this +# name. Each documentation set should have its own identifier. +# The default value is: org.doxygen.Project. +# This tag requires that the tag GENERATE_ECLIPSEHELP is set to YES. + +ECLIPSE_DOC_ID = org.doxygen.Project + +# If you want full control over the layout of the generated HTML pages it might +# be necessary to disable the index and replace it with your own. The +# DISABLE_INDEX tag can be used to turn on/off the condensed index (tabs) at top +# of each HTML page. A value of NO enables the index and the value YES disables +# it. Since the tabs in the index contain the same information as the navigation +# tree, you can set this option to YES if you also set GENERATE_TREEVIEW to YES. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +DISABLE_INDEX = NO + +# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index +# structure should be generated to display hierarchical information. If the tag +# value is set to YES, a side panel will be generated containing a tree-like +# index structure (just like the one that is generated for HTML Help). For this +# to work a browser that supports JavaScript, DHTML, CSS and frames is required +# (i.e. any modern browser). Windows users are probably better off using the +# HTML help feature. Via custom style sheets (see HTML_EXTRA_STYLESHEET) one can +# further fine-tune the look of the index. As an example, the default style +# sheet generated by doxygen has an example that shows how to put an image at +# the root of the tree instead of the PROJECT_NAME. Since the tree basically has +# the same information as the tab index, you could consider setting +# DISABLE_INDEX to YES when enabling this option. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +GENERATE_TREEVIEW = NO + +# The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values that +# doxygen will group on one line in the generated HTML documentation. +# +# Note that a value of 0 will completely suppress the enum values from appearing +# in the overview section. +# Minimum value: 0, maximum value: 20, default value: 4. +# This tag requires that the tag GENERATE_HTML is set to YES. + +ENUM_VALUES_PER_LINE = 4 + +# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be used +# to set the initial width (in pixels) of the frame in which the tree is shown. +# Minimum value: 0, maximum value: 1500, default value: 250. +# This tag requires that the tag GENERATE_HTML is set to YES. + +TREEVIEW_WIDTH = 250 + +# If the EXT_LINKS_IN_WINDOW option is set to YES, doxygen will open links to +# external symbols imported via tag files in a separate window. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +EXT_LINKS_IN_WINDOW = NO + +# Use this tag to change the font size of LaTeX formulas included as images in +# the HTML documentation. When you change the font size after a successful +# doxygen run you need to manually remove any form_*.png images from the HTML +# output directory to force them to be regenerated. +# Minimum value: 8, maximum value: 50, default value: 10. +# This tag requires that the tag GENERATE_HTML is set to YES. + +FORMULA_FONTSIZE = 10 + +# Use the FORMULA_TRANPARENT tag to determine whether or not the images +# generated for formulas are transparent PNGs. Transparent PNGs are not +# supported properly for IE 6.0, but are supported on all modern browsers. +# +# Note that when changing this option you need to delete any form_*.png files in +# the HTML output directory before the changes have effect. +# The default value is: YES. +# This tag requires that the tag GENERATE_HTML is set to YES. + +FORMULA_TRANSPARENT = YES + +# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax (see +# http://www.mathjax.org) which uses client side Javascript for the rendering +# instead of using pre-rendered bitmaps. Use this if you do not have LaTeX +# installed or if you want to formulas look prettier in the HTML output. When +# enabled you may also need to install MathJax separately and configure the path +# to it using the MATHJAX_RELPATH option. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +USE_MATHJAX = NO + +# When MathJax is enabled you can set the default output format to be used for +# the MathJax output. See the MathJax site (see: +# http://docs.mathjax.org/en/latest/output.html) for more details. +# Possible values are: HTML-CSS (which is slower, but has the best +# compatibility), NativeMML (i.e. MathML) and SVG. +# The default value is: HTML-CSS. +# This tag requires that the tag USE_MATHJAX is set to YES. + +MATHJAX_FORMAT = HTML-CSS + +# When MathJax is enabled you need to specify the location relative to the HTML +# output directory using the MATHJAX_RELPATH option. The destination directory +# should contain the MathJax.js script. For instance, if the mathjax directory +# is located at the same level as the HTML output directory, then +# MATHJAX_RELPATH should be ../mathjax. The default value points to the MathJax +# Content Delivery Network so you can quickly see the result without installing +# MathJax. However, it is strongly recommended to install a local copy of +# MathJax from http://www.mathjax.org before deployment. +# The default value is: http://cdn.mathjax.org/mathjax/latest. +# This tag requires that the tag USE_MATHJAX is set to YES. + +MATHJAX_RELPATH = http://cdn.mathjax.org/mathjax/latest + +# The MATHJAX_EXTENSIONS tag can be used to specify one or more MathJax +# extension names that should be enabled during MathJax rendering. For example +# MATHJAX_EXTENSIONS = TeX/AMSmath TeX/AMSsymbols +# This tag requires that the tag USE_MATHJAX is set to YES. + +MATHJAX_EXTENSIONS = + +# The MATHJAX_CODEFILE tag can be used to specify a file with javascript pieces +# of code that will be used on startup of the MathJax code. See the MathJax site +# (see: http://docs.mathjax.org/en/latest/output.html) for more details. For an +# example see the documentation. +# This tag requires that the tag USE_MATHJAX is set to YES. + +MATHJAX_CODEFILE = + +# When the SEARCHENGINE tag is enabled doxygen will generate a search box for +# the HTML output. The underlying search engine uses javascript and DHTML and +# should work on any modern browser. Note that when using HTML help +# (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets (GENERATE_DOCSET) +# there is already a search function so this one should typically be disabled. +# For large projects the javascript based search engine can be slow, then +# enabling SERVER_BASED_SEARCH may provide a better solution. It is possible to +# search using the keyboard; to jump to the search box use + S +# (what the is depends on the OS and browser, but it is typically +# , /