esruby 0.0.9 → 0.0.10

Sign up to get free protection for your applications and to get access to all the features.
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
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: c4a8a81262ba6285384d5346b58cdc2022ba9624
4
- data.tar.gz: bfff4025687aeed38eb7048ab2667986903e6f74
3
+ metadata.gz: a16d0112d53861ad14f8c825229b924f1a980cdf
4
+ data.tar.gz: 0df764960a1cdff6f71723c596825a92995f4709
5
5
  SHA512:
6
- metadata.gz: 1b4eccc319bbc4c23958d287920e51a37c35b4b2101e1b6748d63cf2d34717fe88ad7c3a48179fec8ae906e0ab08a4ef2fef4ee756a994ee1da2ffc728178233
7
- data.tar.gz: 8c42461e416dbd33d53ab2fe903e96a5782b9ec87cacdfc2029991406adaeb7054e16e6a6e70afbd07966e99e7b0770b10292f91832eb38193e3a24a5244c00c
6
+ metadata.gz: 233b64432005b46c61fdcad9a06ef7e9a84f9a1eb79ce02ac38c6172a1e0c8a16a584f6e35b8b340b412d34e84a608468356a67fe6677df5e1e0d13e76957c30
7
+ data.tar.gz: 65d573fe29d8430b7ac4a55a8590c3e1396f0a43cc559d1050834b73eda6fcf0b3de97ba0314965463424f9ddbbe811c58b7811ff6ccbaae1c3ba0b5f50ef720
data/README.md CHANGED
@@ -1,9 +1,9 @@
1
- # ESRuby
1
+ # esruby
2
2
  This project brings *mruby* to the browser. It uses [*emscripten*](https://github.com/kripken/emscripten) to compile the mruby source code into
3
3
  JavaScript (ECMAScript) and runs in the browser. It is heavily based off [*webruby*](https://github.com/xxuejie/webruby) but has been adjusted to work with the updates to *emscripten* and *mruby*.
4
4
 
5
5
  # Install
6
- *ESRuby* depends on [emsdk](http://kripken.github.io/emscripten-site/index.html) to provide a tool chain consisting of *emscripten* and *LLVM*. Although the tool chain is available from `apt-get` we will need to build emscripten from source using my branch as I have introduced some new features that have not made it into the release yet.
6
+ *esruby* depends on [emsdk](http://kripken.github.io/emscripten-site/index.html) to provide a tool chain consisting of *emscripten* and *LLVM*. Although the tool chain is available from `apt-get` we will need to build emscripten from source using my branch as I have introduced some new features that have not made it into the release yet.
7
7
 
8
8
  * we will start with a clean instance of Ubuntu 16.04 with ruby MRI installed
9
9
  * `sudo apt-get install build-essential cmake`
data/lib/esruby/build.rb CHANGED
@@ -13,7 +13,7 @@ module ESRuby
13
13
  new_build
14
14
  end
15
15
 
16
- def_delegators :@configuration, :root_directory, :ruby_sources, :build_directory,
16
+ def_delegators :@configuration, :root_directory, :build_directory,
17
17
  :build_mode, :output, :mruby_directory, :gems
18
18
 
19
19
  def initialize(&block)
@@ -55,10 +55,13 @@ module ESRuby
55
55
  js_files += specification.appended_js_sources
56
56
  end
57
57
  js_files += @configuration.appended_js_sources
58
- js_files << "#{gem_directory}/resources/js/esruby.js"
59
58
  js_files
60
59
  end
61
60
 
61
+ def ruby_sources
62
+ @configuration.ruby_sources + ["#{gem_directory}/resources/rb/append.rb"]
63
+ end
64
+
62
65
  def build_mruby_config
63
66
  template = File.read("#{gem_directory}/resources/build_config.eruby")
64
67
  eruby = Erubis::Eruby.new(template)
@@ -117,8 +120,8 @@ module ESRuby
117
120
  js_arguments += appended_js_sources.map { |path| "--post-js #{path}" }.join(" ")
118
121
  RakeFileUtils.sh "#{mrbc} -B app -o #{build_directory}/app.c #{ruby_sources.join(" ")}"
119
122
  RakeFileUtils.sh "emcc --bind -I #{mruby_directory}/include #{build_directory}/app.c -o #{build_directory}/app.o #{build_directory}/emscripten/lib/libmruby.a -lm #{js_arguments} #{optimization_argument} #{closure_argument} #{debug_argument}"
120
- RakeFileUtils.sh "emcc -std=c++11 --bind -I #{mruby_directory}/include #{gem_directory}/resources/cpp/esruby.cpp -o #{build_directory}/esruby.o #{build_directory}/emscripten/lib/libmruby.a -lm #{js_arguments} #{optimization_argument} #{closure_argument} #{debug_argument}"
121
- RakeFileUtils.sh "emcc --bind -I #{mruby_directory}/include -o #{build_directory}/output.js #{build_directory}/app.o #{build_directory}/esruby.o #{build_directory}/emscripten/lib/libmruby.a -lm #{js_arguments} #{optimization_argument} #{closure_argument} #{debug_argument}"
123
+ RakeFileUtils.sh "emcc -std=c++11 --bind -I #{mruby_directory}/include #{gem_directory}/resources/cpp/main.cpp -o #{build_directory}/main.o #{build_directory}/emscripten/lib/libmruby.a -lm #{js_arguments} #{optimization_argument} #{closure_argument} #{debug_argument}"
124
+ RakeFileUtils.sh "emcc --bind -I #{mruby_directory}/include -o #{build_directory}/output.js #{build_directory}/app.o #{build_directory}/main.o #{build_directory}/emscripten/lib/libmruby.a -lm #{js_arguments} #{optimization_argument} #{closure_argument} #{debug_argument}"
122
125
  #if build.build_mode == 'production'
123
126
  # sh "java -jar #{PROJECT_DIRECTORY}/emsdk/emscripten/incoming/third_party/closure-compiler/compiler.jar --js #{build.absolute_build_directory}/output.js --js_output_file #{build.absolute_output}"
124
127
  #else
@@ -46,6 +46,7 @@ MRuby::CrossBuild.new('app') do |conf|
46
46
  end
47
47
 
48
48
  conf.gembox('default')
49
+ #conf.gem :github => 'robfors/esruby-esruby'
49
50
  <% for gem in gems %>
50
51
  conf.gem(<%= gem.inspect %>)
51
52
  <% end %>
@@ -0,0 +1,14 @@
1
+ #include "/media/file_server/file_drive/projects/esruby/esruby-esruby/include/esruby.hpp"
2
+
3
+ // we need to load the esruby bindings here, see issue:
4
+ // https://github.com/kripken/emscripten/issues/5537
5
+ // although you can observe that the bindings in esruby-bind do work
6
+ // so im not sure what the problem is
7
+ // idealy i would like to use a compiler option like EXPORTED_FUNCTIONS, for classes
8
+ EMSCRIPTEN_BINDINGS(esruby)
9
+ {
10
+ emscripten::class_<ESRuby>("ESRuby")
11
+ .class_function("start", &ESRuby::start)
12
+ .class_function("stop", &ESRuby::stop)
13
+ ;
14
+ }
@@ -26,6 +26,11 @@ conf.gem :github => 'masuidrive/mrbgems-example', :branch => 'master'
26
26
  conf.gem :bitbucket => 'mruby/mrbgems-example', :branch => 'master'
27
27
  ```
28
28
 
29
+ You can specify the sub directory of the repository with `:path` option:
30
+ ```ruby
31
+ conf.gem github: 'mruby/mruby', path: 'mrbgems/mruby-socket'
32
+ ```
33
+
29
34
  To use mrbgem from [mgem-list](https://github.com/mruby/mgem-list) use `:mgem` option:
30
35
  ```ruby
31
36
  conf.gem :mgem => 'mruby-yaml'
@@ -36,12 +36,10 @@
36
36
  /* size of the method cache (need to be the power of 2) */
37
37
  //#define MRB_METHOD_CACHE_SIZE (1<<7)
38
38
 
39
- /* add -DMRB_METHOD_TABLE_INLINE unless platform uses MSB of pointers */
39
+ /* add -DMRB_METHOD_TABLE_INLINE to reduce the size of method table */
40
+ /* MRB_METHOD_TABLE_INLINE requires LSB of function pointers to be zero */
41
+ /* you might need to specify --falign-functions=n (where n>1) */
40
42
  //#define MRB_METHOD_TABLE_INLINE
41
- /* turn MRB_METHOD_TABLE_INLINE on for linux by default */
42
- #if !defined(MRB_METHOD_TABLE_INLINE) && defined(__linux__)
43
- # define MRB_METHOD_TABLE_INLINE
44
- #endif
45
43
 
46
44
  /* add -DMRB_INT16 to use 16bit integer for mrb_int; conflict with MRB_INT64 */
47
45
  //#define MRB_INT16
@@ -98,8 +98,8 @@ MRB_API mrb_value mrb_proc_cfunc_env_get(mrb_state*, mrb_int);
98
98
 
99
99
  #ifdef MRB_METHOD_TABLE_INLINE
100
100
 
101
- #define MRB_METHOD_FUNC_FL ((uintptr_t)1U<<(sizeof(uintptr_t)*8-1))
102
- #define MRB_METHOD_FUNC_P(m) ((uintptr_t)(m)&MRB_METHOD_FUNC_FL)
101
+ #define MRB_METHOD_FUNC_FL ((uintptr_t)1)
102
+ #define MRB_METHOD_FUNC_P(m) (((uintptr_t)(m))&MRB_METHOD_FUNC_FL)
103
103
  #define MRB_METHOD_FUNC(m) ((mrb_func_t)((uintptr_t)(m)&(~MRB_METHOD_FUNC_FL)))
104
104
  #define MRB_METHOD_FROM_FUNC(m,fn) m=(mrb_method_t)((struct RProc*)((uintptr_t)(fn)|MRB_METHOD_FUNC_FL))
105
105
  #define MRB_METHOD_FROM_PROC(m,pr) m=(mrb_method_t)(struct RProc*)(pr)
@@ -829,22 +829,22 @@ MRB_API struct RClass * mrb_define_module_under(mrb_state *mrb, struct RClass *o
829
829
  *
830
830
  * Must be a C string composed of the following format specifiers:
831
831
  *
832
- * | char | Ruby type | C types | Notes |
832
+ * | char | Ruby type | C types | Notes |
833
833
  * |:----:|----------------|-------------------|----------------------------------------------------|
834
834
  * | `o` | {Object} | {mrb_value} | Could be used to retrieve any type of argument |
835
835
  * | `C` | {Class}/{Module} | {mrb_value} | |
836
836
  * | `S` | {String} | {mrb_value} | when `!` follows, the value may be `nil` |
837
837
  * | `A` | {Array} | {mrb_value} | when `!` follows, the value may be `nil` |
838
838
  * | `H` | {Hash} | {mrb_value} | when `!` follows, the value may be `nil` |
839
- * | `s` | {String} | char *, {mrb_int} | Receive two arguments; `s!` gives (`NULL`,`0`) for `nil` |
839
+ * | `s` | {String} | char *, {mrb_int} | Receive two arguments; `s!` gives (`NULL`,`0`) for `nil` |
840
840
  * | `z` | {String} | char * | `NULL` terminated string; `z!` gives `NULL` for `nil` |
841
841
  * | `a` | {Array} | {mrb_value} *, {mrb_int} | Receive two arguments; `a!` gives (`NULL`,`0`) for `nil` |
842
842
  * | `f` | {Float} | {mrb_float} | |
843
843
  * | `i` | {Integer} | {mrb_int} | |
844
844
  * | `b` | boolean | {mrb_bool} | |
845
845
  * | `n` | {Symbol} | {mrb_sym} | |
846
- * | `&` | block | {mrb_value} | |
847
- * | `*` | rest arguments | {mrb_value} *, {mrb_int} | Receive the rest of arguments as an array. |
846
+ * | `&` | block | {mrb_value} | &! raises exception if no block given. |
847
+ * | `*` | rest arguments | {mrb_value} *, {mrb_int} | Receive the rest of arguments as an array; *! avoid copy of the stack. |
848
848
  * | &vert; | optional | | After this spec following specs would be optional. |
849
849
  * | `?` | optional given | {mrb_bool} | `TRUE` if preceding argument is given. Used to check optional argument is given. |
850
850
  *
@@ -1225,6 +1225,13 @@ MRB_API mrb_value mrb_fiber_resume(mrb_state *mrb, mrb_value fib, mrb_int argc,
1225
1225
  */
1226
1226
  MRB_API mrb_value mrb_fiber_yield(mrb_state *mrb, mrb_int argc, const mrb_value *argv);
1227
1227
 
1228
+ /*
1229
+ * Check if a Fiber is alive
1230
+ *
1231
+ * @mrbgem mruby-fiber
1232
+ */
1233
+ MRB_API mrb_value mrb_fiber_alive_p(mrb_state *mrb, mrb_value fib);
1234
+
1228
1235
  /*
1229
1236
  * FiberError reference
1230
1237
  *
@@ -76,9 +76,6 @@ module MRuby
76
76
 
77
77
  if params[:core]
78
78
  gemdir = "#{root}/mrbgems/#{params[:core]}"
79
- elsif params[:path]
80
- require 'pathname'
81
- gemdir = Pathname.new(params[:path]).absolute? ? params[:path] : "#{root}/#{params[:path]}"
82
79
  elsif params[:git]
83
80
  url = params[:git]
84
81
  gemdir = "#{gem_clone_dir}/#{url.match(/([-\w]+)(\.[-\w]+|)$/).to_a[1]}"
@@ -108,6 +105,11 @@ module MRuby
108
105
  # Jump to the top of the branch
109
106
  git.run_checkout gemdir, branch if $pull_gems
110
107
  end
108
+
109
+ gemdir << "/#{params[:path]}" if params[:path]
110
+ elsif params[:path]
111
+ require 'pathname'
112
+ gemdir = Pathname.new(params[:path]).absolute? ? params[:path] : "#{root}/#{params[:path]}"
111
113
  else
112
114
  fail "unknown gem option #{params}"
113
115
  end
@@ -334,6 +334,7 @@ EOS
334
334
  attr_accessor :host_target, :build_target
335
335
 
336
336
  def initialize(name, build_dir=nil, &block)
337
+ @endian = nil
337
338
  @test_runner = Command::CrossTestRunner.new(self)
338
339
  super
339
340
  end
@@ -343,6 +344,7 @@ EOS
343
344
  end
344
345
 
345
346
  def run_test
347
+ @test_runner.runner_options << ' -v' if $verbose
346
348
  mrbtest = exefile("#{build_dir}/bin/mrbtest")
347
349
  if (@test_runner.command == nil)
348
350
  puts "You should run #{mrbtest} on target device."
@@ -351,5 +353,26 @@ EOS
351
353
  @test_runner.run(mrbtest)
352
354
  end
353
355
  end
356
+
357
+ def big_endian
358
+ if @endian
359
+ puts "Endian has already specified as #{@endian}."
360
+ return
361
+ end
362
+ @endian = :big
363
+ @mrbc.compile_options += ' -E'
364
+ compilers.each do |c|
365
+ c.defines += %w(MRB_ENDIAN_BIG)
366
+ end
367
+ end
368
+
369
+ def little_endian
370
+ if @endian
371
+ puts "Endian has already specified as #{@endian}."
372
+ return
373
+ end
374
+ @endian = :little
375
+ @mrbc.compile_options += ' -e'
376
+ end
354
377
  end # CrossBuild
355
378
  end # MRuby
@@ -176,6 +176,7 @@ module MRuby
176
176
  f.puts %Q[ mrb_load_irep(mrb, gem_mrblib_irep_#{funcname});]
177
177
  f.puts %Q[ if (mrb->exc) {]
178
178
  f.puts %Q[ mrb_print_error(mrb);]
179
+ f.puts %Q[ mrb_close(mrb);]
179
180
  f.puts %Q[ exit(EXIT_FAILURE);]
180
181
  f.puts %Q[ }]
181
182
  end
@@ -323,20 +324,22 @@ module MRuby
323
324
  @ary.empty?
324
325
  end
325
326
 
327
+ def default_gem_params dep
328
+ if dep[:default]; dep
329
+ elsif File.exist? "#{MRUBY_ROOT}/mrbgems/#{dep[:gem]}" # check core
330
+ { :gem => dep[:gem], :default => { :core => dep[:gem] } }
331
+ else # fallback to mgem-list
332
+ { :gem => dep[:gem], :default => { :mgem => dep[:gem] } }
333
+ end
334
+ end
335
+
326
336
  def generate_gem_table build
327
337
  gem_table = @ary.reduce({}) { |res,v| res[v.name] = v; res }
328
338
 
329
339
  default_gems = []
330
340
  each do |g|
331
341
  g.dependencies.each do |dep|
332
- unless gem_table.key? dep[:gem]
333
- if dep[:default]; default_gems << dep
334
- elsif File.exist? "#{MRUBY_ROOT}/mrbgems/#{dep[:gem]}" # check core
335
- default_gems << { :gem => dep[:gem], :default => { :core => dep[:gem] } }
336
- else # fallback to mgem-list
337
- default_gems << { :gem => dep[:gem], :default => { :mgem => dep[:gem] } }
338
- end
339
- end
342
+ default_gems << default_gem_params(dep) unless gem_table.key? dep[:gem]
340
343
  end
341
344
  end
342
345
 
@@ -348,11 +351,7 @@ module MRuby
348
351
  spec.setup
349
352
 
350
353
  spec.dependencies.each do |dep|
351
- unless gem_table.key? dep[:gem]
352
- if dep[:default]; default_gems << dep
353
- else default_gems << { :gem => dep[:gem], :default => { :mgem => dep[:gem] } }
354
- end
355
- end
354
+ default_gems << default_gem_params(dep) unless gem_table.key? dep[:gem]
356
355
  end
357
356
  gem_table[spec.name] = spec
358
357
  end
@@ -1,4 +1,10 @@
1
1
  MRuby::GemBox.new do |conf|
2
+ # Use standard IO/File class
3
+ conf.gem :core => "mruby-io"
4
+
5
+ # Use standard Array#pack, String#unpack methods
6
+ conf.gem :core => "mruby-pack"
7
+
2
8
  # Use standard Kernel#sprintf method
3
9
  conf.gem :core => "mruby-sprintf"
4
10
 
@@ -149,8 +149,14 @@ new_label(codegen_scope *s)
149
149
  static inline int
150
150
  genop(codegen_scope *s, mrb_code i)
151
151
  {
152
- if (s->pc == s->icapa) {
152
+ if (s->pc >= s->icapa) {
153
153
  s->icapa *= 2;
154
+ if (s->pc >= MAXARG_sBx) {
155
+ codegen_error(s, "too big code block");
156
+ }
157
+ if (s->icapa > MAXARG_sBx) {
158
+ s->icapa = MAXARG_sBx;
159
+ }
154
160
  s->iseq = (mrb_code *)codegen_realloc(s, s->iseq, sizeof(mrb_code)*s->icapa);
155
161
  if (s->lines) {
156
162
  s->lines = (uint16_t*)codegen_realloc(s, s->lines, sizeof(short)*s->icapa);
@@ -781,7 +781,7 @@ new_dxstr(parser_state *p, node *a)
781
781
  static node*
782
782
  new_dsym(parser_state *p, node *a)
783
783
  {
784
- return cons((node*)NODE_DSYM, new_dstr(p, a));
784
+ return cons((node*)NODE_DSYM, a);
785
785
  }
786
786
 
787
787
  /* (:regx . (s . (opt . enc))) */
@@ -1106,9 +1106,9 @@ heredoc_end(parser_state *p)
1106
1106
  keyword__FILE__
1107
1107
  keyword__ENCODING__
1108
1108
 
1109
- %token <id> tIDENTIFIER tFID tGVAR tIVAR tCONSTANT tCVAR tLABEL
1109
+ %token <id> tIDENTIFIER tFID tGVAR tIVAR tCONSTANT tCVAR tLABEL_TAG
1110
1110
  %token <nd> tINTEGER tFLOAT tCHAR tXSTRING tREGEXP
1111
- %token <nd> tSTRING tSTRING_PART tSTRING_MID tLABEL_END
1111
+ %token <nd> tSTRING tSTRING_PART tSTRING_MID
1112
1112
  %token <nd> tNTH_REF tBACK_REF
1113
1113
  %token <num> tREGEXP_END
1114
1114
 
@@ -1180,7 +1180,7 @@ heredoc_end(parser_state *p)
1180
1180
  %right keyword_not
1181
1181
  %right '=' tOP_ASGN
1182
1182
  %left modifier_rescue
1183
- %right '?' ':'
1183
+ %right '?' ':' tLABEL_TAG
1184
1184
  %nonassoc tDOT2 tDOT3
1185
1185
  %left tOROP
1186
1186
  %left tANDOP
@@ -1926,6 +1926,10 @@ arg : lhs '=' arg_rhs
1926
1926
  {
1927
1927
  $$ = new_if(p, cond($1), $3, $6);
1928
1928
  }
1929
+ | arg '?' arg opt_nl tLABEL_TAG arg
1930
+ {
1931
+ $$ = new_if(p, cond($1), $3, $6);
1932
+ }
1929
1933
  | primary
1930
1934
  {
1931
1935
  $$ = $1;
@@ -2568,7 +2572,7 @@ lambda_body : tLAMBEG compstmt '}'
2568
2572
  {
2569
2573
  $$ = $2;
2570
2574
  }
2571
- | keyword_do_LAMBDA compstmt keyword_end
2575
+ | keyword_do_LAMBDA bodystmt keyword_end
2572
2576
  {
2573
2577
  $$ = $2;
2574
2578
  }
@@ -2861,7 +2865,7 @@ symbol : basic_symbol
2861
2865
  | tSYMBEG tSTRING_BEG string_rep tSTRING
2862
2866
  {
2863
2867
  p->lstate = EXPR_ENDARG;
2864
- $$ = new_dsym(p, push($3, $4));
2868
+ $$ = new_dsym(p, new_dstr(p, push($3, $4)));
2865
2869
  }
2866
2870
  ;
2867
2871
 
@@ -3266,25 +3270,20 @@ assoc : arg tASSOC arg
3266
3270
  void_expr_error(p, $3);
3267
3271
  $$ = cons($1, $3);
3268
3272
  }
3269
- | tLABEL arg
3270
- {
3271
- void_expr_error(p, $2);
3272
- $$ = cons(new_sym(p, $1), $2);
3273
- }
3274
- | tLABEL_END arg
3275
- {
3276
- void_expr_error(p, $2);
3277
- $$ = cons(new_sym(p, new_strsym(p, $1)), $2);
3278
- }
3279
- | tSTRING_BEG tLABEL_END arg
3273
+ | tIDENTIFIER tLABEL_TAG arg
3280
3274
  {
3281
3275
  void_expr_error(p, $3);
3282
- $$ = cons(new_sym(p, new_strsym(p, $2)), $3);
3276
+ $$ = cons(new_sym(p, $1), $3);
3283
3277
  }
3284
- | tSTRING_BEG string_rep tLABEL_END arg
3278
+ | string tLABEL_TAG arg
3285
3279
  {
3286
- void_expr_error(p, $4);
3287
- $$ = cons(new_dsym(p, push($2, $3)), $4);
3280
+ void_expr_error(p, $3);
3281
+ if ($1->car == (node*)NODE_DSTR) {
3282
+ $$ = cons(new_dsym(p, $1), $3);
3283
+ }
3284
+ else {
3285
+ $$ = cons(new_sym(p, new_strsym(p, $1)), $3);
3286
+ }
3288
3287
  }
3289
3288
  ;
3290
3289
 
@@ -3973,7 +3972,6 @@ parse_string(parser_state *p)
3973
3972
  int beg = intn(p->lex_strterm->cdr->cdr->car);
3974
3973
  int end = intn(p->lex_strterm->cdr->cdr->cdr);
3975
3974
  parser_heredoc_info *hinf = (type & STR_FUNC_HEREDOC) ? parsing_heredoc_inf(p) : NULL;
3976
- int cmd_state = p->cmd_start;
3977
3975
 
3978
3976
  if (beg == 0) beg = -3; /* should never happen */
3979
3977
  if (end == 0) end = -3;
@@ -4188,13 +4186,6 @@ parse_string(parser_state *p)
4188
4186
  return tREGEXP;
4189
4187
  }
4190
4188
  pylval.nd = new_str(p, tok(p), toklen(p));
4191
- if (IS_LABEL_POSSIBLE()) {
4192
- if (IS_LABEL_SUFFIX(0)) {
4193
- p->lstate = EXPR_BEG;
4194
- nextc(p);
4195
- return tLABEL_END;
4196
- }
4197
- }
4198
4189
 
4199
4190
  return tSTRING;
4200
4191
  }
@@ -5012,14 +5003,19 @@ parser_yylex(parser_state *p)
5012
5003
  p->lstate = EXPR_DOT;
5013
5004
  return tCOLON2;
5014
5005
  }
5015
- if (IS_END() || ISSPACE(c)) {
5006
+ if (!space_seen && IS_END()) {
5016
5007
  pushback(p, c);
5017
5008
  p->lstate = EXPR_BEG;
5018
- return ':';
5009
+ return tLABEL_TAG;
5010
+ }
5011
+ if (!ISSPACE(c) || IS_BEG()) {
5012
+ pushback(p, c);
5013
+ p->lstate = EXPR_FNAME;
5014
+ return tSYMBEG;
5019
5015
  }
5020
5016
  pushback(p, c);
5021
- p->lstate = EXPR_FNAME;
5022
- return tSYMBEG;
5017
+ p->lstate = EXPR_BEG;
5018
+ return ':';
5023
5019
 
5024
5020
  case '/':
5025
5021
  if (IS_BEG()) {
@@ -5443,11 +5439,10 @@ parser_yylex(parser_state *p)
5443
5439
 
5444
5440
  if (IS_LABEL_POSSIBLE()) {
5445
5441
  if (IS_LABEL_SUFFIX(0)) {
5446
- p->lstate = EXPR_BEG;
5447
- nextc(p);
5442
+ p->lstate = EXPR_END;
5448
5443
  tokfix(p);
5449
5444
  pylval.id = intern_cstr(tok(p));
5450
- return tLABEL;
5445
+ return tIDENTIFIER;
5451
5446
  }
5452
5447
  }
5453
5448
  if (p->lstate != EXPR_DOT) {
@@ -201,7 +201,7 @@ module Enumerable
201
201
  ary.push([block.call(e), i])
202
202
  }
203
203
  if ary.size > 1
204
- __sort_sub__(ary, 0, ary.size - 1) do |a,b|
204
+ ary.__sort_sub__(0, ary.size - 1) do |a,b|
205
205
  a <=> b
206
206
  end
207
207
  end
@@ -610,9 +610,7 @@ module Enumerable
610
610
  # #=> [2, 4, 6, 8, 10, 12, 14, 16, 18, 20]
611
611
  #
612
612
 
613
- def each_with_object(obj=nil, &block)
614
- raise ArgumentError, "wrong number of arguments (0 for 1)" if obj.nil?
615
-
613
+ def each_with_object(obj, &block)
616
614
  return to_enum(:each_with_object, obj) unless block
617
615
 
618
616
  self.each {|*val| block.call(val.__svalue, obj) }
@@ -742,18 +740,39 @@ module Enumerable
742
740
  ##
743
741
  # call-seq:
744
742
  # enum.zip(arg, ...) -> an_array_of_array
743
+ # enum.zip(arg, ...) { |arr| block } -> nil
745
744
  #
746
745
  # Takes one element from <i>enum</i> and merges corresponding
747
746
  # elements from each <i>args</i>. This generates a sequence of
748
747
  # <em>n</em>-element arrays, where <em>n</em> is one more than the
749
748
  # count of arguments. The length of the resulting sequence will be
750
749
  # <code>enum#size</code>. If the size of any argument is less than
751
- # <code>enum#size</code>, <code>nil</code> values are supplied.
750
+ # <code>enum#size</code>, <code>nil</code> values are supplied. If
751
+ # a block is given, it is invoked for each output array, otherwise
752
+ # an array of arrays is returned.
753
+ #
754
+ # a = [ 4, 5, 6 ]
755
+ # b = [ 7, 8, 9 ]
756
+ #
757
+ # a.zip(b) #=> [[4, 7], [5, 8], [6, 9]]
758
+ # [1, 2, 3].zip(a, b) #=> [[1, 4, 7], [2, 5, 8], [3, 6, 9]]
759
+ # [1, 2].zip(a, b) #=> [[1, 4, 7], [2, 5, 8]]
760
+ # a.zip([1, 2], [8]) #=> [[4, 1, 8], [5, 2, nil], [6, nil, nil]]
761
+ #
762
+ # c = []
763
+ # a.zip(b) { |x, y| c << x + y } #=> nil
764
+ # c #=> [11, 13, 15]
752
765
  #
753
766
 
754
- def zip(*arg)
755
- ary = []
756
- arg = arg.map{|a|a.to_a}
767
+ def zip(*arg, &block)
768
+ result = block ? nil : []
769
+ arg = arg.map do |a|
770
+ unless a.respond_to?(:to_a)
771
+ raise TypeError, "wrong argument type #{a.class} (must respond to :to_a)"
772
+ end
773
+ a.to_a
774
+ end
775
+
757
776
  i = 0
758
777
  self.each do |*val|
759
778
  a = []
@@ -763,10 +782,14 @@ module Enumerable
763
782
  a.push(arg[idx][i])
764
783
  idx += 1
765
784
  end
766
- ary.push(a)
767
785
  i += 1
786
+ if result.nil?
787
+ block.call(a)
788
+ else
789
+ result.push(a)
790
+ end
768
791
  end
769
- ary
792
+ result
770
793
  end
771
794
 
772
795
  ##
@@ -166,6 +166,12 @@ assert("Enumerable#zip") do
166
166
  assert_equal [[1, 4, 7], [2, 5, 8], [3, 6, 9]], [1, 2, 3].zip(a, b)
167
167
  assert_equal [[1, 4, 7], [2, 5, 8]], [1, 2].zip(a, b)
168
168
  assert_equal [[4, 1, 8], [5, 2, nil], [6, nil, nil]], a.zip([1, 2], [8])
169
+
170
+ ret = []
171
+ assert_equal nil, a.zip([1, 2], [8]) { |i| ret << i }
172
+ assert_equal [[4, 1, 8], [5, 2, nil], [6, nil, nil]], ret
173
+
174
+ assert_raise(TypeError) { [1].zip(1) }
169
175
  end
170
176
 
171
177
  assert("Enumerable#to_h") do
@@ -40,7 +40,7 @@ assert("Enumerator::Lazy laziness") do
40
40
  assert_equal [10,20], a.b
41
41
  end
42
42
 
43
- assert("Enumrator::Lazy#to_enum") do
43
+ assert("Enumerator::Lazy#to_enum") do
44
44
  lazy_enum = (0..Float::INFINITY).lazy.to_enum(:each_slice, 2)
45
45
  assert_kind_of Enumerator::Lazy, lazy_enum
46
46
  assert_equal [0*1, 2*3, 4*5, 6*7], lazy_enum.map { |a| a.first * a.last }.first(4)
@@ -621,25 +621,40 @@ end
621
621
 
622
622
  module Enumerable
623
623
  # use Enumerator to use infinite sequence
624
- def zip(*arg)
625
- ary = []
626
- arg = arg.map{|a|a.each}
627
- i = 0
628
- self.each do |*val|
629
- a = []
630
- a.push(val.__svalue)
631
- idx = 0
632
- while idx < arg.size
633
- begin
634
- a.push(arg[idx].next)
635
- rescue StopIteration
636
- a.push(nil)
624
+ def zip(*args, &block)
625
+ args = args.map do |a|
626
+ if a.respond_to?(:to_ary)
627
+ a.to_ary.to_enum(:each)
628
+ elsif a.respond_to?(:each)
629
+ a.to_enum(:each)
630
+ else
631
+ raise TypeError, "wrong argument type #{a.class} (must respond to :each)"
632
+ end
633
+ end
634
+
635
+ result = block ? nil : []
636
+
637
+ each do |*val|
638
+ tmp = [val.__svalue]
639
+ args.each do |arg|
640
+ v = if arg.nil?
641
+ nil
642
+ else
643
+ begin
644
+ arg.next
645
+ rescue StopIteration
646
+ nil
647
+ end
637
648
  end
638
- idx += 1
649
+ tmp.push(v)
650
+ end
651
+ if result.nil?
652
+ block.call(tmp)
653
+ else
654
+ result.push(tmp)
639
655
  end
640
- ary.push(a)
641
- i += 1
642
656
  end
643
- ary
657
+
658
+ result
644
659
  end
645
660
  end
@@ -544,3 +544,13 @@ assert 'Range#each' do
544
544
  end
545
545
  assert_equal [1,2,3,4,5], c
546
546
  end
547
+
548
+ assert 'Enumerable#zip' do
549
+ assert_equal [[1, 10], [2, 11], [3, 12]], [1,2,3].zip(10..Float::INFINITY)
550
+
551
+ ret = []
552
+ assert_equal nil, [1,2,3].zip(10..Float::INFINITY) { |i| ret << i }
553
+ assert_equal [[1, 10], [2, 11], [3, 12]], ret
554
+
555
+ assert_raise(TypeError) { [1].zip(1) }
556
+ end
@@ -274,12 +274,13 @@ mrb_fiber_resume(mrb_state *mrb, mrb_value fib, mrb_int len, const mrb_value *a)
274
274
  * Returns true if the fiber can still be resumed. After finishing
275
275
  * execution of the fiber block this method will always return false.
276
276
  */
277
- static mrb_value
278
- fiber_alive_p(mrb_state *mrb, mrb_value self)
277
+ MRB_API mrb_value
278
+ mrb_fiber_alive_p(mrb_state *mrb, mrb_value self)
279
279
  {
280
280
  struct mrb_context *c = fiber_check(mrb, self);
281
281
  return mrb_bool_value(c->status != MRB_FIBER_TERMINATED);
282
282
  }
283
+ #define fiber_alive_p mrb_fiber_alive_p
283
284
 
284
285
  static mrb_value
285
286
  fiber_eq(mrb_state *mrb, mrb_value self)