opal 1.2.0 → 1.3.0.alpha1

Sign up to get free protection for your applications and to get access to all the features.
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'