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
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: f199262b85612cb61bd3f3fa1d05ec8a7fb3fa6fabbd63a36baa03859e241c5c
4
- data.tar.gz: e4af60acb540708612fbed3e4aa04fef968b750b0ff588774bda6d979586fc8f
3
+ metadata.gz: 6ac3c5ae91f1f31b94c292f0aed320bdba76511abd34bb6dc45294c11958e802
4
+ data.tar.gz: 473ca0893f427b05c88c64805dc0f64668816b263b136863b903f5262aba7aef
5
5
  SHA512:
6
- metadata.gz: a4ece0468468bc541c155cb53185550f35b4277c89e18f32990a7bb8abff6c20beaeb9f962f02f80b1afc251a75c0916d35dd8d2944fa8153aa4a6454a7ddf8a
7
- data.tar.gz: 81539b2993e44bfa8217cda753badaa292c26117de8366d04e50922309b95654f5c09f983a02f329b36ea1405affc52c3831c7122f4215a90e7a78c9084b9b31
6
+ metadata.gz: 5ba1e5223c56695db351ede10b36872590b29701f4576c9a1962502686434548d855d71fdd147e5b34492bb70964db72bed3229cc552dfa139a2db747dd4caa1
7
+ data.tar.gz: 30e97d6c8293b918084145f15cd9f42d6495989405d97ebbccc414440c281a8297405f651560e8a65ea21dda191631d9bd20fda058d5693af1c25b8b61cc1e40
data/.eslintrc.js CHANGED
@@ -24,12 +24,14 @@ module.exports = {
24
24
  "no-control-regex": "off",
25
25
  },
26
26
  "globals": {
27
- "Opal": "readonly",
28
- "DataView": "readonly",
29
27
  "ArrayBuffer": "readonly",
28
+ "DataView": "readonly",
30
29
  "globalThis": "readonly",
31
- "Uint8Array": "readonly",
30
+ "Opal": "readonly",
32
31
  "Promise": "readonly",
32
+ "Proxy": "readonly",
33
+ "Reflect": "readonly",
34
+ "Uint8Array": "readonly",
33
35
  "WeakRef": "readonly",
34
36
  }
35
37
  };
data/.rubocop.yml CHANGED
@@ -365,6 +365,7 @@ Naming/FileName:
365
365
  - 'stdlib/opal-parser.rb'
366
366
  - 'stdlib/opal-platform.rb'
367
367
  - 'stdlib/opal-source-maps.rb'
368
+ - 'stdlib/opal-replutils.rb'
368
369
 
369
370
  Naming/ConstantName:
370
371
  Exclude:
data/UNRELEASED.md CHANGED
@@ -1,8 +1,43 @@
1
- <!--
1
+ ### Added
2
+
3
+ - Introduce timezone support for Time (#2394)
4
+ - DateTime and Date refactor (#2398)
5
+ - Implement `Number#prev_float`/`#next_float` (#2404)
6
+ - Support `binding.irb` anywhere in the code, for both browsers and node (#2392)
7
+ - Added `URI.decode_www_form` (#2387)
8
+
9
+ ### Changed
10
+
11
+ - Move Math IE11-supporting polyfills to a separate file (#2395)
12
+ - String methods always return Strings even when overloaded (#2413)
13
+ - `alias` calls will not add the "old name" method to the list of stubs for method missing (#2414)
14
+ - Optimize writer/setter methods, up to 4% performance gain (#2402)
15
+
16
+ ### Performance
17
+
18
+ - Improve performance of argument coertion, fast-track `Integer`, `String`, and calling the designed coertion method (#2383)
19
+ - Optimize `Array#[]=` by moving the implementation to JavaScript and inlining type checks (#2383)
20
+ - Optimize internal runtime passing of block-options (#2383)
21
+ - Compile `case` statements as `switch` whenever possible (#2411)
22
+ - Improve performance with optimized common method/iter implementation shortcuts (#2401)
23
+
2
24
  ### Fixed
25
+
26
+ - Fix `Regexp.new`, previously `\A` and `\z` didn't match beginning and end of input (#2079)
27
+ - Fix exception during `Hash#each` and `Hash#each_key` if keys get deleted during the loop (#2403)
28
+ - Fix defining multiple methods with the same block (#2397)
29
+ - A few edge cases of conditional calls combined with setters, e.g. `foo&.bar = 123` (#2402)
30
+ - Correct String#to_proc and method_missing compatibility (#2418)
31
+ - Exit REPL respecting the exit status number (#2396)
32
+
33
+ ### Internal
34
+
35
+ - Rewriters refactor, fix interaction between cache and inverted runner (#2400)
36
+
37
+ <!--
38
+ ### Internal
3
39
  ### Changed
4
40
  ### Added
5
41
  ### Removed
6
42
  ### Deprecated
7
- ### Internal
8
43
  -->
@@ -1,33 +1,58 @@
1
1
  Benchmark.ips do |x|
2
2
  %x{
3
+ const c_foo = 'foo'
4
+ const v_foo = 'foo'
5
+ const cfoo = Symbol('foo')
6
+ var vfoo = Symbol('foo')
7
+ const cgfoo = Symbol.for('foo')
8
+ var vgfoo = Symbol.for('foo')
9
+
3
10
  var o = {}
4
- o[Symbol.for('foo')] = 123
5
- o.foo = 123
6
- var foo = Symbol('foo')
7
- var gfoo = Symbol.for('foo')
8
- o[foo] = 123
9
- var a = 0, b = 0, c = 0
11
+ o[cfoo] = 1
12
+ o[cgfoo] = 1
13
+ o[c_foo] = 1
14
+ o[vfoo] = 1
15
+
16
+ let a1 = 0, a2 = 0, a3 = 0, a4 = 0, a5 = 0, a6 = 0, a7 = 0, a8 = 0
10
17
  }
11
18
 
19
+ x.report('const string ref') do
20
+ `a1 += o[c_foo]`
21
+ end
22
+
23
+ x.report('var string ref') do
24
+ `a2 += o[v_foo]`
25
+ end
26
+
12
27
  x.report('live global symbol') do
13
- `a += o[Symbol.for('foo')]`
28
+ `a3 += o[Symbol.for('foo')]`
14
29
  end
15
30
 
16
- x.report('stored global symbol') do
17
- `a += o[gfoo]`
31
+ x.report('const global symbol') do
32
+ `a4 += o[cgfoo]`
18
33
  end
19
34
 
20
- x.report('stored symbol') do
21
- `a += o[foo]`
35
+ x.report('var global symbol') do
36
+ `a5 += o[vgfoo]`
37
+ end
38
+
39
+ x.report('const symbol') do
40
+ `a6 += o[cfoo]`
41
+ end
42
+
43
+ x.report('var symbol') do
44
+ `a6 += o[vfoo]`
22
45
  end
23
46
 
24
47
  x.report('ident') do
25
- `b += o.foo`
48
+ `a7 += o.foo`
26
49
  end
27
50
 
28
- x.report('string') do
29
- `c += o['foo']`
51
+ x.report('live string') do
52
+ `a8 += o['foo']`
30
53
  end
31
54
 
55
+ x.time = 10
56
+
32
57
  x.compare!
33
58
  end
data/docs/releasing.md CHANGED
@@ -10,8 +10,8 @@ _This guide is a work-in-progress._
10
10
  ## Updating the changelog
11
11
 
12
12
  - Ensure all the unreleased changes are documented in UNRELEASED.md
13
- - Run `bin/rake changelog VERSION=v1.2.3` specifying the version number you're about to release
14
- - Empty UNRELEASED.md
13
+ - [skip for pre-releases] Run `bin/rake changelog VERSION=v1.2.3` specifying the version number you're about to release
14
+ - [skip for pre-releases] Empty UNRELEASED.md
15
15
 
16
16
  ## The commit
17
17
 
@@ -34,3 +34,11 @@ _This guide is a work-in-progress._
34
34
  ## Opal CDN
35
35
 
36
36
  - Run `bin/release v1.2.3`
37
+
38
+ ## Prepare for the next release
39
+
40
+ - Skip this step if releasing a stable release
41
+ - Create a new pull request that:
42
+ - Updates a version to `v1.x.0.dev` in both `lib/opal/version.rb` and `opal/corelib/constants.rb`
43
+ - Remember to merge that PR before merging anything else next once we decide to not release any more point releases from `master`.
44
+
@@ -0,0 +1,77 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'ast'
4
+ require 'parser/ast/node'
5
+
6
+ module Opal
7
+ module AST
8
+ class Matcher
9
+ def initialize(&block)
10
+ @root = instance_exec(&block)
11
+ end
12
+
13
+ def s(type, *children)
14
+ Node.new(type, children)
15
+ end
16
+
17
+ def cap(capture)
18
+ Node.new(:capture, [capture])
19
+ end
20
+
21
+ def match(ast)
22
+ @captures = []
23
+ @root.match(ast, self) || (return false)
24
+ @captures
25
+ end
26
+
27
+ def inspect
28
+ "#<Opal::AST::Matcher: #{@root.inspect}>"
29
+ end
30
+
31
+ attr_accessor :captures
32
+
33
+ Node = Struct.new(:type, :children) do
34
+ def match(ast, matcher)
35
+ return false if ast.nil?
36
+
37
+ ast_parts = [ast.type] + ast.children
38
+ self_parts = [type] + children
39
+
40
+ return false if ast_parts.length != self_parts.length
41
+
42
+ ast_parts.length.times.all? do |i|
43
+ ast_elem = ast_parts[i]
44
+ self_elem = self_parts[i]
45
+
46
+ if self_elem.is_a?(Node) && self_elem.type == :capture
47
+ capture = true
48
+ self_elem = self_elem.children.first
49
+ end
50
+
51
+ res = case self_elem
52
+ when Node
53
+ self_elem.match(ast_elem, matcher)
54
+ when Array
55
+ self_elem.include?(ast_elem)
56
+ when :*
57
+ true
58
+ else
59
+ self_elem == ast_elem
60
+ end
61
+
62
+ matcher.captures << ast_elem if capture
63
+ res
64
+ end
65
+ end
66
+
67
+ def inspect
68
+ if type == :capture
69
+ "{#{children.first.inspect}}"
70
+ else
71
+ "s(#{type.inspect}, #{children.inspect[1..-2]})"
72
+ end
73
+ end
74
+ end
75
+ end
76
+ end
77
+ end
data/lib/opal/cache.rb CHANGED
@@ -41,7 +41,7 @@ module Opal
41
41
 
42
42
  data || begin
43
43
  compiler = yield
44
- cache.set(key, compiler)
44
+ cache.set(key, compiler) unless compiler.dynamic_cache_result
45
45
  compiler
46
46
  end
47
47
  end
@@ -1,5 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require 'opal/cli_runners/system_runner'
4
+
3
5
  module Opal
4
6
  module CliRunners
5
7
  class Applescript
data/lib/opal/compiler.rb CHANGED
@@ -217,9 +217,16 @@ module Opal
217
217
  # Comments from the source code
218
218
  attr_reader :comments
219
219
 
220
+ # Method calls made in this file
221
+ attr_reader :method_calls
222
+
220
223
  # Magic comment flags extracted from the leading comments
221
224
  attr_reader :magic_comments
222
225
 
226
+ # Set if some rewritter caused a dynamic cache result, meaning it's not
227
+ # fit to be cached
228
+ attr_accessor :dynamic_cache_result
229
+
223
230
  def initialize(source, options = {})
224
231
  @source = source
225
232
  @indent = ''
@@ -227,8 +234,10 @@ module Opal
227
234
  @options = options
228
235
  @comments = Hash.new([])
229
236
  @case_stmt = nil
237
+ @method_calls = Set.new
230
238
  @option_values = {}
231
239
  @magic_comments = {}
240
+ @dynamic_cache_result = false
232
241
  end
233
242
 
234
243
  # Compile some ruby code to a string.
@@ -260,9 +269,12 @@ module Opal
260
269
  :main
261
270
  end
262
271
 
263
- @sexp = s(:top, sexp || s(:nil)).tap { |i| i.meta[:kind] = kind }
264
- @comments = ::Parser::Source::Comment.associate_locations(sexp, comments)
265
- @magic_comments = MagicComments.parse(sexp, comments)
272
+ @sexp = sexp.tap { |i| i.meta[:kind] = kind }
273
+
274
+ first_node = sexp.children.first if sexp.children.first.location
275
+
276
+ @comments = ::Parser::Source::Comment.associate_locations(first_node, comments)
277
+ @magic_comments = MagicComments.parse(first_node, comments)
266
278
  @eof_content = EofContent.new(tokens, @source).eof
267
279
  end
268
280
 
@@ -287,9 +299,8 @@ module Opal
287
299
  )
288
300
  end
289
301
 
290
- # Method calls made in this file
291
- def method_calls
292
- @method_calls ||= Set.new
302
+ def record_method_call(mid)
303
+ @method_calls << mid
293
304
  end
294
305
 
295
306
  alias async_await_before_typecasting async_await
@@ -353,9 +364,7 @@ module Opal
353
364
  @indent
354
365
  end
355
366
 
356
- # Create a new sexp using the given parts. Even though this just
357
- # returns an array, it must be used incase the internal structure
358
- # of sexps does change.
367
+ # Create a new sexp using the given parts.
359
368
  def s(type, *children)
360
369
  ::Opal::AST::Node.new(type, children)
361
370
  end
@@ -8,7 +8,7 @@ require 'opal/rewriters/break_finder'
8
8
  module Opal
9
9
  module Nodes
10
10
  class CallNode < Base
11
- handle :send
11
+ handle :send, :csend
12
12
 
13
13
  attr_reader :recvr, :meth, :arglist, :iter
14
14
 
@@ -43,15 +43,19 @@ module Opal
43
43
  # handle some methods specially
44
44
  # some special methods need to skip compilation, so we pass the default as a block
45
45
  handle_special do
46
- compiler.method_calls << meth.to_sym if record_method?
47
-
48
- # if trying to access an lvar in eval or irb mode
49
- return compile_eval_var if using_eval?
50
-
51
- # if trying to access an lvar in irb mode
52
- return compile_irb_var if using_irb?
53
-
54
- default_compile
46
+ compiler.record_method_call meth
47
+
48
+ with_wrapper do
49
+ if using_eval?
50
+ # if trying to access an lvar in eval or irb mode
51
+ compile_eval_var
52
+ elsif using_irb?
53
+ # if trying to access an lvar in irb mode
54
+ compile_irb_var
55
+ else
56
+ default_compile
57
+ end
58
+ end
55
59
  end
56
60
  end
57
61
 
@@ -81,13 +85,18 @@ module Opal
81
85
  # to a method body. This is some kind of protection from method calls
82
86
  # like 'a(a {}) { 1 }'.
83
87
  def invoke_using_send?
84
- iter || splat?
88
+ iter || splat? || call_is_writer_that_needs_handling?
85
89
  end
86
90
 
87
91
  def invoke_using_refinement?
88
92
  !scope.scope.collect_refinements_temps.empty?
89
93
  end
90
94
 
95
+ # Is it a conditional send, ie. `foo&.bar`?
96
+ def csend?
97
+ @sexp.type == :csend
98
+ end
99
+
91
100
  def default_compile
92
101
  if auto_await?
93
102
  push 'await '
@@ -143,17 +152,19 @@ module Opal
143
152
  end
144
153
 
145
154
  def compile_receiver
146
- push recv(receiver_sexp)
155
+ push @conditional_recvr || recv(receiver_sexp)
147
156
  end
148
157
 
149
158
  def compile_method_name
150
159
  push ", '#{meth}'"
151
160
  end
152
161
 
153
- def compile_arguments
154
- push ', '
162
+ def compile_arguments(skip_comma = false)
163
+ push ', ' unless skip_comma
155
164
 
156
- if splat?
165
+ if @with_writer_temp
166
+ push @with_writer_temp
167
+ elsif splat?
157
168
  push expr(arglist)
158
169
  elsif arglist.children.empty?
159
170
  push '[]'
@@ -197,16 +208,13 @@ module Opal
197
208
  mid_to_jsid meth.to_s
198
209
  end
199
210
 
200
- def record_method?
201
- true
202
- end
203
-
204
211
  # Used to generate the code to use this sexp as an ivar var reference
205
212
  def compile_irb_var
206
213
  with_temp do |tmp|
207
214
  lvar = meth
208
215
  call = s(:send, s(:self), meth.intern, s(:arglist))
209
- push "((#{tmp} = Opal.irb_vars.#{lvar}) == null ? ", expr(call), " : #{tmp})"
216
+ ref = "(typeof #{lvar} !== 'undefined') ? #{lvar} : "
217
+ push "((#{tmp} = Opal.irb_vars.#{lvar}) == null ? ", ref, expr(call), " : #{tmp})"
210
218
  end
211
219
  end
212
220
 
@@ -255,7 +263,7 @@ module Opal
255
263
  if invoke_using_refinement?
256
264
  compile_default.call
257
265
  elsif compiler.inline_operators?
258
- compiler.method_calls << operator.to_sym if record_method?
266
+ compiler.record_method_call operator
259
267
  helper :"rb_#{name}"
260
268
  lhs, rhs = expr(recvr), expr(arglist)
261
269
 
@@ -414,13 +422,8 @@ module Opal
414
422
 
415
423
  scope.nesting
416
424
  push "Opal.Binding.$new("
417
- push " function($code, $value) {"
418
- push " if (typeof $value === 'undefined') {"
419
- push " return eval($code);"
420
- push " }"
421
- push " else {"
422
- push " return eval($code + ' = $value');"
423
- push " }"
425
+ push " function($code) {"
426
+ push " return eval($code);"
424
427
  push " },"
425
428
  push " ", scope.scope_locals.map(&:to_s).inspect, ","
426
429
  push " ", scope.self, ","
@@ -450,6 +453,48 @@ module Opal
450
453
  )
451
454
  end
452
455
 
456
+ def with_wrapper(&block)
457
+ if csend? && !@conditional_recvr
458
+ handle_conditional_send do
459
+ with_wrapper(&block)
460
+ end
461
+ elsif call_is_writer_that_needs_handling?
462
+ handle_writer(&block)
463
+ else
464
+ yield
465
+ end
466
+ end
467
+
468
+ def call_is_writer_that_needs_handling?
469
+ (expr? || recv?) && (meth.to_s =~ /^\w+=$/ || meth == :[]=)
470
+ end
471
+
472
+ # Handle safe-operator calls: foo&.bar / foo&.bar ||= baz / ...
473
+ def handle_conditional_send
474
+ # temporary variable that stores method receiver
475
+ receiver_temp = scope.new_temp
476
+ push "#{receiver_temp} = ", expr(recvr)
477
+
478
+ # execute the sexp only if the receiver isn't nil
479
+ push ", (#{receiver_temp} === nil || #{receiver_temp} == null) ? nil : "
480
+ @conditional_recvr = receiver_temp
481
+ yield
482
+ wrap '(', ')'
483
+ end
484
+
485
+ def handle_writer
486
+ with_temp do |temp|
487
+ push "(#{temp} = "
488
+ compile_arguments(true)
489
+ push ", "
490
+ @with_writer_temp = temp
491
+ yield
492
+ @with_writer_temp = false
493
+ push ", "
494
+ push "#{temp}[#{temp}.length - 1])"
495
+ end
496
+ end
497
+
453
498
  class DependencyResolver
454
499
  def initialize(compiler, sexp, missing_dynamic_require = nil)
455
500
  @compiler = compiler
@@ -10,6 +10,37 @@ module Opal
10
10
  children :mid, :inline_args, :stmts
11
11
 
12
12
  def compile
13
+ compile_body_or_shortcut
14
+
15
+ blockopts = []
16
+
17
+ blockopts << "$$arity: #{arity}"
18
+
19
+ if compiler.arity_check?
20
+ blockopts << "$$parameters: #{parameters_code}"
21
+ end
22
+
23
+ if compiler.parse_comments?
24
+ blockopts << "$$comments: #{comments_code}"
25
+ end
26
+
27
+ if compiler.enable_source_location?
28
+ blockopts << "$$source_location: #{source_location}"
29
+ end
30
+
31
+ if blockopts.length == 1
32
+ push ", #{arity}"
33
+ elsif blockopts.length > 1
34
+ push ', {', blockopts.join(', '), '}'
35
+ end
36
+
37
+ wrap_with_definition
38
+
39
+ scope.nesting if @define_nesting
40
+ scope.relative_access if @define_relative_access
41
+ end
42
+
43
+ def compile_body
13
44
  inline_params = nil
14
45
  scope_name = nil
15
46
 
@@ -51,33 +82,6 @@ module Opal
51
82
  unshift "async "
52
83
  end
53
84
  line '}'
54
-
55
- blockopts = []
56
-
57
- blockopts << "$$arity: #{arity}"
58
-
59
- if compiler.arity_check?
60
- blockopts << "$$parameters: #{parameters_code}"
61
- end
62
-
63
- if compiler.parse_comments?
64
- blockopts << "$$comments: #{comments_code}"
65
- end
66
-
67
- if compiler.enable_source_location?
68
- blockopts << "$$source_location: #{source_location}"
69
- end
70
-
71
- if blockopts.length == 1
72
- push ", #{arity}"
73
- elsif blockopts.length > 1
74
- push ', {', blockopts.join(', '), '}'
75
- end
76
-
77
- wrap_with_definition
78
-
79
- scope.nesting if @define_nesting
80
- scope.relative_access if @define_relative_access
81
85
  end
82
86
 
83
87
  def wrap_with_definition
@@ -31,6 +31,8 @@ module Opal
31
31
  push '$alias_gvar(', new_name_str, ', ', old_name_str, ')'
32
32
  when :dsym, :sym # This is a method alias: alias a b
33
33
  helper :alias
34
+ compiler.record_method_call old_name.children.last if old_name.type == :sym
35
+
34
36
  push "$alias(#{scope.self}, ", expr(new_name), ', ', expr(old_name), ')'
35
37
  else # Nothing else is available, but just in case, drop an error
36
38
  error "Opal doesn't know yet how to alias with #{new_name.type}"
@@ -72,22 +72,22 @@ module Opal
72
72
  case mid
73
73
  when :==
74
74
  helper :eqeq
75
- compiler.method_calls << mid
75
+ compiler.record_method_call mid
76
76
  [fragment('$eqeq('), expr(receiver), fragment(', '), expr(args.first), fragment(')')]
77
77
  when :===
78
78
  helper :eqeqeq
79
- compiler.method_calls << mid
79
+ compiler.record_method_call mid
80
80
  [fragment('$eqeqeq('), expr(receiver), fragment(', '), expr(args.first), fragment(')')]
81
81
  when :!=
82
82
  helper :neqeq
83
- compiler.method_calls << mid
83
+ compiler.record_method_call mid
84
84
  [fragment('$neqeq('), expr(receiver), fragment(', '), expr(args.first), fragment(')')]
85
85
  end
86
86
  elsif args.count == 0
87
87
  case mid
88
88
  when :!
89
89
  helper :not
90
- compiler.method_calls << mid
90
+ compiler.record_method_call mid
91
91
  [fragment('$not('), expr(receiver), fragment(')')]
92
92
  end
93
93
  end
@@ -114,25 +114,6 @@ module Opal
114
114
  end
115
115
  end
116
116
  end
117
-
118
- # Usefule for safe-operator calls: foo&.bar / foo&.bar ||= baz / ...
119
- #
120
- # @param recvr [sexp_pushable] The receiver of the call that will be
121
- # stored in a temporary variable
122
- # @yields receiver_temp [String] the name of the temporary variable
123
- # holding the ref to the original receiver, inside the block
124
- # an expr() should be pushed.
125
- #
126
- def conditional_send(recvr)
127
- # temporary variable that stores method receiver
128
- receiver_temp = scope.new_temp
129
- push "#{receiver_temp} = ", recvr
130
-
131
- # execute the sexp only if the receiver isn't nil
132
- push ", (#{receiver_temp} === nil || #{receiver_temp} == null) ? nil : "
133
- yield receiver_temp
134
- wrap '(', ')'
135
- end
136
117
  end
137
118
  end
138
119
  end