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
@@ -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
  // --------------