opal 1.4.1 → 1.5.0.rc1

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 (89) hide show
  1. checksums.yaml +4 -4
  2. data/.eslintrc.js +5 -3
  3. data/.rubocop.yml +1 -0
  4. data/UNRELEASED.md +37 -2
  5. data/benchmark-ips/bm_js_symbols_vs_strings.rb +39 -14
  6. data/docs/releasing.md +10 -2
  7. data/lib/opal/ast/matcher.rb +77 -0
  8. data/lib/opal/cache.rb +1 -1
  9. data/lib/opal/cli_runners/applescript.rb +2 -0
  10. data/lib/opal/compiler.rb +18 -9
  11. data/lib/opal/nodes/call.rb +73 -28
  12. data/lib/opal/nodes/def.rb +31 -27
  13. data/lib/opal/nodes/definitions.rb +2 -0
  14. data/lib/opal/nodes/helpers.rb +4 -23
  15. data/lib/opal/nodes/if.rb +222 -0
  16. data/lib/opal/nodes/iter.rb +41 -37
  17. data/lib/opal/nodes/literal.rb +2 -2
  18. data/lib/opal/nodes/masgn.rb +15 -17
  19. data/lib/opal/nodes/node_with_args/shortcuts.rb +100 -0
  20. data/lib/opal/nodes/node_with_args.rb +1 -0
  21. data/lib/opal/nodes/top.rb +26 -10
  22. data/lib/opal/nodes.rb +0 -1
  23. data/lib/opal/parser/default_config.rb +3 -2
  24. data/lib/opal/repl.rb +1 -1
  25. data/lib/opal/rewriter.rb +13 -6
  26. data/lib/opal/rewriters/base.rb +12 -1
  27. data/lib/opal/rewriters/rubyspec/filters_rewriter.rb +1 -0
  28. data/lib/opal/version.rb +1 -1
  29. data/opal/corelib/array.rb +23 -28
  30. data/opal/corelib/binding.rb +14 -4
  31. data/opal/corelib/constants.rb +3 -3
  32. data/opal/corelib/hash.rb +2 -2
  33. data/opal/corelib/irb.rb +192 -0
  34. data/opal/corelib/math/polyfills.rb +127 -0
  35. data/opal/corelib/math.rb +14 -194
  36. data/opal/corelib/module.rb +23 -25
  37. data/opal/corelib/number.rb +63 -14
  38. data/opal/corelib/regexp.rb +2 -0
  39. data/opal/corelib/runtime.js +56 -20
  40. data/opal/corelib/string.rb +38 -59
  41. data/opal/corelib/time.rb +106 -68
  42. data/opal/opal/full.rb +0 -1
  43. data/opal/opal.rb +4 -1
  44. data/spec/filters/bugs/date.rb +0 -3
  45. data/spec/filters/bugs/datetime.rb +65 -0
  46. data/spec/filters/bugs/float.rb +0 -18
  47. data/spec/filters/bugs/hash.rb +0 -2
  48. data/spec/filters/bugs/language.rb +0 -3
  49. data/spec/filters/bugs/marshal.rb +0 -1
  50. data/spec/filters/bugs/string.rb +0 -30
  51. data/spec/filters/bugs/time.rb +18 -8
  52. data/spec/lib/cli_spec.rb +2 -2
  53. data/spec/lib/compiler_spec.rb +8 -8
  54. data/spec/lib/rewriters/base_spec.rb +1 -1
  55. data/spec/lib/rewriters/binary_operator_assignment_spec.rb +34 -59
  56. data/spec/lib/rewriters/block_to_iter_spec.rb +3 -6
  57. data/spec/lib/rewriters/dot_js_syntax_spec.rb +2 -5
  58. data/spec/lib/rewriters/for_rewriter_spec.rb +0 -1
  59. data/spec/lib/rewriters/forward_args_spec.rb +2 -3
  60. data/spec/lib/rewriters/js_reserved_words_spec.rb +2 -15
  61. data/spec/lib/rewriters/logical_operator_assignment_spec.rb +64 -89
  62. data/spec/lib/rewriters/numblocks_spec.rb +3 -5
  63. data/spec/lib/rewriters/opal_engine_check_spec.rb +2 -14
  64. data/spec/lib/rewriters/rubyspec/filters_rewriter_spec.rb +10 -2
  65. data/spec/opal/compiler/irb_spec.rb +4 -0
  66. data/spec/opal/core/language/super_spec.rb +26 -0
  67. data/spec/opal/core/regexp/assertions_spec.rb +19 -0
  68. data/spec/opal/core/string/to_proc_spec.rb +19 -0
  69. data/spec/ruby_specs +4 -0
  70. data/spec/support/rewriters_helper.rb +43 -23
  71. data/stdlib/date/date_time.rb +71 -0
  72. data/stdlib/date/formatters.rb +28 -0
  73. data/stdlib/date/infinity.rb +73 -0
  74. data/stdlib/date.rb +77 -214
  75. data/stdlib/opal/repl_js.rb +1 -1
  76. data/stdlib/{opal/replutils.rb → opal-replutils.rb} +3 -3
  77. data/stdlib/time.rb +39 -2
  78. data/stdlib/uri.rb +53 -0
  79. data/tasks/performance/asciidoctor_test.rb.erb +3 -1
  80. data/tasks/performance/optimization_status.rb +3 -2
  81. data/tasks/performance.rake +69 -35
  82. data/tasks/testing.rake +1 -0
  83. data/test/opal/test_uri.rb +35 -0
  84. data/yarn.lock +27 -5
  85. metadata +31 -18
  86. data/lib/opal/nodes/csend.rb +0 -24
  87. data/lib/opal/rewriters/explicit_writer_return.rb +0 -59
  88. data/spec/lib/rewriters/explicit_writer_return_spec.rb +0 -186
  89. data/stdlib/nodejs/irb.rb +0 -43
data/lib/opal/nodes/if.rb CHANGED
@@ -1,6 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'opal/nodes/base'
4
+ require 'opal/ast/matcher'
4
5
 
5
6
  module Opal
6
7
  module Nodes
@@ -18,6 +19,8 @@ module Opal
18
19
  else
19
20
  compile_with_ternary
20
21
  end
22
+ elsif could_become_switch?
23
+ compile_with_switch
21
24
  else
22
25
  compile_with_if
23
26
  end
@@ -158,6 +161,225 @@ module Opal
158
161
  true
159
162
  end
160
163
  end
164
+
165
+ # NOTE: all following matcher will act on case/when statements in their rewitten form:
166
+ #
167
+ # bin/opal --sexp -e'case some_value_or_expression; when 123; when 456, 789; end'
168
+ #
169
+ # s(:top,
170
+ # s(:if,
171
+ # s(:send,
172
+ # s(:int, 123), :===,
173
+ # s(:lvasgn, "$ret_or_1",
174
+ # s(:send, nil, :some_value_or_expression))), nil,
175
+ # s(:if,
176
+ # s(:if,
177
+ # s(:send,
178
+ # s(:int, 456), :===,
179
+ # s(:js_tmp, "$ret_or_1")),
180
+ # s(:true),
181
+ # s(:send,
182
+ # s(:int, 789), :===,
183
+ # s(:js_tmp, "$ret_or_1"))), nil,
184
+ # s(:nil))))
185
+ #
186
+
187
+ # Matches: `case some_value_or_expression; when 123`
188
+ # Captures: [s(:int, 123), "$ret_or_1", s(:send, nil, :some_value_or_expression))]
189
+ SWITCH_TEST_MATCH = AST::Matcher.new do
190
+ s(:send,
191
+ cap(s(%i[float int sym str true false nil], :*)),
192
+ :===,
193
+ s(:lvasgn, cap(:*), cap(:*))
194
+ )
195
+ end
196
+
197
+ # Matches: case some_value_or_expression; when 123, 456; end
198
+ # Captures: [
199
+ # s(:int, 123),
200
+ # "$ret_or_1",
201
+ # s(:send, nil, :some_value_or_expression)),
202
+ # …here we delegate to either SWITCH_BRANCH_TEST_MATCH or SWITCH_BRANCH_TEST_MATCH_CONTINUED
203
+ # ]
204
+ SWITCH_TEST_MATCH_CONTINUED = AST::Matcher.new do
205
+ s(:if,
206
+ s(:send,
207
+ cap(s(%i[float int sym str true false nil], :*)),
208
+ :===,
209
+ s(:lvasgn, cap(:*), cap(:*))
210
+ ),
211
+ s(:true),
212
+ cap(:*)
213
+ )
214
+ end
215
+
216
+ # Matches: `when 456` (from `case foo; when 123; when 456; end`)
217
+ # Captures: [s(:int, 456), "$ret_or_1"]
218
+ SWITCH_BRANCH_TEST_MATCH = AST::Matcher.new do
219
+ s(:send,
220
+ cap(s(%i[float int sym str true false nil], :*)),
221
+ :===,
222
+ s(:js_tmp, cap(:*))
223
+ )
224
+ end
225
+
226
+ # Matches: `when 456`
227
+ # Captures: [
228
+ # s(:int, 789),
229
+ # "$ret_or_1",
230
+ # …here we delegate to either SWITCH_BRANCH_TEST_MATCH or SWITCH_BRANCH_TEST_MATCH_CONTINUED
231
+ # ]
232
+ SWITCH_BRANCH_TEST_MATCH_CONTINUED = AST::Matcher.new do
233
+ s(:if,
234
+ s(:send,
235
+ cap(s(%i[float int sym str true false nil], :*)),
236
+ :===,
237
+ s(:js_tmp, cap(:*))
238
+ ),
239
+ s(:true),
240
+ cap(:*)
241
+ )
242
+ end
243
+
244
+ def could_become_switch?
245
+ return false if expects_expression?
246
+
247
+ return true if sexp.meta[:switch_child]
248
+
249
+ test_match = SWITCH_TEST_MATCH.match(test) || SWITCH_TEST_MATCH_CONTINUED.match(test)
250
+ return false unless test_match
251
+ @switch_test, @switch_variable, @switch_first_test, additional_rules = *test_match
252
+
253
+ additional_rules = handle_additional_switch_rules(additional_rules)
254
+ return false unless additional_rules # It's ok for them to be empty, but false denotes a mismatch
255
+ @switch_additional_rules = additional_rules
256
+
257
+ return false unless valid_switch_body?(true_body)
258
+
259
+ could_become_switch_branch?(false_body)
260
+ end
261
+
262
+ def handle_additional_switch_rules(additional_rules)
263
+ switch_additional_rules = []
264
+ while additional_rules
265
+ match = SWITCH_BRANCH_TEST_MATCH.match(additional_rules) || SWITCH_BRANCH_TEST_MATCH_CONTINUED.match(additional_rules)
266
+ return false unless match
267
+
268
+ switch_test, switch_variable, additional_rules = *match
269
+ return false unless switch_variable == @switch_variable
270
+
271
+ switch_additional_rules << switch_test
272
+ end
273
+ switch_additional_rules
274
+ end
275
+
276
+ def could_become_switch_branch?(body)
277
+ if !body
278
+ return true
279
+ elsif body.type != :if
280
+ if valid_switch_body?(body)
281
+ body.meta[:switch_default] = true
282
+ return true
283
+ end
284
+ return false
285
+ end
286
+
287
+ test, true_body, false_body = *body
288
+
289
+ test_match = SWITCH_BRANCH_TEST_MATCH.match(test) || SWITCH_BRANCH_TEST_MATCH_CONTINUED.match(test)
290
+ unless test_match
291
+ if valid_switch_body?(body, true)
292
+ body.meta[:switch_default] = true
293
+ return true
294
+ end
295
+ end
296
+ switch_test, switch_variable, additional_rules = *test_match
297
+
298
+ switch_additional_rules = handle_additional_switch_rules(additional_rules)
299
+ return false unless switch_additional_rules # It's ok for them to be empty, but false denotes a mismatch
300
+
301
+ return false unless switch_variable == @switch_variable
302
+
303
+ return false unless valid_switch_body?(true_body)
304
+ return false unless could_become_switch_branch?(false_body)
305
+
306
+ body.meta.merge!(switch_child: true,
307
+ switch_test: switch_test,
308
+ switch_variable: @switch_variable,
309
+ switch_additional_rules: switch_additional_rules
310
+ )
311
+
312
+ true
313
+ end
314
+
315
+ def valid_switch_body?(body, check_variable = false)
316
+ case body
317
+ when AST::Node
318
+ case body.type
319
+ when :break, :redo, :retry
320
+ false
321
+ when :iter, :while
322
+ # Don't traverse the iters or whiles!
323
+ true
324
+ else
325
+ body.children.all? { |i| valid_switch_body?(i, check_variable) }
326
+ end
327
+ when @switch_variable
328
+ # Perhaps we ended abruptly and we lack a $ret_or variable... but sometimes
329
+ # we can ignore this.
330
+ !check_variable
331
+ else
332
+ true
333
+ end
334
+ end
335
+
336
+ def compile_with_switch
337
+ if sexp.meta[:switch_child]
338
+ @switch_variable = sexp.meta[:switch_variable]
339
+ @switch_additional_rules = sexp.meta[:switch_additional_rules]
340
+ compile_switch_case(sexp.meta[:switch_test])
341
+ else
342
+ line "switch (", expr(@switch_first_test), ") {"
343
+ indent do
344
+ compile_switch_case(@switch_test)
345
+ end
346
+ line "}"
347
+ end
348
+ end
349
+
350
+ def returning?(body)
351
+ %i[return js_return next].include?(body.type) ||
352
+ (body.type == :begin && %i[return js_return next].include?(body.children.last.type))
353
+ end
354
+
355
+ def compile_switch_case(test)
356
+ line "case ", expr(test), ":"
357
+ if @switch_additional_rules
358
+ @switch_additional_rules.each do |rule|
359
+ line "case ", expr(rule), ":"
360
+ end
361
+ end
362
+ indent do
363
+ line stmt(true_body)
364
+ line "break;" if !true_body || !returning?(true_body)
365
+ end
366
+ if false_body
367
+ if false_body.meta[:switch_default]
368
+ compile_switch_default
369
+ elsif false_body.meta[:switch_child]
370
+ push stmt(false_body)
371
+ end
372
+ else
373
+ push stmt(s(:nil))
374
+ end
375
+ end
376
+
377
+ def compile_switch_default
378
+ line "default:"
379
+ indent do
380
+ line stmt(false_body)
381
+ end
382
+ end
161
383
  end
162
384
 
163
385
  class IFlipFlop < Base
@@ -8,45 +8,12 @@ module Opal
8
8
  class IterNode < NodeWithArgs
9
9
  handle :iter
10
10
 
11
- children :inline_args, :body
11
+ children :inline_args, :stmts
12
12
 
13
13
  def compile
14
14
  is_lambda! if scope.lambda_definition?
15
15
 
16
- inline_params = nil
17
-
18
- to_vars = identity = body_code = nil
19
-
20
- in_scope do
21
- identity = scope.identify!
22
-
23
- inline_params = process(inline_args)
24
-
25
- compile_arity_check
26
-
27
- body_code = stmt(returned_body)
28
-
29
- add_temp "self = #{identity}.$$s == null ? this : #{identity}.$$s" if @define_self
30
-
31
- to_vars = scope.to_vars
32
-
33
- line body_code
34
-
35
- if scope.catch_return
36
- unshift "try {\n"
37
- line '} catch ($returner) { if ($returner === Opal.returner) { return $returner.$v }'
38
- push ' throw $returner; }'
39
- end
40
- end
41
-
42
- unshift to_vars
43
-
44
- if await_encountered
45
- unshift "async function #{identity}(", inline_params, '){'
46
- else
47
- unshift "function #{identity}(", inline_params, '){'
48
- end
49
- push '}'
16
+ compile_body_or_shortcut
50
17
 
51
18
  blockopts = []
52
19
  blockopts << "$$arity: #{arity}"
@@ -83,6 +50,43 @@ module Opal
83
50
  scope.relative_access if @define_relative_access
84
51
  end
85
52
 
53
+ def compile_body
54
+ inline_params = nil
55
+
56
+ to_vars = identity = body_code = nil
57
+
58
+ in_scope do
59
+ identity = scope.identify!
60
+
61
+ inline_params = process(inline_args)
62
+
63
+ compile_arity_check
64
+
65
+ body_code = stmt(returned_body)
66
+
67
+ add_temp "self = #{identity}.$$s == null ? this : #{identity}.$$s" if @define_self
68
+
69
+ to_vars = scope.to_vars
70
+
71
+ line body_code
72
+
73
+ if scope.catch_return
74
+ unshift "try {\n"
75
+ line '} catch ($returner) { if ($returner === Opal.returner) { return $returner.$v }'
76
+ push ' throw $returner; }'
77
+ end
78
+ end
79
+
80
+ unshift to_vars
81
+
82
+ if await_encountered
83
+ unshift "async function #{identity}(", inline_params, '){'
84
+ else
85
+ unshift "function #{identity}(", inline_params, '){'
86
+ end
87
+ push '}'
88
+ end
89
+
86
90
  def compile_block_arg
87
91
  if block_arg
88
92
  scope.prepare_block
@@ -108,13 +112,13 @@ module Opal
108
112
  @sexp = @sexp.updated(
109
113
  nil, [
110
114
  args.updated(nil, valid_args),
111
- body
115
+ stmts
112
116
  ]
113
117
  )
114
118
  end
115
119
 
116
120
  def returned_body
117
- compiler.returns(body || s(:nil))
121
+ compiler.returns(stmts || s(:nil))
118
122
  end
119
123
 
120
124
  def has_top_level_mlhs_arg?
@@ -326,7 +326,7 @@ module Opal
326
326
  children :value
327
327
 
328
328
  def compile
329
- push "Opal.Rational.$new(#{value.numerator}, #{value.denominator})"
329
+ push "#{top_scope.absolute_const}('Rational').$new(#{value.numerator}, #{value.denominator})"
330
330
  end
331
331
  end
332
332
 
@@ -338,7 +338,7 @@ module Opal
338
338
  children :value
339
339
 
340
340
  def compile
341
- push "Opal.Complex.$new(#{value.real}, #{value.imag})"
341
+ push "#{top_scope.absolute_const}('Complex').$new(#{value.real}, #{value.imag})"
342
342
  end
343
343
  end
344
344
  end
@@ -11,24 +11,22 @@ module Opal
11
11
  children :lhs, :rhs
12
12
 
13
13
  def compile
14
- array = scope.new_temp
15
-
16
- if rhs.type == :array
17
- push "#{array} = ", expr(rhs)
18
- rhs_len = rhs.children.any? { |c| c.type == :splat } ? nil : rhs.children.size
19
- compile_masgn(lhs.children, array, rhs_len)
20
- push ", #{array}" # a mass assignment evaluates to the RHS
21
- else
22
- helper :to_ary
23
- retval = scope.new_temp
24
- push "#{retval} = ", expr(rhs)
25
- push ", #{array} = $to_ary(#{retval})"
26
- compile_masgn(lhs.children, array)
27
- push ", #{retval}"
28
- scope.queue_temp(retval)
14
+ with_temp do |array|
15
+ if rhs.type == :array
16
+ push "#{array} = ", expr(rhs)
17
+ rhs_len = rhs.children.any? { |c| c.type == :splat } ? nil : rhs.children.size
18
+ compile_masgn(lhs.children, array, rhs_len)
19
+ push ", #{array}" # a mass assignment evaluates to the RHS
20
+ else
21
+ helper :to_ary
22
+ with_temp do |retval|
23
+ push "#{retval} = ", expr(rhs)
24
+ push ", #{array} = $to_ary(#{retval})"
25
+ compile_masgn(lhs.children, array)
26
+ push ", #{retval}"
27
+ end
28
+ end
29
29
  end
30
-
31
- scope.queue_temp(array)
32
30
  end
33
31
 
34
32
  # 'len' is how many rhs items are we sure we have
@@ -0,0 +1,100 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Opal
4
+ module Nodes
5
+ class NodeWithArgs < ScopeNode
6
+ # Shortcuts for the simplest kinds of methods
7
+ Shortcut = Struct.new(:name, :for, :when, :transform) do
8
+ def match?(node)
9
+ node.instance_exec(&self.when)
10
+ end
11
+
12
+ def compile(node)
13
+ node.helper name
14
+ node.instance_exec(&transform)
15
+ end
16
+ end
17
+
18
+ @shortcuts = []
19
+ @shortcuts_for = {}
20
+ def self.define_shortcut(name, **kwargs, &block)
21
+ kwargs[:for] ||= :def
22
+ @shortcuts << Shortcut.new(name, kwargs[:for], kwargs[:when], block)
23
+ end
24
+
25
+ def self.shortcuts_for(node_type)
26
+ @shortcuts_for[node_type] ||=
27
+ @shortcuts.select do |shortcut|
28
+ [node_type, :*].include? shortcut.for
29
+ end
30
+ end
31
+
32
+ def compile_body_or_shortcut
33
+ # The shortcuts don't check arity. If we want to check arity,
34
+ # we can't use them.
35
+ return compile_body if compiler.arity_check?
36
+
37
+ node_type = is_a?(DefNode) ? :def : :iter
38
+
39
+ NodeWithArgs.shortcuts_for(node_type).each do |shortcut|
40
+ if shortcut.match?(self)
41
+ if ENV['OPAL_DEBUG_SHORTCUTS']
42
+ node_desc = node_type == :def ? "def #{mid}" : "iter"
43
+ warn "* shortcut #{shortcut.name} used for #{node_desc}"
44
+ end
45
+
46
+ return shortcut.compile(self)
47
+ end
48
+ end
49
+
50
+ compile_body
51
+ end
52
+
53
+ # Shortcut definitions
54
+ # --------------------
55
+
56
+ # def a; self; end
57
+ define_shortcut :return_self, when: -> { stmts.type == :self } do
58
+ push '$return_self'
59
+ end
60
+
61
+ def simple_value?(node = stmts)
62
+ %i[true false nil int float str sym].include?(node.type)
63
+ end
64
+
65
+ # def a; 123; end
66
+ define_shortcut :return_val, for: :*, when: -> { simple_value? } do
67
+ push '$return_val(', expr(stmts), ')'
68
+ end
69
+
70
+ # def a; @x; end
71
+ define_shortcut :return_ivar, when: -> { stmts.type == :ivar } do
72
+ name = stmts.children.first.to_s[1..-1].to_sym
73
+ push '$return_ivar(', expr(stmts.updated(:sym, [name])), ')'
74
+ end
75
+
76
+ # def a; @x = 5; end
77
+ define_shortcut :assign_ivar, when: -> {
78
+ stmts.type == :ivasgn &&
79
+ inline_args.children.length == 1 &&
80
+ inline_args.children.last.type == :arg &&
81
+ stmts.children.last.type == :lvar &&
82
+ stmts.children.last.children.last == inline_args.children.last.children.last
83
+ } do
84
+ name = stmts.children.first.to_s[1..-1].to_sym
85
+ name = expr(stmts.updated(:sym, [name]))
86
+ push '$assign_ivar(', name, ')'
87
+ end
88
+
89
+ # def a(x); @x = x; end
90
+ define_shortcut :assign_ivar_val, when: -> {
91
+ stmts.type == :ivasgn &&
92
+ simple_value?(stmts.children.last)
93
+ } do
94
+ name = stmts.children.first.to_s[1..-1].to_sym
95
+ name = expr(stmts.updated(:sym, [name]))
96
+ push '$assign_ivar_val(', name, ', ', expr(stmts.children.last), ')'
97
+ end
98
+ end
99
+ end
100
+ end
@@ -2,6 +2,7 @@
2
2
 
3
3
  require 'opal/nodes/scope'
4
4
  require 'opal/nodes/args/parameters'
5
+ require 'opal/nodes/node_with_args/shortcuts'
5
6
 
6
7
  module Opal
7
8
  module Nodes
@@ -14,14 +14,22 @@ module Opal
14
14
 
15
15
  def compile
16
16
  compiler.top_scope = self
17
+ compiler.dynamic_cache_result = true if sexp.meta[:dynamic_cache_result]
17
18
 
18
19
  push version_comment
19
20
 
20
- in_scope do
21
- if body == s(:nil)
22
- # A shortpath for empty (stub?) modules.
23
- line 'return Opal.nil;'
21
+ helper :return_val if compiler.eof_content
22
+
23
+ if body == s(:nil)
24
+ # A shortpath for empty (stub?) modules.
25
+ if compiler.requirable? || compiler.esm? || compiler.eval?
26
+ unshift 'Opal.return_val(Opal.nil); '
27
+ definition
24
28
  else
29
+ unshift 'Opal.nil; '
30
+ end
31
+ else
32
+ in_scope do
25
33
  line '"use strict";' if compiler.use_strict?
26
34
 
27
35
  body_code = stmt(stmts)
@@ -47,20 +55,28 @@ module Opal
47
55
 
48
56
  line body_code
49
57
  end
58
+
59
+ opening
60
+ definition
61
+ closing
62
+ end
63
+ end
64
+
65
+ def definition
66
+ if compiler.requirable?
67
+ unshift "Opal.modules[#{Opal::Compiler.module_name(compiler.file).inspect}] = "
68
+ elsif compiler.esm?
69
+ unshift 'export default '
50
70
  end
51
- opening
52
- closing
53
71
  end
54
72
 
55
73
  def opening
56
74
  async_prefix = "async " if await_encountered
57
75
 
58
76
  if compiler.requirable?
59
- unshift "Opal.modules[#{Opal::Compiler.module_name(compiler.file).inspect}] = #{async_prefix}function(Opal) {"
77
+ unshift "#{async_prefix}function(Opal) {"
60
78
  elsif compiler.eval?
61
79
  unshift "(#{async_prefix}function(Opal, self) {"
62
- elsif compiler.esm?
63
- unshift "export default Opal.queue(#{async_prefix}function(Opal) {"
64
80
  else
65
81
  unshift "Opal.queue(#{async_prefix}function(Opal) {"
66
82
  end
@@ -108,7 +124,7 @@ module Opal
108
124
  def compile_end_construct
109
125
  if content = compiler.eof_content
110
126
  line 'var $__END__ = Opal.Object.$new();'
111
- line "$__END__.$read = function() { return #{content.inspect}; };"
127
+ line "$__END__.$read = $return_val(#{content.inspect});"
112
128
  end
113
129
  end
114
130
 
data/lib/opal/nodes.rb CHANGED
@@ -5,7 +5,6 @@ require 'opal/nodes/literal'
5
5
  require 'opal/nodes/variables'
6
6
  require 'opal/nodes/constants'
7
7
  require 'opal/nodes/call'
8
- require 'opal/nodes/csend'
9
8
  require 'opal/nodes/call_special'
10
9
  require 'opal/nodes/module'
11
10
  require 'opal/nodes/class'
@@ -29,8 +29,9 @@ module Opal
29
29
  end
30
30
 
31
31
  def parse(source_buffer)
32
- parsed = super
33
- rewriten = rewrite(parsed)
32
+ parsed = super || ::Opal::AST::Node.new(:nil)
33
+ wrapped = ::Opal::AST::Node.new(:top, [parsed])
34
+ rewriten = rewrite(wrapped)
34
35
  rewriten
35
36
  end
36
37
 
data/lib/opal/repl.rb CHANGED
@@ -164,7 +164,7 @@ module Opal
164
164
  load_opal
165
165
  raise e
166
166
  rescue EOFError, Errno::EPIPE
167
- exit $?.exitstatus
167
+ exit $?.nil? ? 0 : $?.exitstatus
168
168
  end
169
169
 
170
170
  def readline
data/lib/opal/rewriter.rb CHANGED
@@ -2,7 +2,6 @@
2
2
 
3
3
  require 'opal/rewriters/opal_engine_check'
4
4
  require 'opal/rewriters/for_rewriter'
5
- require 'opal/rewriters/explicit_writer_return'
6
5
  require 'opal/rewriters/js_reserved_words'
7
6
  require 'opal/rewriters/block_to_iter'
8
7
  require 'opal/rewriters/dot_js_syntax'
@@ -19,6 +18,8 @@ require 'opal/rewriters/forward_args'
19
18
 
20
19
  module Opal
21
20
  class Rewriter
21
+ @disabled = false
22
+
22
23
  class << self
23
24
  def list
24
25
  @list ||= []
@@ -32,15 +33,21 @@ module Opal
32
33
  list.delete(rewriter)
33
34
  end
34
35
 
35
- def disable
36
- @disabled = true
36
+ def disable(except: nil)
37
+ old_disabled = @disabled
38
+ @disabled = except || true
37
39
  yield
38
40
  ensure
39
- @disabled = false
41
+ @disabled = old_disabled
40
42
  end
41
43
 
42
44
  def disabled?
43
- @disabled if defined?(@disabled)
45
+ @disabled == true
46
+ end
47
+
48
+ def rewritter_disabled?(rewriter)
49
+ return false if @disabled == false
50
+ @disabled != rewriter
44
51
  end
45
52
  end
46
53
 
@@ -54,7 +61,6 @@ module Opal
54
61
  use Rewriters::JsReservedWords
55
62
  use Rewriters::LogicalOperatorAssignment
56
63
  use Rewriters::BinaryOperatorAssignment
57
- use Rewriters::ExplicitWriterReturn
58
64
  use Rewriters::Hashes::KeyDuplicatesRewriter
59
65
  use Rewriters::ReturnableLogic
60
66
  use Rewriters::DumpArgs
@@ -69,6 +75,7 @@ module Opal
69
75
  return @sexp if self.class.disabled?
70
76
 
71
77
  self.class.list.each do |rewriter_class|
78
+ next if self.class.rewritter_disabled?(rewriter_class)
72
79
  rewriter = rewriter_class.new
73
80
  @sexp = rewriter.process(@sexp)
74
81
  end