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
@@ -2,7 +2,7 @@
2
2
 
3
3
  module Kernel
4
4
  def method_missing(symbol, *args, &block)
5
- raise NoMethodError.new("undefined method `#{symbol}' for #{inspect}", symbol, args)
5
+ raise NoMethodError.new("undefined method `#{symbol}' for #{inspect}", symbol, args), nil, caller(1)
6
6
  end
7
7
 
8
8
  def =~(obj)
@@ -94,19 +94,18 @@ module Kernel
94
94
 
95
95
  def caller(start = 1, length = nil)
96
96
  %x{
97
- var stack, result
97
+ var stack, result;
98
98
 
99
- stack = (new Error().stack || "").split("\n")
100
- result = []
99
+ stack = new Error().$backtrace();
100
+ result = [];
101
101
 
102
- // Skip the initial line ("Error:") and Kernel#caller with i=3
103
- for (var i = 3, ii = stack.length; i < ii; i++) {
104
- if (!stack[i].match("runtime.js")) {
105
- result.push(stack[i].replace(/^ *\w+ +/, ''))
106
- if (length && result.length == length) break
102
+ for (var i = #{start} + 1, ii = stack.length; i < ii; i++) {
103
+ if (!stack[i].match(/runtime\.js/)) {
104
+ result.push(stack[i]);
107
105
  }
108
106
  }
109
- return result
107
+ if (length != nil) result = result.slice(0, length);
108
+ return result;
110
109
  }
111
110
  end
112
111
 
@@ -239,6 +238,10 @@ module Kernel
239
238
  self
240
239
  end
241
240
 
241
+ def gets(*args)
242
+ $stdin.gets(*args)
243
+ end
244
+
242
245
  def hash
243
246
  __id__
244
247
  end
@@ -247,7 +250,11 @@ module Kernel
247
250
  end
248
251
 
249
252
  def inspect
250
- to_s
253
+ ivs = ''
254
+ instance_variables.each do |i|
255
+ ivs += " #{i}=#{instance_variable_get(i)}"
256
+ end
257
+ "#<#{self.class}:0x#{__id__.to_s(16)}#{ivs}>"
251
258
  end
252
259
 
253
260
  def instance_of?(klass)
@@ -367,22 +374,26 @@ module Kernel
367
374
  base = 2;
368
375
  return head;
369
376
  }
377
+ // no-break
370
378
  case '0':
371
379
  case '0o':
372
380
  if (base === 0 || base === 8) {
373
381
  base = 8;
374
382
  return head;
375
383
  }
384
+ // no-break
376
385
  case '0d':
377
386
  if (base === 0 || base === 10) {
378
387
  base = 10;
379
388
  return head;
380
389
  }
390
+ // no-break
381
391
  case '0x':
382
392
  if (base === 0 || base === 16) {
383
393
  base = 16;
384
394
  return head;
385
395
  }
396
+ // no-break
386
397
  }
387
398
  #{raise ArgumentError, "invalid value for Integer(): \"#{value}\""}
388
399
  });
@@ -516,11 +527,15 @@ module Kernel
516
527
  $stdout.print(*strs)
517
528
  end
518
529
 
530
+ def readline(*args)
531
+ $stdin.readline(*args)
532
+ end
533
+
519
534
  def warn(*strs, uplevel: nil)
520
535
  if uplevel
521
536
  uplevel = Opal.coerce_to!(uplevel, Integer, :to_str)
522
537
  raise ArgumentError, "negative level (#{uplevel})" if uplevel < 0
523
- location = caller(uplevel + 2, 1).first
538
+ location = caller(uplevel + 1, 1).first&.split(':in `')&.first
524
539
  location = "#{location}: " if location
525
540
  strs = strs.map { |s| "#{location}warning: #{s}" }
526
541
  end
@@ -528,33 +543,38 @@ module Kernel
528
543
  $stderr.puts(*strs) unless $VERBOSE.nil? || strs.empty?
529
544
  end
530
545
 
531
- def raise(exception = undefined, string = nil, _backtrace = nil)
546
+ def raise(exception = undefined, string = nil, backtrace = nil)
532
547
  %x{
533
548
  if (exception == null && #{$!} !== nil) {
534
549
  throw #{$!};
535
550
  }
536
551
  if (exception == null) {
537
- exception = #{RuntimeError.new};
552
+ exception = #{RuntimeError.new ''};
538
553
  }
539
- else if (exception.$$is_string) {
540
- exception = #{RuntimeError.new exception};
554
+ else if ($respond_to(exception, '$to_str')) {
555
+ exception = #{RuntimeError.new exception.to_str};
541
556
  }
542
557
  // using respond_to? and not an undefined check to avoid method_missing matching as true
543
- else if (exception.$$is_class && #{exception.respond_to?(:exception)}) {
558
+ else if (exception.$$is_class && $respond_to(exception, '$exception')) {
544
559
  exception = #{exception.exception string};
545
560
  }
546
- else if (#{exception.is_a?(Exception)}) {
561
+ else if (exception.$$is_exception) {
547
562
  // exception is fine
548
563
  }
549
564
  else {
550
565
  exception = #{TypeError.new 'exception class/object expected'};
551
566
  }
552
567
 
568
+ if (backtrace !== nil) {
569
+ exception.$set_backtrace(backtrace);
570
+ }
571
+
553
572
  if (#{$!} !== nil) {
554
573
  Opal.exceptions.push(#{$!});
555
574
  }
556
575
 
557
576
  #{$!} = exception;
577
+ #{$@} = #{`exception`.backtrace};
558
578
 
559
579
  throw exception;
560
580
  }
@@ -687,15 +707,16 @@ module Kernel
687
707
  "#<#{self.class}:0x#{__id__.to_s(16)}>"
688
708
  end
689
709
 
690
- def catch(sym)
691
- yield
710
+ def catch(tag = nil)
711
+ tag ||= Object.new
712
+ yield(tag)
692
713
  rescue UncaughtThrowError => e
693
- return e.arg if e.sym == sym
714
+ return e.value if e.tag == tag
694
715
  raise
695
716
  end
696
717
 
697
- def throw(*args)
698
- raise UncaughtThrowError, args
718
+ def throw(tag, obj = nil)
719
+ raise UncaughtThrowError.new(tag, obj)
699
720
  end
700
721
 
701
722
  # basic implementation of open, delegate to File.open
data/opal/corelib/main.rb CHANGED
@@ -5,3 +5,8 @@ end
5
5
  def self.include(mod)
6
6
  Object.include mod
7
7
  end
8
+
9
+ # Compiler overrides this method
10
+ def self.using(mod)
11
+ raise 'main.using is permitted only at toplevel'
12
+ end
@@ -33,6 +33,7 @@ class Method
33
33
  end
34
34
 
35
35
  alias [] call
36
+ alias === call
36
37
 
37
38
  def >>(other)
38
39
  @method >> other
@@ -629,6 +629,8 @@ class Module
629
629
  `Opal.Module.$name.call(self)` || "#<#{`self.$$is_module ? 'Module' : 'Class'`}:0x#{__id__.to_s(16)}>"
630
630
  end
631
631
 
632
+ alias inspect to_s
633
+
632
634
  def undef_method(*names)
633
635
  %x{
634
636
  for (var i = 0, length = names.length; i < length; i++) {
@@ -678,4 +680,30 @@ class Module
678
680
  }
679
681
  }
680
682
  end
683
+
684
+ def refine(mod, &block)
685
+ s, m, mod_id = self, nil, nil
686
+ %x{
687
+ mod_id = Opal.id(mod);
688
+ if (typeof self.$$refine_modules === "undefined") {
689
+ self.$$refine_modules = {};
690
+ }
691
+ if (typeof self.$$refine_modules[mod_id] === "undefined") {
692
+ m = self.$$refine_modules[mod_id] = #{::Module.new};
693
+ }
694
+ else {
695
+ m = self.$$refine_modules[mod_id];
696
+ }
697
+ }
698
+ m.define_singleton_method :inspect do
699
+ "#<refinement:#{mod.inspect}@#{s.inspect}>"
700
+ end
701
+ m.class_exec(&block)
702
+ m
703
+ end
704
+
705
+ # Compiler overrides this method
706
+ def using(mod)
707
+ raise 'Module#using is not permitted in methods'
708
+ end
681
709
  end
@@ -711,6 +711,11 @@ class Number < Numeric
711
711
  raise ArgumentError, "invalid radix #{base}"
712
712
  end
713
713
 
714
+ # Don't lose the negative zero
715
+ if self == 0 && `1/self === -Infinity`
716
+ return '-0.0'
717
+ end
718
+
714
719
  `self.toString(base)`
715
720
  end
716
721
 
@@ -747,9 +752,15 @@ class Number < Numeric
747
752
  end
748
753
 
749
754
  %x{
755
+ if (self != parseInt(self)) #{raise NoMethodError, "undefined method `digits' for #{inspect}"}
756
+
750
757
  var value = self, result = [];
751
758
 
752
- while (value !== 0) {
759
+ if (self == 0) {
760
+ return [0];
761
+ }
762
+
763
+ while (value != 0) {
753
764
  result.push(value % base);
754
765
  value = parseInt(value / base, 10);
755
766
  }
@@ -2,7 +2,7 @@ class Random
2
2
  %x{
3
3
  var module = { exports: {} };
4
4
 
5
- /* jshint ignore:start */
5
+ /* eslint-disable */
6
6
  /*
7
7
  seedrandom.min.js 2.4.1 (original source: https://github.com/davidbau/seedrandom/blob/2.4.1/seedrandom.min.js)
8
8
  How to update:
@@ -12,7 +12,7 @@ class Random
12
12
  .. Add a module id for the RequireJS `define` method: https://github.com/Mogztter/seedrandom/commit/e047540c3d81f955cab9a01d17b8141d439fbd7d
13
13
  */
14
14
  !function(a,b){function c(c,j,k){var n=[];j=1==j?{entropy:!0}:j||{};var s=g(f(j.entropy?[c,i(a)]:null==c?h():c,3),n),t=new d(n),u=function(){for(var a=t.g(m),b=p,c=0;a<q;)a=(a+c)*l,b*=l,c=t.g(1);for(;a>=r;)a/=2,b/=2,c>>>=1;return(a+c)/b};return u.int32=function(){return 0|t.g(4)},u.quick=function(){return t.g(4)/4294967296},u.double=u,g(i(t.S),a),(j.pass||k||function(a,c,d,f){return f&&(f.S&&e(f,t),a.state=function(){return e(t,{})}),d?(b[o]=a,c):a})(u,s,"global"in j?j.global:this==b,j.state)}function d(a){var b,c=a.length,d=this,e=0,f=d.i=d.j=0,g=d.S=[];for(c||(a=[c++]);e<l;)g[e]=e++;for(e=0;e<l;e++)g[e]=g[f=s&f+a[e%c]+(b=g[e])],g[f]=b;(d.g=function(a){for(var b,c=0,e=d.i,f=d.j,g=d.S;a--;)b=g[e=s&e+1],c=c*l+g[s&(g[e]=g[f=s&f+b])+(g[f]=b)];return d.i=e,d.j=f,c})(l)}function e(a,b){return b.i=a.i,b.j=a.j,b.S=a.S.slice(),b}function f(a,b){var c,d=[],e=typeof a;if(b&&"object"==e)for(c in a)if(a.hasOwnProperty(c))try{d.push(f(a[c],b-1))}catch(a){}return d.length?d:"string"==e?a:a+"\0"}function g(a,b){for(var c,d=a+"",e=0;e<d.length;)b[s&e]=s&(c^=19*b[s&e])+d.charCodeAt(e++);return i(b)}function h(){try{if(j)return i(j.randomBytes(l));var b=new Uint8Array(l);return(k.crypto||k.msCrypto).getRandomValues(b),i(b)}catch(b){var c=k.navigator,d=c&&c.plugins;return[+new Date,k,d,k.screen,i(a)]}}function i(a){return String.fromCharCode.apply(0,a)}var j,k=this,l=256,m=6,n=52,o="random",p=b.pow(l,m),q=b.pow(2,n),r=2*q,s=l-1;if(b["seed"+o]=c,g(b.random(),a),"object"==typeof module&&module.exports){module.exports=c;try{j=require("crypto")}catch(a){}}else"function"==typeof define&&define.amd&&define('seekrandom',function(){return c})}([],Math);
15
- /* jshint ignore:end */
15
+ /* eslint-enable */
16
16
  var seedrandom = module.exports
17
17
  var $seed_generator = new Math.seedrandom('opal', { entropy: true })
18
18
  }
@@ -244,6 +244,20 @@ class Regexp < `RegExp`
244
244
  }
245
245
  end
246
246
 
247
+ def names
248
+ source.scan(/\(?<(\w+)>/).map(&:first).uniq
249
+ end
250
+
251
+ def named_captures
252
+ source.scan(/\(?<(\w+)>/) # Scan for capture groups
253
+ .map(&:first) # Get the first regexp match (\w+)
254
+ .each_with_index # Add index to an iterator
255
+ .group_by(&:first) # Group by the capture group names
256
+ .transform_values do |i| # Convert hash values
257
+ i.map { |j| j.last + 1 } # Drop the capture group names; increase indexes by 1
258
+ end
259
+ end
260
+
247
261
  def ~
248
262
  self =~ $_
249
263
  end
@@ -304,7 +318,17 @@ class MatchData
304
318
  end
305
319
 
306
320
  def [](*args)
307
- @matches[*args]
321
+ %x{
322
+ if (args[0].$$is_string) {
323
+ if (#{!regexp.names.include?(args[0])}) {
324
+ #{raise IndexError, "undefined group name reference: #{args[0]}"}
325
+ }
326
+ return #{named_captures[args[0]]}
327
+ }
328
+ else {
329
+ return #{@matches[*args]}
330
+ }
331
+ }
308
332
  end
309
333
 
310
334
  def offset(n)
@@ -350,12 +374,32 @@ class MatchData
350
374
  `#{@matches}.slice(1)`
351
375
  end
352
376
 
377
+ def named_captures
378
+ matches = captures
379
+ regexp.named_captures.transform_values do |i|
380
+ matches[i.last - 1]
381
+ end
382
+ end
383
+
384
+ def names
385
+ regexp.names
386
+ end
387
+
353
388
  def inspect
354
389
  %x{
355
390
  var str = "#<MatchData " + #{`#{@matches}[0]`.inspect};
356
391
 
357
- for (var i = 1, length = #{@matches}.length; i < length; i++) {
358
- str += " " + i + ":" + #{`#{@matches}[i]`.inspect};
392
+ if (#{regexp.names.empty?}) {
393
+ for (var i = 1, length = #{@matches}.length; i < length; i++) {
394
+ str += " " + i + ":" + #{`#{@matches}[i]`.inspect};
395
+ }
396
+ }
397
+ else {
398
+ #{ named_captures.each do |k, v|
399
+ %x{
400
+ str += " " + #{k} + ":" + #{v.inspect}
401
+ }
402
+ end }
359
403
  }
360
404
 
361
405
  return str + ">";
@@ -65,6 +65,7 @@
65
65
  Opal.config = {
66
66
  missing_require_severity: 'error', // error, warning, ignore
67
67
  unsupported_features_severity: 'warning', // error, warning, ignore
68
+ experimental_features_severity: 'warning',// warning, ignore
68
69
  enable_stack_trace: true // true, false
69
70
  };
70
71
 
@@ -111,7 +112,14 @@
111
112
  // @private
112
113
  // Pops an exception from the stack and updates `$!`.
113
114
  Opal.pop_exception = function() {
114
- Opal.gvars["!"] = Opal.exceptions.pop() || nil;
115
+ var exception = Opal.exceptions.pop();
116
+ if (exception) {
117
+ Opal.gvars["!"] = exception;
118
+ Opal.gvars["@"] = exception.$backtrace();
119
+ }
120
+ else {
121
+ Opal.gvars["!"] = Opal.gvars["@"] = nil;
122
+ }
115
123
  };
116
124
 
117
125
  // Inspect any kind of object, including non Ruby ones
@@ -209,6 +217,22 @@
209
217
  }
210
218
  }
211
219
 
220
+ // TracePoint support
221
+ // ------------------
222
+ //
223
+ // Support for `TracePoint.trace(:class) do ... end`
224
+ Opal.trace_class = false;
225
+ Opal.tracers_for_class = [];
226
+
227
+ function invoke_tracers_for_class(klass_or_module) {
228
+ var i, ii, tracer;
229
+
230
+ for(i = 0, ii = Opal.tracers_for_class.length; i < ii; i++) {
231
+ tracer = Opal.tracers_for_class[i];
232
+ tracer.trace_object = klass_or_module;
233
+ tracer.block.$call(tracer);
234
+ }
235
+ }
212
236
 
213
237
  // Constants
214
238
  // ---------
@@ -565,6 +589,9 @@
565
589
  // Make sure existing class has same superclass
566
590
  ensureSuperclassMatch(klass, superclass);
567
591
  }
592
+
593
+ if (Opal.trace_class) { invoke_tracers_for_class(klass); }
594
+
568
595
  return klass;
569
596
  }
570
597
 
@@ -588,6 +615,8 @@
588
615
  Opal.bridge(bridged, klass);
589
616
  }
590
617
 
618
+ if (Opal.trace_class) { invoke_tracers_for_class(klass); }
619
+
591
620
  return klass;
592
621
  };
593
622
 
@@ -665,6 +694,9 @@
665
694
  module = find_existing_module(scope, name);
666
695
 
667
696
  if (module) {
697
+
698
+ if (Opal.trace_class) { invoke_tracers_for_class(module); }
699
+
668
700
  return module;
669
701
  }
670
702
 
@@ -672,6 +704,8 @@
672
704
  module = Opal.allocate_module(name);
673
705
  Opal.const_set(scope, name, module);
674
706
 
707
+ if (Opal.trace_class) { invoke_tracers_for_class(module); }
708
+
675
709
  return module;
676
710
  };
677
711
 
@@ -1358,9 +1392,10 @@
1358
1392
  // @return [undefined]
1359
1393
  Opal.add_stubs = function(stubs) {
1360
1394
  var proto = Opal.BasicObject.$$prototype;
1395
+ var stub, existing_method;
1361
1396
 
1362
1397
  for (var i = 0, length = stubs.length; i < length; i++) {
1363
- var stub = stubs[i], existing_method = proto[stub];
1398
+ stub = stubs[i], existing_method = proto[stub];
1364
1399
 
1365
1400
  if (existing_method == null || existing_method.$$stub) {
1366
1401
  Opal.add_stub_for(proto, stub);
@@ -1375,8 +1410,8 @@
1375
1410
  // @param stub [String] stub name to add (e.g. "$foo")
1376
1411
  // @return [undefined]
1377
1412
  Opal.add_stub_for = function(prototype, stub) {
1378
- var method_missing_stub = Opal.stub_for(stub);
1379
- $defineProperty(prototype, stub, method_missing_stub);
1413
+ // Opal.stub_for(stub) is the method_missing_stub
1414
+ $defineProperty(prototype, stub, Opal.stub_for(stub));
1380
1415
  };
1381
1416
 
1382
1417
  // Generate the method_missing stub for a given method name.
@@ -1386,8 +1421,6 @@
1386
1421
  Opal.stub_for = function(method_name) {
1387
1422
 
1388
1423
  function method_missing_stub() {
1389
- /* jshint validthis: true */
1390
-
1391
1424
  // Copy any given block onto the method_missing dispatcher
1392
1425
  this.$method_missing.$$p = method_missing_stub.$$p;
1393
1426
 
@@ -1443,7 +1476,7 @@
1443
1476
  };
1444
1477
 
1445
1478
  // Super dispatcher
1446
- Opal.find_super_dispatcher = function(obj, mid, current_func, defcheck, allow_stubs) {
1479
+ Opal.find_super = function(obj, mid, current_func, defcheck, allow_stubs) {
1447
1480
  var jsid = '$' + mid, ancestors, super_method;
1448
1481
 
1449
1482
  if (obj.hasOwnProperty('$$meta')) {
@@ -1477,7 +1510,7 @@
1477
1510
  };
1478
1511
 
1479
1512
  // Iter dispatcher for super in a block
1480
- Opal.find_iter_super_dispatcher = function(obj, jsid, current_func, defcheck, implicit) {
1513
+ Opal.find_block_super = function(obj, jsid, current_func, defcheck, implicit) {
1481
1514
  var call_jsid = jsid;
1482
1515
 
1483
1516
  if (!current_func) {
@@ -1495,6 +1528,12 @@
1495
1528
  return Opal.find_super_dispatcher(obj, call_jsid, current_func, defcheck);
1496
1529
  };
1497
1530
 
1531
+ // @deprecated
1532
+ Opal.find_super_dispatcher = Opal.find_super;
1533
+
1534
+ // @deprecated
1535
+ Opal.find_iter_super_dispatcher = Opal.find_block_super;
1536
+
1498
1537
  // Used to return as an expression. Sometimes, we can't simply return from
1499
1538
  // a javascript function as if we were a method, as the return is used as
1500
1539
  // an expression, or even inside a block which must "return" to the outer
@@ -1773,6 +1812,44 @@
1773
1812
  return body.apply(recv, args);
1774
1813
  };
1775
1814
 
1815
+ Opal.refined_send = function(refinement_groups, recv, method, args, block) {
1816
+ var i, j, k, ancestors, ancestor, refinements, refinement, refine_modules, refine_module, body;
1817
+
1818
+ if (recv.hasOwnProperty('$$meta')) {
1819
+ ancestors = Opal.ancestors(recv.$$meta);
1820
+ } else {
1821
+ ancestors = Opal.ancestors(recv.$$class);
1822
+ }
1823
+
1824
+ // For all ancestors that there are, starting from the closest to the furthest...
1825
+ for (i = 0; i < ancestors.length; i++) {
1826
+ ancestor = Opal.id(ancestors[i]);
1827
+ // For all refinement groups there are, starting from the closest scope to the furthest...
1828
+ for (j = 0; j < refinement_groups.length; j++) {
1829
+ refinements = refinement_groups[j];
1830
+ // For all refinements there are, starting from the last `using` call to the furthest...
1831
+ for (k = refinements.length - 1; k >= 0; k--) {
1832
+ refinement = refinements[k];
1833
+ if (typeof refinement.$$refine_modules === 'undefined') continue;
1834
+ // A single module being given as an argument of the `using` call contains multiple
1835
+ // refinement modules
1836
+ refine_modules = refinement.$$refine_modules;
1837
+ // Does this module refine a given call for a given ancestor module?
1838
+ if (typeof refine_modules[ancestor] !== 'undefined') {
1839
+ refine_module = refine_modules[ancestor];
1840
+ // Does this module define a method we want to call?
1841
+ if (typeof refine_module.$$prototype['$'+method] !== 'undefined') {
1842
+ body = refine_module.$$prototype['$'+method];
1843
+ return Opal.send2(recv, body, method, args, block);
1844
+ }
1845
+ }
1846
+ }
1847
+ }
1848
+ }
1849
+
1850
+ return Opal.send(recv, method, args, block);
1851
+ };
1852
+
1776
1853
  Opal.lambda = function(block) {
1777
1854
  block.$$is_lambda = true;
1778
1855
  return block;
@@ -1915,9 +1992,16 @@
1915
1992
  Opal.alias = function(obj, name, old) {
1916
1993
  var id = '$' + name,
1917
1994
  old_id = '$' + old,
1918
- body = obj.$$prototype['$' + old],
1995
+ body,
1919
1996
  alias;
1920
1997
 
1998
+ // Aliasing on main means aliasing on Object...
1999
+ if (typeof obj.$$prototype === 'undefined') {
2000
+ obj = Opal.Object;
2001
+ }
2002
+
2003
+ body = obj.$$prototype['$' + old];
2004
+
1921
2005
  // When running inside #instance_eval the alias refers to class methods.
1922
2006
  if (obj.$$eval) {
1923
2007
  return Opal.alias(Opal.get_singleton_class(obj), name, old);
@@ -1982,6 +2066,20 @@
1982
2066
  return obj;
1983
2067
  };
1984
2068
 
2069
+ Opal.alias_gvar = function(new_name, old_name) {
2070
+ Object.defineProperty(Opal.gvars, new_name, {
2071
+ configurable: true,
2072
+ enumerable: true,
2073
+ get: function() {
2074
+ return Opal.gvars[old_name];
2075
+ },
2076
+ set: function(new_value) {
2077
+ Opal.gvars[old_name] = new_value;
2078
+ }
2079
+ });
2080
+ return nil;
2081
+ }
2082
+
1985
2083
  Opal.alias_native = function(obj, name, native_name) {
1986
2084
  var id = '$' + name,
1987
2085
  body = obj.$$prototype[native_name];
@@ -2085,7 +2183,7 @@
2085
2183
  };
2086
2184
 
2087
2185
  Opal.hash_delete = function(hash, key) {
2088
- var i, keys = hash.$$keys, length = keys.length, value;
2186
+ var i, keys = hash.$$keys, length = keys.length, value, key_tmp;
2089
2187
 
2090
2188
  if (key.$$is_string) {
2091
2189
  if (typeof key !== "string") key = key.valueOf();
@@ -2095,7 +2193,13 @@
2095
2193
  }
2096
2194
 
2097
2195
  for (i = 0; i < length; i++) {
2098
- if (keys[i] === key) {
2196
+ key_tmp = keys[i];
2197
+
2198
+ if (key_tmp.$$is_string && typeof key_tmp !== "string") {
2199
+ key_tmp = key_tmp.valueOf();
2200
+ }
2201
+
2202
+ if (key_tmp === key) {
2099
2203
  keys.splice(i, 1);
2100
2204
  break;
2101
2205
  }
@@ -2444,7 +2548,12 @@
2444
2548
  var module = Opal.modules[path];
2445
2549
 
2446
2550
  if (module) {
2447
- module(Opal);
2551
+ var retval = module(Opal);
2552
+ if (typeof Promise !== 'undefined' && retval instanceof Promise) {
2553
+ // A special case of require having an async top:
2554
+ // We will need to await it.
2555
+ return retval.then(function() { return true; });
2556
+ }
2448
2557
  }
2449
2558
  else {
2450
2559
  var severity = Opal.config.missing_require_severity;
@@ -2523,6 +2632,37 @@
2523
2632
  return Opal.set_encoding(dup, "binary", "internal_encoding");
2524
2633
  }
2525
2634
 
2635
+ Opal.last_promise = null;
2636
+ Opal.promise_unhandled_exception = false;
2637
+
2638
+ // Run a block of code, but if it returns a Promise, don't run the next
2639
+ // one, but queue it.
2640
+ Opal.queue = function(proc) {
2641
+ if (Opal.last_promise) {
2642
+ // The async path is taken only if anything before returned a
2643
+ // Promise(V2).
2644
+ Opal.last_promise = Opal.last_promise.then(function() {
2645
+ if (!Opal.promise_unhandled_exception) return proc(Opal);
2646
+ })['catch'](function(error) {
2647
+ if (Opal.respond_to(error, '$full_message')) {
2648
+ error = error.$full_message();
2649
+ }
2650
+ console.error(error);
2651
+ // Abort further execution
2652
+ Opal.promise_unhandled_exception = true;
2653
+ Opal.exit(1);
2654
+ });
2655
+ return Opal.last_promise;
2656
+ }
2657
+ else {
2658
+ var ret = proc(Opal);
2659
+ if (typeof Promise === 'function' && typeof ret === 'object' && ret instanceof Promise) {
2660
+ Opal.last_promise = ret;
2661
+ }
2662
+ return ret;
2663
+ }
2664
+ }
2665
+
2526
2666
 
2527
2667
  // Initialization
2528
2668
  // --------------