diff options
| -rw-r--r-- | mrbgems/default.gembox | 3 | ||||
| -rw-r--r-- | mrbgems/mruby-bin-mirb/tools/mirb/mirb.c | 7 | ||||
| -rw-r--r-- | mrbgems/mruby-compar-ext/mrbgem.rake | 5 | ||||
| -rw-r--r-- | mrbgems/mruby-compar-ext/mrblib/compar.rb | 31 | ||||
| -rw-r--r-- | mrbgems/mruby-compiler/core/parse.y | 6 | ||||
| -rw-r--r-- | mrbgems/mruby-enum-ext/mrblib/enum.rb | 16 | ||||
| -rw-r--r-- | mrbgems/mruby-enum-lazy/mrblib/lazy.rb | 15 | ||||
| -rw-r--r-- | mrbgems/mruby-kernel-ext/mrblib/kernel.rb | 13 | ||||
| -rw-r--r-- | mrbgems/mruby-string-ext/mrblib/string.rb | 15 | ||||
| -rw-r--r-- | mrbgems/mruby-string-ext/src/string.c | 120 | ||||
| -rw-r--r-- | mrbgems/mruby-string-ext/test/string.rb | 15 | ||||
| -rw-r--r-- | mrbgems/mruby-struct/src/struct.c | 39 | ||||
| -rw-r--r-- | mrbgems/mruby-symbol-ext/mrblib/symbol.rb | 15 | ||||
| -rw-r--r-- | src/numeric.c | 16 | ||||
| -rw-r--r-- | src/variable.c | 9 | ||||
| -rw-r--r-- | tasks/mrbgems.rake | 10 |
16 files changed, 303 insertions, 32 deletions
diff --git a/mrbgems/default.gembox b/mrbgems/default.gembox index 64f05de10..65584681d 100644 --- a/mrbgems/default.gembox +++ b/mrbgems/default.gembox @@ -14,6 +14,9 @@ MRuby::GemBox.new do |conf| # Use standard Struct class conf.gem :core => "mruby-struct" + # Use Comparable module extension + conf.gem :core => "mruby-compar-ext" + # Use Enumerable module extension conf.gem :core => "mruby-enum-ext" diff --git a/mrbgems/mruby-bin-mirb/tools/mirb/mirb.c b/mrbgems/mruby-bin-mirb/tools/mirb/mirb.c index fe311d830..891259a3f 100644 --- a/mrbgems/mruby-bin-mirb/tools/mirb/mirb.c +++ b/mrbgems/mruby-bin-mirb/tools/mirb/mirb.c @@ -544,6 +544,13 @@ done: if (args.verbose) { mrb_codedump_all(mrb, proc); } + /* adjest stack length of toplevel environment */ + if (mrb->c->cibase->env) { + struct REnv *e = mrb->c->cibase->env; + if (MRB_ENV_STACK_LEN(e) < proc->body.irep->nlocals) { + MRB_SET_ENV_STACK_LEN(e, proc->body.irep->nlocals); + } + } /* pass a proc for evaluation */ /* evaluate the bytecode */ result = mrb_vm_run(mrb, diff --git a/mrbgems/mruby-compar-ext/mrbgem.rake b/mrbgems/mruby-compar-ext/mrbgem.rake new file mode 100644 index 000000000..dcf584339 --- /dev/null +++ b/mrbgems/mruby-compar-ext/mrbgem.rake @@ -0,0 +1,5 @@ +MRuby::Gem::Specification.new('mruby-compar-ext') do |spec| + spec.license = 'MIT' + spec.author = 'mruby developers' + spec.summary = 'Enumerable module extension' +end diff --git a/mrbgems/mruby-compar-ext/mrblib/compar.rb b/mrbgems/mruby-compar-ext/mrblib/compar.rb new file mode 100644 index 000000000..d66f816ef --- /dev/null +++ b/mrbgems/mruby-compar-ext/mrblib/compar.rb @@ -0,0 +1,31 @@ +module Comparable + ## + # Returns <i>min</i> if <i>obj</i> <code><=></code> <i>min</i> is less + # than zero, <i>max</i> if <i>obj</i> <code><=></code> <i>max</i> is + # greater than zero and <i>obj</i> otherwise. + # + # 12.clamp(0, 100) #=> 12 + # 523.clamp(0, 100) #=> 100 + # -3.123.clamp(0, 100) #=> 0 + # + # 'd'.clamp('a', 'f') #=> 'd' + # 'z'.clamp('a', 'f') #=> 'f' + # + def clamp(min, max) + if (min <=> max) > 0 + raise ArgumentError, "min argument must be smaller than max argument" + end + c = self <=> min + if c == 0 + return self + elsif c < 0 + return min + end + c = self <=> max + if c > 0 + return max + else + return self + end + end +end diff --git a/mrbgems/mruby-compiler/core/parse.y b/mrbgems/mruby-compiler/core/parse.y index 82e4c7bdd..bf9d3fe85 100644 --- a/mrbgems/mruby-compiler/core/parse.y +++ b/mrbgems/mruby-compiler/core/parse.y @@ -2577,7 +2577,7 @@ do_block : keyword_do_block local_nest(p); } opt_block_param - compstmt + bodystmt keyword_end { $$ = new_block(p,$3,$4); @@ -2667,7 +2667,7 @@ brace_block : '{' $<num>$ = p->lineno; } opt_block_param - compstmt keyword_end + bodystmt keyword_end { $$ = new_block(p,$3,$4); SET_LINENO($$, $<num>2); @@ -5723,7 +5723,7 @@ mrb_parser_set_filename(struct mrb_parser_state *p, const char *f) new_table = (mrb_sym*)parser_palloc(p, sizeof(mrb_sym) * p->filename_table_length); if (p->filename_table) { - memmove(new_table, p->filename_table, sizeof(mrb_sym) * p->filename_table_length); + memmove(new_table, p->filename_table, sizeof(mrb_sym) * p->current_filename_index); } p->filename_table = new_table; p->filename_table[p->filename_table_length - 1] = sym; diff --git a/mrbgems/mruby-enum-ext/mrblib/enum.rb b/mrbgems/mruby-enum-ext/mrblib/enum.rb index 7741e515d..327b573d4 100644 --- a/mrbgems/mruby-enum-ext/mrblib/enum.rb +++ b/mrbgems/mruby-enum-ext/mrblib/enum.rb @@ -708,4 +708,20 @@ module Enumerable def nil.to_h {} end + + def uniq(&block) + hash = {} + if block + self.each do|*v| + v = v.__svalue + hash[block.call(v)] ||= v + end + else + self.each do|*v| + v = v.__svalue + hash[v] ||= v + end + end + hash.values + end end diff --git a/mrbgems/mruby-enum-lazy/mrblib/lazy.rb b/mrbgems/mruby-enum-lazy/mrblib/lazy.rb index c98681edf..9227abe8a 100644 --- a/mrbgems/mruby-enum-lazy/mrblib/lazy.rb +++ b/mrbgems/mruby-enum-lazy/mrblib/lazy.rb @@ -158,6 +158,21 @@ class Enumerator } end + def uniq(&block) + hash = {} + Lazy.new(self){|yielder, val| + if block + v = block.call(val) + else + v = val + end + unless hash.include?(v) + yielder << val + hash[v] = val + end + } + end + alias force to_a end end diff --git a/mrbgems/mruby-kernel-ext/mrblib/kernel.rb b/mrbgems/mruby-kernel-ext/mrblib/kernel.rb new file mode 100644 index 000000000..25a4d4ed4 --- /dev/null +++ b/mrbgems/mruby-kernel-ext/mrblib/kernel.rb @@ -0,0 +1,13 @@ +module Kernel + # call-seq: + # obj.yield_self {|_obj|...} -> an_object + # + # Yields <i>obj</i> 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 +end diff --git a/mrbgems/mruby-string-ext/mrblib/string.rb b/mrbgems/mruby-string-ext/mrblib/string.rb index c3a7eb380..cb36d9a48 100644 --- a/mrbgems/mruby-string-ext/mrblib/string.rb +++ b/mrbgems/mruby-string-ext/mrblib/string.rb @@ -144,7 +144,20 @@ class String def casecmp(str) self.downcase <=> str.to_str.downcase rescue NoMethodError - raise TypeError, "no implicit conversion of #{str.class} into String" + nil + end + + ## + # call-seq: + # str.casecmp?(other) -> true, false, or nil + # + # Returns true if str and other_str are equal after case folding, + # false if they are not equal, and nil if other_str is not a string. + + def casecmp?(str) + c = self.casecmp(str) + return nil if c.nil? + return c == 0 end def partition(sep) diff --git a/mrbgems/mruby-string-ext/src/string.c b/mrbgems/mruby-string-ext/src/string.c index 63f181749..612fc5335 100644 --- a/mrbgems/mruby-string-ext/src/string.c +++ b/mrbgems/mruby-string-ext/src/string.c @@ -650,6 +650,118 @@ mrb_str_upto(mrb_state *mrb, mrb_value beg) return beg; } +/* + * call-seq: + * str.delete_prefix!(prefix) -> self or nil + * + * Deletes leading <code>prefix</code> from <i>str</i>, returning + * <code>nil</code> if no change was made. + * + * "hello".delete_prefix!("hel") #=> "lo" + * "hello".delete_prefix!("llo") #=> nil + */ +static mrb_value +mrb_str_del_prefix_bang(mrb_state *mrb, mrb_value self) +{ + mrb_int plen, slen; + char *ptr, *s; + struct RString *str = RSTRING(self); + + mrb_get_args(mrb, "s", &ptr, &plen); + slen = RSTR_LEN(str); + if (plen > slen) return mrb_nil_value(); + s = RSTR_PTR(str); + if (memcmp(s, ptr, plen) != 0) return mrb_nil_value(); + if (!MRB_FROZEN_P(str) && (RSTR_SHARED_P(str) || RSTR_FSHARED_P(str))) { + str->as.heap.ptr += plen; + } + else { + mrb_str_modify(mrb, str); + s = RSTR_PTR(str); + memmove(s, s+plen, slen-plen); + } + RSTR_SET_LEN(str, slen-plen); + return self; +} + +/* + * call-seq: + * str.delete_prefix(prefix) -> new_str + * + * Returns a copy of <i>str</i> with leading <code>prefix</code> deleted. + * + * "hello".delete_prefix("hel") #=> "lo" + * "hello".delete_prefix("llo") #=> "hello" + */ +static mrb_value +mrb_str_del_prefix(mrb_state *mrb, mrb_value self) +{ + mrb_int plen, slen; + char *ptr; + + mrb_get_args(mrb, "s", &ptr, &plen); + slen = RSTRING_LEN(self); + if (plen > slen) return mrb_str_dup(mrb, self); + if (memcmp(RSTRING_PTR(self), ptr, plen) != 0) + return mrb_str_dup(mrb, self); + return mrb_str_substr(mrb, self, plen, slen-plen); +} + +/* + * call-seq: + * str.delete_suffix!(suffix) -> self or nil + * + * Deletes trailing <code>suffix</code> from <i>str</i>, returning + * <code>nil</code> if no change was made. + * + * "hello".delete_suffix!("llo") #=> "he" + * "hello".delete_suffix!("hel") #=> nil + */ +static mrb_value +mrb_str_del_suffix_bang(mrb_state *mrb, mrb_value self) +{ + mrb_int plen, slen; + char *ptr, *s; + struct RString *str = RSTRING(self); + + mrb_get_args(mrb, "s", &ptr, &plen); + slen = RSTR_LEN(str); + if (plen > slen) return mrb_nil_value(); + s = RSTR_PTR(str); + if (memcmp(s+slen-plen, ptr, plen) != 0) return mrb_nil_value(); + if (!MRB_FROZEN_P(str) && (RSTR_SHARED_P(str) || RSTR_FSHARED_P(str))) { + /* no need to modify string */ + } + else { + mrb_str_modify(mrb, str); + } + RSTR_SET_LEN(str, slen-plen); + return self; +} + +/* + * call-seq: + * str.delete_suffix(suffix) -> new_str + * + * Returns a copy of <i>str</i> with leading <code>suffix</code> deleted. + * + * "hello".delete_suffix("hel") #=> "lo" + * "hello".delete_suffix("llo") #=> "hello" + */ +static mrb_value +mrb_str_del_suffix(mrb_state *mrb, mrb_value self) +{ + mrb_int plen, slen; + char *ptr; + + mrb_get_args(mrb, "s", &ptr, &plen); + slen = RSTRING_LEN(self); + if (plen > slen) return mrb_str_dup(mrb, self); + if (memcmp(RSTRING_PTR(self)+slen-plen, ptr, plen) != 0) + return mrb_str_dup(mrb, self); + return mrb_str_substr(mrb, self, 0, slen-plen); +} + void mrb_mruby_string_ext_gem_init(mrb_state* mrb) { @@ -673,8 +785,12 @@ mrb_mruby_string_ext_gem_init(mrb_state* mrb) mrb_define_method(mrb, s, "succ!", mrb_str_succ_bang, MRB_ARGS_NONE()); mrb_alias_method(mrb, s, mrb_intern_lit(mrb, "next"), mrb_intern_lit(mrb, "succ")); mrb_alias_method(mrb, s, mrb_intern_lit(mrb, "next!"), mrb_intern_lit(mrb, "succ!")); - mrb_define_method(mrb, s, "ord", mrb_str_ord, MRB_ARGS_NONE()); - mrb_define_method(mrb, s, "upto", mrb_str_upto, MRB_ARGS_ANY()); + mrb_define_method(mrb, s, "ord", mrb_str_ord, MRB_ARGS_NONE()); + mrb_define_method(mrb, s, "upto", mrb_str_upto, MRB_ARGS_ANY()); + mrb_define_method(mrb, s, "delete_prefix!", mrb_str_del_prefix_bang, MRB_ARGS_REQ(1)); + mrb_define_method(mrb, s, "delete_prefix", mrb_str_del_prefix, MRB_ARGS_REQ(1)); + mrb_define_method(mrb, s, "delete_suffix!", mrb_str_del_suffix_bang, MRB_ARGS_REQ(1)); + mrb_define_method(mrb, s, "delete_suffix", mrb_str_del_suffix, MRB_ARGS_REQ(1)); mrb_define_method(mrb, mrb->fixnum_class, "chr", mrb_fixnum_chr, MRB_ARGS_NONE()); } diff --git a/mrbgems/mruby-string-ext/test/string.rb b/mrbgems/mruby-string-ext/test/string.rb index 2a568c7d6..b6146fb90 100644 --- a/mrbgems/mruby-string-ext/test/string.rb +++ b/mrbgems/mruby-string-ext/test/string.rb @@ -1,3 +1,4 @@ +# coding: utf-8 ## # String(Ext) Test @@ -665,3 +666,17 @@ assert('String#each_codepoint(UTF-8)') do end assert_equal expect, cp end if UTF8STRING + +assert('String#delete_prefix') do + assert_equal "llo", "hello".delete_prefix("he") + assert_equal "hello", "hello".delete_prefix("llo") + assert_equal "llo", "hello".delete_prefix!("he") + assert_nil "hello".delete_prefix!("llo") +end + +assert('String#delete_suffix') do + assert_equal "he", "hello".delete_suffix("llo") + assert_equal "hello", "hello".delete_suffix("he") + assert_equal "he", "hello".delete_suffix!("llo") + assert_nil "hello".delete_suffix!("he") +end diff --git a/mrbgems/mruby-struct/src/struct.c b/mrbgems/mruby-struct/src/struct.c index 67762a948..fed9e8105 100644 --- a/mrbgems/mruby-struct/src/struct.c +++ b/mrbgems/mruby-struct/src/struct.c @@ -12,6 +12,7 @@ #include <mruby/variable.h> #include <mruby/hash.h> #include <mruby/range.h> +#include <mruby/proc.h> #define RSTRUCT_LEN(st) RARRAY_LEN(st) #define RSTRUCT_PTR(st) RARRAY_PTR(st) @@ -113,12 +114,14 @@ mrb_struct_members(mrb_state *mrb, mrb_value obj) return mrb_struct_s_members_m(mrb, mrb_obj_value(mrb_obj_class(mrb, obj))); } -static mrb_value struct_aref_sym(mrb_state *mrb, mrb_value obj, mrb_sym id); - static mrb_value mrb_struct_ref(mrb_state *mrb, mrb_value obj) { - return struct_aref_sym(mrb, obj, mrb->c->ci->mid); + mrb_int i = mrb_fixnum(mrb_proc_cfunc_env_get(mrb, 0)); + mrb_value *ptr = RSTRUCT_PTR(obj); + + if (!ptr) return mrb_nil_value(); + return ptr[i]; } static mrb_sym @@ -140,24 +143,23 @@ mrb_id_attrset(mrb_state *mrb, mrb_sym id) return mid; } -static mrb_value mrb_struct_aset_sym(mrb_state *mrb, mrb_value s, mrb_sym id, mrb_value val); - static mrb_value mrb_struct_set_m(mrb_state *mrb, mrb_value obj) { + mrb_int i = mrb_fixnum(mrb_proc_cfunc_env_get(mrb, 0)); + mrb_value *ptr; mrb_value val; - const char *name; - mrb_int slen; - mrb_sym mid; - mrb_get_args(mrb, "o", &val); - - /* get base id */ - name = mrb_sym2name_len(mrb, mrb->c->ci->mid, &slen); - mid = mrb_intern(mrb, name, slen-1); /* omit last "=" */ - - return mrb_struct_aset_sym(mrb, obj, mid, val); + mrb_struct_modify(mrb, obj); + ptr = RSTRUCT_PTR(obj); + if (ptr == NULL || i >= RSTRUCT_LEN(obj)) { + mrb_ary_set(mrb, obj, i, val); + } + else { + ptr[i] = val; + } + return val; } static mrb_bool @@ -187,8 +189,11 @@ make_struct_define_accessors(mrb_state *mrb, mrb_value members, struct RClass *c const char *name = mrb_sym2name_len(mrb, id, NULL); if (is_local_id(mrb, name) || is_const_id(mrb, name)) { - mrb_define_method_id(mrb, c, id, mrb_struct_ref, MRB_ARGS_NONE()); - mrb_define_method_id(mrb, c, mrb_id_attrset(mrb, id), mrb_struct_set_m, MRB_ARGS_REQ(1)); + mrb_value at = mrb_fixnum_value(i); + struct RProc *aref = mrb_proc_new_cfunc_with_env(mrb, mrb_struct_ref, 1, &at); + struct RProc *aset = mrb_proc_new_cfunc_with_env(mrb, mrb_struct_set_m, 1, &at); + mrb_define_method_raw(mrb, c, id, aref); + mrb_define_method_raw(mrb, c, mrb_id_attrset(mrb, id), aset); mrb_gc_arena_restore(mrb, ai); } } diff --git a/mrbgems/mruby-symbol-ext/mrblib/symbol.rb b/mrbgems/mruby-symbol-ext/mrblib/symbol.rb index 1e3d24b80..28cce3156 100644 --- a/mrbgems/mruby-symbol-ext/mrblib/symbol.rb +++ b/mrbgems/mruby-symbol-ext/mrblib/symbol.rb @@ -48,10 +48,23 @@ class Symbol def casecmp(other) return nil unless other.kind_of?(Symbol) lhs = self.to_s; lhs.upcase! - rhs = other.to_s; rhs.upcase! + rhs = other.to_s.upcase lhs <=> rhs end + ## + # call-seq: + # sym.casecmp?(other) -> true, false, or nil + # + # Returns true if sym and other_sym are equal after case folding, + # false if they are not equal, and nil if other_sym is not a string. + + def casecmp?(sym) + c = self.casecmp(sym) + return nil if c.nil? + return c == 0 + end + # # call-seq: # sym.empty? -> true or false diff --git a/src/numeric.c b/src/numeric.c index 8c7d448bd..b381bd206 100644 --- a/src/numeric.c +++ b/src/numeric.c @@ -1254,6 +1254,20 @@ num_cmp(mrb_state *mrb, mrb_value self) } } +static mrb_value +num_finite_p(mrb_state *mrb, mrb_value self) +{ + mrb_get_args(mrb, ""); + return mrb_true_value(); +} + +static mrb_value +num_infinite_p(mrb_state *mrb, mrb_value self) +{ + mrb_get_args(mrb, ""); + return mrb_false_value(); +} + /* 15.2.9.3.1 */ /* * call-seq: @@ -1284,6 +1298,8 @@ mrb_init_numeric(mrb_state *mrb) 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, "<=>", num_cmp, MRB_ARGS_REQ(1)); /* 15.2.9.3.6 */ + mrb_define_method(mrb, numeric, "finite?", num_finite_p, MRB_ARGS_NONE()); + mrb_define_method(mrb, numeric, "infinite?",num_infinite_p, MRB_ARGS_NONE()); /* Integer Class */ integer = mrb_define_class(mrb, "Integer", numeric); /* 15.2.8 */ diff --git a/src/variable.c b/src/variable.c index 50fc70682..4fbe82dd9 100644 --- a/src/variable.c +++ b/src/variable.c @@ -663,17 +663,18 @@ mod_const_check(mrb_state *mrb, mrb_value mod) } static mrb_value -const_get(mrb_state *mrb, struct RClass *base, mrb_sym sym) +const_get(mrb_state *mrb, struct RClass *base, mrb_sym sym, mrb_bool top) { struct RClass *c = base; mrb_value v; iv_tbl *t; mrb_bool retry = FALSE; mrb_value name; + struct RClass *oclass = mrb->object_class; L_RETRY: while (c) { - if (c->iv) { + if (c->iv && (top || c != oclass || base == oclass)) { t = c->iv; if (iv_get(mrb, t, sym, &v)) return v; @@ -693,7 +694,7 @@ MRB_API mrb_value mrb_const_get(mrb_state *mrb, mrb_value mod, mrb_sym sym) { mod_const_check(mrb, mod); - return const_get(mrb, mrb_class_ptr(mod), sym); + return const_get(mrb, mrb_class_ptr(mod), sym, FALSE); } mrb_value @@ -729,7 +730,7 @@ mrb_vm_const_get(mrb_state *mrb, mrb_sym sym) } irep = irep->outer; } - return const_get(mrb, c, sym); + return const_get(mrb, c, sym, TRUE); } MRB_API void diff --git a/tasks/mrbgems.rake b/tasks/mrbgems.rake index 65368c303..1b964524c 100644 --- a/tasks/mrbgems.rake +++ b/tasks/mrbgems.rake @@ -34,11 +34,13 @@ MRuby.each_target do f.puts %Q[#include <mruby.h>] f.puts %Q[] f.write gem_func_decls + unless gem_final_calls.empty? f.puts %Q[] - f.puts %Q[static void] - f.puts %Q[mrb_final_mrbgems(mrb_state *mrb) {] - f.write gem_final_calls - f.puts %Q[}] + f.puts %Q[static void] + f.puts %Q[mrb_final_mrbgems(mrb_state *mrb) {] + f.write gem_final_calls + f.puts %Q[}] + end f.puts %Q[] f.puts %Q[void] f.puts %Q[mrb_init_mrbgems(mrb_state *mrb) {] |
