opal 0.3.2 → 0.3.6

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 (203) hide show
  1. data/README.md +85 -127
  2. data/bin/opal +3 -3
  3. data/lib/core.rb +114 -0
  4. data/{gems/core/lib → lib}/core/array.rb +68 -187
  5. data/{gems/core/lib → lib}/core/basic_object.rb +22 -5
  6. data/lib/core/class.rb +38 -0
  7. data/{gems/core/lib → lib}/core/dir.rb +1 -1
  8. data/lib/core/enumerable.rb +33 -0
  9. data/{gems/core/lib → lib}/core/error.rb +1 -4
  10. data/{gems/core/lib → lib}/core/false_class.rb +0 -0
  11. data/{gems/core/lib → lib}/core/file.rb +11 -3
  12. data/{gems/core/lib → lib}/core/hash.rb +12 -0
  13. data/{gems/core/lib → lib}/core/kernel.rb +114 -86
  14. data/lib/core/match_data.rb +33 -0
  15. data/lib/core/module.rb +97 -0
  16. data/{gems/core/lib → lib}/core/nil_class.rb +0 -0
  17. data/{gems/core/lib → lib}/core/numeric.rb +5 -0
  18. data/{gems/core/lib → lib}/core/object.rb +0 -0
  19. data/{gems/core/lib → lib}/core/proc.rb +13 -3
  20. data/{gems/core/lib → lib}/core/range.rb +10 -0
  21. data/{gems/core/lib → lib}/core/regexp.rb +33 -1
  22. data/{gems/core/lib → lib}/core/string.rb +25 -10
  23. data/{gems/core/lib → lib}/core/symbol.rb +3 -3
  24. data/{gems/core/lib → lib}/core/top_self.rb +0 -0
  25. data/{gems/core/lib → lib}/core/true_class.rb +0 -0
  26. data/lib/dev.rb +169 -0
  27. data/{gems/ospec/lib → lib}/ospec.rb +1 -0
  28. data/lib/ospec/autorun.rb +8 -0
  29. data/{gems/ospec/lib → lib}/ospec/dsl.rb +2 -2
  30. data/{gems/ospec/lib → lib}/ospec/example.rb +0 -0
  31. data/{gems/ospec/lib → lib}/ospec/example/before_and_after_hooks.rb +0 -0
  32. data/{gems/ospec/lib → lib}/ospec/example/errors.rb +0 -0
  33. data/{gems/ospec/lib → lib}/ospec/example/example_group.rb +0 -0
  34. data/{gems/ospec/lib → lib}/ospec/example/example_group_factory.rb +0 -3
  35. data/{gems/ospec/lib → lib}/ospec/example/example_group_hierarchy.rb +4 -3
  36. data/{gems/ospec/lib → lib}/ospec/example/example_group_methods.rb +1 -1
  37. data/{gems/ospec/lib → lib}/ospec/example/example_group_proxy.rb +3 -2
  38. data/{gems/ospec/lib → lib}/ospec/example/example_methods.rb +1 -1
  39. data/{gems/ospec/lib → lib}/ospec/example/example_proxy.rb +7 -7
  40. data/{gems/ospec/lib → lib}/ospec/expectations.rb +0 -0
  41. data/{gems/ospec/lib → lib}/ospec/expectations/errors.rb +0 -0
  42. data/{gems/ospec/lib → lib}/ospec/expectations/fail_with.rb +4 -3
  43. data/{gems/ospec/lib → lib}/ospec/expectations/handler.rb +6 -0
  44. data/lib/ospec/helpers/scratch.rb +18 -0
  45. data/{gems/ospec/lib → lib}/ospec/matchers.rb +2 -2
  46. data/{gems/ospec/lib → lib}/ospec/matchers/be.rb +0 -0
  47. data/{gems/ospec/lib → lib}/ospec/matchers/generated_descriptions.rb +0 -0
  48. data/{gems/ospec/lib → lib}/ospec/matchers/operator_matcher.rb +2 -0
  49. data/lib/ospec/matchers/raise_error.rb +38 -0
  50. data/lib/ospec/runner.rb +90 -0
  51. data/{gems/ospec/lib → lib}/ospec/runner/example_group_runner.rb +10 -13
  52. data/lib/ospec/runner/formatter/html_formatter.rb +139 -0
  53. data/{gems/ospec/lib → lib}/ospec/runner/formatter/terminal_formatter.rb +0 -0
  54. data/{gems/ospec/lib → lib}/ospec/runner/options.rb +1 -3
  55. data/{gems/ospec/lib → lib}/ospec/runner/reporter.rb +0 -9
  56. data/lib/racc/parser.rb +165 -0
  57. data/lib/strscan.rb +52 -0
  58. data/{lib → opal_lib}/opal.rb +2 -0
  59. data/opal_lib/opal/build_methods.rb +51 -0
  60. data/opal_lib/opal/builder.rb +164 -0
  61. data/opal_lib/opal/bundle.rb +70 -0
  62. data/opal_lib/opal/command.rb +68 -0
  63. data/{lib → opal_lib}/opal/context.rb +21 -9
  64. data/{lib → opal_lib}/opal/context/console.rb +0 -2
  65. data/opal_lib/opal/context/file_system.rb +34 -0
  66. data/{lib → opal_lib}/opal/context/loader.rb +26 -8
  67. data/opal_lib/opal/gem.rb +84 -0
  68. data/{lib → opal_lib}/opal/rake/builder_task.rb +2 -2
  69. data/opal_lib/opal/rake/spec_task.rb +32 -0
  70. data/{lib → opal_lib}/opal/ruby/nodes.rb +730 -109
  71. data/{lib → opal_lib}/opal/ruby/parser.rb +90 -23
  72. data/opal_lib/opal/ruby/ruby_parser.rb +4862 -0
  73. data/opal_lib/opal/ruby/ruby_parser.y +1454 -0
  74. data/opal_lib/opal/version.rb +4 -0
  75. data/runtime/class.js +359 -0
  76. data/runtime/debug.js +84 -0
  77. data/runtime/fs.js +199 -0
  78. data/runtime/init.js +558 -0
  79. data/runtime/loader.js +351 -0
  80. data/runtime/module.js +109 -0
  81. data/runtime/post.js +10 -0
  82. data/runtime/pre.js +7 -0
  83. data/runtime/runtime.js +351 -0
  84. metadata +88 -175
  85. data/.gitignore +0 -7
  86. data/Changelog +0 -31
  87. data/LICENSE +0 -75
  88. data/Rakefile +0 -86
  89. data/gems/core/README.md +0 -14
  90. data/gems/core/Rakefile +0 -8
  91. data/gems/core/core.gemspec +0 -13
  92. data/gems/core/lib/core.rb +0 -34
  93. data/gems/core/lib/core/class.rb +0 -31
  94. data/gems/core/lib/core/module.rb +0 -100
  95. data/gems/core/lib/core/vm.rb +0 -16
  96. data/gems/core/spec/core/array/append_spec.rb +0 -30
  97. data/gems/core/spec/core/array/assoc_spec.rb +0 -29
  98. data/gems/core/spec/core/array/at_spec.rb +0 -37
  99. data/gems/core/spec/core/array/clear_spec.rb +0 -22
  100. data/gems/core/spec/core/array/collect_bang_spec.rb +0 -27
  101. data/gems/core/spec/core/array/collect_spec.rb +0 -27
  102. data/gems/core/spec/core/array/compact_spec.rb +0 -41
  103. data/gems/core/spec/core/array/concat_spec.rb +0 -15
  104. data/gems/core/spec/core/array/constructor_spec.rb +0 -14
  105. data/gems/core/spec/core/array/each_spec.rb +0 -9
  106. data/gems/core/spec/core/array/element_reference_spec.rb +0 -4
  107. data/gems/core/spec/core/array/first_spec.rb +0 -35
  108. data/gems/core/spec/core/array/include_spec.rb +0 -9
  109. data/gems/core/spec/core/array/join_spec.rb +0 -6
  110. data/gems/core/spec/core/array/last_spec.rb +0 -51
  111. data/gems/core/spec/core/array/length_spec.rb +0 -6
  112. data/gems/core/spec/core/array/map_spec.rb +0 -33
  113. data/gems/core/spec/core/array/reverse_spec.rb +0 -6
  114. data/gems/core/spec/core/builtin_constants/builtin_constants_spec.rb +0 -7
  115. data/gems/core/spec/core/false/and_spec.rb +0 -10
  116. data/gems/core/spec/core/false/inspect_spec.rb +0 -6
  117. data/gems/core/spec/core/false/or_spec.rb +0 -10
  118. data/gems/core/spec/core/false/to_s_spec.rb +0 -6
  119. data/gems/core/spec/core/false/xor_spec.rb +0 -10
  120. data/gems/core/spec/core/file/join_spec.rb +0 -19
  121. data/gems/core/spec/core/hash/assoc_spec.rb +0 -32
  122. data/gems/core/spec/core/kernel/instance_eval_spec.rb +0 -0
  123. data/gems/core/spec/core/kernel/loop_spec.rb +0 -24
  124. data/gems/core/spec/core/kernel/raise_spec.rb +0 -0
  125. data/gems/core/spec/core/module/attr_accessor_spec.rb +0 -28
  126. data/gems/core/spec/core/number/lt_spec.rb +0 -12
  127. data/gems/core/spec/core/string/sub_spec.rb +0 -24
  128. data/gems/core/spec/core/true/and_spec.rb +0 -10
  129. data/gems/core/spec/core/true/inspect_spec.rb +0 -6
  130. data/gems/core/spec/core/true/or_spec.rb +0 -10
  131. data/gems/core/spec/core/true/to_s_spec.rb +0 -6
  132. data/gems/core/spec/core/true/xor_spec.rb +0 -10
  133. data/gems/core/spec/language/and_spec.rb +0 -61
  134. data/gems/core/spec/language/array_spec.rb +0 -68
  135. data/gems/core/spec/language/block_spec.rb +0 -38
  136. data/gems/core/spec/language/break_spec.rb +0 -36
  137. data/gems/core/spec/language/case_spec.rb +0 -103
  138. data/gems/core/spec/language/def_spec.rb +0 -21
  139. data/gems/core/spec/language/eigenclass_spec.rb +0 -60
  140. data/gems/core/spec/language/file_spec.rb +0 -13
  141. data/gems/core/spec/language/fixtures/block.rb +0 -21
  142. data/gems/core/spec/language/fixtures/super.rb +0 -293
  143. data/gems/core/spec/language/hash_spec.rb +0 -29
  144. data/gems/core/spec/language/if_spec.rb +0 -54
  145. data/gems/core/spec/language/loop_spec.rb +0 -11
  146. data/gems/core/spec/language/metaclass_spec.rb +0 -21
  147. data/gems/core/spec/language/method_spec.rb +0 -124
  148. data/gems/core/spec/language/next_spec.rb +0 -25
  149. data/gems/core/spec/language/or_spec.rb +0 -34
  150. data/gems/core/spec/language/redo_spec.rb +0 -24
  151. data/gems/core/spec/language/regexp_spec.rb +0 -26
  152. data/gems/core/spec/language/rescue_spec.rb +0 -20
  153. data/gems/core/spec/language/return_spec.rb +0 -47
  154. data/gems/core/spec/language/string_spec.rb +0 -25
  155. data/gems/core/spec/language/super_spec.rb +0 -32
  156. data/gems/core/spec/language/until_spec.rb +0 -157
  157. data/gems/core/spec/language/variables_spec.rb +0 -155
  158. data/gems/core/spec/language/while_spec.rb +0 -163
  159. data/gems/core/spec/spec_helper.rb +0 -5
  160. data/gems/core_fs/README.md +0 -19
  161. data/gems/dev/Rakefile +0 -5
  162. data/gems/dev/lib/dev.js +0 -99
  163. data/gems/dev/lib/dev/generator.js +0 -1264
  164. data/gems/dev/lib/dev/parser.js +0 -979
  165. data/gems/dev/lib/dev/ruby_parser.js +0 -1088
  166. data/gems/dev/lib/dev/ruby_parser.y +0 -1267
  167. data/gems/dev/lib/dev/string_scanner.js +0 -38
  168. data/gems/dev/tools/racc2js/README.md +0 -39
  169. data/gems/dev/tools/racc2js/math_parser.js +0 -222
  170. data/gems/dev/tools/racc2js/math_parser.rb +0 -133
  171. data/gems/dev/tools/racc2js/math_parser.y +0 -28
  172. data/gems/dev/tools/racc2js/parser.js +0 -218
  173. data/gems/dev/tools/racc2js/racc2js.rb +0 -153
  174. data/gems/json/README.md +0 -4
  175. data/gems/json/json.gemspec +0 -14
  176. data/gems/json/lib/json.rb +0 -64
  177. data/gems/json/lib/json/ext.rb +0 -51
  178. data/gems/json/lib/json/json2.js +0 -481
  179. data/gems/ospec/README.md +0 -0
  180. data/gems/ospec/lib/ospec/autorun.rb +0 -3
  181. data/gems/ospec/lib/ospec/runner.rb +0 -40
  182. data/gems/ospec/lib/ospec/runner/formatter/html_formatter.rb +0 -91
  183. data/gems/ospec/ospec.gemspec +0 -0
  184. data/gems/rquery/README.md +0 -9
  185. data/gems/rquery/lib/rquery.rb +0 -10
  186. data/gems/rquery/lib/rquery/ajax.rb +0 -4
  187. data/gems/rquery/lib/rquery/css.rb +0 -96
  188. data/gems/rquery/lib/rquery/document.rb +0 -25
  189. data/gems/rquery/lib/rquery/element.rb +0 -292
  190. data/gems/rquery/lib/rquery/event.rb +0 -108
  191. data/gems/rquery/lib/rquery/jquery.js +0 -8177
  192. data/gems/rquery/lib/rquery/request.rb +0 -138
  193. data/gems/rquery/lib/rquery/response.rb +0 -49
  194. data/gems/rquery/rquery.gemspec +0 -16
  195. data/lib/opal.js +0 -1597
  196. data/lib/opal/builder.rb +0 -117
  197. data/lib/opal/bundle.rb +0 -131
  198. data/lib/opal/command.rb +0 -11
  199. data/lib/opal/context/file_system.rb +0 -19
  200. data/lib/opal/gem.rb +0 -153
  201. data/lib/opal/ruby/ruby_parser.rb +0 -5170
  202. data/lib/opal/ruby/ruby_parser.y +0 -1298
  203. data/opal.gemspec +0 -15
@@ -1,4 +1,5 @@
1
- class Opal::RubyParser < Racc::Parser
1
+ module Opal
2
+ class RubyParser < Racc::Parser
2
3
 
3
4
  # Indent for generated code scopes; 2 spaces, never use tabs
4
5
  INDENT = ' '
@@ -90,6 +91,28 @@ class Opal::RubyParser < Racc::Parser
90
91
  @temp_queue = []
91
92
  # ivars..we need to make sure these exist (make sure they are nil if new)
92
93
  @ivars = []
94
+
95
+ # keep tabs on whether in while loop or not
96
+ @while_scope = 0
97
+ @while_scope_stack = []
98
+ end
99
+
100
+ def push_while_scope(while_scope)
101
+ @while_scope_stack << while_scope
102
+ @while_scope += 1
103
+ end
104
+
105
+ def pop_while_scope
106
+ @while_scope_stack.pop
107
+ @while_scope -= 1
108
+ end
109
+
110
+ def in_while_scope?
111
+ @while_scope > 0
112
+ end
113
+
114
+ def while_scope
115
+ @while_scope_stack.last
93
116
  end
94
117
 
95
118
  def ensure_ivar(name)
@@ -163,45 +186,76 @@ class Opal::RubyParser < Racc::Parser
163
186
  # keep track of the current line number in the generator
164
187
  attr_accessor :line
165
188
 
189
+ # expose top level options... useful for certain nodes to know if we are
190
+ # debug mode etc
191
+ attr_reader :opts
192
+
166
193
  def initialize(statements)
167
194
  super nil, statements
168
195
  @file_helpers = []
169
196
  @line = 1
170
197
  @mm_ids = []
198
+
199
+ @symbol_refs = {}
200
+ @symbol_count = 1
201
+
202
+ @regexp_refs = []
171
203
  end
172
204
 
173
- # Register a method name that needs to be called to $opal.mm. This method
174
- # will remove duplicates.
175
205
  def register_mm_id(mid)
176
206
  @mm_ids << mid unless @mm_ids.include? mid
177
207
  end
178
208
 
209
+ def register_symbol(sym)
210
+ if ref = @symbol_refs[sym]
211
+ ref
212
+ else
213
+ ref = @symbol_refs[sym] = "$symbol_#{@symbol_count}"
214
+ @symbol_count += 1
215
+ ref
216
+ end
217
+ end
218
+
179
219
  def generate(opts, level)
220
+ @opts = opts
180
221
  code = []
181
- code << super(opts, level)
222
+ @statements.returns
223
+ # code << super(opts, level)
224
+ code << @statements.generate(opts, level)
225
+
226
+ pre = 'function $$(){'
227
+ post = "\n}\n"
228
+ # post = "\n\n}\nvar nil, $ac, $super, $break, $class, $def, $symbol, $range, "
229
+ # post += '$hash, $B, Qtrue, Qfalse, $cg;'
230
+ # local vars... only if we used any..
231
+ unless @scope_vars.empty?
232
+ post += "var #{@scope_vars.join ', '};"
233
+ end
182
234
 
183
- pre = ''
184
- pre += 'var nil = VM.Qnil, '
185
- pre += '$class = VM.dc, $def = VM.dm, $symbol = VM.Y, '
186
- pre += '$hash = VM.H, $block = VM.P, Qtrue = VM.Qtrue, Qfalse = VM.Qfalse;'
235
+ post += 'var nil = $rb.Qnil, $ac = $rb.ac, $super = $rb.S, $break = $rb.B, '
236
+ post += '$class = $rb.dc, $defn = $rb.dm, $defs = $rb.ds, $symbol = $rb.Y, '
237
+ post += '$hash = $rb.H, $B = $rb.P, Qtrue = $rb.Qtrue, Qfalse = $rb.Qfalse, '
238
+ post += '$cg = $rb.cg, $range = $rb.G'
187
239
 
188
- # add method missing setup
189
- if @mm_ids.length > 0
190
- mm_ids = "VM.mm(['#{@mm_ids.join "', '"}']);"
191
- pre += mm_ids
240
+ # symbols
241
+ @symbol_refs.each do |val, sym|
242
+ post += ", #{sym} = $symbol('#{val}')"
192
243
  end
193
244
 
194
- # local vars... only if we used any..
195
- unless @scope_vars.empty?
196
- pre = pre + "var #{@scope_vars.join ', '};"
245
+ post += ';'
246
+
247
+ if @mm_ids.length > 0
248
+ post += "$rb.mm(['#{ @mm_ids.join "', '" }']);"
197
249
  end
198
250
 
199
251
  # ivars
200
252
  @ivars.each do |ivar|
201
- pre += "if (self['#{ivar}'] == undefined) { self['#{ivar}'] = nil; }"
253
+ post += "if (self['#{ivar}'] == undefined) { self['#{ivar}'] = nil; }"
202
254
  end
203
255
 
204
- pre + code.join('')
256
+ post += "return $$();\n"
257
+
258
+ pre + code.join('') + post
205
259
  end
206
260
  end
207
261
 
@@ -229,7 +283,7 @@ class Opal::RubyParser < Racc::Parser
229
283
  return NilNode.new.generate(opts, level) if @nodes.empty?
230
284
 
231
285
  @nodes.each do |node|
232
- node_code = node.process opts, LEVEL_TOP
286
+ node_code = node.process opts, level
233
287
 
234
288
  if level <= LEVEL_TOP_CLOSURE
235
289
  # to prevent lots of trailing whitespace when we generate statements
@@ -274,6 +328,8 @@ class Opal::RubyParser < Racc::Parser
274
328
 
275
329
  class NumericNode < BaseNode
276
330
 
331
+ attr_accessor :value
332
+
277
333
  def initialize(val)
278
334
  @line = val[:line]
279
335
  @value = val[:value]
@@ -292,7 +348,7 @@ class Opal::RubyParser < Racc::Parser
292
348
  end
293
349
 
294
350
  def generate(opts, level)
295
- "$symbol('#{@value}')"
351
+ opts[:top].register_symbol @value
296
352
  end
297
353
  end
298
354
 
@@ -315,8 +371,6 @@ class Opal::RubyParser < Racc::Parser
315
371
  def mid_to_jsid(id)
316
372
  return ".$m['#{id}']" if /[\!\=\?\+\-\*\/\^\&\%\@\|\[\]\<\>\~]/ =~ id
317
373
 
318
- # FIXME: if our id is a reserved word in js, we need to also wrap it in
319
- # brackets.
320
374
  return ".$m['#{id}']" if js_reserved_words.include? id
321
375
 
322
376
  # default we just do .method_name
@@ -332,26 +386,48 @@ class Opal::RubyParser < Racc::Parser
332
386
  end
333
387
 
334
388
  def generate(opts, level)
335
- code, arg_res, recv, mid = '', [], nil, nil
389
+ # Special handlers
390
+ if @recv.is_a? NumericNode and @mid == '-@'
391
+ @recv.value = "-#{@recv.value}"
392
+ return @recv.generate opts, level
393
+
394
+ elsif @mid == "block_given?"
395
+ # name = opts[:scope].set_uses_block
396
+ return "($yy == $y.y ? Qfalse : Qtrue)"
397
+ end
336
398
 
337
- # we need a temp var for the receiver, which we add to the front of
338
- # the args to send.
399
+ code = ''
400
+ arg_res = []
401
+ recv = nil
402
+ mid = @mid
339
403
  tmp_recv = opts[:scope].temp_local
340
404
 
405
+ opts[:top].register_mm_id @mid
406
+
341
407
  # receiver
342
408
  if @recv.is_a? NumericNode
343
409
  recv = "(#{@recv.process opts, LEVEL_EXPR})"
344
410
  elsif @recv
345
411
  recv = @recv.process opts, LEVEL_EXPR
346
412
  else
347
- recv = SelfNode.new.generate opts, LEVEL_EXPR
413
+ @recv = SelfNode.new
414
+ recv = "self"
415
+ mid = '$' + mid
348
416
  end
349
417
 
350
- # method id
351
- mid = mid_to_jsid @mid
418
+ mid = mid_to_jsid(mid)
419
+
420
+ if @recv.is_a? SelfNode
421
+ recv_code = recv
422
+ recv_arg = recv
423
+ elsif @recv.is_a?(IdentifierNode) and @recv.local_variable?(opts)
424
+ recv_code = recv
425
+ recv_arg = recv
426
+ else
427
+ recv_code = "(#{tmp_recv} = #{recv})"
428
+ recv_arg = "#{tmp_recv}"
429
+ end
352
430
 
353
- # Register our method_id to ensure $opal.mm gets it
354
- opts[:top].register_mm_id @mid
355
431
 
356
432
  args = @args
357
433
  # normal args
@@ -367,18 +443,13 @@ class Opal::RubyParser < Racc::Parser
367
443
  end
368
444
 
369
445
  if @block
370
- # tmp_self = opts[:scope].temp_local
371
- tmp_args = opts[:scope].temp_local
372
446
  block = @block.generate opts, LEVEL_TOP
373
- arg_res.unshift tmp_recv
447
+ arg_res.unshift recv_arg
374
448
 
375
- code = "(#{tmp_recv} = #{recv}, #{tmp_args} = [#{arg_res.join ', '}]"
376
- code += ", ($block.p = #{block}).$self = #{SelfNode.new.generate opts, level}"
377
- code += ", ($block.f = #{tmp_recv}#{mid}).apply(#{tmp_recv}, #{tmp_args}))"
449
+ code = "($B.f = #{recv_code}#{mid}, ($B.p ="
450
+ code += "#{block}).$proc =[self], $B.f)(#{arg_res.join ', '})"
378
451
 
379
452
  opts[:scope].queue_temp tmp_recv
380
- opts[:scope].queue_temp tmp_args
381
-
382
453
  code
383
454
 
384
455
  # &to_proc. Note, this must not reassign the $self for the proc.. we are
@@ -386,16 +457,12 @@ class Opal::RubyParser < Racc::Parser
386
457
  #
387
458
  # FIXME need to actually call to_proc.
388
459
  elsif args[3]
389
- tmp_args = opts[:scope].temp_local
390
-
391
- arg_res.unshift tmp_recv
460
+ arg_res.unshift recv_arg
392
461
 
393
- code = "(#{tmp_recv} = #{recv}, #{tmp_args} = [#{arg_res.join ', '}]"
394
- code += ", ($block.p = #{args[3].process opts, LEVEL_LIST})"
395
- code += ", ($block.f = #{tmp_recv}#{mid}).apply(#{tmp_recv}, #{tmp_args}))"
462
+ code = "($B.p = #{args[3].process opts, LEVEL_LIST}, "
463
+ code += "$B.f = #{recv_code}#{mid})(#{arg_res.join ', '})"
396
464
 
397
465
  opts[:scope].queue_temp tmp_recv
398
- opts[:scope].queue_temp tmp_args
399
466
 
400
467
  code
401
468
 
@@ -403,22 +470,20 @@ class Opal::RubyParser < Racc::Parser
403
470
  else
404
471
  # splat args
405
472
  if args[1]
406
- arg_res.unshift tmp_recv
473
+ arg_res.unshift recv_arg
407
474
  splat = args[1].generate(opts, LEVEL_EXPR)
408
- splat_args = arg_res.empty? ? splat : "[#{arg_res.join ', '}].concat(#{splat})"
475
+ splat_args = arg_res.empty? ? "#{splat}" : "[#{arg_res.join ', '}].concat(#{splat})"
409
476
  # when using splat, our this val for apply may need a tmp var
410
477
  # to save just outputting it twice (have to follow recv path twice)
411
478
  splat_recv = recv
412
- result = "(#{tmp_recv} = #{recv})" + mid + ".apply(nil, #{splat_args})"
479
+ result = "#{recv_code}" + mid + ".apply(nil, #{splat_args})"
413
480
 
414
481
  opts[:scope].queue_temp tmp_recv
415
482
  result
416
483
  else
417
- arg_res.unshift tmp_recv
484
+ arg_res.unshift recv_arg
418
485
 
419
- result = "(#{tmp_recv} = #{recv})" + mid + '(' + arg_res.join(', ') + ')'
420
-
421
- # requeue the tmp receiver as we are done with it and return
486
+ result = "#{recv_code}#{mid}(#{arg_res.join(', ')})"
422
487
  opts[:scope].queue_temp tmp_recv
423
488
  result
424
489
  end
@@ -466,7 +531,7 @@ class Opal::RubyParser < Racc::Parser
466
531
  if @base.nil?
467
532
  code += SelfNode.new.generate(opts, level)
468
533
  else
469
- code += 'w'
534
+ code += @base.generate(opts, level)
470
535
  end
471
536
 
472
537
  code += ', '
@@ -479,9 +544,14 @@ class Opal::RubyParser < Racc::Parser
479
544
 
480
545
  # scope
481
546
  scope = { :indent => opts[:indent] + INDENT, :top => opts[:top], :scope => self }
547
+ @statements.returns
482
548
  stmt = @statements.generate scope, LEVEL_TOP
483
549
 
484
- code += ('function() { var self = this; ' + stmt)
550
+ if @scope_vars.empty?
551
+ code += ('function(self) { ' + stmt)
552
+ else
553
+ code += "function(self) {var #{@scope_vars.join ', '};#{stmt}"
554
+ end
485
555
 
486
556
  # fix line ending
487
557
  code += fix_line_number opts, @end_line
@@ -495,7 +565,6 @@ class Opal::RubyParser < Racc::Parser
495
565
 
496
566
  def initialize(cls, path, sup, body, _end)
497
567
  super nil, body
498
- @scope_vars << 'self = this'
499
568
  @line = cls[:line]
500
569
  @base = path[0]
501
570
  @cls_name = path[1]
@@ -507,7 +576,7 @@ class Opal::RubyParser < Racc::Parser
507
576
  code = '$class('
508
577
 
509
578
  # base
510
- code += (@base.nil? ? SelfNode.new.generate(opts, level) : 'w')
579
+ code += (@base.nil? ? SelfNode.new.generate(opts, level) : @base.generate(opts, level))
511
580
  code += ', '
512
581
 
513
582
  # superclass
@@ -519,8 +588,14 @@ class Opal::RubyParser < Racc::Parser
519
588
 
520
589
  # scope
521
590
  scope = { :indent => opts[:indent] + INDENT, :top => opts[:top], :scope => self }
591
+ @statements.returns
522
592
  stmt = @statements.generate scope, level
523
- code += "function() { var #{@scope_vars.join ', '};#{stmt}"
593
+
594
+ if @scope_vars.empty?
595
+ code += "function(self) {#{stmt}"
596
+ else
597
+ code += "function(self) { var #{@scope_vars.join ', '};#{stmt}"
598
+ end
524
599
 
525
600
  # fix trailing line number
526
601
  code += fix_line_number opts, @end_line
@@ -530,6 +605,41 @@ class Opal::RubyParser < Racc::Parser
530
605
  end
531
606
  end
532
607
 
608
+ class ClassShiftNode < ScopeNode
609
+
610
+ def initialize(cls, expr, body, endn)
611
+ super nil, body
612
+ @line = cls[:line]
613
+ @expr = expr
614
+ @end_line = endn[:line]
615
+ end
616
+
617
+ def generate(opts, level)
618
+ code = '$class('
619
+
620
+ # base
621
+ code += @expr.generate(opts, level)
622
+ code += ', nil, nil, '
623
+
624
+ # scope
625
+ scope = { :indent => opts[:indent] + INDENT, :top => opts[:top], :scope => self }
626
+ @statements.returns
627
+ stmt = @statements.generate scope, level
628
+
629
+ if @scope_vars.empty?
630
+ code += "function(self) {#{stmt}"
631
+ else
632
+ code += "function(self) { var #{@scope_vars.join ', '};#{stmt}"
633
+ end
634
+
635
+ # fix trailing line number
636
+ code += fix_line_number opts, @end_line
637
+
638
+ code += opts[:indent] + '}, 1)'
639
+ code
640
+ end
641
+ end
642
+
533
643
  class DefNode < ScopeNode
534
644
 
535
645
  def initialize(defn, singleton, fname, args, body, endn)
@@ -544,11 +654,11 @@ class Opal::RubyParser < Racc::Parser
544
654
  end
545
655
 
546
656
  def generate(opts, level)
547
- code = '$def('
548
-
549
- # singleton
550
- code += (@singleton ? @singleton.generate(opts, level) : SelfNode.new.generate(opts, level))
551
- code += ', '
657
+ if @singleton
658
+ code = "$defs(#{@singleton.generate opts, level}, "
659
+ else
660
+ code = "$defn(self, "
661
+ end
552
662
 
553
663
  # method id
554
664
  code += "'#{@fname[:value]}', "
@@ -571,6 +681,8 @@ class Opal::RubyParser < Racc::Parser
571
681
  end
572
682
  end
573
683
 
684
+ arity = method_args.length
685
+
574
686
  # optional args
575
687
  if args[1]
576
688
  args[1].each do |arg|
@@ -582,23 +694,27 @@ class Opal::RubyParser < Racc::Parser
582
694
 
583
695
  # rest args
584
696
  if args[2]
585
- param_variable args[2][:value]
586
- method_args << args[2][:value]
587
- pre_code += "#{args[2][:value]} = [].slice.call(arguments, #{method_args.length});"
697
+ if args[2][:value] != "*"
698
+ param_variable args[2][:value]
699
+ method_args << args[2][:value]
700
+ pre_code += "#{args[2][:value]} = [].slice.call(arguments, #{method_args.length});"
701
+ end
588
702
  end
589
703
 
704
+ arity = (-arity) - 1 if args[1] or args[2]
705
+
590
706
  # block arg
591
707
  if args[3]
592
708
  param_variable args[3][:value]
593
709
  @block_arg_name = args[3][:value]
710
+ pre_code += "var #{args[3][:value]} = (($yy == $y.y) ? nil: $yy);"
594
711
  end
595
712
 
596
713
  @body.returns
597
714
  stmt = @body.generate scope, LEVEL_TOP
598
-
599
715
  method_args.unshift 'self'
600
716
 
601
- code += "function(#{method_args.join ', '}) { "
717
+ code += "function(#{method_args.join ', '}) {"
602
718
 
603
719
  # local vars... only if we used any..
604
720
  unless @scope_vars.empty?
@@ -607,19 +723,23 @@ class Opal::RubyParser < Racc::Parser
607
723
 
608
724
  # ivars
609
725
  @ivars.each do |ivar|
610
- pre_code += "if (self['#{ivar}'] == undefined) { self['#{ivar}'] = nil; }"
726
+ pre_code += "self['#{ivar}']==undefined&&(self['#{ivar}']=nil);"
611
727
  end
612
728
 
613
- # block arg
729
+ # block support
614
730
  if @block_arg_name
615
- pre_code += " var #{@block_arg_name} = ($block.f == arguments.callee)"
616
- pre_code += " ? $block.p : nil; $block.p = $block.f = nil;"
731
+
732
+ block_code = "var $y = $B, $yy, $ys, $yb = $y.b;"
733
+ block_code += "if ($y.f == arguments.callee) { $yy = $y.p; }"
734
+ block_code += "else { $yy = $y.y; }"
735
+ block_code += "$y.f = nil ;$ys = $yy.$proc[0];"
736
+ pre_code = block_code + pre_code
617
737
  end
618
738
 
619
739
  code += (pre_code + stmt)
620
740
 
621
741
  # fix trailing end and 0/1 for normal/singleton
622
- code += (fix_line_number(opts, @end_line) + "}, #{@singleton ? '1' : '0'})")
742
+ code += (fix_line_number(opts, @end_line) + "}, #{arity})")
623
743
 
624
744
  code
625
745
  end
@@ -685,8 +805,8 @@ class Opal::RubyParser < Racc::Parser
685
805
  class ArrayNode < BaseNode
686
806
 
687
807
  def initialize(parts, begn, endn)
688
- @line = begn[:line]
689
- @end_line = endn[:line]
808
+ @line = begn[:line] || 0
809
+ @end_line = endn[:line] || 0
690
810
  @args = parts
691
811
  end
692
812
 
@@ -694,15 +814,23 @@ class Opal::RubyParser < Racc::Parser
694
814
  # on a new line are indented to that of the array beg/end
695
815
  def generate(opts, level)
696
816
  parts = @args[0].map { |arg| arg.process opts, LEVEL_LIST }
697
- "[#{parts.join ', '}#{fix_line_number opts, @end_line}]"
817
+ code = "[#{parts.join ', '}#{fix_line_number opts, @end_line}]"
818
+
819
+ if @args[1]
820
+ res = "#{code}.concat(#{@args[1].generate opts, LEVEL_EXPR})"
821
+ else
822
+ res = code
823
+ end
824
+
825
+ res
698
826
  end
699
827
  end
700
828
 
701
829
  class HashNode < BaseNode
702
830
 
703
831
  def initialize(parts, begn, endn)
704
- @line = begn[:line]
705
- @end_line = endn[:line]
832
+ @line = begn[:line] || 0
833
+ @end_line = endn[:line] || 0
706
834
  @parts = parts
707
835
  end
708
836
 
@@ -715,6 +843,7 @@ class Opal::RubyParser < Racc::Parser
715
843
  class IfNode < BaseNode
716
844
 
717
845
  def initialize(begn, expr, stmt, tail, endn)
846
+ @type = begn[:value]
718
847
  @line = begn[:line]
719
848
  @end_line = endn[:line]
720
849
  @expr = expr
@@ -740,9 +869,12 @@ class Opal::RubyParser < Racc::Parser
740
869
  end
741
870
 
742
871
  def generate(opts, level)
743
- code, done_else, tail, old_indent = '', false, nil, opts[:indent]
872
+ code = ''
873
+ done_else = false
874
+ tail = nil
875
+ old_indent = opts[:indent]
744
876
 
745
- opts[:indent] += INDENT
877
+ opts[:indent] = opts[:indent] + INDENT
746
878
 
747
879
  # stmt_level is level_top, unless we are an expression.. then it is level_top_closure..
748
880
  stmt_level = (level == LEVEL_EXPR ? LEVEL_TOP_CLOSURE : LEVEL_TOP)
@@ -752,20 +884,27 @@ class Opal::RubyParser < Racc::Parser
752
884
  @level_expr = true
753
885
  end
754
886
 
755
- code += "if ((#{@expr.generate opts, LEVEL_EXPR}).$r) {#{@stmt.process opts, stmt_level}"
887
+ expr = @expr.generate opts, LEVEL_EXPR
888
+ expr = "(#{expr})" if @expr.is_a? NumericNode
889
+
890
+ # code += "if ((#{@expr.generate opts, LEVEL_EXPR}).$r) {#{@stmt.process opts, stmt_level}"
891
+ code += "if (#{@type == 'if' ? '' : '!'}#{expr}.$r) {#{@stmt.process opts, stmt_level}"
756
892
 
757
893
  @tail.each do |tail|
758
894
  opts[:indent] = old_indent
759
- code += fix_line_number opts, tail[0][:line]
895
+ code = code + fix_line_number(opts, tail[0][:line])
760
896
 
761
897
  if tail[0][:value] == 'elsif'
762
- code += "} else if ((#{tail[1].generate opts, LEVEL_EXPR}).$r) {"
763
- opts[:indent] += INDENT
764
- code += tail[2].process(opts, stmt_level)
898
+ expr = tail[1].generate opts, LEVEL_EXPR
899
+ expr = "(#{expr})" if tail[1].is_a? NumericNode
900
+ code += "} else if (#{expr}.$r) {"
901
+ # code += "} else if ((#{tail[1].generate opts, LEVEL_EXPR}).$r) {"
902
+ opts[:indent] = opts[:indent] + INDENT
903
+ code = code + tail[2].process(opts, stmt_level)
765
904
  else
766
905
  done_else = true
767
906
  code += '} else {'
768
- opts[:indent] += INDENT
907
+ opts[:indent] = opts[:indent] + INDENT
769
908
  code += tail[1].process(opts, stmt_level)
770
909
  end
771
910
  end
@@ -780,11 +919,92 @@ class Opal::RubyParser < Racc::Parser
780
919
  code += (fix_line_number(opts, @end_line) + '}')
781
920
 
782
921
  # if we were an expression, we need to wrap ourself as closure
922
+ code = "(function() {#{code}})()" if level == LEVEL_EXPR
923
+ code
924
+ end
925
+ end
926
+
927
+ class CaseNode < BaseNode
928
+
929
+ def initialize(begn, expr, body, endn)
930
+ @line = begn[:line]
931
+ @expr = expr
932
+ @body = body
933
+ @end_line = endn[:line]
934
+ end
935
+
936
+ def returns
937
+ @body.each do |part|
938
+ if part[0][:value] == 'when'
939
+ part[2].returns
940
+ else
941
+ part[1].returns
942
+ end
943
+ end
944
+ self
945
+ end
946
+
947
+ def generate(opts, level)
948
+ code = ''
949
+ done_else = false
950
+ tail = nil
951
+ old_indent = opts[:indent]
952
+
953
+ opts[:indent] = opts[:indent] + INDENT
954
+
955
+ stmt_level = (level == LEVEL_EXPR ? LEVEL_TOP_CLOSURE : LEVEL_TOP)
956
+
957
+ if stmt_level == LEVEL_TOP_CLOSURE
958
+ returns
959
+ @level_expr = true
960
+ end
961
+
962
+ expr = @expr.generate opts, LEVEL_EXPR
963
+ case_ref = opts[:scope].temp_local
964
+
965
+ code += "#{case_ref} = #{expr};"
966
+
967
+ @body.each_with_index do |part, idx|
968
+ opts[:indent] = old_indent
969
+ code += fix_line_number opts, part[0][:line]
970
+
971
+ if part[0][:value] == 'when'
972
+ code += (idx == 0 ? "if" : "} else if")
973
+ parts = part[1].map do |expr|
974
+ CallNode.new(expr,
975
+ {:value => '===' },
976
+ [[TempNode.new(case_ref)]]
977
+ ).generate(opts, LEVEL_EXPR) + '.$r'
978
+ end
979
+ opts[:indent] = opts[:indent] + INDENT
980
+ code += " (#{parts.join ' || '}) {#{part[2].process opts, stmt_level}"
981
+ else
982
+ code += "} else {#{part[1].process opts, stmt_level}"
983
+ end
984
+ end
985
+
986
+ opts[:indent] = old_indent
987
+
988
+ opts[:scope].queue_temp case_ref
989
+ code += (fix_line_number(opts, @end_line) + '}')
990
+
783
991
  code = "(function() {#{code})()" if level == LEVEL_EXPR
784
992
  code
785
993
  end
786
994
  end
787
995
 
996
+ class TempNode < BaseNode
997
+
998
+ def initialize(val)
999
+ @val = val
1000
+ @line = 0
1001
+ end
1002
+
1003
+ def generate(opts, level)
1004
+ @val
1005
+ end
1006
+ end
1007
+
788
1008
  class ConstantNode < BaseNode
789
1009
 
790
1010
  def initialize(name)
@@ -797,7 +1017,7 @@ class Opal::RubyParser < Racc::Parser
797
1017
  end
798
1018
 
799
1019
  def generate(opts, level)
800
- "rb_vm_cg(#{SelfNode.new.generate opts, level}, '#{@name}')"
1020
+ "$cg(#{SelfNode.new.generate opts, level}, '#{@name}')"
801
1021
  end
802
1022
  end
803
1023
 
@@ -811,7 +1031,7 @@ class Opal::RubyParser < Racc::Parser
811
1031
 
812
1032
  def generate(opts, level)
813
1033
  # FIXME This should really be 'const at'.. const_get will relook all the way up chain
814
- "rb_vm_cg(#{@lhs.generate opts, level}, '#{@name}')"
1034
+ "$cg(#{@lhs.generate opts, level}, '#{@name}')"
815
1035
  end
816
1036
  end
817
1037
 
@@ -840,17 +1060,22 @@ class Opal::RubyParser < Racc::Parser
840
1060
  return "#{SelfNode.new.generate(opts, level)}['#{@lhs.value}'] = #{@rhs.generate(opts, LEVEL_EXPR)}"
841
1061
 
842
1062
  elsif @lhs.is_a? GvarNode
843
- return "VM.gs('#{@lhs.value}', #{@rhs.generate(opts, LEVEL_EXPR)})"
1063
+ return "$rb.gs('#{@lhs.value}', #{@rhs.generate(opts, LEVEL_EXPR)})"
844
1064
 
845
1065
  elsif @lhs.is_a? IdentifierNode
846
1066
  opts[:scope].ensure_variable @lhs.value
1067
+
1068
+ # optimize yield assigning
1069
+ if @rhs.is_a?(YieldNode) and level == LEVEL_TOP
1070
+ return @rhs.generate_assign(opts, @lhs)
1071
+ end
847
1072
  return @lhs.value + " = " + @rhs.generate(opts, LEVEL_EXPR)
848
1073
 
849
1074
  elsif @lhs.is_a? ArefNode
850
1075
  return AsetNode.new(@lhs.recv, @lhs.arefs, @rhs).process(opts, level)
851
1076
 
852
1077
  elsif @lhs.is_a? ConstantNode
853
- return "rb_vm_cs(self, '#{@lhs.value}', #{@rhs.generate(opts, LEVEL_EXPR)})"
1078
+ return "$rb.cs(self, '#{@lhs.value}', #{@rhs.generate(opts, LEVEL_EXPR)})"
854
1079
 
855
1080
  elsif @lhs.is_a? CallNode
856
1081
  return CallNode.new(@lhs.recv, { :value => @lhs.mid + '=', :line => @line }, [[@rhs]]).generate(opts, level);
@@ -861,6 +1086,54 @@ class Opal::RubyParser < Racc::Parser
861
1086
  end
862
1087
  end
863
1088
 
1089
+ class MlhsAssignNode < BaseNode
1090
+
1091
+ def initialize(node, lhs, rhs)
1092
+ @line = node[:line]
1093
+ @lhs = lhs
1094
+ @rhs = rhs
1095
+ end
1096
+
1097
+ def generate(opts, level)
1098
+ @lhs.inspect
1099
+ @generator_opts = opts
1100
+ '(' + generate_mlhs_context(@lhs, @rhs) + ')'
1101
+ end
1102
+
1103
+ def generate_mlhs_context(arr, rhs)
1104
+ puts "mlhs node at #@line"
1105
+ parts = []
1106
+
1107
+ tmp_recv = @generator_opts[:scope].temp_local
1108
+ tmp_len = @generator_opts[:scope].temp_local
1109
+ rhs_code = rhs.generate @generator_opts, LEVEL_EXPR
1110
+
1111
+ parts << "#{tmp_recv} = #{rhs_code}"
1112
+ parts << "(#{tmp_recv}.$flags & $rb.T_ARRAY) || (#{tmp_recv} = [#{tmp_recv}])"
1113
+ parts << "#{tmp_len} = #{tmp_recv}.length"
1114
+
1115
+ if arr[0]
1116
+ arr[0].each_with_index do |part, idx|
1117
+ if part.is_a? Array
1118
+ parts.push generate_mlhs_context part, rhs
1119
+ else
1120
+ assign = AssignNode.new part, TempNode.new("#{tmp_recv}[#{idx}]")
1121
+ code = assign.generate @generator_opts, LEVEL_EXPR
1122
+ parts.push "#{idx} < #{tmp_len} ? #{code} : nil"
1123
+ # parts.push assign.generate @generator_opts, LEVE<D-/>L_EXPR
1124
+ end
1125
+ end
1126
+ end
1127
+
1128
+ parts << tmp_recv
1129
+
1130
+ @generator_opts[:scope].queue_temp tmp_recv
1131
+ @generator_opts[:scope].queue_temp tmp_len
1132
+
1133
+ parts.join ', '
1134
+ end
1135
+ end
1136
+
864
1137
  class OpAsgnNode < BaseNode
865
1138
 
866
1139
  def initialize(asgn, lhs, rhs)
@@ -900,7 +1173,6 @@ class Opal::RubyParser < Racc::Parser
900
1173
  end
901
1174
 
902
1175
  class IdentifierNode < BaseNode
903
-
904
1176
  attr_reader :value
905
1177
 
906
1178
  def initialize(val)
@@ -908,6 +1180,10 @@ class Opal::RubyParser < Racc::Parser
908
1180
  @value = val[:value]
909
1181
  end
910
1182
 
1183
+ def local_variable?(opts)
1184
+ opts[:scope].find_variable(@value) ? true : false
1185
+ end
1186
+
911
1187
  def generate(opts, level)
912
1188
  if opts[:scope].find_variable @value
913
1189
  @value
@@ -943,6 +1219,8 @@ class Opal::RubyParser < Racc::Parser
943
1219
  elsif @parts.length == 1
944
1220
  if @parts[0][0] == 'string_content'
945
1221
  @join + @parts[0][1][:value] + @join
1222
+ elsif @parts[0][0] == 'string_dbegin'
1223
+ CallNode.new(@parts[0][1], { :value => 'to_s', :line => 0 }, [[]]).generate(opts, level)
946
1224
  end
947
1225
 
948
1226
  else
@@ -1006,6 +1284,18 @@ class Opal::RubyParser < Racc::Parser
1006
1284
  args[0].each do |arg|
1007
1285
  param_variable arg[:value]
1008
1286
  method_args << arg[:value]
1287
+
1288
+ # Argument checking.. If normal args are required but not passed
1289
+ # they just default to nil. Lambdas have the same effect as
1290
+ # methods, so we check this by wrapping lambdas in an anon
1291
+ # function that knows the arity of this block. So here, make all
1292
+ # norm args nil if not present.
1293
+ #
1294
+ # Also, this is optional, and can be turned on/off for
1295
+ # performance gains.
1296
+ if true
1297
+ pre_code += "if (#{arg[:value]} === undefined) { #{arg[:value]} = nil; }"
1298
+ end
1009
1299
  end
1010
1300
  end
1011
1301
 
@@ -1015,17 +1305,26 @@ class Opal::RubyParser < Racc::Parser
1015
1305
  opt_arg_name = arg[0][:value]
1016
1306
  param_variable opt_arg_name
1017
1307
  method_args << arg[0][:value]
1018
- pre_code += "if (#{opt_arg_name} == undefined) { #{opt_arg_name} = #{arg[1].generate(opts, level)};}"
1308
+ pre_code += "if (#{opt_arg_name} === undefined) { #{opt_arg_name} = #{arg[1].generate(opts, level)};}"
1019
1309
  end
1020
1310
  end
1021
1311
 
1022
1312
  # rest args
1023
1313
  if args[2]
1314
+ # ignore rest arg if it is anonymous
1315
+ unless args[2][:value] == '*'
1024
1316
  rest_arg_name = args[2][:value]
1025
1317
  # FIXME if we just pass '*', then we make a tmp variable name for it..
1026
1318
  param_variable rest_arg_name
1027
1319
  method_args << rest_arg_name
1028
- pre_code += "#{rest_arg_name} = [].slice.call(arguments, #{method_args.length});"
1320
+ pre_code += "#{rest_arg_name} = [].slice.call($A, #{method_args.length});"
1321
+ end
1322
+ end
1323
+
1324
+ # block arg
1325
+ if args[3]
1326
+ param_variable args[3][:value]
1327
+ @block_arg_name = args[3][:value]
1029
1328
  end
1030
1329
  end
1031
1330
 
@@ -1033,13 +1332,33 @@ class Opal::RubyParser < Racc::Parser
1033
1332
  stmt = @stmt.process scope, LEVEL_TOP
1034
1333
  method_args.unshift 'self'
1035
1334
 
1335
+ block_var = opts[:scope].temp_local
1336
+ # code += "(#{block_var} = "
1337
+
1036
1338
  code += "function(#{method_args.join ', '}) {"
1037
-
1339
+
1038
1340
  unless @scope_vars.empty?
1039
1341
  code += " var #{@scope_vars.join ', '};"
1040
1342
  end
1041
1343
 
1344
+ # block arg
1345
+ if @block_arg_name
1346
+ pre_code += "var $yield, #@block_arg_name; if ($B.f == arguments.callee && $B.p != nil) { #@block_arg_name = "
1347
+ pre_code += "$yield = $B.p; } else { #@block_arg_name = nil; "
1348
+ pre_code += "$yield = $B.y; } $B.p = $B.f = nil;"
1349
+ pre_code += "var $yself = $yield.$proc[0];"
1350
+
1351
+ stmt = "try{" + stmt
1352
+
1353
+ # catch break statements
1354
+ stmt += "} catch (__err__) {if(__err__.$keyword == 2) {return __err__.$value;} throw __err__;}"
1355
+ end
1356
+
1042
1357
  code += (pre_code + stmt + fix_line_number(opts, @end_line) + "}")
1358
+
1359
+ # code += ", #{block_var}.$arity = 0, #{block_var}.$meth = null"
1360
+ # code += ", #{block_var})"
1361
+ opts[:scope].queue_temp block_var
1043
1362
  code
1044
1363
  end
1045
1364
  end
@@ -1123,7 +1442,8 @@ class Opal::RubyParser < Racc::Parser
1123
1442
  end
1124
1443
 
1125
1444
  def generate(opts, level)
1126
- (@arefs[0] ||= []) << @val
1445
+ @arefs[0] || (@arefs[0] = [])
1446
+ @arefs[0] << @val
1127
1447
  CallNode.new(@recv, { :line => @line, :value => '[]='}, @arefs ).generate(opts, level)
1128
1448
  end
1129
1449
  end
@@ -1160,36 +1480,239 @@ class Opal::RubyParser < Racc::Parser
1160
1480
  end
1161
1481
  end
1162
1482
 
1163
- class BlockGivenNode < BaseNode
1483
+ class YieldNode < BaseNode
1484
+
1485
+ def initialize(start, args)
1486
+ @line = start[:line]
1487
+ @args = args
1488
+ end
1489
+
1490
+ # Get basic yielding code yield(yself,...)
1491
+ def yield_code(opts)
1492
+ block_code = "$yy"
1493
+
1494
+ parts = []
1495
+
1496
+ if @args[0]
1497
+ @args[0].each { |arg| parts << arg.generate(opts, LEVEL_EXPR) }
1498
+ end
1499
+
1500
+ if @args[1]
1501
+ parts.unshift '$ys'
1502
+ code = "#{block_code}(null, [#{parts.join ', '}].concat(#{@args[1].generate(opts, LEVEL_EXPR)}))"
1503
+ else
1504
+ parts.unshift '$ys'
1505
+ code = "#{block_code}(#{parts.join ', '})"
1506
+ end
1164
1507
 
1165
- def initialize(given)
1166
- @line = given[:line]
1508
+ code
1167
1509
  end
1168
1510
 
1169
1511
  def generate(opts, level)
1170
- name = opts[:scope].set_uses_block
1171
- "(#{name} !== nil ? Qtrue : Qfalse)"
1512
+ # need to get block from nearest method
1513
+ block = opts[:scope].set_uses_block
1514
+ code = yield_code opts
1515
+
1516
+ if level == LEVEL_TOP
1517
+ "if (#{code} == $yb) { return $yb.$value; }"
1518
+ else
1519
+ # basically we need to return out of this method and we are not
1520
+ # top level so we will need to throw and error which is caught
1521
+ # directly inside this method which just returns the break
1522
+ # value. We should warn that the given code is going to cause
1523
+ # a try/catch statement to be added to check for this. i.e. this
1524
+ # can/should be optimized out in the source code
1525
+ tmp = opts[:scope].temp_local
1526
+ "((#{tmp} = #{code}) == $yb ? $break() : #{tmp})"
1527
+ end
1528
+ end
1529
+
1530
+ # special generator for assigning to variable. We know we will be
1531
+ # top level if this is called.
1532
+ def generate_assign(opts, lhs)
1533
+ "if ((#{lhs.value} = #{yield_code opts}) == $yb) { return $yb.$value; }"
1172
1534
  end
1173
1535
  end
1174
1536
 
1175
- class YieldNode < BaseNode
1537
+ class BreakNode < BaseNode
1176
1538
 
1177
1539
  def initialize(start, args)
1178
1540
  @line = start[:line]
1179
1541
  @args = args
1180
1542
  end
1181
1543
 
1544
+ # as we either throw or return ourself we can ignore the
1545
+ # request to return ourself if last statement
1546
+ def returns
1547
+ self
1548
+ end
1549
+
1182
1550
  def generate(opts, level)
1183
- # need to get block from nearest method
1184
- block = opts[:scope].set_uses_block
1551
+ code = []
1552
+
1553
+ if @args[0]
1554
+ @args[0].each { |arg| code << arg.generate(opts, LEVEL_EXPR) }
1555
+ end
1556
+
1557
+ case code.length
1558
+ when 0
1559
+ code = "nil"
1560
+ when 1
1561
+ code = code[0]
1562
+ else
1563
+ code = '[' + code.join(', ') + ']'
1564
+ end
1565
+
1566
+ if opts[:scope].in_while_scope?
1567
+ while_scope = opts[:scope].while_scope
1568
+ tmp_break_val = while_scope.set_captures_break
1569
+ "#{tmp_break_val} = #{code}; break"
1570
+ elsif opts[:scope].is_a? BlockNode
1571
+ if level == LEVEL_TOP
1572
+ "return ($B.b.$value = #{code}, $B.b)"
1573
+ else
1574
+ # block must have a try/catch wrapper inside to detect
1575
+ # breaks and return the break value if a break is fired.
1576
+ # We should also warn that the ruby code is not optimized
1577
+ # and suggest it is reconfigured to avoid the (possibly)
1578
+ # expensive try/catch block.
1579
+ "$break(#{code})"
1580
+ end
1581
+ else
1582
+ "$break(#{code})"
1583
+ end
1584
+ end
1585
+ end
1586
+
1587
+ class NextNode < BaseNode
1588
+
1589
+ def initialize(start, args)
1590
+ @line = start[:line]
1591
+ @args = args
1592
+ end
1593
+
1594
+ def returns
1595
+ self
1596
+ end
1597
+
1598
+ def generate(opts, level)
1599
+ code = []
1600
+
1601
+ if @args[0]
1602
+ @args[0].each { |arg| code << arg.generate(opts, LEVEL_EXPR) }
1603
+ end
1604
+
1605
+ case code.length
1606
+ when 0
1607
+ code = "nil"
1608
+ when 1
1609
+ code = code[0]
1610
+ else
1611
+ code = '[' + code.join(', ') + ']'
1612
+ end
1613
+
1614
+ if opts[:scope].in_while_scope?
1615
+ "continue"
1616
+ else
1617
+ # if in block
1618
+ "return #{code}"
1619
+ # else if in while/until loop
1620
+
1621
+ end
1622
+ end
1623
+ end
1624
+
1625
+ class RedoNode < BaseNode
1626
+
1627
+ def initialize(start)
1628
+ @line = start[:line]
1629
+ end
1630
+
1631
+ def generate(opts, level)
1632
+ if opts[:scope].in_while_scope?
1633
+ "#{opts[:scope].while_scope.redo_var} = true"
1634
+ else
1635
+ "REDO()"
1636
+ end
1637
+ end
1638
+ end
1639
+
1640
+ class WhileNode < BaseNode
1641
+
1642
+ attr_reader :redo_var
1643
+
1644
+ def initialize(begn, exp, stmt, endn)
1645
+ @line = begn[:line]
1646
+ @type = begn[:value]
1647
+ @expr = exp
1648
+ @stmt = stmt
1649
+ @end_line = endn[:line]
1650
+ end
1651
+
1652
+ def returns
1653
+ @returns = true
1654
+ self
1655
+ end
1656
+
1657
+ def set_captures_break
1658
+ tmp = @current_scope.temp_local
1659
+ @captures_break = tmp
1660
+ end
1661
+
1662
+ def generate(opts, level)
1663
+ @current_scope = opts[:scope]
1664
+ stmt_level = (level == LEVEL_EXPR ? LEVEL_TOP_CLOSURE : LEVEL_TOP)
1665
+ truthy = @type == 'while' ? '' : '!'
1666
+
1667
+ if stmt_level == LEVEL_TOP_CLOSURE
1668
+ returns
1669
+ @level_expr = true
1670
+ end
1671
+
1672
+ @redo_var = eval_expr = opts[:scope].temp_local
1673
+ code = "#{eval_expr} = false; while (#{eval_expr} || #{truthy}("
1674
+ code += @expr.generate opts, LEVEL_EXPR
1675
+ code += ").$r) {#{eval_expr} = false;"
1676
+
1677
+ opts[:scope].push_while_scope self
1678
+
1679
+ code += @stmt.process opts, LEVEL_TOP
1185
1680
 
1186
- parts = ["#{block}.$self"]
1681
+ opts[:scope].pop_while_scope
1682
+
1683
+ code += fix_line_number opts, @end_line
1684
+ code += "}"
1685
+
1686
+ opts[:scope].queue_temp eval_expr
1687
+
1688
+ return_value = "nil"
1689
+
1690
+ if @captures_break
1691
+ code = "#@captures_break = nil; #{code}"
1692
+ opts[:scope].queue_temp @captures_break
1693
+ return_value = @captures_break
1694
+ end
1695
+
1696
+ code = "(function() {#{code} return #{return_value};})()" if stmt_level == LEVEL_TOP_CLOSURE
1697
+ code
1698
+ end
1699
+ end
1700
+
1701
+ class SuperNode < BaseNode
1702
+
1703
+ def initialize(start, args)
1704
+ @line = start[:line]
1705
+ @args = args
1706
+ end
1707
+
1708
+ def generate(opts, level)
1709
+ parts = []
1187
1710
 
1188
1711
  if @args[0]
1189
1712
  @args[0].each { |arg| parts << arg.generate(opts, LEVEL_EXPR) }
1190
1713
  end
1191
1714
 
1192
- "#{block}(#{parts.join ', '})"
1715
+ "$super(arguments.callee, self, [#{parts.join ', '}])"
1193
1716
  end
1194
1717
  end
1195
1718
 
@@ -1214,6 +1737,9 @@ class Opal::RubyParser < Racc::Parser
1214
1737
  else
1215
1738
  # this really should return array of return vals
1216
1739
  code = NilNode.new.generate opts, level
1740
+ code = []
1741
+ args[0].each { |arg| code << arg.generate(opts, LEVEL_EXPR) }
1742
+ code = code = '[' + code.join(', ') + ']'
1217
1743
  end
1218
1744
 
1219
1745
  # if we are in a block, we need to throw return to nearest mthod
@@ -1241,16 +1767,16 @@ class Opal::RubyParser < Racc::Parser
1241
1767
  def generate(opts, level)
1242
1768
  code = "try {"
1243
1769
  old_indent = opts[:indent]
1244
- opts[:indent] += INDENT
1770
+ opts[:indent] = opts[:indent] + INDENT
1245
1771
 
1246
1772
  code += @body.process opts, LEVEL_TOP
1247
1773
  code += "} catch (__err__) {"
1248
1774
 
1249
1775
  @body.opt_rescue.each do |res|
1250
1776
  code += "#{fix_line_number opts, res[0][:line]}if (true){"
1251
- opts[:indent] += INDENT
1252
- opts[:scope].ensure_variable res[2].value
1253
- code += (res[2].value + " = __err__;")
1777
+ opts[:indent] = opts[:indent] + INDENT
1778
+ opts[:scope].ensure_variable res[2].value if res[2]
1779
+ code += (res[2].value + " = __err__;") if res[2]
1254
1780
  code += "#{res[3].process opts, LEVEL_TOP}}"
1255
1781
  opts[:indent] = old_indent + INDENT
1256
1782
  end
@@ -1262,6 +1788,20 @@ class Opal::RubyParser < Racc::Parser
1262
1788
  end
1263
1789
  end
1264
1790
 
1791
+ class TernaryNode < BaseNode
1792
+
1793
+ def initialize(expr, truthy, falsy)
1794
+ @line = expr.line
1795
+ @expr = expr
1796
+ @true = truthy
1797
+ @false = falsy
1798
+ end
1799
+
1800
+ def generate(opts, level)
1801
+ "(#{@expr.generate opts, LEVEL_EXPR}.$r ? #{@true.generate opts, LEVEL_EXPR} : #{@false.generate opts, LEVEL_EXPR})"
1802
+ end
1803
+ end
1804
+
1265
1805
  class GvarNode < BaseNode
1266
1806
 
1267
1807
  attr_reader :value
@@ -1272,7 +1812,7 @@ class Opal::RubyParser < Racc::Parser
1272
1812
  end
1273
1813
 
1274
1814
  def generate(opts, level)
1275
- "VM.gg('#{@value}')"
1815
+ "$rb.gg('#{@value}')"
1276
1816
  end
1277
1817
  end
1278
1818
 
@@ -1295,8 +1835,89 @@ class Opal::RubyParser < Racc::Parser
1295
1835
  end
1296
1836
 
1297
1837
  def generate(opts, level)
1298
- @val
1838
+ "(#{@val})"
1839
+ end
1840
+ end
1841
+
1842
+ class RegexpNode < BaseNode
1843
+
1844
+ def initialize(begn, parts)
1845
+ @line = begn[:line]
1846
+ @parts = parts
1847
+ end
1848
+
1849
+ def generate(opts, level)
1850
+ parts = @parts.map do |part|
1851
+ if part[0] == 'string_content'
1852
+ part[1][:value]
1853
+ elsif part[0] == 'string_dbegin'
1854
+ part[1].generate opts, LEVEL_EXPR
1855
+ end
1856
+ end
1857
+
1858
+ "/#{parts.join ''}/"
1859
+ end
1860
+ end
1861
+
1862
+ class WordsNode < BaseNode
1863
+
1864
+ def initialize(begn, parts, endn)
1865
+ @line = begn[:line]
1866
+ @parts = parts
1867
+ @end_line = endn[:line]
1868
+ end
1869
+
1870
+ def generate(opts, level)
1871
+ parts = @parts.map do |part|
1872
+ if part[0] == 'string_content'
1873
+ part[1][:value].inspect
1874
+ else
1875
+ CallNode.new(part[1], {:value => 'to_s', :line => @line }, []).generate(opts, LEVEL_EXPR)
1876
+ end
1877
+ end
1878
+
1879
+ '[' + parts.join(', ') + ']'
1880
+ end
1881
+ end
1882
+
1883
+ class RangeNode < BaseNode
1884
+
1885
+ def initialize(range, beg, last)
1886
+ @line = beg.line
1887
+ @beg = beg
1888
+ @last = last
1889
+ @range = range[:value]
1890
+ @end_line = last.line
1891
+ end
1892
+
1893
+ def generate(opts, level)
1894
+ beg = @beg.generate opts, LEVEL_EXPR
1895
+ last = @last.generate opts, LEVEL_EXPR
1896
+ excl = @range == '...'
1897
+ "$range(#{beg}, #{last}, #{excl})"
1898
+ end
1899
+ end
1900
+
1901
+ class UndefNode < BaseNode
1902
+
1903
+ def initialize(start, parts)
1904
+ @line = start[:line]
1905
+ @parts = parts
1906
+ end
1907
+
1908
+ def generate(opts, level)
1909
+ parts = @parts.map do |a|
1910
+ if a.is_a? SymbolNode
1911
+ a.generate opts, level
1912
+ else
1913
+ '"' + a[:value] + '"'
1914
+ end
1915
+ end
1916
+ parts.unshift 'self'
1917
+ "$rb.um(#{parts.join ', '})"
1299
1918
  end
1300
1919
  end
1301
1920
  end
1921
+ end
1922
+
1302
1923