opal 1.7.4 → 1.8.0.beta1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (260) hide show
  1. checksums.yaml +4 -4
  2. data/.eslintrc.js +1 -0
  3. data/.github/workflows/build.yml +9 -9
  4. data/.rubocop/todo.yml +2 -2
  5. data/.rubocop.yml +17 -10
  6. data/.rubocop_todo.yml +311 -0
  7. data/CHANGELOG.md +1 -15
  8. data/README.md +7 -7
  9. data/UNRELEASED.md +92 -1
  10. data/benchmark-ips/bm_block_vs_yield.rb +3 -0
  11. data/benchmark-ips/bm_slice_or_not.rb +53 -0
  12. data/docs/bridging.md +112 -0
  13. data/docs/compiled_ruby.md +10 -10
  14. data/docs/getting_started.md +18 -22
  15. data/docs/releasing.md +8 -16
  16. data/lib/opal/cli_runners/chrome_cdp_interface.rb +1 -0
  17. data/lib/opal/cli_runners/firefox_cdp_interface.rb +1 -0
  18. data/lib/opal/compiler.rb +33 -1
  19. data/lib/opal/nodes/args/extract_kwoptarg.rb +2 -1
  20. data/lib/opal/nodes/call.rb +1 -1
  21. data/lib/opal/nodes/call_special.rb +71 -47
  22. data/lib/opal/nodes/closure.rb +15 -7
  23. data/lib/opal/nodes/defined.rb +1 -1
  24. data/lib/opal/nodes/hash.rb +14 -30
  25. data/lib/opal/nodes/if.rb +37 -29
  26. data/lib/opal/nodes/literal.rb +15 -7
  27. data/lib/opal/nodes/rescue.rb +1 -1
  28. data/lib/opal/nodes/x_string.rb +13 -0
  29. data/lib/opal/parser/patch.rb +1 -0
  30. data/lib/opal/rewriters/for_rewriter.rb +36 -24
  31. data/lib/opal/source_map/file.rb +1 -1
  32. data/lib/opal/version.rb +1 -1
  33. data/opal/corelib/array/pack.rb +1 -0
  34. data/opal/corelib/array.rb +110 -64
  35. data/opal/corelib/basic_object.rb +1 -0
  36. data/opal/corelib/binding.rb +2 -0
  37. data/opal/corelib/boolean.rb +1 -0
  38. data/opal/corelib/class.rb +28 -8
  39. data/opal/corelib/comparable.rb +1 -0
  40. data/opal/corelib/complex.rb +3 -1
  41. data/opal/corelib/constants.rb +2 -2
  42. data/opal/corelib/dir.rb +2 -0
  43. data/opal/corelib/enumerable.rb +3 -2
  44. data/opal/corelib/enumerator/arithmetic_sequence.rb +3 -1
  45. data/opal/corelib/enumerator/chain.rb +1 -0
  46. data/opal/corelib/enumerator/generator.rb +1 -0
  47. data/opal/corelib/enumerator/lazy.rb +1 -0
  48. data/opal/corelib/enumerator/yielder.rb +2 -0
  49. data/opal/corelib/enumerator.rb +1 -0
  50. data/opal/corelib/error/errno.rb +2 -0
  51. data/opal/corelib/error.rb +22 -0
  52. data/opal/corelib/file.rb +1 -0
  53. data/opal/corelib/hash.rb +224 -519
  54. data/opal/corelib/helpers.rb +1 -0
  55. data/opal/corelib/io.rb +2 -0
  56. data/opal/corelib/irb.rb +2 -0
  57. data/opal/corelib/kernel/format.rb +1 -0
  58. data/opal/corelib/kernel.rb +70 -15
  59. data/opal/corelib/main.rb +2 -0
  60. data/opal/corelib/marshal/read_buffer.rb +2 -0
  61. data/opal/corelib/marshal/write_buffer.rb +2 -0
  62. data/opal/corelib/math/polyfills.rb +2 -0
  63. data/opal/corelib/math.rb +1 -0
  64. data/opal/corelib/method.rb +2 -0
  65. data/opal/corelib/module.rb +45 -5
  66. data/opal/corelib/nil.rb +3 -1
  67. data/opal/corelib/number.rb +30 -1
  68. data/opal/corelib/numeric.rb +2 -0
  69. data/opal/corelib/object_space.rb +1 -0
  70. data/opal/corelib/pack_unpack/format_string_parser.rb +2 -0
  71. data/opal/corelib/proc.rb +30 -28
  72. data/opal/corelib/process.rb +2 -0
  73. data/opal/corelib/random/formatter.rb +2 -0
  74. data/opal/corelib/random/math_random.js.rb +2 -0
  75. data/opal/corelib/random/mersenne_twister.rb +2 -0
  76. data/opal/corelib/random/seedrandom.js.rb +2 -0
  77. data/opal/corelib/random.rb +1 -0
  78. data/opal/corelib/range.rb +35 -13
  79. data/opal/corelib/rational.rb +3 -1
  80. data/opal/corelib/regexp.rb +1 -0
  81. data/opal/corelib/runtime.js +297 -259
  82. data/opal/corelib/set.rb +2 -0
  83. data/opal/corelib/string/encoding.rb +3 -0
  84. data/opal/corelib/string/unpack.rb +2 -0
  85. data/opal/corelib/string.rb +56 -20
  86. data/opal/corelib/struct.rb +4 -2
  87. data/opal/corelib/time.rb +2 -1
  88. data/opal/corelib/trace_point.rb +2 -0
  89. data/opal/corelib/unsupported.rb +2 -0
  90. data/opal/corelib/variables.rb +2 -0
  91. data/opal.gemspec +2 -2
  92. data/spec/filters/bugs/array.rb +58 -2
  93. data/spec/filters/bugs/basicobject.rb +7 -0
  94. data/spec/filters/bugs/bigdecimal.rb +1 -2
  95. data/spec/filters/bugs/binding.rb +1 -0
  96. data/spec/filters/bugs/class.rb +2 -3
  97. data/spec/filters/bugs/complex.rb +3 -0
  98. data/spec/filters/bugs/date.rb +5 -2
  99. data/spec/filters/bugs/datetime.rb +1 -0
  100. data/spec/filters/bugs/delegate.rb +1 -2
  101. data/spec/filters/bugs/encoding.rb +1 -1
  102. data/spec/filters/bugs/enumerable.rb +11 -3
  103. data/spec/filters/bugs/enumerator.rb +15 -2
  104. data/spec/filters/bugs/exception.rb +9 -4
  105. data/spec/filters/bugs/file.rb +2 -0
  106. data/spec/filters/bugs/float.rb +1 -0
  107. data/spec/filters/bugs/freeze.rb +5 -49
  108. data/spec/filters/bugs/hash.rb +1 -13
  109. data/spec/filters/bugs/integer.rb +5 -6
  110. data/spec/filters/bugs/kernel.rb +12 -43
  111. data/spec/filters/bugs/language.rb +33 -15
  112. data/spec/filters/bugs/marshal.rb +63 -4
  113. data/spec/filters/bugs/method.rb +2 -10
  114. data/spec/filters/bugs/module.rb +18 -7
  115. data/spec/filters/bugs/objectspace.rb +2 -0
  116. data/spec/filters/bugs/pathname.rb +1 -0
  117. data/spec/filters/bugs/proc.rb +4 -2
  118. data/spec/filters/bugs/random.rb +0 -3
  119. data/spec/filters/bugs/range.rb +1 -2
  120. data/spec/filters/bugs/rational.rb +2 -0
  121. data/spec/filters/bugs/refinement.rb +19 -0
  122. data/spec/filters/bugs/regexp.rb +27 -5
  123. data/spec/filters/bugs/ruby-32.rb +0 -6
  124. data/spec/filters/bugs/set.rb +10 -2
  125. data/spec/filters/bugs/singleton.rb +0 -2
  126. data/spec/filters/bugs/string.rb +140 -2
  127. data/spec/filters/bugs/struct.rb +16 -10
  128. data/spec/filters/bugs/time.rb +56 -2
  129. data/spec/filters/bugs/trace_point.rb +1 -0
  130. data/spec/filters/bugs/unboundmethod.rb +4 -9
  131. data/spec/filters/bugs/warnings.rb +0 -1
  132. data/spec/filters/platform/firefox/exception.rb +3 -3
  133. data/spec/filters/platform/firefox/kernel.rb +1 -0
  134. data/spec/filters/platform/safari/exception.rb +2 -2
  135. data/spec/filters/platform/safari/float.rb +1 -0
  136. data/spec/filters/platform/safari/kernel.rb +1 -0
  137. data/spec/filters/platform/safari/literal_regexp.rb +2 -2
  138. data/spec/filters/unsupported/hash.rb +1 -0
  139. data/spec/lib/compiler_spec.rb +28 -17
  140. data/spec/mspec-opal/formatters.rb +2 -0
  141. data/spec/mspec-opal/runner.rb +2 -0
  142. data/spec/opal/core/array/dup_spec.rb +2 -0
  143. data/spec/opal/core/class/clone_spec.rb +36 -0
  144. data/spec/opal/core/exception_spec.rb +2 -0
  145. data/spec/opal/core/hash/internals_spec.rb +154 -206
  146. data/spec/opal/core/hash_spec.rb +2 -0
  147. data/spec/opal/core/iterable_props_spec.rb +2 -0
  148. data/spec/opal/core/kernel/at_exit_spec.rb +2 -0
  149. data/spec/opal/core/kernel/respond_to_spec.rb +2 -0
  150. data/spec/opal/core/language/arguments/mlhs_arg_spec.rb +2 -0
  151. data/spec/opal/core/language/safe_navigator_spec.rb +2 -0
  152. data/spec/opal/core/language/xstring_send_spec.rb +15 -0
  153. data/spec/opal/core/language/xstring_spec.rb +2 -0
  154. data/spec/opal/core/language_spec.rb +2 -0
  155. data/spec/opal/core/module_spec.rb +44 -0
  156. data/spec/opal/core/number/to_i_spec.rb +2 -0
  157. data/spec/opal/core/object_id_spec.rb +2 -6
  158. data/spec/opal/core/regexp/match_spec.rb +2 -0
  159. data/spec/opal/core/runtime/bridged_classes_spec.rb +38 -0
  160. data/spec/opal/core/runtime/constants_spec.rb +2 -0
  161. data/spec/opal/core/runtime/eval_spec.rb +2 -0
  162. data/spec/opal/core/runtime/exit_spec.rb +2 -0
  163. data/spec/opal/core/runtime/is_a_spec.rb +2 -0
  164. data/spec/opal/core/runtime/loaded_spec.rb +2 -0
  165. data/spec/opal/core/runtime/method_missing_spec.rb +2 -0
  166. data/spec/opal/core/runtime/rescue_spec.rb +2 -0
  167. data/spec/opal/core/runtime/string_spec.rb +2 -0
  168. data/spec/opal/core/runtime/truthy_spec.rb +2 -0
  169. data/spec/opal/core/runtime_spec.rb +2 -6
  170. data/spec/opal/core/string/to_sym_spec.rb +2 -0
  171. data/spec/opal/language/predefined_spec.rb +20 -0
  172. data/spec/opal/language/yield_spec.rb +43 -0
  173. data/spec/opal/stdlib/js_spec.rb +2 -0
  174. data/spec/opal/stdlib/native/alias_native_spec.rb +2 -0
  175. data/spec/opal/stdlib/native/array_spec.rb +2 -0
  176. data/spec/opal/stdlib/native/date_spec.rb +2 -0
  177. data/spec/opal/stdlib/native/each_spec.rb +2 -0
  178. data/spec/opal/stdlib/native/element_reference_spec.rb +2 -0
  179. data/spec/opal/stdlib/native/exposure_spec.rb +2 -0
  180. data/spec/opal/stdlib/native/ext_spec.rb +2 -0
  181. data/spec/opal/stdlib/native/hash_spec.rb +30 -2
  182. data/spec/opal/stdlib/native/initialize_spec.rb +2 -0
  183. data/spec/opal/stdlib/native/method_missing_spec.rb +2 -0
  184. data/spec/opal/stdlib/native/native_alias_spec.rb +2 -0
  185. data/spec/opal/stdlib/native/native_class_spec.rb +2 -0
  186. data/spec/opal/stdlib/native/native_module_spec.rb +2 -0
  187. data/spec/opal/stdlib/native/native_reader_spec.rb +2 -0
  188. data/spec/opal/stdlib/native/native_writer_spec.rb +2 -0
  189. data/spec/opal/stdlib/native/new_spec.rb +2 -0
  190. data/spec/opal/stdlib/native/struct_spec.rb +2 -0
  191. data/spec/ruby_specs +0 -2
  192. data/spec/spec_helper.rb +2 -0
  193. data/stdlib/await.rb +1 -0
  194. data/stdlib/base64.rb +2 -0
  195. data/stdlib/bigdecimal/bignumber.js.rb +2 -0
  196. data/stdlib/bigdecimal/util.rb +1 -0
  197. data/stdlib/bigdecimal.rb +4 -0
  198. data/stdlib/buffer/array.rb +2 -0
  199. data/stdlib/buffer/view.rb +2 -0
  200. data/stdlib/buffer.rb +2 -0
  201. data/stdlib/cgi.rb +14 -0
  202. data/stdlib/console.rb +2 -0
  203. data/stdlib/date/date_time.rb +2 -0
  204. data/stdlib/date.rb +2 -0
  205. data/stdlib/delegate.rb +5 -4
  206. data/stdlib/deno/base.rb +2 -0
  207. data/stdlib/deno/file.rb +2 -0
  208. data/stdlib/erb.rb +2 -0
  209. data/stdlib/gjs/io.rb +2 -0
  210. data/stdlib/gjs/kernel.rb +2 -0
  211. data/stdlib/headless_browser/base.rb +2 -0
  212. data/stdlib/headless_browser/file.rb +1 -0
  213. data/stdlib/headless_browser.rb +1 -0
  214. data/stdlib/js.rb +2 -0
  215. data/stdlib/json.rb +9 -15
  216. data/stdlib/logger.rb +2 -0
  217. data/stdlib/nashorn/file.rb +2 -0
  218. data/stdlib/nashorn/io.rb +2 -0
  219. data/stdlib/native.rb +48 -48
  220. data/stdlib/nodejs/base.rb +2 -0
  221. data/stdlib/nodejs/dir.rb +2 -0
  222. data/stdlib/nodejs/env.rb +2 -0
  223. data/stdlib/nodejs/file.rb +2 -0
  224. data/stdlib/nodejs/fileutils.rb +2 -0
  225. data/stdlib/nodejs/io.rb +2 -0
  226. data/stdlib/nodejs/js-yaml-3-6-1.js +1 -1
  227. data/stdlib/nodejs/kernel.rb +2 -0
  228. data/stdlib/nodejs/open-uri.rb +2 -0
  229. data/stdlib/nodejs/pathname.rb +2 -0
  230. data/stdlib/nodejs/require.rb +2 -0
  231. data/stdlib/nodejs/yaml.rb +9 -3
  232. data/stdlib/opal/miniracer.rb +2 -0
  233. data/stdlib/opal-parser.rb +8 -1
  234. data/stdlib/opal-platform.rb +2 -0
  235. data/stdlib/opal-replutils.rb +2 -0
  236. data/stdlib/open-uri.rb +4 -1
  237. data/stdlib/ostruct.rb +4 -2
  238. data/stdlib/pathname.rb +3 -1
  239. data/stdlib/pp.rb +1 -0
  240. data/stdlib/promise/v2.rb +24 -7
  241. data/stdlib/quickjs/io.rb +2 -0
  242. data/stdlib/quickjs/kernel.rb +2 -0
  243. data/stdlib/quickjs.rb +2 -0
  244. data/stdlib/securerandom.rb +2 -0
  245. data/stdlib/stringio.rb +2 -0
  246. data/stdlib/strscan.rb +2 -0
  247. data/stdlib/time.rb +2 -0
  248. data/stdlib/uri.rb +1 -0
  249. data/tasks/performance/optimization_status.rb +2 -0
  250. data/tasks/testing.rake +16 -11
  251. data/test/nodejs/test_await.rb +1 -0
  252. data/test/nodejs/test_dir.rb +2 -0
  253. data/test/nodejs/test_error.rb +2 -0
  254. data/test/nodejs/test_file.rb +2 -0
  255. data/test/nodejs/test_string.rb +2 -0
  256. data/test/nodejs/test_yaml.rb +20 -0
  257. data/test/opal/promisev2/test_always.rb +14 -0
  258. data/test/opal/unsupported_and_bugs.rb +0 -8
  259. metadata +26 -13
  260. data/spec/filters/bugs/openstruct.rb +0 -8
@@ -119,14 +119,16 @@
119
119
 
120
120
  // @private
121
121
  // Pops an exception from the stack and updates `$!`.
122
- Opal.pop_exception = function() {
122
+ Opal.pop_exception = function(rescued_exception) {
123
123
  var exception = Opal.exceptions.pop();
124
- if (exception) {
124
+ if (exception === rescued_exception) {
125
+ // Current $! is raised in the rescue block, so we don't update it
126
+ }
127
+ else if (exception) {
125
128
  $gvars["!"] = exception;
126
- $gvars["@"] = exception.$backtrace();
127
129
  }
128
130
  else {
129
- $gvars["!"] = $gvars["@"] = nil;
131
+ $gvars["!"] = nil;
130
132
  }
131
133
  };
132
134
 
@@ -152,6 +154,14 @@
152
154
  }
153
155
  }
154
156
 
157
+ // Reuse the same object for performance/memory sake
158
+ var prop_options = {
159
+ value: undefined,
160
+ enumerable: false,
161
+ configurable: true,
162
+ writable: true
163
+ };
164
+
155
165
  function $prop(object, name, initialValue) {
156
166
  if (typeof(object) === "string") {
157
167
  // Special case for:
@@ -163,12 +173,8 @@
163
173
  // numbers, true, false and null do not support it.
164
174
  object[name] = initialValue;
165
175
  } else {
166
- Object.defineProperty(object, name, {
167
- value: initialValue,
168
- enumerable: false,
169
- configurable: true,
170
- writable: true
171
- });
176
+ prop_options.value = initialValue;
177
+ Object.defineProperty(object, name, prop_options);
172
178
  }
173
179
  }
174
180
 
@@ -538,6 +544,13 @@
538
544
  Opal.$$$ = Opal.const_get_qualified;
539
545
  Opal.$r = Opal.const_get_relative_factory;
540
546
 
547
+ function descends_from_bridged_class(klass) {
548
+ if (klass == null) return false;
549
+ if (klass.$$bridge) return klass;
550
+ if (klass.$$super) return descends_from_bridged_class(klass.$$super);
551
+ return false;
552
+ }
553
+
541
554
  // Modules & Classes
542
555
  // -----------------
543
556
 
@@ -567,14 +580,13 @@
567
580
  // @return new [Class] or existing ruby class
568
581
  //
569
582
  function $allocate_class(name, superclass, singleton) {
570
- var klass;
583
+ var klass, bridged_descendant;
571
584
 
572
- if (superclass != null && superclass.$$bridge) {
585
+ if (bridged_descendant = descends_from_bridged_class(superclass)) {
573
586
  // Inheritance from bridged classes requires
574
587
  // calling original JS constructors
575
588
  klass = function() {
576
- var args = $slice(arguments),
577
- self = new ($bind.apply(superclass.$$constructor, [null].concat(args)))();
589
+ var self = new ($bind.apply(bridged_descendant.$$constructor, $prepend(null, arguments)))();
578
590
 
579
591
  // and replacing a __proto__ manually
580
592
  $set_proto(self, klass.$$prototype);
@@ -601,6 +613,7 @@
601
613
  $prop(klass, '$$ancestors', []);
602
614
  $prop(klass, '$$ancestors_cache_version', null);
603
615
  $prop(klass, '$$subclasses', []);
616
+ $prop(klass, '$$cloned_from', []);
604
617
 
605
618
  $prop(klass.$$prototype, '$$class', klass);
606
619
 
@@ -768,6 +781,7 @@
768
781
  $prop(module, '$$own_prepended_modules', []);
769
782
  $prop(module, '$$ancestors', [module]);
770
783
  $prop(module, '$$ancestors_cache_version', null);
784
+ $prop(module, '$$cloned_from', []);
771
785
 
772
786
  $set_proto(module, Opal.Module.prototype);
773
787
 
@@ -1538,7 +1552,6 @@
1538
1552
  // @param method_name [String] The js-name of the method to stub (e.g. "$foo")
1539
1553
  // @return [undefined]
1540
1554
  Opal.stub_for = function(method_name) {
1541
-
1542
1555
  function method_missing_stub() {
1543
1556
  // Copy any given block onto the method_missing dispatcher
1544
1557
  this.$method_missing.$$p = method_missing_stub.$$p;
@@ -1547,11 +1560,8 @@
1547
1560
  method_missing_stub.$$p = null;
1548
1561
 
1549
1562
  // call method missing with correct args (remove '$' prefix on method name)
1550
- var args_ary = new Array(arguments.length);
1551
- for(var i = 0, l = args_ary.length; i < l; i++) { args_ary[i] = arguments[i]; }
1552
-
1553
- return this.$method_missing.apply(this, [method_name.slice(1)].concat(args_ary));
1554
- }
1563
+ return this.$method_missing.apply(this, $prepend(method_name.slice(1), arguments));
1564
+ };
1555
1565
 
1556
1566
  method_missing_stub.$$stub = true;
1557
1567
 
@@ -1604,15 +1614,22 @@
1604
1614
 
1605
1615
  // Super dispatcher
1606
1616
  Opal.find_super = function(obj, mid, current_func, defcheck, allow_stubs) {
1607
- var jsid = $jsid(mid), ancestors, super_method;
1617
+ var jsid = $jsid(mid), ancestors, ancestor, super_method, method_owner, current_index = -1, i;
1608
1618
 
1609
1619
  ancestors = get_ancestors(obj);
1620
+ method_owner = current_func.$$owner;
1610
1621
 
1611
- var current_index = ancestors.indexOf(current_func.$$owner);
1622
+ for (i = 0; i < ancestors.length; i++) {
1623
+ ancestor = ancestors[i];
1624
+ if (ancestor === method_owner || ancestor.$$cloned_from.indexOf(method_owner) !== -1) {
1625
+ current_index = i;
1626
+ break;
1627
+ }
1628
+ }
1612
1629
 
1613
- for (var i = current_index + 1; i < ancestors.length; i++) {
1614
- var ancestor = ancestors[i],
1615
- proto = ancestor.$$prototype;
1630
+ for (i = current_index + 1; i < ancestors.length; i++) {
1631
+ ancestor = ancestors[i];
1632
+ var proto = ancestor.$$prototype;
1616
1633
 
1617
1634
  if (proto.hasOwnProperty('$$dummy')) {
1618
1635
  proto = proto.$$define_methods_on;
@@ -1660,6 +1677,17 @@
1660
1677
  // @deprecated
1661
1678
  Opal.find_iter_super_dispatcher = Opal.find_block_super;
1662
1679
 
1680
+ function call_lambda(block, arg, ret) {
1681
+ try {
1682
+ block(arg);
1683
+ } catch (e) {
1684
+ if (e === ret) {
1685
+ return ret.$v;
1686
+ }
1687
+ throw e;
1688
+ }
1689
+ }
1690
+
1663
1691
  // handles yield calls for 1 yielded arg
1664
1692
  Opal.yield1 = function(block, arg) {
1665
1693
  if (typeof(block) !== "function") {
@@ -1667,16 +1695,23 @@
1667
1695
  }
1668
1696
 
1669
1697
  var has_mlhs = block.$$has_top_level_mlhs_arg,
1670
- has_trailing_comma = block.$$has_trailing_comma_in_args;
1698
+ has_trailing_comma = block.$$has_trailing_comma_in_args,
1699
+ is_returning_lambda = block.$$is_lambda && block.$$ret;
1671
1700
 
1672
1701
  if (block.length > 1 || ((has_mlhs || has_trailing_comma) && block.length === 1)) {
1673
1702
  arg = Opal.to_ary(arg);
1674
1703
  }
1675
1704
 
1676
1705
  if ((block.length > 1 || (has_trailing_comma && block.length === 1)) && arg.$$is_array) {
1706
+ if (is_returning_lambda) {
1707
+ return call_lambda(block.apply.bind(block, null), arg, block.$$ret);
1708
+ }
1677
1709
  return block.apply(null, arg);
1678
1710
  }
1679
1711
  else {
1712
+ if (is_returning_lambda) {
1713
+ return call_lambda(block, arg, block.$$ret);
1714
+ }
1680
1715
  return block(arg);
1681
1716
  }
1682
1717
  };
@@ -1689,17 +1724,13 @@
1689
1724
 
1690
1725
  if (block.length > 1 && args.length === 1) {
1691
1726
  if (args[0].$$is_array) {
1692
- return block.apply(null, args[0]);
1727
+ args = args[0];
1693
1728
  }
1694
1729
  }
1695
1730
 
1696
- if (!args.$$is_array) {
1697
- var args_ary = new Array(args.length);
1698
- for(var i = 0, l = args_ary.length; i < l; i++) { args_ary[i] = args[i]; }
1699
-
1700
- return block.apply(null, args_ary);
1731
+ if (block.$$is_lambda && block.$$ret) {
1732
+ return call_lambda(block.apply.bind(block, null), args, block.$$ret);
1701
1733
  }
1702
-
1703
1734
  return block.apply(null, args);
1704
1735
  };
1705
1736
 
@@ -1812,11 +1843,10 @@
1812
1843
  };
1813
1844
 
1814
1845
  // Used for extracting keyword arguments from arguments passed to
1815
- // JS function. If provided +arguments+ list doesn't have a Hash
1816
- // as a last item, returns a blank Hash.
1846
+ // JS function.
1817
1847
  //
1818
1848
  // @param parameters [Array]
1819
- // @return [Hash]
1849
+ // @return [Hash] or undefined
1820
1850
  //
1821
1851
  Opal.extract_kwargs = function(parameters) {
1822
1852
  var kwargs = parameters[parameters.length - 1];
@@ -1828,7 +1858,7 @@
1828
1858
 
1829
1859
  // Used to get a list of rest keyword arguments. Method takes the given
1830
1860
  // keyword args, i.e. the hash literal passed to the method containing all
1831
- // keyword arguemnts passed to method, as well as the used args which are
1861
+ // keyword arguments passed to method, as well as the used args which are
1832
1862
  // the names of required and optional arguments defined. This method then
1833
1863
  // just returns all key/value pairs which have not been used, in a new
1834
1864
  // hash literal.
@@ -1838,19 +1868,16 @@
1838
1868
  // @return [Hash]
1839
1869
  //
1840
1870
  Opal.kwrestargs = function(given_args, used_args) {
1841
- var keys = [],
1842
- map = {},
1843
- key ,
1844
- given_map = given_args.$$smap;
1871
+ var map = new Map();
1845
1872
 
1846
- for (key in given_map) {
1873
+ Opal.hash_each(given_args, false, function(key, value) {
1847
1874
  if (!used_args[key]) {
1848
- keys.push(key);
1849
- map[key] = given_map[key];
1875
+ Opal.hash_put(map, key, value);
1850
1876
  }
1851
- }
1877
+ return [false, false];
1878
+ });
1852
1879
 
1853
- return Opal.hash2(keys, map);
1880
+ return map;
1854
1881
  };
1855
1882
 
1856
1883
  function apply_blockopts(block, blockopts) {
@@ -1874,6 +1901,11 @@
1874
1901
  }
1875
1902
  Opal.jsid = $jsid;
1876
1903
 
1904
+ function $prepend(first, second) {
1905
+ if (!second.$$is_array) second = $slice(second);
1906
+ return [first].concat(second);
1907
+ }
1908
+
1877
1909
  // Calls passed method on a ruby object with arguments and block:
1878
1910
  //
1879
1911
  // Can take a method or a method name.
@@ -1917,7 +1949,7 @@
1917
1949
  Opal.send2 = function(recv, body, method, args, block, blockopts) {
1918
1950
  if (body == null && method != null && recv.$method_missing) {
1919
1951
  body = recv.$method_missing;
1920
- args = [method].concat(args);
1952
+ args = $prepend(method, args);
1921
1953
  }
1922
1954
 
1923
1955
  apply_blockopts(block, blockopts);
@@ -2073,6 +2105,18 @@
2073
2105
  return Opal.defn(Opal.get_singleton_class(obj), jsid, body);
2074
2106
  };
2075
2107
 
2108
+ // Since JavaScript has no concept of modules, we create proxy classes
2109
+ // called `iclasses` that store copies of methods loaded. We need to
2110
+ // update them if we remove a method.
2111
+ function remove_method_from_iclasses(obj, jsid) {
2112
+ if (obj.$$is_module) {
2113
+ for (var i = 0, iclasses = obj.$$iclasses, length = iclasses.length; i < length; i++) {
2114
+ var iclass = iclasses[i];
2115
+ delete iclass[jsid];
2116
+ }
2117
+ }
2118
+ }
2119
+
2076
2120
  // Called from #remove_method.
2077
2121
  Opal.rdef = function(obj, jsid) {
2078
2122
  if (!$has_own(obj.$$prototype, jsid)) {
@@ -2081,6 +2125,8 @@
2081
2125
 
2082
2126
  delete obj.$$prototype[jsid];
2083
2127
 
2128
+ remove_method_from_iclasses(obj, jsid);
2129
+
2084
2130
  if (obj.$$is_singleton) {
2085
2131
  if (obj.$$prototype.$singleton_method_removed && !obj.$$prototype.$singleton_method_removed.$$stub) {
2086
2132
  obj.$$prototype.$singleton_method_removed(jsid.substr(1));
@@ -2101,6 +2147,8 @@
2101
2147
 
2102
2148
  Opal.add_stub_for(obj.$$prototype, jsid);
2103
2149
 
2150
+ remove_method_from_iclasses(obj, jsid);
2151
+
2104
2152
  if (obj.$$is_singleton) {
2105
2153
  if (obj.$$prototype.$singleton_method_undefined && !obj.$$prototype.$singleton_method_undefined.$$stub) {
2106
2154
  obj.$$prototype.$singleton_method_undefined(jsid.substr(1));
@@ -2159,17 +2207,25 @@
2159
2207
 
2160
2208
  // We need a wrapper because otherwise properties
2161
2209
  // would be overwritten on the original body.
2162
- alias = function() {
2163
- var block = alias.$$p, args, i, ii;
2210
+ alias = Opal.wrapMethodBody(body);
2164
2211
 
2165
- args = new Array(arguments.length);
2166
- for(i = 0, ii = arguments.length; i < ii; i++) {
2167
- args[i] = arguments[i];
2168
- }
2212
+ // Try to make the browser pick the right name
2213
+ alias.displayName = name;
2214
+ alias.$$alias_of = body;
2215
+ alias.$$alias_name = name;
2169
2216
 
2170
- alias.$$p = null;
2217
+ Opal.defn(obj, id, alias);
2171
2218
 
2172
- return Opal.send(this, body, args, block);
2219
+ return obj;
2220
+ };
2221
+
2222
+ Opal.wrapMethodBody = function(body) {
2223
+ var wrapped = function() {
2224
+ var block = wrapped.$$p;
2225
+
2226
+ wrapped.$$p = null;
2227
+
2228
+ return Opal.send(this, body, arguments, block);
2173
2229
  };
2174
2230
 
2175
2231
  // Assign the 'length' value with defineProperty because
@@ -2177,21 +2233,14 @@
2177
2233
  // It doesn't work in older browsers (like Chrome 38), where
2178
2234
  // an exception is thrown breaking Opal altogether.
2179
2235
  try {
2180
- Object.defineProperty(alias, 'length', { value: body.length });
2236
+ Object.defineProperty(wrapped, 'length', { value: body.length });
2181
2237
  } catch (e) {}
2182
2238
 
2183
- // Try to make the browser pick the right name
2184
- alias.displayName = name;
2185
-
2186
- alias.$$arity = body.$$arity == null ? body.length : body.$$arity;
2187
- alias.$$parameters = body.$$parameters;
2188
- alias.$$source_location = body.$$source_location;
2189
- alias.$$alias_of = body;
2190
- alias.$$alias_name = name;
2191
-
2192
- Opal.defn(obj, id, alias);
2239
+ wrapped.$$arity = body.$$arity == null ? body.length : body.$$arity;
2240
+ wrapped.$$parameters = body.$$parameters;
2241
+ wrapped.$$source_location = body.$$source_location;
2193
2242
 
2194
- return obj;
2243
+ return wrapped;
2195
2244
  };
2196
2245
 
2197
2246
  Opal.alias_gvar = function(new_name, old_name) {
@@ -2225,228 +2274,169 @@
2225
2274
  // Hashes
2226
2275
  // ------
2227
2276
 
2228
- Opal.hash_init = function(hash) {
2229
- hash.$$smap = Object.create(null);
2230
- hash.$$map = Object.create(null);
2231
- hash.$$keys = [];
2232
- };
2277
+ Opal.hash_init = function (_hash) {
2278
+ console.warn("DEPRECATION: Opal.hash_init is deprecated and is now a no-op.");
2279
+ }
2233
2280
 
2234
2281
  Opal.hash_clone = function(from_hash, to_hash) {
2235
2282
  to_hash.$$none = from_hash.$$none;
2236
2283
  to_hash.$$proc = from_hash.$$proc;
2237
2284
 
2238
- for (var i = 0, keys = from_hash.$$keys, smap = from_hash.$$smap, len = keys.length, key, value; i < len; i++) {
2239
- key = keys[i];
2240
-
2241
- if (key.$$is_string) {
2242
- value = smap[key];
2243
- } else {
2244
- value = key.value;
2245
- key = key.key;
2246
- }
2247
-
2285
+ return Opal.hash_each(from_hash, to_hash, function(key, value) {
2248
2286
  Opal.hash_put(to_hash, key, value);
2249
- }
2287
+ return [false, to_hash];
2288
+ });
2250
2289
  };
2251
2290
 
2252
2291
  Opal.hash_put = function(hash, key, value) {
2253
- if (key.$$is_string) {
2254
- if (!$has_own(hash.$$smap, key)) {
2255
- hash.$$keys.push(key);
2256
- }
2257
- hash.$$smap[key] = value;
2258
- return;
2259
- }
2292
+ var type = typeof key;
2293
+ if (type === "string" || type === "symbol" || type === "number" || type === "boolean" || type === "bigint") {
2294
+ hash.set(key, value)
2295
+ } else if (key.$$is_string) {
2296
+ hash.set(key.valueOf(), value);
2297
+ } else {
2298
+ if (!hash.$$keys)
2299
+ hash.$$keys = new Map();
2260
2300
 
2261
- var key_hash, bucket, last_bucket;
2262
- key_hash = hash.$$by_identity ? Opal.id(key) : key.$hash();
2301
+ var key_hash = key.$$is_string ? key.valueOf() : (hash.$$by_identity ? Opal.id(key) : key.$hash()),
2302
+ keys = hash.$$keys;
2263
2303
 
2264
- if (!$has_own(hash.$$map, key_hash)) {
2265
- bucket = {key: key, key_hash: key_hash, value: value};
2266
- hash.$$keys.push(bucket);
2267
- hash.$$map[key_hash] = bucket;
2268
- return;
2269
- }
2304
+ if (!keys.has(key_hash)) {
2305
+ keys.set(key_hash, [key]);
2306
+ hash.set(key, value);
2307
+ return;
2308
+ }
2270
2309
 
2271
- bucket = hash.$$map[key_hash];
2310
+ var objects = keys.get(key_hash),
2311
+ object;
2272
2312
 
2273
- while (bucket) {
2274
- if (key === bucket.key || key['$eql?'](bucket.key)) {
2275
- last_bucket = undefined;
2276
- bucket.value = value;
2277
- break;
2313
+ for (var i=0; i<objects.length; i++) {
2314
+ object = objects[i];
2315
+ if (key === object || key['$eql?'](object)) {
2316
+ hash.set(object, value);
2317
+ return;
2318
+ }
2278
2319
  }
2279
- last_bucket = bucket;
2280
- bucket = bucket.next;
2281
- }
2282
2320
 
2283
- if (last_bucket) {
2284
- bucket = {key: key, key_hash: key_hash, value: value};
2285
- hash.$$keys.push(bucket);
2286
- last_bucket.next = bucket;
2321
+ objects.push(key);
2322
+ hash.set(key, value);
2287
2323
  }
2288
2324
  };
2289
2325
 
2290
2326
  Opal.hash_get = function(hash, key) {
2291
- if (key.$$is_string) {
2292
- if ($has_own(hash.$$smap, key)) {
2293
- return hash.$$smap[key];
2294
- }
2295
- return;
2296
- }
2297
-
2298
- var key_hash, bucket;
2299
- key_hash = hash.$$by_identity ? Opal.id(key) : key.$hash();
2300
-
2301
- if ($has_own(hash.$$map, key_hash)) {
2302
- bucket = hash.$$map[key_hash];
2303
-
2304
- while (bucket) {
2305
- if (key === bucket.key || key['$eql?'](bucket.key)) {
2306
- return bucket.value;
2327
+ var type = typeof key;
2328
+ if (type === "string" || type === "symbol" || type === "number" || type === "boolean" || type === "bigint") {
2329
+ return hash.get(key)
2330
+ } else if (hash.$$keys) {
2331
+ var key_hash = key.$$is_string ? key.valueOf() : (hash.$$by_identity ? Opal.id(key) : key.$hash()),
2332
+ objects = hash.$$keys.get(key_hash),
2333
+ object;
2334
+
2335
+ if (objects !== undefined) {
2336
+ for (var i=0; i<objects.length; i++) {
2337
+ object = objects[i];
2338
+ if (key === object || key['$eql?'](object))
2339
+ return hash.get(object);
2307
2340
  }
2308
- bucket = bucket.next;
2341
+ } else if (key.$$is_string) {
2342
+ return hash.get(key_hash);
2309
2343
  }
2344
+ } else if (key.$$is_string) {
2345
+ return hash.get(key.valueOf());
2310
2346
  }
2311
2347
  };
2312
2348
 
2313
- Opal.hash_delete = function(hash, key) {
2314
- var i, keys = hash.$$keys, length = keys.length, value, key_tmp;
2315
-
2316
- if (key.$$is_string) {
2317
- if (typeof key !== "string") key = key.valueOf();
2318
-
2319
- if (!$has_own(hash.$$smap, key)) {
2320
- return;
2321
- }
2322
-
2323
- for (i = 0; i < length; i++) {
2324
- key_tmp = keys[i];
2325
-
2326
- if (key_tmp.$$is_string && typeof key_tmp !== "string") {
2327
- key_tmp = key_tmp.valueOf();
2328
- }
2329
-
2330
- if (key_tmp === key) {
2331
- keys.splice(i, 1);
2332
- break;
2333
- }
2334
- }
2335
-
2336
- value = hash.$$smap[key];
2337
- delete hash.$$smap[key];
2349
+ function $hash_delete_stage2(hash, key) {
2350
+ var value = hash.get(key);
2351
+ if (value !== undefined) {
2352
+ hash.delete(key);
2338
2353
  return value;
2339
2354
  }
2355
+ }
2340
2356
 
2341
- var key_hash = key.$hash();
2342
-
2343
- if (!$has_own(hash.$$map, key_hash)) {
2344
- return;
2345
- }
2346
-
2347
- var bucket = hash.$$map[key_hash], last_bucket;
2348
-
2349
- while (bucket) {
2350
- if (key === bucket.key || key['$eql?'](bucket.key)) {
2351
- value = bucket.value;
2352
-
2353
- for (i = 0; i < length; i++) {
2354
- if (keys[i] === bucket) {
2355
- keys.splice(i, 1);
2356
- break;
2357
+ Opal.hash_delete = function(hash, key) {
2358
+ var type = typeof key
2359
+ if (type === "string" || type === "symbol" || type === "number" || type === "boolean" || type === "bigint") {
2360
+ return $hash_delete_stage2(hash, key);
2361
+ } else if (hash.$$keys) {
2362
+ var key_hash = key.$$is_string ? key.valueOf() : (hash.$$by_identity ? Opal.id(key) : key.$hash()),
2363
+ objects = hash.$$keys.get(key_hash),
2364
+ object;
2365
+
2366
+ if (objects !== undefined) {
2367
+ for (var i=0; i<objects.length; i++) {
2368
+ object = objects[i];
2369
+ if (key === object || key['$eql?'](object)) {
2370
+ objects.splice(i, 1);
2371
+ if (objects.length === 0)
2372
+ hash.$$keys.delete(key_hash);
2373
+ return $hash_delete_stage2(hash, object);
2357
2374
  }
2358
2375
  }
2359
-
2360
- if (last_bucket && bucket.next) {
2361
- last_bucket.next = bucket.next;
2362
- }
2363
- else if (last_bucket) {
2364
- delete last_bucket.next;
2365
- }
2366
- else if (bucket.next) {
2367
- hash.$$map[key_hash] = bucket.next;
2368
- }
2369
- else {
2370
- delete hash.$$map[key_hash];
2371
- }
2372
-
2373
- return value;
2376
+ } else if (key.$$is_string) {
2377
+ return $hash_delete_stage2(hash, key_hash);
2374
2378
  }
2375
- last_bucket = bucket;
2376
- bucket = bucket.next;
2379
+ } else if (key.$$is_string) {
2380
+ return $hash_delete_stage2(hash, key.valueOf());
2377
2381
  }
2378
2382
  };
2379
2383
 
2380
2384
  Opal.hash_rehash = function(hash) {
2381
- for (var i = 0, length = hash.$$keys.length, key_hash, bucket, last_bucket; i < length; i++) {
2385
+ var keys = hash.$$keys;
2382
2386
 
2383
- if (hash.$$keys[i].$$is_string) {
2384
- continue;
2385
- }
2387
+ if (keys)
2388
+ keys.clear();
2386
2389
 
2387
- key_hash = hash.$$keys[i].key.$hash();
2390
+ Opal.hash_each(hash, false, function(key, value) {
2391
+ var type = typeof key;
2392
+ if (type === "string" || type === "symbol" || type === "number" || type === "boolean" || type === "bigint")
2393
+ return [false, false]; // nothing to rehash
2388
2394
 
2389
- if (key_hash === hash.$$keys[i].key_hash) {
2390
- continue;
2391
- }
2395
+ var key_hash = key.$$is_string ? key.valueOf() : (hash.$$by_identity ? Opal.id(key) : key.$hash());
2392
2396
 
2393
- bucket = hash.$$map[hash.$$keys[i].key_hash];
2394
- last_bucket = undefined;
2397
+ if (!keys)
2398
+ hash.$$keys = keys = new Map();
2395
2399
 
2396
- while (bucket) {
2397
- if (bucket === hash.$$keys[i]) {
2398
- if (last_bucket && bucket.next) {
2399
- last_bucket.next = bucket.next;
2400
- }
2401
- else if (last_bucket) {
2402
- delete last_bucket.next;
2403
- }
2404
- else if (bucket.next) {
2405
- hash.$$map[hash.$$keys[i].key_hash] = bucket.next;
2406
- }
2407
- else {
2408
- delete hash.$$map[hash.$$keys[i].key_hash];
2409
- }
2410
- break;
2411
- }
2412
- last_bucket = bucket;
2413
- bucket = bucket.next;
2400
+ if (!keys.has(key_hash)) {
2401
+ keys.set(key_hash, [key]);
2402
+ return [false, false];
2414
2403
  }
2415
2404
 
2416
- hash.$$keys[i].key_hash = key_hash;
2405
+ var objects = keys.get(key_hash),
2406
+ objects_copy = $slice(objects),
2407
+ object;
2417
2408
 
2418
- if (!$has_own(hash.$$map, key_hash)) {
2419
- hash.$$map[key_hash] = hash.$$keys[i];
2420
- continue;
2409
+ for (var i=0; i<objects_copy.length; i++) {
2410
+ object = objects_copy[i];
2411
+ if (key === object || key['$eql?'](object)) {
2412
+ // got a duplicate, remove it
2413
+ objects.splice(objects.indexOf(object), 1);
2414
+ hash.delete(object);
2415
+ }
2421
2416
  }
2422
2417
 
2423
- bucket = hash.$$map[key_hash];
2424
- last_bucket = undefined;
2418
+ objects.push(key);
2425
2419
 
2426
- while (bucket) {
2427
- if (bucket === hash.$$keys[i]) {
2428
- last_bucket = undefined;
2429
- break;
2430
- }
2431
- last_bucket = bucket;
2432
- bucket = bucket.next;
2433
- }
2420
+ return [false, false]
2421
+ });
2434
2422
 
2435
- if (last_bucket) {
2436
- last_bucket.next = hash.$$keys[i];
2437
- }
2438
- }
2423
+ return hash;
2439
2424
  };
2440
2425
 
2441
- Opal.hash = function() {
2442
- var arguments_length = arguments.length, args, hash, i, length, key, value;
2426
+ Opal.hash = function () {
2427
+ var arguments_length = arguments.length,
2428
+ args,
2429
+ hash,
2430
+ i,
2431
+ length,
2432
+ key,
2433
+ value;
2443
2434
 
2444
2435
  if (arguments_length === 1 && arguments[0].$$is_hash) {
2445
2436
  return arguments[0];
2446
2437
  }
2447
2438
 
2448
- hash = new Opal.Hash();
2449
- Opal.hash_init(hash);
2439
+ hash = new Map();
2450
2440
 
2451
2441
  if (arguments_length === 1) {
2452
2442
  args = arguments[0];
@@ -2456,7 +2446,7 @@
2456
2446
 
2457
2447
  for (i = 0; i < length; i++) {
2458
2448
  if (args[i].length !== 2) {
2459
- $raise(Opal.ArgumentError, "value not of length 2: " + args[i].$inspect());
2449
+ $raise(Opal.ArgumentError, 'value not of length 2: ' + args[i].$inspect());
2460
2450
  }
2461
2451
 
2462
2452
  key = args[i][0];
@@ -2466,8 +2456,7 @@
2466
2456
  }
2467
2457
 
2468
2458
  return hash;
2469
- }
2470
- else {
2459
+ } else {
2471
2460
  args = arguments[0];
2472
2461
  for (key in args) {
2473
2462
  if ($has_own(args, key)) {
@@ -2482,7 +2471,7 @@
2482
2471
  }
2483
2472
 
2484
2473
  if (arguments_length % 2 !== 0) {
2485
- $raise(Opal.ArgumentError, "odd number of arguments for Hash");
2474
+ $raise(Opal.ArgumentError, 'odd number of arguments for Hash');
2486
2475
  }
2487
2476
 
2488
2477
  for (i = 0; i < arguments_length; i += 2) {
@@ -2501,15 +2490,29 @@
2501
2490
  // function.
2502
2491
  //
2503
2492
  Opal.hash2 = function(keys, smap) {
2504
- var hash = new Opal.Hash();
2505
-
2506
- hash.$$smap = smap;
2507
- hash.$$map = Object.create(null);
2508
- hash.$$keys = keys;
2493
+ console.warn("DEPRECATION: `Opal.hash2` is deprecated and will be removed in Opal 2.0. Use `new Map()` with an array of key/value pairs instead.");
2509
2494
 
2495
+ var hash = new Map();
2496
+ for (var i = 0, max = keys.length; i < max; i++) {
2497
+ hash.set(keys[i], smap[keys[i]]);
2498
+ }
2510
2499
  return hash;
2511
2500
  };
2512
2501
 
2502
+ Opal.hash_each = function (hash, dres, fun) {
2503
+ // dres = default result, returned if hash is empty
2504
+ // fun is called as fun(key, value) and must return a array with [break, result]
2505
+ // if break is true, iteration stops and result is returned
2506
+ // if break is false, iteration continues and eventually the last result is returned
2507
+ var res;
2508
+ for (var i = 0, entry, entries = Array.from(hash.entries()), l = entries.length; i < l; i++) {
2509
+ entry = entries[i];
2510
+ res = fun(entry[0], entry[1]);
2511
+ if (res[0]) return res[1];
2512
+ }
2513
+ return res ? res[1] : dres;
2514
+ };
2515
+
2513
2516
  // Create a new range instance with first and last values, and whether the
2514
2517
  // range excludes the last value.
2515
2518
  //
@@ -2547,7 +2550,7 @@
2547
2550
  // helper that can be used from methods
2548
2551
  function $deny_frozen_access(obj) {
2549
2552
  if (obj.$$frozen) {
2550
- $raise(Opal.FrozenError, "can't modify frozen " + (obj.$class()) + ": " + (obj), Opal.hash2(["receiver"], {"receiver": obj}));
2553
+ $raise(Opal.FrozenError, "can't modify frozen " + (obj.$class()) + ": " + (obj), new Map([["receiver", obj]]));
2551
2554
  }
2552
2555
  };
2553
2556
  Opal.deny_frozen_access = $deny_frozen_access;
@@ -2672,7 +2675,7 @@
2672
2675
  if (part.ignoreCase !== ignoreCase)
2673
2676
  Opal.Kernel.$warn(
2674
2677
  "ignore case doesn't match for " + part.source.$inspect(),
2675
- Opal.hash({uplevel: 1})
2678
+ new Map([['uplevel', 1]])
2676
2679
  )
2677
2680
 
2678
2681
  part = part.source;
@@ -2923,7 +2926,7 @@
2923
2926
  // Primitives for handling parameters
2924
2927
  Opal.ensure_kwargs = function(kwargs) {
2925
2928
  if (kwargs == null) {
2926
- return Opal.hash2([], {});
2929
+ return new Map();
2927
2930
  } else if (kwargs.$$is_hash) {
2928
2931
  return kwargs;
2929
2932
  } else {
@@ -2932,10 +2935,11 @@
2932
2935
  }
2933
2936
 
2934
2937
  Opal.get_kwarg = function(kwargs, key) {
2935
- if (!$has_own(kwargs.$$smap, key)) {
2938
+ var kwarg = Opal.hash_get(kwargs, key);
2939
+ if (kwarg === undefined) {
2936
2940
  $raise(Opal.ArgumentError, 'missing keyword: '+key);
2937
2941
  }
2938
- return kwargs.$$smap[key];
2942
+ return kwarg;
2939
2943
  }
2940
2944
 
2941
2945
  // Arrays of size > 32 elements that contain only strings,
@@ -2965,6 +2969,20 @@
2965
2969
  return array;
2966
2970
  }
2967
2971
 
2972
+ // Opal32-checksum algorithm for #hash
2973
+ // -----------------------------------
2974
+ Opal.opal32_init = $return_val(0x4f70616c);
2975
+
2976
+ function $opal32_ror(n, d) {
2977
+ return (n << d)|(n >>> (32 - d));
2978
+ };
2979
+
2980
+ Opal.opal32_add = function(hash, next) {
2981
+ hash ^= next;
2982
+ hash = $opal32_ror(hash, 1);
2983
+ return hash;
2984
+ };
2985
+
2968
2986
  // Initialization
2969
2987
  // --------------
2970
2988
  Opal.BasicObject = BasicObject = $allocate_class('BasicObject', null);
@@ -3020,10 +3038,9 @@
3020
3038
 
3021
3039
  // Foward calls to define_method on the top object to Object
3022
3040
  function top_define_method() {
3023
- var args = $slice(arguments);
3024
3041
  var block = top_define_method.$$p;
3025
3042
  top_define_method.$$p = null;
3026
- return Opal.send(_Object, 'define_method', args, block)
3043
+ return Opal.send(_Object, 'define_method', arguments, block)
3027
3044
  };
3028
3045
 
3029
3046
  // Nil
@@ -3037,16 +3054,37 @@
3037
3054
  Object.seal(nil);
3038
3055
 
3039
3056
  Opal.thrower = function(type) {
3040
- var thrower = new Error('unexpected '+type);
3041
- thrower.$thrower_type = type;
3042
- thrower.$throw = function(value) {
3043
- if (value == null) value = nil;
3044
- thrower.$v = value;
3045
- throw thrower;
3046
- };
3057
+ var thrower = {
3058
+ $thrower_type: type,
3059
+ $throw: function(value, called_from_lambda) {
3060
+ if (value == null) value = nil;
3061
+ if (this.is_orphan && !called_from_lambda) {
3062
+ $raise(Opal.LocalJumpError, 'unexpected ' + type, value, type.$to_sym());
3063
+ }
3064
+ this.$v = value;
3065
+ throw this;
3066
+ },
3067
+ is_orphan: false
3068
+ }
3047
3069
  return thrower;
3048
3070
  };
3049
3071
 
3072
+ // Define a "$@" global variable, which would compute and return a backtrace on demand.
3073
+ Object.defineProperty($gvars, "@", {
3074
+ enumerable: true,
3075
+ configurable: true,
3076
+ get: function() {
3077
+ if ($truthy($gvars["!"])) return $gvars["!"].$backtrace();
3078
+ return nil;
3079
+ },
3080
+ set: function(bt) {
3081
+ if ($truthy($gvars["!"]))
3082
+ $gvars["!"].$set_backtrace(bt);
3083
+ else
3084
+ $raise(Opal.ArgumentError, "$! not set");
3085
+ }
3086
+ });
3087
+
3050
3088
  Opal.t_eval_return = Opal.thrower("return");
3051
3089
 
3052
3090
  TypeError.$$super = Error;