diff options
| -rw-r--r-- | mrbgems/mruby-compiler/core/parse.y | 102 | ||||
| -rw-r--r-- | src/array.c | 15 | ||||
| -rw-r--r-- | src/proc.c | 2 | ||||
| -rw-r--r-- | test/t/array.rb | 13 | ||||
| -rw-r--r-- | test/t/class.rb | 12 | ||||
| -rw-r--r-- | test/t/hash.rb | 7 | ||||
| -rw-r--r-- | test/t/proc.rb | 16 | ||||
| -rw-r--r-- | test/t/syntax.rb | 20 | ||||
| -rw-r--r-- | test/t/unicode.rb | 32 |
9 files changed, 157 insertions, 62 deletions
diff --git a/mrbgems/mruby-compiler/core/parse.y b/mrbgems/mruby-compiler/core/parse.y index ef522d239..bf893fb37 100644 --- a/mrbgems/mruby-compiler/core/parse.y +++ b/mrbgems/mruby-compiler/core/parse.y @@ -3752,6 +3752,44 @@ scan_hex(const int *start, int len, int *retlen) return retval; } +static int32_t +read_escape_unicode(parser_state *p, int limit) +{ + int32_t c; + int buf[9]; + int i; + + /* Look for opening brace */ + i = 0; + buf[0] = nextc(p); + if (buf[0] < 0) goto eof; + if (ISXDIGIT(buf[0])) { + /* \uxxxx form */ + for (i=1; i<limit; i++) { + buf[i] = nextc(p); + if (buf[i] < 0) goto eof; + if (!ISXDIGIT(buf[i])) { + pushback(p, buf[i]); + break; + } + } + } + else { + pushback(p, buf[0]); + } + c = scan_hex(buf, i, &i); + if (i == 0) { + eof: + yyerror(p, "Invalid escape character syntax"); + return -1; + } + if (c < 0 || c > 0x10FFFF || (c & 0xFFFFF800) == 0xD800) { + yyerror(p, "Invalid Unicode code point"); + return -1; + } + return c; +} + /* Return negative to indicate Unicode code point */ static int32_t read_escape(parser_state *p) @@ -3824,53 +3862,17 @@ read_escape(parser_state *p) return c; case 'u': /* Unicode */ - { - int buf[9]; - int i; - - /* Look for opening brace */ - i = 0; - buf[0] = nextc(p); - if (buf[0] < 0) goto eof; - if (buf[0] == '{') { + if (peek(p, '{')) { /* \u{xxxxxxxx} form */ - for (i=0; i<9; i++) { - buf[i] = nextc(p); - if (buf[i] < 0) goto eof; - if (buf[i] == '}') { - break; - } - else if (!ISXDIGIT(buf[i])) { - yyerror(p, "Invalid escape character syntax"); - pushback(p, buf[i]); - return 0; - } - } - } - else if (ISXDIGIT(buf[0])) { - /* \uxxxx form */ - for (i=1; i<4; i++) { - buf[i] = nextc(p); - if (buf[i] < 0) goto eof; - if (!ISXDIGIT(buf[i])) { - pushback(p, buf[i]); - break; - } - } + nextc(p); + c = read_escape_unicode(p, 8); + if (c < 0) return 0; + if (nextc(p) != '}') goto eof; } else { - pushback(p, buf[0]); - } - c = scan_hex(buf, i, &i); - if (i == 0) { - yyerror(p, "Invalid escape character syntax"); - return 0; + c = read_escape_unicode(p, 4); + if (c < 0) return 0; } - if (c < 0 || c > 0x10FFFF || (c & 0xFFFFF800) == 0xD800) { - yyerror(p, "Invalid Unicode code point"); - return 0; - } - } return -c; case 'b':/* backspace */ @@ -3993,6 +3995,20 @@ parse_string(parser_state *p) tokadd(p, '\\'); tokadd(p, c); } + else if (c == 'u' && peek(p, '{')) { + /* \u{xxxx xxxx xxxx} form */ + nextc(p); + while (1) { + do c = nextc(p); while (ISSPACE(c)); + if (c == '}') break; + pushback(p, c); + c = read_escape_unicode(p, 8); + if (c < 0) break; + tokadd(p, -c); + } + if (hinf) + hinf->line_head = FALSE; + } else { pushback(p, c); tokadd(p, read_escape(p)); diff --git a/src/array.c b/src/array.c index 8902f2dda..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); @@ -244,10 +246,12 @@ mrb_ary_s_create(mrb_state *mrb, mrb_value self) static void ary_concat(mrb_state *mrb, struct RArray *a, struct RArray *a2) { + mrb_int len; + if (a2->len > ARY_MAX_SIZE - a->len) { mrb_raise(mrb, E_ARGUMENT_ERROR, "array size too big"); } - mrb_int len = a->len + a2->len; + len = a->len + a2->len; ary_modify(mrb, a); if (a->aux.capa < len) { @@ -501,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/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/test/t/array.rb b/test/t/array.rb index 3c5211591..9cc2f64ad 100644 --- a/test/t/array.rb +++ b/test/t/array.rb @@ -82,6 +82,14 @@ assert('Array#[]=', '15.2.12.5.5') do a = [1,2,3,4,5] a[2...4] = 6 assert_equal([1,2,6,5], a) + + # passing self (#3274) + a = [1,2,3] + a[1,0] = a + assert_equal([1,1,2,3,2,3], a) + a = [1,2,3] + a[-1,0] = a + assert_equal([1,2,1,2,3,3], a) end assert('Array#clear', '15.2.12.5.6') do @@ -98,6 +106,11 @@ end assert('Array#concat', '15.2.12.5.8') do assert_equal([1,2,3,4], [1, 2].concat([3, 4])) + + # passing self (#3302) + a = [1,2,3] + a.concat(a) + assert_equal([1,2,3,1,2,3], a) end assert('Array#delete_at', '15.2.12.5.9') do diff --git a/test/t/class.rb b/test/t/class.rb index 597999d3e..605b7ec40 100644 --- a/test/t/class.rb +++ b/test/t/class.rb @@ -397,6 +397,18 @@ assert('class variable in module and class << self style class method') do assert_equal("value", ClassVariableInModuleTest.class_variable) end +assert('overriding class variable with a module (#3235)') do + module ModuleWithCVar + @@class_variable = 1 + end + class CVarOverrideTest + @@class_variable = 2 + include ModuleWithCVar + + assert_equal(1, @@class_variable) + end +end + assert('class with non-class/module outer raises TypeError') do assert_raise(TypeError) { class 0::C1; end } assert_raise(TypeError) { class []::C2; end } diff --git a/test/t/hash.rb b/test/t/hash.rb index c8d7a70ef..b455812cf 100644 --- a/test/t/hash.rb +++ b/test/t/hash.rb @@ -16,6 +16,13 @@ assert('Hash#[]', '15.2.13.4.2') do a = { 'abc' => 'abc' } assert_equal 'abc', a['abc'] + + # Hash#[] should call #default (#3272) + hash = {} + def hash.default(k); self[k] = 1; end + hash[:foo] += 1 + + assert_equal 2, hash[:foo] end assert('Hash#[]=', '15.2.13.4.3') do 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 diff --git a/test/t/syntax.rb b/test/t/syntax.rb index 3bc68484b..461f5430b 100644 --- a/test/t/syntax.rb +++ b/test/t/syntax.rb @@ -47,6 +47,19 @@ assert('yield', '11.3.5') do end end +assert('redo in a for loop (#3275)') do + sum = 0 + for i in 1..10 + sum += i + i -= 1 + if i > 0 + redo + end + end + + assert_equal 220, sum +end + assert('Abbreviated variable assignment', '11.4.2.3.2') do a ||= 1 b &&= 1 @@ -255,6 +268,13 @@ assert('multiple assignment (nosplat array rhs)') do assert_equal 2, g end +assert('multiple assignment (empty array rhs #3236, #3239)') do + a,b,*c = []; assert_equal [nil, nil, []], [a, b, c] + a,b,*c = [1]; assert_equal [1, nil, []], [a, b, c] + a,b,*c = [nil]; assert_equal [nil,nil, []], [a, b, c] + a,b,*c = [[]]; assert_equal [[], nil, []], [a, b, c] +end + assert('Return values of case statements') do a = [] << case 1 when 3 then 2 diff --git a/test/t/unicode.rb b/test/t/unicode.rb index 7edd65ef2..8622ae08a 100644 --- a/test/t/unicode.rb +++ b/test/t/unicode.rb @@ -2,34 +2,38 @@ assert('bare \u notation test') do # Mininum and maximum one byte characters - assert_equal("\u0000", "\x00") - assert_equal("\u007F", "\x7F") + assert_equal("\x00", "\u0000") + assert_equal("\x7F", "\u007F") # Mininum and maximum two byte characters - assert_equal("\u0080", "\xC2\x80") - assert_equal("\u07FF", "\xDF\xBF") + assert_equal("\xC2\x80", "\u0080") + assert_equal("\xDF\xBF", "\u07FF") # Mininum and maximum three byte characters - assert_equal("\u0800", "\xE0\xA0\x80") - assert_equal("\uFFFF", "\xEF\xBF\xBF") + assert_equal("\xE0\xA0\x80", "\u0800") + assert_equal("\xEF\xBF\xBF", "\uFFFF") # Four byte characters require the \U notation end assert('braced \u notation test') do # Mininum and maximum one byte characters - assert_equal("\u{0000}", "\x00") - assert_equal("\u{007F}", "\x7F") + assert_equal("\x00", "\u{0000}") + assert_equal("\x7F", "\u{007F}") # Mininum and maximum two byte characters - assert_equal("\u{0080}", "\xC2\x80") - assert_equal("\u{07FF}", "\xDF\xBF") + assert_equal("\xC2\x80", "\u{0080}") + assert_equal("\xDF\xBF", "\u{07FF}") # Mininum and maximum three byte characters - assert_equal("\u{0800}", "\xE0\xA0\x80") - assert_equal("\u{FFFF}", "\xEF\xBF\xBF") + assert_equal("\xE0\xA0\x80", "\u{0800}") + assert_equal("\xEF\xBF\xBF", "\u{FFFF}") # Mininum and maximum four byte characters - assert_equal("\u{10000}", "\xF0\x90\x80\x80") - assert_equal("\u{10FFFF}", "\xF4\x8F\xBF\xBF") + assert_equal("\xF0\x90\x80\x80", "\u{10000}") + assert_equal("\xF4\x8F\xBF\xBF", "\u{10FFFF}") +end + +assert('braced multiple \u notation test') do + assert_equal("ABC", "\u{41 42 43}") end |
