esruby 0.0.9 → 0.0.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (51) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +2 -2
  3. data/lib/esruby/build.rb +7 -4
  4. data/resources/build_config.eruby +1 -0
  5. data/resources/cpp/main.cpp +14 -0
  6. data/resources/mruby/doc/guides/mrbgems.md +5 -0
  7. data/resources/mruby/include/mrbconf.h +3 -5
  8. data/resources/mruby/include/mruby/proc.h +2 -2
  9. data/resources/mruby/include/mruby.h +11 -4
  10. data/resources/mruby/lib/mruby/build/load_gems.rb +5 -3
  11. data/resources/mruby/lib/mruby/build.rb +23 -0
  12. data/resources/mruby/lib/mruby/gem.rb +12 -13
  13. data/resources/mruby/mrbgems/default.gembox +6 -0
  14. data/resources/mruby/mrbgems/mruby-compiler/core/codegen.c +7 -1
  15. data/resources/mruby/mrbgems/mruby-compiler/core/parse.y +31 -36
  16. data/resources/mruby/mrbgems/mruby-enum-ext/mrblib/enum.rb +33 -10
  17. data/resources/mruby/mrbgems/mruby-enum-ext/test/enum.rb +6 -0
  18. data/resources/mruby/mrbgems/mruby-enum-lazy/test/lazy.rb +1 -1
  19. data/resources/mruby/mrbgems/mruby-enumerator/mrblib/enumerator.rb +32 -17
  20. data/resources/mruby/mrbgems/mruby-enumerator/test/enumerator.rb +10 -0
  21. data/resources/mruby/mrbgems/mruby-fiber/src/fiber.c +3 -2
  22. data/resources/mruby/mrbgems/mruby-io/mrblib/io.rb +3 -2
  23. data/resources/mruby/mrbgems/mruby-io/src/file.c +15 -0
  24. data/resources/mruby/mrbgems/mruby-io/src/io.c +16 -8
  25. data/resources/mruby/mrbgems/mruby-io/test/file.rb +17 -1
  26. data/resources/mruby/mrbgems/mruby-io/test/io.rb +4 -0
  27. data/resources/mruby/mrbgems/mruby-pack/src/pack.c +16 -6
  28. data/resources/mruby/mrbgems/mruby-socket/mrbgem.rake +2 -2
  29. data/resources/mruby/mrbgems/mruby-socket/test/sockettest.c +42 -6
  30. data/resources/mruby/mrbgems/mruby-test/init_mrbtest.c +1 -0
  31. data/resources/mruby/mrbgems/mruby-test/mrbgem.rake +1 -0
  32. data/resources/mruby/mrbgems/mruby-time/src/time.c +22 -3
  33. data/resources/mruby/mrbgems/mruby-time/test/time.rb +4 -0
  34. data/resources/mruby/mrblib/array.rb +8 -9
  35. data/resources/mruby/mrblib/enum.rb +1 -1
  36. data/resources/mruby/src/array.c +1 -1
  37. data/resources/mruby/src/class.c +8 -2
  38. data/resources/mruby/src/error.c +2 -1
  39. data/resources/mruby/src/gc.c +1 -1
  40. data/resources/mruby/src/object.c +2 -2
  41. data/resources/mruby/src/string.c +8 -8
  42. data/resources/mruby/src/variable.c +41 -7
  43. data/resources/mruby/src/vm.c +5 -4
  44. data/resources/mruby/tasks/toolchains/visualcpp.rake +10 -9
  45. data/resources/mruby/test/t/string.rb +2 -1
  46. data/resources/project_template/config.rb +5 -0
  47. data/resources/rb/append.rb +3 -0
  48. metadata +3 -4
  49. data/resources/cpp/esruby.cpp +0 -51
  50. data/resources/cpp/esruby.hpp +0 -38
  51. data/resources/js/esruby.js +0 -17
@@ -93,8 +93,9 @@ class IO
93
93
  if path[0] == "|"
94
94
  io = IO.popen(path[1..-1], (opt[:mode] || "r"))
95
95
  else
96
- fd = IO.sysopen(path)
97
- io = IO.open(fd, opt[:mode] || "r")
96
+ mode = opt[:mode] || "r"
97
+ fd = IO.sysopen(path, mode)
98
+ io = IO.open(fd, mode)
98
99
  end
99
100
  io.seek(offset) if offset > 0
100
101
  str = io.read(length)
@@ -332,6 +332,20 @@ mrb_file__gethome(mrb_state *mrb, mrb_value klass)
332
332
  #endif
333
333
  }
334
334
 
335
+ static mrb_value
336
+ mrb_file_mtime(mrb_state *mrb, mrb_value self)
337
+ {
338
+ mrb_value obj;
339
+ struct stat st;
340
+ int fd;
341
+
342
+ obj = mrb_obj_value(mrb_class_get(mrb, "Time"));
343
+ fd = (int)mrb_fixnum(mrb_io_fileno(mrb, self));
344
+ if (fstat(fd, &st) == -1)
345
+ return mrb_false_value();
346
+ return mrb_funcall(mrb, obj, "at", 1, mrb_float_value(mrb, st.st_mtime));
347
+ }
348
+
335
349
  mrb_value
336
350
  mrb_file_flock(mrb_state *mrb, mrb_value self)
337
351
  {
@@ -471,6 +485,7 @@ mrb_init_file(mrb_state *mrb)
471
485
  mrb_define_class_method(mrb, file, "_gethome", mrb_file__gethome, MRB_ARGS_OPT(1));
472
486
 
473
487
  mrb_define_method(mrb, file, "flock", mrb_file_flock, MRB_ARGS_REQ(1));
488
+ mrb_define_method(mrb, file, "mtime", mrb_file_mtime, MRB_ARGS_NONE());
474
489
 
475
490
  cnst = mrb_define_module_under(mrb, file, "Constants");
476
491
  mrb_define_const(mrb, cnst, "LOCK_SH", mrb_fixnum_value(LOCK_SH));
@@ -180,7 +180,7 @@ mrb_io_flags_to_modenum(mrb_state *mrb, int flags)
180
180
  return modenum;
181
181
  }
182
182
 
183
- void
183
+ static void
184
184
  mrb_fd_cloexec(mrb_state *mrb, int fd)
185
185
  {
186
186
  #if defined(F_GETFD) && defined(F_SETFD) && defined(FD_CLOEXEC)
@@ -188,7 +188,8 @@ mrb_fd_cloexec(mrb_state *mrb, int fd)
188
188
 
189
189
  flags = fcntl(fd, F_GETFD);
190
190
  if (flags == -1) {
191
- mrb_sys_fail(mrb, "fcntl");
191
+ mrb_bug(mrb, "mrb_fd_cloexec: fcntl(%S, F_GETFD) failed: %S",
192
+ mrb_fixnum_value(fd), mrb_fixnum_value(errno));
192
193
  }
193
194
  if (fd <= 2) {
194
195
  flags2 = flags & ~FD_CLOEXEC; /* Clear CLOEXEC for standard file descriptors: 0, 1, 2. */
@@ -198,7 +199,8 @@ mrb_fd_cloexec(mrb_state *mrb, int fd)
198
199
  }
199
200
  if (flags != flags2) {
200
201
  if (fcntl(fd, F_SETFD, flags2) == -1) {
201
- mrb_sys_fail(mrb, "fcntl");
202
+ mrb_bug(mrb, "mrb_fd_cloexec: fcntl(%S, F_SETFD, %S) failed: %S",
203
+ mrb_fixnum_value(fd), mrb_fixnum_value(flags2), mrb_fixnum_value(errno));
202
204
  }
203
205
  }
204
206
  #endif
@@ -577,11 +579,17 @@ mrb_io_initialize_copy(mrb_state *mrb, mrb_value copy)
577
579
  if (failed) {
578
580
  mrb_sys_fail(mrb, 0);
579
581
  }
580
- fptr_copy->fd2 = mrb_dup(mrb, fptr_orig->fd2, &failed);
581
- if (failed) {
582
- close(fptr_copy->fd);
583
- mrb_sys_fail(mrb, 0);
582
+ mrb_fd_cloexec(mrb, fptr_copy->fd);
583
+
584
+ if (fptr_orig->fd2 != -1) {
585
+ fptr_copy->fd2 = mrb_dup(mrb, fptr_orig->fd2, &failed);
586
+ if (failed) {
587
+ close(fptr_copy->fd);
588
+ mrb_sys_fail(mrb, 0);
589
+ }
590
+ mrb_fd_cloexec(mrb, fptr_copy->fd2);
584
591
  }
592
+
585
593
  fptr_copy->pid = fptr_orig->pid;
586
594
  fptr_copy->readable = fptr_orig->readable;
587
595
  fptr_copy->writable = fptr_orig->writable;
@@ -676,7 +684,7 @@ fptr_finalize(mrb_state *mrb, struct mrb_io *fptr, int quiet)
676
684
  io_set_process_status(mrb, pid, status);
677
685
  }
678
686
  #else
679
- HANDLE h = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, fptr->pid);
687
+ HANDLE h = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, fptr->pid);
680
688
  DWORD status;
681
689
  if (WaitForSingleObject(h, INFINITE) && GetExitCodeProcess(h, &status))
682
690
  if (!quiet)
@@ -54,7 +54,7 @@ assert('File.extname') do
54
54
  assert_equal '', File.extname('.foo')
55
55
  end
56
56
 
57
- assert('IO#flock') do
57
+ assert('File#flock') do
58
58
  f = File.open $mrbtest_io_rfname
59
59
  begin
60
60
  assert_equal(f.flock(File::LOCK_SH), 0)
@@ -68,6 +68,22 @@ assert('IO#flock') do
68
68
  end
69
69
  end
70
70
 
71
+ assert('File#mtime') do
72
+ unless Object.const_defined?(:Time)
73
+ skip "File#mtime require Time"
74
+ end
75
+ begin
76
+ now = Time.now.to_i
77
+ mt = 0
78
+ File.open('mtime-test', 'w') do |f|
79
+ mt = f.mtime.to_i
80
+ end
81
+ assert_equal true, mt >= now
82
+ ensure
83
+ File.delete('mtime-test')
84
+ end
85
+ end
86
+
71
87
  assert('File.join') do
72
88
  assert_equal "", File.join()
73
89
  assert_equal "a", File.join("a")
@@ -216,6 +216,10 @@ assert('IO#dup for readable') do
216
216
  dup = io.dup
217
217
  assert_true io != dup
218
218
  assert_true io.fileno != dup.fileno
219
+ begin
220
+ assert_true dup.close_on_exec?
221
+ rescue NotImplementedError
222
+ end
219
223
  assert_equal 'm', dup.sysread(1)
220
224
  assert_equal 'r', io.sysread(1)
221
225
  assert_equal 'u', dup.sysread(1)
@@ -107,6 +107,9 @@ static mrb_value
107
107
  str_len_ensure(mrb_state *mrb, mrb_value str, mrb_int len)
108
108
  {
109
109
  mrb_int n = RSTRING_LEN(str);
110
+ if (len < 0) {
111
+ mrb_raise(mrb, E_RANGE_ERROR, "negative (or overflowed) integer");
112
+ }
110
113
  if (len > n) {
111
114
  do {
112
115
  n *= 2;
@@ -515,7 +518,7 @@ utf8_to_uv(mrb_state *mrb, const char *p, long *lenp)
515
518
  c = *p++ & 0xff;
516
519
  if ((c & 0xc0) != 0x80) {
517
520
  *lenp -= n + 1;
518
- mrb_raisef(mrb, E_ARGUMENT_ERROR, "malformed UTF-8 character");
521
+ mrb_raise(mrb, E_ARGUMENT_ERROR, "malformed UTF-8 character");
519
522
  }
520
523
  else {
521
524
  c &= 0x3f;
@@ -525,7 +528,7 @@ utf8_to_uv(mrb_state *mrb, const char *p, long *lenp)
525
528
  }
526
529
  n = *lenp - 1;
527
530
  if (uv < utf8_limits[n]) {
528
- mrb_raisef(mrb, E_ARGUMENT_ERROR, "redundant UTF-8 sequence");
531
+ mrb_raise(mrb, E_ARGUMENT_ERROR, "redundant UTF-8 sequence");
529
532
  }
530
533
  return uv;
531
534
  }
@@ -726,7 +729,7 @@ pack_m(mrb_state *mrb, mrb_value src, mrb_value dst, mrb_int didx, long count, u
726
729
  count -= count % 3;
727
730
  }
728
731
 
729
- dstlen = srclen / 3 * 4;
732
+ dstlen = (srclen+2) / 3 * 4;
730
733
  if (count > 0) {
731
734
  dstlen += (srclen / count) + ((srclen % count) == 0 ? 0 : 1);
732
735
  }
@@ -803,7 +806,7 @@ unpack_m(mrb_state *mrb, const void *src, int slen, mrb_value ary, unsigned int
803
806
  ch[i] = 0;
804
807
  padding++;
805
808
  }
806
- } while (ch[i] == PACK_BASE64_IGNORE);
809
+ } while (c >= sizeof(base64_dec_tab) || ch[i] == PACK_BASE64_IGNORE);
807
810
  }
808
811
 
809
812
  l = (ch[0] << 18) + (ch[1] << 12) + (ch[2] << 6) + ch[3];
@@ -833,16 +836,17 @@ pack_x(mrb_state *mrb, mrb_value src, mrb_value dst, mrb_int didx, long count, u
833
836
  {
834
837
  long i;
835
838
 
839
+ if (count < 0) return 0;
836
840
  dst = str_len_ensure(mrb, dst, didx + count);
837
841
  for (i = 0; i < count; i++) {
838
- RSTRING_PTR(dst)[didx] = '\0';
842
+ RSTRING_PTR(dst)[didx + i] = '\0';
839
843
  }
840
844
  return count;
841
845
  }
842
-
843
846
  static int
844
847
  unpack_x(mrb_state *mrb, const void *src, int slen, mrb_value ary, int count, unsigned int flags)
845
848
  {
849
+ if (count < 0) return slen;
846
850
  if (slen < count) {
847
851
  mrb_raise(mrb, E_ARGUMENT_ERROR, "x outside of string");
848
852
  }
@@ -1050,6 +1054,9 @@ alias:
1050
1054
  count = ch - '0';
1051
1055
  while (tmpl->idx < tlen && isdigit(tptr[tmpl->idx])) {
1052
1056
  count = count * 10 + (tptr[tmpl->idx++] - '0');
1057
+ if (count < 0) {
1058
+ mrb_raisef(mrb, E_RUNTIME_ERROR, "too big template length");
1059
+ }
1053
1060
  }
1054
1061
  continue; /* special case */
1055
1062
  } else if (ch == '*') {
@@ -1171,6 +1178,9 @@ mrb_pack_pack(mrb_state *mrb, mrb_value ary)
1171
1178
  count--;
1172
1179
  }
1173
1180
  }
1181
+ if (ridx < 0) {
1182
+ mrb_raise(mrb, E_RANGE_ERROR, "negative (or overflowed) template size");
1183
+ }
1174
1184
  }
1175
1185
 
1176
1186
  mrb_str_resize(mrb, result, ridx);
@@ -11,7 +11,7 @@ MRuby::Gem::Specification.new('mruby-socket') do |spec|
11
11
  spec.linker.libraries << "ws2_32"
12
12
  end
13
13
 
14
- spec.add_dependency('mruby-io')
15
- spec.add_dependency('mruby-pack')
14
+ spec.add_dependency('mruby-io', :core => 'mruby-io')
15
+ spec.add_dependency('mruby-pack', :core => 'mruby-pack')
16
16
  # spec.add_dependency('mruby-mtest')
17
17
  end
@@ -2,18 +2,54 @@
2
2
  #include <stdlib.h>
3
3
 
4
4
  #include "mruby.h"
5
+ #include "mruby/error.h"
6
+
7
+ #if defined(_WIN32) || defined(_WIN64)
8
+
9
+ #include <io.h>
10
+
11
+ #ifdef _MSC_VER
12
+
13
+ #include <fcntl.h>
14
+ #include <sys/stat.h>
15
+ #define close _close
16
+ #define unlink _unlink
17
+
18
+ static int
19
+ mkstemp(char *p)
20
+ {
21
+ int fd;
22
+ char* fname = _mktemp(p);
23
+ if (fname == NULL)
24
+ return -1;
25
+ fd = open(fname, O_RDWR | O_CREAT | O_EXCL, _S_IREAD | _S_IWRITE);
26
+ if (fd >= 0)
27
+ return fd;
28
+ return -1;
29
+ }
30
+ #endif
31
+
32
+ #else
33
+
34
+ #include <unistd.h>
5
35
 
6
- #ifdef _WIN32
7
- #define tempnam _tempnam
8
36
  #endif
9
37
 
10
38
  mrb_value
11
39
  mrb_sockettest_tmppath(mrb_state *mrb, mrb_value klass)
12
40
  {
13
- char *tmp = tempnam(NULL, "mruby-socket");
14
- mrb_value str = mrb_str_new_cstr(mrb, tmp);
15
- free(tmp);
16
- return str;
41
+ char name[] = "mruby-socket.XXXXXXXX";
42
+ int fd = mkstemp(name);
43
+ if (fd == -1) {
44
+ mrb_sys_fail(mrb, 0);
45
+ }
46
+ if (close(fd) == -1) {
47
+ mrb_sys_fail(mrb, 0);
48
+ }
49
+ if (unlink(name) == -1) {
50
+ mrb_sys_fail(mrb, 0);
51
+ }
52
+ return mrb_str_new_cstr(mrb, name);
17
53
  }
18
54
 
19
55
  mrb_value
@@ -31,6 +31,7 @@ mrb_init_mrbtest(mrb_state *mrb)
31
31
 
32
32
  if (mrb->exc) {
33
33
  mrb_print_error(mrb);
34
+ mrb_close(mrb);
34
35
  exit(EXIT_FAILURE);
35
36
  }
36
37
  mrb_close(core_test);
@@ -101,6 +101,7 @@ MRuby::Gem::Specification.new('mruby-test') do |spec|
101
101
  end
102
102
  f.puts %Q[ if (mrb2->exc) {]
103
103
  f.puts %Q[ mrb_print_error(mrb2);]
104
+ f.puts %Q[ mrb_close(mrb2);]
104
105
  f.puts %Q[ exit(EXIT_FAILURE);]
105
106
  f.puts %Q[ }]
106
107
  f.puts %Q[ mrb_const_set(mrb2, mrb_obj_value(mrb2->object_class), mrb_intern_lit(mrb2, "GEMNAME"), mrb_str_new(mrb2, "#{g.name}", #{g.name.length}));]
@@ -67,6 +67,11 @@ double round(double x) {
67
67
  /* define following macro to use probably faster timegm() on the platform */
68
68
  /* #define USE_SYSTEM_TIMEGM */
69
69
 
70
+ /* time_t */
71
+ /* If your platform supports time_t as uint (e.g. uint32_t, uint64_t), */
72
+ /* uncomment following macro. */
73
+ /* #define MRB_TIME_T_UINT */
74
+
70
75
  /** end of Time class configuration */
71
76
 
72
77
  #ifndef NO_GETTIMEOFDAY
@@ -138,8 +143,14 @@ timegm(struct tm *tm)
138
143
  int i;
139
144
  unsigned int *nday = (unsigned int*) ndays[is_leapyear(tm->tm_year+1900)];
140
145
 
141
- for (i = 70; i < tm->tm_year; ++i)
142
- r += is_leapyear(i+1900) ? 366*24*60*60 : 365*24*60*60;
146
+ static const int epoch_year = 70;
147
+ if(tm->tm_year >= epoch_year) {
148
+ for (i = epoch_year; i < tm->tm_year; ++i)
149
+ r += is_leapyear(i+1900) ? 366*24*60*60 : 365*24*60*60;
150
+ } else {
151
+ for (i = tm->tm_year; i < epoch_year; ++i)
152
+ r -= is_leapyear(i+1900) ? 366*24*60*60 : 365*24*60*60;
153
+ }
143
154
  for (i = 0; i < tm->tm_mon; ++i)
144
155
  r += nday[i] * 24 * 60 * 60;
145
156
  r += (tm->tm_mday - 1) * 24 * 60 * 60;
@@ -234,13 +245,21 @@ time_alloc(mrb_state *mrb, double sec, double usec, enum mrb_timezone timezone)
234
245
 
235
246
  mrb_check_num_exact(mrb, (mrb_float)sec);
236
247
  mrb_check_num_exact(mrb, (mrb_float)usec);
237
-
248
+ #ifndef MRB_TIME_T_UINT
238
249
  if (sizeof(time_t) == 4 && (sec > (double)INT32_MAX || (double)INT32_MIN > sec)) {
239
250
  goto out_of_range;
240
251
  }
241
252
  if (sizeof(time_t) == 8 && (sec > (double)INT64_MAX || (double)INT64_MIN > sec)) {
242
253
  goto out_of_range;
243
254
  }
255
+ #else
256
+ if (sizeof(time_t) == 4 && (sec > (double)UINT32_MAX || (double)0 > sec)) {
257
+ goto out_of_range;
258
+ }
259
+ if (sizeof(time_t) == 8 && (sec > (double)UINT64_MAX || (double)0 > sec)) {
260
+ goto out_of_range;
261
+ }
262
+ #endif
244
263
  tsec = (time_t)sec;
245
264
  if ((sec > 0 && tsec < 0) || (sec < 0 && (double)tsec > sec)) {
246
265
  out_of_range:
@@ -226,3 +226,7 @@ assert('2000 times 500us make a second') do
226
226
  end
227
227
  t.usec == 0
228
228
  end
229
+
230
+ assert('Time.gm with Dec 31 23:59:59 1969 raise ArgumentError') do
231
+ assert_raise(ArgumentError) {Time.gm(1969, 12, 31, 23, 59, 59)}
232
+ end
@@ -200,28 +200,27 @@ class Array
200
200
 
201
201
  ##
202
202
  # Quick sort
203
- # a : the array to sort
204
203
  # left : the beginning of sort region
205
204
  # right : the end of sort region
206
- def __sort_sub__(a, left, right, &block)
205
+ def __sort_sub__(left, right, &block)
207
206
  if left < right
208
207
  i = left
209
208
  j = right
210
- pivot = a[i + (j - i) / 2]
209
+ pivot = self[i + (j - i) / 2]
211
210
  while true
212
- while ((block)? block.call(a[i], pivot): (a[i] <=> pivot)) < 0
211
+ while ((block)? block.call(self[i], pivot): (self[i] <=> pivot)) < 0
213
212
  i += 1
214
213
  end
215
- while ((block)? block.call(pivot, a[j]): (pivot <=> a[j])) < 0
214
+ while ((block)? block.call(pivot, self[j]): (pivot <=> self[j])) < 0
216
215
  j -= 1
217
216
  end
218
217
  break if (i >= j)
219
- tmp = a[i]; a[i] = a[j]; a[j] = tmp;
218
+ tmp = self[i]; self[i] = self[j]; self[j] = tmp;
220
219
  i += 1
221
220
  j -= 1
222
221
  end
223
- __sort_sub__(a, left, i-1, &block)
224
- __sort_sub__(a, j+1, right, &block)
222
+ __sort_sub__(left, i-1, &block)
223
+ __sort_sub__(j+1, right, &block)
225
224
  end
226
225
  end
227
226
  # private :__sort_sub__
@@ -232,7 +231,7 @@ class Array
232
231
  def sort!(&block)
233
232
  size = self.size
234
233
  if size > 1
235
- __sort_sub__(self, 0, size - 1, &block)
234
+ __sort_sub__(0, size - 1, &block)
236
235
  end
237
236
  self
238
237
  end
@@ -325,7 +325,7 @@ module Enumerable
325
325
  #
326
326
  # ISO 15.3.2.2.19
327
327
  def sort(&block)
328
- self.map{|*val| val.__svalue}.sort
328
+ self.map{|*val| val.__svalue}.sort(&block)
329
329
  end
330
330
 
331
331
  ##
@@ -256,7 +256,6 @@ mrb_ary_resize(mrb_state *mrb, mrb_value ary, mrb_int new_len)
256
256
  ary_modify(mrb, a);
257
257
  old_len = RARRAY_LEN(ary);
258
258
  if (old_len != new_len) {
259
- ARY_SET_LEN(a, new_len);
260
259
  if (new_len < old_len) {
261
260
  ary_shrink_capa(mrb, a);
262
261
  }
@@ -264,6 +263,7 @@ mrb_ary_resize(mrb_state *mrb, mrb_value ary, mrb_int new_len)
264
263
  ary_expand_capa(mrb, a, new_len);
265
264
  ary_fill_with_nil(ARY_PTR(a) + old_len, new_len - old_len);
266
265
  }
266
+ ARY_SET_LEN(a, new_len);
267
267
  }
268
268
 
269
269
  return ary;
@@ -593,7 +593,7 @@ mrb_get_argv(mrb_state *mrb)
593
593
  n: Symbol [mrb_sym]
594
594
  d: Data [void*,mrb_data_type const] 2nd argument will be used to check data type so it won't be modified
595
595
  I: Inline struct [void*]
596
- &: Block [mrb_value]
596
+ &: Block [mrb_value] &! raises exception if no block given
597
597
  *: rest argument [mrb_value*,mrb_int] The rest of the arguments as an array; *! avoid copy of the stack
598
598
  |: optional Following arguments are optional
599
599
  ?: optional given [mrb_bool] true if preceding argument (optional) is given
@@ -937,6 +937,12 @@ mrb_get_args(mrb_state *mrb, const char *format, ...)
937
937
  else {
938
938
  bp = mrb->c->stack + mrb->c->ci->argc + 1;
939
939
  }
940
+ if (*format == '!') {
941
+ format ++;
942
+ if (mrb_nil_p(*bp)) {
943
+ mrb_raise(mrb, E_ARGUMENT_ERROR, "no block given");
944
+ }
945
+ }
940
946
  *p = *bp;
941
947
  }
942
948
  break;
@@ -1744,7 +1750,7 @@ mrb_class_path(mrb_state *mrb, struct RClass *c)
1744
1750
  return mrb_class_find_path(mrb, c);
1745
1751
  }
1746
1752
  else if (mrb_symbol_p(path)) {
1747
- /* topleve class/module */
1753
+ /* toplevel class/module */
1748
1754
  const char *str;
1749
1755
  mrb_int len;
1750
1756
 
@@ -229,7 +229,8 @@ mrb_exc_set(mrb_state *mrb, mrb_value exc)
229
229
  }
230
230
  else {
231
231
  mrb->exc = mrb_obj_ptr(exc);
232
- if ((struct RBasic*)mrb->exc == mrb->gc.arena[mrb->gc.arena_idx-1]) {
232
+ if (mrb->gc.arena_idx > 0 &&
233
+ (struct RBasic*)mrb->exc == mrb->gc.arena[mrb->gc.arena_idx-1]) {
233
234
  mrb->gc.arena_idx--;
234
235
  }
235
236
  if (!mrb->gc.out_of_memory) {
@@ -658,7 +658,7 @@ gc_mark_children(mrb_state *mrb, mrb_gc *gc, struct RBasic *obj)
658
658
  struct REnv *e = (struct REnv*)obj;
659
659
  mrb_int i, len;
660
660
 
661
- if (MRB_ENV_STACK_SHARED_P(e) && e->cxt->fib) {
661
+ if (MRB_ENV_STACK_SHARED_P(e) && e->cxt && e->cxt->fib) {
662
662
  mrb_gc_mark(mrb, (struct RBasic*)e->cxt->fib);
663
663
  }
664
664
  len = MRB_ENV_STACK_LEN(e);
@@ -569,8 +569,8 @@ arg_error:
569
569
  mrb_raise(mrb, E_ARGUMENT_ERROR, "base specified for non string value");
570
570
  }
571
571
  tmp = convert_type(mrb, val, "Integer", "to_int", FALSE);
572
- if (mrb_nil_p(tmp)) {
573
- return mrb_to_integer(mrb, val, "to_i");
572
+ if (mrb_nil_p(tmp) || !mrb_fixnum_p(tmp)) {
573
+ tmp = mrb_to_integer(mrb, val, "to_i");
574
574
  }
575
575
  return tmp;
576
576
  }
@@ -926,7 +926,7 @@ mrb_str_cmp_m(mrb_state *mrb, mrb_value str1)
926
926
  else {
927
927
  mrb_value tmp = mrb_funcall(mrb, str2, "<=>", 1, str1);
928
928
 
929
- if (!mrb_nil_p(tmp)) return mrb_nil_value();
929
+ if (mrb_nil_p(tmp)) return mrb_nil_value();
930
930
  if (!mrb_fixnum_p(tmp)) {
931
931
  return mrb_funcall(mrb, mrb_fixnum_value(0), "-", 1, tmp);
932
932
  }
@@ -2542,10 +2542,10 @@ mrb_str_dump(mrb_state *mrb, mrb_value str)
2542
2542
  }
2543
2543
  else {
2544
2544
  *q++ = '\\';
2545
- q[2] = '0' + c % 8; c /= 8;
2546
- q[1] = '0' + c % 8; c /= 8;
2547
- q[0] = '0' + c % 8;
2548
- q += 3;
2545
+ *q++ = 'x';
2546
+ q[1] = mrb_digitmap[c % 16]; c /= 16;
2547
+ q[0] = mrb_digitmap[c % 16];
2548
+ q += 2;
2549
2549
  }
2550
2550
  }
2551
2551
  }
@@ -2685,9 +2685,9 @@ mrb_str_inspect(mrb_state *mrb, mrb_value str)
2685
2685
  }
2686
2686
  else {
2687
2687
  buf[0] = '\\';
2688
- buf[3] = '0' + c % 8; c /= 8;
2689
- buf[2] = '0' + c % 8; c /= 8;
2690
- buf[1] = '0' + c % 8;
2688
+ buf[1] = 'x';
2689
+ buf[3] = mrb_digitmap[c % 16]; c /= 16;
2690
+ buf[2] = mrb_digitmap[c % 16];
2691
2691
  mrb_str_cat(mrb, result, buf, 4);
2692
2692
  continue;
2693
2693
  }
@@ -955,27 +955,61 @@ find_class_sym(mrb_state *mrb, struct RClass *outer, struct RClass *c)
955
955
  return arg.sym;
956
956
  }
957
957
 
958
+ static struct RClass*
959
+ outer_class(mrb_state *mrb, struct RClass *c)
960
+ {
961
+ mrb_value ov;
962
+
963
+ ov = mrb_obj_iv_get(mrb, (struct RObject*)c, mrb_intern_lit(mrb, "__outer__"));
964
+ if (mrb_nil_p(ov)) return NULL;
965
+ switch (mrb_type(ov)) {
966
+ case MRB_TT_CLASS:
967
+ case MRB_TT_MODULE:
968
+ return mrb_class_ptr(ov);
969
+ default:
970
+ break;
971
+ }
972
+ return NULL;
973
+ }
974
+
975
+ static mrb_bool
976
+ detect_outer_loop(mrb_state *mrb, struct RClass *c)
977
+ {
978
+ struct RClass *t = c; /* tortoise */
979
+ struct RClass *h = c; /* hare */
980
+
981
+ for (;;) {
982
+ if (h == NULL) return FALSE;
983
+ h = outer_class(mrb, h);
984
+ if (h == NULL) return FALSE;
985
+ h = outer_class(mrb, h);
986
+ t = outer_class(mrb, t);
987
+ if (t == h) return TRUE;
988
+ }
989
+ }
990
+
958
991
  mrb_value
959
992
  mrb_class_find_path(mrb_state *mrb, struct RClass *c)
960
993
  {
961
- mrb_value outer, path;
994
+ struct RClass *outer;
995
+ mrb_value path;
962
996
  mrb_sym name;
963
997
  const char *str;
964
998
  mrb_int len;
965
- mrb_sym osym = mrb_intern_lit(mrb, "__outer__");
966
999
 
967
- outer = mrb_obj_iv_get(mrb, (struct RObject*)c, osym);
968
- if (mrb_nil_p(outer)) return outer;
969
- name = find_class_sym(mrb, mrb_class_ptr(outer), c);
1000
+ if (detect_outer_loop(mrb, c)) return mrb_nil_value();
1001
+ outer = outer_class(mrb, c);
1002
+ if (outer == NULL) return mrb_nil_value();
1003
+ name = find_class_sym(mrb, outer, c);
970
1004
  if (name == 0) return mrb_nil_value();
971
- str = mrb_class_name(mrb, mrb_class_ptr(outer));
1005
+ str = mrb_class_name(mrb, outer);
972
1006
  path = mrb_str_new_capa(mrb, 40);
973
1007
  mrb_str_cat_cstr(mrb, path, str);
974
1008
  mrb_str_cat_cstr(mrb, path, "::");
975
1009
 
976
1010
  str = mrb_sym2name_len(mrb, name, &len);
977
1011
  mrb_str_cat(mrb, path, str, len);
978
- iv_del(mrb, c->iv, osym, NULL);
1012
+ iv_del(mrb, c->iv, mrb_intern_lit(mrb, "__outer__"), NULL);
979
1013
  iv_put(mrb, c->iv, mrb_intern_lit(mrb, "__classname__"), path);
980
1014
  mrb_field_write_barrier_value(mrb, (struct RBasic*)c, path);
981
1015
  return path;
@@ -516,7 +516,7 @@ mrb_exec_irep(mrb_state *mrb, mrb_value self, struct RProc *p)
516
516
  }
517
517
  ci->nregs = p->body.irep->nregs;
518
518
  if (ci->argc < 0) keep = 3;
519
- else keep = ci->argc + 1;
519
+ else keep = ci->argc + 2;
520
520
  if (ci->nregs < keep) {
521
521
  stack_extend(mrb, keep);
522
522
  }
@@ -1351,6 +1351,7 @@ RETRY_TRY_BLOCK:
1351
1351
  for (n=0; n<a; n++) {
1352
1352
  proc = mrb->c->ensure[epos+n];
1353
1353
  mrb->c->ensure[epos+n] = NULL;
1354
+ if (proc == NULL) continue;
1354
1355
  irep = proc->body.irep;
1355
1356
  ci = cipush(mrb);
1356
1357
  ci->mid = ci[-1].mid;
@@ -1661,6 +1662,9 @@ RETRY_TRY_BLOCK:
1661
1662
  if (MRB_METHOD_CFUNC_P(m)) {
1662
1663
  mrb_value v;
1663
1664
  ci->nregs = (argc < 0) ? 3 : n+2;
1665
+ if (MRB_METHOD_PROC_P(m)) {
1666
+ ci->proc = MRB_METHOD_PROC(m);
1667
+ }
1664
1668
  v = MRB_METHOD_CFUNC(m)(mrb, recv);
1665
1669
  mrb_gc_arena_restore(mrb, ai);
1666
1670
  if (mrb->exc) goto L_RAISE;
@@ -2934,9 +2938,6 @@ RETRY_TRY_BLOCK:
2934
2938
  CASE(OP_STOP) {
2935
2939
  /* stop VM */
2936
2940
  L_STOP:
2937
- while (mrb->c->ci > mrb->c->cibase) {
2938
- cipop(mrb);
2939
- }
2940
2941
  while (mrb->c->eidx > 0) {
2941
2942
  ecall(mrb);
2942
2943
  }