opal 0.3.2 → 0.3.6

Sign up to get free protection for your applications and to get access to all the features.
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