opal 1.4.0.alpha1 → 1.5.0.rc1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (95) hide show
  1. checksums.yaml +4 -4
  2. data/.eslintrc.js +5 -3
  3. data/.github/workflows/build.yml +20 -18
  4. data/.rubocop.yml +1 -0
  5. data/CHANGELOG.md +98 -7
  6. data/UNRELEASED.md +31 -59
  7. data/benchmark-ips/bm_js_symbols_vs_strings.rb +39 -14
  8. data/docs/releasing.md +11 -4
  9. data/lib/opal/ast/matcher.rb +77 -0
  10. data/lib/opal/cache.rb +1 -1
  11. data/lib/opal/cli_runners/applescript.rb +2 -0
  12. data/lib/opal/compiler.rb +18 -9
  13. data/lib/opal/nodes/call.rb +73 -28
  14. data/lib/opal/nodes/def.rb +31 -27
  15. data/lib/opal/nodes/definitions.rb +2 -0
  16. data/lib/opal/nodes/helpers.rb +4 -23
  17. data/lib/opal/nodes/if.rb +226 -0
  18. data/lib/opal/nodes/iter.rb +41 -37
  19. data/lib/opal/nodes/literal.rb +2 -2
  20. data/lib/opal/nodes/masgn.rb +15 -17
  21. data/lib/opal/nodes/node_with_args/shortcuts.rb +100 -0
  22. data/lib/opal/nodes/node_with_args.rb +1 -0
  23. data/lib/opal/nodes/super.rb +9 -9
  24. data/lib/opal/nodes/top.rb +26 -10
  25. data/lib/opal/nodes/x_string.rb +27 -28
  26. data/lib/opal/nodes.rb +0 -1
  27. data/lib/opal/parser/default_config.rb +3 -2
  28. data/lib/opal/repl.rb +1 -1
  29. data/lib/opal/rewriter.rb +13 -6
  30. data/lib/opal/rewriters/base.rb +12 -1
  31. data/lib/opal/rewriters/rubyspec/filters_rewriter.rb +1 -0
  32. data/lib/opal/version.rb +1 -1
  33. data/opal/corelib/array.rb +23 -28
  34. data/opal/corelib/binding.rb +14 -4
  35. data/opal/corelib/constants.rb +3 -3
  36. data/opal/corelib/hash.rb +2 -2
  37. data/opal/corelib/irb.rb +192 -0
  38. data/opal/corelib/math/polyfills.rb +127 -0
  39. data/opal/corelib/math.rb +14 -194
  40. data/opal/corelib/module.rb +25 -40
  41. data/opal/corelib/number.rb +63 -14
  42. data/opal/corelib/regexp.rb +2 -0
  43. data/opal/corelib/runtime.js +56 -20
  44. data/opal/corelib/string.rb +38 -59
  45. data/opal/corelib/time.rb +106 -68
  46. data/opal/opal/full.rb +0 -1
  47. data/opal/opal.rb +4 -1
  48. data/spec/filters/bugs/date.rb +0 -3
  49. data/spec/filters/bugs/datetime.rb +65 -0
  50. data/spec/filters/bugs/float.rb +0 -18
  51. data/spec/filters/bugs/hash.rb +0 -2
  52. data/spec/filters/bugs/language.rb +0 -3
  53. data/spec/filters/bugs/marshal.rb +0 -1
  54. data/spec/filters/bugs/string.rb +0 -30
  55. data/spec/filters/bugs/time.rb +18 -8
  56. data/spec/lib/cli_spec.rb +2 -2
  57. data/spec/lib/compiler_spec.rb +8 -8
  58. data/spec/lib/rewriters/base_spec.rb +1 -1
  59. data/spec/lib/rewriters/binary_operator_assignment_spec.rb +34 -59
  60. data/spec/lib/rewriters/block_to_iter_spec.rb +3 -6
  61. data/spec/lib/rewriters/dot_js_syntax_spec.rb +2 -5
  62. data/spec/lib/rewriters/for_rewriter_spec.rb +0 -1
  63. data/spec/lib/rewriters/forward_args_spec.rb +2 -3
  64. data/spec/lib/rewriters/js_reserved_words_spec.rb +2 -15
  65. data/spec/lib/rewriters/logical_operator_assignment_spec.rb +64 -89
  66. data/spec/lib/rewriters/numblocks_spec.rb +3 -5
  67. data/spec/lib/rewriters/opal_engine_check_spec.rb +2 -14
  68. data/spec/lib/rewriters/rubyspec/filters_rewriter_spec.rb +10 -2
  69. data/spec/opal/compiler/irb_spec.rb +4 -0
  70. data/spec/opal/core/language/super_spec.rb +40 -17
  71. data/spec/opal/core/language/xstring_spec.rb +13 -0
  72. data/spec/opal/core/regexp/assertions_spec.rb +19 -0
  73. data/spec/opal/core/string/to_proc_spec.rb +19 -0
  74. data/spec/ruby_specs +4 -0
  75. data/spec/support/rewriters_helper.rb +43 -23
  76. data/stdlib/date/date_time.rb +71 -0
  77. data/stdlib/date/formatters.rb +28 -0
  78. data/stdlib/date/infinity.rb +73 -0
  79. data/stdlib/date.rb +77 -214
  80. data/stdlib/opal/repl_js.rb +1 -1
  81. data/stdlib/{opal/replutils.rb → opal-replutils.rb} +3 -3
  82. data/stdlib/promise/v2.rb +0 -7
  83. data/stdlib/time.rb +39 -2
  84. data/stdlib/uri.rb +53 -0
  85. data/tasks/performance/asciidoctor_test.rb.erb +3 -1
  86. data/tasks/performance/optimization_status.rb +3 -2
  87. data/tasks/performance.rake +69 -35
  88. data/tasks/testing.rake +1 -0
  89. data/test/opal/test_uri.rb +35 -0
  90. data/yarn.lock +27 -5
  91. metadata +30 -16
  92. data/lib/opal/nodes/csend.rb +0 -24
  93. data/lib/opal/rewriters/explicit_writer_return.rb +0 -59
  94. data/spec/lib/rewriters/explicit_writer_return_spec.rb +0 -186
  95. data/stdlib/nodejs/irb.rb +0 -43
@@ -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
@@ -179,28 +179,28 @@ module Opal
179
179
  same_arg_counter = Hash.new(0)
180
180
 
181
181
  def_scope.original_args.children.each do |sexp|
182
- arg_name = sexp.meta[:arg_name]
182
+ lvar_name = sexp.children[0]
183
183
 
184
184
  case sexp.type
185
185
  when :arg, :optarg
186
- arg_node = s(:lvar, arg_name)
186
+ arg_node = s(:lvar, lvar_name)
187
187
  # def m(_, _)
188
188
  # is compiled to
189
189
  # function $$m(_, __$2)
190
190
  # See Opal::Node::ArgsNode
191
- if arg_name[0] == '_'
192
- same_arg_counter[arg_name] += 1
193
- arg_node = s(:js_tmp, "#{arg_name}_$#{same_arg_counter[arg_name]}") if same_arg_counter[arg_name] > 1
191
+ if lvar_name[0] == '_'
192
+ same_arg_counter[lvar_name] += 1
193
+ arg_node = s(:js_tmp, "#{lvar_name}_$#{same_arg_counter[lvar_name]}") if same_arg_counter[lvar_name] > 1
194
194
  end
195
-
196
195
  args << arg_node
197
196
  when :restarg
198
- arg_node = arg_name ? s(:lvar, arg_name) : s(:js_tmp, '$rest_arg')
197
+ arg_node = lvar_name ? s(:lvar, lvar_name) : s(:js_tmp, '$rest_arg')
199
198
  args << s(:splat, arg_node)
200
199
  when :kwarg, :kwoptarg
201
- kwargs << s(:pair, s(:sym, arg_name), s(:lvar, arg_name))
200
+ key_name = sexp.meta[:arg_name]
201
+ kwargs << s(:pair, s(:sym, key_name), s(:lvar, lvar_name))
202
202
  when :kwrestarg
203
- arg_node = arg_name ? s(:lvar, arg_name) : s(:js_tmp, '$kw_rest_arg')
203
+ arg_node = lvar_name ? s(:lvar, lvar_name) : s(:js_tmp, '$kw_rest_arg')
204
204
  kwargs << s(:kwsplat, arg_node)
205
205
  end
206
206
  end
@@ -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
 
@@ -8,9 +8,9 @@ module Opal
8
8
  def compile
9
9
  @should_add_semicolon = false
10
10
  unpacked_children = unpack_return(children)
11
- stripped_children = strip_empty_children(unpacked_children)
11
+ stripped_children = XStringNode.strip_empty_children(unpacked_children)
12
12
 
13
- if single_line?(stripped_children)
13
+ if XStringNode.single_line?(stripped_children)
14
14
  # If it's a single line we'll try to:
15
15
  #
16
16
  # - strip empty lines
@@ -30,6 +30,31 @@ module Opal
30
30
  push ';' if @should_add_semicolon
31
31
  end
32
32
 
33
+ # Check if there's only one child or if they're all part of
34
+ # the same line (e.g. because of interpolations)
35
+ def self.single_line?(children)
36
+ (children.size == 1) || children.none? do |c|
37
+ c.type == :str && c.loc.expression.source.end_with?("\n")
38
+ end
39
+ end
40
+
41
+ # Will remove empty :str lines coming from cosmetic newlines in x-strings
42
+ #
43
+ # @example
44
+ # # this will generate two additional empty
45
+ # # children before and after `foo()`
46
+ # %x{
47
+ # foo()
48
+ # }
49
+ def self.strip_empty_children(children)
50
+ children = children.dup
51
+ empty_line = ->(child) { child.nil? || (child.type == :str && child.loc.expression.source.rstrip.empty?) }
52
+
53
+ children.shift while children.any? && empty_line[children.first]
54
+ children.pop while children.any? && empty_line[children.last]
55
+
56
+ children
57
+ end
33
58
 
34
59
  private
35
60
 
@@ -97,14 +122,6 @@ module Opal
97
122
  last_value
98
123
  end
99
124
 
100
- # Check if there's only one child or if they're all part of
101
- # the same line (e.g. because of interpolations)
102
- def single_line?(children)
103
- (children.size == 1) || children.none? do |c|
104
- c.type == :str && c.loc.expression.source.end_with?("\n")
105
- end
106
- end
107
-
108
125
  # A case for manually created :js_return statement in Compiler#returns
109
126
  # Since we need to take original source of :str we have to use raw source
110
127
  # so we need to combine "return" with "raw_source"
@@ -119,24 +136,6 @@ module Opal
119
136
 
120
137
  children
121
138
  end
122
-
123
- # Will remove empty :str lines coming from cosmetic newlines in x-strings
124
- #
125
- # @example
126
- # # this will generate two additional empty
127
- # # children before and after `foo()`
128
- # %x{
129
- # foo()
130
- # }
131
- def strip_empty_children(children)
132
- children = children.dup
133
- empty_line = ->(child) { child.nil? || (child.type == :str && child.loc.expression.source.rstrip.empty?) }
134
-
135
- children.shift while children.any? && empty_line[children.first]
136
- children.pop while children.any? && empty_line[children.last]
137
-
138
- children
139
- end
140
139
  end
141
140
  end
142
141
  end
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
@@ -51,7 +51,6 @@ module Opal
51
51
  end
52
52
 
53
53
  alias on_iter process_regular_node
54
- alias on_top process_regular_node
55
54
  alias on_zsuper process_regular_node
56
55
  alias on_jscall on_send
57
56
  alias on_jsattr process_regular_node
@@ -124,6 +123,18 @@ module Opal
124
123
  error.location = current_node.loc if current_node
125
124
  raise error
126
125
  end
126
+
127
+ def on_top(node)
128
+ node = process_regular_node(node)
129
+ node.meta[:dynamic_cache_result] = true if @dynamic_cache_result
130
+ node
131
+ end
132
+
133
+ # Called when a given transformation is deemed to be dynamic, so
134
+ # that cache is conditionally disabled for a given file.
135
+ def dynamic!
136
+ @dynamic_cache_result = true
137
+ end
127
138
  end
128
139
  end
129
140
  end
@@ -36,6 +36,7 @@ module Opal
36
36
  _recvr, method_name, *args = *node
37
37
 
38
38
  if rubyspec_dsl?(method_name)
39
+ dynamic!
39
40
  spec_name, _ = *args.first
40
41
  begin
41
42
  @specs_stack.push(spec_name)
data/lib/opal/version.rb CHANGED
@@ -3,5 +3,5 @@
3
3
  module Opal
4
4
  # WHEN RELEASING:
5
5
  # Remember to update RUBY_ENGINE_VERSION in opal/corelib/constants.rb too!
6
- VERSION = '1.4.0.alpha1'
6
+ VERSION = '1.5.0.rc1'
7
7
  end
@@ -441,20 +441,18 @@ class ::Array < `Array`
441
441
  end
442
442
 
443
443
  def []=(index, value, extra = undefined)
444
+ data = nil
444
445
  %x{
445
446
  var i, size = self.length;
446
- }
447
447
 
448
- if ::Range === index
449
- data = if ::Array === value
450
- value.to_a
451
- elsif value.respond_to? :to_ary
452
- value.to_ary.to_a
453
- else
454
- [value]
455
- end
448
+ if (index.$$is_range) {
449
+ if (value.$$is_array)
450
+ data = #{value.to_a};
451
+ else if (#{value.respond_to? :to_ary})
452
+ data = #{value.to_ary.to_a};
453
+ else
454
+ data = [value];
456
455
 
457
- %x{
458
456
  var exclude = index.excl,
459
457
  from = index.begin === nil ? 0 : $coerce_to(index.begin, Opal.Integer, 'to_int'),
460
458
  to = index.end === nil ? -1 : $coerce_to(index.end, Opal.Integer, 'to_int');
@@ -489,24 +487,21 @@ class ::Array < `Array`
489
487
  }
490
488
 
491
489
  return value;
492
- }
493
- else
494
- if `extra === undefined`
495
- length = 1
496
- else
497
- length = value
498
- value = extra
499
-
500
- data = if ::Array === value
501
- value.to_a
502
- elsif value.respond_to? :to_ary
503
- value.to_ary.to_a
504
- else
505
- [value]
506
- end
507
- end
490
+ } else {
491
+ if (extra === undefined) {
492
+ #{length = 1}
493
+ } else {
494
+ length = value;
495
+ value = extra;
496
+
497
+ if (value.$$is_array)
498
+ data = #{value.to_a};
499
+ else if (#{value.respond_to? :to_ary})
500
+ data = #{value.to_ary.to_a};
501
+ else
502
+ data = [value];
503
+ }
508
504
 
509
- %x{
510
505
  var old;
511
506
 
512
507
  index = $coerce_to(index, #{::Integer}, 'to_int');
@@ -540,7 +535,7 @@ class ::Array < `Array`
540
535
 
541
536
  return value;
542
537
  }
543
- end
538
+ }
544
539
  end
545
540
 
546
541
  def any?(pattern = undefined, &block)
@@ -1,8 +1,9 @@
1
1
  class ::Binding
2
2
  # @private
3
- def initialize(jseval, scope_variables, receiver, source_location)
3
+ def initialize(jseval, scope_variables = [], receiver = undefined, source_location = nil)
4
4
  @jseval, @scope_variables, @receiver, @source_location = \
5
5
  jseval, scope_variables, receiver, source_location
6
+ receiver = js_eval('self') unless `typeof receiver !== undefined`
6
7
  end
7
8
 
8
9
  def js_eval(*args)
@@ -20,7 +21,10 @@ class ::Binding
20
21
  end
21
22
 
22
23
  def local_variable_set(symbol, value)
23
- js_eval(symbol, value)
24
+ `Opal.Binding.tmp_value = value`
25
+ js_eval("#{symbol} = Opal.Binding.tmp_value")
26
+ `delete Opal.Binding.tmp_value`
27
+ value
24
28
  end
25
29
 
26
30
  def local_variables
@@ -46,5 +50,11 @@ module ::Kernel
46
50
  end
47
51
  end
48
52
 
49
- TOPLEVEL_BINDING = binding
50
- `#{TOPLEVEL_BINDING}.source_location = ["<main>", 0]`
53
+ TOPLEVEL_BINDING = ::Binding.new(
54
+ %x{
55
+ function(js) {
56
+ return (new Function("self", "return " + js))(self);
57
+ }
58
+ },
59
+ [], self, ['<main>', 0]
60
+ )
@@ -1,9 +1,9 @@
1
1
  ::RUBY_PLATFORM = 'opal'
2
2
  ::RUBY_ENGINE = 'opal'
3
3
  ::RUBY_VERSION = '3.1.0'
4
- ::RUBY_ENGINE_VERSION = '1.4.0.alpha1'
5
- ::RUBY_RELEASE_DATE = '2021-12-21'
4
+ ::RUBY_ENGINE_VERSION = '1.5.0.rc1'
5
+ ::RUBY_RELEASE_DATE = '2022-04-06'
6
6
  ::RUBY_PATCHLEVEL = 0
7
7
  ::RUBY_REVISION = '0'
8
- ::RUBY_COPYRIGHT = 'opal - Copyright (C) 2013-2021 Adam Beynon and the Opal contributors'
8
+ ::RUBY_COPYRIGHT = 'opal - Copyright (C) 2013-2022 Adam Beynon and the Opal contributors'
9
9
  ::RUBY_DESCRIPTION = "opal #{::RUBY_ENGINE_VERSION} (#{::RUBY_RELEASE_DATE} revision #{::RUBY_REVISION})"
data/opal/corelib/hash.rb CHANGED
@@ -423,7 +423,7 @@ class ::Hash
423
423
  return enum_for(:each) { size } unless block
424
424
 
425
425
  %x{
426
- for (var i = 0, keys = self.$$keys, length = keys.length, key, value; i < length; i++) {
426
+ for (var i = 0, keys = self.$$keys.slice(), length = keys.length, key, value; i < length; i++) {
427
427
  key = keys[i];
428
428
 
429
429
  if (key.$$is_string) {
@@ -444,7 +444,7 @@ class ::Hash
444
444
  return enum_for(:each_key) { size } unless block
445
445
 
446
446
  %x{
447
- for (var i = 0, keys = self.$$keys, length = keys.length, key; i < length; i++) {
447
+ for (var i = 0, keys = self.$$keys.slice(), length = keys.length, key; i < length; i++) {
448
448
  key = keys[i];
449
449
 
450
450
  block(key.$$is_string ? key : key.key);