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
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)