opal 1.5.1 → 1.6.0.rc1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (142) hide show
  1. checksums.yaml +4 -4
  2. data/.gitattributes +4 -0
  3. data/.github/workflows/build.yml +17 -3
  4. data/HACKING.md +23 -0
  5. data/README.md +3 -3
  6. data/UNRELEASED.md +47 -0
  7. data/benchmark/run.rb +1 -0
  8. data/docs/compiled_ruby.md +8 -0
  9. data/docs/compiler.md +1 -1
  10. data/docs/compiler_directives.md +1 -1
  11. data/docs/getting_started.md +17 -0
  12. data/docs/headless_chrome.md +1 -1
  13. data/docs/index.md +123 -0
  14. data/docs/jquery.md +5 -5
  15. data/docs/templates.md +37 -37
  16. data/docs/unsupported_features.md +0 -4
  17. data/lib/opal/builder.rb +59 -39
  18. data/lib/opal/builder_processors.rb +24 -0
  19. data/lib/opal/builder_scheduler/prefork.rb +262 -0
  20. data/lib/opal/builder_scheduler/sequential.rb +13 -0
  21. data/lib/opal/builder_scheduler.rb +29 -0
  22. data/lib/opal/cache/file_cache.rb +13 -2
  23. data/lib/opal/cli.rb +36 -19
  24. data/lib/opal/cli_options.rb +4 -0
  25. data/lib/opal/cli_runners/chrome.rb +17 -13
  26. data/lib/opal/cli_runners/chrome_cdp_interface.rb +19 -2
  27. data/lib/opal/cli_runners/compiler.rb +1 -1
  28. data/lib/opal/cli_runners/gjs.rb +3 -1
  29. data/lib/opal/cli_runners/mini_racer.rb +5 -3
  30. data/lib/opal/cli_runners/nodejs.rb +3 -3
  31. data/lib/opal/cli_runners/server.rb +13 -28
  32. data/lib/opal/cli_runners/system_runner.rb +5 -3
  33. data/lib/opal/cli_runners.rb +7 -6
  34. data/lib/opal/compiler.rb +25 -2
  35. data/lib/opal/config.rb +10 -0
  36. data/lib/opal/eof_content.rb +5 -2
  37. data/lib/opal/nodes/args/ensure_kwargs_are_kwargs.rb +2 -6
  38. data/lib/opal/nodes/args/extract_kwarg.rb +3 -4
  39. data/lib/opal/nodes/args/extract_kwargs.rb +3 -1
  40. data/lib/opal/nodes/args/extract_kwoptarg.rb +1 -1
  41. data/lib/opal/nodes/args/extract_kwrestarg.rb +4 -1
  42. data/lib/opal/nodes/args/extract_optarg.rb +1 -1
  43. data/lib/opal/nodes/args/extract_post_arg.rb +1 -1
  44. data/lib/opal/nodes/args/extract_post_optarg.rb +1 -1
  45. data/lib/opal/nodes/args/extract_restarg.rb +2 -2
  46. data/lib/opal/nodes/args/initialize_iterarg.rb +1 -1
  47. data/lib/opal/nodes/args/initialize_shadowarg.rb +1 -1
  48. data/lib/opal/nodes/args/prepare_post_args.rb +4 -2
  49. data/lib/opal/nodes/base.rb +14 -3
  50. data/lib/opal/nodes/call.rb +13 -16
  51. data/lib/opal/nodes/class.rb +3 -1
  52. data/lib/opal/nodes/closure.rb +250 -0
  53. data/lib/opal/nodes/def.rb +7 -11
  54. data/lib/opal/nodes/definitions.rb +4 -2
  55. data/lib/opal/nodes/if.rb +12 -2
  56. data/lib/opal/nodes/iter.rb +11 -17
  57. data/lib/opal/nodes/logic.rb +15 -63
  58. data/lib/opal/nodes/module.rb +3 -1
  59. data/lib/opal/nodes/rescue.rb +23 -15
  60. data/lib/opal/nodes/scope.rb +7 -1
  61. data/lib/opal/nodes/top.rb +27 -4
  62. data/lib/opal/nodes/while.rb +42 -26
  63. data/lib/opal/nodes.rb +1 -0
  64. data/lib/opal/os.rb +59 -0
  65. data/lib/opal/rewriter.rb +2 -0
  66. data/lib/opal/rewriters/returnable_logic.rb +14 -0
  67. data/lib/opal/rewriters/thrower_finder.rb +90 -0
  68. data/lib/opal/simple_server.rb +12 -6
  69. data/lib/opal/source_map/file.rb +4 -3
  70. data/lib/opal/source_map/map.rb +9 -1
  71. data/lib/opal/util.rb +1 -1
  72. data/lib/opal/version.rb +1 -1
  73. data/opal/corelib/array.rb +68 -3
  74. data/opal/corelib/basic_object.rb +1 -0
  75. data/opal/corelib/comparable.rb +1 -1
  76. data/opal/corelib/complex.rb +1 -0
  77. data/opal/corelib/constants.rb +2 -2
  78. data/opal/corelib/enumerable.rb +4 -2
  79. data/opal/corelib/enumerator/chain.rb +4 -0
  80. data/opal/corelib/enumerator/generator.rb +5 -3
  81. data/opal/corelib/enumerator/lazy.rb +3 -1
  82. data/opal/corelib/enumerator/yielder.rb +2 -4
  83. data/opal/corelib/enumerator.rb +3 -1
  84. data/opal/corelib/error/errno.rb +3 -1
  85. data/opal/corelib/error.rb +13 -2
  86. data/opal/corelib/hash.rb +39 -1
  87. data/opal/corelib/io.rb +1 -1
  88. data/opal/corelib/kernel.rb +56 -5
  89. data/opal/corelib/module.rb +60 -4
  90. data/opal/corelib/proc.rb +8 -5
  91. data/opal/corelib/rational.rb +1 -0
  92. data/opal/corelib/regexp.rb +15 -1
  93. data/opal/corelib/runtime.js +307 -238
  94. data/opal/corelib/string/encoding.rb +0 -6
  95. data/opal/corelib/string.rb +28 -7
  96. data/opal/corelib/time.rb +5 -2
  97. data/opal/corelib/unsupported.rb +2 -14
  98. data/opal.gemspec +2 -2
  99. data/spec/filters/bugs/delegate.rb +11 -0
  100. data/spec/filters/bugs/kernel.rb +1 -3
  101. data/spec/filters/bugs/language.rb +3 -23
  102. data/spec/filters/bugs/method.rb +0 -1
  103. data/spec/filters/bugs/module.rb +0 -3
  104. data/spec/filters/bugs/proc.rb +0 -3
  105. data/spec/filters/bugs/set.rb +4 -16
  106. data/spec/filters/bugs/unboundmethod.rb +0 -2
  107. data/spec/filters/unsupported/array.rb +0 -58
  108. data/spec/filters/unsupported/freeze.rb +8 -192
  109. data/spec/filters/unsupported/hash.rb +0 -25
  110. data/spec/filters/unsupported/kernel.rb +0 -1
  111. data/spec/filters/unsupported/privacy.rb +17 -0
  112. data/spec/lib/builder_spec.rb +14 -0
  113. data/spec/lib/cli_runners/server_spec.rb +2 -3
  114. data/spec/lib/cli_spec.rb +15 -1
  115. data/spec/lib/compiler_spec.rb +1 -1
  116. data/spec/opal/core/language/DATA/characters_support_crlf_spec.rb +9 -0
  117. data/spec/opal/core/language/DATA/multiple___END___crlf_spec.rb +10 -0
  118. data/spec/opal/core/language/if_spec.rb +13 -0
  119. data/spec/opal/core/language/safe_navigator_spec.rb +10 -0
  120. data/spec/opal/core/module_spec.rb +8 -0
  121. data/spec/ruby_specs +2 -1
  122. data/stdlib/await.rb +44 -7
  123. data/stdlib/delegate.rb +427 -6
  124. data/stdlib/headless_chrome.rb +6 -2
  125. data/stdlib/nodejs/file.rb +2 -1
  126. data/stdlib/opal-parser.rb +1 -1
  127. data/stdlib/opal-platform.rb +1 -1
  128. data/stdlib/opal-replutils.rb +5 -3
  129. data/stdlib/promise.rb +3 -0
  130. data/stdlib/rbconfig.rb +4 -1
  131. data/stdlib/ruby2_keywords.rb +60 -0
  132. data/stdlib/set.rb +21 -0
  133. data/tasks/performance.rake +41 -35
  134. data/tasks/releasing.rake +1 -0
  135. data/tasks/testing/mspec_special_calls.rb +1 -0
  136. data/tasks/testing.rake +13 -12
  137. data/test/nodejs/test_await.rb +39 -1
  138. data/test/nodejs/test_file.rb +3 -2
  139. metadata +37 -22
  140. data/docs/faq.md +0 -17
  141. data/lib/opal/rewriters/break_finder.rb +0 -36
  142. data/spec/opal/core/kernel/freeze_spec.rb +0 -15
@@ -1,4 +1,4 @@
1
- # helpers: truthy, coerce_to, respond_to, Opal
1
+ # helpers: truthy, coerce_to, respond_to, Opal, deny_frozen_access, freeze, freeze_props
2
2
  # use_strict: true
3
3
 
4
4
  module ::Kernel
@@ -106,6 +106,12 @@ module ::Kernel
106
106
  }
107
107
  end
108
108
 
109
+ def caller_locations(*args)
110
+ caller(*args).map do |loc|
111
+ ::Thread::Backtrace::Location.new(loc)
112
+ end
113
+ end
114
+
109
115
  def class
110
116
  `self.$$class`
111
117
  end
@@ -126,7 +132,7 @@ module ::Kernel
126
132
  %x{
127
133
  var i, name, names, length;
128
134
 
129
- if (other.hasOwnProperty('$$meta')) {
135
+ if (other.hasOwnProperty('$$meta') && other.$$meta !== null) {
130
136
  var other_singleton_class = Opal.get_singleton_class(other);
131
137
  var self_singleton_class = Opal.get_singleton_class(self);
132
138
  names = Object.getOwnPropertyNames(other_singleton_class.$$prototype);
@@ -154,18 +160,27 @@ module ::Kernel
154
160
  }
155
161
  end
156
162
 
157
- def clone(freeze: true)
163
+ def clone(freeze: nil)
164
+ unless freeze.nil? || freeze == true || freeze == false
165
+ raise ArgumentError, "unexpected value for freeze: #{freeze.class}"
166
+ end
167
+
158
168
  copy = self.class.allocate
159
169
 
160
170
  copy.copy_instance_variables(self)
161
171
  copy.copy_singleton_methods(self)
162
- copy.initialize_clone(self)
172
+ copy.initialize_clone(self, freeze: freeze)
173
+
174
+ if freeze == true || (freeze.nil? && frozen?)
175
+ copy.freeze
176
+ end
163
177
 
164
178
  copy
165
179
  end
166
180
 
167
- def initialize_clone(other)
181
+ def initialize_clone(other, freeze: nil)
168
182
  initialize_copy(other)
183
+ self
169
184
  end
170
185
 
171
186
  def define_singleton_method(name, method = undefined, &block)
@@ -215,6 +230,12 @@ module ::Kernel
215
230
 
216
231
  def extend(*mods)
217
232
  %x{
233
+ if (mods.length == 0) {
234
+ #{raise ::ArgumentError, 'wrong number of arguments (given 0, expected 1+)'}
235
+ }
236
+
237
+ $deny_frozen_access(self);
238
+
218
239
  var singleton = #{singleton_class};
219
240
 
220
241
  for (var i = mods.length - 1; i >= 0; i--) {
@@ -233,6 +254,34 @@ module ::Kernel
233
254
  self
234
255
  end
235
256
 
257
+ def freeze
258
+ return self if frozen?
259
+
260
+ %x{
261
+ if (typeof(self) === "object") {
262
+ $freeze_props(self);
263
+ return $freeze(self);
264
+ }
265
+ return self;
266
+ }
267
+ end
268
+
269
+ def frozen?
270
+ %x{
271
+ switch (typeof(self)) {
272
+ case "string":
273
+ case "symbol":
274
+ case "number":
275
+ case "boolean":
276
+ return true;
277
+ case "object":
278
+ return (self.$$frozen || false);
279
+ default:
280
+ return false;
281
+ }
282
+ }
283
+ end
284
+
236
285
  def gets(*args)
237
286
  $stdin.gets(*args)
238
287
  end
@@ -294,6 +343,8 @@ module ::Kernel
294
343
  end
295
344
 
296
345
  def instance_variable_set(name, value)
346
+ `$deny_frozen_access(self)`
347
+
297
348
  name = ::Opal.instance_variable_name!(name)
298
349
 
299
350
  `self[Opal.ivar(name.substr(1))] = value`
@@ -1,4 +1,4 @@
1
- # helpers: truthy, coerce_to, const_set, Object, return_ivar, assign_ivar, ivar
1
+ # helpers: truthy, coerce_to, const_set, Object, return_ivar, assign_ivar, ivar, deny_frozen_access, freeze, prop
2
2
 
3
3
  class ::Module
4
4
  def self.allocate
@@ -84,6 +84,8 @@ class ::Module
84
84
  end
85
85
 
86
86
  def alias_method(newname, oldname)
87
+ `$deny_frozen_access(self)`
88
+
87
89
  newname = `$coerce_to(newname, #{::String}, 'to_str')`
88
90
  oldname = `$coerce_to(oldname, #{::String}, 'to_str')`
89
91
  `Opal.alias(self, newname, oldname)`
@@ -92,6 +94,8 @@ class ::Module
92
94
  end
93
95
 
94
96
  def alias_native(mid, jsid = mid)
97
+ `$deny_frozen_access(self)`
98
+
95
99
  `Opal.alias_native(self, mid, jsid)`
96
100
 
97
101
  self
@@ -102,6 +106,8 @@ class ::Module
102
106
  end
103
107
 
104
108
  def append_features(includer)
109
+ `$deny_frozen_access(includer)`
110
+
105
111
  `Opal.append_features(self, includer)`
106
112
  self
107
113
  end
@@ -126,6 +132,8 @@ class ::Module
126
132
 
127
133
  def attr_reader(*names)
128
134
  %x{
135
+ $deny_frozen_access(self);
136
+
129
137
  var proto = self.$$prototype;
130
138
 
131
139
  for (var i = names.length - 1; i >= 0; i--) {
@@ -150,6 +158,8 @@ class ::Module
150
158
 
151
159
  def attr_writer(*names)
152
160
  %x{
161
+ $deny_frozen_access(self);
162
+
153
163
  var proto = self.$$prototype;
154
164
 
155
165
  for (var i = names.length - 1; i >= 0; i--) {
@@ -174,6 +184,8 @@ class ::Module
174
184
 
175
185
  def autoload(const, path)
176
186
  %x{
187
+ $deny_frozen_access(self);
188
+
177
189
  if (!#{Opal.const_name?(const)}) {
178
190
  #{::Kernel.raise ::NameError, "autoload must be constant name: #{const}"}
179
191
  }
@@ -221,6 +233,8 @@ class ::Module
221
233
  end
222
234
 
223
235
  def class_variable_set(name, value)
236
+ `$deny_frozen_access(self)`
237
+
224
238
  name = ::Opal.class_variable_name!(name)
225
239
 
226
240
  `Opal.class_variable_set(self, name, value)`
@@ -233,6 +247,8 @@ class ::Module
233
247
  end
234
248
 
235
249
  def remove_class_variable(name)
250
+ `$deny_frozen_access(self)`
251
+
236
252
  name = ::Opal.class_variable_name!(name)
237
253
 
238
254
  %x{
@@ -341,6 +357,8 @@ class ::Module
341
357
  end
342
358
 
343
359
  def const_set(name, value)
360
+ `$deny_frozen_access(self)`
361
+
344
362
  name = ::Opal.const_name!(name)
345
363
 
346
364
  if name !~ ::Opal::CONST_NAME_REGEXP || name.start_with?('::')
@@ -357,6 +375,8 @@ class ::Module
357
375
 
358
376
  def define_method(name, method = undefined, &block)
359
377
  %x{
378
+ $deny_frozen_access(self);
379
+
360
380
  if (method === undefined && block === nil)
361
381
  #{::Kernel.raise ::ArgumentError, 'tried to create a Proc object without a block'}
362
382
  }
@@ -389,6 +409,9 @@ class ::Module
389
409
  target.$$jsid = name;
390
410
  try {
391
411
  return target.apply(self, args);
412
+ } catch(e) {
413
+ if (e === target.$$brk || e === target.$$ret) return e.$v;
414
+ throw e;
392
415
  } finally {
393
416
  target.$$jsid = old_name
394
417
  }
@@ -405,10 +428,29 @@ class ::Module
405
428
  }
406
429
  end
407
430
 
431
+ def freeze
432
+ # Specialized version of freeze, because the $$base_module property needs to be
433
+ # accessible despite the frozen status
434
+
435
+ return self if frozen?
436
+
437
+ %x{
438
+ if (!self.hasOwnProperty('$$base_module')) { $prop(self, '$$base_module', null); }
439
+
440
+ return $freeze(self);
441
+ }
442
+ end
443
+
408
444
  def remove_method(*names)
409
445
  %x{
410
- for (var i = 0, length = names.length; i < length; i++) {
411
- Opal.rdef(self, "$" + names[i]);
446
+ for (var i = 0; i < names.length; i++) {
447
+ var name = names[i];
448
+ if (!(typeof name === "string" || name.$$is_string)) {
449
+ #{raise ::TypeError, "#{name} is not a symbol nor a string"}
450
+ }
451
+ $deny_frozen_access(self);
452
+
453
+ Opal.rdef(self, "$" + name);
412
454
  }
413
455
  }
414
456
 
@@ -488,6 +530,8 @@ class ::Module
488
530
  end
489
531
 
490
532
  def extend_object(object)
533
+ `$deny_frozen_access(object)`
534
+ nil
491
535
  end
492
536
 
493
537
  def method_added(*)
@@ -552,6 +596,8 @@ class ::Module
552
596
 
553
597
  def module_function(*methods)
554
598
  %x{
599
+ $deny_frozen_access(self);
600
+
555
601
  if (methods.length === 0) {
556
602
  self.$$module_function = true;
557
603
  return nil;
@@ -623,6 +669,8 @@ class ::Module
623
669
 
624
670
  def prepend_features(prepender)
625
671
  %x{
672
+ $deny_frozen_access(prepender);
673
+
626
674
  if (!self.$$is_module) {
627
675
  #{::Kernel.raise ::TypeError, "wrong argument type #{self.class} (expected Module)"};
628
676
  }
@@ -636,6 +684,8 @@ class ::Module
636
684
  end
637
685
 
638
686
  def remove_const(name)
687
+ `$deny_frozen_access(self)`
688
+
639
689
  `Opal.const_remove(self, name)`
640
690
  end
641
691
 
@@ -645,7 +695,13 @@ class ::Module
645
695
 
646
696
  def undef_method(*names)
647
697
  %x{
648
- for (var i = 0, length = names.length; i < length; i++) {
698
+ for (var i = 0; i < names.length; i++) {
699
+ var name = names[i];
700
+ if (!(typeof name === "string" || name.$$is_string)) {
701
+ #{raise ::TypeError, "#{name} is not a symbol nor a string"}
702
+ }
703
+ $deny_frozen_access(self);
704
+
649
705
  Opal.udef(self, "$" + names[i]);
650
706
  }
651
707
  }
data/opal/corelib/proc.rb CHANGED
@@ -18,9 +18,9 @@ class ::Proc < `Function`
18
18
  self.$$p = block;
19
19
  }
20
20
 
21
- var result, $brk = self.$$brk;
21
+ var result, $brk = self.$$brk, $ret = self.$$ret;
22
22
 
23
- if ($brk) {
23
+ if ($brk || ($ret && self.$$is_lambda)) {
24
24
  try {
25
25
  if (self.$$is_lambda) {
26
26
  result = self.apply(null, args);
@@ -30,10 +30,13 @@ class ::Proc < `Function`
30
30
  }
31
31
  } catch (err) {
32
32
  if (err === $brk) {
33
- return $brk.$v
33
+ return err.$v;
34
+ }
35
+ else if (self.$$is_lambda && err === $ret) {
36
+ return err.$v;
34
37
  }
35
38
  else {
36
- throw err
39
+ throw err;
37
40
  }
38
41
  }
39
42
  }
@@ -86,7 +89,7 @@ class ::Proc < `Function`
86
89
 
87
90
  def source_location
88
91
  `if (self.$$is_curried) { return nil; }`
89
- nil
92
+ `self.$$source_location` || nil
90
93
  end
91
94
 
92
95
  def binding
@@ -49,6 +49,7 @@ class ::Rational < ::Numeric
49
49
  def initialize(num, den)
50
50
  @num = num
51
51
  @den = den
52
+ freeze
52
53
  end
53
54
 
54
55
  def numerator
@@ -1,4 +1,4 @@
1
- # helpers: coerce_to
1
+ # helpers: coerce_to, prop, freeze
2
2
 
3
3
  class ::RegexpError < ::StandardError; end
4
4
 
@@ -119,6 +119,20 @@ class ::Regexp < `RegExp`
119
119
  match(string) && $~.begin(0)
120
120
  end
121
121
 
122
+ def freeze
123
+ # Specialized version of freeze, because the $$gm and $$g properties need to be set
124
+ # especially for RegExp.
125
+
126
+ return self if frozen?
127
+
128
+ %x{
129
+ if (!self.hasOwnProperty('$$g')) { $prop(self, '$$g', null); }
130
+ if (!self.hasOwnProperty('$$gm')) { $prop(self, '$$gm', null); }
131
+
132
+ return $freeze(self);
133
+ }
134
+ end
135
+
122
136
  def inspect
123
137
  # Use a regexp to extract the regular expression and the optional mode modifiers from the string.
124
138
  # In the regular expression, escape any front slash (not already escaped) with a backslash.