opal 1.4.1 → 1.5.0.rc1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (89) hide show
  1. checksums.yaml +4 -4
  2. data/.eslintrc.js +5 -3
  3. data/.rubocop.yml +1 -0
  4. data/UNRELEASED.md +37 -2
  5. data/benchmark-ips/bm_js_symbols_vs_strings.rb +39 -14
  6. data/docs/releasing.md +10 -2
  7. data/lib/opal/ast/matcher.rb +77 -0
  8. data/lib/opal/cache.rb +1 -1
  9. data/lib/opal/cli_runners/applescript.rb +2 -0
  10. data/lib/opal/compiler.rb +18 -9
  11. data/lib/opal/nodes/call.rb +73 -28
  12. data/lib/opal/nodes/def.rb +31 -27
  13. data/lib/opal/nodes/definitions.rb +2 -0
  14. data/lib/opal/nodes/helpers.rb +4 -23
  15. data/lib/opal/nodes/if.rb +222 -0
  16. data/lib/opal/nodes/iter.rb +41 -37
  17. data/lib/opal/nodes/literal.rb +2 -2
  18. data/lib/opal/nodes/masgn.rb +15 -17
  19. data/lib/opal/nodes/node_with_args/shortcuts.rb +100 -0
  20. data/lib/opal/nodes/node_with_args.rb +1 -0
  21. data/lib/opal/nodes/top.rb +26 -10
  22. data/lib/opal/nodes.rb +0 -1
  23. data/lib/opal/parser/default_config.rb +3 -2
  24. data/lib/opal/repl.rb +1 -1
  25. data/lib/opal/rewriter.rb +13 -6
  26. data/lib/opal/rewriters/base.rb +12 -1
  27. data/lib/opal/rewriters/rubyspec/filters_rewriter.rb +1 -0
  28. data/lib/opal/version.rb +1 -1
  29. data/opal/corelib/array.rb +23 -28
  30. data/opal/corelib/binding.rb +14 -4
  31. data/opal/corelib/constants.rb +3 -3
  32. data/opal/corelib/hash.rb +2 -2
  33. data/opal/corelib/irb.rb +192 -0
  34. data/opal/corelib/math/polyfills.rb +127 -0
  35. data/opal/corelib/math.rb +14 -194
  36. data/opal/corelib/module.rb +23 -25
  37. data/opal/corelib/number.rb +63 -14
  38. data/opal/corelib/regexp.rb +2 -0
  39. data/opal/corelib/runtime.js +56 -20
  40. data/opal/corelib/string.rb +38 -59
  41. data/opal/corelib/time.rb +106 -68
  42. data/opal/opal/full.rb +0 -1
  43. data/opal/opal.rb +4 -1
  44. data/spec/filters/bugs/date.rb +0 -3
  45. data/spec/filters/bugs/datetime.rb +65 -0
  46. data/spec/filters/bugs/float.rb +0 -18
  47. data/spec/filters/bugs/hash.rb +0 -2
  48. data/spec/filters/bugs/language.rb +0 -3
  49. data/spec/filters/bugs/marshal.rb +0 -1
  50. data/spec/filters/bugs/string.rb +0 -30
  51. data/spec/filters/bugs/time.rb +18 -8
  52. data/spec/lib/cli_spec.rb +2 -2
  53. data/spec/lib/compiler_spec.rb +8 -8
  54. data/spec/lib/rewriters/base_spec.rb +1 -1
  55. data/spec/lib/rewriters/binary_operator_assignment_spec.rb +34 -59
  56. data/spec/lib/rewriters/block_to_iter_spec.rb +3 -6
  57. data/spec/lib/rewriters/dot_js_syntax_spec.rb +2 -5
  58. data/spec/lib/rewriters/for_rewriter_spec.rb +0 -1
  59. data/spec/lib/rewriters/forward_args_spec.rb +2 -3
  60. data/spec/lib/rewriters/js_reserved_words_spec.rb +2 -15
  61. data/spec/lib/rewriters/logical_operator_assignment_spec.rb +64 -89
  62. data/spec/lib/rewriters/numblocks_spec.rb +3 -5
  63. data/spec/lib/rewriters/opal_engine_check_spec.rb +2 -14
  64. data/spec/lib/rewriters/rubyspec/filters_rewriter_spec.rb +10 -2
  65. data/spec/opal/compiler/irb_spec.rb +4 -0
  66. data/spec/opal/core/language/super_spec.rb +26 -0
  67. data/spec/opal/core/regexp/assertions_spec.rb +19 -0
  68. data/spec/opal/core/string/to_proc_spec.rb +19 -0
  69. data/spec/ruby_specs +4 -0
  70. data/spec/support/rewriters_helper.rb +43 -23
  71. data/stdlib/date/date_time.rb +71 -0
  72. data/stdlib/date/formatters.rb +28 -0
  73. data/stdlib/date/infinity.rb +73 -0
  74. data/stdlib/date.rb +77 -214
  75. data/stdlib/opal/repl_js.rb +1 -1
  76. data/stdlib/{opal/replutils.rb → opal-replutils.rb} +3 -3
  77. data/stdlib/time.rb +39 -2
  78. data/stdlib/uri.rb +53 -0
  79. data/tasks/performance/asciidoctor_test.rb.erb +3 -1
  80. data/tasks/performance/optimization_status.rb +3 -2
  81. data/tasks/performance.rake +69 -35
  82. data/tasks/testing.rake +1 -0
  83. data/test/opal/test_uri.rb +35 -0
  84. data/yarn.lock +27 -5
  85. metadata +31 -18
  86. data/lib/opal/nodes/csend.rb +0 -24
  87. data/lib/opal/rewriters/explicit_writer_return.rb +0 -59
  88. data/spec/lib/rewriters/explicit_writer_return_spec.rb +0 -186
  89. data/stdlib/nodejs/irb.rb +0 -43
data/opal/corelib/math.rb CHANGED
@@ -36,124 +36,6 @@ module ::Math
36
36
 
37
37
  module_function
38
38
 
39
- def acos(x)
40
- ::Math.checked :acos, ::Math.float!(x)
41
- end
42
-
43
- unless defined?(`Math.acosh`)
44
- %x{
45
- Math.acosh = function(x) {
46
- return Math.log(x + Math.sqrt(x * x - 1));
47
- }
48
- }
49
- end
50
-
51
- def acosh(x)
52
- ::Math.checked :acosh, ::Math.float!(x)
53
- end
54
-
55
- def asin(x)
56
- ::Math.checked :asin, ::Math.float!(x)
57
- end
58
-
59
- unless defined?(`Math.asinh`)
60
- %x{
61
- Math.asinh = function(x) {
62
- return Math.log(x + Math.sqrt(x * x + 1))
63
- }
64
- }
65
- end
66
-
67
- def asinh(x)
68
- ::Math.checked :asinh, ::Math.float!(x)
69
- end
70
-
71
- def atan(x)
72
- ::Math.checked :atan, ::Math.float!(x)
73
- end
74
-
75
- def atan2(y, x)
76
- ::Math.checked :atan2, ::Math.float!(y), ::Math.float!(x)
77
- end
78
-
79
- unless defined?(`Math.atanh`)
80
- %x{
81
- Math.atanh = function(x) {
82
- return 0.5 * Math.log((1 + x) / (1 - x));
83
- }
84
- }
85
- end
86
-
87
- def atanh(x)
88
- ::Math.checked :atanh, ::Math.float!(x)
89
- end
90
-
91
- unless defined?(`Math.cbrt`)
92
- %x{
93
- Math.cbrt = function(x) {
94
- if (x == 0) {
95
- return 0;
96
- }
97
-
98
- if (x < 0) {
99
- return -Math.cbrt(-x);
100
- }
101
-
102
- var r = x,
103
- ex = 0;
104
-
105
- while (r < 0.125) {
106
- r *= 8;
107
- ex--;
108
- }
109
-
110
- while (r > 1.0) {
111
- r *= 0.125;
112
- ex++;
113
- }
114
-
115
- r = (-0.46946116 * r + 1.072302) * r + 0.3812513;
116
-
117
- while (ex < 0) {
118
- r *= 0.5;
119
- ex++;
120
- }
121
-
122
- while (ex > 0) {
123
- r *= 2;
124
- ex--;
125
- }
126
-
127
- r = (2.0 / 3.0) * r + (1.0 / 3.0) * x / (r * r);
128
- r = (2.0 / 3.0) * r + (1.0 / 3.0) * x / (r * r);
129
- r = (2.0 / 3.0) * r + (1.0 / 3.0) * x / (r * r);
130
- r = (2.0 / 3.0) * r + (1.0 / 3.0) * x / (r * r);
131
-
132
- return r;
133
- }
134
- }
135
- end
136
-
137
- def cbrt(x)
138
- ::Math.checked :cbrt, ::Math.float!(x)
139
- end
140
-
141
- def cos(x)
142
- ::Math.checked :cos, ::Math.float!(x)
143
- end
144
-
145
- unless defined?(`Math.cosh`)
146
- %x{
147
- Math.cosh = function(x) {
148
- return (Math.exp(x) + Math.exp(-x)) / 2;
149
- }
150
- }
151
- end
152
-
153
- def cosh(x)
154
- ::Math.checked :cosh, ::Math.float!(x)
155
- end
156
-
157
39
  unless defined?(`Math.erf`)
158
40
  %x{
159
41
  Opal.prop(Math, 'erf', function(x) {
@@ -180,10 +62,6 @@ module ::Math
180
62
  }
181
63
  end
182
64
 
183
- def erf(x)
184
- ::Math.checked :erf, ::Math.float!(x)
185
- end
186
-
187
65
  unless defined?(`Math.erfc`)
188
66
  %x{
189
67
  Opal.prop(Math, 'erfc', function(x) {
@@ -213,12 +91,22 @@ module ::Math
213
91
  }
214
92
  end
215
93
 
216
- def erfc(x)
217
- ::Math.checked :erfc, ::Math.float!(x)
94
+ # Single argument equivalent functions
95
+ %i[
96
+ acos acosh asin asinh atan atanh cbrt
97
+ cos cosh erf erfc exp sin sinh sqrt tanh
98
+ ].each do |method|
99
+ define_method method do |x|
100
+ ::Math.checked method, ::Math.float!(x)
101
+ end
218
102
  end
219
103
 
220
- def exp(x)
221
- ::Math.checked :exp, ::Math.float!(x)
104
+ def atan2(y, x)
105
+ ::Math.checked :atan2, ::Math.float!(y), ::Math.float!(x)
106
+ end
107
+
108
+ def hypot(x, y)
109
+ ::Math.checked :hypot, ::Math.float!(x), ::Math.float!(y)
222
110
  end
223
111
 
224
112
  def frexp(x)
@@ -332,18 +220,6 @@ module ::Math
332
220
  }
333
221
  end
334
222
 
335
- unless defined?(`Math.hypot`)
336
- %x{
337
- Math.hypot = function(x, y) {
338
- return Math.sqrt(x * x + y * y)
339
- }
340
- }
341
- end
342
-
343
- def hypot(x, y)
344
- ::Math.checked :hypot, ::Math.float!(x), ::Math.float!(y)
345
- end
346
-
347
223
  def ldexp(mantissa, exponent)
348
224
  mantissa = Math.float!(mantissa)
349
225
  exponent = Math.integer!(exponent)
@@ -384,14 +260,6 @@ module ::Math
384
260
  end
385
261
  end
386
262
 
387
- unless defined?(`Math.log10`)
388
- %x{
389
- Math.log10 = function(x) {
390
- return Math.log(x) / Math.LN10;
391
- }
392
- }
393
- end
394
-
395
263
  def log10(x)
396
264
  if ::String === x
397
265
  ::Kernel.raise `$type_error(x, #{::Float})`
@@ -400,14 +268,6 @@ module ::Math
400
268
  ::Math.checked :log10, ::Math.float!(x)
401
269
  end
402
270
 
403
- unless defined?(`Math.log2`)
404
- %x{
405
- Math.log2 = function(x) {
406
- return Math.log(x) / Math.LN2;
407
- }
408
- }
409
- end
410
-
411
271
  def log2(x)
412
272
  if ::String === x
413
273
  ::Kernel.raise `$type_error(x, #{::Float})`
@@ -416,26 +276,6 @@ module ::Math
416
276
  ::Math.checked :log2, ::Math.float!(x)
417
277
  end
418
278
 
419
- def sin(x)
420
- ::Math.checked :sin, ::Math.float!(x)
421
- end
422
-
423
- unless defined?(`Math.sinh`)
424
- %x{
425
- Math.sinh = function(x) {
426
- return (Math.exp(x) - Math.exp(-x)) / 2;
427
- }
428
- }
429
- end
430
-
431
- def sinh(x)
432
- ::Math.checked :sinh, ::Math.float!(x)
433
- end
434
-
435
- def sqrt(x)
436
- ::Math.checked :sqrt, ::Math.float!(x)
437
- end
438
-
439
279
  def tan(x)
440
280
  x = ::Math.float!(x)
441
281
 
@@ -445,24 +285,4 @@ module ::Math
445
285
 
446
286
  ::Math.checked :tan, ::Math.float!(x)
447
287
  end
448
-
449
- unless defined?(`Math.tanh`)
450
- %x{
451
- Math.tanh = function(x) {
452
- if (x == Infinity) {
453
- return 1;
454
- }
455
- else if (x == -Infinity) {
456
- return -1;
457
- }
458
- else {
459
- return (Math.exp(x) - Math.exp(-x)) / (Math.exp(x) + Math.exp(-x));
460
- }
461
- }
462
- }
463
- end
464
-
465
- def tanh(x)
466
- ::Math.checked :tanh, ::Math.float!(x)
467
- end
468
288
  end
@@ -1,4 +1,4 @@
1
- # helpers: truthy, coerce_to, const_set, Object
1
+ # helpers: truthy, coerce_to, const_set, Object, return_ivar, assign_ivar, ivar
2
2
 
3
3
  class ::Module
4
4
  def self.allocate
@@ -131,20 +131,9 @@ class ::Module
131
131
  for (var i = names.length - 1; i >= 0; i--) {
132
132
  var name = names[i],
133
133
  id = '$' + name,
134
- ivar = Opal.ivar(name);
135
-
136
- // the closure here is needed because name will change at the next
137
- // cycle, I wish we could use let.
138
- var body = (function(ivar) {
139
- return function() {
140
- if (this[ivar] == null) {
141
- return nil;
142
- }
143
- else {
144
- return this[ivar];
145
- }
146
- };
147
- })(ivar);
134
+ ivar = $ivar(name);
135
+
136
+ var body = $return_ivar(ivar);
148
137
 
149
138
  // initialize the instance variable as nil
150
139
  Opal.prop(proto, ivar, nil);
@@ -166,15 +155,9 @@ class ::Module
166
155
  for (var i = names.length - 1; i >= 0; i--) {
167
156
  var name = names[i],
168
157
  id = '$' + name + '=',
169
- ivar = Opal.ivar(name);
158
+ ivar = $ivar(name);
170
159
 
171
- // the closure here is needed because name will change at the next
172
- // cycle, I wish we could use let.
173
- var body = (function(ivar){
174
- return function(value) {
175
- return this[ivar] = value;
176
- }
177
- })(ivar);
160
+ var body = $assign_ivar(ivar)
178
161
 
179
162
  body.$$parameters = [['req']];
180
163
  body.$$arity = 1;
@@ -396,14 +379,29 @@ class ::Module
396
379
  end
397
380
 
398
381
  %x{
399
- var id = '$' + name;
382
+ if (typeof(Proxy) !== 'undefined') {
383
+ var meta = Object.create(null)
384
+
385
+ block.$$proxy_target = block
386
+ block = new Proxy(block, {
387
+ apply: function(target, self, args) {
388
+ var old_name = target.$$jsid
389
+ target.$$jsid = name;
390
+ try {
391
+ return target.apply(self, args);
392
+ } finally {
393
+ target.$$jsid = old_name
394
+ }
395
+ }
396
+ })
397
+ }
400
398
 
401
399
  block.$$jsid = name;
402
400
  block.$$s = null;
403
401
  block.$$def = block;
404
402
  block.$$define_meth = true;
405
403
 
406
- return Opal.defn(self, id, block);
404
+ return Opal.defn(self, '$' + name, block);
407
405
  }
408
406
  end
409
407
 
@@ -263,20 +263,6 @@ class ::Number < ::Numeric
263
263
  end
264
264
  end
265
265
 
266
- def ===(other)
267
- %x{
268
- if (other.$$is_number) {
269
- return self.valueOf() === other.valueOf();
270
- }
271
- else if (#{other.respond_to? :==}) {
272
- return #{other == self};
273
- }
274
- else {
275
- return false;
276
- }
277
- }
278
- end
279
-
280
266
  def ==(other)
281
267
  %x{
282
268
  if (other.$$is_number) {
@@ -291,6 +277,8 @@ class ::Number < ::Numeric
291
277
  }
292
278
  end
293
279
 
280
+ alias === ==
281
+
294
282
  def abs
295
283
  `Math.abs(self)`
296
284
  end
@@ -817,6 +805,67 @@ class ::Number < ::Numeric
817
805
  `self == -Infinity || 1 / self < 0`
818
806
  end
819
807
 
808
+ %x{
809
+ function numberToUint8Array(num) {
810
+ var uint8array = new Uint8Array(8);
811
+ new DataView(uint8array.buffer).setFloat64(0, num, true);
812
+ return uint8array;
813
+ }
814
+
815
+ function uint8ArrayToNumber(arr) {
816
+ return new DataView(arr.buffer).getFloat64(0, true);
817
+ }
818
+
819
+ function incrementNumberBit(num) {
820
+ var arr = numberToUint8Array(num);
821
+ for (var i = 0; i < arr.length; i++) {
822
+ if (arr[i] === 0xff) {
823
+ arr[i] = 0;
824
+ } else {
825
+ arr[i]++;
826
+ break;
827
+ }
828
+ }
829
+ return uint8ArrayToNumber(arr);
830
+ }
831
+
832
+ function decrementNumberBit(num) {
833
+ var arr = numberToUint8Array(num);
834
+ for (var i = 0; i < arr.length; i++) {
835
+ if (arr[i] === 0) {
836
+ arr[i] = 0xff;
837
+ } else {
838
+ arr[i]--;
839
+ break;
840
+ }
841
+ }
842
+ return uint8ArrayToNumber(arr);
843
+ }
844
+ }
845
+
846
+ def next_float
847
+ return ::Float::INFINITY if self == ::Float::INFINITY
848
+ return ::Float::NAN if nan?
849
+
850
+ if self >= 0
851
+ # Math.abs() is needed to handle -0.0
852
+ `incrementNumberBit(Math.abs(self))`
853
+ else
854
+ `decrementNumberBit(self)`
855
+ end
856
+ end
857
+
858
+ def prev_float
859
+ return -::Float::INFINITY if self == -::Float::INFINITY
860
+ return ::Float::NAN if nan?
861
+
862
+ if self > 0
863
+ `decrementNumberBit(self)`
864
+ else
865
+ `-incrementNumberBit(Math.abs(self))`
866
+ end
867
+ end
868
+
820
869
  alias arg angle
821
870
  alias eql? ==
822
871
  alias fdiv /
@@ -83,6 +83,8 @@ class ::Regexp < `RegExp`
83
83
  #{::Kernel.raise ::RegexpError, "too short escape sequence: /#{regexp}/"}
84
84
  }
85
85
 
86
+ regexp = regexp.replace('\\A', '^').replace('\\z', '$')
87
+
86
88
  if (options === undefined || #{!options}) {
87
89
  return new RegExp(regexp);
88
90
  }
@@ -184,7 +184,22 @@
184
184
  };
185
185
 
186
186
  Opal.coerce_to = function(object, type, method, args) {
187
- if (type['$==='](object)) return object;
187
+ var body;
188
+
189
+ if (method === 'to_int' && type === Opal.Integer && object.$$is_number)
190
+ return object < 0 ? Math.ceil(object) : Math.floor(object);
191
+
192
+ if (method === 'to_str' && type === Opal.String && object.$$is_string)
193
+ return object;
194
+
195
+ if (Opal.is_a(object, type)) return object;
196
+
197
+ // Fast path for the most common situation
198
+ if (object['$respond_to?'].$$pristine && object.$method_missing.$$pristine) {
199
+ body = object['$' + method];
200
+ if (body == null || body.$$stub) throw Opal.type_error(object, type);
201
+ return body.apply(object, args);
202
+ }
188
203
 
189
204
  if (!object['$respond_to?'](method)) {
190
205
  throw Opal.type_error(object, type);
@@ -1592,7 +1607,10 @@
1592
1607
  }
1593
1608
 
1594
1609
  if (implicit && current_func.$$define_meth) {
1595
- throw Opal.RuntimeError.$new("implicit argument passing of super from method defined by define_method() is not supported. Specify all arguments explicitly");
1610
+ throw Opal.RuntimeError.$new(
1611
+ "implicit argument passing of super from method defined by define_method() is not supported. " +
1612
+ "Specify all arguments explicitly"
1613
+ );
1596
1614
  }
1597
1615
 
1598
1616
  if (current_func.$$def) {
@@ -1708,15 +1726,9 @@
1708
1726
  return (klass.$$is_integer_class) ? (object % 1) === 0 : true;
1709
1727
  }
1710
1728
 
1711
- var i, length, ancestors = Opal.ancestors(object.$$is_class ? Opal.get_singleton_class(object) : (object.$$meta || object.$$class));
1729
+ var ancestors = Opal.ancestors(object.$$is_class ? Opal.get_singleton_class(object) : (object.$$meta || object.$$class));
1712
1730
 
1713
- for (i = 0, length = ancestors.length; i < length; i++) {
1714
- if (ancestors[i] === klass) {
1715
- return true;
1716
- }
1717
- }
1718
-
1719
- return false;
1731
+ return ancestors.indexOf(klass) !== -1;
1720
1732
  };
1721
1733
 
1722
1734
  // Helpers for extracting kwsplats
@@ -1874,8 +1886,6 @@
1874
1886
  Opal.send = function(recv, method, args, block, blockopts) {
1875
1887
  var body;
1876
1888
 
1877
- apply_blockopts(block, blockopts);
1878
-
1879
1889
  if (typeof(method) === 'function') {
1880
1890
  body = method;
1881
1891
  method = null;
@@ -1885,7 +1895,7 @@
1885
1895
  throw Opal.NameError.$new("Passed method should be a string or a function");
1886
1896
  }
1887
1897
 
1888
- return Opal.send2(recv, body, method, args, block);
1898
+ return Opal.send2(recv, body, method, args, block, blockopts);
1889
1899
  };
1890
1900
 
1891
1901
  Opal.send2 = function(recv, body, method, args, block, blockopts) {
@@ -1909,8 +1919,6 @@
1909
1919
  ancestors = Opal.ancestors(recv.$$class);
1910
1920
  }
1911
1921
 
1912
- apply_blockopts(block, blockopts);
1913
-
1914
1922
  // For all ancestors that there are, starting from the closest to the furthest...
1915
1923
  for (i = 0; i < ancestors.length; i++) {
1916
1924
  ancestor = Opal.id(ancestors[i]);
@@ -1930,14 +1938,14 @@
1930
1938
  // Does this module define a method we want to call?
1931
1939
  if (typeof refine_module.$$prototype['$'+method] !== 'undefined') {
1932
1940
  body = refine_module.$$prototype['$'+method];
1933
- return Opal.send2(recv, body, method, args, block);
1941
+ return Opal.send2(recv, body, method, args, block, blockopts);
1934
1942
  }
1935
1943
  }
1936
1944
  }
1937
1945
  }
1938
1946
  }
1939
1947
 
1940
- return Opal.send(recv, method, args, block);
1948
+ return Opal.send(recv, method, args, block, blockopts);
1941
1949
  };
1942
1950
 
1943
1951
  Opal.lambda = function(block, blockopts) {
@@ -2654,7 +2662,7 @@
2654
2662
  if (typeof Promise !== 'undefined' && retval instanceof Promise) {
2655
2663
  // A special case of require having an async top:
2656
2664
  // We will need to await it.
2657
- return retval.then(function() { return true; });
2665
+ return retval.then($return_val(true));
2658
2666
  }
2659
2667
  }
2660
2668
  else {
@@ -2777,13 +2785,15 @@
2777
2785
  Opal.rb_ge = function(l,r) { return (typeof(l) === 'number' && typeof(r) === 'number') ? l >= r : l['$>='](r); }
2778
2786
 
2779
2787
  // Optimized helpers for calls like $truthy((a)['$==='](b)) -> $eqeqeq(a, b)
2780
- Opal.eqeq = function(lhs, rhs) {
2788
+ function $eqeq(lhs, rhs) {
2781
2789
  if ((typeof lhs === 'number' && typeof rhs === 'number') ||
2782
2790
  (typeof lhs === 'string' && typeof rhs === 'string')) {
2783
2791
  return lhs === rhs;
2784
2792
  }
2785
2793
  return $truthy((lhs)['$=='](rhs));
2786
2794
  };
2795
+ Opal.eqeq = $eqeq;
2796
+
2787
2797
  Opal.eqeqeq = function(lhs, rhs) {
2788
2798
  if ((typeof lhs === 'number' && typeof rhs === 'number') ||
2789
2799
  (typeof lhs === 'string' && typeof rhs === 'string')) {
@@ -2804,7 +2814,33 @@
2804
2814
  return $truthy(arg['$!']());
2805
2815
  }
2806
2816
 
2817
+ // Shortcuts - optimized function generators for simple kinds of functions
2818
+ function $return_val(arg) {
2819
+ return function() {
2820
+ return arg;
2821
+ }
2822
+ }
2823
+ Opal.return_val = $return_val;
2807
2824
 
2825
+ Opal.return_self = function() {
2826
+ return this;
2827
+ }
2828
+ Opal.return_ivar = function(ivar) {
2829
+ return function() {
2830
+ if (this[ivar] == null) this[ivar] = nil;
2831
+ return this[ivar];
2832
+ }
2833
+ }
2834
+ Opal.assign_ivar = function(ivar) {
2835
+ return function(val) {
2836
+ return this[ivar] = val;
2837
+ }
2838
+ }
2839
+ Opal.assign_ivar_val = function(ivar, static_val) {
2840
+ return function() {
2841
+ return this[ivar] = static_val;
2842
+ }
2843
+ }
2808
2844
 
2809
2845
  // Initialization
2810
2846
  // --------------
@@ -2856,7 +2892,7 @@
2856
2892
 
2857
2893
  // Instantiate the main object
2858
2894
  Opal.top = new _Object();
2859
- Opal.top.$to_s = Opal.top.$inspect = function() { return 'main' };
2895
+ Opal.top.$to_s = Opal.top.$inspect = $return_val('main');
2860
2896
  Opal.top.$define_method = top_define_method;
2861
2897
 
2862
2898
  // Foward calls to define_method on the top object to Object