summaryrefslogtreecommitdiffhomepage
path: root/mrblib
diff options
context:
space:
mode:
authorYukihiro "Matz" Matsumoto <[email protected]>2019-07-17 10:35:41 +0900
committerGitHub <[email protected]>2019-07-17 10:35:41 +0900
commitd605b72c1d6fa4564a0a5e88535504b6850463b5 (patch)
tree774fc0de56002abb3bb2b1c3387ff08f91876d17 /mrblib
parent2af92d0ebcbeca6d3d85a27c8193273080a63090 (diff)
parent9af3b7c6258de327218dd04e69d76ae68caf17b1 (diff)
downloadmruby-d605b72c1d6fa4564a0a5e88535504b6850463b5.tar.gz
mruby-d605b72c1d6fa4564a0a5e88535504b6850463b5.zip
Merge branch 'master' into i110/inspect-recursion
Diffstat (limited to 'mrblib')
-rw-r--r--mrblib/array.rb105
-rw-r--r--mrblib/enum.rb18
-rw-r--r--mrblib/float.rb9
-rw-r--r--mrblib/hash.rb60
-rw-r--r--mrblib/kernel.rb2
-rw-r--r--mrblib/mrblib.rake5
-rw-r--r--mrblib/numeric.rb12
-rw-r--r--mrblib/range.rb2
-rw-r--r--mrblib/string.rb133
-rw-r--r--mrblib/symbol.rb7
10 files changed, 135 insertions, 218 deletions
diff --git a/mrblib/array.rb b/mrblib/array.rb
index bc9a2a492..2b080564c 100644
--- a/mrblib/array.rb
+++ b/mrblib/array.rb
@@ -66,7 +66,7 @@ class Array
#
# ISO 15.2.12.5.15
def initialize(size=0, obj=nil, &block)
- raise TypeError, "expected Integer for 1st argument" unless size.kind_of? Integer
+ size = size.__to_int
raise ArgumentError, "negative array size" if size < 0
self.clear
@@ -84,10 +84,17 @@ class Array
end
def _inspect(recur_list)
- return "[]" if self.size == 0
+ size = self.size
+ return "[]" if size == 0
return "[...]" if recur_list[self.object_id]
recur_list[self.object_id] = true
- "["+self.map{|x|x._inspect(recur_list)}.join(", ")+"]"
+ ary=[]
+ i=0
+ while i<size
+ ary<<self[i]._inspect(recur_list)
+ i+=1
+ end
+ "["+ary.join(", ")+"]"
end
##
# Return the contents of this array as a string.
@@ -191,43 +198,69 @@ class Array
include Enumerable
##
- # Quick sort
- # left : the beginning of sort region
- # right : the end of sort region
- def __sort_sub__(left, right, &block)
- stack = [ [left, right] ]
+ # Sort all elements and replace +self+ with these
+ # elements.
+ def sort!(&block)
+ stack = [ [ 0, self.size - 1 ] ]
until stack.empty?
- left, right = stack.pop
- if left < right
- i = left
- j = right
- pivot = self[i + (j - i) / 2]
- while true
- while ((block)? block.call(self[i], pivot): (self[i] <=> pivot)) < 0
- i += 1
+ left, mid, right = stack.pop
+ if right == nil
+ right = mid
+ # sort self[left..right]
+ if left < right
+ if left + 1 == right
+ lval = self[left]
+ rval = self[right]
+ cmp = if block then block.call(lval,rval) else lval <=> rval end
+ if cmp.nil?
+ raise ArgumentError, "comparison of #{lval.inspect} and #{rval.inspect} failed"
+ end
+ if cmp > 0
+ self[left] = rval
+ self[right] = lval
+ end
+ else
+ mid = ((left + right + 1) / 2).floor
+ stack.push [ left, mid, right ]
+ stack.push [ mid, right ]
+ stack.push [ left, (mid - 1) ] if left < mid - 1
end
- while ((block)? block.call(pivot, self[j]): (pivot <=> self[j])) < 0
- j -= 1
- end
- break if (i >= j)
- tmp = self[i]; self[i] = self[j]; self[j] = tmp;
- i += 1
- j -= 1
end
- stack.push [left, i-1]
- stack.push [j+1, right]
- end
- end
- end
- # private :__sort_sub__
+ else
+ lary = self[left, mid - left]
+ lsize = lary.size
- ##
- # Sort all elements and replace +self+ with these
- # elements.
- def sort!(&block)
- size = self.size
- if size > 1
- __sort_sub__(0, size - 1, &block)
+ # The entity sharing between lary and self may cause a large memory
+ # copy operation in the merge loop below. This harmless operation
+ # cancels the sharing and provides a huge performance gain.
+ lary[0] = lary[0]
+
+ # merge
+ lidx = 0
+ ridx = mid
+ (left..right).each { |i|
+ if lidx >= lsize
+ break
+ elsif ridx > right
+ self[i, lsize - lidx] = lary[lidx, lsize - lidx]
+ break
+ else
+ lval = lary[lidx]
+ rval = self[ridx]
+ cmp = if block then block.call(lval,rval) else lval <=> rval end
+ if cmp.nil?
+ raise ArgumentError, "comparison of #{lval.inspect} and #{rval.inspect} failed"
+ end
+ if cmp <= 0
+ self[i] = lval
+ lidx += 1
+ else
+ self[i] = rval
+ ridx += 1
+ end
+ end
+ }
+ end
end
self
end
diff --git a/mrblib/enum.rb b/mrblib/enum.rb
index a97a26f97..fe40b4d27 100644
--- a/mrblib/enum.rb
+++ b/mrblib/enum.rb
@@ -13,6 +13,8 @@
# @ISO 15.3.2
module Enumerable
+ NONE = Object.new
+
##
# Call the given block for each element
# which is yield by +each+. Return false
@@ -63,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/mrblib/float.rb b/mrblib/float.rb
deleted file mode 100644
index 2b86dc1e5..000000000
--- a/mrblib/float.rb
+++ /dev/null
@@ -1,9 +0,0 @@
-##
-# Float
-#
-# ISO 15.2.9
-class Float
- # mruby special - since mruby integers may be upgraded to floats,
- # floats should be compatible to integers.
- include Integral
-end if class_defined?("Float")
diff --git a/mrblib/hash.rb b/mrblib/hash.rb
index 6fcbba173..0e2da62e1 100644
--- a/mrblib/hash.rb
+++ b/mrblib/hash.rb
@@ -12,9 +12,7 @@ class Hash
# ISO 15.2.13.4.1
def ==(hash)
return true if self.equal?(hash)
- begin
- hash = hash.to_hash
- rescue NoMethodError
+ unless Hash === hash
return false
end
return false if self.size != hash.size
@@ -32,9 +30,7 @@ class Hash
# ISO 15.2.13.4.32 (x)
def eql?(hash)
return true if self.equal?(hash)
- begin
- hash = hash.to_hash
- rescue NoMethodError
+ unless Hash === hash
return false
end
return false if self.size != hash.size
@@ -55,10 +51,9 @@ class Hash
# ISO 15.2.13.4.8
def delete(key, &block)
if block && !self.has_key?(key)
- block.call(key)
- else
- self.__delete(key)
+ return block.call(key)
end
+ self.__delete(key)
end
##
@@ -154,9 +149,8 @@ class Hash
#
# ISO 15.2.13.4.23
def replace(hash)
- raise TypeError, "can't convert argument into Hash" unless hash.respond_to?(:to_hash)
+ raise TypeError, "Hash required (#{hash.class} given)" unless Hash === hash
self.clear
- hash = hash.to_hash
hash.each_key{|k|
self[k] = hash[k]
}
@@ -179,8 +173,7 @@ class Hash
#
# ISO 15.2.13.4.22
def merge(other, &block)
- raise TypeError, "can't convert argument into Hash" unless other.respond_to?(:to_hash)
- other = other.to_hash
+ raise TypeError, "Hash required (#{other.class} given)" unless Hash === other
h = self.dup
if block
other.each_key{|k|
@@ -197,9 +190,16 @@ class Hash
return "{}" if self.size == 0
return "{...}" if recur_list[self.object_id]
recur_list[self.object_id] = true
- "{"+self.map {|k,v|
- k._inspect(recur_list) + "=>" + v._inspect(recur_list)
- }.join(", ")+"}"
+ ary=[]
+ keys=self.keys
+ size=keys.size
+ i=0
+ while i<size
+ k=keys[i]
+ ary<<(k._inspect + "=>" + self[k]._inspect)
+ i+=1
+ end
+ "{"+ary.join(", ")+"}"
end
##
# Return the contents of this hash as a string.
@@ -316,34 +316,6 @@ class Hash
}
h
end
-
- ##
- # call-seq:
- # hsh.rehash -> hsh
- #
- # Rebuilds the hash based on the current hash values for each key. If
- # values of key objects have changed since they were inserted, this
- # method will reindex <i>hsh</i>.
- #
- # h = {"AAA" => "b"}
- # h.keys[0].chop!
- # h #=> {"AA"=>"b"}
- # h["AA"] #=> nil
- # h.rehash #=> {"AA"=>"b"}
- # h["AA"] #=> "b"
- #
- def rehash
- h = {}
- self.each{|k,v|
- h[k] = v
- }
- self.replace(h)
- end
-
- def __update(h)
- h.each_key{|k| self[k] = h[k]}
- self
- end
end
##
diff --git a/mrblib/kernel.rb b/mrblib/kernel.rb
index 3fb324908..7c3ea9420 100644
--- a/mrblib/kernel.rb
+++ b/mrblib/kernel.rb
@@ -6,7 +6,7 @@ module Kernel
# 15.3.1.2.1 Kernel.`
# provided by Kernel#`
- # 15.3.1.3.5
+ # 15.3.1.3.3
def `(s)
raise NotImplementedError.new("backquotes not implemented")
end
diff --git a/mrblib/mrblib.rake b/mrblib/mrblib.rake
index fe4aae1f7..e96decb27 100644
--- a/mrblib/mrblib.rake
+++ b/mrblib/mrblib.rake
@@ -3,14 +3,11 @@ MRuby.each_target do
relative_from_root = File.dirname(__FILE__).relative_path_from(MRUBY_ROOT)
current_build_dir = "#{build_dir}/#{relative_from_root}"
- self.libmruby << objfile("#{current_build_dir}/mrblib")
+ self.libmruby_objs << objfile("#{current_build_dir}/mrblib")
file objfile("#{current_build_dir}/mrblib") => "#{current_build_dir}/mrblib.c"
file "#{current_build_dir}/mrblib.c" => [mrbcfile, __FILE__] + Dir.glob("#{current_dir}/*.rb").sort do |t|
_, _, *rbfiles = t.prerequisites
- if self.cc.defines.flatten.include?("MRB_WITHOUT_FLOAT")
- rbfiles.delete("#{current_dir}/float.rb")
- end
FileUtils.mkdir_p File.dirname(t.name)
open(t.name, 'w') do |f|
_pp "GEN", "*.rb", "#{t.name.relative_path}"
diff --git a/mrblib/numeric.rb b/mrblib/numeric.rb
index 1b11e92ad..5926518d5 100644
--- a/mrblib/numeric.rb
+++ b/mrblib/numeric.rb
@@ -104,15 +104,15 @@ module Integral
raise ArgumentError, "step can't be 0" if step == 0
return to_enum(:step, num, step) unless block
- i = if class_defined?("Float") && num.kind_of?(Float) then self.to_f else self end
- if num == nil
+ i = __coerce_step_counter(num, step)
+ 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
+ i += step
end
- return self
- end
- if step > 0
+ elsif step > 0
while i <= num
block.call(i)
i += step
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
diff --git a/mrblib/string.rb b/mrblib/string.rb
index ee98cfa0c..c26cdb1e2 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.
@@ -12,7 +14,7 @@ class String
def each_line(rs = "\n", &block)
return to_enum(:each_line, rs, &block) unless block
return block.call(self) if rs.nil?
- rs = rs.to_str
+ rs.__to_str
offset = 0
rs_len = rs.length
this = dup
@@ -67,7 +69,7 @@ class String
block = nil
end
if !replace.nil? || !block
- replace = replace.to_str
+ replace.__to_str
end
offset = 0
result = []
@@ -99,22 +101,19 @@ class String
raise FrozenError, "can't modify frozen String" if frozen?
return to_enum(:gsub!, *args) if args.length == 1 && !block
str = self.gsub(*args, &block)
- return nil if str == self
+ return nil unless self.index(args[0])
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
@@ -129,12 +128,12 @@ class String
end
pattern, replace = *args
- pattern = pattern.to_str
+ pattern.__to_str
if args.length == 2 && block
block = nil
end
unless block
- replace = replace.to_str
+ replace.__to_str
end
result = []
this = dup
@@ -161,25 +160,14 @@ class String
def sub!(*args, &block)
raise FrozenError, "can't modify frozen String" if frozen?
str = self.sub(*args, &block)
- return nil if str == self
+ return nil unless self.index(args[0])
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)
+ return to_enum(:each_byte, &block) unless block
bytes = self.bytes
pos = 0
while pos < bytes.size
@@ -189,87 +177,16 @@ 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
- case pos
- when String
- posnum = self.index(pos)
- if posnum
- b = self[0, posnum.to_i]
- 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 += 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]
- a = self[pos + 1..-1]
- self.replace([b, value, a].join(''))
- end
- return value
- elsif anum == 3
- pos, len, value = args
- 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.to_i]
- 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
- def =~(re)
- raise TypeError, "type mismatch: String given" if re.respond_to? :to_str
- re =~ self
- end
+ #def =~(re)
+ # re =~ self
+ #end
##
# ISO 15.2.10.5.27
- def match(re, &block)
- if re.respond_to? :to_str
- 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
- end
-end
-
-##
-# String is comparable
-#
-# ISO 15.2.10.3
-module Comparable; end
-class String
- include Comparable
+ #def match(re, &block)
+ # re.match(self, &block)
+ #end
end
diff --git a/mrblib/symbol.rb b/mrblib/symbol.rb
new file mode 100644
index 000000000..9c981dd9e
--- /dev/null
+++ b/mrblib/symbol.rb
@@ -0,0 +1,7 @@
+class Symbol
+ def to_proc
+ ->(obj,*args,&block) do
+ obj.__send__(self, *args, &block)
+ end
+ end
+end