opal 1.7.4 → 1.8.0.beta1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.eslintrc.js +1 -0
- data/.github/workflows/build.yml +9 -9
- data/.rubocop/todo.yml +2 -2
- data/.rubocop.yml +17 -10
- data/.rubocop_todo.yml +311 -0
- data/CHANGELOG.md +1 -15
- data/README.md +7 -7
- data/UNRELEASED.md +92 -1
- data/benchmark-ips/bm_block_vs_yield.rb +3 -0
- data/benchmark-ips/bm_slice_or_not.rb +53 -0
- data/docs/bridging.md +112 -0
- data/docs/compiled_ruby.md +10 -10
- data/docs/getting_started.md +18 -22
- data/docs/releasing.md +8 -16
- data/lib/opal/cli_runners/chrome_cdp_interface.rb +1 -0
- data/lib/opal/cli_runners/firefox_cdp_interface.rb +1 -0
- data/lib/opal/compiler.rb +33 -1
- data/lib/opal/nodes/args/extract_kwoptarg.rb +2 -1
- data/lib/opal/nodes/call.rb +1 -1
- data/lib/opal/nodes/call_special.rb +71 -47
- data/lib/opal/nodes/closure.rb +15 -7
- data/lib/opal/nodes/defined.rb +1 -1
- data/lib/opal/nodes/hash.rb +14 -30
- data/lib/opal/nodes/if.rb +37 -29
- data/lib/opal/nodes/literal.rb +15 -7
- data/lib/opal/nodes/rescue.rb +1 -1
- data/lib/opal/nodes/x_string.rb +13 -0
- data/lib/opal/parser/patch.rb +1 -0
- data/lib/opal/rewriters/for_rewriter.rb +36 -24
- data/lib/opal/source_map/file.rb +1 -1
- data/lib/opal/version.rb +1 -1
- data/opal/corelib/array/pack.rb +1 -0
- data/opal/corelib/array.rb +110 -64
- data/opal/corelib/basic_object.rb +1 -0
- data/opal/corelib/binding.rb +2 -0
- data/opal/corelib/boolean.rb +1 -0
- data/opal/corelib/class.rb +28 -8
- data/opal/corelib/comparable.rb +1 -0
- data/opal/corelib/complex.rb +3 -1
- data/opal/corelib/constants.rb +2 -2
- data/opal/corelib/dir.rb +2 -0
- data/opal/corelib/enumerable.rb +3 -2
- data/opal/corelib/enumerator/arithmetic_sequence.rb +3 -1
- data/opal/corelib/enumerator/chain.rb +1 -0
- data/opal/corelib/enumerator/generator.rb +1 -0
- data/opal/corelib/enumerator/lazy.rb +1 -0
- data/opal/corelib/enumerator/yielder.rb +2 -0
- data/opal/corelib/enumerator.rb +1 -0
- data/opal/corelib/error/errno.rb +2 -0
- data/opal/corelib/error.rb +22 -0
- data/opal/corelib/file.rb +1 -0
- data/opal/corelib/hash.rb +224 -519
- data/opal/corelib/helpers.rb +1 -0
- data/opal/corelib/io.rb +2 -0
- data/opal/corelib/irb.rb +2 -0
- data/opal/corelib/kernel/format.rb +1 -0
- data/opal/corelib/kernel.rb +70 -15
- data/opal/corelib/main.rb +2 -0
- data/opal/corelib/marshal/read_buffer.rb +2 -0
- data/opal/corelib/marshal/write_buffer.rb +2 -0
- data/opal/corelib/math/polyfills.rb +2 -0
- data/opal/corelib/math.rb +1 -0
- data/opal/corelib/method.rb +2 -0
- data/opal/corelib/module.rb +45 -5
- data/opal/corelib/nil.rb +3 -1
- data/opal/corelib/number.rb +30 -1
- data/opal/corelib/numeric.rb +2 -0
- data/opal/corelib/object_space.rb +1 -0
- data/opal/corelib/pack_unpack/format_string_parser.rb +2 -0
- data/opal/corelib/proc.rb +30 -28
- data/opal/corelib/process.rb +2 -0
- data/opal/corelib/random/formatter.rb +2 -0
- data/opal/corelib/random/math_random.js.rb +2 -0
- data/opal/corelib/random/mersenne_twister.rb +2 -0
- data/opal/corelib/random/seedrandom.js.rb +2 -0
- data/opal/corelib/random.rb +1 -0
- data/opal/corelib/range.rb +35 -13
- data/opal/corelib/rational.rb +3 -1
- data/opal/corelib/regexp.rb +1 -0
- data/opal/corelib/runtime.js +297 -259
- data/opal/corelib/set.rb +2 -0
- data/opal/corelib/string/encoding.rb +3 -0
- data/opal/corelib/string/unpack.rb +2 -0
- data/opal/corelib/string.rb +56 -20
- data/opal/corelib/struct.rb +4 -2
- data/opal/corelib/time.rb +2 -1
- data/opal/corelib/trace_point.rb +2 -0
- data/opal/corelib/unsupported.rb +2 -0
- data/opal/corelib/variables.rb +2 -0
- data/opal.gemspec +2 -2
- data/spec/filters/bugs/array.rb +58 -2
- data/spec/filters/bugs/basicobject.rb +7 -0
- data/spec/filters/bugs/bigdecimal.rb +1 -2
- data/spec/filters/bugs/binding.rb +1 -0
- data/spec/filters/bugs/class.rb +2 -3
- data/spec/filters/bugs/complex.rb +3 -0
- data/spec/filters/bugs/date.rb +5 -2
- data/spec/filters/bugs/datetime.rb +1 -0
- data/spec/filters/bugs/delegate.rb +1 -2
- data/spec/filters/bugs/encoding.rb +1 -1
- data/spec/filters/bugs/enumerable.rb +11 -3
- data/spec/filters/bugs/enumerator.rb +15 -2
- data/spec/filters/bugs/exception.rb +9 -4
- data/spec/filters/bugs/file.rb +2 -0
- data/spec/filters/bugs/float.rb +1 -0
- data/spec/filters/bugs/freeze.rb +5 -49
- data/spec/filters/bugs/hash.rb +1 -13
- data/spec/filters/bugs/integer.rb +5 -6
- data/spec/filters/bugs/kernel.rb +12 -43
- data/spec/filters/bugs/language.rb +33 -15
- data/spec/filters/bugs/marshal.rb +63 -4
- data/spec/filters/bugs/method.rb +2 -10
- data/spec/filters/bugs/module.rb +18 -7
- data/spec/filters/bugs/objectspace.rb +2 -0
- data/spec/filters/bugs/pathname.rb +1 -0
- data/spec/filters/bugs/proc.rb +4 -2
- data/spec/filters/bugs/random.rb +0 -3
- data/spec/filters/bugs/range.rb +1 -2
- data/spec/filters/bugs/rational.rb +2 -0
- data/spec/filters/bugs/refinement.rb +19 -0
- data/spec/filters/bugs/regexp.rb +27 -5
- data/spec/filters/bugs/ruby-32.rb +0 -6
- data/spec/filters/bugs/set.rb +10 -2
- data/spec/filters/bugs/singleton.rb +0 -2
- data/spec/filters/bugs/string.rb +140 -2
- data/spec/filters/bugs/struct.rb +16 -10
- data/spec/filters/bugs/time.rb +56 -2
- data/spec/filters/bugs/trace_point.rb +1 -0
- data/spec/filters/bugs/unboundmethod.rb +4 -9
- data/spec/filters/bugs/warnings.rb +0 -1
- data/spec/filters/platform/firefox/exception.rb +3 -3
- data/spec/filters/platform/firefox/kernel.rb +1 -0
- data/spec/filters/platform/safari/exception.rb +2 -2
- data/spec/filters/platform/safari/float.rb +1 -0
- data/spec/filters/platform/safari/kernel.rb +1 -0
- data/spec/filters/platform/safari/literal_regexp.rb +2 -2
- data/spec/filters/unsupported/hash.rb +1 -0
- data/spec/lib/compiler_spec.rb +28 -17
- data/spec/mspec-opal/formatters.rb +2 -0
- data/spec/mspec-opal/runner.rb +2 -0
- data/spec/opal/core/array/dup_spec.rb +2 -0
- data/spec/opal/core/class/clone_spec.rb +36 -0
- data/spec/opal/core/exception_spec.rb +2 -0
- data/spec/opal/core/hash/internals_spec.rb +154 -206
- data/spec/opal/core/hash_spec.rb +2 -0
- data/spec/opal/core/iterable_props_spec.rb +2 -0
- data/spec/opal/core/kernel/at_exit_spec.rb +2 -0
- data/spec/opal/core/kernel/respond_to_spec.rb +2 -0
- data/spec/opal/core/language/arguments/mlhs_arg_spec.rb +2 -0
- data/spec/opal/core/language/safe_navigator_spec.rb +2 -0
- data/spec/opal/core/language/xstring_send_spec.rb +15 -0
- data/spec/opal/core/language/xstring_spec.rb +2 -0
- data/spec/opal/core/language_spec.rb +2 -0
- data/spec/opal/core/module_spec.rb +44 -0
- data/spec/opal/core/number/to_i_spec.rb +2 -0
- data/spec/opal/core/object_id_spec.rb +2 -6
- data/spec/opal/core/regexp/match_spec.rb +2 -0
- data/spec/opal/core/runtime/bridged_classes_spec.rb +38 -0
- data/spec/opal/core/runtime/constants_spec.rb +2 -0
- data/spec/opal/core/runtime/eval_spec.rb +2 -0
- data/spec/opal/core/runtime/exit_spec.rb +2 -0
- data/spec/opal/core/runtime/is_a_spec.rb +2 -0
- data/spec/opal/core/runtime/loaded_spec.rb +2 -0
- data/spec/opal/core/runtime/method_missing_spec.rb +2 -0
- data/spec/opal/core/runtime/rescue_spec.rb +2 -0
- data/spec/opal/core/runtime/string_spec.rb +2 -0
- data/spec/opal/core/runtime/truthy_spec.rb +2 -0
- data/spec/opal/core/runtime_spec.rb +2 -6
- data/spec/opal/core/string/to_sym_spec.rb +2 -0
- data/spec/opal/language/predefined_spec.rb +20 -0
- data/spec/opal/language/yield_spec.rb +43 -0
- data/spec/opal/stdlib/js_spec.rb +2 -0
- data/spec/opal/stdlib/native/alias_native_spec.rb +2 -0
- data/spec/opal/stdlib/native/array_spec.rb +2 -0
- data/spec/opal/stdlib/native/date_spec.rb +2 -0
- data/spec/opal/stdlib/native/each_spec.rb +2 -0
- data/spec/opal/stdlib/native/element_reference_spec.rb +2 -0
- data/spec/opal/stdlib/native/exposure_spec.rb +2 -0
- data/spec/opal/stdlib/native/ext_spec.rb +2 -0
- data/spec/opal/stdlib/native/hash_spec.rb +30 -2
- data/spec/opal/stdlib/native/initialize_spec.rb +2 -0
- data/spec/opal/stdlib/native/method_missing_spec.rb +2 -0
- data/spec/opal/stdlib/native/native_alias_spec.rb +2 -0
- data/spec/opal/stdlib/native/native_class_spec.rb +2 -0
- data/spec/opal/stdlib/native/native_module_spec.rb +2 -0
- data/spec/opal/stdlib/native/native_reader_spec.rb +2 -0
- data/spec/opal/stdlib/native/native_writer_spec.rb +2 -0
- data/spec/opal/stdlib/native/new_spec.rb +2 -0
- data/spec/opal/stdlib/native/struct_spec.rb +2 -0
- data/spec/ruby_specs +0 -2
- data/spec/spec_helper.rb +2 -0
- data/stdlib/await.rb +1 -0
- data/stdlib/base64.rb +2 -0
- data/stdlib/bigdecimal/bignumber.js.rb +2 -0
- data/stdlib/bigdecimal/util.rb +1 -0
- data/stdlib/bigdecimal.rb +4 -0
- data/stdlib/buffer/array.rb +2 -0
- data/stdlib/buffer/view.rb +2 -0
- data/stdlib/buffer.rb +2 -0
- data/stdlib/cgi.rb +14 -0
- data/stdlib/console.rb +2 -0
- data/stdlib/date/date_time.rb +2 -0
- data/stdlib/date.rb +2 -0
- data/stdlib/delegate.rb +5 -4
- data/stdlib/deno/base.rb +2 -0
- data/stdlib/deno/file.rb +2 -0
- data/stdlib/erb.rb +2 -0
- data/stdlib/gjs/io.rb +2 -0
- data/stdlib/gjs/kernel.rb +2 -0
- data/stdlib/headless_browser/base.rb +2 -0
- data/stdlib/headless_browser/file.rb +1 -0
- data/stdlib/headless_browser.rb +1 -0
- data/stdlib/js.rb +2 -0
- data/stdlib/json.rb +9 -15
- data/stdlib/logger.rb +2 -0
- data/stdlib/nashorn/file.rb +2 -0
- data/stdlib/nashorn/io.rb +2 -0
- data/stdlib/native.rb +48 -48
- data/stdlib/nodejs/base.rb +2 -0
- data/stdlib/nodejs/dir.rb +2 -0
- data/stdlib/nodejs/env.rb +2 -0
- data/stdlib/nodejs/file.rb +2 -0
- data/stdlib/nodejs/fileutils.rb +2 -0
- data/stdlib/nodejs/io.rb +2 -0
- data/stdlib/nodejs/js-yaml-3-6-1.js +1 -1
- data/stdlib/nodejs/kernel.rb +2 -0
- data/stdlib/nodejs/open-uri.rb +2 -0
- data/stdlib/nodejs/pathname.rb +2 -0
- data/stdlib/nodejs/require.rb +2 -0
- data/stdlib/nodejs/yaml.rb +9 -3
- data/stdlib/opal/miniracer.rb +2 -0
- data/stdlib/opal-parser.rb +8 -1
- data/stdlib/opal-platform.rb +2 -0
- data/stdlib/opal-replutils.rb +2 -0
- data/stdlib/open-uri.rb +4 -1
- data/stdlib/ostruct.rb +4 -2
- data/stdlib/pathname.rb +3 -1
- data/stdlib/pp.rb +1 -0
- data/stdlib/promise/v2.rb +24 -7
- data/stdlib/quickjs/io.rb +2 -0
- data/stdlib/quickjs/kernel.rb +2 -0
- data/stdlib/quickjs.rb +2 -0
- data/stdlib/securerandom.rb +2 -0
- data/stdlib/stringio.rb +2 -0
- data/stdlib/strscan.rb +2 -0
- data/stdlib/time.rb +2 -0
- data/stdlib/uri.rb +1 -0
- data/tasks/performance/optimization_status.rb +2 -0
- data/tasks/testing.rake +16 -11
- data/test/nodejs/test_await.rb +1 -0
- data/test/nodejs/test_dir.rb +2 -0
- data/test/nodejs/test_error.rb +2 -0
- data/test/nodejs/test_file.rb +2 -0
- data/test/nodejs/test_string.rb +2 -0
- data/test/nodejs/test_yaml.rb +20 -0
- data/test/opal/promisev2/test_always.rb +14 -0
- data/test/opal/unsupported_and_bugs.rb +0 -8
- metadata +26 -13
- data/spec/filters/bugs/openstruct.rb +0 -8
data/lib/opal/nodes/hash.rb
CHANGED
@@ -27,14 +27,12 @@ module Opal
|
|
27
27
|
end
|
28
28
|
|
29
29
|
def simple_keys?
|
30
|
-
keys.all? { |key| %i[sym str].include?(key.type) }
|
30
|
+
keys.all? { |key| %i[sym str int].include?(key.type) }
|
31
31
|
end
|
32
32
|
|
33
33
|
def compile
|
34
34
|
if has_kwsplat
|
35
35
|
compile_merge
|
36
|
-
elsif simple_keys?
|
37
|
-
compile_hash2
|
38
36
|
else
|
39
37
|
compile_hash
|
40
38
|
end
|
@@ -47,8 +45,6 @@ module Opal
|
|
47
45
|
# Each kwsplat overrides previosly defined keys
|
48
46
|
# Hash k/v pairs override previously defined kwsplat values
|
49
47
|
def compile_merge
|
50
|
-
helper :hash
|
51
|
-
|
52
48
|
result, seq = [], []
|
53
49
|
|
54
50
|
children.each do |child|
|
@@ -76,38 +72,26 @@ module Opal
|
|
76
72
|
end
|
77
73
|
|
78
74
|
# Compiles a hash without kwsplats
|
79
|
-
# with complex keys.
|
75
|
+
# with simple or complex keys.
|
80
76
|
def compile_hash
|
81
|
-
helper :hash
|
82
|
-
|
83
77
|
children.each_with_index do |pair, idx|
|
84
78
|
key, value = pair.children
|
85
79
|
push ', ' unless idx == 0
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
# Compiles a hash without kwsplats
|
93
|
-
# and containing **only** string/symbols as keys.
|
94
|
-
def compile_hash2
|
95
|
-
hash_obj, hash_keys = {}, []
|
96
|
-
helper :hash2
|
97
|
-
|
98
|
-
keys.size.times do |idx|
|
99
|
-
key = keys[idx].children[0].to_s.inspect
|
100
|
-
hash_keys << key unless hash_obj.include? key
|
101
|
-
hash_obj[key] = expr(values[idx])
|
80
|
+
if %i[sym str].include?(key.type)
|
81
|
+
push "[#{key.children[0].to_s.inspect}", ', ', expr(value), ']'
|
82
|
+
else
|
83
|
+
push '[', expr(key), ', ', expr(value), ']'
|
84
|
+
end
|
102
85
|
end
|
103
86
|
|
104
|
-
|
105
|
-
push '
|
106
|
-
|
107
|
-
|
87
|
+
if keys.empty?
|
88
|
+
push '(new Map())'
|
89
|
+
elsif simple_keys?
|
90
|
+
wrap '(new Map([', ']))'
|
91
|
+
else
|
92
|
+
helper :hash_rehash
|
93
|
+
wrap '$hash_rehash(new Map([', ']))'
|
108
94
|
end
|
109
|
-
|
110
|
-
wrap "$hash2([#{hash_keys.join ', '}], {", '})'
|
111
95
|
end
|
112
96
|
end
|
113
97
|
|
data/lib/opal/nodes/if.rb
CHANGED
@@ -392,45 +392,53 @@ module Opal
|
|
392
392
|
end
|
393
393
|
end
|
394
394
|
|
395
|
-
class
|
396
|
-
|
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
|
-
|
411
|
-
|
412
|
-
|
413
|
-
|
414
|
-
push "
|
415
|
-
|
416
|
-
|
417
|
-
push "
|
418
|
-
|
419
|
-
|
420
|
-
push "
|
421
|
-
|
422
|
-
|
423
|
-
push "})
|
424
|
-
|
425
|
-
|
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
|
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
|
-
#
|
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
|
data/lib/opal/nodes/literal.rb
CHANGED
@@ -5,14 +5,10 @@ require 'opal/nodes/base'
|
|
5
5
|
module Opal
|
6
6
|
module Nodes
|
7
7
|
class ValueNode < Base
|
8
|
-
handle :true, :false, :
|
8
|
+
handle :true, :false, :nil
|
9
9
|
|
10
10
|
def compile
|
11
|
-
|
12
|
-
push scope.self
|
13
|
-
else
|
14
|
-
push type.to_s
|
15
|
-
end
|
11
|
+
push type.to_s
|
16
12
|
end
|
17
13
|
|
18
14
|
def self.truthy_optimize?
|
@@ -20,6 +16,14 @@ module Opal
|
|
20
16
|
end
|
21
17
|
end
|
22
18
|
|
19
|
+
class SelfNode < Base
|
20
|
+
handle :self
|
21
|
+
|
22
|
+
def compile
|
23
|
+
push scope.self
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
23
27
|
class NumericNode < Base
|
24
28
|
handle :int, :float
|
25
29
|
|
@@ -158,11 +162,15 @@ module Opal
|
|
158
162
|
case value
|
159
163
|
when ''
|
160
164
|
push('/(?:)/')
|
161
|
-
when /\(
|
165
|
+
when /\(\?[(<>#]|[*+?]\+/
|
162
166
|
# Safari/WebKit will not execute javascript code if it contains a lookbehind literal RegExp
|
163
167
|
# and they fail with "Syntax Error". This tricks their parser by disguising the literal RegExp
|
164
168
|
# as string for the dynamic $regexp helper. Safari/Webkit will still fail to execute the RegExp,
|
165
169
|
# but at least they will parse and run everything else.
|
170
|
+
#
|
171
|
+
# Also, let's compile a couple of more patterns into $regexp calls, as there are many syntax
|
172
|
+
# errors in RubySpec when ran in reverse, while there shouldn't be (they should be catchable
|
173
|
+
# errors) - at least since Node 17.
|
166
174
|
static_as_dynamic(value)
|
167
175
|
else
|
168
176
|
push "#{Regexp.new(value).inspect}#{flags.join}"
|
data/lib/opal/nodes/rescue.rb
CHANGED
data/lib/opal/nodes/x_string.rb
CHANGED
@@ -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)
|
data/lib/opal/parser/patch.rb
CHANGED
@@ -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
|
-
|
41
|
-
|
38
|
+
def on_for(node)
|
39
|
+
loop_variable, loop_range, loop_body = *node
|
42
40
|
|
43
|
-
#
|
44
|
-
|
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
|
-
#
|
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
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
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
|
-
|
57
|
+
private
|
62
58
|
|
63
|
-
|
64
|
-
|
65
|
-
|
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
|
-
|
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
|
data/lib/opal/source_map/file.rb
CHANGED
@@ -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] -
|
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
data/opal/corelib/array/pack.rb
CHANGED
data/opal/corelib/array.rb
CHANGED
@@ -1,4 +1,5 @@
|
|
1
|
-
# helpers: truthy, falsy,
|
1
|
+
# helpers: truthy, falsy, yield1, hash_get, hash_put, hash_delete, coerce_to, respond_to, deny_frozen_access, freeze, opal32_init, opal32_add
|
2
|
+
# backtick_javascript: true
|
2
3
|
|
3
4
|
require 'corelib/enumerable'
|
4
5
|
require 'corelib/numeric'
|
@@ -68,6 +69,29 @@ 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
|
+
}
|
79
|
+
|
80
|
+
function fast_push(arr, objects) {
|
81
|
+
// push.apply() for arrays longer than 32767 may cause various argument errors in browsers
|
82
|
+
// but it is significantly faster than a for loop, which pushes each element separately
|
83
|
+
// but apply() has a overhead by itself, for a small number of elements
|
84
|
+
// the for loop is significantly faster
|
85
|
+
// this is using the best option depending on objects.length
|
86
|
+
var length = objects.length;
|
87
|
+
if (length > 6 && length < 32767) {
|
88
|
+
arr.push.apply(arr, objects);
|
89
|
+
} else {
|
90
|
+
for (var i = 0; i < length; i++) {
|
91
|
+
arr.push(objects[i]);
|
92
|
+
}
|
93
|
+
}
|
94
|
+
}
|
71
95
|
}
|
72
96
|
|
73
97
|
def self.[](*objects)
|
@@ -91,7 +115,7 @@ class ::Array < `Array`
|
|
91
115
|
}
|
92
116
|
|
93
117
|
if (arguments.length === 0) {
|
94
|
-
self.splice(0, self.length);
|
118
|
+
if (self.length > 0) self.splice(0, self.length);
|
95
119
|
return self;
|
96
120
|
}
|
97
121
|
|
@@ -135,13 +159,13 @@ class ::Array < `Array`
|
|
135
159
|
end
|
136
160
|
|
137
161
|
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
162
|
%x{
|
163
|
+
other = convertToArray(other)
|
164
|
+
|
165
|
+
if (self.length === 0 || other.length === 0) {
|
166
|
+
return [];
|
167
|
+
}
|
168
|
+
|
145
169
|
var result = [], hash = #{{}}, i, length, item;
|
146
170
|
|
147
171
|
for (i = 0, length = other.length; i < length; i++) {
|
@@ -160,11 +184,7 @@ class ::Array < `Array`
|
|
160
184
|
end
|
161
185
|
|
162
186
|
def |(other)
|
163
|
-
other =
|
164
|
-
other.to_a
|
165
|
-
else
|
166
|
-
`$coerce_to(other, #{::Array}, 'to_ary')`.to_a
|
167
|
-
end
|
187
|
+
other = `convertToArray(other)`
|
168
188
|
|
169
189
|
%x{
|
170
190
|
var hash = #{{}}, i, length, item;
|
@@ -203,21 +223,13 @@ class ::Array < `Array`
|
|
203
223
|
end
|
204
224
|
|
205
225
|
def +(other)
|
206
|
-
other =
|
207
|
-
other.to_a
|
208
|
-
else
|
209
|
-
`$coerce_to(other, #{::Array}, 'to_ary')`.to_a
|
210
|
-
end
|
226
|
+
other = `convertToArray(other)`
|
211
227
|
|
212
228
|
`self.concat(other)`
|
213
229
|
end
|
214
230
|
|
215
231
|
def -(other)
|
216
|
-
other =
|
217
|
-
other.to_a
|
218
|
-
else
|
219
|
-
`$coerce_to(other, #{::Array}, 'to_ary')`.to_a
|
220
|
-
end
|
232
|
+
other = `convertToArray(other)`
|
221
233
|
|
222
234
|
return [] if `self.length === 0`
|
223
235
|
return `self.slice()` if `other.length === 0`
|
@@ -257,7 +269,7 @@ class ::Array < `Array`
|
|
257
269
|
end
|
258
270
|
|
259
271
|
%x{
|
260
|
-
if (#{
|
272
|
+
if (#{self} === #{other}) {
|
261
273
|
return 0;
|
262
274
|
}
|
263
275
|
|
@@ -696,11 +708,12 @@ class ::Array < `Array`
|
|
696
708
|
return enum_for(:collect) { size } unless block_given?
|
697
709
|
|
698
710
|
%x{
|
699
|
-
var
|
711
|
+
var length = self.length;
|
712
|
+
var result = new Array(length);
|
700
713
|
|
701
|
-
for (var i = 0
|
714
|
+
for (var i = 0; i < length; i++) {
|
702
715
|
var value = $yield1(block, self[i]);
|
703
|
-
result
|
716
|
+
result[i] = value;
|
704
717
|
}
|
705
718
|
|
706
719
|
return result;
|
@@ -849,11 +862,7 @@ class ::Array < `Array`
|
|
849
862
|
`$deny_frozen_access(self)`
|
850
863
|
|
851
864
|
others = others.map do |other|
|
852
|
-
other =
|
853
|
-
other.to_a
|
854
|
-
else
|
855
|
-
`$coerce_to(other, #{::Array}, 'to_ary')`.to_a
|
856
|
-
end
|
865
|
+
`other = convertToArray(other)`
|
857
866
|
|
858
867
|
if other.equal?(self)
|
859
868
|
other = other.dup
|
@@ -1223,7 +1232,7 @@ class ::Array < `Array`
|
|
1223
1232
|
result.push(ary);
|
1224
1233
|
break;
|
1225
1234
|
default:
|
1226
|
-
|
1235
|
+
fast_push(result, _flatten(ary, level - 1));
|
1227
1236
|
}
|
1228
1237
|
}
|
1229
1238
|
return result;
|
@@ -1267,27 +1276,31 @@ class ::Array < `Array`
|
|
1267
1276
|
`$freeze(self)`
|
1268
1277
|
end
|
1269
1278
|
|
1279
|
+
`var $hash_ids`
|
1280
|
+
|
1270
1281
|
def hash
|
1271
1282
|
%x{
|
1272
1283
|
var top = ($hash_ids === undefined),
|
1273
|
-
result =
|
1284
|
+
result = $opal32_init(),
|
1274
1285
|
hash_id = self.$object_id(),
|
1275
1286
|
item, i, key;
|
1276
1287
|
|
1277
|
-
|
1278
|
-
|
1279
|
-
$hash_ids = Object.create(null);
|
1280
|
-
}
|
1288
|
+
result = $opal32_add(result, 0xA);
|
1289
|
+
result = $opal32_add(result, self.length);
|
1281
1290
|
|
1282
|
-
|
1283
|
-
|
1284
|
-
|
1285
|
-
|
1291
|
+
if (top) {
|
1292
|
+
$hash_ids = Object.create(null);
|
1293
|
+
}
|
1294
|
+
// return early for recursive structures
|
1295
|
+
else if ($hash_ids[hash_id]) {
|
1296
|
+
return $opal32_add(result, 0x01010101);
|
1297
|
+
}
|
1286
1298
|
|
1299
|
+
try {
|
1287
1300
|
for (key in $hash_ids) {
|
1288
1301
|
item = $hash_ids[key];
|
1289
1302
|
if (#{eql?(`item`)}) {
|
1290
|
-
return
|
1303
|
+
return $opal32_add(result, 0x01010101);
|
1291
1304
|
}
|
1292
1305
|
}
|
1293
1306
|
|
@@ -1295,10 +1308,10 @@ class ::Array < `Array`
|
|
1295
1308
|
|
1296
1309
|
for (i = 0; i < self.length; i++) {
|
1297
1310
|
item = self[i];
|
1298
|
-
result
|
1311
|
+
result = $opal32_add(result, item.$hash());
|
1299
1312
|
}
|
1300
1313
|
|
1301
|
-
return result
|
1314
|
+
return result;
|
1302
1315
|
} finally {
|
1303
1316
|
if (top) {
|
1304
1317
|
$hash_ids = undefined;
|
@@ -1410,11 +1423,54 @@ class ::Array < `Array`
|
|
1410
1423
|
end
|
1411
1424
|
|
1412
1425
|
def intersection(*arrays)
|
1413
|
-
|
1426
|
+
%x{
|
1427
|
+
if (arrays.length === 0) {
|
1428
|
+
return #{to_a.dup};
|
1429
|
+
}
|
1430
|
+
arrays = arrays.map(convertToArray);
|
1431
|
+
if (self.length === 0) {
|
1432
|
+
return [];
|
1433
|
+
}
|
1434
|
+
}
|
1435
|
+
|
1436
|
+
arrays = arrays.sort_by(&:length)
|
1437
|
+
# When self is the smallest among the arrays
|
1438
|
+
if `self.length < arrays[0].length`
|
1439
|
+
return arrays.reduce(self, &:&)
|
1440
|
+
end
|
1441
|
+
|
1442
|
+
# First, calculate intersection of argument arrays.
|
1443
|
+
# Array#& is faster when the argument size is small.
|
1444
|
+
# So `largest & shortest & second_shortest & ...` would be the fastest.
|
1445
|
+
largest = `arrays.pop()`
|
1446
|
+
intersection_of_args = arrays.reduce(largest, &:&)
|
1447
|
+
|
1448
|
+
# self array must come last to maintain the order
|
1449
|
+
self & intersection_of_args
|
1414
1450
|
end
|
1415
1451
|
|
1416
1452
|
def intersect?(other)
|
1417
|
-
|
1453
|
+
%x{
|
1454
|
+
var small, large, hash = #{{}}, i, length;
|
1455
|
+
if (self.length < other.length) {
|
1456
|
+
small = self;
|
1457
|
+
large = other;
|
1458
|
+
} else {
|
1459
|
+
small = other;
|
1460
|
+
large = self;
|
1461
|
+
}
|
1462
|
+
|
1463
|
+
for (i = 0, length = small.length; i < length; i++) {
|
1464
|
+
$hash_put(hash, small[i], true);
|
1465
|
+
}
|
1466
|
+
|
1467
|
+
for (i = 0, length = large.length; i < length; i++) {
|
1468
|
+
if ($hash_get(hash, large[i])) {
|
1469
|
+
return true;
|
1470
|
+
}
|
1471
|
+
}
|
1472
|
+
return false;
|
1473
|
+
}
|
1418
1474
|
end
|
1419
1475
|
|
1420
1476
|
def join(sep = nil)
|
@@ -1705,9 +1761,7 @@ class ::Array < `Array`
|
|
1705
1761
|
%x{
|
1706
1762
|
$deny_frozen_access(self);
|
1707
1763
|
|
1708
|
-
|
1709
|
-
self.push(objects[i]);
|
1710
|
-
}
|
1764
|
+
fast_push(self, objects);
|
1711
1765
|
}
|
1712
1766
|
|
1713
1767
|
self
|
@@ -1762,15 +1816,11 @@ class ::Array < `Array`
|
|
1762
1816
|
def replace(other)
|
1763
1817
|
`$deny_frozen_access(self)`
|
1764
1818
|
|
1765
|
-
other =
|
1766
|
-
other.to_a
|
1767
|
-
else
|
1768
|
-
`$coerce_to(other, #{::Array}, 'to_ary')`.to_a
|
1769
|
-
end
|
1819
|
+
other = `convertToArray(other)`
|
1770
1820
|
|
1771
1821
|
%x{
|
1772
|
-
self.splice(0, self.length);
|
1773
|
-
|
1822
|
+
if (self.length > 0) self.splice(0, self.length);
|
1823
|
+
fast_push(self, other);
|
1774
1824
|
}
|
1775
1825
|
|
1776
1826
|
self
|
@@ -2284,10 +2334,10 @@ class ::Array < `Array`
|
|
2284
2334
|
for (i = 0; i < len; i++) {
|
2285
2335
|
ary = #{::Opal.coerce_to?(`array[i]`, ::Array, :to_ary)};
|
2286
2336
|
if (!ary.$$is_array) {
|
2287
|
-
#{::Kernel.raise ::TypeError, "wrong element type #{`
|
2337
|
+
#{::Kernel.raise ::TypeError, "wrong element type #{`array[i]`.class} at #{`i`} (expected array)"}
|
2288
2338
|
}
|
2289
2339
|
if (ary.length !== 2) {
|
2290
|
-
#{::Kernel.raise ::ArgumentError, "wrong array length at #{`i`} (expected 2, was #{`ary`.length})"}
|
2340
|
+
#{::Kernel.raise ::ArgumentError, "element has wrong array length at #{`i`} (expected 2, was #{`ary`.length})"}
|
2291
2341
|
}
|
2292
2342
|
key = ary[0];
|
2293
2343
|
val = ary[1];
|
@@ -2305,11 +2355,7 @@ class ::Array < `Array`
|
|
2305
2355
|
max = nil
|
2306
2356
|
|
2307
2357
|
each do |row|
|
2308
|
-
row =
|
2309
|
-
row.to_a
|
2310
|
-
else
|
2311
|
-
`$coerce_to(row, #{::Array}, 'to_ary')`.to_a
|
2312
|
-
end
|
2358
|
+
`row = convertToArray(row)`
|
2313
2359
|
|
2314
2360
|
max ||= `row.length`
|
2315
2361
|
|