opal 0.4.3 → 0.4.4

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 (303) hide show
  1. data/.rspec +3 -0
  2. data/.travis.yml +0 -4
  3. data/README.md +6 -0
  4. data/Rakefile +30 -6
  5. data/bin/opal +6 -82
  6. data/corelib/{opal/array.rb → array.rb} +40 -56
  7. data/corelib/{opal/basic_object.rb → basic_object.rb} +2 -2
  8. data/corelib/{opal/boolean.rb → boolean.rb} +0 -8
  9. data/corelib/class.rb +47 -0
  10. data/corelib/{opal/comparable.rb → comparable.rb} +0 -0
  11. data/corelib/{opal/enumerable.rb → enumerable.rb} +208 -141
  12. data/corelib/{opal/enumerator.rb → enumerator.rb} +3 -3
  13. data/corelib/{opal/error.rb → error.rb} +1 -0
  14. data/corelib/{opal/hash.rb → hash.rb} +67 -56
  15. data/corelib/io.rb +39 -0
  16. data/corelib/{opal/kernel.rb → kernel.rb} +35 -31
  17. data/corelib/{opal/class.rb → module.rb} +29 -57
  18. data/corelib/native.rb +148 -0
  19. data/corelib/{opal/nil_class.rb → nil_class.rb} +2 -10
  20. data/corelib/{opal/numeric.rb → numeric.rb} +39 -14
  21. data/corelib/opal.rb +42 -25
  22. data/corelib/{opal/proc.rb → proc.rb} +3 -3
  23. data/corelib/{opal/range.rb → range.rb} +5 -1
  24. data/corelib/{opal/regexp.rb → regexp.rb} +0 -0
  25. data/corelib/{opal/runtime.js → runtime.js} +96 -188
  26. data/corelib/{opal/string.rb → string.rb} +20 -15
  27. data/corelib/struct.rb +139 -0
  28. data/corelib/{opal/time.rb → time.rb} +0 -0
  29. data/lib/opal.rb +4 -0
  30. data/lib/opal/cli.rb +79 -32
  31. data/lib/opal/cli_options.rb +91 -0
  32. data/lib/opal/erb.rb +41 -8
  33. data/lib/opal/grammar.rb +24 -10
  34. data/lib/opal/grammar.y +15 -4
  35. data/lib/opal/grammar_helpers.rb +4 -0
  36. data/lib/opal/lexer.rb +214 -143
  37. data/lib/opal/parser.rb +596 -562
  38. data/lib/opal/require_parser.rb +1 -1
  39. data/lib/opal/source_map.rb +15 -30
  40. data/lib/opal/target_scope.rb +24 -5
  41. data/lib/opal/version.rb +1 -1
  42. data/mri_spec/cli_spec.rb +18 -0
  43. data/mri_spec/fixtures/opal_file.rb +2 -0
  44. data/mri_spec/spec_helper.rb +17 -0
  45. data/opal.gemspec +5 -2
  46. data/spec/{rubyspec/filters → filters}/bugs/alias.rb +0 -0
  47. data/spec/{rubyspec/filters → filters}/bugs/ancestors.rb +0 -0
  48. data/spec/{rubyspec/filters → filters}/bugs/array.rb +0 -0
  49. data/spec/filters/bugs/array/combination.rb +11 -0
  50. data/spec/filters/bugs/array/count.rb +3 -0
  51. data/spec/filters/bugs/array/delete_if.rb +3 -0
  52. data/spec/filters/bugs/array/drop.rb +3 -0
  53. data/spec/filters/bugs/array/drop_while.rb +5 -0
  54. data/spec/filters/bugs/array/eql.rb +3 -0
  55. data/spec/filters/bugs/array/flatten.rb +9 -0
  56. data/spec/filters/bugs/array/minus.rb +5 -0
  57. data/spec/filters/bugs/array/multipliy.rb +9 -0
  58. data/spec/filters/bugs/array/new.rb +3 -0
  59. data/spec/filters/bugs/array/pop.rb +6 -0
  60. data/spec/filters/bugs/array/rassoc.rb +4 -0
  61. data/spec/filters/bugs/array/rindex.rb +6 -0
  62. data/spec/filters/bugs/array/select.rb +3 -0
  63. data/spec/filters/bugs/array/shift.rb +7 -0
  64. data/spec/filters/bugs/array/shuffle.rb +11 -0
  65. data/spec/filters/bugs/array/slice.rb +7 -0
  66. data/spec/filters/bugs/array/take.rb +3 -0
  67. data/spec/filters/bugs/array/to_a.rb +3 -0
  68. data/spec/filters/bugs/array/try_convert.rb +7 -0
  69. data/spec/filters/bugs/array/uniq.rb +10 -0
  70. data/spec/filters/bugs/array/zip.rb +4 -0
  71. data/spec/{rubyspec/filters → filters}/bugs/array_delete.rb +1 -0
  72. data/spec/{rubyspec/filters → filters}/bugs/array_fetch.rb +0 -0
  73. data/spec/{rubyspec/filters → filters}/bugs/array_first.rb +0 -0
  74. data/spec/{rubyspec/filters → filters}/bugs/array_flatten.rb +0 -0
  75. data/spec/{rubyspec/filters → filters}/bugs/array_intersection.rb +0 -0
  76. data/spec/{rubyspec/filters → filters}/bugs/array_join.rb +0 -0
  77. data/spec/{rubyspec/filters → filters}/bugs/break.rb +0 -0
  78. data/spec/filters/bugs/case.rb +4 -0
  79. data/spec/{rubyspec/filters → filters}/bugs/coerce_integer.rb +0 -0
  80. data/spec/filters/bugs/enumerable_sort_by.rb +3 -0
  81. data/spec/{rubyspec/filters → filters}/bugs/kernel/instance_variables.rb +0 -0
  82. data/spec/filters/bugs/kernel/rand.rb +4 -0
  83. data/spec/filters/bugs/language/array.rb +3 -0
  84. data/spec/filters/bugs/language/block.rb +6 -0
  85. data/spec/filters/bugs/language/break.rb +3 -0
  86. data/spec/{rubyspec/filters → filters}/bugs/language/class.rb +3 -0
  87. data/spec/{rubyspec/filters → filters}/bugs/language/class_variables.rb +0 -0
  88. data/spec/filters/bugs/language/def.rb +27 -0
  89. data/spec/filters/bugs/language/defined.rb +3 -0
  90. data/spec/filters/bugs/language/ensure.rb +4 -0
  91. data/spec/filters/bugs/language/execution.rb +4 -0
  92. data/spec/filters/bugs/language/for.rb +18 -0
  93. data/spec/filters/bugs/language/if.rb +13 -0
  94. data/spec/filters/bugs/language/loop.rb +4 -0
  95. data/spec/filters/bugs/language/metaclass.rb +14 -0
  96. data/spec/filters/bugs/language/module.rb +6 -0
  97. data/spec/filters/bugs/language/next.rb +3 -0
  98. data/spec/filters/bugs/language/or.rb +3 -0
  99. data/spec/filters/bugs/language/order.rb +4 -0
  100. data/spec/filters/bugs/language/precedence.rb +10 -0
  101. data/spec/filters/bugs/language/proc.rb +24 -0
  102. data/spec/filters/bugs/language/redo.rb +5 -0
  103. data/spec/filters/bugs/language/rescue.rb +9 -0
  104. data/spec/filters/bugs/language/retry.rb +5 -0
  105. data/spec/filters/bugs/language/send.rb +10 -0
  106. data/spec/filters/bugs/language/super.rb +9 -0
  107. data/spec/filters/bugs/language/until.rb +8 -0
  108. data/spec/filters/bugs/language/variables.rb +37 -0
  109. data/spec/filters/bugs/language/while.rb +6 -0
  110. data/spec/filters/bugs/language/yield.rb +5 -0
  111. data/spec/{rubyspec/filters → filters}/bugs/module/class_variables.rb +0 -0
  112. data/spec/filters/bugs/module/method_defined.rb +6 -0
  113. data/spec/filters/bugs/parser.rb +10 -0
  114. data/spec/{rubyspec/filters → filters}/bugs/public_methods.rb +1 -0
  115. data/spec/filters/bugs/return.rb +7 -0
  116. data/spec/filters/bugs/singleton/instance.rb +4 -0
  117. data/spec/filters/bugs/source_map.rb +3 -0
  118. data/spec/filters/bugs/string/center.rb +4 -0
  119. data/spec/filters/bugs/string/lines.rb +3 -0
  120. data/spec/{rubyspec/filters → filters}/mspec/mocks.rb +0 -0
  121. data/spec/{rubyspec/filters → filters}/mspec/ruby_exe.rb +0 -0
  122. data/spec/{rubyspec/filters → filters}/mspec/should_receive.rb +0 -0
  123. data/spec/{rubyspec/filters → filters}/parser/block_args.rb +0 -0
  124. data/spec/{rubyspec/filters → filters}/unsupported/array_subclasses.rb +1 -0
  125. data/spec/filters/unsupported/frozen.rb +32 -0
  126. data/spec/filters/unsupported/immutable_strings.rb +3 -0
  127. data/spec/filters/unsupported/tainted.rb +17 -0
  128. data/spec/filters/unsupported/trusted.rb +15 -0
  129. data/spec/opal/class/constants_spec.rb +7 -0
  130. data/spec/opal/erb/erb_spec.rb +7 -1
  131. data/spec/opal/erb/inline_block.opalerb +3 -0
  132. data/spec/opal/hash/allocate_spec.rb +16 -0
  133. data/spec/opal/hash/new_spec.rb +10 -0
  134. data/spec/opal/hash/to_s_spec.rb +9 -0
  135. data/spec/opal/kernel/instance_variable_defined_spec.rb +15 -0
  136. data/spec/opal/kernel/rand_spec.rb +5 -5
  137. data/spec/opal/kernel/respond_to_spec.rb +14 -1
  138. data/spec/opal/language/block_spec.rb +13 -0
  139. data/spec/opal/language/rescue_spec.rb +27 -0
  140. data/spec/opal/language/return_spec.rb +38 -0
  141. data/spec/opal/language/singleton_class_spec.rb +13 -0
  142. data/spec/opal/language/super_spec.rb +99 -0
  143. data/spec/opal/language/variables_spec.rb +20 -0
  144. data/spec/opal/module/attr_accessor_spec.rb +8 -0
  145. data/spec/opal/module/constants_spec.rb +2 -2
  146. data/spec/opal/native/alias_native_spec.rb +18 -0
  147. data/spec/opal/native/each_spec.rb +14 -0
  148. data/spec/opal/native/element_reference_spec.rb +14 -0
  149. data/spec/opal/native/method_missing_spec.rb +39 -0
  150. data/spec/opal/native/new_spec.rb +19 -0
  151. data/spec/opal/native/nil_spec.rb +14 -0
  152. data/spec/opal/runtime2/class_hierarchy_spec.rb +2 -2
  153. data/spec/opal/source_map_spec.rb +3 -7
  154. data/spec/ospec/main.rb.erb +2 -5
  155. data/spec/parser/alias_spec.rb +4 -4
  156. data/spec/parser/and_spec.rb +2 -2
  157. data/spec/parser/array_spec.rb +6 -6
  158. data/spec/parser/attrasgn_spec.rb +8 -8
  159. data/spec/parser/begin_spec.rb +11 -11
  160. data/spec/parser/block_spec.rb +3 -3
  161. data/spec/parser/break_spec.rb +4 -4
  162. data/spec/parser/call_spec.rb +50 -48
  163. data/spec/parser/class_spec.rb +2 -2
  164. data/spec/parser/const_spec.rb +1 -1
  165. data/spec/parser/cvar_spec.rb +1 -1
  166. data/spec/parser/def_spec.rb +5 -5
  167. data/spec/parser/gvar_spec.rb +2 -2
  168. data/spec/parser/hash_spec.rb +4 -4
  169. data/spec/parser/iasgn_spec.rb +3 -3
  170. data/spec/parser/if_spec.rb +6 -6
  171. data/spec/parser/iter_spec.rb +6 -6
  172. data/spec/parser/lambda_spec.rb +5 -5
  173. data/spec/parser/lasgn_spec.rb +2 -2
  174. data/spec/parser/line_spec.rb +2 -2
  175. data/spec/parser/lvar_spec.rb +5 -5
  176. data/spec/parser/masgn_spec.rb +1 -1
  177. data/spec/parser/module_spec.rb +2 -2
  178. data/spec/parser/not_spec.rb +4 -4
  179. data/spec/parser/op_asgn1_spec.rb +2 -2
  180. data/spec/parser/op_asgn2_spec.rb +2 -2
  181. data/spec/parser/or_spec.rb +2 -2
  182. data/spec/parser/parse_spec.rb +66 -0
  183. data/spec/parser/parser_spec.rb +32 -38
  184. data/spec/parser/regexp_spec.rb +4 -4
  185. data/spec/parser/return_spec.rb +4 -4
  186. data/spec/parser/sclass_spec.rb +4 -4
  187. data/spec/parser/str_spec.rb +3 -3
  188. data/spec/parser/super_spec.rb +6 -6
  189. data/spec/parser/undef_spec.rb +3 -3
  190. data/spec/parser/unless_spec.rb +4 -4
  191. data/spec/parser/while_spec.rb +3 -3
  192. data/spec/parser/xstr_spec.rb +3 -3
  193. data/spec/parser/yield_spec.rb +6 -6
  194. data/spec/rubyspec/core/array/drop_spec.rb +1 -1
  195. data/spec/rubyspec/core/array/keep_if_spec.rb +1 -3
  196. data/spec/rubyspec/core/array/length_spec.rb +1 -3
  197. data/spec/rubyspec/core/array/map_spec.rb +2 -6
  198. data/spec/rubyspec/core/array/minus_spec.rb +3 -3
  199. data/spec/rubyspec/core/array/multiply_spec.rb +14 -16
  200. data/spec/rubyspec/core/array/new_spec.rb +3 -5
  201. data/spec/rubyspec/core/array/plus_spec.rb +2 -2
  202. data/spec/rubyspec/core/array/pop_spec.rb +4 -4
  203. data/spec/rubyspec/core/array/rassoc_spec.rb +2 -2
  204. data/spec/rubyspec/core/array/reject_spec.rb +2 -6
  205. data/spec/rubyspec/core/array/replace_spec.rb +1 -3
  206. data/spec/rubyspec/core/array/reverse_each_spec.rb +1 -3
  207. data/spec/rubyspec/core/array/reverse_spec.rb +4 -4
  208. data/spec/rubyspec/core/array/rindex_spec.rb +1 -1
  209. data/spec/rubyspec/core/array/select_spec.rb +3 -7
  210. data/spec/rubyspec/core/array/shared/collect.rb +7 -0
  211. data/spec/rubyspec/core/array/shared/index.rb +1 -1
  212. data/spec/rubyspec/core/array/shared/keep_if.rb +3 -0
  213. data/spec/rubyspec/core/array/shared/length.rb +3 -0
  214. data/spec/rubyspec/core/array/shared/replace.rb +3 -0
  215. data/spec/rubyspec/core/array/shared/slice.rb +3 -0
  216. data/spec/rubyspec/core/array/shuffle_spec.rb +1 -1
  217. data/spec/rubyspec/core/array/size_spec.rb +1 -3
  218. data/spec/rubyspec/core/array/slice_spec.rb +4 -6
  219. data/spec/rubyspec/core/array/sort_spec.rb +2 -2
  220. data/spec/rubyspec/core/array/to_a_spec.rb +1 -1
  221. data/spec/rubyspec/core/array/try_convert_spec.rb +7 -7
  222. data/spec/rubyspec/core/array/uniq_spec.rb +7 -7
  223. data/spec/rubyspec/core/array/zip_spec.rb +1 -1
  224. data/spec/rubyspec/core/enumerable/collect_spec.rb +24 -0
  225. data/spec/rubyspec/core/enumerable/count_spec.rb +35 -19
  226. data/spec/rubyspec/core/enumerable/find_spec.rb +5 -0
  227. data/spec/rubyspec/core/hash/each_pair_spec.rb +7 -7
  228. data/spec/rubyspec/core/hash/each_spec.rb +13 -7
  229. data/spec/rubyspec/core/module/method_defined_spec.rb +4 -4
  230. data/spec/rubyspec/core/module/public_method_defined_spec.rb +19 -0
  231. data/spec/rubyspec/core/module/remove_const_spec.rb +23 -0
  232. data/spec/rubyspec/core/numeric/step_spec.rb +14 -0
  233. data/spec/rubyspec/core/string/center_spec.rb +43 -65
  234. data/spec/rubyspec/core/string/lines_spec.rb +1 -1
  235. data/spec/rubyspec/core/string/ljust_spec.rb +25 -9
  236. data/spec/rubyspec/core/string/rjust_spec.rb +26 -10
  237. data/spec/rubyspec/core/struct/fixtures/classes.rb +26 -0
  238. data/spec/rubyspec/core/struct/initialize_spec.rb +11 -0
  239. data/spec/rubyspec/core/struct/new_spec.rb +24 -0
  240. data/spec/rubyspec/fixtures/constants.rb +7 -0
  241. data/spec/rubyspec/language/break_spec.rb +1 -1
  242. data/spec/rubyspec/language/case_spec.rb +30 -30
  243. data/spec/rubyspec/language/def_spec.rb +34 -34
  244. data/spec/rubyspec/language/defined_spec.rb +2 -2
  245. data/spec/rubyspec/language/ensure_spec.rb +2 -2
  246. data/spec/rubyspec/language/execution_spec.rb +2 -2
  247. data/spec/rubyspec/language/for_spec.rb +17 -17
  248. data/spec/rubyspec/language/hash_spec.rb +3 -3
  249. data/spec/rubyspec/language/if_spec.rb +11 -11
  250. data/spec/rubyspec/language/loop_spec.rb +3 -3
  251. data/spec/rubyspec/language/metaclass_spec.rb +14 -14
  252. data/spec/rubyspec/language/module_spec.rb +6 -6
  253. data/spec/rubyspec/language/next_spec.rb +5 -5
  254. data/spec/rubyspec/language/not_spec.rb +1 -1
  255. data/spec/rubyspec/language/or_spec.rb +1 -1
  256. data/spec/rubyspec/language/order_spec.rb +3 -5
  257. data/spec/rubyspec/language/precedence_spec.rb +19 -19
  258. data/spec/rubyspec/language/proc_spec.rb +29 -29
  259. data/spec/rubyspec/language/redo_spec.rb +3 -5
  260. data/spec/rubyspec/language/rescue_spec.rb +7 -7
  261. data/spec/rubyspec/language/retry_spec.rb +2 -2
  262. data/spec/rubyspec/language/return_spec.rb +12 -12
  263. data/spec/rubyspec/language/send_spec.rb +9 -9
  264. data/spec/rubyspec/language/singleton_class_spec.rb +3 -4
  265. data/spec/rubyspec/language/super_spec.rb +7 -11
  266. data/spec/rubyspec/language/until_spec.rb +10 -10
  267. data/spec/rubyspec/language/variables_spec.rb +59 -67
  268. data/spec/rubyspec/language/versions/array_1.9.rb +1 -1
  269. data/spec/rubyspec/language/versions/block_1.9.rb +0 -0
  270. data/spec/rubyspec/language/versions/break_1.9.rb +0 -0
  271. data/spec/rubyspec/language/versions/literal_lambda_1.9.rb +12 -12
  272. data/spec/rubyspec/language/versions/send_1.9.rb +23 -23
  273. data/spec/rubyspec/language/versions/symbol_1.9.rb +2 -2
  274. data/spec/rubyspec/language/versions/variables_1.9.rb +1 -1
  275. data/spec/rubyspec/language/while_spec.rb +4 -4
  276. data/spec/rubyspec/language/yield_spec.rb +3 -3
  277. data/spec/rubyspec/library/erb/util/html_escape_spec.rb +10 -0
  278. data/spec/rubyspec/library/singleton/clone_spec.rb +8 -0
  279. data/spec/rubyspec/library/singleton/dup_spec.rb +8 -0
  280. data/spec/rubyspec/library/singleton/fixtures/classes.rb +18 -0
  281. data/spec/rubyspec/library/singleton/instance_spec.rb +30 -0
  282. data/spec/spec_helper.rb +214 -0
  283. data/stdlib/buffer.rb +40 -0
  284. data/stdlib/buffer/array.rb +66 -0
  285. data/stdlib/buffer/view.rb +70 -0
  286. data/stdlib/erb.rb +11 -20
  287. data/stdlib/forwardable.rb +71 -0
  288. data/stdlib/json.rb +78 -0
  289. data/stdlib/ostruct.rb +69 -0
  290. data/stdlib/rbconfig.rb +1 -0
  291. data/stdlib/singleton.rb +40 -0
  292. data/stdlib/stringio.rb +173 -0
  293. data/stdlib/template.rb +44 -0
  294. metadata +285 -79
  295. data/corelib/opal/native.rb +0 -31
  296. data/spec/opal/class/bridge_class_spec.rb +0 -39
  297. data/spec/opal/native_spec.rb +0 -209
  298. data/spec/ospec/runner.rb +0 -223
  299. data/spec/rubyspec/filters/bugs/block_args.rb +0 -3
  300. data/spec/rubyspec/filters/bugs/case.rb +0 -8
  301. data/spec/rubyspec/filters/bugs/language/module.rb +0 -3
  302. data/spec/rubyspec/filters/unsupported/frozen.rb +0 -4
  303. data/spec/rubyspec/filters/unsupported/tainted.rb +0 -7
data/lib/opal/parser.rb CHANGED
@@ -6,15 +6,21 @@ require 'opal/version'
6
6
  module Opal
7
7
  class Parser
8
8
 
9
+ # A fragment holds a string of generated javascript that will be written
10
+ # to the destination. It also keeps hold of the original sexp from which
11
+ # it was generated. Using this sexp, when writing fragments in order, a
12
+ # mapping can be created of the original location => target location,
13
+ # aka, source-maps!
9
14
  class Fragment
10
-
15
+ # String of javascript this fragment holds
11
16
  attr_reader :code
12
17
 
13
18
  def initialize(code, sexp = nil)
14
- @code = code
19
+ @code = code.to_s
15
20
  @sexp = sexp
16
21
  end
17
22
 
23
+ # In debug mode we may wish to include the original line as a comment
18
24
  def to_code
19
25
  if @sexp
20
26
  "/*:#{@sexp.line}*/#{@code}"
@@ -23,8 +29,13 @@ module Opal
23
29
  end
24
30
  end
25
31
 
32
+ # inspect the contents of this fragment, f("fooo")
26
33
  def inspect
27
- "fragment(#{@code.inspect})"
34
+ "f(#{@code.inspect})"
35
+ end
36
+
37
+ def line
38
+ @sexp.line if @sexp
28
39
  end
29
40
  end
30
41
 
@@ -51,8 +62,16 @@ module Opal
51
62
  # Statements which should not have ';' added to them.
52
63
  STATEMENTS = [:xstr, :dxstr]
53
64
 
65
+ # Final generated javascript for this parser
54
66
  attr_reader :result
55
67
 
68
+ # generated fragments as an array
69
+ attr_reader :fragments
70
+
71
+ # Parse some ruby code to a string.
72
+ #
73
+ # Opal::Parser.new.parse("1 + 2")
74
+ # # => "(function() {....})()"
56
75
  def parse(source, options = {})
57
76
  @sexp = Grammar.new.parse(source, options[:file])
58
77
  @line = 1
@@ -68,29 +87,45 @@ module Opal
68
87
  @file = options[:file] || '(file)'
69
88
  @source_file = options[:source_file] || @file
70
89
  @method_missing = (options[:method_missing] != false)
71
- @optimized_operators = (options[:optimized_operators] != false)
72
90
  @arity_check = options[:arity_check]
73
91
  @const_missing = (options[:const_missing] != false)
74
92
  @irb_vars = (options[:irb] == true)
75
- @source_map = (options[:source_map_enabled] != false)
76
93
 
77
- fragments = self.top(@sexp).flatten
94
+ @method_calls = {}
78
95
 
79
- code = @source_map ? fragments.map(&:to_code).join('') : fragments.map(&:code).join('')
96
+ @fragments = self.top(@sexp).flatten
80
97
 
81
- @result = source_map_comment + version_comment + file_comment + code
98
+ @fragments.unshift f(version_comment)
99
+
100
+ @result = @fragments.map(&:code).join('')
82
101
  end
83
102
 
103
+ # Always at top of generated file to show current opal version
84
104
  def version_comment
85
105
  "/* Generated by Opal #{Opal::VERSION} */\n"
86
106
  end
87
107
 
88
- def source_map_comment
89
- @source_map ? "//@ sourceMappingURL=/__opal_source_maps__/#{@file}.js.map\n" : ''
108
+ def source_map
109
+ Opal::SourceMap.new(@fragments, '(file)')
90
110
  end
91
111
 
92
- def file_comment
93
- @source_map ? "/*-file:#{@source_file}-*/" : ''
112
+ def extract_parser_options(content)
113
+ result = {}
114
+
115
+ if /^#\ opal\:(.*)/ =~ content
116
+ $~[1].split(',').map(&:strip).each do |opt|
117
+ next if opt == ""
118
+ opt = opt.gsub('-', '_')
119
+
120
+ if opt =~ /no_/
121
+ result[opt.sub(/no_/, '').to_sym] = false
122
+ else
123
+ result[opt.to_sym] = true
124
+ end
125
+ end
126
+ end
127
+
128
+ result
94
129
  end
95
130
 
96
131
  # This is called when a parsing/processing error occurs. This
@@ -139,10 +174,12 @@ module Opal
139
174
 
140
175
  # @param [String] code the string of code
141
176
  # @return [Fragment]
142
- def fragment(code, sexp = nil)
177
+ def f(code, sexp = nil)
143
178
  Fragment.new(code, sexp)
144
179
  end
145
180
 
181
+ alias_method :fragment, :f
182
+
146
183
  # Converts a ruby method name into its javascript equivalent for
147
184
  # a method/function call. All ruby method names get prefixed with
148
185
  # a '$', and if the name is a valid javascript identifier, it will
@@ -164,6 +201,13 @@ module Opal
164
201
  end
165
202
  end
166
203
 
204
+ # Converts a ruby lvar/arg name to a js identifier. Not all ruby names
205
+ # are valid in javascript. A $ suffix is added to non-valid names.
206
+ def lvar_to_js(var)
207
+ var = "#{var}$" if RESERVED.include? var.to_s
208
+ var.to_sym
209
+ end
210
+
167
211
  # Used to generate a unique id name per file. These are used
168
212
  # mainly to name method bodies for methods that use blocks.
169
213
  #
@@ -192,24 +236,29 @@ module Opal
192
236
 
193
237
  code = process(scope, :stmt)
194
238
  code = [code] unless code.is_a? Array
195
- code.unshift fragment(@indent, sexp)
239
+ code.unshift f(@indent, sexp)
196
240
  }
197
241
 
198
- @scope.add_temp "self = __opal.top"
199
- @scope.add_temp "__scope = __opal"
200
- @scope.add_temp "$mm = __opal.mm"
201
- @scope.add_temp "nil = __opal.nil"
202
- @scope.add_temp "def = __opal.Object._proto" if @scope.defines_defn
203
- @helpers.keys.each { |h| @scope.add_temp "__#{h} = __opal.#{h}" }
242
+ @scope.add_temp "self = $opal.top"
243
+ @scope.add_temp "$scope = $opal"
244
+ @scope.add_temp "nil = $opal.nil"
245
+ @scope.add_temp "def = $opal.Object._proto" if @scope.defines_defn
246
+ @helpers.keys.each { |h| @scope.add_temp "$#{h} = $opal.#{h}" }
204
247
 
205
- vars = [fragment(INDENT, sexp), @scope.to_vars, fragment("\n", sexp)]
248
+ vars = [f(INDENT, sexp), @scope.to_vars, f("\n", sexp)]
206
249
 
207
250
  if @irb_vars
208
- code.unshift fragment("if (!Opal.irb_vars) { Opal.irb_vars = {}; }\n", sexp)
251
+ code.unshift f("if (!$opal.irb_vars) { $opal.irb_vars = {}; }\n", sexp)
209
252
  end
210
253
  end
211
254
 
212
- [fragment("(function(__opal) {\n", sexp), vars, code, fragment("\n})(Opal);\n", sexp)]
255
+ if @method_missing
256
+ stubs = f("\n#{INDENT}$opal.add_stubs([" + @method_calls.keys.map { |k| "'$#{k}'" }.join(", ") + "]);\n", sexp)
257
+ else
258
+ stubs = []
259
+ end
260
+
261
+ [f("(function($opal) {\n", sexp), vars, stubs, code, f("\n})(Opal);\n", sexp)]
213
262
  end
214
263
 
215
264
  # Every time the parser enters a new scope, this is called with
@@ -296,6 +345,14 @@ module Opal
296
345
  result
297
346
  end
298
347
 
348
+ def in_case
349
+ return unless block_given?
350
+ old = @case_stmt
351
+ @case_stmt = {}
352
+ yield
353
+ @case_stmt = old
354
+ end
355
+
299
356
  # Returns true if the parser is curently handling a while sexp,
300
357
  # false otherwise.
301
358
  #
@@ -318,7 +375,7 @@ module Opal
318
375
  # @param [Array] sexp the sexp to process
319
376
  # @param [Symbol] level the level to process (see `LEVEL`)
320
377
  # @return [String]
321
- def process(sexp, level)
378
+ def process(sexp, level = :expr)
322
379
  type = sexp.shift
323
380
  meth = "process_#{type}"
324
381
  raise "Unsupported sexp: #{type}" unless respond_to? meth
@@ -373,6 +430,10 @@ module Opal
373
430
  sexp
374
431
  when :rescue
375
432
  sexp[1] = returns sexp[1]
433
+
434
+ if sexp[2] and sexp[2][0] == :resbody and sexp[2][2]
435
+ sexp[2][2] = returns sexp[2][2]
436
+ end
376
437
  sexp
377
438
  when :ensure
378
439
  sexp[1] = returns sexp[1]
@@ -422,30 +483,23 @@ module Opal
422
483
  #
423
484
  # @return [String]
424
485
  def process_block(sexp, level)
425
- result = []
426
- sexp << s(:nil) if sexp.empty?
486
+ return process s(:nil) if sexp.empty?
427
487
 
488
+ result = []
428
489
  join = (@scope.class_scope? ? "\n\n#@indent" : "\n#@indent")
429
490
 
430
- until sexp.empty?
431
- stmt = sexp.shift
432
-
433
- result << fragment(join, sexp) unless result.empty?
491
+ sexp.each do |stmt|
492
+ result << f(join, sexp) unless result.empty?
434
493
 
435
494
  # find any inline yield statements
436
495
  if yasgn = find_inline_yield(stmt)
437
- result << process(yasgn, level)
438
- result << fragment(";", yasgn)
496
+ result << process(yasgn, level) << f(";", yasgn)
439
497
  end
440
498
 
441
499
  expr = expression?(stmt) and LEVEL.index(level) < LEVEL.index(:list)
442
500
 
443
- code = process(stmt, level)
444
-
445
- result << code
446
- if expr
447
- result << fragment(";", stmt)
448
- end
501
+ result << process(stmt, level)
502
+ result << f(";", stmt) if expr
449
503
  end
450
504
 
451
505
  result
@@ -476,12 +530,14 @@ module Opal
476
530
  found = nil
477
531
  case stmt.first
478
532
  when :js_return
479
- found = find_inline_yield stmt[1]
533
+ if found = find_inline_yield(stmt[1])
534
+ found = found[2]
535
+ end
480
536
  when :array
481
537
  stmt[1..-1].each_with_index do |el, idx|
482
538
  if el.first == :yield
483
539
  found = el
484
- stmt[idx+1] = s(:js_tmp, '__yielded')
540
+ stmt[idx+1] = s(:js_tmp, '$yielded')
485
541
  end
486
542
  end
487
543
  when :call
@@ -489,72 +545,42 @@ module Opal
489
545
  arglist[1..-1].each_with_index do |el, idx|
490
546
  if el.first == :yield
491
547
  found = el
492
- arglist[idx+1] = s(:js_tmp, '__yielded')
548
+ arglist[idx+1] = s(:js_tmp, '$yielded')
493
549
  end
494
550
  end
495
551
  end
496
552
 
497
553
  if found
498
- @scope.add_temp '__yielded' unless @scope.has_temp? '__yielded'
499
- s(:yasgn, '__yielded', found)
554
+ @scope.add_temp '$yielded' unless @scope.has_temp? '$yielded'
555
+ s(:yasgn, '$yielded', found)
500
556
  end
501
557
  end
502
558
 
503
559
  def process_scope(sexp, level)
504
- stmt = sexp.shift
505
- if stmt
506
- unless @scope.class_scope?
507
- stmt = returns stmt
508
- end
560
+ stmt = sexp[0] || s(:nil)
561
+ stmt = returns stmt unless @scope.class_scope?
509
562
 
510
- process stmt, :stmt
511
- else
512
- fragment("nil", sexp)
513
- end
563
+ process stmt, :stmt
514
564
  end
515
565
 
516
566
  # s(:js_return, sexp)
517
567
  def process_js_return(sexp, level)
518
- [fragment("return ", sexp), process(sexp.shift, :expr)]
568
+ [f("return ", sexp), process(sexp[0])]
519
569
  end
520
570
 
521
571
  # s(:js_tmp, str)
522
572
  def process_js_tmp(sexp, level)
523
- fragment(sexp.shift.to_s, sexp)
524
- end
525
-
526
- def process_operator(sexp, level)
527
- meth, recv, arg = sexp
528
- mid = mid_to_jsid meth.to_s
529
- result = []
530
-
531
- if @optimized_operators
532
- with_temp do |a|
533
- with_temp do |b|
534
- l = process recv, :expr
535
- r = process arg, :expr
536
-
537
- result << fragment("(#{a} = ", sexp)
538
- result << l
539
- result << fragment(", #{b} = ", sexp)
540
- result << r
541
- result << fragment(", typeof(#{a}) === 'number' ? #{a} #{meth} #{b} ", sexp)
542
- result << fragment(": #{a}#{mid}(#{b}))", sexp)
543
- end
544
- end
545
- else
546
- "#{process recv, :recv}#{mid}(#{process arg, :expr})"
547
- end
548
-
549
- result
573
+ f(sexp[0].to_s, sexp)
550
574
  end
551
575
 
552
576
  def js_block_given(sexp, level)
553
577
  @scope.uses_block!
554
578
  if @scope.block_name
555
- fragment("(#{@scope.block_name} !== nil)", sexp)
579
+ f("(#{@scope.block_name} !== nil)", sexp)
580
+ elsif scope = @scope.find_parent_def and scope.block_name
581
+ f("(#{scope.block_name} !== nil)", sexp)
556
582
  else
557
- fragment("false", sexp)
583
+ f("false", sexp)
558
584
  end
559
585
  end
560
586
 
@@ -562,127 +588,124 @@ module Opal
562
588
  @scope.uses_block!
563
589
  name = @scope.block_name
564
590
 
565
- fragment((reverse ? "#{ name } === nil" : "#{ name } !== nil"), sexp)
591
+ f((reverse ? "#{ name } === nil" : "#{ name } !== nil"), sexp)
566
592
  end
567
593
 
568
594
  def process_sym(sexp, level)
569
- fragment(sexp[0].to_s.inspect, sexp)
595
+ f(sexp[0].to_s.inspect, sexp)
570
596
  end
571
597
 
598
+ # Process integers. Wrap in parens if a receiver of method call
572
599
  def process_int(sexp, level)
573
- handle_number sexp, level
600
+ f((level == :recv ? "(#{sexp[0]})" : sexp[0].to_s), sexp)
574
601
  end
575
602
 
576
- def process_float(sexp, level)
577
- handle_number sexp, level
578
- end
579
-
580
- def handle_number(sexp, level)
581
- if level == :recv
582
- fragment("(#{sexp[0]})", sexp)
583
- else
584
- fragment(sexp[0].to_s, sexp)
585
- end
586
- end
603
+ # Floats generated just like integers
604
+ alias_method :process_float, :process_int
587
605
 
606
+ # Regexp literals. Convert to empty js regexp if empty (not compatible)
588
607
  def process_regexp(sexp, level)
589
608
  val = sexp[0]
590
- fragment((val == // ? /^/.inspect : val.inspect), sexp)
609
+ f((val == // ? /^/.inspect : val.inspect), sexp)
591
610
  end
592
611
 
612
+ # Dynamic regexps with interpolation
613
+ # s(:dregx, parts...) => new Regexp("...")
593
614
  def process_dregx(sexp, level)
594
615
  result = []
595
616
 
596
617
  sexp.each do |part|
597
- result << fragment(" + ", sexp) unless result.empty?
618
+ result << f(" + ", sexp) unless result.empty?
598
619
 
599
620
  if String === part
600
- result << fragment(part.inspect, sexp)
621
+ result << f(part.inspect, sexp)
601
622
  elsif part[0] == :str
602
- result << process(part, :expr)
623
+ result << process(part)
603
624
  else
604
- result << process(part[1], :expr)
625
+ result << process(part[1])
605
626
  end
606
627
  end
607
628
 
608
- [fragment("(new RegExp(", sexp), result, fragment("))", sexp)]
629
+ [f("(new RegExp(", sexp), result, f("))", sexp)]
609
630
  end
610
631
 
632
+ # Exclusive range, uses opal __range helper.
633
+ # s(:dot3, start, end) => __range(start, end, false)
611
634
  def process_dot2(sexp, level)
612
- lhs = process sexp[0], :expr
613
- rhs = process sexp[1], :expr
614
635
  @helpers[:range] = true
615
636
 
616
- [fragment("__range(", sexp), lhs, fragment(", ", sexp), rhs, fragment(", false)", sexp)]
637
+ [f("$range(", sexp), process(sexp[0]), f(", ", sexp), process(sexp[1]), f(", false)", sexp)]
617
638
  end
618
639
 
640
+ # Inclusive range, uses __range helper
641
+ # s(:dot3, start, end) => __range(start, end, true)
619
642
  def process_dot3(sexp, level)
620
- lhs = process sexp[0], :expr
621
- rhs = process sexp[1], :expr
622
643
  @helpers[:range] = true
623
644
 
624
- [fragment("__range(", sexp), lhs, fragment(", ", sexp), rhs, fragment(", true)", sexp)]
645
+ [f("$range(", sexp), process(sexp[0]), f(", ", sexp), process(sexp[1]), f(", true)", sexp)]
625
646
  end
626
647
 
627
- # s(:str, "string")
648
+ # Simple strings, no interpolation.
649
+ # s(:str, "string") => "string"
628
650
  def process_str(sexp, level)
629
- str = sexp.shift
630
- if str == @file
631
- @uses_file = true
632
- fragment(@file.inspect, sexp)
633
- else
634
- fragment(str.inspect, sexp)
635
- end
651
+ f sexp[0].inspect, sexp
636
652
  end
637
653
 
654
+ # defined?(x) => various
638
655
  def process_defined(sexp, level)
639
656
  part = sexp[0]
640
657
  case part[0]
641
658
  when :self
642
- fragment("self".inspect, sexp)
659
+ f("'self'", sexp)
643
660
  when :nil
644
- fragment("nil".inspect, sexp)
661
+ f("'nil'", sexp)
645
662
  when :true
646
- fragment("true".inspect, sexp)
663
+ f("'true'", sexp)
647
664
  when :false
648
- fragment("false".inspect, sexp)
665
+ f("'false'", sexp)
649
666
  when :call
650
667
  mid = mid_to_jsid part[2].to_s
651
- recv = part[1] ? process(part[1], :expr) : fragment(current_self, sexp)
652
- [fragment("(", sexp), recv, fragment("#{mid} ? 'method' : nil)", sexp)]
653
- when :xstr
654
- [fragment("(typeof(", sexp), process(part, :expr), fragment(") !== 'undefined')", sexp)]
668
+ recv = part[1] ? process(part[1]) : f(current_self, sexp)
669
+ [f("(", sexp), recv, f("#{mid} ? 'method' : nil)", sexp)]
670
+ when :xstr, :dxstr
671
+ [f("(typeof(", sexp), process(part), f(") !== 'undefined')", sexp)]
655
672
  when :const
656
- fragment("(__scope.#{part[1].to_s} != null)", sexp)
673
+ f("($scope.#{part[1].to_s} != null)", sexp)
674
+ when :cvar
675
+ f("($opal.cvars[#{part[1].to_s.inspect}] != null ? 'class-variable' : nil)", sexp)
657
676
  when :colon2
658
- fragment("false", sexp)
677
+ f("false", sexp)
659
678
  when :colon3
660
- fragment("(__opal.Object._scope.#{sexp[0][1]} == null ? nil : 'constant')", sexp)
679
+ f("($opal.Object._scope.#{sexp[0][1]} == null ? nil : 'constant')", sexp)
661
680
  when :ivar
662
681
  ivar_name = part[1].to_s[1..-1]
663
682
  with_temp do |t|
664
- fragment("((#{t} = #{current_self}[#{ivar_name.inspect}], #{t} != null && #{t} !== nil) ? 'instance-variable' : nil)", sexp)
683
+ f("((#{t} = #{current_self}[#{ivar_name.inspect}], #{t} != null && #{t} !== nil) ? 'instance-variable' : nil)", sexp)
665
684
  end
666
685
  when :lvar
667
- fragment("local-variable", sexp)
686
+ f("local-variable", sexp)
668
687
  else
669
688
  raise "bad defined? part: #{part[0]}"
670
689
  end
671
690
  end
672
691
 
673
- # s(:not, sexp)
692
+ # not keyword or '!' operand
693
+ # s(:not, value) => (tmp = value, (tmp === nil || tmp === false))
674
694
  def process_not(sexp, level)
675
695
  with_temp do |tmp|
676
- expr = sexp.shift
677
- [fragment("(#{tmp} = ", sexp), process(expr, :expr), fragment(", (#{tmp} === nil || #{tmp} === false))", sexp)]
696
+ expr = sexp[0]
697
+ [f("(#{tmp} = ", sexp), process(expr), f(", (#{tmp} === nil || #{tmp} === false))", sexp)]
678
698
  end
679
699
  end
680
700
 
701
+ # A block pass '&foo' syntax
702
+ # s(:block_pass, value) => value.$to_proc()
681
703
  def process_block_pass(exp, level)
682
- process(s(:call, exp.shift, :to_proc, s(:arglist)), :expr)
704
+ process s(:call, exp[0], :to_proc, s(:arglist))
683
705
  end
684
706
 
685
- # s(:iter, call, block_args [, body)
707
+ # A block/iter with embeded call. Compiles into function
708
+ # s(:iter, call, block_args [, body) => (function() { ... })
686
709
  def process_iter(sexp, level)
687
710
  call, args, body = sexp
688
711
 
@@ -698,6 +721,12 @@ module Opal
698
721
  args ||= s(:masgn, s(:array))
699
722
  args = args.first == :lasgn ? s(:array, args) : args[1]
700
723
 
724
+ # opt args are last, if present, and are a [:block]
725
+ if args.last.is_a?(Array) and args.last[0] == :block
726
+ opt_args = args.pop
727
+ opt_args.shift
728
+ end
729
+
701
730
  if args.last.is_a?(Array) and args.last[0] == :block_pass
702
731
  block_arg = args.pop
703
732
  block_arg = block_arg[1][1].to_sym
@@ -717,7 +746,12 @@ module Opal
717
746
  args[1..-1].each do |arg|
718
747
  arg = arg[1]
719
748
  arg = "#{arg}$" if RESERVED.include? arg.to_s
720
- code << fragment("if (#{arg} == null) #{arg} = nil;\n", sexp)
749
+
750
+ if opt_args and current_opt = opt_args.find { |s| s[1] == arg.to_sym }
751
+ code << [f("if (#{arg} == null) #{arg} = ", sexp), process(current_opt[2]), f(";\n", sexp)]
752
+ else
753
+ code << f("if (#{arg} == null) #{arg} = nil;\n", sexp)
754
+ end
721
755
  end
722
756
 
723
757
  params = js_block_args(args[1..-1])
@@ -725,47 +759,47 @@ module Opal
725
759
  if splat
726
760
  @scope.add_arg splat
727
761
  params << splat
728
- code << fragment("#{splat} = __slice.call(arguments, #{len - 1});", sexp)
762
+ code << f("#{splat} = $slice.call(arguments, #{len - 1});", sexp)
729
763
  end
730
764
 
731
765
  if block_arg
732
766
  @scope.block_name = block_arg
733
767
  @scope.add_temp block_arg
734
- @scope.add_temp '__context'
735
768
  scope_name = @scope.identify!
736
769
 
737
770
  blk = []
738
- blk << fragment("\n#@indent#{block_arg} = #{scope_name}._p || nil, #{scope_name}.p = null;\n#@indent", sexp)
771
+ blk << f("\n#@indent#{block_arg} = #{scope_name}._p || nil, #{scope_name}.p = null;\n#@indent", sexp)
739
772
 
740
773
  code.unshift blk
741
774
  end
742
775
 
743
- code << fragment("\n#@indent", sexp)
776
+ code << f("\n#@indent", sexp)
744
777
  code << process(body, :stmt)
745
778
 
746
779
  if @scope.defines_defn
747
780
  @scope.add_temp "def = ((#{current_self}._isClass) ? #{current_self}._proto : #{current_self})"
748
781
  end
749
782
 
750
- to_vars = [fragment("\n#@indent", sexp), @scope.to_vars, fragment("\n#@indent", sexp)]
783
+ to_vars = [f("\n#@indent", sexp), @scope.to_vars, f("\n#@indent", sexp)]
751
784
  end
752
785
  end
753
786
 
754
- itercode = [fragment("function(#{params.join ', '}) {\n", sexp), to_vars, code, fragment("\n#@indent}", sexp)]
787
+ itercode = [f("function(#{params.join ', '}) {\n", sexp), to_vars, code, f("\n#@indent}", sexp)]
755
788
 
756
- itercode.unshift fragment("(#{identity} = ", sexp)
757
- itercode << fragment(", #{identity}._s = #{current_self}, #{identity})", sexp)
789
+ itercode.unshift f("(#{identity} = ", sexp)
790
+ itercode << f(", #{identity}._s = #{current_self}, #{identity})", sexp)
758
791
 
759
792
  call << itercode
760
793
  process call, level
761
794
  end
762
795
 
796
+ # Maps block args into array of jsid. Adds $ suffix to invalid js
797
+ # identifiers.
798
+ #
799
+ # s(:args, parts...) => ["a", "b", "break$"]
763
800
  def js_block_args(sexp)
764
801
  sexp.map do |arg|
765
- a = arg[1].to_sym
766
- a = "#{a}$".to_sym if RESERVED.include? a.to_s
767
- @scope.add_arg a
768
- a
802
+ @scope.add_arg lvar_to_js(arg[1])
769
803
  end
770
804
  end
771
805
 
@@ -778,60 +812,25 @@ module Opal
778
812
  process s(:call, recv, mid, arglist), level
779
813
  end
780
814
 
781
- # Used to generate optimized attr_reader, attr_writer and
782
- # attr_accessor methods. These are optimized to avoid the added
783
- # cost of converting the method id's into jsid's at runtime.
784
- #
785
- # This method will only be called if all the given ids are strings
786
- # or symbols. Any dynamic arguments will default to being called
787
- # using the Module#attr_* methods as expected.
788
- #
789
- # @param [Symbol] meth :attr_{reader,writer,accessor}
790
- # @param [Array<Sexp>] attrs array of s(:sym) or s(:str)
791
- # @return [String] precompiled attr methods
792
- def handle_attr_optimize(meth, attrs)
793
- out = []
794
-
795
- attrs.each do |attr|
796
- mid = attr[1]
797
- ivar = "@#{mid}".to_sym
798
-
799
- unless meth == :attr_writer
800
- out << fragment(", \n#@indent") unless out.empty?
801
- out << process(s(:defn, mid, s(:args), s(:scope, s(:ivar, ivar))), :stmt)
802
- end
803
-
804
- unless meth == :attr_reader
805
- out << fragment(", \n#@indent") unless out.empty?
806
- mid = "#{mid}=".to_sym
807
- out << process(s(:defn, mid, s(:args, :val), s(:scope,
808
- s(:iasgn, ivar, s(:lvar, :val)))), :stmt)
809
- end
810
- end
811
-
812
- out << fragment(", nil")
813
- out
814
- end
815
-
816
815
  # s(:call, recv, :mid, s(:arglist))
817
816
  # s(:call, nil, :mid, s(:arglist))
818
817
  def process_call(sexp, level)
819
818
  recv, meth, arglist, iter = sexp
820
819
  mid = mid_to_jsid meth.to_s
821
820
 
821
+ @method_calls[meth.to_sym] = true
822
+
822
823
  # we are trying to access a lvar in irb mode
823
824
  if @irb_vars and @scope.top? and arglist == s(:arglist) and recv == nil
824
825
  return with_temp { |t|
825
826
  lvar = meth.intern
826
827
  lvar = "#{lvar}$" if RESERVED.include? lvar
827
828
  call = s(:call, s(:self), meth.intern, s(:arglist))
828
- [fragment("((#{t} = Opal.irb_vars.#{lvar}) == null ? ", sexp), process(call, :expr), fragment(" : #{t})", sexp)]
829
+ [f("((#{t} = $opal.irb_vars.#{lvar}) == null ? ", sexp), process(call), f(" : #{t})", sexp)]
829
830
  }
830
831
  end
831
832
 
832
833
  case meth
833
- when :attr_reader, :attr_writer, :attr_accessor
834
- return handle_attr_optimize(meth, arglist[1..-1]) if @scope.class_scope?
835
834
  when :block_given?
836
835
  return js_block_given(sexp, level)
837
836
  end
@@ -839,7 +838,7 @@ module Opal
839
838
  splat = arglist[1..-1].any? { |a| a.first == :splat }
840
839
 
841
840
  if Array === arglist.last and arglist.last.first == :block_pass
842
- block = process(arglist.pop, :expr)
841
+ block = process(arglist.pop)
843
842
  elsif iter
844
843
  block = iter
845
844
  end
@@ -850,54 +849,35 @@ module Opal
850
849
  tmpfunc = @scope.new_temp
851
850
  end
852
851
 
853
- tmprecv = @scope.new_temp
852
+ tmprecv = @scope.new_temp if splat || tmpfunc
854
853
  args = ""
855
854
 
856
855
  recv_code = process recv, :recv
857
856
 
858
- if @method_missing
859
- call_recv = s(:js_tmp, tmprecv || recv_code)
860
- arglist.insert 1, call_recv unless splat
861
- args = process arglist, :expr
862
-
863
- dispatch = "((#{tmprecv} = #{recv_code})#{mid} || $mm('#{meth.to_s}'))"
864
- dispatch = [fragment("((#{tmprecv} = ", sexp), recv_code, fragment(")#{mid} || $mm('#{meth.to_s}'))", sexp)]
865
-
866
- if tmpfunc
867
- dispatch.unshift fragment("(#{tmpfunc} = ", sexp)
868
- dispatch << fragment(", #{tmpfunc}._p = ", sexp)
869
- dispatch << block
870
- dispatch << fragment(", #{tmpfunc})", sexp)
871
- end
857
+ call_recv = s(:js_tmp, tmprecv || recv_code)
858
+ arglist.insert 1, call_recv if tmpfunc and !splat
859
+ args = process arglist
872
860
 
873
- if splat
874
- dispatch << fragment(".apply(", sexp)
875
- dispatch << process(call_recv, :expr)
876
- dispatch << fragment(", ", sexp)
877
- dispatch << args
878
- dispatch << fragment(")", sexp)
879
- else
880
- dispatch << fragment(".call(", sexp)
881
- dispatch.push(*args)
882
- dispatch << fragment(")", sexp)
883
- end
884
-
885
- result = dispatch
861
+ dispatch = if tmprecv
862
+ [f("(#{tmprecv} = "), recv_code, f(")#{mid}")]
886
863
  else
887
- args = process arglist, :expr
864
+ [recv_code, f(mid)]
865
+ end
888
866
 
889
- dispatch = if tmprecv
890
- [fragment("(#{tmprecv} = ", sexp), recv_code, fragment(")#{mid}", sexp)]
891
- else
892
- [recv_code, fragment(mid, sexp)]
893
- end
867
+ if tmpfunc
868
+ dispatch.unshift f("(#{tmpfunc} = ")
869
+ dispatch << f(", #{tmpfunc}._p = ")
870
+ dispatch << block
871
+ dispatch << f(", #{tmpfunc})")
872
+ end
894
873
 
895
- result = if splat
896
- [dispatch, fragment(".apply(", sexp), (tmprecv ? fragment(tmprecv, sexp) : recv_code),
897
- fragment(", ", sexp), args, fragment(")", sexp)]
898
- else
899
- [dispatch, fragment("(", sexp), args, fragment(")", sexp)]
900
- end
874
+ result = if splat
875
+ [dispatch, f(".apply("), (tmprecv ? f(tmprecv) : recv_code),
876
+ f(", "), args, f(")")]
877
+ elsif tmpfunc
878
+ [dispatch, f(".call("), args, f(")")]
879
+ else
880
+ [dispatch, f("("), args, f(")")]
901
881
  end
902
882
 
903
883
  @scope.queue_temp tmpfunc if tmpfunc
@@ -906,37 +886,35 @@ module Opal
906
886
 
907
887
  # s(:arglist, [arg [, arg ..]])
908
888
  def process_arglist(sexp, level)
909
- code = []
910
- work = []
889
+ code, work = [], []
911
890
 
912
- until sexp.empty?
913
- current = sexp.shift
891
+ sexp.each do |current|
914
892
  splat = current.first == :splat
915
- arg = process current, :expr
893
+ arg = process current
916
894
 
917
895
  if splat
918
896
  if work.empty?
919
897
  if code.empty?
920
- code << fragment("[].concat(", sexp)
898
+ code << f("[].concat(", sexp)
921
899
  code << arg
922
- code << fragment(")", sexp)
900
+ code << f(")")
923
901
  else
924
902
  code += ".concat(#{arg})"
925
903
  end
926
904
  else
927
905
  if code.empty?
928
- code << [fragment("[", sexp), work, fragment("]", sexp)]
906
+ code << [f("["), work, f("]")]
929
907
  else
930
- code << [fragment(".concat([", sexp), work, fragment("])", sexp)]
908
+ code << [f(".concat(["), work, f("])")]
931
909
  end
932
910
 
933
- code << [fragment(".concat(", sexp), arg, fragment(")", sexp)]
911
+ code << [f(".concat("), arg, f(")")]
934
912
  end
935
913
 
936
914
  work = []
937
915
  else
938
- work << fragment(", ", current) unless work.empty?
939
- work.push(*arg)
916
+ work << f(", ") unless work.empty?
917
+ work << arg
940
918
  end
941
919
  end
942
920
 
@@ -946,7 +924,7 @@ module Opal
946
924
  if code.empty?
947
925
  code = join
948
926
  else
949
- code << fragment(".concat(", sexp) << join << fragment(")", sexp)
927
+ code << f(".concat(") << join << f(")")
950
928
  end
951
929
  end
952
930
 
@@ -956,9 +934,9 @@ module Opal
956
934
  # s(:splat, sexp)
957
935
  def process_splat(sexp, level)
958
936
  if sexp.first == [:nil]
959
- [fragment("[]", sexp)]
937
+ [f("[]")]
960
938
  elsif sexp.first.first == :sym
961
- [fragment("[", sexp), process(sexp.first, :expr), fragment("]", sexp)]
939
+ [f("["), process(sexp[0]), f("]")]
962
940
  else
963
941
  process sexp.first, :recv
964
942
  end
@@ -974,24 +952,24 @@ module Opal
974
952
  @helpers[:klass] = true
975
953
 
976
954
  if Symbol === cid or String === cid
977
- base = process(s(:self), :expr)
955
+ base = process s(:self)
978
956
  name = cid.to_s
979
957
  elsif cid[0] == :colon2
980
- base = process(cid[1], :expr)
958
+ base = process(cid[1])
981
959
  name = cid[2].to_s
982
960
  elsif cid[0] == :colon3
983
- base = process(s(:js_tmp, 'Opal.Object'), :expr)
961
+ base = process(s(:js_tmp, '$opal.Object'))
984
962
  name = cid[1].to_s
985
963
  else
986
964
  raise "Bad receiver in class"
987
965
  end
988
966
 
989
- sup = sup ? process(sup, :expr) : process(s(:js_tmp, 'null'), :expr)
967
+ sup = sup ? process(sup) : process(s(:js_tmp, 'null'))
990
968
 
991
969
  indent do
992
970
  in_scope(:class) do
993
971
  @scope.name = name
994
- @scope.add_temp "#{ @scope.proto } = #{name}._proto", "__scope = #{name}._scope"
972
+ @scope.add_temp "#{ @scope.proto } = #{name}._proto", "$scope = #{name}._scope"
995
973
 
996
974
  if Array === body.last
997
975
  # A single statement will need a block
@@ -1007,62 +985,54 @@ module Opal
1007
985
  end
1008
986
  end
1009
987
 
1010
- body = returns(body)
1011
- body = process body, :stmt
1012
- code << fragment("\n", sexp)
988
+ body = process(returns(body), :stmt)
989
+ code << f("\n")
1013
990
  code << @scope.to_donate_methods
1014
991
 
1015
- code << fragment(@indent, sexp)
992
+ code << f(@indent)
1016
993
  code << @scope.to_vars
1017
- code << fragment("\n\n#@indent", sexp)
994
+ code << f("\n\n#@indent")
1018
995
  code << body
1019
996
  end
1020
997
  end
1021
998
 
1022
999
  spacer = "\n#{@indent}#{INDENT}"
1023
1000
  cls = "function #{name}() {};"
1024
- boot = "#{name} = __klass(__base, __super, #{name.inspect}, #{name});"
1001
+ boot = "#{name} = $klass($base, $super, #{name.inspect}, #{name});"
1025
1002
 
1026
- [fragment("(function(__base, __super){#{spacer}#{cls}#{spacer}#{boot}\n", sexp),
1027
- code, fragment("\n#@indent})", sexp), fragment("(", sexp), base, fragment(", ", sexp), sup, fragment(")", sexp)]
1003
+ [f("(function($base, $super){#{spacer}#{cls}#{spacer}#{boot}\n", sexp),
1004
+ code, f("\n#@indent})", sexp), f("(", sexp), base, f(", ", sexp), sup, f(")", sexp)]
1028
1005
  end
1029
1006
 
1030
- # s(:sclass, recv, body)
1007
+ # Singleton class syntax. Runs body in context of singleton_class.
1008
+ # s(:sclass, recv, body) => (function() { ... }).call(recv.$singleton_class())
1031
1009
  def process_sclass(sexp, level)
1032
- recv = sexp[0]
1033
- body = sexp[1]
1034
- code = []
1010
+ recv, body, code = sexp[0], sexp[1], []
1035
1011
 
1036
1012
  in_scope(:sclass) do
1037
- @scope.add_temp "__scope = #{current_self}._scope"
1013
+ @scope.add_temp "$scope = #{current_self}._scope"
1038
1014
  @scope.add_temp "def = #{current_self}._proto"
1039
1015
 
1040
- body = process body, :stmt
1041
- code << @scope.to_vars << body
1016
+ code << @scope.to_vars << process(body, :stmt)
1042
1017
  end
1043
1018
 
1044
- result = []
1045
- result << fragment("(function(){", sexp) << code
1046
- result << fragment("}).call(__opal.singleton(", sexp)
1047
- result << process(recv, :expr) << fragment("))", sexp)
1048
- result
1019
+ [f("(function(){"), code, f("}).call("), process(recv, :recv), f(".$singleton_class())")]
1049
1020
  end
1050
1021
 
1051
1022
  # s(:module, cid, body)
1052
1023
  def process_module(sexp, level)
1053
- cid = sexp[0]
1054
- body = sexp[1]
1024
+ cid, body = sexp
1055
1025
  code = []
1056
1026
  @helpers[:module] = true
1057
1027
 
1058
1028
  if Symbol === cid or String === cid
1059
- base = process(s(:self), :expr)
1029
+ base = process(s(:self))
1060
1030
  name = cid.to_s
1061
1031
  elsif cid[0] == :colon2
1062
- base = process(cid[1], :expr)
1032
+ base = process(cid[1])
1063
1033
  name = cid[2].to_s
1064
1034
  elsif cid[0] == :colon3
1065
- base = fragment('Opal.Object', sexp)
1035
+ base = f('$opal.Object', sexp)
1066
1036
  name = cid[1].to_s
1067
1037
  else
1068
1038
  raise "Bad receiver in class"
@@ -1071,34 +1041,35 @@ module Opal
1071
1041
  indent do
1072
1042
  in_scope(:module) do
1073
1043
  @scope.name = name
1074
- @scope.add_temp "#{ @scope.proto } = #{name}._proto", "__scope = #{name}._scope"
1044
+ @scope.add_temp "#{ @scope.proto } = #{name}._proto", "$scope = #{name}._scope"
1075
1045
  body = process body, :stmt
1076
1046
 
1077
- code << fragment(@indent, sexp)
1078
- code.push(*@scope.to_vars)
1079
- code << fragment("\n\n#@indent", sexp)
1080
- code.push(*body)
1081
- code << fragment("\n#@ident", sexp)
1082
- code.push(*@scope.to_donate_methods)
1047
+ code << f(@indent)
1048
+ code << @scope.to_vars
1049
+ code << f("\n\n#@indent")
1050
+ code << body
1051
+ code << f("\n#@ident")
1052
+ code << @scope.to_donate_methods
1083
1053
  end
1084
1054
  end
1085
1055
 
1086
1056
  spacer = "\n#{@indent}#{INDENT}"
1087
1057
  cls = "function #{name}() {};"
1088
- boot = "#{name} = __module(__base, #{name.inspect}, #{name});"
1058
+ boot = "#{name} = $module($base, #{name.inspect}, #{name});"
1089
1059
 
1090
- code.unshift fragment("(function(__base){#{spacer}#{cls}#{spacer}#{boot}\n", sexp)
1091
- code << fragment("\n#@indent})(", sexp)
1092
- code.push(*base)
1093
- code << fragment(")", sexp)
1060
+ code.unshift f("(function($base){#{spacer}#{cls}#{spacer}#{boot}\n", sexp)
1061
+ code << f("\n#@indent})(")
1062
+ code << base
1063
+ code << f(")")
1094
1064
 
1095
1065
  code
1096
1066
  end
1097
1067
 
1098
1068
  # undef :foo
1099
1069
  # => delete MyClass.prototype.$foo
1070
+ # FIXME: we should be setting method to a stub method here
1100
1071
  def process_undef(sexp, level)
1101
- fragment("delete #{ @scope.proto }#{ mid_to_jsid sexp[0][1].to_s }", sexp)
1072
+ f("delete #{ @scope.proto }#{ mid_to_jsid sexp[0][1].to_s }", sexp)
1102
1073
  end
1103
1074
 
1104
1075
  # s(:defn, mid, s(:args), s(:scope))
@@ -1121,7 +1092,7 @@ module Opal
1121
1092
  if recvr
1122
1093
  @scope.defines_defs = true
1123
1094
  smethod = true if @scope.class_scope? && recvr.first == :self
1124
- recv = process(recvr, :expr)
1095
+ recv = process(recvr)
1125
1096
  else
1126
1097
  @scope.defines_defn = true
1127
1098
  recv = current_self
@@ -1167,54 +1138,64 @@ module Opal
1167
1138
 
1168
1139
  if block_name
1169
1140
  @scope.uses_block!
1141
+ @scope.add_arg block_name
1170
1142
  end
1171
1143
 
1172
- yielder = block_name || '__yield'
1144
+ yielder = block_name || '$yield'
1173
1145
  @scope.block_name = yielder
1174
1146
 
1175
- params = process args, :expr
1176
- stmt_code = [fragment("\n#@indent", stmts), *process(stmts, :stmt)]
1147
+ params = process args
1148
+ stmt_code = [f("\n#@indent"), process(stmts, :stmt)]
1177
1149
 
1178
1150
  opt[1..-1].each do |o|
1179
1151
  next if o[2][2] == :undefined
1180
- code << fragment("if (#{o[1]} == null) {\n#{@indent + INDENT}", o)
1181
- code << process(o, :expr)
1182
- code << fragment("\n#{@indent}}", o)
1152
+ code << f("if (#{o[1]} == null) {\n#{@indent + INDENT}", o)
1153
+ code << process(o)
1154
+ code << f("\n#{@indent}}", o)
1183
1155
  end if opt
1184
1156
 
1185
- code << fragment("#{splat} = __slice.call(arguments, #{argc});", sexp) if splat
1157
+ code << f("#{splat} = $slice.call(arguments, #{argc});", sexp) if splat
1186
1158
 
1187
1159
  scope_name = @scope.identity
1188
1160
 
1189
1161
  if @scope.uses_block?
1190
- @scope.add_temp yielder
1191
- blk = fragment(("\n%s%s = %s._p || nil, %s._p = null;\n%s" %
1192
- [@indent, yielder, scope_name, scope_name, @indent]), sexp)
1162
+ @scope.add_temp "$iter = #{scope_name}._p"
1163
+ @scope.add_temp "#{yielder} = $iter || nil"
1164
+
1165
+ code.unshift f("#{scope_name}._p = null;", sexp)
1193
1166
  end
1194
1167
 
1195
1168
  code.push(*stmt_code)
1196
- code.unshift blk if blk
1197
1169
 
1198
1170
  uses_super = @scope.uses_super
1199
1171
 
1200
- code = [fragment("#{arity_code}#@indent", sexp), @scope.to_vars, code]
1172
+ code = [f("#{arity_code}#@indent", sexp), @scope.to_vars, code]
1173
+
1174
+ if @scope.uses_zuper
1175
+ code.unshift f("var $zuper = $slice.call(arguments, 0);", sexp)
1176
+ end
1177
+
1178
+ if @scope.catch_return
1179
+ code.unshift f("try {\n", sexp)
1180
+ code.push f("\n} catch($returner) { if ($returner === $opal.returner) { return $returner.$v; } throw $returner; }", sexp)
1181
+ end
1201
1182
  end
1202
1183
  end
1203
1184
 
1204
- result = [fragment("#{"#{scope_name} = " if scope_name}function(", sexp)]
1185
+ result = [f("#{"#{scope_name} = " if scope_name}function(", sexp)]
1205
1186
  result.push(*params)
1206
- result << fragment(") {\n", sexp)
1187
+ result << f(") {\n", sexp)
1207
1188
  result.push(*code)
1208
- result << fragment("\n#@indent}", sexp)
1189
+ result << f("\n#@indent}", sexp)
1209
1190
 
1210
1191
  if recvr
1211
1192
  if smethod
1212
- [fragment("#{@scope.name}.constructor.prototype['$#{mid}'] = ", sexp), result]
1193
+ [f("#{@scope.name}.constructor.prototype['$#{mid}'] = ", sexp), result]
1213
1194
  else
1214
- [recv, fragment("#{jsid} = ", sexp), result]
1195
+ [recv, f("#{jsid} = ", sexp), result]
1215
1196
  end
1216
1197
  elsif @scope.class? and @scope.name == 'Object'
1217
- [fragment("#{current_self}._defn('$#{mid}', ", sexp), result, fragment(")", sexp)]
1198
+ [f("#{current_self}._defn('$#{mid}', ", sexp), result, f(")", sexp)]
1218
1199
  elsif @scope.class_scope?
1219
1200
  @scope.methods << "$#{mid}"
1220
1201
  if uses_super
@@ -1222,13 +1203,9 @@ module Opal
1222
1203
  uses_super = "#{uses_super} = #{@scope.proto}#{jsid};\n#@indent"
1223
1204
  end
1224
1205
 
1225
- [fragment("#{uses_super}#{@scope.proto}#{jsid} = ", sexp), result]
1226
- elsif @scope.type == :iter
1227
- [fragment("def#{jsid} = ", sexp), result]
1228
- elsif @scope.type == :top
1229
- [fragment("def#{ jsid } = ", sexp), *result]
1230
- else
1231
- [fragment("def#{jsid} = ", sexp), result]
1206
+ [f("#{uses_super}#{@scope.proto}#{jsid} = ", sexp), result]
1207
+ else # :top, :iter
1208
+ [f("def#{jsid} = ", sexp), result]
1232
1209
  end
1233
1210
  end
1234
1211
 
@@ -1246,34 +1223,35 @@ module Opal
1246
1223
  aritycode = "var $arity = arguments.length;"
1247
1224
 
1248
1225
  if arity < 0 # splat or opt args
1249
- aritycode + "if ($arity < #{-(arity + 1)}) { __opal.ac($arity, #{arity}, this, #{meth}); }"
1226
+ aritycode + "if ($arity < #{-(arity + 1)}) { $opal.ac($arity, #{arity}, this, #{meth}); }"
1250
1227
  else
1251
- aritycode + "if ($arity !== #{arity}) { __opal.ac($arity, #{arity}, this, #{meth}); }"
1228
+ aritycode + "if ($arity !== #{arity}) { $opal.ac($arity, #{arity}, this, #{meth}); }"
1252
1229
  end
1253
1230
  end
1254
1231
 
1255
1232
  def process_args(exp, level)
1256
1233
  args = []
1257
1234
 
1258
- until exp.empty?
1259
- a = exp.shift.to_sym
1235
+ exp.each do |a|
1236
+ a = a.to_sym
1260
1237
  next if a.to_s == '*'
1261
- a = "#{a}$".to_sym if RESERVED.include? a.to_s
1238
+ a = lvar_to_js a
1262
1239
  @scope.add_arg a
1263
1240
  args << a
1264
1241
  end
1265
1242
 
1266
- [fragment(args.join(', '), exp)]
1243
+ f(args.join(', '), exp)
1267
1244
  end
1268
1245
 
1269
1246
  # s(:self) # => this
1270
1247
  def process_self(sexp, level)
1271
- fragment(current_self, sexp)
1248
+ f(current_self, sexp)
1272
1249
  end
1273
1250
 
1274
1251
  # Returns the current value for 'self'. This will be native
1275
1252
  # 'this' for methods and blocks, and the class name for class
1276
1253
  # and module bodies.
1254
+ # s(:self) => self or this or class name
1277
1255
  def current_self
1278
1256
  if @scope.class_scope?
1279
1257
  @scope.name
@@ -1284,60 +1262,64 @@ module Opal
1284
1262
  end
1285
1263
  end
1286
1264
 
1265
+ # true literal
1266
+ # s(:true) => true
1287
1267
  def process_true(sexp, level)
1288
- fragment("true", sexp)
1268
+ f "true", sexp
1289
1269
  end
1290
1270
 
1271
+ # false literal
1272
+ # s(:false) => false
1291
1273
  def process_false(sexp, level)
1292
- fragment("false", sexp)
1274
+ f "false", sexp
1293
1275
  end
1294
1276
 
1277
+ # nil literal
1278
+ # s(:nil) => nil
1295
1279
  def process_nil(sexp, level)
1296
- fragment("nil", sexp)
1280
+ f "nil", sexp
1297
1281
  end
1298
1282
 
1299
- # s(:array [, sexp [, sexp]])
1283
+ # s(:array [, sexp [, sexp]]) => [...]
1300
1284
  def process_array(sexp, level)
1301
- return [fragment("[]", sexp)] if sexp.empty?
1285
+ return [f("[]", sexp)] if sexp.empty?
1302
1286
 
1303
- code = []
1304
- work = []
1287
+ code, work = [], []
1305
1288
 
1306
- until sexp.empty?
1307
- current = sexp.shift
1289
+ sexp.each do |current|
1308
1290
  splat = current.first == :splat
1309
- part = process current, :expr
1291
+ part = process current
1310
1292
 
1311
1293
  if splat
1312
1294
  if work.empty?
1313
1295
  if code.empty?
1314
- code << fragment("[].concat(", sexp) << part << fragment(")", sexp)
1296
+ code << f("[].concat(", sexp) << part << f(")", sexp)
1315
1297
  else
1316
- code << fragment(".concat(", sexp) << part << fragment(")", sexp)
1298
+ code << f(".concat(", sexp) << part << f(")", sexp)
1317
1299
  end
1318
1300
  else
1319
1301
  if code.empty?
1320
- code << fragment("[", sexp) << work << fragment("]", sexp)
1302
+ code << f("[", sexp) << work << f("]", sexp)
1321
1303
  else
1322
- code << fragment(".concat([", sexp) << work << fragment("])", sexp)
1304
+ code << f(".concat([", sexp) << work << f("])", sexp)
1323
1305
  end
1324
1306
 
1325
- code << fragment(".concat(", sexp) << part << fragment(")", sexp)
1307
+ code << f(".concat(", sexp) << part << f(")", sexp)
1326
1308
  end
1327
1309
  work = []
1328
1310
  else
1329
- work << fragment(", ", current) unless work.empty?
1311
+ work << f(", ", current) unless work.empty?
1330
1312
  work << part
1331
1313
  end
1332
1314
  end
1333
1315
 
1334
1316
  unless work.empty?
1335
- join = [fragment("[", sexp), work, fragment("]", sexp)]
1317
+ join = [f("[", sexp), work, f("]", sexp)]
1336
1318
 
1337
1319
  if code.empty?
1338
1320
  code = join
1339
1321
  else
1340
- code.push([fragment(".concat(", sexp), join, fragment(")", sexp)])
1322
+ code.push([f(".concat(", sexp), join, f(")", sexp)])
1341
1323
  end
1342
1324
  end
1343
1325
 
@@ -1363,29 +1345,29 @@ module Opal
1363
1345
  keys.size.times do |i|
1364
1346
  k = keys[i][1].to_s.inspect
1365
1347
  hash_keys << k unless hash_obj.include? k
1366
- hash_obj[k] = process(vals[i], :expr)
1348
+ hash_obj[k] = process(vals[i])
1367
1349
  end
1368
1350
 
1369
1351
  result = []
1370
1352
  @helpers[:hash2] = true
1371
1353
 
1372
1354
  hash_keys.each do |k|
1373
- result << fragment(", ", sexp) unless result.empty?
1374
- result << fragment("#{k}: ", sexp)
1355
+ result << f(", ", sexp) unless result.empty?
1356
+ result << f("#{k}: ", sexp)
1375
1357
  result << hash_obj[k]
1376
1358
  end
1377
1359
 
1378
- [fragment("__hash2([#{hash_keys.join ', '}], {", sexp), result, fragment("})", sexp)]
1360
+ [f("$hash2([#{hash_keys.join ', '}], {", sexp), result, f("})", sexp)]
1379
1361
  else
1380
1362
  @helpers[:hash] = true
1381
1363
  result = []
1382
1364
 
1383
1365
  sexp.each do |p|
1384
- result << fragment(", ", p) unless result.empty?
1385
- result << process(p, :expr)
1366
+ result << f(", ", p) unless result.empty?
1367
+ result << process(p)
1386
1368
  end
1387
1369
 
1388
- [fragment("__hash(", sexp), result, fragment(")", sexp)]
1370
+ [f("$hash(", sexp), result, f(")", sexp)]
1389
1371
  end
1390
1372
  end
1391
1373
 
@@ -1401,7 +1383,7 @@ module Opal
1401
1383
  :stmt
1402
1384
  end
1403
1385
 
1404
- code << js_truthy(expr) << fragment("){", sexp)
1386
+ code << js_truthy(expr) << f("){", sexp)
1405
1387
  pre = "while ("
1406
1388
 
1407
1389
  in_while do
@@ -1411,27 +1393,26 @@ module Opal
1411
1393
 
1412
1394
  if @while_loop[:use_redo]
1413
1395
  pre = "#{redo_var}=false;" + pre + "#{redo_var} || "
1414
- code << fragment("#{redo_var}=false;", sexp)
1396
+ code << f("#{redo_var}=false;", sexp)
1415
1397
  end
1416
1398
 
1417
1399
  code << body
1418
1400
  end
1419
1401
 
1420
- code << fragment("}", sexp)
1421
- code.unshift fragment(pre, sexp)
1402
+ code << f("}", sexp)
1403
+ code.unshift f(pre, sexp)
1422
1404
  @scope.queue_temp redo_var
1423
1405
 
1424
1406
  if stmt_level == :stmt_closure
1425
- code.unshift fragment("(function() {", sexp)
1426
- code.push fragment("; return nil; }).call(#{current_self})", sexp)
1407
+ code.unshift f("(function() {", sexp)
1408
+ code.push f("; return nil; }).call(#{current_self})", sexp)
1427
1409
  end
1428
1410
 
1429
1411
  code
1430
1412
  end
1431
1413
 
1432
1414
  def process_until(exp, level)
1433
- expr = exp[0]
1434
- stmt = exp[1]
1415
+ expr, stmt = exp
1435
1416
  redo_var = @scope.new_temp
1436
1417
  stmt_level = if level == :expr or level == :recv
1437
1418
  :stmt_closure
@@ -1441,7 +1422,7 @@ module Opal
1441
1422
 
1442
1423
  code = []
1443
1424
  pre = "while (!("
1444
- code << js_truthy(expr) << fragment(")) {", exp)
1425
+ code << js_truthy(expr) << f(")) {", exp)
1445
1426
 
1446
1427
  in_while do
1447
1428
  @while_loop[:closure] = true if stmt_level == :stmt_closure
@@ -1450,19 +1431,19 @@ module Opal
1450
1431
 
1451
1432
  if @while_loop[:use_redo]
1452
1433
  pre = "#{redo_var}=false;" + pre + "#{redo_var} || "
1453
- code << fragment("#{redo_var}=false;", exp)
1434
+ code << f("#{redo_var}=false;", exp)
1454
1435
  end
1455
1436
 
1456
1437
  code << body
1457
1438
  end
1458
1439
 
1459
- code << fragment("}", exp)
1460
- code.unshift fragment(pre, exp)
1440
+ code << f("}", exp)
1441
+ code.unshift f(pre, exp)
1461
1442
  @scope.queue_temp redo_var
1462
1443
 
1463
1444
  if stmt_level == :stmt_closure
1464
- code.unshift fragment("(function() {", exp)
1465
- code << fragment("; return nil; }).call(#{current_self})", exp)
1445
+ code.unshift f("(function() {", exp)
1446
+ code << f("; return nil; }).call(#{current_self})", exp)
1466
1447
  end
1467
1448
 
1468
1449
  code
@@ -1477,50 +1458,59 @@ module Opal
1477
1458
 
1478
1459
  if [:class, :module].include? @scope.type
1479
1460
  @scope.methods << "$#{exp[0][1].to_s}"
1480
- fragment("%s%s = %s%s" % [@scope.proto, new, @scope.proto, old], exp)
1461
+ f("%s%s = %s%s" % [@scope.proto, new, @scope.proto, old], exp)
1481
1462
  else
1482
1463
  current = current_self
1483
- fragment("%s._proto%s = %s._proto%s" % [current, new, current, old], exp)
1464
+ f("%s._proto%s = %s._proto%s" % [current, new, current, old], exp)
1484
1465
  end
1485
1466
  end
1486
1467
 
1487
1468
  def process_masgn(sexp, level)
1488
- lhs = sexp[0]
1489
- rhs = sexp[1]
1469
+ lhs, rhs = sexp
1490
1470
  tmp = @scope.new_temp
1491
1471
  len = 0
1492
1472
  code = []
1493
1473
 
1494
- # remote :array part
1495
- lhs.shift
1496
1474
  if rhs[0] == :array
1497
1475
  len = rhs.length - 1 # we are guaranteed an array of this length
1498
- code << fragment("#{tmp} = ", sexp) << process(rhs, :expr)
1476
+ code << f("#{tmp} = ", sexp) << process(rhs)
1499
1477
  elsif rhs[0] == :to_ary
1500
- code << fragment("((#{tmp} = ", sexp) << process(rhs[1], :expr)
1501
- code << fragment(")._isArray ? #{tmp} : (#{tmp} = [#{tmp}]))", sexp)
1478
+ code << f("((#{tmp} = ", sexp) << process(rhs[1])
1479
+ code << f(")._isArray ? #{tmp} : (#{tmp} = [#{tmp}]))", sexp)
1502
1480
  elsif rhs[0] == :splat
1503
- code << fragment("(#{tmp} = ", sexp) << process(rhs[1], :expr)
1504
- code << fragment(")['$to_a'] ? (#{tmp} = #{tmp}['$to_a']()) : (#{tmp})._isArray ? #{tmp} : (#{tmp} = [#{tmp}])", sexp)
1481
+ code << f("(#{tmp} = ", sexp) << process(rhs[1])
1482
+ code << f(")['$to_a'] ? (#{tmp} = #{tmp}['$to_a']()) : (#{tmp})._isArray ? #{tmp} : (#{tmp} = [#{tmp}])", sexp)
1505
1483
  else
1506
1484
  raise "Unsupported mlhs type"
1507
1485
  end
1508
1486
 
1509
- lhs.each_with_index do |l, idx|
1510
- code << fragment(", ", sexp) unless code.empty?
1487
+ lhs[1..-1].each_with_index do |l, idx|
1488
+ code << f(", ", sexp) unless code.empty?
1511
1489
 
1512
1490
  if l.first == :splat
1513
1491
  if s = l[1]
1514
- s << s(:js_tmp, "__slice.call(#{tmp}, #{idx})")
1515
- code << process(s, :expr)
1492
+ s << s(:js_tmp, "$slice.call(#{tmp}, #{idx})")
1493
+ code << process(s)
1516
1494
  end
1517
1495
  else
1518
1496
  if idx >= len
1519
- l << s(:js_tmp, "(#{tmp}[#{idx}] == null ? nil : #{tmp}[#{idx}])")
1497
+ assign = s(:js_tmp, "(#{tmp}[#{idx}] == null ? nil : #{tmp}[#{idx}])")
1498
+ else
1499
+ assign = s(:js_tmp, "#{tmp}[#{idx}]")
1500
+ end
1501
+
1502
+ if l[0] == :lasgn or l[0] == :iasgn or l[0] == :lvar
1503
+ l << assign
1504
+ elsif l[0] == :call
1505
+ l[2] = "#{l[2]}=".to_sym
1506
+ l.last << assign
1507
+ elsif l[0] == :attrasgn
1508
+ l.last << assign
1520
1509
  else
1521
- l << s(:js_tmp, "#{tmp}[#{idx}]")
1510
+ raise "bad lhs for masgn: #{l.inspect}"
1522
1511
  end
1523
- code << process(l, :expr)
1512
+
1513
+ code << process(l)
1524
1514
  end
1525
1515
  end
1526
1516
 
@@ -1529,7 +1519,7 @@ module Opal
1529
1519
  end
1530
1520
 
1531
1521
  def process_svalue(sexp, level)
1532
- process sexp.shift, level
1522
+ process sexp[0], level
1533
1523
  end
1534
1524
 
1535
1525
  # s(:lasgn, :lvar, rhs)
@@ -1539,15 +1529,15 @@ module Opal
1539
1529
  lvar = "#{lvar}$".to_sym if RESERVED.include? lvar.to_s
1540
1530
 
1541
1531
  if @irb_vars and @scope.top?
1542
- [fragment("Opal.irb_vars.#{lvar} = ", sexp), process(rhs, :expr)]
1532
+ [f("$opal.irb_vars.#{lvar} = ", sexp), process(rhs)]
1543
1533
  else
1544
1534
  @scope.add_local lvar
1545
- rhs = process(rhs, :expr)
1546
- result = [fragment(lvar, sexp), fragment(" = ", sexp), rhs]
1535
+ rhs = process(rhs)
1536
+ result = [f(lvar, sexp), f(" = ", sexp), rhs]
1547
1537
 
1548
1538
  if level == :recv
1549
- result.unshift fragment("(", sexp)
1550
- result.push fragment(")", sexp)
1539
+ result.unshift f("(", sexp)
1540
+ result.push f(")", sexp)
1551
1541
  end
1552
1542
 
1553
1543
  result
@@ -1556,42 +1546,41 @@ module Opal
1556
1546
 
1557
1547
  # s(:lvar, :lvar)
1558
1548
  def process_lvar(sexp, level)
1559
- lvar = sexp.shift.to_s
1549
+ lvar = sexp[0].to_s
1560
1550
  lvar = "#{lvar}$" if RESERVED.include? lvar
1561
1551
 
1562
1552
  if @irb_vars and @scope.top?
1563
- with_temp { |t| fragment("((#{t} = Opal.irb_vars.#{lvar}) == null ? nil : #{t})", sexp) }
1553
+ with_temp { |t| f("((#{t} = $opal.irb_vars.#{lvar}) == null ? nil : #{t})", sexp) }
1564
1554
  else
1565
- fragment(lvar, sexp)
1555
+ f(lvar, sexp)
1566
1556
  end
1567
1557
  end
1568
1558
 
1569
1559
  # s(:iasgn, :ivar, rhs)
1570
1560
  def process_iasgn(exp, level)
1571
- ivar = exp[0]
1572
- rhs = exp[1]
1561
+ ivar, rhs = exp
1573
1562
  ivar = ivar.to_s[1..-1]
1574
1563
  lhs = RESERVED.include?(ivar) ? "#{current_self}['#{ivar}']" : "#{current_self}.#{ivar}"
1575
- [fragment(lhs, exp), fragment(" = ", exp), process(rhs, :expr)]
1564
+ [f(lhs, exp), f(" = ", exp), process(rhs)]
1576
1565
  end
1577
1566
 
1578
1567
  # s(:ivar, :ivar)
1579
1568
  def process_ivar(exp, level)
1580
- ivar = exp.shift.to_s[1..-1]
1569
+ ivar = exp[0].to_s[1..-1]
1581
1570
  part = RESERVED.include?(ivar) ? "['#{ivar}']" : ".#{ivar}"
1582
1571
  @scope.add_ivar part
1583
- fragment("#{current_self}#{part}", exp)
1572
+ f("#{current_self}#{part}", exp)
1584
1573
  end
1585
1574
 
1586
1575
  # s(:gvar, gvar)
1587
1576
  def process_gvar(sexp, level)
1588
- gvar = sexp.shift.to_s[1..-1]
1577
+ gvar = sexp[0].to_s[1..-1]
1589
1578
  @helpers['gvars'] = true
1590
- fragment("__gvars[#{gvar.inspect}]", sexp)
1579
+ f("$gvars[#{gvar.inspect}]", sexp)
1591
1580
  end
1592
1581
 
1593
1582
  def process_nth_ref(sexp, level)
1594
- fragment("nil", sexp)
1583
+ f("nil", sexp)
1595
1584
  end
1596
1585
 
1597
1586
  # s(:gasgn, :gvar, rhs)
@@ -1599,34 +1588,53 @@ module Opal
1599
1588
  gvar = sexp[0].to_s[1..-1]
1600
1589
  rhs = sexp[1]
1601
1590
  @helpers['gvars'] = true
1602
- [fragment("__gvars[#{gvar.to_s.inspect}] = ", sexp), process(rhs, :expr)]
1591
+ [f("$gvars[#{gvar.to_s.inspect}] = ", sexp), process(rhs)]
1603
1592
  end
1604
1593
 
1605
1594
  # s(:const, :const)
1606
1595
  def process_const(sexp, level)
1607
- cname = sexp.shift.to_s
1596
+ cname = sexp[0].to_s
1608
1597
 
1609
1598
  if @const_missing
1610
1599
  with_temp do |t|
1611
- fragment("((#{t} = __scope.#{cname}) == null ? __opal.cm(#{cname.inspect}) : #{t})", sexp)
1600
+ f("((#{t} = $scope.#{cname}) == null ? $opal.cm(#{cname.inspect}) : #{t})", sexp)
1612
1601
  end
1613
1602
  else
1614
- fragment("__scope.#{cname}", sexp)
1603
+ f("$scope.#{cname}", sexp)
1615
1604
  end
1616
1605
  end
1617
1606
 
1618
1607
  # s(:cdecl, :const, rhs)
1619
1608
  def process_cdecl(sexp, level)
1620
1609
  const, rhs = sexp
1621
- [fragment("__scope.#{const} = ", sexp), process(rhs, :expr)]
1610
+ [f("$scope.#{const} = ", sexp), process(rhs)]
1611
+ end
1612
+
1613
+ # s(:casgn, s(:const, ::A), :B, val)
1614
+ # A::B = 100
1615
+ def process_casgn(sexp, level)
1616
+ lhs, const, rhs = sexp
1617
+ [process(lhs), f("._scope.#{const} = ", sexp), process(rhs)]
1622
1618
  end
1623
1619
 
1624
1620
  # s(:return [val])
1625
1621
  def process_return(sexp, level)
1626
- val = process(sexp.shift || s(:nil), :expr)
1622
+ val = process(sexp[0] || s(:nil))
1623
+
1624
+ if @scope.iter? and parent_def = @scope.find_parent_def
1625
+ parent_def.catch_return = true
1626
+ [f("$opal.$return(", sexp), val, f(")", sexp)]
1627
1627
 
1628
- raise SyntaxError, "void value expression: cannot return as an expression" unless level == :stmt
1629
- [fragment("return ", sexp), val]
1628
+ elsif level == :expr and @scope.def?
1629
+ @scope.catch_return = true
1630
+ [f("$opal.$return(", sexp), val, f(")", sexp)]
1631
+
1632
+ elsif level == :stmt
1633
+ [f("return ", sexp), val]
1634
+
1635
+ else
1636
+ raise SyntaxError, "void value expression: cannot return as an expression"
1637
+ end
1630
1638
  end
1631
1639
 
1632
1640
  # s(:xstr, content)
@@ -1634,9 +1642,9 @@ module Opal
1634
1642
  code = sexp.first.to_s
1635
1643
  code += ";" if level == :stmt and !code.include?(';')
1636
1644
 
1637
- result = fragment(code, sexp)
1645
+ result = f(code, sexp)
1638
1646
 
1639
- level == :recv ? [fragment("(", sexp), result, fragment(")", sexp)] : result
1647
+ level == :recv ? [f("(", sexp), result, f(")", sexp)] : result
1640
1648
  end
1641
1649
 
1642
1650
  # s(:dxstr, parts...)
@@ -1646,22 +1654,22 @@ module Opal
1646
1654
 
1647
1655
  sexp.each do |p|
1648
1656
  if String === p
1649
- result << fragment(p.to_s, sexp)
1657
+ result << f(p.to_s, sexp)
1650
1658
  needs_sc = true if level == :stmt and !p.to_s.include?(';')
1651
1659
  elsif p.first == :evstr
1652
1660
  result.push(*process(p.last, :stmt))
1653
1661
  elsif p.first == :str
1654
- result << fragment(p.last.to_s, p)
1662
+ result << f(p.last.to_s, p)
1655
1663
  needs_sc = true if level == :stmt and !p.last.to_s.include?(';')
1656
1664
  else
1657
1665
  raise "Bad dxstr part"
1658
1666
  end
1659
1667
  end
1660
1668
 
1661
- result << fragment(";", sexp) if needs_sc
1669
+ result << f(";", sexp) if needs_sc
1662
1670
 
1663
1671
  if level == :recv
1664
- [fragment("(", sexp), result, fragment(")", sexp)]
1672
+ [f("(", sexp), result, f(")", sexp)]
1665
1673
  else
1666
1674
  result
1667
1675
  end
@@ -1672,22 +1680,22 @@ module Opal
1672
1680
  result = []
1673
1681
 
1674
1682
  sexp.each do |p|
1675
- result << fragment(" + ", sexp) unless result.empty?
1683
+ result << f(" + ", sexp) unless result.empty?
1676
1684
  if String === p
1677
- result << fragment(p.inspect, sexp)
1685
+ result << f(p.inspect, sexp)
1678
1686
  elsif p.first == :evstr
1679
- result << fragment("(", p)
1680
- result << process(p.last, :expr)
1681
- result << fragment(")", p)
1687
+ result << f("(", p)
1688
+ result << process(p.last)
1689
+ result << f(")", p)
1682
1690
  elsif p.first == :str
1683
- result << fragment(p.last.inspect, p)
1691
+ result << f(p.last.inspect, p)
1684
1692
  else
1685
1693
  raise "Bad dstr part"
1686
1694
  end
1687
1695
  end
1688
1696
 
1689
1697
  if level == :recv
1690
- [fragment("(", sexp), result, fragment(")", sexp)]
1698
+ [f("(", sexp), result, f(")", sexp)]
1691
1699
  else
1692
1700
  result
1693
1701
  end
@@ -1697,20 +1705,20 @@ module Opal
1697
1705
  result = []
1698
1706
 
1699
1707
  sexp.each do |p|
1700
- result << fragment(" + ", sexp) unless result.empty?
1708
+ result << f(" + ", sexp) unless result.empty?
1701
1709
 
1702
1710
  if String === p
1703
- result << fragment(p.inspect, sexp)
1711
+ result << f(p.inspect, sexp)
1704
1712
  elsif p.first == :evstr
1705
- result << process(s(:call, p.last, :to_s, s(:arglist)), :expr)
1713
+ result << process(s(:call, p.last, :to_s, s(:arglist)))
1706
1714
  elsif p.first == :str
1707
- result << fragment(p.last.inspect, sexp)
1715
+ result << f(p.last.inspect, sexp)
1708
1716
  else
1709
1717
  raise "Bad dsym part"
1710
1718
  end
1711
1719
  end
1712
1720
 
1713
- [fragment("(", sexp), result, fragment(")", sexp)]
1721
+ [f("(", sexp), result, f(")", sexp)]
1714
1722
  end
1715
1723
 
1716
1724
  # s(:if, test, truthy, falsy)
@@ -1732,18 +1740,18 @@ module Opal
1732
1740
  check = js_truthy test
1733
1741
  end
1734
1742
 
1735
- result = [fragment("if (", sexp), check, fragment(") {\n", sexp)]
1743
+ result = [f("if (", sexp), check, f(") {\n", sexp)]
1736
1744
 
1737
- indent { result.push(fragment(@indent, sexp), process(truthy, :stmt)) } if truthy
1745
+ indent { result.push(f(@indent, sexp), process(truthy, :stmt)) } if truthy
1738
1746
 
1739
1747
  outdent = @indent
1740
- indent { result.push(fragment("\n#{outdent}} else {\n#@indent", sexp), process(falsy, :stmt)) } if falsy
1748
+ indent { result.push(f("\n#{outdent}} else {\n#@indent", sexp), process(falsy, :stmt)) } if falsy
1741
1749
 
1742
- result << fragment("\n#@indent}", sexp)
1750
+ result << f("\n#@indent}", sexp)
1743
1751
 
1744
1752
  if returnable
1745
- result.unshift fragment("(function() { ", sexp)
1746
- result.push fragment("; return nil; }).call(#{current_self})", sexp)
1753
+ result.unshift f("(function() { ", sexp)
1754
+ result.push f("; return nil; }).call(#{current_self})", sexp)
1747
1755
  end
1748
1756
 
1749
1757
  result
@@ -1753,14 +1761,14 @@ module Opal
1753
1761
  if sexp.first == :call
1754
1762
  mid = sexp[2]
1755
1763
  if mid == :block_given?
1756
- return process sexp, :expr
1764
+ return process sexp
1757
1765
  elsif COMPARE.include? mid.to_s
1758
- return process sexp, :expr
1766
+ return process sexp
1759
1767
  elsif mid == :"=="
1760
- return process sexp, :expr
1768
+ return process sexp
1761
1769
  end
1762
1770
  elsif [:lvar, :self].include? sexp.first
1763
- [process(sexp.dup, :expr), fragment(" !== false && ", sexp), process(sexp.dup, :expr), fragment(" !== nil", sexp)]
1771
+ [process(sexp.dup), f(" !== false && ", sexp), process(sexp.dup), f(" !== nil", sexp)]
1764
1772
  end
1765
1773
  end
1766
1774
 
@@ -1770,7 +1778,7 @@ module Opal
1770
1778
  end
1771
1779
 
1772
1780
  with_temp do |tmp|
1773
- [fragment("(#{tmp} = ", sexp), process(sexp, :expr), fragment(") !== false && #{tmp} !== nil", sexp)]
1781
+ [f("(#{tmp} = ", sexp), process(sexp), f(") !== false && #{tmp} !== nil", sexp)]
1774
1782
  end
1775
1783
  end
1776
1784
 
@@ -1784,9 +1792,9 @@ module Opal
1784
1792
 
1785
1793
  with_temp do |tmp|
1786
1794
  result = []
1787
- result << fragment("(#{tmp} = ", sexp)
1788
- result << process(sexp, :expr)
1789
- result << fragment(") === false || #{tmp} === nil", sexp)
1795
+ result << f("(#{tmp} = ", sexp)
1796
+ result << process(sexp)
1797
+ result << f(") === false || #{tmp} === nil", sexp)
1790
1798
  result
1791
1799
  end
1792
1800
  end
@@ -1799,9 +1807,9 @@ module Opal
1799
1807
 
1800
1808
  if t = js_truthy_optimize(lhs)
1801
1809
  result = []
1802
- result << fragment("((#{tmp} = ", sexp) << t
1803
- result << fragment(") ? ", sexp) << process(rhs, :expr)
1804
- result << fragment(" : #{tmp})", sexp)
1810
+ result << f("((#{tmp} = ", sexp) << t
1811
+ result << f(") ? ", sexp) << process(rhs)
1812
+ result << f(" : #{tmp})", sexp)
1805
1813
  @scope.queue_temp tmp
1806
1814
 
1807
1815
  return result
@@ -1809,19 +1817,18 @@ module Opal
1809
1817
 
1810
1818
  @scope.queue_temp tmp
1811
1819
 
1812
- [fragment("(#{tmp} = ", sexp), process(lhs, :expr), fragment(", #{tmp} !== false && #{tmp} !== nil ? ", sexp), process(rhs, :expr), fragment(" : #{tmp})", sexp)]
1820
+ [f("(#{tmp} = ", sexp), process(lhs), f(", #{tmp} !== false && #{tmp} !== nil ? ", sexp), process(rhs), f(" : #{tmp})", sexp)]
1813
1821
 
1814
1822
  end
1815
1823
 
1816
1824
  # s(:or, lhs, rhs)
1817
1825
  def process_or(sexp, level)
1818
- lhs = sexp[0]
1819
- rhs = sexp[1]
1826
+ lhs, rhs = sexp
1820
1827
 
1821
1828
  with_temp do |tmp|
1822
- lhs = process lhs, :expr
1823
- rhs = process rhs, :expr
1824
- [fragment("(((#{tmp} = ", sexp), lhs, fragment(") !== false && #{tmp} !== nil) ? #{tmp} : ", sexp), rhs, fragment(")", sexp)]
1829
+ lhs = process lhs
1830
+ rhs = process rhs
1831
+ [f("(((#{tmp} = ", sexp), lhs, f(") !== false && #{tmp} !== nil) ? #{tmp} : ", sexp), rhs, f(")", sexp)]
1825
1832
  end
1826
1833
  end
1827
1834
 
@@ -1830,10 +1837,10 @@ module Opal
1830
1837
  call = handle_yield_call sexp, level
1831
1838
 
1832
1839
  if level == :stmt
1833
- [fragment("if (", sexp), call, fragment(" === __breaker) return __breaker.$v")]
1840
+ [f("if (", sexp), call, f(" === $breaker) return $breaker.$v")]
1834
1841
  else
1835
1842
  with_temp do |tmp|
1836
- [fragment("(((#{tmp} = ", sexp), call, fragment(") === __breaker) ? __breaker.$v : #{tmp})", sexp)]
1843
+ [f("(((#{tmp} = ", sexp), call, f(") === $breaker) ? $breaker.$v : #{tmp})", sexp)]
1837
1844
  end
1838
1845
  end
1839
1846
  end
@@ -1847,7 +1854,7 @@ module Opal
1847
1854
  def process_yasgn(sexp, level)
1848
1855
  call = handle_yield_call s(*sexp[1][1..-1]), :stmt
1849
1856
 
1850
- [fragment("if ((#{sexp[0]} = ", sexp), call, fragment(") === __breaker) return __breaker.$v", sexp)]
1857
+ [f("if ((#{sexp[0]} = ", sexp), call, f(") === $breaker) return $breaker.$v", sexp)]
1851
1858
  end
1852
1859
 
1853
1860
  # Created by `#returns()` for when a yield statement should return
@@ -1856,8 +1863,8 @@ module Opal
1856
1863
  call = handle_yield_call sexp, level
1857
1864
 
1858
1865
  with_temp do |tmp|
1859
- [fragment("return #{tmp} = ", sexp), call,
1860
- fragment(", #{tmp} === __breaker ? #{tmp} : #{tmp}")]
1866
+ [f("return #{tmp} = ", sexp), call,
1867
+ f(", #{tmp} === $breaker ? #{tmp} : #{tmp}")]
1861
1868
  end
1862
1869
  end
1863
1870
 
@@ -1865,25 +1872,28 @@ module Opal
1865
1872
  @scope.uses_block!
1866
1873
 
1867
1874
  splat = sexp.any? { |s| s.first == :splat }
1868
- sexp.unshift s(:js_tmp, 'null') unless splat # self
1869
- args = process_arglist sexp, level
1870
1875
 
1871
- y = @scope.block_name || '__yield'
1876
+ if !splat and sexp.size == 1
1877
+ return [f("$opal.$yield1(#{@scope.block_name || '$yield'}, "), process(sexp[0]), f(")")]
1878
+ end
1879
+
1880
+ args = process_arglist sexp, level
1881
+ y = @scope.block_name || '$yield'
1872
1882
 
1873
1883
  if splat
1874
- [fragment("#{y}.apply(null, ", sexp), args, fragment(")", sexp)]
1884
+ [f("$opal.$yieldX(#{y}, ", sexp), args, f(")")]
1875
1885
  else
1876
- [fragment("#{y}.call(", sexp), args, fragment(")", sexp)]
1886
+ [f("$opal.$yieldX(#{y}, [", sexp), args, f("])")]
1877
1887
  end
1878
1888
  end
1879
1889
 
1880
1890
  def process_break(sexp, level)
1881
- val = sexp.empty? ? fragment('nil', sexp) : process(sexp.shift, :expr)
1891
+ val = sexp.empty? ? f('nil', sexp) : process(sexp[0])
1882
1892
  if in_while?
1883
- @while_loop[:closure] ? [fragment("return ", sexp), val, fragment("", sexp)] : fragment("break;", sexp)
1893
+ @while_loop[:closure] ? [f("return ", sexp), val, f("", sexp)] : f("break;", sexp)
1884
1894
  elsif @scope.iter?
1885
1895
  error "break must be used as a statement" unless level == :stmt
1886
- [fragment("return (__breaker.$v = ", sexp), val, fragment(", __breaker)", sexp)]
1896
+ [f("return ($breaker.$v = ", sexp), val, f(", $breaker)", sexp)]
1887
1897
  else
1888
1898
  error "void value expression: cannot use break outside of iter/while"
1889
1899
  end
@@ -1891,37 +1901,41 @@ module Opal
1891
1901
 
1892
1902
  # s(:case, expr, when1, when2, ..)
1893
1903
  def process_case(exp, level)
1894
- pre = []
1895
- code = []
1896
- @scope.add_local "$case"
1897
- expr = process exp.shift, :expr
1904
+ pre, code = [], []
1905
+
1898
1906
  # are we inside a statement_closure
1899
1907
  returnable = level != :stmt
1900
1908
  done_else = false
1901
1909
 
1902
- pre << fragment("$case = ", exp) << expr << fragment(";", exp)
1903
-
1904
- until exp.empty?
1905
- wen = exp.shift
1906
- if wen and wen.first == :when
1907
- returns(wen) if returnable
1908
- wen = process(wen, :stmt)
1909
- code << fragment("else ", exp) unless code.empty?
1910
- code << wen
1911
- elsif wen # s(:else)
1912
- done_else = true
1913
- wen = returns(wen) if returnable
1914
- code << fragment("else {", exp) << process(wen, :stmt) << fragment("}", exp)
1910
+ in_case do
1911
+ if cond = exp[0]
1912
+ @case_stmt[:cond] = true
1913
+ @scope.add_local "$case"
1914
+ expr = process cond
1915
+ pre << f("$case = ", exp) << expr << f(";", exp)
1916
+ end
1917
+
1918
+ exp[1..-1].each do |wen|
1919
+ if wen and wen.first == :when
1920
+ returns(wen) if returnable
1921
+ wen = process(wen, :stmt)
1922
+ code << f("else ", exp) unless code.empty?
1923
+ code << wen
1924
+ elsif wen # s(:else)
1925
+ done_else = true
1926
+ wen = returns(wen) if returnable
1927
+ code << f("else {", exp) << process(wen, :stmt) << f("}", exp)
1928
+ end
1915
1929
  end
1916
1930
  end
1917
1931
 
1918
- code << fragment("else { return nil }", exp) if returnable and !done_else
1932
+ code << f("else { return nil }", exp) if returnable and !done_else
1919
1933
 
1920
1934
  code.unshift pre
1921
1935
 
1922
1936
  if returnable
1923
- code.unshift fragment("(function() { ", exp)
1924
- code << fragment(" }).call(#{current_self})", exp)
1937
+ code.unshift f("(function() { ", exp)
1938
+ code << f(" }).call(#{current_self})", exp)
1925
1939
  end
1926
1940
 
1927
1941
  code
@@ -1932,43 +1946,41 @@ module Opal
1932
1946
  #
1933
1947
  # s(:when, s(:array, foo), bar)
1934
1948
  def process_when(exp, level)
1935
- arg = exp.shift[1..-1]
1936
- body = exp.shift || s(:nil)
1937
- #body = process body, level if body
1949
+ arg = exp[0][1..-1]
1950
+ body = exp[1] || s(:nil)
1938
1951
  body = process body, level
1939
1952
 
1940
1953
  test = []
1941
- until arg.empty?
1942
- test << fragment(" || ", exp) unless test.empty?
1943
- a = arg.shift
1954
+ arg.each do |a|
1955
+ test << f(" || ") unless test.empty?
1944
1956
 
1945
1957
  if a.first == :splat # when inside another when means a splat of values
1946
- call = s(:call, s(:js_tmp, "$splt[i]"), :===, s(:arglist, s(:js_tmp, "$case")))
1947
- splt = [fragment("(function($splt) { for(var i = 0; i < $splt.length; i++) {", exp)]
1948
- splt << fragment("if (", exp) << process(call, :expr) << fragment(") { return true; }", exp)
1949
- splt << fragment("} return false; }).call(#{current_self}, ", exp)
1950
- splt << process(a[1], :expr) << fragment(")", exp)
1958
+ call = f("$splt[i]['$===']($case)", a)
1959
+
1960
+ splt = [f("(function($splt) { for(var i = 0; i < $splt.length; i++) {", exp)]
1961
+ splt << f("if (") << call << f(") { return true; }", exp)
1962
+ splt << f("} return false; }).call(#{current_self}, ", exp)
1963
+ splt << process(a[1]) << f(")")
1951
1964
 
1952
1965
  test << splt
1953
1966
  else
1954
- call = s(:call, a, :===, s(:arglist, s(:js_tmp, "$case")))
1955
- call = process call, :expr
1956
-
1957
- test << call
1967
+ if @case_stmt[:cond]
1968
+ call = s(:call, a, :===, s(:arglist, s(:js_tmp, "$case")))
1969
+ test << process(call)
1970
+ else
1971
+ test << js_truthy(a)
1972
+ end
1958
1973
  end
1959
1974
  end
1960
1975
 
1961
- [fragment("if (", exp), test, fragment(") {#@space", exp), body, fragment("#@space}", exp)]
1976
+ [f("if ("), test, f(") {#@space"), body, f("#@space}")]
1962
1977
  end
1963
1978
 
1964
1979
  # lhs =~ rhs
1965
1980
  #
1966
- # s(:match3, lhs, rhs)
1981
+ # s(:match3, lhs, rhs) # => s(:call, lhs, :=~, s(:arglist, rhs))
1967
1982
  def process_match3(sexp, level)
1968
- lhs = sexp[0]
1969
- rhs = sexp[1]
1970
- call = s(:call, lhs, :=~, s(:arglist, rhs))
1971
- process call, level
1983
+ process s(:call, sexp[0], :=~, s(:arglist, sexp[1])), level
1972
1984
  end
1973
1985
 
1974
1986
  # @@class_variable
@@ -1976,8 +1988,7 @@ module Opal
1976
1988
  # s(:cvar, name)
1977
1989
  def process_cvar(exp, level)
1978
1990
  with_temp do |tmp|
1979
- fragment(("((%s = Opal.cvars[%s]) == null ? nil : %s)" %
1980
- [tmp, exp.shift.to_s.inspect, tmp]), exp)
1991
+ f("((#{tmp} = $opal.cvars['#{exp[0]}']) == null ? nil : #{tmp})", exp)
1981
1992
  end
1982
1993
  end
1983
1994
 
@@ -1985,41 +1996,39 @@ module Opal
1985
1996
  #
1986
1997
  # s(:cvasgn, :@@name, rhs)
1987
1998
  def process_cvasgn(exp, level)
1988
- "(Opal.cvars[#{exp.shift.to_s.inspect}] = #{process exp.shift, :expr})"
1999
+ "($opal.cvars['#{exp[0]}'] = #{process exp[1]})"
1989
2000
  end
1990
2001
 
2002
+ # s(:cvdecl, :@@foo, value) # => ($opal.cvars['@@foo'] = value)
1991
2003
  def process_cvdecl(exp, level)
1992
- [fragment("(Opal.cvars[#{exp.shift.to_s.inspect}] = ", exp), process(exp.shift, :expr), fragment(")", exp)]
2004
+ [f("($opal.cvars['#{exp[0]}'] = ", exp), process(exp[1]), f(")", exp)]
1993
2005
  end
1994
2006
 
1995
2007
  # BASE::NAME
1996
2008
  #
1997
2009
  # s(:colon2, base, :NAME)
1998
2010
  def process_colon2(sexp, level)
1999
- base = sexp[0]
2000
- cname = sexp[1].to_s
2011
+ base, cname = sexp
2001
2012
  result = []
2002
2013
 
2003
2014
  if @const_missing
2004
2015
  with_temp do |t|
2005
- base = process base, :expr
2016
+ base = process base
2006
2017
 
2007
- result << fragment("((#{t} = (", sexp) << base << fragment(")._scope).", sexp)
2008
- result << fragment("#{cname} == null ? #{t}.cm(#{cname.inspect}) : #{t}.#{cname})", sexp)
2018
+ result << f("((#{t} = (", sexp) << base << f(")._scope).", sexp)
2019
+ result << f("#{cname} == null ? #{t}.cm('#{cname}') : #{t}.#{cname})", sexp)
2009
2020
  end
2010
2021
  else
2011
- base = process base, :expr
2012
-
2013
- result << fragment("(", sexp) << base << fragment(")._scope.#{cname}", sexp)
2022
+ result << f("(", sexp) << process(base) << f(")._scope.#{cname}", sexp)
2014
2023
  end
2015
2024
 
2016
2025
  result
2017
2026
  end
2018
2027
 
2028
+ # s(:colon3, :CONST_NAME) # => $opal.Object._scope.CONST_NAME
2019
2029
  def process_colon3(exp, level)
2020
2030
  with_temp do |t|
2021
- cname = exp.shift.to_s
2022
- fragment("((#{t} = __opal.Object._scope.#{cname}) == null ? __opal.cm(#{cname.inspect}) : #{t})", exp)
2031
+ f("((#{t} = $opal.Object._scope.#{exp[0]}) == null ? $opal.cm('#{exp[0]}') : #{t})", exp)
2023
2032
  end
2024
2033
  end
2025
2034
 
@@ -2028,46 +2037,68 @@ module Opal
2028
2037
  # s(:super, arg1, arg2, ...)
2029
2038
  def process_super(sexp, level)
2030
2039
  args = []
2031
- until sexp.empty?
2032
- args << fragment(", ", sexp) unless args.empty?
2033
- args << process(sexp.shift, :expr)
2040
+ sexp.each do |part|
2041
+ args << f(", ", sexp) unless args.empty?
2042
+ args << process(part)
2034
2043
  end
2035
2044
 
2036
- js_super [fragment("[", sexp), args, fragment("]", sexp)], sexp
2045
+ js_super [f("[", sexp), args, f("]", sexp)], false, sexp
2037
2046
  end
2038
2047
 
2039
2048
  # super
2040
2049
  #
2041
2050
  # s(:zsuper)
2042
2051
  def process_zsuper(exp, level)
2043
- js_super fragment("__slice.call(arguments)", exp), exp
2052
+ if @scope.def?
2053
+ @scope.uses_zuper = true
2054
+ js_super f("$zuper", exp), true, exp
2055
+ else
2056
+ js_super f("$slice.call(arguments)", exp), true, exp
2057
+ end
2044
2058
  end
2045
2059
 
2046
- def js_super args, sexp
2060
+ def js_super args, pass_block, sexp
2047
2061
  if @scope.def_in_class?
2062
+ @scope.uses_block!
2048
2063
  mid = @scope.mid.to_s
2049
- sid = "super_#{unique_temp}"
2050
2064
 
2051
- @scope.uses_super = sid
2065
+ if @scope.uses_super
2066
+ sid = @scope.uses_super
2067
+ else
2068
+ sid = @scope.uses_super = "super_#{unique_temp}"
2069
+ end
2052
2070
 
2071
+ if pass_block
2072
+ @scope.uses_block!
2073
+ [f("(#{sid}._p = $iter, #{sid}.apply(#{current_self}, ", sexp), args, f("))", sexp)]
2074
+ else
2075
+ [f("#{sid}.apply(#{current_self}, ", sexp), args, f(")", sexp)]
2076
+ end
2053
2077
 
2054
- [fragment("#{sid}.apply(#{current_self}, ", sexp), args, fragment(")", sexp)]
2055
2078
 
2056
2079
  elsif @scope.type == :def
2080
+ @scope.uses_block!
2057
2081
  @scope.identify!
2058
2082
  cls_name = @scope.parent.name || "#{current_self}._klass._proto"
2059
2083
  jsid = mid_to_jsid @scope.mid.to_s
2060
2084
 
2085
+ if pass_block
2086
+ @scope.uses_block!
2087
+ iter = "$iter"
2088
+ else
2089
+ iter = "null"
2090
+ end
2091
+
2061
2092
  if @scope.defs
2062
- [fragment(("%s._super%s.apply(this, " % [cls_name, jsid]), sexp), args, fragment(")", sexp)]
2093
+ [f("$opal.dispatch_super(this, #{@scope.mid.to_s.inspect},", sexp), args, f(", #{iter}, #{cls_name})", sexp)]
2063
2094
  else
2064
- [fragment("#{current_self}._klass._super._proto#{jsid}.apply(#{current_self}, ", sexp), args, fragment(")", sexp)]
2095
+ [f("$opal.dispatch_super(#{current_self}, #{@scope.mid.to_s.inspect}, ", sexp), args, f(", #{iter})", sexp)]
2065
2096
  end
2066
2097
 
2067
2098
  elsif @scope.type == :iter
2068
2099
  chain, defn, mid = @scope.get_super_chain
2069
2100
  trys = chain.map { |c| "#{c}._sup" }.join ' || '
2070
- [fragment("(#{trys} || #{current_self}._klass._super._proto[#{mid}]).apply(#{current_self}, ", sexp), args, fragment(")", sexp)]
2101
+ [f("(#{trys} || #{current_self}._klass._super._proto[#{mid}]).apply(#{current_self}, ", sexp), args, f(")", sexp)]
2071
2102
  else
2072
2103
  raise "Cannot call super() from outside a method block"
2073
2104
  end
@@ -2077,14 +2108,14 @@ module Opal
2077
2108
  #
2078
2109
  # s(:op_asgn_or, s(:lvar, :a), s(:lasgn, :a, rhs))
2079
2110
  def process_op_asgn_or(exp, level)
2080
- process s(:or, exp.shift, exp.shift), :expr
2111
+ process s(:or, exp[0], exp[1])
2081
2112
  end
2082
2113
 
2083
2114
  # a &&= rhs
2084
2115
  #
2085
2116
  # s(:op_asgn_and, s(:lvar, :a), s(:lasgn, :a, rhs))
2086
2117
  def process_op_asgn_and(sexp, level)
2087
- process s(:and, sexp.shift, sexp.shift), :expr
2118
+ process s(:and, sexp[0], sexp[1])
2088
2119
  end
2089
2120
 
2090
2121
  # lhs[args] ||= rhs
@@ -2095,17 +2126,17 @@ module Opal
2095
2126
 
2096
2127
  with_temp do |a| # args
2097
2128
  with_temp do |r| # recv
2098
- args = process arglist[1], :expr
2099
- recv = process lhs, :expr
2129
+ args = process arglist[1]
2130
+ recv = process lhs
2100
2131
 
2101
2132
  aref = s(:call, s(:js_tmp, r), :[], s(:arglist, s(:js_tmp, a)))
2102
2133
  aset = s(:call, s(:js_tmp, r), :[]=, s(:arglist, s(:js_tmp, a), rhs))
2103
2134
  orop = s(:or, aref, aset)
2104
2135
 
2105
2136
  result = []
2106
- result << fragment("(#{a} = ", sexp) << args << fragment(", #{r} = ", sexp)
2107
- result << recv << fragment(", ", sexp) << process(orop, :expr)
2108
- result << fragment(")", sexp)
2137
+ result << f("(#{a} = ", sexp) << args << f(", #{r} = ", sexp)
2138
+ result << recv << f(", ", sexp) << process(orop)
2139
+ result << f(")", sexp)
2109
2140
  result
2110
2141
  end
2111
2142
  end
@@ -2115,10 +2146,10 @@ module Opal
2115
2146
  #
2116
2147
  # s(:op_asgn2, lhs, :b=, :+, rhs)
2117
2148
  def process_op_asgn2(sexp, level)
2118
- lhs = process sexp.shift, :expr
2119
- mid = sexp.shift.to_s[0..-2]
2120
- op = sexp.shift
2121
- rhs = sexp.shift
2149
+ lhs = process sexp[0]
2150
+ mid = sexp[1].to_s[0..-2]
2151
+ op = sexp[2]
2152
+ rhs = sexp[3]
2122
2153
 
2123
2154
  if op.to_s == "||"
2124
2155
  with_temp do |temp|
@@ -2126,7 +2157,7 @@ module Opal
2126
2157
  asgn = s(:call, s(:js_tmp, temp), "#{mid}=", s(:arglist, rhs))
2127
2158
  orop = s(:or, getr, asgn)
2128
2159
 
2129
- [fragment("(#{temp} = ", sexp), lhs, fragment(", ", sexp), process(orop, :expr), fragment(")", sexp)]
2160
+ [f("(#{temp} = ", sexp), lhs, f(", ", sexp), process(orop), f(")", sexp)]
2130
2161
  end
2131
2162
  elsif op.to_s == '&&'
2132
2163
  with_temp do |temp|
@@ -2134,7 +2165,7 @@ module Opal
2134
2165
  asgn = s(:call, s(:js_tmp, temp), "#{mid}=", s(:arglist, rhs))
2135
2166
  andop = s(:and, getr, asgn)
2136
2167
 
2137
- [fragment("(#{temp} = ", sexp), lhs, fragment(", ", sexp), process(andop, :expr), fragment(")", sexp)]
2168
+ [f("(#{temp} = ", sexp), lhs, f(", ", sexp), process(andop), f(")", sexp)]
2138
2169
  end
2139
2170
  else
2140
2171
  with_temp do |temp|
@@ -2142,14 +2173,14 @@ module Opal
2142
2173
  oper = s(:call, getr, op, s(:arglist, rhs))
2143
2174
  asgn = s(:call, s(:js_tmp, temp), "#{mid}=", s(:arglist, oper))
2144
2175
 
2145
- [fragment("(#{temp} = ", sexp), lhs, fragment(", ", sexp), process(asgn, :expr), fragment(")", sexp)]
2176
+ [f("(#{temp} = ", sexp), lhs, f(", ", sexp), process(asgn), f(")", sexp)]
2146
2177
  end
2147
2178
  end
2148
2179
  end
2149
2180
 
2150
2181
  # s(:ensure, body, ensure)
2151
2182
  def process_ensure(exp, level)
2152
- begn = exp.shift
2183
+ begn = exp[0]
2153
2184
  if level == :recv || level == :expr
2154
2185
  retn = true
2155
2186
  begn = returns begn
@@ -2157,49 +2188,49 @@ module Opal
2157
2188
 
2158
2189
  result = []
2159
2190
  body = process begn, level
2160
- ensr = exp.shift || s(:nil)
2191
+ ensr = exp[1] || s(:nil)
2161
2192
  ensr = process ensr, level
2162
2193
 
2163
- body = [fragment("try {\n", exp), body, fragment("}", exp)]
2194
+ body = [f("try {\n", exp), body, f("}", exp)]
2164
2195
 
2165
- result << body << fragment("#{@space}finally {#@space", exp) << ensr << fragment("}", exp)
2196
+ result << body << f("#{@space}finally {#@space", exp) << ensr << f("}", exp)
2166
2197
 
2167
2198
  if retn
2168
- [fragment("(function() { ", exp), result, fragment("; }).call(#{current_self})", exp)]
2199
+ [f("(function() { ", exp), result, f("; }).call(#{current_self})", exp)]
2169
2200
  else
2170
2201
  result
2171
2202
  end
2172
2203
  end
2173
2204
 
2174
2205
  def process_rescue(exp, level)
2175
- body = exp.first.first == :resbody ? s(:nil) : exp.shift
2206
+ body = exp.first.first == :resbody ? s(:nil) : exp[0]
2176
2207
  body = indent { process body, level }
2177
2208
  handled_else = false
2178
2209
 
2179
2210
  parts = []
2180
- until exp.empty?
2181
- handled_else = true unless exp.first.first == :resbody
2182
- part = indent { process exp.shift, level }
2211
+ exp[1..-1].each do |a|
2212
+ handled_else = true unless a.first == :resbody
2213
+ part = indent { process a, level }
2183
2214
 
2184
2215
  unless parts.empty?
2185
- parts << fragment("else ", exp)
2216
+ parts << f("else ", exp)
2186
2217
  end
2187
2218
 
2188
2219
  parts << part
2189
2220
  end
2190
2221
  # if no rescue statement captures our error, we should rethrow
2191
- parts << indent { fragment("else { throw $err; }", exp) } unless handled_else
2222
+ parts << indent { f("else { throw $err; }", exp) } unless handled_else
2192
2223
 
2193
2224
  code = []
2194
- code << fragment("try {#@space#{INDENT}", exp)
2225
+ code << f("try {#@space#{INDENT}", exp)
2195
2226
  code << body
2196
- code << fragment("#@space} catch ($err) {#@space", exp)
2227
+ code << f("#@space} catch ($err) {#@space", exp)
2197
2228
  code << parts
2198
- code << fragment("#@space}", exp)
2229
+ code << f("#@space}", exp)
2199
2230
 
2200
2231
  if level == :expr
2201
- code.unshift fragment("(function() { ", exp)
2202
- code << fragment(" }).call(#{current_self})", exp)
2232
+ code.unshift f("(function() { ", exp)
2233
+ code << f(" }).call(#{current_self})", exp)
2203
2234
  end
2204
2235
 
2205
2236
  code
@@ -2215,49 +2246,52 @@ module Opal
2215
2246
 
2216
2247
  err = []
2217
2248
  types.each do |t|
2218
- err << fragment(", ", exp) unless err.empty?
2249
+ err << f(", ", exp) unless err.empty?
2219
2250
  call = s(:call, t, :===, s(:arglist, s(:js_tmp, "$err")))
2220
- a = process call, :expr
2251
+ a = process call
2221
2252
  err << a
2222
2253
  end
2223
- err << fragment("true", exp) if err.empty?
2254
+ err << f("true", exp) if err.empty?
2224
2255
 
2225
2256
  if Array === args.last and [:lasgn, :iasgn].include? args.last.first
2226
2257
  val = args.last
2227
2258
  val[2] = s(:js_tmp, "$err")
2228
- val = [process(val, :expr) , fragment(";", exp)]
2259
+ val = [process(val) , f(";", exp)]
2229
2260
  end
2230
2261
 
2231
2262
  val = [] unless val
2232
2263
 
2233
- [fragment("if (", exp), err, fragment("){#@space", exp), val, body, fragment("}", exp)]
2264
+ [f("if (", exp), err, f("){#@space", exp), val, body, f("}", exp)]
2234
2265
  end
2235
2266
 
2236
2267
  # FIXME: Hack.. grammar should remove top level begin.
2237
2268
  def process_begin(exp, level)
2238
- result = process exp[0], level
2269
+ process exp[0], level
2239
2270
  end
2240
2271
 
2241
2272
  def process_next(exp, level)
2242
2273
  if in_while?
2243
- fragment("continue;", exp)
2274
+ f("continue;", exp)
2244
2275
  else
2245
2276
  result = []
2246
- result << fragment("return ", exp)
2277
+ result << f("return ", exp)
2247
2278
 
2248
- result << (exp.empty? ? fragment('nil', exp) : process(exp.shift, :expr))
2249
- result << fragment(";", exp)
2279
+ result << (exp.empty? ? f('nil', exp) : process(exp[0]))
2280
+ result << f(";", exp)
2250
2281
 
2251
2282
  result
2252
2283
  end
2253
2284
  end
2254
2285
 
2286
+ # s(:redo) # => $redo_var = true
2287
+ # Only currently supported inside while loops. Simply sets the redo variable
2288
+ # for the loop to true.
2255
2289
  def process_redo(exp, level)
2256
2290
  if in_while?
2257
2291
  @while_loop[:use_redo] = true
2258
- fragment("#{@while_loop[:redo_var]} = true", exp)
2292
+ f("#{@while_loop[:redo_var]} = true", exp)
2259
2293
  else
2260
- fragment("REDO()", exp)
2294
+ f("REDO()", exp)
2261
2295
  end
2262
2296
  end
2263
2297
  end