opal 1.4.1 → 1.5.0.rc1
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.
- checksums.yaml +4 -4
- data/.eslintrc.js +5 -3
- data/.rubocop.yml +1 -0
- data/UNRELEASED.md +37 -2
- data/benchmark-ips/bm_js_symbols_vs_strings.rb +39 -14
- data/docs/releasing.md +10 -2
- data/lib/opal/ast/matcher.rb +77 -0
- data/lib/opal/cache.rb +1 -1
- data/lib/opal/cli_runners/applescript.rb +2 -0
- data/lib/opal/compiler.rb +18 -9
- data/lib/opal/nodes/call.rb +73 -28
- data/lib/opal/nodes/def.rb +31 -27
- data/lib/opal/nodes/definitions.rb +2 -0
- data/lib/opal/nodes/helpers.rb +4 -23
- data/lib/opal/nodes/if.rb +222 -0
- data/lib/opal/nodes/iter.rb +41 -37
- data/lib/opal/nodes/literal.rb +2 -2
- data/lib/opal/nodes/masgn.rb +15 -17
- data/lib/opal/nodes/node_with_args/shortcuts.rb +100 -0
- data/lib/opal/nodes/node_with_args.rb +1 -0
- data/lib/opal/nodes/top.rb +26 -10
- data/lib/opal/nodes.rb +0 -1
- data/lib/opal/parser/default_config.rb +3 -2
- data/lib/opal/repl.rb +1 -1
- data/lib/opal/rewriter.rb +13 -6
- data/lib/opal/rewriters/base.rb +12 -1
- data/lib/opal/rewriters/rubyspec/filters_rewriter.rb +1 -0
- data/lib/opal/version.rb +1 -1
- data/opal/corelib/array.rb +23 -28
- data/opal/corelib/binding.rb +14 -4
- data/opal/corelib/constants.rb +3 -3
- data/opal/corelib/hash.rb +2 -2
- data/opal/corelib/irb.rb +192 -0
- data/opal/corelib/math/polyfills.rb +127 -0
- data/opal/corelib/math.rb +14 -194
- data/opal/corelib/module.rb +23 -25
- data/opal/corelib/number.rb +63 -14
- data/opal/corelib/regexp.rb +2 -0
- data/opal/corelib/runtime.js +56 -20
- data/opal/corelib/string.rb +38 -59
- data/opal/corelib/time.rb +106 -68
- data/opal/opal/full.rb +0 -1
- data/opal/opal.rb +4 -1
- data/spec/filters/bugs/date.rb +0 -3
- data/spec/filters/bugs/datetime.rb +65 -0
- data/spec/filters/bugs/float.rb +0 -18
- data/spec/filters/bugs/hash.rb +0 -2
- data/spec/filters/bugs/language.rb +0 -3
- data/spec/filters/bugs/marshal.rb +0 -1
- data/spec/filters/bugs/string.rb +0 -30
- data/spec/filters/bugs/time.rb +18 -8
- data/spec/lib/cli_spec.rb +2 -2
- data/spec/lib/compiler_spec.rb +8 -8
- data/spec/lib/rewriters/base_spec.rb +1 -1
- data/spec/lib/rewriters/binary_operator_assignment_spec.rb +34 -59
- data/spec/lib/rewriters/block_to_iter_spec.rb +3 -6
- data/spec/lib/rewriters/dot_js_syntax_spec.rb +2 -5
- data/spec/lib/rewriters/for_rewriter_spec.rb +0 -1
- data/spec/lib/rewriters/forward_args_spec.rb +2 -3
- data/spec/lib/rewriters/js_reserved_words_spec.rb +2 -15
- data/spec/lib/rewriters/logical_operator_assignment_spec.rb +64 -89
- data/spec/lib/rewriters/numblocks_spec.rb +3 -5
- data/spec/lib/rewriters/opal_engine_check_spec.rb +2 -14
- data/spec/lib/rewriters/rubyspec/filters_rewriter_spec.rb +10 -2
- data/spec/opal/compiler/irb_spec.rb +4 -0
- data/spec/opal/core/language/super_spec.rb +26 -0
- data/spec/opal/core/regexp/assertions_spec.rb +19 -0
- data/spec/opal/core/string/to_proc_spec.rb +19 -0
- data/spec/ruby_specs +4 -0
- data/spec/support/rewriters_helper.rb +43 -23
- data/stdlib/date/date_time.rb +71 -0
- data/stdlib/date/formatters.rb +28 -0
- data/stdlib/date/infinity.rb +73 -0
- data/stdlib/date.rb +77 -214
- data/stdlib/opal/repl_js.rb +1 -1
- data/stdlib/{opal/replutils.rb → opal-replutils.rb} +3 -3
- data/stdlib/time.rb +39 -2
- data/stdlib/uri.rb +53 -0
- data/tasks/performance/asciidoctor_test.rb.erb +3 -1
- data/tasks/performance/optimization_status.rb +3 -2
- data/tasks/performance.rake +69 -35
- data/tasks/testing.rake +1 -0
- data/test/opal/test_uri.rb +35 -0
- data/yarn.lock +27 -5
- metadata +31 -18
- data/lib/opal/nodes/csend.rb +0 -24
- data/lib/opal/rewriters/explicit_writer_return.rb +0 -59
- data/spec/lib/rewriters/explicit_writer_return_spec.rb +0 -186
- data/stdlib/nodejs/irb.rb +0 -43
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 6ac3c5ae91f1f31b94c292f0aed320bdba76511abd34bb6dc45294c11958e802
|
4
|
+
data.tar.gz: 473ca0893f427b05c88c64805dc0f64668816b263b136863b903f5262aba7aef
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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
|
-
"
|
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
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[
|
5
|
-
o
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
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
|
-
`
|
28
|
+
`a3 += o[Symbol.for('foo')]`
|
14
29
|
end
|
15
30
|
|
16
|
-
x.report('
|
17
|
-
`
|
31
|
+
x.report('const global symbol') do
|
32
|
+
`a4 += o[cgfoo]`
|
18
33
|
end
|
19
34
|
|
20
|
-
x.report('
|
21
|
-
`
|
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
|
-
`
|
48
|
+
`a7 += o.foo`
|
26
49
|
end
|
27
50
|
|
28
|
-
x.report('string') do
|
29
|
-
`
|
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
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 =
|
264
|
-
|
265
|
-
|
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
|
-
|
291
|
-
|
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.
|
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
|
data/lib/opal/nodes/call.rb
CHANGED
@@ -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.
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
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
|
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
|
-
|
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.
|
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
|
418
|
-
push "
|
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
|
data/lib/opal/nodes/def.rb
CHANGED
@@ -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}"
|
data/lib/opal/nodes/helpers.rb
CHANGED
@@ -72,22 +72,22 @@ module Opal
|
|
72
72
|
case mid
|
73
73
|
when :==
|
74
74
|
helper :eqeq
|
75
|
-
compiler.
|
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.
|
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.
|
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.
|
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
|