opal 1.7.2 → 1.8.0.alpha1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (216) hide show
  1. checksums.yaml +4 -4
  2. data/.eslintrc.js +1 -0
  3. data/.github/workflows/build.yml +9 -9
  4. data/.rubocop/todo.yml +2 -2
  5. data/.rubocop.yml +17 -10
  6. data/.rubocop_todo.yml +311 -0
  7. data/CHANGELOG.md +16 -2
  8. data/UNRELEASED.md +78 -1
  9. data/benchmark-ips/bm_block_vs_yield.rb +3 -0
  10. data/benchmark-ips/bm_slice_or_not.rb +53 -0
  11. data/docs/bridging.md +112 -0
  12. data/docs/compiled_ruby.md +10 -10
  13. data/docs/getting_started.md +18 -22
  14. data/docs/index.md +1 -1
  15. data/lib/opal/builder_scheduler/prefork.rb +2 -2
  16. data/lib/opal/cache/file_cache.rb +7 -10
  17. data/lib/opal/cli_runners/chrome_cdp_interface.rb +5 -2
  18. data/lib/opal/cli_runners/firefox_cdp_interface.rb +5 -2
  19. data/lib/opal/compiler.rb +33 -1
  20. data/lib/opal/nodes/args/extract_kwoptarg.rb +2 -1
  21. data/lib/opal/nodes/call.rb +1 -1
  22. data/lib/opal/nodes/call_special.rb +71 -47
  23. data/lib/opal/nodes/hash.rb +14 -30
  24. data/lib/opal/nodes/if.rb +38 -30
  25. data/lib/opal/nodes/literal.rb +5 -1
  26. data/lib/opal/nodes/x_string.rb +13 -0
  27. data/lib/opal/parser/patch.rb +7 -0
  28. data/lib/opal/rewriters/for_rewriter.rb +36 -24
  29. data/lib/opal/source_map/file.rb +1 -1
  30. data/lib/opal/version.rb +1 -1
  31. data/opal/corelib/array/pack.rb +1 -0
  32. data/opal/corelib/array.rb +75 -47
  33. data/opal/corelib/basic_object.rb +1 -0
  34. data/opal/corelib/binding.rb +2 -0
  35. data/opal/corelib/boolean.rb +1 -0
  36. data/opal/corelib/class.rb +2 -0
  37. data/opal/corelib/comparable.rb +1 -0
  38. data/opal/corelib/complex.rb +2 -0
  39. data/opal/corelib/constants.rb +2 -2
  40. data/opal/corelib/dir.rb +2 -0
  41. data/opal/corelib/enumerable.rb +3 -2
  42. data/opal/corelib/enumerator/arithmetic_sequence.rb +2 -0
  43. data/opal/corelib/enumerator/chain.rb +1 -0
  44. data/opal/corelib/enumerator/generator.rb +1 -0
  45. data/opal/corelib/enumerator/lazy.rb +1 -0
  46. data/opal/corelib/enumerator/yielder.rb +2 -0
  47. data/opal/corelib/enumerator.rb +1 -0
  48. data/opal/corelib/error/errno.rb +2 -0
  49. data/opal/corelib/error.rb +12 -0
  50. data/opal/corelib/file.rb +1 -0
  51. data/opal/corelib/hash.rb +197 -504
  52. data/opal/corelib/helpers.rb +1 -0
  53. data/opal/corelib/io.rb +2 -0
  54. data/opal/corelib/irb.rb +2 -0
  55. data/opal/corelib/kernel/format.rb +1 -0
  56. data/opal/corelib/kernel.rb +70 -14
  57. data/opal/corelib/main.rb +2 -0
  58. data/opal/corelib/marshal/read_buffer.rb +2 -0
  59. data/opal/corelib/marshal/write_buffer.rb +2 -0
  60. data/opal/corelib/math/polyfills.rb +2 -0
  61. data/opal/corelib/math.rb +1 -0
  62. data/opal/corelib/method.rb +2 -0
  63. data/opal/corelib/module.rb +1 -0
  64. data/opal/corelib/nil.rb +3 -1
  65. data/opal/corelib/number.rb +2 -0
  66. data/opal/corelib/numeric.rb +2 -0
  67. data/opal/corelib/object_space.rb +1 -0
  68. data/opal/corelib/pack_unpack/format_string_parser.rb +2 -0
  69. data/opal/corelib/proc.rb +30 -28
  70. data/opal/corelib/process.rb +2 -0
  71. data/opal/corelib/random/formatter.rb +2 -0
  72. data/opal/corelib/random/math_random.js.rb +2 -0
  73. data/opal/corelib/random/mersenne_twister.rb +2 -0
  74. data/opal/corelib/random/seedrandom.js.rb +2 -0
  75. data/opal/corelib/random.rb +1 -0
  76. data/opal/corelib/range.rb +34 -12
  77. data/opal/corelib/rational.rb +2 -0
  78. data/opal/corelib/regexp.rb +5 -1
  79. data/opal/corelib/runtime.js +188 -224
  80. data/opal/corelib/set.rb +2 -0
  81. data/opal/corelib/string/encoding.rb +3 -0
  82. data/opal/corelib/string/unpack.rb +2 -0
  83. data/opal/corelib/string.rb +20 -12
  84. data/opal/corelib/struct.rb +3 -1
  85. data/opal/corelib/time.rb +1 -0
  86. data/opal/corelib/trace_point.rb +2 -0
  87. data/opal/corelib/unsupported.rb +2 -0
  88. data/opal/corelib/variables.rb +2 -0
  89. data/opal.gemspec +2 -2
  90. data/spec/filters/bugs/array.rb +0 -3
  91. data/spec/filters/bugs/enumerable.rb +0 -3
  92. data/spec/filters/bugs/hash.rb +0 -13
  93. data/spec/filters/bugs/integer.rb +0 -1
  94. data/spec/filters/bugs/kernel.rb +0 -39
  95. data/spec/filters/bugs/language.rb +0 -3
  96. data/spec/filters/bugs/range.rb +0 -1
  97. data/spec/filters/bugs/ruby-32.rb +0 -2
  98. data/spec/filters/bugs/string.rb +0 -1
  99. data/spec/filters/bugs/struct.rb +1 -5
  100. data/spec/filters/unsupported/hash.rb +1 -0
  101. data/spec/lib/compiler_spec.rb +24 -17
  102. data/spec/mspec-opal/formatters.rb +2 -0
  103. data/spec/mspec-opal/runner.rb +2 -0
  104. data/spec/opal/core/array/dup_spec.rb +2 -0
  105. data/spec/opal/core/exception_spec.rb +2 -0
  106. data/spec/opal/core/hash/internals_spec.rb +154 -206
  107. data/spec/opal/core/hash_spec.rb +2 -0
  108. data/spec/opal/core/iterable_props_spec.rb +2 -0
  109. data/spec/opal/core/kernel/at_exit_spec.rb +2 -0
  110. data/spec/opal/core/kernel/respond_to_spec.rb +2 -0
  111. data/spec/opal/core/language/arguments/mlhs_arg_spec.rb +2 -0
  112. data/spec/opal/core/language/case_spec.rb +13 -0
  113. data/spec/opal/core/language/safe_navigator_spec.rb +2 -0
  114. data/spec/opal/core/language/xstring_send_spec.rb +15 -0
  115. data/spec/opal/core/language/xstring_spec.rb +2 -0
  116. data/spec/opal/core/language_spec.rb +2 -0
  117. data/spec/opal/core/module_spec.rb +44 -0
  118. data/spec/opal/core/number/to_i_spec.rb +2 -0
  119. data/spec/opal/core/object_id_spec.rb +2 -0
  120. data/spec/opal/core/regexp/match_spec.rb +2 -0
  121. data/spec/opal/core/runtime/bridged_classes_spec.rb +38 -0
  122. data/spec/opal/core/runtime/constants_spec.rb +2 -0
  123. data/spec/opal/core/runtime/eval_spec.rb +2 -0
  124. data/spec/opal/core/runtime/exit_spec.rb +2 -0
  125. data/spec/opal/core/runtime/is_a_spec.rb +2 -0
  126. data/spec/opal/core/runtime/loaded_spec.rb +2 -0
  127. data/spec/opal/core/runtime/method_missing_spec.rb +2 -0
  128. data/spec/opal/core/runtime/rescue_spec.rb +2 -0
  129. data/spec/opal/core/runtime/string_spec.rb +2 -0
  130. data/spec/opal/core/runtime/truthy_spec.rb +2 -0
  131. data/spec/opal/core/runtime_spec.rb +2 -6
  132. data/spec/opal/core/string/to_sym_spec.rb +2 -0
  133. data/spec/opal/stdlib/js_spec.rb +2 -0
  134. data/spec/opal/stdlib/native/alias_native_spec.rb +2 -0
  135. data/spec/opal/stdlib/native/array_spec.rb +2 -0
  136. data/spec/opal/stdlib/native/date_spec.rb +2 -0
  137. data/spec/opal/stdlib/native/each_spec.rb +2 -0
  138. data/spec/opal/stdlib/native/element_reference_spec.rb +2 -0
  139. data/spec/opal/stdlib/native/exposure_spec.rb +2 -0
  140. data/spec/opal/stdlib/native/ext_spec.rb +2 -0
  141. data/spec/opal/stdlib/native/hash_spec.rb +30 -2
  142. data/spec/opal/stdlib/native/initialize_spec.rb +2 -0
  143. data/spec/opal/stdlib/native/method_missing_spec.rb +2 -0
  144. data/spec/opal/stdlib/native/native_alias_spec.rb +2 -0
  145. data/spec/opal/stdlib/native/native_class_spec.rb +2 -0
  146. data/spec/opal/stdlib/native/native_module_spec.rb +2 -0
  147. data/spec/opal/stdlib/native/native_reader_spec.rb +2 -0
  148. data/spec/opal/stdlib/native/native_writer_spec.rb +2 -0
  149. data/spec/opal/stdlib/native/new_spec.rb +2 -0
  150. data/spec/opal/stdlib/native/struct_spec.rb +2 -0
  151. data/spec/spec_helper.rb +2 -0
  152. data/stdlib/await.rb +1 -0
  153. data/stdlib/base64.rb +2 -0
  154. data/stdlib/bigdecimal/bignumber.js.rb +2 -0
  155. data/stdlib/bigdecimal/util.rb +1 -0
  156. data/stdlib/bigdecimal.rb +2 -0
  157. data/stdlib/buffer/array.rb +2 -0
  158. data/stdlib/buffer/view.rb +2 -0
  159. data/stdlib/buffer.rb +2 -0
  160. data/stdlib/cgi.rb +14 -0
  161. data/stdlib/console.rb +2 -0
  162. data/stdlib/date/date_time.rb +2 -0
  163. data/stdlib/date.rb +2 -0
  164. data/stdlib/delegate.rb +2 -0
  165. data/stdlib/deno/base.rb +2 -0
  166. data/stdlib/deno/file.rb +2 -0
  167. data/stdlib/erb.rb +2 -0
  168. data/stdlib/gjs/io.rb +2 -0
  169. data/stdlib/gjs/kernel.rb +2 -0
  170. data/stdlib/headless_browser/base.rb +2 -0
  171. data/stdlib/headless_browser/file.rb +1 -0
  172. data/stdlib/headless_browser.rb +1 -0
  173. data/stdlib/js.rb +2 -0
  174. data/stdlib/json.rb +9 -15
  175. data/stdlib/logger.rb +2 -0
  176. data/stdlib/nashorn/file.rb +2 -0
  177. data/stdlib/nashorn/io.rb +2 -0
  178. data/stdlib/native.rb +48 -48
  179. data/stdlib/nodejs/base.rb +2 -0
  180. data/stdlib/nodejs/dir.rb +2 -0
  181. data/stdlib/nodejs/env.rb +2 -0
  182. data/stdlib/nodejs/file.rb +2 -0
  183. data/stdlib/nodejs/fileutils.rb +2 -0
  184. data/stdlib/nodejs/io.rb +2 -0
  185. data/stdlib/nodejs/js-yaml-3-6-1.js +1 -1
  186. data/stdlib/nodejs/kernel.rb +2 -0
  187. data/stdlib/nodejs/open-uri.rb +2 -0
  188. data/stdlib/nodejs/pathname.rb +2 -0
  189. data/stdlib/nodejs/require.rb +2 -0
  190. data/stdlib/nodejs/yaml.rb +9 -3
  191. data/stdlib/opal/miniracer.rb +2 -0
  192. data/stdlib/opal-parser.rb +8 -1
  193. data/stdlib/opal-platform.rb +2 -0
  194. data/stdlib/opal-replutils.rb +2 -0
  195. data/stdlib/open-uri.rb +4 -1
  196. data/stdlib/ostruct.rb +4 -2
  197. data/stdlib/pathname.rb +2 -0
  198. data/stdlib/pp.rb +1 -0
  199. data/stdlib/promise/v2.rb +2 -0
  200. data/stdlib/quickjs/io.rb +2 -0
  201. data/stdlib/quickjs/kernel.rb +2 -0
  202. data/stdlib/quickjs.rb +2 -0
  203. data/stdlib/securerandom.rb +2 -0
  204. data/stdlib/strscan.rb +2 -0
  205. data/stdlib/time.rb +2 -0
  206. data/stdlib/uri.rb +1 -0
  207. data/tasks/performance/optimization_status.rb +2 -0
  208. data/tasks/testing.rake +1 -0
  209. data/test/nodejs/test_await.rb +1 -0
  210. data/test/nodejs/test_dir.rb +2 -0
  211. data/test/nodejs/test_error.rb +2 -0
  212. data/test/nodejs/test_file.rb +2 -0
  213. data/test/nodejs/test_string.rb +2 -0
  214. data/test/nodejs/test_yaml.rb +20 -0
  215. metadata +24 -14
  216. data/spec/filters/bugs/openstruct.rb +0 -8
data/lib/opal/nodes/if.rb CHANGED
@@ -349,7 +349,7 @@ module Opal
349
349
  @switch_additional_rules = sexp.meta[:switch_additional_rules]
350
350
  compile_switch_case(sexp.meta[:switch_test])
351
351
  else
352
- line "switch (", expr(@switch_first_test), ") {"
352
+ line "switch (", expr(@switch_first_test), ".valueOf()) {"
353
353
  indent do
354
354
  compile_switch_case(@switch_test)
355
355
  end
@@ -392,45 +392,53 @@ module Opal
392
392
  end
393
393
  end
394
394
 
395
- class IFlipFlop < Base
396
- handle :iflipflop
397
-
398
- children :from, :to
399
-
400
- # Is this an exclusive flip flop? If no, run both branches
401
- def excl
402
- ""
403
- end
395
+ class BaseFlipFlop < Base
396
+ children :start_condition, :end_condition
404
397
 
405
- # We create a function that we put in the top scope, that stores the state of our
406
- # flip-flop. We pass to it functions that are ran with the current binding.
407
398
  def compile
408
399
  helper :truthy
409
400
 
410
- fun_name = top_scope.new_temp
411
- ff = "#{fun_name}.$$ff"
412
-
413
- push "(typeof #{fun_name} === 'undefined' ? (#{fun_name} = function(from, to){"
414
- push " if (typeof #{ff} === 'undefined') #{ff} = false;"
415
- push " var retval = #{ff};"
416
- push " if (!#{ff}) {"
417
- push " #{ff} = retval = $truthy(from());"
418
- push " }"
419
- push " #{excl}if (#{ff}) {"
420
- push " if ($truthy(to())) #{ff} = false;"
421
- push " }"
422
- push " return retval;"
423
- push "}) : #{fun_name})("
424
- push " function() { ", stmt(compiler.returns(from)), " },"
425
- push " function() { ", stmt(compiler.returns(to)), " }"
401
+ func_name = top_scope.new_temp
402
+ flip_flop_state = "#{func_name}.$$ff"
403
+
404
+ # Start function definition, checking and initializing it if necessary
405
+ push "(#{func_name} = #{func_name} || function(_start_func, _end_func){"
406
+
407
+ # If flip flop state is not defined, set it to false
408
+ push " var flip_flop = #{flip_flop_state} || false;"
409
+
410
+ # If flip flop state is false, call the 'start_condition' function and store its truthy result into flip flop state
411
+ push " if (!flip_flop) #{flip_flop_state} = flip_flop = $truthy(_start_func());"
412
+
413
+ # If flip flop state is true, call the 'end_condition' function and set flip flop state to false if 'end_condition' is truthy
414
+ push " #{excl}if (flip_flop && $truthy(_end_func())) #{flip_flop_state} = false;"
415
+
416
+ # Return current state of flip flop
417
+ push " return flip_flop;"
418
+
419
+ # End function definition
420
+ push "})("
421
+
422
+ # Call the function with 'start_condition' and 'end_condition' arguments wrapped in functions to ensure correct binding and delay evaluation
423
+ push " function() { ", stmt(compiler.returns(start_condition)), " },"
424
+ push " function() { ", stmt(compiler.returns(end_condition)), " }"
426
425
  push ")"
427
426
  end
428
427
  end
429
428
 
430
- class EFlipFlop < IFlipFlop
429
+ class IFlipFlop < BaseFlipFlop
430
+ handle :iflipflop
431
+
432
+ # Inclusive flip flop, check 'end_condition' in the same iteration when 'start_condition' is truthy
433
+ def excl
434
+ ""
435
+ end
436
+ end
437
+
438
+ class EFlipFlop < BaseFlipFlop
431
439
  handle :eflipflop
432
440
 
433
- # Is this an exclusive flip flop? If yes, run only a single branch
441
+ # Exclusive flip flop, check 'end_condition' in the next iteration after 'start_condition' is truthy
434
442
  def excl
435
443
  "else "
436
444
  end
@@ -158,11 +158,15 @@ module Opal
158
158
  case value
159
159
  when ''
160
160
  push('/(?:)/')
161
- when /\(\?<=|\(\?<!/
161
+ when /\(\?[(<>#]|[*+?]\+/
162
162
  # Safari/WebKit will not execute javascript code if it contains a lookbehind literal RegExp
163
163
  # and they fail with "Syntax Error". This tricks their parser by disguising the literal RegExp
164
164
  # as string for the dynamic $regexp helper. Safari/Webkit will still fail to execute the RegExp,
165
165
  # but at least they will parse and run everything else.
166
+ #
167
+ # Also, let's compile a couple of more patterns into $regexp calls, as there are many syntax
168
+ # errors in RubySpec when ran in reverse, while there shouldn't be (they should be catchable
169
+ # errors) - at least since Node 17.
166
170
  static_as_dynamic(value)
167
171
  else
168
172
  push "#{Regexp.new(value).inspect}#{flags.join}"
@@ -6,6 +6,19 @@ module Opal
6
6
  handle :xstr
7
7
 
8
8
  def compile
9
+ if compiler.backtick_javascript_or_warn?
10
+ compile_javascript
11
+ else
12
+ compile_send
13
+ end
14
+ end
15
+
16
+ def compile_send
17
+ sexp = s(:send, nil, :`, s(:dstr, *children))
18
+ push process(sexp, @level)
19
+ end
20
+
21
+ def compile_javascript
9
22
  @should_add_semicolon = false
10
23
  unpacked_children = unpack_return(children)
11
24
  stripped_children = XStringNode.strip_empty_children(unpacked_children)
@@ -1,3 +1,4 @@
1
+ # backtick_javascript: true
1
2
  # frozen_string_literal: true
2
3
 
3
4
  if RUBY_ENGINE == 'opal'
@@ -13,6 +14,12 @@ if RUBY_ENGINE == 'opal'
13
14
  else
14
15
  @source_pts = nil
15
16
  end
17
+
18
+ # Since parser v3.2.1 Parser::Lexer has @strings
19
+ if @strings
20
+ @strings.source_buffer = @source_buffer
21
+ @strings.source_pts = @source_pts
22
+ end
16
23
  end
17
24
  end
18
25
 
@@ -34,40 +34,52 @@ module Opal
34
34
  # j = nil
35
35
  # [[1, 2], [3, 4]].each { |__jstmp| i, j = __jstmp }
36
36
  #
37
- def on_for(node)
38
- loop_variable, iterating_value, loop_body = *node
39
37
 
40
- iterating_lvars = LocalVariableAssigns.find(loop_variable) # [:i]
41
- lvars_declared_in_body = LocalVariableAssigns.find(loop_body) # [:j]
38
+ def on_for(node)
39
+ loop_variable, loop_range, loop_body = *node
42
40
 
43
- # i = nil; j = nil
44
- outer_assigns = (iterating_lvars + lvars_declared_in_body).map do |lvar_name|
45
- s(:lvdeclare, lvar_name)
46
- end
41
+ # Declare local variables used in the loop and the loop body at the outer scope
42
+ outer_assignments = generate_outer_assignments(loop_variable, loop_body)
47
43
 
48
- # :__jstmp
44
+ # Generate temporary loop variable
49
45
  tmp_loop_variable = self.class.next_tmp
50
46
  get_tmp_loop_variable = s(:js_tmp, tmp_loop_variable)
51
47
 
52
- loop_variable_assignment = case loop_variable.type
53
- when :mlhs # multiple left-hand statement like in "for i,j in [[1, 2], [3, 4]]"
54
- # i, j = __jstmp
55
- loop_variable.updated(:masgn, [loop_variable, get_tmp_loop_variable])
56
- else # single argument like "for i in (0..3)"
57
- # i = __jstmp
58
- loop_variable << get_tmp_loop_variable
59
- end
48
+ # Assign the loop variables in the loop body
49
+ loop_body = prepend_to_body(loop_body, assign_loop_variable(loop_variable, get_tmp_loop_variable))
50
+
51
+ # Transform the for-loop into each-loop with updated loop body
52
+ node = transform_for_to_each_loop(node, loop_range, tmp_loop_variable, loop_body)
53
+
54
+ node.updated(:begin, [*outer_assignments, node])
55
+ end
60
56
 
61
- loop_body = prepend_to_body(loop_body, loop_variable_assignment)
57
+ private
62
58
 
63
- node = node.updated(:send, [iterating_value, :each, # (0..3).each {
64
- node.updated(:iter, [s(:args, s(:arg, tmp_loop_variable)), # |__jstmp|
65
- process(loop_body)] # i = __jstmp; j = i + 1 }
66
- )]
67
- )
59
+ def generate_outer_assignments(loop_variable, loop_body)
60
+ loop_local_vars = LocalVariableAssigns.find(loop_variable)
61
+ body_local_vars = LocalVariableAssigns.find(loop_body)
62
+
63
+ (loop_local_vars + body_local_vars).map { |lvar_name| s(:lvdeclare, lvar_name) }
64
+ end
65
+
66
+ def assign_loop_variable(loop_variable, tmp_loop_variable)
67
+ case loop_variable.type
68
+ when :mlhs # multiple left-hand statement like in "for i,j in [[1, 2], [3, 4]]"
69
+ loop_variable.updated(:masgn, [loop_variable, tmp_loop_variable])
70
+ else # single argument like "for i in (0..3)"
71
+ loop_variable << tmp_loop_variable
72
+ end
73
+ end
68
74
 
69
- node.updated(:begin, [*outer_assigns, node])
75
+ # rubocop:disable Layout/MultilineMethodCallBraceLayout,Layout/MultilineArrayBraceLayout
76
+ def transform_for_to_each_loop(node, loop_range, tmp_loop_variable, loop_body)
77
+ node.updated(:send, [loop_range, :each, # (0..3).each {
78
+ node.updated(:iter, [s(:args, s(:arg, tmp_loop_variable)), # |__jstmp|
79
+ process(loop_body) # i = __jstmp; j = i + 1 }
80
+ ])])
70
81
  end
82
+ # rubocop:enable Layout/MultilineMethodCallBraceLayout,Layout/MultilineArrayBraceLayout
71
83
 
72
84
  class LocalVariableAssigns < Base
73
85
  attr_reader :result
@@ -134,7 +134,7 @@ class Opal::SourceMap::File
134
134
  absolute_mapping.map do |absolute_segment|
135
135
  segment = []
136
136
 
137
- segment[0] = absolute_segment[0] - reference_segment[0]
137
+ segment[0] = absolute_segment[0] - reference_segment[0]
138
138
  segment[1] = absolute_segment[1] - (reference_segment[1] || 0)
139
139
  segment[2] = absolute_segment[2] - (reference_segment[2] || 0)
140
140
  segment[3] = absolute_segment[3] - (reference_segment[3] || 0)
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.7.2'
6
+ VERSION = '1.8.0.alpha1'
7
7
  end
@@ -1,4 +1,5 @@
1
1
  # helpers: coerce_to
2
+ # backtick_javascript: true
2
3
 
3
4
  require 'corelib/pack_unpack/format_string_parser'
4
5
 
@@ -1,4 +1,5 @@
1
1
  # helpers: truthy, falsy, hash_ids, yield1, hash_get, hash_put, hash_delete, coerce_to, respond_to, deny_frozen_access, freeze
2
+ # backtick_javascript: true
2
3
 
3
4
  require 'corelib/enumerable'
4
5
  require 'corelib/numeric'
@@ -68,6 +69,13 @@ class ::Array < `Array`
68
69
 
69
70
  if (raised) throw raised;
70
71
  }
72
+
73
+ function convertToArray(array) {
74
+ if (!array.$$is_array) {
75
+ array = $coerce_to(array, #{::Array}, 'to_ary');
76
+ }
77
+ return #{`array`.to_a};
78
+ }
71
79
  }
72
80
 
73
81
  def self.[](*objects)
@@ -135,13 +143,13 @@ class ::Array < `Array`
135
143
  end
136
144
 
137
145
  def &(other)
138
- other = if ::Array === other
139
- other.to_a
140
- else
141
- `$coerce_to(other, #{::Array}, 'to_ary')`.to_a
142
- end
143
-
144
146
  %x{
147
+ other = convertToArray(other)
148
+
149
+ if (self.length === 0 || other.length === 0) {
150
+ return [];
151
+ }
152
+
145
153
  var result = [], hash = #{{}}, i, length, item;
146
154
 
147
155
  for (i = 0, length = other.length; i < length; i++) {
@@ -160,11 +168,7 @@ class ::Array < `Array`
160
168
  end
161
169
 
162
170
  def |(other)
163
- other = if ::Array === other
164
- other.to_a
165
- else
166
- `$coerce_to(other, #{::Array}, 'to_ary')`.to_a
167
- end
171
+ other = `convertToArray(other)`
168
172
 
169
173
  %x{
170
174
  var hash = #{{}}, i, length, item;
@@ -203,21 +207,13 @@ class ::Array < `Array`
203
207
  end
204
208
 
205
209
  def +(other)
206
- other = if ::Array === other
207
- other.to_a
208
- else
209
- `$coerce_to(other, #{::Array}, 'to_ary')`.to_a
210
- end
210
+ other = `convertToArray(other)`
211
211
 
212
212
  `self.concat(other)`
213
213
  end
214
214
 
215
215
  def -(other)
216
- other = if ::Array === other
217
- other.to_a
218
- else
219
- `$coerce_to(other, #{::Array}, 'to_ary')`.to_a
220
- end
216
+ other = `convertToArray(other)`
221
217
 
222
218
  return [] if `self.length === 0`
223
219
  return `self.slice()` if `other.length === 0`
@@ -696,11 +692,12 @@ class ::Array < `Array`
696
692
  return enum_for(:collect) { size } unless block_given?
697
693
 
698
694
  %x{
699
- var result = [];
695
+ var length = self.length;
696
+ var result = new Array(length);
700
697
 
701
- for (var i = 0, length = self.length; i < length; i++) {
698
+ for (var i = 0; i < length; i++) {
702
699
  var value = $yield1(block, self[i]);
703
- result.push(value);
700
+ result[i] = value;
704
701
  }
705
702
 
706
703
  return result;
@@ -849,11 +846,7 @@ class ::Array < `Array`
849
846
  `$deny_frozen_access(self)`
850
847
 
851
848
  others = others.map do |other|
852
- other = if ::Array === other
853
- other.to_a
854
- else
855
- `$coerce_to(other, #{::Array}, 'to_ary')`.to_a
856
- end
849
+ `other = convertToArray(other)`
857
850
 
858
851
  if other.equal?(self)
859
852
  other = other.dup
@@ -1410,11 +1403,54 @@ class ::Array < `Array`
1410
1403
  end
1411
1404
 
1412
1405
  def intersection(*arrays)
1413
- arrays.reduce(to_a.dup) { |a, b| a & b }
1406
+ %x{
1407
+ if (arrays.length === 0) {
1408
+ return #{to_a.dup};
1409
+ }
1410
+ arrays = arrays.map(convertToArray);
1411
+ if (self.length === 0) {
1412
+ return [];
1413
+ }
1414
+ }
1415
+
1416
+ arrays = arrays.sort_by(&:length)
1417
+ # When self is the smallest among the arrays
1418
+ if `self.length < arrays[0].length`
1419
+ return arrays.reduce(self, &:&)
1420
+ end
1421
+
1422
+ # First, calculate intersection of argument arrays.
1423
+ # Array#& is faster when the argument size is small.
1424
+ # So `largest & shortest & second_shortest & ...` would be the fastest.
1425
+ largest = `arrays.pop()`
1426
+ intersection_of_args = arrays.reduce(largest, &:&)
1427
+
1428
+ # self array must come last to maintain the order
1429
+ self & intersection_of_args
1414
1430
  end
1415
1431
 
1416
1432
  def intersect?(other)
1417
- !intersection(other).empty?
1433
+ %x{
1434
+ var small, large, hash = #{{}}, i, length;
1435
+ if (self.length < other.length) {
1436
+ small = self;
1437
+ large = other;
1438
+ } else {
1439
+ small = other;
1440
+ large = self;
1441
+ }
1442
+
1443
+ for (i = 0, length = small.length; i < length; i++) {
1444
+ $hash_put(hash, small[i], true);
1445
+ }
1446
+
1447
+ for (i = 0, length = large.length; i < length; i++) {
1448
+ if ($hash_get(hash, large[i])) {
1449
+ return true;
1450
+ }
1451
+ }
1452
+ return false;
1453
+ }
1418
1454
  end
1419
1455
 
1420
1456
  def join(sep = nil)
@@ -1762,11 +1798,7 @@ class ::Array < `Array`
1762
1798
  def replace(other)
1763
1799
  `$deny_frozen_access(self)`
1764
1800
 
1765
- other = if ::Array === other
1766
- other.to_a
1767
- else
1768
- `$coerce_to(other, #{::Array}, 'to_ary')`.to_a
1769
- end
1801
+ other = `convertToArray(other)`
1770
1802
 
1771
1803
  %x{
1772
1804
  self.splice(0, self.length);
@@ -1927,9 +1959,9 @@ class ::Array < `Array`
1927
1959
  break;
1928
1960
  case 2:
1929
1961
  i = #{rng.rand(`self.length`)};
1930
- j = #{rng.rand(`self.length`)};
1931
- if (i === j) {
1932
- j = i === 0 ? i + 1 : i - 1;
1962
+ j = #{rng.rand(`self.length - 1`)};
1963
+ if (i <= j) {
1964
+ j++;
1933
1965
  }
1934
1966
  return [self[i], self[j]];
1935
1967
  break;
@@ -1981,7 +2013,7 @@ class ::Array < `Array`
1981
2013
  result = self.slice();
1982
2014
 
1983
2015
  for (var c = 0; c < count; c++) {
1984
- targetIndex = #{rng.rand(`self.length`)};
2016
+ targetIndex = #{rng.rand(`self.length - c`)} + c;
1985
2017
  oldValue = result[c];
1986
2018
  result[c] = result[targetIndex];
1987
2019
  result[targetIndex] = oldValue;
@@ -2284,10 +2316,10 @@ class ::Array < `Array`
2284
2316
  for (i = 0; i < len; i++) {
2285
2317
  ary = #{::Opal.coerce_to?(`array[i]`, ::Array, :to_ary)};
2286
2318
  if (!ary.$$is_array) {
2287
- #{::Kernel.raise ::TypeError, "wrong element type #{`ary`.class} at #{`i`} (expected array)"}
2319
+ #{::Kernel.raise ::TypeError, "wrong element type #{`array[i]`.class} at #{`i`} (expected array)"}
2288
2320
  }
2289
2321
  if (ary.length !== 2) {
2290
- #{::Kernel.raise ::ArgumentError, "wrong array length at #{`i`} (expected 2, was #{`ary`.length})"}
2322
+ #{::Kernel.raise ::ArgumentError, "element has wrong array length at #{`i`} (expected 2, was #{`ary`.length})"}
2291
2323
  }
2292
2324
  key = ary[0];
2293
2325
  val = ary[1];
@@ -2305,11 +2337,7 @@ class ::Array < `Array`
2305
2337
  max = nil
2306
2338
 
2307
2339
  each do |row|
2308
- row = if ::Array === row
2309
- row.to_a
2310
- else
2311
- `$coerce_to(row, #{::Array}, 'to_ary')`.to_a
2312
- end
2340
+ `row = convertToArray(row)`
2313
2341
 
2314
2342
  max ||= `row.length`
2315
2343
 
@@ -1,4 +1,5 @@
1
1
  # use_strict: true
2
+ # backtick_javascript: true
2
3
 
3
4
  class ::BasicObject
4
5
  def initialize(*)
@@ -1,3 +1,5 @@
1
+ # backtick_javascript: true
2
+
1
3
  class ::Binding
2
4
  # @private
3
5
  def initialize(jseval, scope_variables = [], receiver = undefined, source_location = nil)
@@ -1,4 +1,5 @@
1
1
  # use_strict: true
2
+ # backtick_javascript: true
2
3
 
3
4
  class ::Boolean < `Boolean`
4
5
  `Opal.prop(self.$$prototype, '$$is_boolean', true)`
@@ -1,3 +1,5 @@
1
+ # backtick_javascript: true
2
+
1
3
  require 'corelib/module'
2
4
 
3
5
  class ::Class
@@ -1,4 +1,5 @@
1
1
  # helpers: truthy
2
+ # backtick_javascript: true
2
3
 
3
4
  module ::Comparable
4
5
  %x{
@@ -1,3 +1,5 @@
1
+ # backtick_javascript: true
2
+
1
3
  require 'corelib/numeric'
2
4
  require 'corelib/complex/base'
3
5
 
@@ -1,8 +1,8 @@
1
1
  ::RUBY_PLATFORM = 'opal'
2
2
  ::RUBY_ENGINE = 'opal'
3
3
  ::RUBY_VERSION = '3.2.0'
4
- ::RUBY_ENGINE_VERSION = '1.7.2'
5
- ::RUBY_RELEASE_DATE = '2023-01-20'
4
+ ::RUBY_ENGINE_VERSION = '1.8.0.alpha1'
5
+ ::RUBY_RELEASE_DATE = '2023-08-04'
6
6
  ::RUBY_PATCHLEVEL = 0
7
7
  ::RUBY_REVISION = '0'
8
8
  ::RUBY_COPYRIGHT = 'opal - Copyright (C) 2011-2023 Adam Beynon and the Opal contributors'
data/opal/corelib/dir.rb CHANGED
@@ -1,3 +1,5 @@
1
+ # backtick_javascript: true
2
+
1
3
  class ::Dir
2
4
  class << self
3
5
  def chdir(dir)
@@ -1,4 +1,5 @@
1
1
  # helpers: truthy, coerce_to, yield1, yieldX, deny_frozen_access
2
+ # backtick_javascript: true
2
3
 
3
4
  module ::Enumerable
4
5
  %x{
@@ -1251,10 +1252,10 @@ module ::Enumerable
1251
1252
  var param = #{::Opal.destructure(`arguments`)};
1252
1253
  var ary = #{::Opal.coerce_to?(`param`, ::Array, :to_ary)}, key, val;
1253
1254
  if (!ary.$$is_array) {
1254
- #{::Kernel.raise ::TypeError, "wrong element type #{`ary`.class} (expected array)"}
1255
+ #{::Kernel.raise ::TypeError, "wrong element type #{`param`.class} (expected array)"}
1255
1256
  }
1256
1257
  if (ary.length !== 2) {
1257
- #{::Kernel.raise ::ArgumentError, "wrong array length (expected 2, was #{`ary`.length})"}
1258
+ #{::Kernel.raise ::ArgumentError, "element has wrong array length (expected 2, was #{`ary`.length})"}
1258
1259
  }
1259
1260
  key = ary[0];
1260
1261
  val = ary[1];
@@ -1,3 +1,5 @@
1
+ # backtick_javascript: true
2
+
1
3
  class ::Enumerator
2
4
  class self::ArithmeticSequence < self
3
5
  `Opal.prop(self.$$prototype, '$$is_arithmetic_seq', true)`
@@ -1,4 +1,5 @@
1
1
  # helpers: deny_frozen_access
2
+ # backtick_javascript: true
2
3
 
3
4
  class ::Enumerator
4
5
  class self::Chain < self
@@ -1,4 +1,5 @@
1
1
  # helpers: deny_frozen_access
2
+ # backtick_javascript: true
2
3
 
3
4
  class Enumerator
4
5
  class Generator
@@ -1,4 +1,5 @@
1
1
  # helpers: truthy, coerce_to, yield1, yieldX, deny_frozen_access
2
+ # backtick_javascript: true
2
3
 
3
4
  class ::Enumerator
4
5
  class self::Lazy < self
@@ -1,3 +1,5 @@
1
+ # backtick_javascript: true
2
+
1
3
  class Enumerator
2
4
  class Yielder
3
5
  def initialize(&block)
@@ -1,4 +1,5 @@
1
1
  # helpers: slice, coerce_to, deny_frozen_access
2
+ # backtick_javascript: true
2
3
 
3
4
  require 'corelib/enumerable'
4
5
 
@@ -1,3 +1,5 @@
1
+ # backtick_javascript: true
2
+
1
3
  module ::Errno
2
4
  errors = [
3
5
  [:EINVAL, 'Invalid argument', 22],
@@ -1,3 +1,5 @@
1
+ # backtick_javascript: true
2
+
1
3
  class ::Exception < `Error`
2
4
  `Opal.prop(self.$$prototype, '$$is_exception', true)`
3
5
  `var stack_trace_limit`
@@ -36,6 +38,16 @@ class ::Exception < `Error`
36
38
  `self.message = (args.length > 0) ? args[0] : nil`
37
39
  end
38
40
 
41
+ # Those instance variables are not enumerable.
42
+ def copy_instance_variables(other)
43
+ super
44
+ %x{
45
+ self.message = other.message;
46
+ self.cause = other.cause;
47
+ self.stack = other.stack;
48
+ }
49
+ end
50
+
39
51
  %x{
40
52
  // Convert backtrace from any format to Ruby format
41
53
  function correct_backtrace(backtrace) {
data/opal/corelib/file.rb CHANGED
@@ -1,4 +1,5 @@
1
1
  # helpers: truthy
2
+ # backtick_javascript: true
2
3
 
3
4
  class ::File < ::IO
4
5
  Separator = SEPARATOR = '/'