opal 0.9.4 → 0.10.0.beta1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (193) hide show
  1. checksums.yaml +4 -4
  2. data/.gitattributes +1 -0
  3. data/.gitignore +2 -3
  4. data/.gitmodules +5 -2
  5. data/.jshintrc +1 -8
  6. data/.rspec +1 -1
  7. data/.travis.yml +15 -23
  8. data/CHANGELOG.md +511 -326
  9. data/CODE_OF_CONDUCT.md +13 -15
  10. data/CONTRIBUTING.md +26 -216
  11. data/Gemfile +20 -12
  12. data/Guardfile +2 -2
  13. data/HACKING.md +230 -0
  14. data/README.md +6 -7
  15. data/bin/opal-mspec +1 -1
  16. data/config.ru +2 -2
  17. data/docs/faq.md +1 -1
  18. data/docs/source_maps.md +1 -1
  19. data/lib/opal.rb +1 -0
  20. data/lib/opal/builder.rb +1 -1
  21. data/lib/opal/cli.rb +30 -28
  22. data/lib/opal/cli_options.rb +3 -0
  23. data/lib/opal/cli_runners.rb +14 -1
  24. data/lib/opal/cli_runners/{apple_script.rb → applescript.rb} +3 -3
  25. data/lib/opal/cli_runners/nashorn.rb +2 -2
  26. data/lib/opal/cli_runners/nodejs.rb +2 -2
  27. data/lib/opal/cli_runners/phantom.js +24 -0
  28. data/lib/opal/cli_runners/phantomjs.rb +10 -10
  29. data/lib/opal/cli_runners/server.rb +3 -3
  30. data/lib/opal/compiler.rb +43 -4
  31. data/lib/opal/config.rb +3 -1
  32. data/lib/opal/errors.rb +13 -0
  33. data/lib/opal/fragment.rb +0 -13
  34. data/lib/opal/nodes.rb +10 -0
  35. data/lib/opal/nodes/args/initialize_kwargs.rb +28 -0
  36. data/lib/opal/nodes/args/kwarg.rb +29 -0
  37. data/lib/opal/nodes/args/kwoptarg.rb +29 -0
  38. data/lib/opal/nodes/args/kwrestarg.rb +39 -0
  39. data/lib/opal/nodes/args/mlhsarg.rb +79 -0
  40. data/lib/opal/nodes/args/normarg.rb +26 -0
  41. data/lib/opal/nodes/args/optarg.rb +27 -0
  42. data/lib/opal/nodes/args/post_args.rb +200 -0
  43. data/lib/opal/nodes/args/post_kwargs.rb +31 -0
  44. data/lib/opal/nodes/args/restarg.rb +33 -0
  45. data/lib/opal/nodes/base.rb +12 -0
  46. data/lib/opal/nodes/call.rb +92 -33
  47. data/lib/opal/nodes/def.rb +26 -169
  48. data/lib/opal/nodes/hash.rb +10 -4
  49. data/lib/opal/nodes/helpers.rb +6 -3
  50. data/lib/opal/nodes/inline_args.rb +61 -0
  51. data/lib/opal/nodes/iter.rb +73 -82
  52. data/lib/opal/nodes/logic.rb +12 -2
  53. data/lib/opal/nodes/masgn.rb +1 -2
  54. data/lib/opal/nodes/node_with_args.rb +141 -0
  55. data/lib/opal/nodes/rescue.rb +121 -43
  56. data/lib/opal/nodes/scope.rb +24 -5
  57. data/lib/opal/nodes/super.rb +122 -54
  58. data/lib/opal/nodes/top.rb +0 -12
  59. data/lib/opal/nodes/yield.rb +2 -13
  60. data/lib/opal/parser.rb +67 -39
  61. data/lib/opal/parser/grammar.rb +3319 -2961
  62. data/lib/opal/parser/grammar.y +234 -46
  63. data/lib/opal/parser/lexer.rb +105 -17
  64. data/lib/opal/parser/sexp.rb +4 -0
  65. data/lib/opal/paths.rb +4 -0
  66. data/lib/opal/regexp_anchors.rb +19 -1
  67. data/lib/opal/sprockets.rb +21 -18
  68. data/lib/opal/sprockets/environment.rb +0 -8
  69. data/lib/opal/sprockets/processor.rb +13 -16
  70. data/lib/opal/sprockets/server.rb +6 -12
  71. data/lib/opal/version.rb +1 -1
  72. data/opal.gemspec +1 -0
  73. data/opal/corelib/array.rb +209 -131
  74. data/opal/corelib/basic_object.rb +7 -3
  75. data/opal/corelib/class.rb +11 -17
  76. data/opal/corelib/constants.rb +2 -2
  77. data/opal/corelib/enumerable.rb +178 -355
  78. data/opal/corelib/enumerator.rb +3 -46
  79. data/opal/corelib/error.rb +2 -2
  80. data/opal/corelib/file.rb +13 -1
  81. data/opal/corelib/hash.rb +26 -56
  82. data/opal/corelib/helpers.rb +10 -0
  83. data/opal/corelib/kernel.rb +6 -3
  84. data/opal/corelib/module.rb +62 -31
  85. data/opal/corelib/number.rb +7 -16
  86. data/opal/corelib/proc.rb +24 -9
  87. data/opal/corelib/range.rb +4 -13
  88. data/opal/corelib/runtime.js +515 -378
  89. data/opal/corelib/string.rb +21 -49
  90. data/opal/corelib/struct.rb +50 -35
  91. data/opal/corelib/unsupported.rb +18 -30
  92. data/opal/opal.rb +0 -1
  93. data/opal/opal/mini.rb +1 -0
  94. data/spec/README.md +6 -4
  95. data/spec/filters/bugs/array.rb +0 -42
  96. data/spec/filters/bugs/basicobject.rb +0 -2
  97. data/spec/filters/bugs/bigdecimal.rb +160 -0
  98. data/spec/filters/bugs/class.rb +0 -5
  99. data/spec/filters/bugs/date.rb +1 -48
  100. data/spec/filters/bugs/enumerable.rb +4 -12
  101. data/spec/filters/bugs/enumerator.rb +0 -1
  102. data/spec/filters/bugs/exception.rb +4 -3
  103. data/spec/filters/bugs/float.rb +4 -2
  104. data/spec/filters/bugs/kernel.rb +25 -10
  105. data/spec/filters/bugs/language.rb +119 -68
  106. data/spec/filters/bugs/method.rb +135 -0
  107. data/spec/filters/bugs/module.rb +13 -28
  108. data/spec/filters/bugs/proc.rb +18 -8
  109. data/spec/filters/bugs/range.rb +0 -3
  110. data/spec/filters/bugs/rational.rb +4 -0
  111. data/spec/filters/bugs/regexp.rb +68 -36
  112. data/spec/filters/bugs/string.rb +1 -1
  113. data/spec/filters/bugs/struct.rb +0 -12
  114. data/spec/filters/bugs/time.rb +1 -0
  115. data/spec/filters/bugs/unboundmethod.rb +2 -1
  116. data/spec/filters/unsupported/freeze.rb +3 -1
  117. data/spec/filters/unsupported/language.rb +0 -7
  118. data/spec/filters/unsupported/privacy.rb +7 -6
  119. data/spec/filters/unsupported/string.rb +10 -0
  120. data/spec/filters/unsupported/struct.rb +3 -0
  121. data/spec/filters/unsupported/symbol.rb +9 -0
  122. data/spec/filters/unsupported/taint.rb +0 -3
  123. data/spec/filters/unsupported/thread.rb +1 -0
  124. data/spec/lib/cli_runners/phantomjs_spec.rb +39 -0
  125. data/spec/lib/cli_spec.rb +42 -1
  126. data/spec/lib/compiler/call_spec.rb +700 -0
  127. data/spec/lib/compiler_spec.rb +46 -28
  128. data/spec/lib/config_spec.rb +13 -0
  129. data/spec/lib/parser/call_spec.rb +18 -0
  130. data/spec/lib/parser/def_spec.rb +29 -0
  131. data/spec/lib/parser/iter_spec.rb +15 -15
  132. data/spec/lib/parser/lambda_spec.rb +153 -12
  133. data/spec/lib/parser/string_spec.rb +5 -0
  134. data/spec/lib/parser/undef_spec.rb +1 -1
  135. data/spec/lib/parser/variables_spec.rb +24 -0
  136. data/spec/lib/paths_spec.rb +12 -5
  137. data/spec/lib/spec_helper.rb +5 -0
  138. data/spec/lib/sprockets/processor_spec.rb +6 -5
  139. data/spec/lib/sprockets_spec.rb +8 -0
  140. data/spec/mspec-opal/formatters.rb +188 -0
  141. data/spec/mspec-opal/runner.rb +193 -0
  142. data/spec/opal/core/enumerator/with_index_spec.rb +6 -0
  143. data/spec/opal/core/kernel/define_singleton_method_spec.rb +1 -1
  144. data/spec/opal/core/kernel/instance_variables_spec.rb +14 -0
  145. data/spec/opal/core/kernel/loop_spec.rb +1 -1
  146. data/spec/opal/core/kernel/raise_spec.rb +1 -1
  147. data/spec/opal/core/language/heredoc_spec.rb +42 -0
  148. data/spec/opal/core/language/rescue_spec.rb +18 -0
  149. data/spec/opal/core/language_spec.rb +22 -0
  150. data/spec/opal/core/module/const_defined_spec.rb +1 -2
  151. data/spec/opal/core/module/name_spec.rb +6 -0
  152. data/spec/opal/core/runtime/bridged_classes_spec.rb +14 -2
  153. data/spec/opal/core/runtime/rescue_spec.rb +12 -2
  154. data/spec/opal/core/runtime/super_spec.rb +1 -0
  155. data/spec/opal/core/string_spec.rb +21 -0
  156. data/spec/opal/stdlib/js_spec.rb +1 -1
  157. data/spec/opal/stdlib/native/hash_spec.rb +7 -0
  158. data/spec/opal/stdlib/promise/always_spec.rb +24 -5
  159. data/spec/opal/stdlib/promise/rescue_spec.rb +15 -6
  160. data/spec/opal/stdlib/promise/then_spec.rb +13 -5
  161. data/spec/opal/stdlib/promise/trace_spec.rb +5 -6
  162. data/spec/opal/stdlib/strscan/scan_spec.rb +1 -1
  163. data/spec/ruby_specs +122 -0
  164. data/spec/spec_helper.rb +3 -15
  165. data/stdlib/base64.rb +51 -121
  166. data/stdlib/bigdecimal.rb +231 -0
  167. data/stdlib/bigdecimal/bignumber.js.rb +11 -0
  168. data/stdlib/bigdecimal/kernel.rb +5 -0
  169. data/stdlib/date.rb +252 -10
  170. data/stdlib/native.rb +38 -38
  171. data/stdlib/nodejs/dir.rb +8 -6
  172. data/stdlib/nodejs/file.rb +28 -3
  173. data/stdlib/nodejs/node_modules/.bin/js-yaml +1 -0
  174. data/stdlib/nodejs/node_modules/js-yaml/node_modules/.bin/esparse +1 -0
  175. data/stdlib/nodejs/node_modules/js-yaml/node_modules/.bin/esvalidate +1 -0
  176. data/stdlib/nodejs/require.rb +1 -1
  177. data/stdlib/nodejs/yaml.rb +3 -2
  178. data/stdlib/opal-parser.rb +7 -2
  179. data/stdlib/pathname.rb +23 -1
  180. data/stdlib/phantomjs.rb +10 -0
  181. data/stdlib/promise.rb +38 -23
  182. data/tasks/building.rake +3 -3
  183. data/tasks/testing.rake +27 -14
  184. data/tasks/testing/mspec_special_calls.rb +1 -1
  185. data/tasks/testing/sprockets-phantomjs.js +4 -0
  186. data/test/opal/test_keyword.rb +110 -110
  187. data/test/opal/unsupported_and_bugs.rb +30 -0
  188. data/vendored-minitest/minitest/assertions.rb +1 -1
  189. metadata +65 -15
  190. data/.spectator +0 -2
  191. data/.spectator-mspec +0 -3
  192. data/opal/corelib/array/inheritance.rb +0 -127
  193. data/spec/rubyspecs +0 -139
@@ -16,7 +16,13 @@ module Opal
16
16
  end
17
17
 
18
18
  def compile
19
- push "try {", expr(body), " } catch ($err) { ", expr(rescue_val), " }"
19
+ line "try {", expr(body), " } catch ($err) { "
20
+
21
+ indent do
22
+ line "if (Opal.rescue($err, [", expr(Sexp.new([:const, :StandardError])), "])) {"
23
+ line expr(rescue_val)
24
+ line "} else { throw $err; } }"
25
+ end
20
26
 
21
27
  wrap '(function() {', '})()' unless stmt?
22
28
  end
@@ -29,16 +35,56 @@ module Opal
29
35
 
30
36
  def compile
31
37
  push "try {"
32
- line compiler.process(body_sexp, @level)
38
+
39
+ in_ensure do
40
+ line compiler.process(body_sexp, @level)
41
+ end
42
+
33
43
  line "} finally {"
34
- line compiler.process(ensr_sexp, @level)
44
+
45
+ indent do
46
+ if has_rescue_else?
47
+ # $no_errors indicates thate there were no error raised
48
+ unshift "var $no_errors = true; "
49
+
50
+ # when there's a begin;rescue;else;ensure;end statement,
51
+ # ruby returns a result of the 'else' branch
52
+ # but invokes it before 'ensure'.
53
+ # so, here we
54
+ # 1. save the result of calling else to $rescue_else_result
55
+ # 2. call ensure
56
+ # 2. return $rescue_else_result
57
+ line "var $rescue_else_result;"
58
+ line "if ($no_errors) { "
59
+ indent do
60
+ line "$rescue_else_result = (function() {"
61
+ indent do
62
+ line compiler.process(compiler.returns(scope.rescue_else_sexp), @level)
63
+ end
64
+ line "})();"
65
+ end
66
+ line "}"
67
+ line compiler.process(ensr_sexp, @level)
68
+ line "if ($no_errors) { return $rescue_else_result; }"
69
+ else
70
+ line compiler.process(ensr_sexp, @level)
71
+ end
72
+ end
73
+
35
74
  line "}"
36
75
 
37
- wrap '(function() {', '; })()' if wrap_in_closure?
76
+ wrap '(function() { ', '; })()' if wrap_in_closure?
38
77
  end
39
78
 
40
79
  def body_sexp
41
- wrap_in_closure? ? compiler.returns(begn) : begn
80
+ if wrap_in_closure?
81
+ sexp = compiler.returns(begn)
82
+ # 'rescue' is an edge case that should be compiled to
83
+ # try { return function(){ ..rescue through try/catch.. }() }
84
+ sexp.type == :rescue ? s(:js_return, sexp) : sexp
85
+ else
86
+ sexp = begn
87
+ end
42
88
  end
43
89
 
44
90
  def ensr_sexp
@@ -46,7 +92,7 @@ module Opal
46
92
  end
47
93
 
48
94
  def wrap_in_closure?
49
- recv? or expr?
95
+ recv? or expr? or has_rescue_else?
50
96
  end
51
97
  end
52
98
 
@@ -56,37 +102,74 @@ module Opal
56
102
  children :body
57
103
 
58
104
  def compile
59
- handled_else = false
105
+ scope.rescue_else_sexp = children[1..-1].detect { |sexp| sexp.type != :resbody }
106
+ has_rescue_handlers = false
107
+
108
+ if handle_rescue_else_manually?
109
+ line "var $no_errors = true;"
110
+ end
60
111
 
61
112
  push "try {"
62
- line(indent { process(body_code, @level) })
113
+ indent do
114
+ line process(body_code, @level)
115
+ end
63
116
  line "} catch ($err) {"
64
117
 
65
- children[1..-1].each_with_index do |child, idx|
66
- handled_else = true unless child.type == :resbody
118
+ indent do
119
+ if has_rescue_else?
120
+ line "$no_errors = false;"
121
+ end
67
122
 
68
- push "else " unless idx == 0
69
- push(indent { process(child, @level) })
70
- end
123
+ children[1..-1].each_with_index do |child, idx|
124
+ # counting only rescue, ignoring rescue-else statement
125
+ if child.type == :resbody
126
+ has_rescue_handlers = true
71
127
 
72
- # if no resbodys capture our error, then rethrow
73
- unless handled_else
74
- push "else { throw $err; }"
128
+ push " else " unless idx == 0
129
+ line process(child, @level)
130
+ end
131
+ end
132
+
133
+ # if no resbodys capture our error, then rethrow
134
+ push " else { throw $err; }"
75
135
  end
76
136
 
77
137
  line "}"
78
138
 
79
- wrap '(function() { ', '})()' if expr?
139
+ if handle_rescue_else_manually?
140
+ # here we must add 'finally' explicitly
141
+ push "finally {"
142
+ indent do
143
+ line "if ($no_errors) { "
144
+ indent do
145
+ line "return (function() {"
146
+ indent do
147
+ line compiler.process(compiler.returns(scope.rescue_else_sexp), @level)
148
+ end
149
+ line "})();"
150
+ end
151
+ line "}"
152
+ end
153
+ push "}"
154
+ end
155
+
156
+ # Wrap a try{} catch{} into a function
157
+ # when it's an expression
158
+ # or when there's a method call after begin;rescue;end
159
+ wrap '(function() { ', '})()' if expr? or recv?
80
160
  end
81
161
 
82
162
  def body_code
83
163
  body_code = (body.type == :resbody ? s(:nil) : body)
164
+ body_code = compiler.returns body_code unless stmt?
165
+ body_code
166
+ end
84
167
 
85
- if !stmt?
86
- compiler.returns body_code
87
- else
88
- body_code
89
- end
168
+ # Returns true when there's no 'ensure' statement
169
+ # wrapping current rescue.
170
+ #
171
+ def handle_rescue_else_manually?
172
+ !scope.in_ensure? && scope.has_rescue_else?
90
173
  end
91
174
  end
92
175
 
@@ -96,36 +179,31 @@ module Opal
96
179
  children :args, :body
97
180
 
98
181
  def compile
99
- push "if ("
182
+ push "if (Opal.rescue($err, ["
100
183
  if rescue_exprs.empty?
101
- # if no expressions are given, then catch all errors
102
- push "true"
184
+ # if no expressions are given, then catch StandardError only
185
+ push expr(Sexp.new([:const, :StandardError]))
103
186
  else
104
- push "Opal.rescue($err, ["
105
187
  rescue_exprs.each_with_index do |rexpr, idx|
106
188
  push ', ' unless idx == 0
107
189
  push expr(rexpr)
108
190
  end
109
- push "])"
110
191
  end
111
- push ") {"
112
-
113
- if variable = rescue_variable
114
- variable[2] = s(:js_tmp, '$err')
115
- push expr(variable), ';'
116
- end
117
-
118
- # Need to ensure we clear the current exception out after the rescue block ends
119
- line "try {"
120
- indent do
121
- line process(rescue_body, @level)
122
- end
123
- line "} finally {"
192
+ push "])) {"
124
193
  indent do
125
- line 'Opal.gvars["!"] = Opal.exceptions.pop() || Opal.nil;'
194
+ if variable = rescue_variable
195
+ variable[2] = s(:js_tmp, '$err')
196
+ push expr(variable), ';'
197
+ end
198
+
199
+ # Need to ensure we clear the current exception out after the rescue block ends
200
+ line "try {"
201
+ indent do
202
+ line process(rescue_body, @level)
203
+ end
204
+ line '} finally { Opal.pop_exception() }'
126
205
  end
127
206
  line "}"
128
- line "}"
129
207
  end
130
208
 
131
209
  def rescue_variable?(variable)
@@ -144,7 +222,7 @@ module Opal
144
222
 
145
223
  def rescue_body
146
224
  body_code = (body || s(:nil))
147
- body_code = compiler.returns(body_code) if !stmt?
225
+ body_code = compiler.returns(body_code) unless stmt?
148
226
  body_code
149
227
  end
150
228
  end
@@ -30,7 +30,9 @@ module Opal
30
30
  attr_accessor :uses_super
31
31
  attr_accessor :uses_zuper
32
32
 
33
- attr_accessor :catch_return
33
+ attr_accessor :catch_return, :has_break
34
+
35
+ attr_accessor :rescue_else_sexp
34
36
 
35
37
  def initialize(*)
36
38
  super
@@ -169,14 +171,15 @@ module Opal
169
171
  end
170
172
 
171
173
  def has_local?(local)
172
- return true if @locals.include? local or @args.include? local
174
+ return true if @locals.include? local or @args.include? local or @temps.include? local
173
175
  return @parent.has_local?(local) if @parent and @type == :iter
174
-
175
176
  false
176
177
  end
177
178
 
178
- def add_scope_temp(*tmps)
179
- @temps.push(*tmps)
179
+ def add_scope_temp(tmp)
180
+ return if has_temp?(tmp)
181
+
182
+ @temps.push(tmp)
180
183
  end
181
184
 
182
185
  def has_temp?(tmp)
@@ -277,6 +280,22 @@ module Opal
277
280
  def uses_block?
278
281
  @uses_block
279
282
  end
283
+
284
+ def has_rescue_else?
285
+ !!rescue_else_sexp
286
+ end
287
+
288
+ def in_ensure
289
+ return unless block_given?
290
+
291
+ @in_ensure = true
292
+ result = yield
293
+ @in_ensure = false
294
+ end
295
+
296
+ def in_ensure?
297
+ !!@in_ensure
298
+ end
280
299
  end
281
300
  end
282
301
  end
@@ -5,92 +5,160 @@ module Opal
5
5
  # This base class is used just to child the find_super_dispatcher method
6
6
  # body. This is then used by actual super calls, or a defined?(super) style
7
7
  # call.
8
- class BaseSuperNode < Base
9
- children :arglist, :iter
8
+ class BaseSuperNode < CallNode
9
+ children :arglist, :raw_iter
10
10
 
11
- def compile_dispatcher
12
- if arglist or iter
13
- iter = expr(iter_sexp)
14
- else
15
- scope.uses_block!
16
- iter = '$iter'
17
- end
11
+ def compile
18
12
  if scope.def?
19
13
  scope.uses_block!
20
- scope_name = scope.identify!
21
- class_name = scope.parent.name ? "$#{scope.parent.name}" : 'self.$$class.$$proto'
14
+ end
15
+
16
+ default_compile
17
+ end
18
+
19
+ private
20
+
21
+ # always on self
22
+ def recvr
23
+ s(:self)
24
+ end
22
25
 
23
- if scope.defs
24
- push "Opal.find_super_dispatcher(self, '#{scope.mid.to_s}', #{scope_name}, "
25
- push iter
26
- push ", #{class_name})"
26
+ def iter
27
+ # Need to support passing block up even if it's not referenced in this method at all
28
+ @iter ||= begin
29
+ if raw_iter
30
+ raw_iter
31
+ elsif arglist # TODO: Better understand this elsif vs. the else code path
32
+ s(:js_tmp, 'null')
27
33
  else
28
- push "Opal.find_super_dispatcher(self, '#{scope.mid.to_s}', #{scope_name}, "
29
- push iter
30
- push ")"
34
+ scope.uses_block!
35
+ s(:js_tmp, '$iter')
31
36
  end
32
- elsif scope.iter?
33
- chain, cur_defn, mid = scope.get_super_chain
34
- trys = chain.map { |c| "#{c}.$$def" }.join(' || ')
37
+ end
38
+ end
39
+
40
+ def method_jsid
41
+ raise 'Not implemented, see #add_method'
42
+ end
43
+
44
+ # Need a way to pass self into the method invocation
45
+ def redefine_this?(temporary_receiver)
46
+ true
47
+ end
48
+
49
+ def arguments_array?
50
+ # zuper is an implicit super argument array
51
+ super || @implicit_args
52
+ end
53
+
54
+ def containing_def_scope
55
+ return scope if scope.def?
56
+
57
+ # using super in a block inside a method is allowed, e.g.
58
+ # def a
59
+ # { super }
60
+ # end
61
+ scope.find_parent_def
62
+ end
63
+
64
+ def defined_check_param
65
+ 'false'
66
+ end
35
67
 
36
- push "Opal.find_iter_super_dispatcher(self, #{mid}, (#{trys} || #{cur_defn}), null)"
68
+ def implicit_arguments_param
69
+ @implicit_args ? 'true' : 'false'
70
+ end
71
+
72
+ def super_method_invocation
73
+ def_scope = containing_def_scope
74
+ method_jsid = def_scope.mid.to_s
75
+ current_func = def_scope.identify!
76
+
77
+ if def_scope.defs
78
+ class_name = def_scope.parent.name ? "$#{def_scope.parent.name}" : 'self.$$class.$$proto'
79
+ "Opal.find_super_dispatcher(self, '#{method_jsid}', #{current_func}, #{defined_check_param}, #{class_name})"
37
80
  else
38
- raise "Cannot call super() from outside a method block"
81
+ "Opal.find_super_dispatcher(self, '#{method_jsid}', #{current_func}, #{defined_check_param})"
39
82
  end
40
83
  end
41
84
 
42
- def args
43
- arglist || s(:arglist)
85
+ def super_block_invocation
86
+ chain, cur_defn, mid = scope.get_super_chain
87
+ trys = chain.map { |c| "#{c}.$$def" }.join(' || ')
88
+ implicit = @implicit_args.to_s
89
+
90
+ "Opal.find_iter_super_dispatcher(self, #{mid}, (#{trys} || #{cur_defn}), #{defined_check_param}, #{implicit_arguments_param})"
44
91
  end
45
92
 
46
- def iter_sexp
47
- iter || s(:js_tmp, 'null')
93
+ def add_method(temporary_receiver)
94
+ super_call = if scope.def?
95
+ super_method_invocation
96
+ elsif scope.iter?
97
+ super_block_invocation
98
+ else
99
+ raise 'unexpected compilation error'
100
+ end
101
+
102
+ if temporary_receiver
103
+ push "(#{temporary_receiver} = ", receiver_fragment, ", ", super_call, ")"
104
+ else
105
+ push super_call
106
+ end
48
107
  end
49
108
  end
50
109
 
51
110
  class DefinedSuperNode < BaseSuperNode
52
111
  handle :defined_super
53
112
 
54
- def compile
55
- # insert method body to find super method
56
- self.compile_dispatcher
113
+ def defined_check_param
114
+ 'true'
115
+ end
57
116
 
58
- wrap '((', ') != null ? "super" : nil)'
117
+ def compile
118
+ add_method(nil)
119
+ # will never come back null with method missing on
120
+ if compiler.method_missing?
121
+ wrap '(!(', '.$$stub) ? "super" : nil)'
122
+ else
123
+ # TODO: With method_missing support off, something breaks in runtime.js's chain
124
+ wrap '((', ') != null ? "super" : nil)'
125
+ end
59
126
  end
60
127
  end
61
128
 
62
129
  class SuperNode < BaseSuperNode
63
130
  handle :super
64
131
 
65
- children :arglist, :iter
66
-
67
132
  def compile
68
- if arglist or iter
69
- splat = has_splat?
70
- args = expr(self.args)
71
-
72
- unless splat
73
- args = [fragment('['), args, fragment(']')]
74
- end
75
- else
76
- if scope.def?
77
- scope.uses_zuper = true
78
- args = fragment('$zuper')
133
+ if arglist == nil
134
+ @implicit_args = true
135
+ if containing_def_scope
136
+ containing_def_scope.uses_zuper = true
137
+ @arguments_without_block = [s(:js_tmp, '$zuper')]
138
+ # If the method we're in has a block and we're using a default super call with no args, we need to grab the block
139
+ # If an iter (block via braces) is provided, that takes precedence
140
+ if (block_arg = formal_block_parameter) && !iter
141
+ expr = s(:block_pass, s(:lvar, block_arg[1]))
142
+ @arguments_without_block << expr
143
+ end
79
144
  else
80
- args = fragment('$slice.call(arguments)')
145
+ @arguments_without_block = []
81
146
  end
82
147
  end
83
-
84
- # compile our call to runtime to get super method
85
- self.compile_dispatcher
86
-
87
- push ".apply(self, "
88
- push(*args)
89
- push ")"
148
+ super
90
149
  end
91
150
 
92
- def has_splat?
93
- args.children.any? { |child| child.type == :splat }
151
+ private
152
+
153
+ def formal_block_parameter
154
+ case containing_def_scope
155
+ when Opal::Nodes::IterNode
156
+ containing_def_scope.extract_block_arg
157
+ when Opal::Nodes::DefNode
158
+ containing_def_scope.block_arg
159
+ else
160
+ raise "Don't know what to do with scope #{containing_def_scope}"
161
+ end
94
162
  end
95
163
  end
96
164
  end