diff options
| -rw-r--r-- | include/mruby/range.h | 3 | ||||
| -rw-r--r-- | include/mruby/value.h | 5 | ||||
| -rw-r--r-- | mrbgems/mruby-compiler/core/codegen.c | 12 | ||||
| -rw-r--r-- | mrbgems/mruby-compiler/core/parse.y | 56 | ||||
| -rw-r--r-- | mrbgems/mruby-enumerator/mrblib/enumerator.rb | 14 | ||||
| -rw-r--r-- | mrbgems/mruby-enumerator/test/enumerator.rb | 3 | ||||
| -rw-r--r-- | mrbgems/mruby-range-ext/src/range.c | 6 | ||||
| -rw-r--r-- | src/array.c | 11 | ||||
| -rw-r--r-- | src/class.c | 2 | ||||
| -rw-r--r-- | src/object.c | 2 | ||||
| -rw-r--r-- | src/proc.c | 2 | ||||
| -rw-r--r-- | src/range.c | 39 | ||||
| -rw-r--r-- | src/string.c | 242 | ||||
| -rw-r--r-- | src/vm.c | 47 | ||||
| -rw-r--r-- | test/t/codegen.rb | 9 | ||||
| -rw-r--r-- | test/t/kernel.rb | 15 | ||||
| -rw-r--r-- | test/t/nomethoderror.rb | 31 | ||||
| -rw-r--r-- | test/t/proc.rb | 16 |
18 files changed, 441 insertions, 74 deletions
diff --git a/include/mruby/range.h b/include/mruby/range.h index cf42ce133..fb602b3f3 100644 --- a/include/mruby/range.h +++ b/include/mruby/range.h @@ -25,7 +25,8 @@ struct RRange { mrb_bool excl : 1; }; -#define mrb_range_ptr(v) ((struct RRange*)(mrb_ptr(v))) +MRB_API struct RRange* mrb_range_ptr(mrb_state *mrb, mrb_value v); +#define mrb_range_raw_ptr(v) ((struct RRange*)mrb_ptr(v)) #define mrb_range_value(p) mrb_obj_value((void*)(p)) /* diff --git a/include/mruby/value.h b/include/mruby/value.h index 61110e3dd..54d197f8f 100644 --- a/include/mruby/value.h +++ b/include/mruby/value.h @@ -62,12 +62,12 @@ struct mrb_state; # define MRB_PRIx PRIx32 #endif + +MRB_API double mrb_float_read(const char*, char**); #ifdef MRB_USE_FLOAT typedef float mrb_float; -# define str_to_mrb_float(buf) strtof(buf, NULL) #else typedef double mrb_float; -# define str_to_mrb_float(buf) strtod(buf, NULL) #endif #if defined _MSC_VER && _MSC_VER < 1900 @@ -85,7 +85,6 @@ MRB_API int mrb_msvc_snprintf(char *s, size_t n, const char *format, ...); # define isnan _isnan # define isinf(n) (!_finite(n) && !_isnan(n)) # define signbit(n) (_copysign(1.0, (n)) < 0.0) -# define strtof (float)strtod static const unsigned int IEEE754_INFINITY_BITS_SINGLE = 0x7F800000; # define INFINITY (*(float *)&IEEE754_INFINITY_BITS_SINGLE) # define NAN ((float)(INFINITY - INFINITY)) diff --git a/mrbgems/mruby-compiler/core/codegen.c b/mrbgems/mruby-compiler/core/codegen.c index 553baa116..b2cd12225 100644 --- a/mrbgems/mruby-compiler/core/codegen.c +++ b/mrbgems/mruby-compiler/core/codegen.c @@ -1061,7 +1061,9 @@ gen_vmassignment(codegen_scope *s, node *tree, int rhs, int val) n++; } } - push(); + if (!val) { + push(); + } } } @@ -1518,7 +1520,9 @@ codegen(codegen_scope *s, node *tree, int val) genop(s, MKOP_A(OP_LOADNIL, cursp())); if (pos3) dispatch_linked(s, pos3); if (head) pop(); - genop(s, MKOP_AB(OP_MOVE, cursp(), pos)); + if (cursp() != pos) { + genop(s, MKOP_AB(OP_MOVE, cursp(), pos)); + } push(); } else { @@ -2207,7 +2211,7 @@ codegen(codegen_scope *s, node *tree, int val) case NODE_FLOAT: if (val) { char *p = (char*)tree; - mrb_float f = str_to_mrb_float(p); + mrb_float f = mrb_float_read(p, NULL); int off = new_lit(s, mrb_float_value(s->mrb, f)); genop(s, MKOP_ABx(OP_LOADL, cursp(), off)); @@ -2223,7 +2227,7 @@ codegen(codegen_scope *s, node *tree, int val) case NODE_FLOAT: { char *p = (char*)tree; - mrb_float f = str_to_mrb_float(p); + mrb_float f = mrb_float_read(p, NULL); int off = new_lit(s, mrb_float_value(s->mrb, -f)); genop(s, MKOP_ABx(OP_LOADL, cursp(), off)); diff --git a/mrbgems/mruby-compiler/core/parse.y b/mrbgems/mruby-compiler/core/parse.y index bf893fb37..05b948f8e 100644 --- a/mrbgems/mruby-compiler/core/parse.y +++ b/mrbgems/mruby-compiler/core/parse.y @@ -871,6 +871,7 @@ call_with_block(parser_state *p, node *a, node *b) break; case NODE_CALL: case NODE_FCALL: + case NODE_SCALL: n = a->cdr->cdr->cdr; if (!n->car) n->car = cons(0, b); else { @@ -1917,7 +1918,7 @@ aref_args : none $$ = $1; NODE_LINENO($$, $1); } - | args ',' assocs trailer + | args comma assocs trailer { $$ = push($1, new_hash(p, $3)); } @@ -1957,7 +1958,7 @@ opt_call_args : none $$ = cons($1,0); NODE_LINENO($$, $1); } - | args ',' assocs ',' + | args comma assocs ',' { $$ = cons(push($1, new_hash(p, $3)), 0); NODE_LINENO($$, $1); @@ -1984,7 +1985,7 @@ call_args : command $$ = cons(list1(new_hash(p, $1)), $2); NODE_LINENO($$, $1); } - | args ',' assocs opt_block_arg + | args comma assocs opt_block_arg { $$ = cons(push($1, new_hash(p, $3)), $4); NODE_LINENO($$, $1); @@ -2013,7 +2014,7 @@ block_arg : tAMPER arg } ; -opt_block_arg : ',' block_arg +opt_block_arg : comma block_arg { $$ = $2; } @@ -2023,6 +2024,10 @@ opt_block_arg : ',' block_arg } ; +comma : ',' + | ',' heredoc_bodies + ; + args : arg { void_expr_error(p, $1); @@ -2035,34 +2040,24 @@ args : arg $$ = cons(new_splat(p, $2), 0); NODE_LINENO($$, $2); } - | args ',' arg + | args comma arg { void_expr_error(p, $3); $$ = push($1, $3); } - | args ',' tSTAR arg + | args comma tSTAR arg { void_expr_error(p, $4); $$ = push($1, new_splat(p, $4)); } - | args ',' heredoc_bodies arg - { - void_expr_error(p, $4); - $$ = push($1, $4); - } - | args ',' heredoc_bodies tSTAR arg - { - void_expr_error(p, $5); - $$ = push($1, new_splat(p, $5)); - } ; -mrhs : args ',' arg +mrhs : args comma arg { void_expr_error(p, $3); $$ = push($1, $3); } - | args ',' tSTAR arg + | args comma tSTAR arg { void_expr_error(p, $4); $$ = push($1, new_splat(p, $4)); @@ -2786,10 +2781,6 @@ regexp : tREGEXP_BEG tREGEXP heredoc : tHEREDOC_BEG ; -opt_heredoc_bodies : /* none */ - | heredoc_bodies - ; - heredoc_bodies : heredoc_body | heredoc_bodies heredoc_body ; @@ -3311,11 +3302,12 @@ rbracket : opt_nl ']' trailer : /* none */ | nl - | ',' + | comma ; term : ';' {yyerrok;} | nl + | heredoc_body ; nl : '\n' @@ -3323,10 +3315,10 @@ nl : '\n' p->lineno++; p->column = 0; } - opt_heredoc_bodies + ; terms : term - | terms ';' {yyerrok;} + | terms term ; none : /* none */ @@ -4911,7 +4903,7 @@ parser_yylex(parser_state *p) char *endp; errno = 0; - d = strtod(tok(p), &endp); + d = mrb_float_read(tok(p), &endp); if (d == 0 && endp == tok(p)) { yywarning_s(p, "corrupted float value %s", tok(p)); } @@ -6067,7 +6059,17 @@ mrb_parser_dump(mrb_state *mrb, node *tree, int offset) case NODE_FCALL: case NODE_CALL: - printf("NODE_CALL:\n"); + case NODE_SCALL: + switch (nodetype) { + case NODE_FCALL: + printf("NODE_FCALL:\n"); break; + case NODE_CALL: + printf("NODE_CALL(.):\n"); break; + case NODE_SCALL: + printf("NODE_SCALL(&.):\n"); break; + default: + break; + } mrb_parser_dump(mrb, tree->car, offset+1); dump_prefix(tree, offset+1); printf("method='%s' (%d)\n", diff --git a/mrbgems/mruby-enumerator/mrblib/enumerator.rb b/mrbgems/mruby-enumerator/mrblib/enumerator.rb index 1515a7a89..89b66cd45 100644 --- a/mrbgems/mruby-enumerator/mrblib/enumerator.rb +++ b/mrbgems/mruby-enumerator/mrblib/enumerator.rb @@ -153,12 +153,18 @@ class Enumerator # def with_index(offset=0) return to_enum :with_index, offset unless block_given? - raise TypeError, "no implicit conversion of #{offset.class} into Integer" unless offset.respond_to?(:to_int) + offset = if offset.nil? + 0 + elsif offset.respond_to?(:to_int) + offset.to_int + else + raise TypeError, "no implicit conversion of #{offset.class} into Integer" + end - n = offset.to_int - 1 - enumerator_block_call do |i| + n = offset - 1 + enumerator_block_call do |*i| n += 1 - yield [i,n] + yield i.__svalue, n end end diff --git a/mrbgems/mruby-enumerator/test/enumerator.rb b/mrbgems/mruby-enumerator/test/enumerator.rb index 2e45dae4b..e86e874f0 100644 --- a/mrbgems/mruby-enumerator/test/enumerator.rb +++ b/mrbgems/mruby-enumerator/test/enumerator.rb @@ -50,6 +50,9 @@ end assert 'Enumerator#with_index' do assert_equal([[1,0],[2,1],[3,2]], @obj.to_enum(:foo, 1, 2, 3).with_index.to_a) assert_equal([[1,5],[2,6],[3,7]], @obj.to_enum(:foo, 1, 2, 3).with_index(5).to_a) + a = [] + @obj.to_enum(:foo, 1, 2, 3).with_index(10).with_index(20) { |*i| a << i } + assert_equal [[[1, 10], 20], [[2, 11], 21], [[3, 12], 22]], a end assert 'Enumerator#with_index nonnum offset' do diff --git a/mrbgems/mruby-range-ext/src/range.c b/mrbgems/mruby-range-ext/src/range.c index ccb5a9e45..8aa1379b0 100644 --- a/mrbgems/mruby-range-ext/src/range.c +++ b/mrbgems/mruby-range-ext/src/range.c @@ -44,7 +44,7 @@ static mrb_value mrb_range_cover(mrb_state *mrb, mrb_value range) { mrb_value val; - struct RRange *r = mrb_range_ptr(range); + struct RRange *r = mrb_range_ptr(mrb, range); mrb_value beg, end; mrb_get_args(mrb, "o", &val); @@ -87,7 +87,7 @@ mrb_range_last(mrb_state *mrb, mrb_value range) { mrb_value num; mrb_value array; - struct RRange *r = mrb_range_ptr(range); + struct RRange *r = mrb_range_ptr(mrb, range); if (mrb_get_args(mrb, "|o", &num) == 0) { return r->edges->end; @@ -111,7 +111,7 @@ mrb_range_last(mrb_state *mrb, mrb_value range) static mrb_value mrb_range_size(mrb_state *mrb, mrb_value range) { - struct RRange *r = mrb_range_ptr(range); + struct RRange *r = mrb_range_ptr(mrb, range); mrb_value beg, end; mrb_float beg_f, end_f; mrb_bool num_p = TRUE; diff --git a/src/array.c b/src/array.c index 9013492fb..f6599bd5b 100644 --- a/src/array.c +++ b/src/array.c @@ -173,11 +173,13 @@ ary_expand_capa(mrb_state *mrb, struct RArray *a, mrb_int len) capa = ARY_DEFAULT_LEN; } while (capa < len) { - capa *= 2; + if (capa <= ARY_MAX_SIZE / 2) { + capa *= 2; + } else { + capa = ARY_MAX_SIZE; + } } - if (capa > ARY_MAX_SIZE) capa = ARY_MAX_SIZE; /* len <= capa <= ARY_MAX_SIZE */ - if (capa > a->aux.capa) { mrb_value *expanded_ptr = (mrb_value *)mrb_realloc(mrb, a->ptr, sizeof(mrb_value)*capa); @@ -503,6 +505,9 @@ mrb_ary_unshift_m(mrb_state *mrb, mrb_value self) mrb_int len; mrb_get_args(mrb, "*", &vals, &len); + if (len > ARY_MAX_SIZE - a->len) { + mrb_raise(mrb, E_ARGUMENT_ERROR, "array size too big"); + } if (ARY_SHARED_P(a) && a->aux.shared->refcnt == 1 /* shared only referenced from this array */ && a->ptr - a->aux.shared->ptr >= len) /* there's room for unshifted item */ { diff --git a/src/class.c b/src/class.c index bac1d2984..e724dbb91 100644 --- a/src/class.c +++ b/src/class.c @@ -1817,7 +1817,7 @@ mrb_mod_undef(mrb_state *mrb, mrb_value mod) mrb_get_args(mrb, "*", &argv, &argc); while (argc--) { - undef_method(mrb, c, mrb_symbol(*argv)); + undef_method(mrb, c, to_sym(mrb, *argv)); argv++; } return mrb_nil_value(); diff --git a/src/object.c b/src/object.c index f76ee68a2..eb2c23e63 100644 --- a/src/object.c +++ b/src/object.c @@ -444,7 +444,7 @@ mrb_any_to_s(mrb_state *mrb, mrb_value obj) mrb_str_cat_lit(mrb, str, "#<"); mrb_str_cat_cstr(mrb, str, cname); mrb_str_cat_lit(mrb, str, ":"); - mrb_str_concat(mrb, str, mrb_ptr_to_str(mrb, mrb_cptr(obj))); + mrb_str_concat(mrb, str, mrb_ptr_to_str(mrb, mrb_ptr(obj))); mrb_str_cat_lit(mrb, str, ">"); return str; diff --git a/src/proc.c b/src/proc.c index 4f770932b..470547094 100644 --- a/src/proc.c +++ b/src/proc.c @@ -140,7 +140,7 @@ mrb_proc_copy(struct RProc *a, struct RProc *b) { a->flags = b->flags; a->body = b->body; - if (!MRB_PROC_CFUNC_P(a)) { + if (!MRB_PROC_CFUNC_P(a) && a->body.irep) { a->body.irep->refcnt++; } a->target_class = b->target_class; diff --git a/src/range.c b/src/range.c index f0a976e53..417957420 100644 --- a/src/range.c +++ b/src/range.c @@ -12,6 +12,17 @@ #define RANGE_CLASS (mrb_class_get(mrb, "Range")) +MRB_API struct RRange* +mrb_range_ptr(mrb_state *mrb, mrb_value v) +{ + struct RRange *r = (struct RRange*)mrb_ptr(v); + + if (r->edges == NULL) { + mrb_raise(mrb, E_ARGUMENT_ERROR, "uninitialized range"); + } + return r; +} + static void range_check(mrb_state *mrb, mrb_value a, mrb_value b) { @@ -57,7 +68,7 @@ mrb_range_new(mrb_state *mrb, mrb_value beg, mrb_value end, mrb_bool excl) mrb_value mrb_range_beg(mrb_state *mrb, mrb_value range) { - struct RRange *r = mrb_range_ptr(range); + struct RRange *r = mrb_range_ptr(mrb, range); return r->edges->beg; } @@ -76,7 +87,7 @@ mrb_range_beg(mrb_state *mrb, mrb_value range) mrb_value mrb_range_end(mrb_state *mrb, mrb_value range) { - struct RRange *r = mrb_range_ptr(range); + struct RRange *r = mrb_range_ptr(mrb, range); return r->edges->end; } @@ -90,7 +101,7 @@ mrb_range_end(mrb_state *mrb, mrb_value range) mrb_value mrb_range_excl(mrb_state *mrb, mrb_value range) { - struct RRange *r = mrb_range_ptr(range); + struct RRange *r = mrb_range_ptr(mrb, range); return mrb_bool_value(r->excl); } @@ -98,7 +109,7 @@ mrb_range_excl(mrb_state *mrb, mrb_value range) static void range_init(mrb_state *mrb, mrb_value range, mrb_value beg, mrb_value end, mrb_bool exclude_end) { - struct RRange *r = mrb_range_ptr(range); + struct RRange *r = mrb_range_raw_ptr(range); range_check(mrb, beg, end); r->excl = exclude_end; @@ -129,7 +140,7 @@ mrb_range_initialize(mrb_state *mrb, mrb_value range) exclusive = FALSE; } /* Ranges are immutable, so that they should be initialized only once. */ - if (mrb_range_ptr(range)->edges) { + if (mrb_range_raw_ptr(range)->edges) { mrb_name_error(mrb, mrb_intern_lit(mrb, "initialize"), "`initialize' called twice"); } range_init(mrb, range, beg, end, exclusive); @@ -164,8 +175,8 @@ mrb_range_eq(mrb_state *mrb, mrb_value range) return mrb_false_value(); } - rr = mrb_range_ptr(range); - ro = mrb_range_ptr(obj); + rr = mrb_range_ptr(mrb, range); + ro = mrb_range_ptr(mrb, obj); v1 = mrb_funcall(mrb, rr->edges->beg, "==", 1, ro->edges->beg); v2 = mrb_funcall(mrb, rr->edges->end, "==", 1, ro->edges->end); if (!mrb_bool(v1) || !mrb_bool(v2) || rr->excl != ro->excl) { @@ -222,7 +233,7 @@ mrb_value mrb_range_include(mrb_state *mrb, mrb_value range) { mrb_value val; - struct RRange *r = mrb_range_ptr(range); + struct RRange *r = mrb_range_ptr(mrb, range); mrb_value beg, end; mrb_bool include_p; @@ -241,7 +252,7 @@ static mrb_bool 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 = mrb_range_ptr(range); + struct RRange *r = mrb_range_ptr(mrb, range); if (mrb_type(range) != MRB_TT_RANGE) return FALSE; @@ -287,7 +298,7 @@ static mrb_value range_to_s(mrb_state *mrb, mrb_value range) { mrb_value str, str2; - struct RRange *r = mrb_range_ptr(range); + struct RRange *r = mrb_range_ptr(mrb, range); str = mrb_obj_as_string(mrb, r->edges->beg); str2 = mrb_obj_as_string(mrb, r->edges->end); @@ -312,7 +323,7 @@ static mrb_value range_inspect(mrb_state *mrb, mrb_value range) { mrb_value str, str2; - struct RRange *r = mrb_range_ptr(range); + struct RRange *r = mrb_range_ptr(mrb, range); str = mrb_inspect(mrb, r->edges->beg); str2 = mrb_inspect(mrb, r->edges->end); @@ -352,8 +363,8 @@ range_eql(mrb_state *mrb, mrb_value range) } if (mrb_type(obj) != MRB_TT_RANGE) return mrb_false_value(); - r = mrb_range_ptr(range); - o = mrb_range_ptr(obj); + r = mrb_range_ptr(mrb, range); + o = mrb_range_ptr(mrb, obj); if (!mrb_eql(mrb, r->edges->beg, o->edges->beg) || !mrb_eql(mrb, r->edges->end, o->edges->end) || (r->excl != o->excl)) { @@ -376,7 +387,7 @@ range_initialize_copy(mrb_state *mrb, mrb_value copy) mrb_raise(mrb, E_TYPE_ERROR, "wrong argument class"); } - r = mrb_range_ptr(src); + r = mrb_range_ptr(mrb, src); range_init(mrb, copy, r->edges->beg, r->edges->end, r->excl); return copy; diff --git a/src/string.c b/src/string.c index f47294291..4f722b273 100644 --- a/src/string.c +++ b/src/string.c @@ -2286,7 +2286,7 @@ mrb_cstr_to_dbl(mrb_state *mrb, const char * p, mrb_bool badcheck) if (!badcheck && p[0] == '0' && (p[1] == 'x' || p[1] == 'X')) { return 0.0; } - d = strtod(p, &end); + d = mrb_float_read(p, &end); if (p == end) { if (badcheck) { bad: @@ -2324,7 +2324,7 @@ bad: return 0.0; } - d = strtod(p, &end); + d = mrb_float_read(p, &end); if (badcheck) { if (!end || p == end) goto bad; while (*end && ISSPACE(*end)) end++; @@ -2749,3 +2749,241 @@ mrb_init_string(mrb_state *mrb) mrb_define_method(mrb, s, "freeze", mrb_str_freeze, MRB_ARGS_NONE()); } + +/* + * Source code for the "strtod" library procedure. + * + * Copyright (c) 1988-1993 The Regents of the University of California. + * Copyright (c) 1994 Sun Microsystems, Inc. + * + * Permission to use, copy, modify, and distribute this + * software and its documentation for any purpose and without + * fee is hereby granted, provided that the above copyright + * notice appear in all copies. The University of California + * makes no representations about the suitability of this + * software for any purpose. It is provided "as is" without + * express or implied warranty. + * + * RCS: @(#) $Id: strtod.c 11708 2007-02-12 23:01:19Z shyouhei $ + */ + +#include <ctype.h> +#include <errno.h> +extern int errno; + +#ifndef __STDC__ +# ifdef __GNUC__ +# define const __const__ +# else +# define const +# endif +#endif + +static const int maxExponent = 511; /* Largest possible base 10 exponent. Any + * exponent larger than this will already + * produce underflow or overflow, so there's + * no need to worry about additional digits. + */ +static const double powersOf10[] = {/* Table giving binary powers of 10. Entry */ + 10., /* is 10^2^i. Used to convert decimal */ + 100., /* exponents into floating-point numbers. */ + 1.0e4, + 1.0e8, + 1.0e16, + 1.0e32, + 1.0e64, + 1.0e128, + 1.0e256 +}; + +MRB_API double +mrb_float_read(const char *string, char **endPtr) +/* const char *string; A decimal ASCII floating-point number, + * optionally preceded by white space. + * Must have form "-I.FE-X", where I is the + * integer part of the mantissa, F is the + * fractional part of the mantissa, and X + * is the exponent. Either of the signs + * may be "+", "-", or omitted. Either I + * or F may be omitted, or both. The decimal + * point isn't necessary unless F is present. + * The "E" may actually be an "e". E and X + * may both be omitted (but not just one). + */ +/* char **endPtr; If non-NULL, store terminating character's + * address here. */ +{ + int sign, expSign = FALSE; + double fraction, dblExp; + const double *d; + register const char *p; + register int c; + int exp = 0; /* Exponent read from "EX" field. */ + int fracExp = 0; /* Exponent that derives from the fractional + * part. Under normal circumstatnces, it is + * the negative of the number of digits in F. + * However, if I is very long, the last digits + * of I get dropped (otherwise a long I with a + * large negative exponent could cause an + * unnecessary overflow on I alone). In this + * case, fracExp is incremented one for each + * dropped digit. */ + int mantSize; /* Number of digits in mantissa. */ + int decPt; /* Number of mantissa digits BEFORE decimal + * point. */ + const char *pExp; /* Temporarily holds location of exponent + * in string. */ + + /* + * Strip off leading blanks and check for a sign. + */ + + p = string; + while (isspace(*p)) { + p += 1; + } + if (*p == '-') { + sign = TRUE; + p += 1; + } else { + if (*p == '+') { + p += 1; + } + sign = FALSE; + } + + /* + * Count the number of digits in the mantissa (including the decimal + * point), and also locate the decimal point. + */ + + decPt = -1; + for (mantSize = 0; ; mantSize += 1) + { + c = *p; + if (!isdigit(c)) { + if ((c != '.') || (decPt >= 0)) { + break; + } + decPt = mantSize; + } + p += 1; + } + + /* + * Now suck up the digits in the mantissa. Use two integers to + * collect 9 digits each (this is faster than using floating-point). + * If the mantissa has more than 18 digits, ignore the extras, since + * they can't affect the value anyway. + */ + + pExp = p; + p -= mantSize; + if (decPt < 0) { + decPt = mantSize; + } else { + mantSize -= 1; /* One of the digits was the point. */ + } + if (mantSize > 18) { + fracExp = decPt - 18; + mantSize = 18; + } else { + fracExp = decPt - mantSize; + } + if (mantSize == 0) { + fraction = 0.0; + p = string; + goto done; + } else { + int frac1, frac2; + frac1 = 0; + for ( ; mantSize > 9; mantSize -= 1) + { + c = *p; + p += 1; + if (c == '.') { + c = *p; + p += 1; + } + frac1 = 10*frac1 + (c - '0'); + } + frac2 = 0; + for (; mantSize > 0; mantSize -= 1) + { + c = *p; + p += 1; + if (c == '.') { + c = *p; + p += 1; + } + frac2 = 10*frac2 + (c - '0'); + } + fraction = (1.0e9 * frac1) + frac2; + } + + /* + * Skim off the exponent. + */ + + p = pExp; + if ((*p == 'E') || (*p == 'e')) { + p += 1; + if (*p == '-') { + expSign = TRUE; + p += 1; + } else { + if (*p == '+') { + p += 1; + } + expSign = FALSE; + } + while (isdigit(*p)) { + exp = exp * 10 + (*p - '0'); + p += 1; + } + } + if (expSign) { + exp = fracExp - exp; + } else { + exp = fracExp + exp; + } + + /* + * Generate a floating-point number that represents the exponent. + * Do this by processing the exponent one bit at a time to combine + * many powers of 2 of 10. Then combine the exponent with the + * fraction. + */ + + if (exp < 0) { + expSign = TRUE; + exp = -exp; + } else { + expSign = FALSE; + } + if (exp > maxExponent) { + exp = maxExponent; + errno = ERANGE; + } + dblExp = 1.0; + for (d = powersOf10; exp != 0; exp >>= 1, d += 1) { + if (exp & 01) { + dblExp *= *d; + } + } + if (expSign) { + fraction /= dblExp; + } else { + fraction *= dblExp; + } + +done: + if (endPtr != NULL) { + *endPtr = (char *) p; + } + + if (sign) { + return -fraction; + } + return fraction; +} @@ -54,6 +54,10 @@ The value below allows about 60000 recursive calls in the simplest case. */ #define ARENA_RESTORE(mrb,ai) (mrb)->gc.arena_idx = (ai) +#define CALL_MAXARGS 127 + +void mrb_method_missing(mrb_state *mrb, mrb_sym name, mrb_value self, mrb_value args); + static inline void stack_clear(mrb_value *from, size_t count) { @@ -362,9 +366,13 @@ mrb_funcall_with_block(mrb_state *mrb, mrb_value self, mrb_sym mid, mrb_int argc c = mrb_class(mrb, self); p = mrb_method_search_vm(mrb, &c, mid); if (!p) { + mrb_sym missing = mrb_intern_lit(mrb, "method_missing"); + p = mrb_method_search_vm(mrb, &c, missing); + if (!p) { + mrb_value args = mrb_ary_new_from_values(mrb, argc, argv); + mrb_method_missing(mrb, mid, self, args); + } undef = mid; - mid = mrb_intern_lit(mrb, "method_missing"); - p = mrb_method_search_vm(mrb, &c, mid); n++; argc++; } ci = cipush(mrb); @@ -749,10 +757,6 @@ argnum_error(mrb_state *mrb, mrb_int num) #endif -#define CALL_MAXARGS 127 - -void mrb_method_missing(mrb_state *mrb, mrb_sym name, mrb_value self, mrb_value args); - MRB_API mrb_value mrb_vm_run(mrb_state *mrb, struct RProc *proc, mrb_value self, unsigned int stack_keep) { @@ -1290,8 +1294,20 @@ RETRY_TRY_BLOCK: c = mrb->c->ci->target_class->super; m = mrb_method_search_vm(mrb, &c, mid); if (!m) { - mid = mrb_intern_lit(mrb, "method_missing"); - m = mrb_method_search_vm(mrb, &c, mid); + mrb_sym missing = mrb_intern_lit(mrb, "method_missing"); + m = mrb_method_search_vm(mrb, &c, missing); + if (!m) { + mrb_value args; + + if (n == CALL_MAXARGS) { + args = regs[a+1]; + } + else { + args = mrb_ary_new_from_values(mrb, n, regs+a+1); + } + mrb_method_missing(mrb, mid, recv, args); + } + mid = missing; if (n == CALL_MAXARGS) { mrb_ary_unshift(mrb, regs[a+1], mrb_symbol_value(ci->mid)); } @@ -1681,9 +1697,20 @@ RETRY_TRY_BLOCK: m = mrb_method_search_vm(mrb, &c, mid); if (!m) { mrb_value sym = mrb_symbol_value(mid); + mrb_sym missing = mrb_intern_lit(mrb, "method_missing"); + m = mrb_method_search_vm(mrb, &c, missing); + if (!m) { + mrb_value args; - mid = mrb_intern_lit(mrb, "method_missing"); - m = mrb_method_search_vm(mrb, &c, mid); + if (n == CALL_MAXARGS) { + args = regs[a+1]; + } + else { + args = mrb_ary_new_from_values(mrb, n, regs+a+1); + } + mrb_method_missing(mrb, mid, recv, args); + } + mid = missing; if (n == CALL_MAXARGS) { mrb_ary_unshift(mrb, regs[a+1], sym); } diff --git a/test/t/codegen.rb b/test/t/codegen.rb index 1ac689a82..bb0f5c306 100644 --- a/test/t/codegen.rb +++ b/test/t/codegen.rb @@ -54,3 +54,12 @@ A B assert_equal "\n", a end + +assert('splat in case splat') do + a = *case + when 0 + * = 1 + end + + assert_equal [1], a +end diff --git a/test/t/kernel.rb b/test/t/kernel.rb index d240e59dc..e59bd6a10 100644 --- a/test/t/kernel.rb +++ b/test/t/kernel.rb @@ -520,6 +520,21 @@ assert('Kernel#to_s', '15.3.1.3.46') do assert_equal to_s.class, String end +assert('Kernel#to_s on primitives') do + begin + Fixnum.alias_method :to_s_, :to_s + Fixnum.remove_method :to_s + + assert_nothing_raised do + # segfaults if mrb_cptr is used + 1.to_s + end + ensure + Fixnum.alias_method :to_s, :to_s_ + Fixnum.remove_method :to_s_ + end +end + assert('Kernel.local_variables', '15.3.1.2.7') do a, b = 0, 1 a += b diff --git a/test/t/nomethoderror.rb b/test/t/nomethoderror.rb index 5fed79689..1c09bc20e 100644 --- a/test/t/nomethoderror.rb +++ b/test/t/nomethoderror.rb @@ -20,3 +20,34 @@ assert('NoMethodError#args', '15.2.32.2.1') do end end end + +assert('Can still raise when BasicObject#method_missing is removed') do + assert_raise(NoMethodError) do + begin + BasicObject.alias_method(:old_method_missing, :method_missing) + BasicObject.remove_method(:method_missing) + 1.__send__(:foo) + ensure + BasicObject.alias_method(:method_missing, :old_method_missing) + BasicObject.remove_method(:old_method_missing) + end + end +end + +assert('Can still call super when BasicObject#method_missing is removed') do + assert_raise(NoMethodError) do + class A + def foo + super + end + end + begin + BasicObject.alias_method(:old_method_missing, :method_missing) + BasicObject.remove_method(:method_missing) + A.new.foo + ensure + BasicObject.alias_method(:method_missing, :old_method_missing) + BasicObject.remove_method(:old_method_missing) + end + end +end diff --git a/test/t/proc.rb b/test/t/proc.rb index bc9821f7c..29530e8dd 100644 --- a/test/t/proc.rb +++ b/test/t/proc.rb @@ -163,3 +163,19 @@ assert('&obj call to_proc if defined') do assert_raise(TypeError){ mock(&(Object.new)) } end + +assert('initialize_copy works when initialize is removed') do + begin + Proc.alias_method(:old_initialize, :initialize) + Proc.remove_method(:initialize) + + a = Proc.new {} + b = Proc.new {} + assert_nothing_raised do + a.initialize_copy(b) + end + ensure + Proc.alias_method(:initialize, :old_initialize) + Proc.remove_method(:old_initialize) + end +end |
