opal 1.2.0 → 1.3.0.alpha1

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 (159) hide show
  1. checksums.yaml +4 -4
  2. data/.eslintrc.await.js +6 -0
  3. data/.eslintrc.js +34 -0
  4. data/.github/workflows/build.yml +8 -0
  5. data/.rubocop.yml +9 -0
  6. data/CHANGELOG.md +4 -0
  7. data/README.md +1 -1
  8. data/Rakefile +1 -0
  9. data/UNRELEASED.md +64 -38
  10. data/docs/async.md +109 -0
  11. data/docs/roda-sprockets.md +0 -2
  12. data/exe/opal +2 -0
  13. data/exe/opal-repl +2 -2
  14. data/lib/opal/builder.rb +5 -1
  15. data/lib/opal/builder_processors.rb +7 -2
  16. data/lib/opal/cache/file_cache.rb +119 -0
  17. data/lib/opal/cache.rb +71 -0
  18. data/lib/opal/cli.rb +35 -1
  19. data/lib/opal/cli_options.rb +21 -0
  20. data/lib/opal/cli_runners/chrome.rb +21 -14
  21. data/lib/opal/cli_runners/chrome_cdp_interface.js +30285 -0
  22. data/lib/opal/cli_runners/{chrome.js → chrome_cdp_interface.rb} +27 -6
  23. data/lib/opal/cli_runners/compiler.rb +2 -1
  24. data/lib/opal/cli_runners/gjs.rb +27 -0
  25. data/lib/opal/cli_runners/mini_racer.rb +36 -0
  26. data/lib/opal/cli_runners/source-map-support-browser.js +276 -91
  27. data/lib/opal/cli_runners/source-map-support-node.js +276 -91
  28. data/lib/opal/cli_runners/source-map-support.js +60 -18
  29. data/lib/opal/cli_runners.rb +2 -0
  30. data/lib/opal/compiler.rb +99 -10
  31. data/lib/opal/fragment.rb +77 -14
  32. data/lib/opal/nodes/args/extract_kwrestarg.rb +6 -4
  33. data/lib/opal/nodes/args/extract_restarg.rb +10 -12
  34. data/lib/opal/nodes/args.rb +28 -0
  35. data/lib/opal/nodes/base.rb +29 -5
  36. data/lib/opal/nodes/call.rb +123 -2
  37. data/lib/opal/nodes/case.rb +7 -1
  38. data/lib/opal/nodes/class.rb +12 -2
  39. data/lib/opal/nodes/def.rb +3 -23
  40. data/lib/opal/nodes/definitions.rb +21 -4
  41. data/lib/opal/nodes/helpers.rb +2 -2
  42. data/lib/opal/nodes/if.rb +39 -9
  43. data/lib/opal/nodes/iter.rb +15 -3
  44. data/lib/opal/nodes/lambda.rb +3 -1
  45. data/lib/opal/nodes/literal.rb +13 -7
  46. data/lib/opal/nodes/logic.rb +2 -2
  47. data/lib/opal/nodes/module.rb +12 -2
  48. data/lib/opal/nodes/rescue.rb +59 -34
  49. data/lib/opal/nodes/scope.rb +88 -6
  50. data/lib/opal/nodes/super.rb +52 -25
  51. data/lib/opal/nodes/top.rb +13 -7
  52. data/lib/opal/nodes/while.rb +7 -1
  53. data/lib/opal/parser/patch.rb +2 -1
  54. data/lib/opal/repl.rb +137 -49
  55. data/lib/opal/rewriters/binary_operator_assignment.rb +10 -10
  56. data/lib/opal/rewriters/block_to_iter.rb +3 -3
  57. data/lib/opal/rewriters/for_rewriter.rb +7 -7
  58. data/lib/opal/rewriters/js_reserved_words.rb +5 -3
  59. data/lib/opal/source_map/file.rb +7 -4
  60. data/lib/opal/source_map/map.rb +17 -3
  61. data/lib/opal/version.rb +1 -1
  62. data/opal/corelib/array.rb +2 -2
  63. data/opal/corelib/binding.rb +46 -0
  64. data/opal/corelib/boolean.rb +54 -4
  65. data/opal/corelib/class.rb +2 -0
  66. data/opal/corelib/constants.rb +2 -2
  67. data/opal/corelib/error.rb +98 -12
  68. data/opal/corelib/io.rb +250 -38
  69. data/opal/corelib/kernel/format.rb +5 -2
  70. data/opal/corelib/kernel.rb +44 -23
  71. data/opal/corelib/main.rb +5 -0
  72. data/opal/corelib/method.rb +1 -0
  73. data/opal/corelib/module.rb +28 -0
  74. data/opal/corelib/number.rb +12 -1
  75. data/opal/corelib/random/seedrandom.js.rb +2 -2
  76. data/opal/corelib/regexp.rb +47 -3
  77. data/opal/corelib/runtime.js +152 -12
  78. data/opal/corelib/string/encoding.rb +17 -17
  79. data/opal/corelib/string.rb +2 -0
  80. data/opal/corelib/struct.rb +10 -3
  81. data/opal/corelib/trace_point.rb +57 -0
  82. data/opal/opal/full.rb +2 -0
  83. data/package.json +3 -2
  84. data/spec/filters/bugs/array.rb +0 -1
  85. data/spec/filters/bugs/basicobject.rb +0 -1
  86. data/spec/filters/bugs/binding.rb +27 -0
  87. data/spec/filters/bugs/enumerator.rb +132 -0
  88. data/spec/filters/bugs/exception.rb +70 -93
  89. data/spec/filters/bugs/float.rb +0 -1
  90. data/spec/filters/bugs/kernel.rb +3 -9
  91. data/spec/filters/bugs/language.rb +15 -58
  92. data/spec/filters/bugs/main.rb +16 -0
  93. data/spec/filters/bugs/matrix.rb +39 -0
  94. data/spec/filters/bugs/method.rb +0 -2
  95. data/spec/filters/bugs/module.rb +36 -79
  96. data/spec/filters/bugs/proc.rb +0 -1
  97. data/spec/filters/bugs/regexp.rb +0 -16
  98. data/spec/filters/bugs/trace_point.rb +12 -0
  99. data/spec/filters/bugs/warnings.rb +0 -4
  100. data/spec/filters/unsupported/freeze.rb +2 -0
  101. data/spec/filters/unsupported/privacy.rb +4 -0
  102. data/spec/lib/compiler_spec.rb +7 -1
  103. data/spec/lib/repl_spec.rb +4 -2
  104. data/spec/lib/source_map/file_spec.rb +1 -1
  105. data/spec/mspec-opal/formatters.rb +18 -4
  106. data/spec/mspec-opal/runner.rb +2 -2
  107. data/spec/opal/core/boolean_spec.rb +44 -0
  108. data/spec/opal/core/hash_spec.rb +8 -0
  109. data/spec/opal/core/number/to_s_spec.rb +11 -0
  110. data/spec/opal/stdlib/json/ext_spec.rb +3 -3
  111. data/spec/opal/stdlib/logger/logger_spec.rb +10 -1
  112. data/spec/ruby_specs +18 -0
  113. data/stdlib/await.rb +83 -0
  114. data/stdlib/base64.rb +4 -4
  115. data/stdlib/bigdecimal/bignumber.js.rb +4 -2
  116. data/stdlib/bigdecimal.rb +1 -0
  117. data/stdlib/gjs/io.rb +33 -0
  118. data/stdlib/gjs/kernel.rb +5 -0
  119. data/stdlib/gjs.rb +2 -0
  120. data/stdlib/js.rb +4 -0
  121. data/stdlib/json.rb +3 -3
  122. data/stdlib/logger.rb +1 -1
  123. data/stdlib/nashorn/file.rb +2 -0
  124. data/stdlib/nodejs/env.rb +7 -0
  125. data/stdlib/nodejs/file.rb +6 -41
  126. data/stdlib/nodejs/io.rb +21 -5
  127. data/stdlib/nodejs/js-yaml-3-6-1.js +2 -2
  128. data/stdlib/opal/miniracer.rb +6 -0
  129. data/stdlib/opal/platform.rb +4 -0
  130. data/stdlib/opal/repl_js.rb +5 -0
  131. data/stdlib/opal/replutils.rb +271 -0
  132. data/stdlib/opal-parser.rb +24 -11
  133. data/stdlib/opal-platform.rb +8 -0
  134. data/stdlib/promise/v2.rb +16 -4
  135. data/stdlib/promise.rb +14 -0
  136. data/stdlib/stringio.rb +13 -110
  137. data/stdlib/thread.rb +29 -0
  138. data/tasks/building.rake +10 -4
  139. data/tasks/linting-parse-eslint-results.js +39 -0
  140. data/tasks/linting.rake +38 -28
  141. data/tasks/performance/asciidoctor_test.rb.erb +6 -0
  142. data/tasks/performance/optimization_status.rb +77 -0
  143. data/tasks/performance.rake +149 -0
  144. data/tasks/testing.rake +9 -1
  145. data/test/nodejs/test_await.rb +169 -0
  146. data/test/opal/promisev2/test_error.rb +9 -3
  147. data/test/opal/unsupported_and_bugs.rb +5 -0
  148. data/vendored-minitest/minitest/benchmark.rb +9 -7
  149. data/vendored-minitest/minitest/test.rb +14 -12
  150. data/vendored-minitest/minitest.rb +19 -16
  151. data/yarn.lock +686 -117
  152. metadata +60 -23
  153. data/.jshintrc +0 -41
  154. data/spec/filters/unsupported/refinements.rb +0 -8
  155. data/vendored-minitest/minitest/hell.rb +0 -11
  156. data/vendored-minitest/minitest/parallel.rb +0 -65
  157. data/vendored-minitest/minitest/pride.rb +0 -4
  158. data/vendored-minitest/minitest/pride_plugin.rb +0 -142
  159. data/vendored-minitest/minitest/unit.rb +0 -45
data/lib/opal/repl.rb CHANGED
@@ -2,17 +2,18 @@
2
2
 
3
3
  require 'opal'
4
4
  require 'securerandom'
5
+ require 'stringio'
6
+ require 'fileutils'
5
7
 
6
8
  module Opal
7
9
  class REPL
8
10
  HISTORY_PATH = File.expand_path('~/.opal-repl-history')
9
11
 
12
+ attr_accessor :colorize
13
+
10
14
  def initialize
11
- begin
12
- require 'mini_racer'
13
- rescue LoadError
14
- abort 'opal-repl depends on mini_racer gem, which is not currently installed'
15
- end
15
+ @argv = []
16
+ @colorize = true
16
17
 
17
18
  begin
18
19
  require 'readline'
@@ -20,80 +21,154 @@ module Opal
20
21
  abort 'opal-repl depends on readline, which is not currently available'
21
22
  end
22
23
 
23
- MiniRacer::Platform.set_flags! :harmony
24
-
24
+ begin
25
+ FileUtils.touch(HISTORY_PATH)
26
+ rescue
27
+ nil
28
+ end
25
29
  @history = File.exist?(HISTORY_PATH)
26
30
  end
27
31
 
28
- def run(filename = nil)
32
+ def run(argv = [])
33
+ @argv = argv
34
+
35
+ savepoint = save_tty
29
36
  load_opal
30
- load_file(filename) if filename
31
37
  load_history
32
38
  run_input_loop
33
39
  ensure
34
40
  dump_history
35
- end
36
-
37
- def load_file(filename)
38
- raise "file does not exist: #{filename}" unless File.exist? filename
39
- eval_ruby File.read(filename)
40
- end
41
-
42
- # A polyfill so that SecureRandom works in repl correctly.
43
- def random_bytes(bytes)
44
- ::SecureRandom.bytes(bytes).split('').map(&:ord)
41
+ restore_tty(savepoint)
45
42
  end
46
43
 
47
44
  def load_opal
48
- v8.attach('console.log', method(:puts).to_proc)
49
- v8.attach('console.warn', method(:warn).to_proc)
50
- v8.attach('crypto.randomBytes', method(:random_bytes).to_proc)
51
- v8.eval Opal::Builder.new.build('opal').to_s
52
- v8.attach('Opal.exit', method(:exit).to_proc)
53
- end
54
-
55
- def run_line(line)
56
- result = eval_ruby(line)
57
- puts "=> #{result}"
45
+ runner = @argv.reject { |i| i == '--repl' }
46
+ runner += ['-e', 'require "opal/repl_js"']
47
+ runner = %w[bundle exec opal] + runner
48
+
49
+ @pipe = IO.popen(runner, 'r+',
50
+ # What I try to achieve here: let the runner ignore
51
+ # interrupts. Those should be handled by a supervisor.
52
+ pgroup: true,
53
+ new_pgroup: true,
54
+ )
58
55
  end
59
56
 
60
57
  def run_input_loop
61
- # on SIGINT lets just return from the loop..
62
- previous_trap = trap('SIGINT') { return }
63
-
64
58
  while (line = readline)
65
- run_line(line)
59
+ eval_ruby(line)
66
60
  end
67
-
61
+ rescue Interrupt
62
+ @incomplete = nil
63
+ retry
68
64
  ensure
69
- trap('SIGINT', previous_trap || 'DEFAULT')
65
+ finish
70
66
  end
71
67
 
72
- private
68
+ def finish
69
+ @pipe.close
70
+ rescue
71
+ nil
72
+ end
73
73
 
74
74
  def eval_ruby(code)
75
75
  builder = Opal::Builder.new
76
- builder.build_str(code, '(irb)', irb: true, const_missing: true)
77
- builder.processed[0...-1].each { |js_code| eval_js js_code.to_s }
76
+ silencer = Silencer.new
77
+
78
+ code = "#{@incomplete}#{code}"
79
+ if code.start_with? 'ls '
80
+ eval_code = code[3..-1]
81
+ mode = :ls
82
+ elsif code == 'ls'
83
+ eval_code = 'self'
84
+ mode = :ls
85
+ elsif code.start_with? 'show '
86
+ eval_code = code[5..-1]
87
+ mode = :show
88
+ else
89
+ eval_code = code
90
+ mode = :inspect
91
+ end
92
+
93
+ begin
94
+ silencer.silence do
95
+ builder.build_str(eval_code, '(irb)', irb: true, const_missing: true)
96
+ end
97
+ @incomplete = nil
98
+ rescue Opal::SyntaxError => e
99
+ if LINEBREAKS.include?(e.message)
100
+ @incomplete = "#{code}\n"
101
+ else
102
+ @incomplete = nil
103
+ if silencer.warnings.empty?
104
+ warn e.full_message
105
+ else
106
+ # Most likely a parser error
107
+ warn silencer.warnings
108
+ end
109
+ end
110
+ return
111
+ end
112
+ builder.processed[0...-1].each { |js_code| eval_js(:silent, js_code.to_s) }
78
113
  last_processed_file = builder.processed.last.to_s
79
- eval_js <<-JS
80
- var $_result = #{last_processed_file};
81
- $_result.$inspect()
82
- JS
83
- rescue => e
84
- puts "#{e.message}\n\t#{e.backtrace.join("\n\t")}"
114
+
115
+ if mode == :show
116
+ puts last_processed_file
117
+ return
118
+ end
119
+
120
+ eval_js(mode, last_processed_file)
121
+ rescue Interrupt, SystemExit => e
122
+ raise e
123
+ rescue Exception => e # rubocop:disable Lint/RescueException
124
+ puts e.full_message(highlight: true)
85
125
  end
86
126
 
87
- def eval_js(code)
88
- v8.eval(code)
127
+ private
128
+
129
+ LINEBREAKS = [
130
+ 'unexpected token $end',
131
+ 'unterminated string meets end of file'
132
+ ].freeze
133
+
134
+ class Silencer
135
+ def initialize
136
+ @stderr = $stderr
137
+ end
138
+
139
+ def silence
140
+ @collector = StringIO.new
141
+ $stderr = @collector
142
+ yield
143
+ ensure
144
+ $stderr = @stderr
145
+ end
146
+
147
+ def warnings
148
+ @collector.string
149
+ end
89
150
  end
90
151
 
91
- def v8
92
- @v8 ||= MiniRacer::Context.new
152
+ def eval_js(mode, code)
153
+ obj = { mode: mode, code: code, colors: colorize }.to_json
154
+ @pipe.puts obj
155
+ while (line = @pipe.readline)
156
+ break if line.chomp == '<<<ready>>>'
157
+ puts line
158
+ end
159
+ rescue Interrupt => e
160
+ # A child stopped responding... let's create a new one
161
+ warn "* Killing #{@pipe.pid}"
162
+ Process.kill('-KILL', @pipe.pid)
163
+ load_opal
164
+ raise e
165
+ rescue EOFError, Errno::EPIPE
166
+ exit $?.exitstatus
93
167
  end
94
168
 
95
169
  def readline
96
- Readline.readline '>> ', true
170
+ prompt = @incomplete ? '.. ' : '>> '
171
+ Readline.readline prompt, true
97
172
  end
98
173
 
99
174
  def load_history
@@ -106,5 +181,18 @@ module Opal
106
181
  length = Readline::HISTORY.size > 1000 ? 1000 : Readline::HISTORY.size
107
182
  File.write(HISTORY_PATH, Readline::HISTORY.to_a[-length..-1].join("\n"))
108
183
  end
184
+
185
+ # How do we support Win32?
186
+ def save_tty
187
+ %x{stty -g}.chomp
188
+ rescue
189
+ nil
190
+ end
191
+
192
+ def restore_tty(savepoint)
193
+ system('stty', savepoint)
194
+ rescue
195
+ nil
196
+ end
109
197
  end
110
198
  end
@@ -16,11 +16,11 @@ module Opal
16
16
  end
17
17
 
18
18
  GET_SET = ->(get_type, set_type) {
19
- ->(lhs, operation, rhs) {
20
- get_node = lhs.updated(get_type) # lhs
21
- set_node = s(:send, get_node, operation, rhs) # lhs + rhs
19
+ ->(node, lhs, operation, rhs) {
20
+ get_node = lhs.updated(get_type) # lhs
21
+ set_node = node.updated(:send, [get_node, operation, rhs]) # lhs + rhs
22
22
 
23
- lhs.updated(set_type, [*lhs, set_node]) # lhs = lhs + rhs
23
+ lhs.updated(set_type, [*lhs, set_node]) # lhs = lhs + rhs
24
24
  }
25
25
  }
26
26
 
@@ -48,7 +48,7 @@ module Opal
48
48
  # Produces `recvr.meth = recvr.meth + rhs`
49
49
  # (lhs is a recvr.meth, op is :+)
50
50
  class SendHandler < self
51
- def self.call(lhs, operation, rhs)
51
+ def self.call(node, lhs, operation, rhs)
52
52
  recvr, reader_method, *args = *lhs
53
53
 
54
54
  # If recvr is a complex expression it must be cached.
@@ -62,11 +62,11 @@ module Opal
62
62
  writer_method = :"#{reader_method}="
63
63
 
64
64
  call_reader = lhs.updated(:send, [recvr, reader_method, *args]) # $tmp.meth
65
- call_op = s(:send, call_reader, operation, rhs) # $tmp.meth + rhs
65
+ call_op = node.updated(:send, [call_reader, operation, rhs]) # $tmp.meth + rhs
66
66
  call_writer = lhs.updated(:send, [recvr, writer_method, *args, call_op]) # $tmp.meth = $tmp.meth + rhs
67
67
 
68
68
  if cache_recvr
69
- s(:begin, cache_recvr, call_writer)
69
+ node.updated(:begin, [cache_recvr, call_writer])
70
70
  else
71
71
  call_writer
72
72
  end
@@ -78,7 +78,7 @@ module Opal
78
78
  # NOTE: Later output of this handler gets post-processed by this rewriter again
79
79
  # using SendHandler to `recvr.nil? ? nil : (recvr.meth = recvr.meth + rhs)`
80
80
  class ConditionalSendHandler < self
81
- def self.call(lhs, operation, rhs)
81
+ def self.call(node, lhs, operation, rhs)
82
82
  recvr, meth, *args = *lhs
83
83
 
84
84
  recvr_tmp = new_temp
@@ -87,7 +87,7 @@ module Opal
87
87
 
88
88
  recvr_is_nil = s(:send, recvr, :nil?) # recvr.nil?
89
89
  plain_send = lhs.updated(:send, [recvr, meth, *args]) # recvr.meth
90
- plain_op_asgn = s(:op_asgn, plain_send, operation, rhs) # recvr.meth += rhs
90
+ plain_op_asgn = node.updated(:op_asgn, [plain_send, operation, rhs]) # recvr.meth += rhs
91
91
 
92
92
  s(:begin,
93
93
  cache_recvr,
@@ -116,7 +116,7 @@ module Opal
116
116
 
117
117
  result = HANDLERS
118
118
  .fetch(lhs.type) { error "cannot handle LHS type: #{lhs.type}" }
119
- .call(lhs, op, rhs)
119
+ .call(node, lhs, op, rhs)
120
120
 
121
121
  process(result)
122
122
  end
@@ -6,11 +6,11 @@ module Opal
6
6
  module Rewriters
7
7
  class BlockToIter < Base
8
8
  def on_block(node)
9
- recvr, args, body = *super
9
+ recvr, args, body = *node
10
10
  iter_node = s(:iter, args, body)
11
- recvr.updated(
11
+ process recvr.updated(
12
12
  nil,
13
- recvr.children + [iter_node],
13
+ (recvr.children + [iter_node]),
14
14
  )
15
15
  end
16
16
  end
@@ -52,7 +52,7 @@ module Opal
52
52
  loop_variable_assignment = case loop_variable.type
53
53
  when :mlhs # multiple left-hand statement like in "for i,j in [[1, 2], [3, 4]]"
54
54
  # i, j = __jstmp
55
- s(:masgn, loop_variable, get_tmp_loop_variable)
55
+ loop_variable.updated(:masgn, [loop_variable, get_tmp_loop_variable])
56
56
  else # single argument like "for i in (0..3)"
57
57
  # i = __jstmp
58
58
  loop_variable << get_tmp_loop_variable
@@ -60,13 +60,13 @@ module Opal
60
60
 
61
61
  loop_body = prepend_to_body(loop_body, loop_variable_assignment)
62
62
 
63
- node = s(:send, iterating_value, :each, # (0..3).each {
64
- s(:iter, s(:args, s(:arg, tmp_loop_variable)), # |__jstmp|
65
- process(loop_body)
66
- )
67
- ) # i = __jstmp; j = i + 1 }
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
+ )
68
68
 
69
- s(:begin, *outer_assigns, node)
69
+ node.updated(:begin, [*outer_assigns, node])
70
70
  end
71
71
 
72
72
  class LocalVariableAssigns < Base
@@ -86,9 +86,9 @@ module Opal
86
86
  super(node)
87
87
  end
88
88
 
89
- # Restarg is a special case
90
- # because it may have no name
91
- # def m(*); end
89
+ # Restarg and kwrestarg are special cases
90
+ # because they may have no name
91
+ # def m(*, **); end
92
92
  def on_restarg(node)
93
93
  name, _ = *node
94
94
 
@@ -99,6 +99,8 @@ module Opal
99
99
  node
100
100
  end
101
101
 
102
+ alias on_kwrestarg on_restarg
103
+
102
104
  def on_argument(node)
103
105
  node = super(node)
104
106
  name, value = *node
@@ -7,11 +7,12 @@ class Opal::SourceMap::File
7
7
  attr_reader :file
8
8
  attr_reader :source
9
9
 
10
- def initialize(fragments, file, source)
10
+ def initialize(fragments, file, source, generated_code = nil)
11
11
  @fragments = fragments
12
12
  @file = file
13
13
  @source = source
14
14
  @names_map = Hash.new { |hash, name| hash[name] = hash.size }
15
+ @generated_code = generated_code
15
16
  @absolute_mappings = nil
16
17
  end
17
18
 
@@ -98,8 +99,10 @@ class Opal::SourceMap::File
98
99
  # field, in which case the whole value is represented.
99
100
  def segment_from_fragment(fragment, generated_column)
100
101
  source_index = 0 # always 0, we're dealing with a single file
101
- original_line = fragment.line - 1 # fragments have 1-based lines
102
- original_column = fragment.column # fragments have 0-based columns
102
+ original_line = (fragment.line || 0) - 1 # fragments have 1-based lines
103
+ original_line = 0 if original_line < 0 # line 0 (-1) for fragments in source maps will crash
104
+ # browsers devtools and the webpack build process
105
+ original_column = fragment.column || 0 # fragments have 0-based columns
103
106
 
104
107
  if fragment.source_map_name
105
108
  map_name_index = (@names_map[fragment.source_map_name.to_s] ||= @names_map.size)
@@ -162,7 +165,7 @@ class Opal::SourceMap::File
162
165
  generated_column = 0
163
166
  segments = []
164
167
  raw_segments.each do |(generated_code, fragment)|
165
- if fragment.line && fragment.column
168
+ unless fragment.is_a?(Opal::Fragment) && fragment.skip_source_map?
166
169
  segments << segment_from_fragment(fragment, generated_column)
167
170
  end
168
171
  generated_column += generated_code.size
@@ -5,11 +5,11 @@ require 'json'
5
5
 
6
6
  module Opal::SourceMap::Map
7
7
  def to_h
8
- map
8
+ @to_h || map
9
9
  end
10
10
 
11
11
  def to_json
12
- map.to_json
12
+ to_h.to_json
13
13
  end
14
14
 
15
15
  def as_json(*)
@@ -17,10 +17,24 @@ module Opal::SourceMap::Map
17
17
  end
18
18
 
19
19
  def to_s
20
- map.to_s
20
+ to_h.to_s
21
21
  end
22
22
 
23
23
  def to_data_uri_comment
24
24
  "//# sourceMappingURL=data:application/json;base64,#{Base64.encode64(to_json).delete("\n")}"
25
25
  end
26
+
27
+ # Marshaling for cache shortpath
28
+ def cache
29
+ @to_h ||= map
30
+ self
31
+ end
32
+
33
+ def marshal_dump
34
+ [to_h, generated_code]
35
+ end
36
+
37
+ def marshal_load(value)
38
+ @to_h, @generated_code = value
39
+ end
26
40
  end
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.2.0'
6
+ VERSION = '1.3.0.alpha1'
7
7
  end
@@ -647,8 +647,8 @@ class Array < `Array`
647
647
  self
648
648
  end
649
649
 
650
- def count(object = nil, &block)
651
- if object || block
650
+ def count(object = undefined, &block)
651
+ if `object !== undefined` || block
652
652
  super
653
653
  else
654
654
  size
@@ -0,0 +1,46 @@
1
+ class Binding
2
+ # @private
3
+ def initialize(jseval, scope_variables, receiver, source_location)
4
+ @jseval, @scope_variables, @receiver, @source_location = \
5
+ jseval, scope_variables, receiver, source_location
6
+ end
7
+
8
+ def js_eval(*args)
9
+ @jseval.call(*args)
10
+ end
11
+
12
+ def local_variable_get(symbol)
13
+ js_eval(symbol)
14
+ rescue Exception
15
+ raise NameError, "local variable `#{symbol}' is not defined for #{inspect}"
16
+ end
17
+
18
+ def local_variable_set(symbol, value)
19
+ js_eval(symbol, value)
20
+ end
21
+
22
+ def local_variables
23
+ @scope_variables
24
+ end
25
+
26
+ def local_variable_defined?(value)
27
+ @scope_variables.include?(value)
28
+ end
29
+
30
+ def eval(str, file = nil, line = nil)
31
+ return receiver if str == 'self'
32
+
33
+ Kernel.eval(str, self, file, line)
34
+ end
35
+
36
+ attr_reader :receiver, :source_location
37
+ end
38
+
39
+ module Kernel
40
+ def binding
41
+ raise "Opal doesn't support dynamic calls to binding"
42
+ end
43
+ end
44
+
45
+ TOPLEVEL_BINDING = binding
46
+ `#{TOPLEVEL_BINDING}.source_location = ["<main>", 0]`
@@ -1,6 +1,31 @@
1
1
  class Boolean < `Boolean`
2
2
  `Opal.defineProperty(self.$$prototype, '$$is_boolean', true)`
3
- `Opal.defineProperty(self.$$prototype, '$$meta', #{self})`
3
+
4
+ %x{
5
+ var properties = ['$$class', '$$meta'];
6
+
7
+ for (var i = 0; i < properties.length; i++) {
8
+ Object.defineProperty(self.$$prototype, properties[i], {
9
+ configurable: true,
10
+ enumerable: false,
11
+ get: function() {
12
+ return this == true ? Opal.TrueClass :
13
+ this == false ? Opal.FalseClass :
14
+ Opal.Boolean;
15
+ }
16
+ });
17
+ }
18
+
19
+ Object.defineProperty(self.$$prototype, "$$id", {
20
+ configurable: true,
21
+ enumerable: false,
22
+ get: function() {
23
+ return this == true ? 2 :
24
+ this == false ? 0 :
25
+ nil;
26
+ }
27
+ });
28
+ }
4
29
 
5
30
  class << self
6
31
  def allocate
@@ -40,13 +65,15 @@ class Boolean < `Boolean`
40
65
  alias eql? ==
41
66
 
42
67
  def singleton_class
43
- Boolean
68
+ `self.$$meta`
44
69
  end
45
70
 
46
71
  def to_s
47
72
  `(self == true) ? 'true' : 'false'`
48
73
  end
49
74
 
75
+ alias inspect to_s
76
+
50
77
  def dup
51
78
  self
52
79
  end
@@ -54,10 +81,33 @@ class Boolean < `Boolean`
54
81
  def clone(freeze: true)
55
82
  self
56
83
  end
84
+
85
+ # See: https://github.com/opal/opal/issues/2230
86
+ #
87
+ # This is a hack that allows you to add methods to TrueClass and FalseClass.
88
+ # Do note, that while true and false have a correct $$class (it's either
89
+ # TrueClass or FalseClass), their prototype is `Boolean.$$prototype`, which
90
+ # basically means that when calling `true.something` we actually call
91
+ # `Boolean#something` instead of `TrueClass#something`. So using
92
+ # method_missing we dispatch it to `TrueClass/FalseClass#something` correctly.
93
+ #
94
+ # The downside is that a correct implementation would also allow us to override
95
+ # the methods defined on Boolean, but our implementation doesn't allow that,
96
+ # unless you define them on Boolean and not on TrueClass/FalseClass.
97
+ def method_missing(method, *args, &block)
98
+ `var body = self.$$class.$$prototype['$' + #{method}]`
99
+ super unless `typeof body !== 'undefined' && !body.$$stub`
100
+ `Opal.send(self, body, #{args}, #{block})`
101
+ end
102
+
103
+ def respond_to_missing?(method, _include_all = false)
104
+ `var body = self.$$class.$$prototype['$' + #{method}]`
105
+ `typeof body !== 'undefined' && !body.$$stub`
106
+ end
57
107
  end
58
108
 
59
- TrueClass = Boolean
60
- FalseClass = Boolean
109
+ class TrueClass < Boolean; end
110
+ class FalseClass < Boolean; end
61
111
 
62
112
  TRUE = true
63
113
  FALSE = false
@@ -60,4 +60,6 @@ class Class
60
60
  return #{super()};
61
61
  }
62
62
  end
63
+
64
+ alias inspect to_s
63
65
  end
@@ -1,8 +1,8 @@
1
1
  RUBY_PLATFORM = 'opal'
2
2
  RUBY_ENGINE = 'opal'
3
3
  RUBY_VERSION = '3.0.2'
4
- RUBY_ENGINE_VERSION = '1.2.0'
5
- RUBY_RELEASE_DATE = '2021-07-28'
4
+ RUBY_ENGINE_VERSION = '1.3.0.alpha1'
5
+ RUBY_RELEASE_DATE = '2021-09-29'
6
6
  RUBY_PATCHLEVEL = 0
7
7
  RUBY_REVISION = '0'
8
8
  RUBY_COPYRIGHT = 'opal - Copyright (C) 2013-2021 Adam Beynon and the Opal contributors'