opal 1.1.0 → 1.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (125) hide show
  1. checksums.yaml +4 -4
  2. data/.codeclimate.yml +4 -4
  3. data/.github/ISSUE_TEMPLATE/bug-report.md +47 -0
  4. data/.github/ISSUE_TEMPLATE/feature_request.md +20 -0
  5. data/.github/workflows/build.yml +11 -5
  6. data/.gitignore +1 -0
  7. data/.jshintrc +1 -1
  8. data/.rubocop.yml +2 -1
  9. data/CHANGELOG.md +95 -1
  10. data/Gemfile +0 -4
  11. data/HACKING.md +1 -1
  12. data/README.md +19 -15
  13. data/UNRELEASED.md +37 -96
  14. data/benchmark-ips/bm_array_unshift.rb +7 -0
  15. data/bin/build-browser-source-map-support +2 -3
  16. data/bin/opal-mspec +2 -0
  17. data/docs/compiler.md +1 -1
  18. data/examples/rack/Gemfile +0 -1
  19. data/examples/rack/Gemfile.lock +0 -4
  20. data/lib/opal/cli.rb +1 -0
  21. data/lib/opal/cli_options.rb +4 -0
  22. data/lib/opal/cli_runners/nodejs.rb +5 -1
  23. data/lib/opal/cli_runners/source-map-support-browser.js +8 -2
  24. data/lib/opal/cli_runners/source-map-support-node.js +3706 -0
  25. data/lib/opal/cli_runners/source-map-support.js +3 -1
  26. data/lib/opal/compiler.rb +2 -2
  27. data/lib/opal/nodes/args/arity_check.rb +1 -0
  28. data/lib/opal/nodes/args/parameters.rb +6 -0
  29. data/lib/opal/nodes/class.rb +1 -13
  30. data/lib/opal/nodes/literal.rb +14 -7
  31. data/lib/opal/nodes/module.rb +13 -9
  32. data/lib/opal/nodes/variables.rb +13 -4
  33. data/lib/opal/nodes/while.rb +54 -17
  34. data/lib/opal/parser.rb +1 -5
  35. data/lib/opal/parser/patch.rb +44 -0
  36. data/lib/opal/repl.rb +7 -0
  37. data/lib/opal/rewriter.rb +4 -0
  38. data/lib/opal/rewriters/arguments.rb +4 -1
  39. data/lib/opal/rewriters/forward_args.rb +54 -0
  40. data/lib/opal/rewriters/logical_operator_assignment.rb +5 -2
  41. data/lib/opal/rewriters/opal_engine_check.rb +5 -7
  42. data/lib/opal/rewriters/pattern_matching.rb +287 -0
  43. data/lib/opal/version.rb +1 -1
  44. data/opal/corelib/array.rb +42 -20
  45. data/opal/corelib/array/pack.rb +6 -1
  46. data/opal/corelib/complex.rb +2 -0
  47. data/opal/corelib/constants.rb +3 -3
  48. data/opal/corelib/hash.rb +45 -38
  49. data/opal/corelib/module.rb +2 -7
  50. data/opal/corelib/number.rb +2 -180
  51. data/opal/corelib/numeric.rb +156 -0
  52. data/opal/corelib/object_space.rb +102 -0
  53. data/opal/corelib/pattern_matching.rb +159 -0
  54. data/opal/corelib/random.rb +31 -66
  55. data/opal/corelib/random/formatter.rb +122 -0
  56. data/opal/corelib/range.rb +50 -19
  57. data/opal/corelib/runtime.js +82 -21
  58. data/opal/corelib/string.rb +86 -52
  59. data/opal/corelib/string/encoding.rb +140 -25
  60. data/opal/corelib/string/unpack.rb +26 -40
  61. data/opal/opal.rb +1 -0
  62. data/opal/opal/full.rb +2 -0
  63. data/package.json +1 -1
  64. data/spec/filters/bugs/array.rb +0 -23
  65. data/spec/filters/bugs/basicobject.rb +3 -0
  66. data/spec/filters/bugs/encoding.rb +0 -2
  67. data/spec/filters/bugs/exception.rb +1 -0
  68. data/spec/filters/bugs/float.rb +0 -2
  69. data/spec/filters/bugs/hash.rb +3 -13
  70. data/spec/filters/bugs/integer.rb +0 -2
  71. data/spec/filters/bugs/kernel.rb +16 -3
  72. data/spec/filters/bugs/language.rb +27 -90
  73. data/spec/filters/bugs/marshal.rb +1 -3
  74. data/spec/filters/bugs/module.rb +16 -1
  75. data/spec/filters/bugs/numeric.rb +4 -12
  76. data/spec/filters/bugs/objectspace.rb +67 -0
  77. data/spec/filters/bugs/pack_unpack.rb +0 -9
  78. data/spec/filters/bugs/pathname.rb +1 -0
  79. data/spec/filters/bugs/proc.rb +8 -0
  80. data/spec/filters/bugs/random.rb +3 -6
  81. data/spec/filters/bugs/range.rb +83 -113
  82. data/spec/filters/bugs/set.rb +2 -0
  83. data/spec/filters/bugs/string.rb +32 -70
  84. data/spec/filters/bugs/struct.rb +2 -10
  85. data/spec/filters/bugs/time.rb +8 -2
  86. data/spec/filters/unsupported/float.rb +3 -0
  87. data/spec/filters/unsupported/freeze.rb +1 -0
  88. data/spec/filters/unsupported/integer.rb +3 -0
  89. data/spec/filters/unsupported/refinements.rb +8 -0
  90. data/spec/filters/unsupported/string.rb +100 -95
  91. data/spec/filters/unsupported/time.rb +4 -0
  92. data/spec/lib/compiler_spec.rb +16 -0
  93. data/spec/lib/rewriters/forward_args_spec.rb +61 -0
  94. data/spec/lib/rewriters/logical_operator_assignment_spec.rb +1 -1
  95. data/spec/lib/rewriters/numblocks_spec.rb +44 -0
  96. data/spec/lib/rewriters/opal_engine_check_spec.rb +49 -4
  97. data/spec/opal/core/language/forward_args_spec.rb +53 -0
  98. data/spec/opal/core/language/infinite_range_spec.rb +13 -0
  99. data/spec/opal/core/language/memoization_spec.rb +16 -0
  100. data/spec/opal/core/language/pattern_matching_spec.rb +124 -0
  101. data/spec/opal/core/module_spec.rb +38 -2
  102. data/spec/opal/core/number/to_i_spec.rb +28 -0
  103. data/spec/opal/core/runtime/bridged_classes_spec.rb +16 -0
  104. data/spec/opal/core/runtime/constants_spec.rb +20 -1
  105. data/spec/opal/core/string/subclassing_spec.rb +16 -0
  106. data/spec/opal/core/string/unpack_spec.rb +22 -0
  107. data/spec/opal/core/string_spec.rb +4 -4
  108. data/spec/ruby_specs +4 -1
  109. data/stdlib/json.rb +3 -1
  110. data/stdlib/promise/v1.rb +1 -0
  111. data/stdlib/promise/v2.rb +386 -0
  112. data/stdlib/securerandom.rb +55 -35
  113. data/tasks/releasing.rake +1 -1
  114. data/tasks/testing.rake +6 -4
  115. data/test/nodejs/test_string.rb +25 -0
  116. data/test/opal/promisev2/test_always.rb +63 -0
  117. data/test/opal/promisev2/test_error.rb +16 -0
  118. data/test/opal/promisev2/test_rescue.rb +59 -0
  119. data/test/opal/promisev2/test_then.rb +90 -0
  120. data/test/opal/promisev2/test_trace.rb +52 -0
  121. data/test/opal/promisev2/test_value.rb +16 -0
  122. data/test/opal/promisev2/test_when.rb +35 -0
  123. data/vendored-minitest/minitest/assertions.rb +2 -0
  124. metadata +47 -8
  125. data/lib/opal/parser/with_c_lexer.rb +0 -15
@@ -0,0 +1,54 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'opal/rewriters/base'
4
+
5
+ module Opal
6
+ module Rewriters
7
+ class ForwardArgs < Base
8
+ def on_forward_args(_node)
9
+ process(
10
+ s(:args, s(:forward_arg, :"$"))
11
+ )
12
+ end
13
+
14
+ def on_args(node)
15
+ if node.children.last && node.children.last.type == :forward_arg
16
+ prev_children = node.children[0..-2]
17
+
18
+ node.updated(nil,
19
+ [
20
+ *prev_children,
21
+ s(:restarg, '$fwd_rest'),
22
+ s(:blockarg, '$fwd_block')
23
+ ]
24
+ )
25
+ else
26
+ super
27
+ end
28
+ end
29
+
30
+ def on_send(node)
31
+ if node.children.last &&
32
+ node.children.last.class != Symbol &&
33
+ node.children.last.type == :forwarded_args
34
+
35
+ prev_children = node.children[0..-2]
36
+
37
+ node.updated(nil,
38
+ [
39
+ *prev_children,
40
+ s(:splat,
41
+ s(:lvar, '$fwd_rest')
42
+ ),
43
+ s(:block_pass,
44
+ s(:lvar, '$fwd_block')
45
+ )
46
+ ]
47
+ )
48
+ else
49
+ super
50
+ end
51
+ end
52
+ end
53
+ end
54
+ end
@@ -20,7 +20,7 @@ module Opal
20
20
  get_node = lhs.updated(get_type) # lhs
21
21
  condition_node = s(root_type, get_node, rhs) # lhs || rhs
22
22
 
23
- if get_type == :const && root_type == :or
23
+ if %i[const cvar].include?(get_type) && root_type == :or
24
24
  # defined?(lhs)
25
25
  defined_node = s(:defined?, get_node)
26
26
  # LHS = defined?(LHS) ? (LHS || rhs) : rhs
@@ -51,7 +51,10 @@ module Opal
51
51
  GlobalVariableHandler = GET_SET[:gvar, :gvasgn]
52
52
 
53
53
  # Takes `@@lhs ||= rhs`
54
- # Produces `@@lhs = @@lhs || rhs`
54
+ # Produces `@@lhs = defined?(@@lhs) ? (@@lhs || rhs) : rhs`
55
+ #
56
+ # Takes `@@lhs &&= rhs`
57
+ # Produces `@@lhs = @@lhs && rhs`
55
58
  ClassVariableHandler = GET_SET[:cvar, :cvasgn]
56
59
 
57
60
  # Takes `recvr.meth ||= rhs`
@@ -9,14 +9,12 @@ module Opal
9
9
  test, true_body, false_body = *node.children
10
10
 
11
11
  if skip_check_present?(test)
12
- false_body = s(:nil)
12
+ process(true_body || s(:nil))
13
+ elsif skip_check_present_not?(test)
14
+ process(false_body || s(:nil))
15
+ else
16
+ super
13
17
  end
14
-
15
- if skip_check_present_not?(test)
16
- true_body = s(:nil)
17
- end
18
-
19
- node.updated(nil, process_all([test, true_body, false_body]))
20
18
  end
21
19
 
22
20
  def skip_check_present?(test)
@@ -0,0 +1,287 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'opal/rewriters/base'
4
+
5
+ module Opal
6
+ module Rewriters
7
+ class PatternMatching < Base
8
+ def initialize
9
+ @depth = 0
10
+ super
11
+ end
12
+
13
+ # a => b
14
+ def on_match_pattern(node)
15
+ from, pat = *node
16
+
17
+ s(:begin,
18
+ s(:lvasgn, :"$pmvar", from),
19
+ s(:if,
20
+ convert_full_pattern(from, pat),
21
+ nil,
22
+ raise_no_matching_pattern_error(:"$pmvar")
23
+ )
24
+ )
25
+ end
26
+
27
+ # a in b
28
+ def on_match_pattern_p(node)
29
+ from, pat = *node
30
+
31
+ s(:if,
32
+ convert_full_pattern(from, pat),
33
+ s(:true),
34
+ s(:false)
35
+ )
36
+ end
37
+
38
+ # case a; in b; end
39
+ def on_case_match(node)
40
+ @depth += 1
41
+
42
+ cmvar = :"$cmvar#{@depth}"
43
+
44
+ from, *cases, els = *node
45
+
46
+ if els
47
+ process els
48
+ else
49
+ els = raise_no_matching_pattern_error(cmvar)
50
+ end
51
+
52
+ s(:begin,
53
+ s(:lvasgn, cmvar, from),
54
+ single_case_match(cmvar, *cases, els)
55
+ )
56
+ end
57
+
58
+ private
59
+
60
+ # raise NoMatchingPatternError, from
61
+ def raise_no_matching_pattern_error(from)
62
+ s(:send, nil, :raise,
63
+ s(:const, nil, :NoMatchingPatternError),
64
+ s(:lvar, from)
65
+ )
66
+ end
67
+
68
+ # in b
69
+ def single_case_match(from, *cases, els)
70
+ cas = cases.shift
71
+ pat, if_guard, body = *cas
72
+
73
+ pat = convert_full_pattern(from, pat)
74
+ if if_guard
75
+ guard, = *if_guard
76
+ case if_guard.type
77
+ when :if_guard
78
+ pat = s(:and, pat, guard)
79
+ when :unless_guard
80
+ pat = s(:and, pat, s(:send, guard, :!))
81
+ end
82
+ end
83
+
84
+ s(:if,
85
+ pat,
86
+ process(body),
87
+ if !cases.empty?
88
+ single_case_match(from, *cases, els)
89
+ elsif els != s(:empty_else)
90
+ els
91
+ end
92
+ )
93
+ end
94
+
95
+ def convert_full_pattern(from, pat)
96
+ if from.class == Symbol
97
+ from = s(:lvar, from)
98
+ end
99
+
100
+ converter = PatternConverter.new(pat)
101
+ converter.run!
102
+
103
+ # a, b, c = ::PatternMatching.(from, [...])
104
+ s(:masgn,
105
+ s(:mlhs,
106
+ *converter.variables
107
+ ),
108
+ s(:send,
109
+ s(:const, s(:cbase), :PatternMatching),
110
+ :call,
111
+ from,
112
+ converter.pattern,
113
+ )
114
+ )
115
+ end
116
+
117
+ class PatternConverter < ::Opal::Rewriters::Base
118
+ def initialize(pat)
119
+ @pat = pat
120
+ @variables = []
121
+ end
122
+
123
+ def run!
124
+ @outpat = process(@pat)
125
+ end
126
+
127
+ def pattern
128
+ @outpat
129
+ end
130
+
131
+ def variables
132
+ @variables.map { |i| s(:lvasgn, i) }
133
+ end
134
+
135
+ # a
136
+ def on_match_var(node)
137
+ var, = *node
138
+
139
+ @variables << var
140
+
141
+ s(:sym, :var)
142
+ end
143
+
144
+ # [...] => a
145
+ def on_match_as(node)
146
+ pat, save = *node
147
+
148
+ process(save)
149
+ array(s(:sym, :save), process(pat))
150
+ end
151
+
152
+ def on_literal(node)
153
+ array(s(:sym, :lit), node)
154
+ end
155
+
156
+ alias on_int on_literal
157
+ alias on_float on_literal
158
+ alias on_complex on_literal
159
+ alias on_rational on_literal
160
+ alias on_array on_literal
161
+ alias on_str on_literal
162
+ alias on_dstr on_literal
163
+ alias on_xstr on_literal
164
+ alias on_sym on_literal
165
+ alias on_irange on_literal
166
+ alias on_erange on_literal
167
+ alias on_const on_literal
168
+ alias on_regexp on_literal
169
+ alias on_lambda on_literal
170
+ alias on_begin on_literal
171
+
172
+ # ^a
173
+ def on_pin(node)
174
+ on_literal(node.children.first)
175
+ end
176
+
177
+ # *
178
+ def on_match_rest(node)
179
+ if node.children.empty?
180
+ array(s(:sym, :rest))
181
+ else
182
+ array(s(:sym, :rest), process(node.children.first))
183
+ end
184
+ end
185
+
186
+ # {} | []
187
+ def on_match_alt(node)
188
+ array(s(:sym, :any), *node.children.map(&method(:process)))
189
+ end
190
+
191
+ # MyStructName
192
+ def on_const_pattern(node)
193
+ array(s(:sym, :all), *node.children.map(&method(:process)))
194
+ end
195
+
196
+ # [0, 1, 2] or [*, 0, 1] or [0, 1, *]
197
+ def on_array_pattern(node, tail = false)
198
+ children = *node
199
+ children << s(:match_rest) if tail
200
+
201
+ fixed_size = true
202
+ array_size = 0
203
+
204
+ children = children.each do |i|
205
+ case i.type
206
+ when :match_rest
207
+ fixed_size = false
208
+ else
209
+ array_size += 1
210
+ end
211
+ end
212
+
213
+ array(
214
+ s(:sym, :array),
215
+ to_ast(fixed_size),
216
+ to_ast(array_size),
217
+ to_ast(children.map(&method(:process)))
218
+ )
219
+ end
220
+
221
+ # [0, 1, 2,]
222
+ def on_array_pattern_with_tail(node)
223
+ on_array_pattern(node, true)
224
+ end
225
+
226
+ # {a:, b:}
227
+ def on_hash_pattern(node)
228
+ children = *node
229
+
230
+ any_size = children.empty? ? to_ast(false) : to_ast(true)
231
+
232
+ children = children.map do |i|
233
+ case i.type
234
+ when :pair
235
+ array(i.children[0], process(i.children[1]))
236
+ when :match_var
237
+ array(s(:sym, i.children[0]), process(i))
238
+ when :match_nil_pattern
239
+ any_size = to_ast(false)
240
+ nil
241
+ when :match_rest
242
+ # Capturing rest?
243
+ if i.children.first
244
+ any_size = process(i.children.first)
245
+ else
246
+ any_size = to_ast(true)
247
+ end
248
+ nil
249
+ end
250
+ end.compact
251
+
252
+ array(s(:sym, :hash), any_size, array(*children))
253
+ end
254
+
255
+ # [*, a, b, *]
256
+ def on_find_pattern(node)
257
+ children = *node
258
+
259
+ children = children.map(&method(:process))
260
+
261
+ array(s(:sym, :find), array(*children))
262
+ end
263
+
264
+ private
265
+
266
+ def array(*args)
267
+ to_ast(args)
268
+ end
269
+
270
+ def to_ast(val)
271
+ case val
272
+ when Array
273
+ s(:array, *val)
274
+ when Integer
275
+ s(:int, val)
276
+ when true
277
+ s(:true)
278
+ when false
279
+ s(:false)
280
+ when nil
281
+ s(:nil)
282
+ end
283
+ end
284
+ end
285
+ end
286
+ end
287
+ 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.1.0'
6
+ VERSION = '1.2.0'
7
7
  end
@@ -196,7 +196,7 @@ class Array < `Array`
196
196
  result = result.concat(converted);
197
197
  }
198
198
 
199
- return toArraySubclass(result, #{self.class});
199
+ return result;
200
200
  }
201
201
  end
202
202
 
@@ -361,7 +361,7 @@ class Array < `Array`
361
361
  }
362
362
 
363
363
  result = self.slice(from, to);
364
- return toArraySubclass(result, self.$class());
364
+ return result;
365
365
  }
366
366
 
367
367
  function $array_slice_index_length(self, index, length) {
@@ -394,7 +394,7 @@ class Array < `Array`
394
394
 
395
395
  result = self.slice(index, index + length);
396
396
  }
397
- return toArraySubclass(result, self.$class());
397
+ return result;
398
398
  }
399
399
  }
400
400
 
@@ -883,7 +883,9 @@ class Array < `Array`
883
883
  self
884
884
  end
885
885
 
886
- alias difference -
886
+ def difference(*arrays)
887
+ arrays.reduce(to_a.dup) { |a, b| a - b }
888
+ end
887
889
 
888
890
  def dig(idx, *idxs)
889
891
  item = self[idx]
@@ -1180,7 +1182,7 @@ class Array < `Array`
1180
1182
  level = $coerce_to(level, #{Integer}, 'to_int');
1181
1183
  }
1182
1184
 
1183
- return toArraySubclass(_flatten(self, level), #{self.class});
1185
+ return _flatten(self, level);
1184
1186
  }
1185
1187
  end
1186
1188
 
@@ -1335,7 +1337,9 @@ class Array < `Array`
1335
1337
  }
1336
1338
  end
1337
1339
 
1338
- alias intersection &
1340
+ def intersection(*arrays)
1341
+ arrays.reduce(to_a.dup) { |a, b| a & b }
1342
+ end
1339
1343
 
1340
1344
  def join(sep = nil)
1341
1345
  return '' if `self.length === 0`
@@ -2165,10 +2169,19 @@ class Array < `Array`
2165
2169
  end
2166
2170
 
2167
2171
  def to_a
2168
- self
2172
+ %x{
2173
+ if (self.$$class === Opal.Array) {
2174
+ return self;
2175
+ }
2176
+ else {
2177
+ return Opal.Array.$new(self);
2178
+ }
2179
+ }
2169
2180
  end
2170
2181
 
2171
- alias to_ary to_a
2182
+ def to_ary
2183
+ self
2184
+ end
2172
2185
 
2173
2186
  def to_h(&block)
2174
2187
  array = self
@@ -2224,7 +2237,9 @@ class Array < `Array`
2224
2237
  result
2225
2238
  end
2226
2239
 
2227
- alias union |
2240
+ def union(*arrays)
2241
+ arrays.reduce(uniq) { |a, b| a | b }
2242
+ end
2228
2243
 
2229
2244
  def uniq(&block)
2230
2245
  %x{
@@ -2248,7 +2263,7 @@ class Array < `Array`
2248
2263
  }
2249
2264
  }
2250
2265
 
2251
- return toArraySubclass(#{`hash`.values}, #{self.class});
2266
+ return #{`hash`.values};
2252
2267
  }
2253
2268
  end
2254
2269
 
@@ -2276,12 +2291,23 @@ class Array < `Array`
2276
2291
 
2277
2292
  def unshift(*objects)
2278
2293
  %x{
2279
- for (var i = objects.length - 1; i >= 0; i--) {
2280
- self.unshift(objects[i]);
2294
+ var selfLength = self.length
2295
+ var objectsLength = objects.length
2296
+ if (objectsLength == 0) return self;
2297
+ var index = selfLength - objectsLength
2298
+ for (var i = 0; i < objectsLength; i++) {
2299
+ self.push(self[index + i])
2300
+ }
2301
+ var len = selfLength - 1
2302
+ while (len - objectsLength >= 0) {
2303
+ self[len] = self[len - objectsLength]
2304
+ len--
2305
+ }
2306
+ for (var j = 0; j < objectsLength; j++) {
2307
+ self[j] = objects[j]
2281
2308
  }
2309
+ return self;
2282
2310
  }
2283
-
2284
- self
2285
2311
  end
2286
2312
 
2287
2313
  alias prepend unshift
@@ -2332,12 +2358,8 @@ class Array < `Array`
2332
2358
  if (o.$$is_array) {
2333
2359
  continue;
2334
2360
  }
2335
- if (o.$$is_enumerator) {
2336
- if (o.$size() === Infinity) {
2337
- others[j] = o.$take(size);
2338
- } else {
2339
- others[j] = o.$to_a();
2340
- }
2361
+ if (o.$$is_range || o.$$is_enumerator) {
2362
+ others[j] = o.$take(size);
2341
2363
  continue;
2342
2364
  }
2343
2365
  others[j] = #{(