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
data/lib/opal/nodes/if.rb
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require 'opal/nodes/base'
|
4
|
+
require 'opal/ast/matcher'
|
4
5
|
|
5
6
|
module Opal
|
6
7
|
module Nodes
|
@@ -18,6 +19,8 @@ module Opal
|
|
18
19
|
else
|
19
20
|
compile_with_ternary
|
20
21
|
end
|
22
|
+
elsif could_become_switch?
|
23
|
+
compile_with_switch
|
21
24
|
else
|
22
25
|
compile_with_if
|
23
26
|
end
|
@@ -158,6 +161,225 @@ module Opal
|
|
158
161
|
true
|
159
162
|
end
|
160
163
|
end
|
164
|
+
|
165
|
+
# NOTE: all following matcher will act on case/when statements in their rewitten form:
|
166
|
+
#
|
167
|
+
# bin/opal --sexp -e'case some_value_or_expression; when 123; when 456, 789; end'
|
168
|
+
#
|
169
|
+
# s(:top,
|
170
|
+
# s(:if,
|
171
|
+
# s(:send,
|
172
|
+
# s(:int, 123), :===,
|
173
|
+
# s(:lvasgn, "$ret_or_1",
|
174
|
+
# s(:send, nil, :some_value_or_expression))), nil,
|
175
|
+
# s(:if,
|
176
|
+
# s(:if,
|
177
|
+
# s(:send,
|
178
|
+
# s(:int, 456), :===,
|
179
|
+
# s(:js_tmp, "$ret_or_1")),
|
180
|
+
# s(:true),
|
181
|
+
# s(:send,
|
182
|
+
# s(:int, 789), :===,
|
183
|
+
# s(:js_tmp, "$ret_or_1"))), nil,
|
184
|
+
# s(:nil))))
|
185
|
+
#
|
186
|
+
|
187
|
+
# Matches: `case some_value_or_expression; when 123`
|
188
|
+
# Captures: [s(:int, 123), "$ret_or_1", s(:send, nil, :some_value_or_expression))]
|
189
|
+
SWITCH_TEST_MATCH = AST::Matcher.new do
|
190
|
+
s(:send,
|
191
|
+
cap(s(%i[float int sym str true false nil], :*)),
|
192
|
+
:===,
|
193
|
+
s(:lvasgn, cap(:*), cap(:*))
|
194
|
+
)
|
195
|
+
end
|
196
|
+
|
197
|
+
# Matches: case some_value_or_expression; when 123, 456; end
|
198
|
+
# Captures: [
|
199
|
+
# s(:int, 123),
|
200
|
+
# "$ret_or_1",
|
201
|
+
# s(:send, nil, :some_value_or_expression)),
|
202
|
+
# …here we delegate to either SWITCH_BRANCH_TEST_MATCH or SWITCH_BRANCH_TEST_MATCH_CONTINUED
|
203
|
+
# ]
|
204
|
+
SWITCH_TEST_MATCH_CONTINUED = AST::Matcher.new do
|
205
|
+
s(:if,
|
206
|
+
s(:send,
|
207
|
+
cap(s(%i[float int sym str true false nil], :*)),
|
208
|
+
:===,
|
209
|
+
s(:lvasgn, cap(:*), cap(:*))
|
210
|
+
),
|
211
|
+
s(:true),
|
212
|
+
cap(:*)
|
213
|
+
)
|
214
|
+
end
|
215
|
+
|
216
|
+
# Matches: `when 456` (from `case foo; when 123; when 456; end`)
|
217
|
+
# Captures: [s(:int, 456), "$ret_or_1"]
|
218
|
+
SWITCH_BRANCH_TEST_MATCH = AST::Matcher.new do
|
219
|
+
s(:send,
|
220
|
+
cap(s(%i[float int sym str true false nil], :*)),
|
221
|
+
:===,
|
222
|
+
s(:js_tmp, cap(:*))
|
223
|
+
)
|
224
|
+
end
|
225
|
+
|
226
|
+
# Matches: `when 456`
|
227
|
+
# Captures: [
|
228
|
+
# s(:int, 789),
|
229
|
+
# "$ret_or_1",
|
230
|
+
# …here we delegate to either SWITCH_BRANCH_TEST_MATCH or SWITCH_BRANCH_TEST_MATCH_CONTINUED
|
231
|
+
# ]
|
232
|
+
SWITCH_BRANCH_TEST_MATCH_CONTINUED = AST::Matcher.new do
|
233
|
+
s(:if,
|
234
|
+
s(:send,
|
235
|
+
cap(s(%i[float int sym str true false nil], :*)),
|
236
|
+
:===,
|
237
|
+
s(:js_tmp, cap(:*))
|
238
|
+
),
|
239
|
+
s(:true),
|
240
|
+
cap(:*)
|
241
|
+
)
|
242
|
+
end
|
243
|
+
|
244
|
+
def could_become_switch?
|
245
|
+
return false if expects_expression?
|
246
|
+
|
247
|
+
return true if sexp.meta[:switch_child]
|
248
|
+
|
249
|
+
test_match = SWITCH_TEST_MATCH.match(test) || SWITCH_TEST_MATCH_CONTINUED.match(test)
|
250
|
+
return false unless test_match
|
251
|
+
@switch_test, @switch_variable, @switch_first_test, additional_rules = *test_match
|
252
|
+
|
253
|
+
additional_rules = handle_additional_switch_rules(additional_rules)
|
254
|
+
return false unless additional_rules # It's ok for them to be empty, but false denotes a mismatch
|
255
|
+
@switch_additional_rules = additional_rules
|
256
|
+
|
257
|
+
return false unless valid_switch_body?(true_body)
|
258
|
+
|
259
|
+
could_become_switch_branch?(false_body)
|
260
|
+
end
|
261
|
+
|
262
|
+
def handle_additional_switch_rules(additional_rules)
|
263
|
+
switch_additional_rules = []
|
264
|
+
while additional_rules
|
265
|
+
match = SWITCH_BRANCH_TEST_MATCH.match(additional_rules) || SWITCH_BRANCH_TEST_MATCH_CONTINUED.match(additional_rules)
|
266
|
+
return false unless match
|
267
|
+
|
268
|
+
switch_test, switch_variable, additional_rules = *match
|
269
|
+
return false unless switch_variable == @switch_variable
|
270
|
+
|
271
|
+
switch_additional_rules << switch_test
|
272
|
+
end
|
273
|
+
switch_additional_rules
|
274
|
+
end
|
275
|
+
|
276
|
+
def could_become_switch_branch?(body)
|
277
|
+
if !body
|
278
|
+
return true
|
279
|
+
elsif body.type != :if
|
280
|
+
if valid_switch_body?(body)
|
281
|
+
body.meta[:switch_default] = true
|
282
|
+
return true
|
283
|
+
end
|
284
|
+
return false
|
285
|
+
end
|
286
|
+
|
287
|
+
test, true_body, false_body = *body
|
288
|
+
|
289
|
+
test_match = SWITCH_BRANCH_TEST_MATCH.match(test) || SWITCH_BRANCH_TEST_MATCH_CONTINUED.match(test)
|
290
|
+
unless test_match
|
291
|
+
if valid_switch_body?(body, true)
|
292
|
+
body.meta[:switch_default] = true
|
293
|
+
return true
|
294
|
+
end
|
295
|
+
end
|
296
|
+
switch_test, switch_variable, additional_rules = *test_match
|
297
|
+
|
298
|
+
switch_additional_rules = handle_additional_switch_rules(additional_rules)
|
299
|
+
return false unless switch_additional_rules # It's ok for them to be empty, but false denotes a mismatch
|
300
|
+
|
301
|
+
return false unless switch_variable == @switch_variable
|
302
|
+
|
303
|
+
return false unless valid_switch_body?(true_body)
|
304
|
+
return false unless could_become_switch_branch?(false_body)
|
305
|
+
|
306
|
+
body.meta.merge!(switch_child: true,
|
307
|
+
switch_test: switch_test,
|
308
|
+
switch_variable: @switch_variable,
|
309
|
+
switch_additional_rules: switch_additional_rules
|
310
|
+
)
|
311
|
+
|
312
|
+
true
|
313
|
+
end
|
314
|
+
|
315
|
+
def valid_switch_body?(body, check_variable = false)
|
316
|
+
case body
|
317
|
+
when AST::Node
|
318
|
+
case body.type
|
319
|
+
when :break, :redo, :retry
|
320
|
+
false
|
321
|
+
when :iter, :while
|
322
|
+
# Don't traverse the iters or whiles!
|
323
|
+
true
|
324
|
+
else
|
325
|
+
body.children.all? { |i| valid_switch_body?(i, check_variable) }
|
326
|
+
end
|
327
|
+
when @switch_variable
|
328
|
+
# Perhaps we ended abruptly and we lack a $ret_or variable... but sometimes
|
329
|
+
# we can ignore this.
|
330
|
+
!check_variable
|
331
|
+
else
|
332
|
+
true
|
333
|
+
end
|
334
|
+
end
|
335
|
+
|
336
|
+
def compile_with_switch
|
337
|
+
if sexp.meta[:switch_child]
|
338
|
+
@switch_variable = sexp.meta[:switch_variable]
|
339
|
+
@switch_additional_rules = sexp.meta[:switch_additional_rules]
|
340
|
+
compile_switch_case(sexp.meta[:switch_test])
|
341
|
+
else
|
342
|
+
line "switch (", expr(@switch_first_test), ") {"
|
343
|
+
indent do
|
344
|
+
compile_switch_case(@switch_test)
|
345
|
+
end
|
346
|
+
line "}"
|
347
|
+
end
|
348
|
+
end
|
349
|
+
|
350
|
+
def returning?(body)
|
351
|
+
%i[return js_return next].include?(body.type) ||
|
352
|
+
(body.type == :begin && %i[return js_return next].include?(body.children.last.type))
|
353
|
+
end
|
354
|
+
|
355
|
+
def compile_switch_case(test)
|
356
|
+
line "case ", expr(test), ":"
|
357
|
+
if @switch_additional_rules
|
358
|
+
@switch_additional_rules.each do |rule|
|
359
|
+
line "case ", expr(rule), ":"
|
360
|
+
end
|
361
|
+
end
|
362
|
+
indent do
|
363
|
+
line stmt(true_body)
|
364
|
+
line "break;" if !true_body || !returning?(true_body)
|
365
|
+
end
|
366
|
+
if false_body
|
367
|
+
if false_body.meta[:switch_default]
|
368
|
+
compile_switch_default
|
369
|
+
elsif false_body.meta[:switch_child]
|
370
|
+
push stmt(false_body)
|
371
|
+
end
|
372
|
+
else
|
373
|
+
push stmt(s(:nil))
|
374
|
+
end
|
375
|
+
end
|
376
|
+
|
377
|
+
def compile_switch_default
|
378
|
+
line "default:"
|
379
|
+
indent do
|
380
|
+
line stmt(false_body)
|
381
|
+
end
|
382
|
+
end
|
161
383
|
end
|
162
384
|
|
163
385
|
class IFlipFlop < Base
|
data/lib/opal/nodes/iter.rb
CHANGED
@@ -8,45 +8,12 @@ module Opal
|
|
8
8
|
class IterNode < NodeWithArgs
|
9
9
|
handle :iter
|
10
10
|
|
11
|
-
children :inline_args, :
|
11
|
+
children :inline_args, :stmts
|
12
12
|
|
13
13
|
def compile
|
14
14
|
is_lambda! if scope.lambda_definition?
|
15
15
|
|
16
|
-
|
17
|
-
|
18
|
-
to_vars = identity = body_code = nil
|
19
|
-
|
20
|
-
in_scope do
|
21
|
-
identity = scope.identify!
|
22
|
-
|
23
|
-
inline_params = process(inline_args)
|
24
|
-
|
25
|
-
compile_arity_check
|
26
|
-
|
27
|
-
body_code = stmt(returned_body)
|
28
|
-
|
29
|
-
add_temp "self = #{identity}.$$s == null ? this : #{identity}.$$s" if @define_self
|
30
|
-
|
31
|
-
to_vars = scope.to_vars
|
32
|
-
|
33
|
-
line body_code
|
34
|
-
|
35
|
-
if scope.catch_return
|
36
|
-
unshift "try {\n"
|
37
|
-
line '} catch ($returner) { if ($returner === Opal.returner) { return $returner.$v }'
|
38
|
-
push ' throw $returner; }'
|
39
|
-
end
|
40
|
-
end
|
41
|
-
|
42
|
-
unshift to_vars
|
43
|
-
|
44
|
-
if await_encountered
|
45
|
-
unshift "async function #{identity}(", inline_params, '){'
|
46
|
-
else
|
47
|
-
unshift "function #{identity}(", inline_params, '){'
|
48
|
-
end
|
49
|
-
push '}'
|
16
|
+
compile_body_or_shortcut
|
50
17
|
|
51
18
|
blockopts = []
|
52
19
|
blockopts << "$$arity: #{arity}"
|
@@ -83,6 +50,43 @@ module Opal
|
|
83
50
|
scope.relative_access if @define_relative_access
|
84
51
|
end
|
85
52
|
|
53
|
+
def compile_body
|
54
|
+
inline_params = nil
|
55
|
+
|
56
|
+
to_vars = identity = body_code = nil
|
57
|
+
|
58
|
+
in_scope do
|
59
|
+
identity = scope.identify!
|
60
|
+
|
61
|
+
inline_params = process(inline_args)
|
62
|
+
|
63
|
+
compile_arity_check
|
64
|
+
|
65
|
+
body_code = stmt(returned_body)
|
66
|
+
|
67
|
+
add_temp "self = #{identity}.$$s == null ? this : #{identity}.$$s" if @define_self
|
68
|
+
|
69
|
+
to_vars = scope.to_vars
|
70
|
+
|
71
|
+
line body_code
|
72
|
+
|
73
|
+
if scope.catch_return
|
74
|
+
unshift "try {\n"
|
75
|
+
line '} catch ($returner) { if ($returner === Opal.returner) { return $returner.$v }'
|
76
|
+
push ' throw $returner; }'
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
unshift to_vars
|
81
|
+
|
82
|
+
if await_encountered
|
83
|
+
unshift "async function #{identity}(", inline_params, '){'
|
84
|
+
else
|
85
|
+
unshift "function #{identity}(", inline_params, '){'
|
86
|
+
end
|
87
|
+
push '}'
|
88
|
+
end
|
89
|
+
|
86
90
|
def compile_block_arg
|
87
91
|
if block_arg
|
88
92
|
scope.prepare_block
|
@@ -108,13 +112,13 @@ module Opal
|
|
108
112
|
@sexp = @sexp.updated(
|
109
113
|
nil, [
|
110
114
|
args.updated(nil, valid_args),
|
111
|
-
|
115
|
+
stmts
|
112
116
|
]
|
113
117
|
)
|
114
118
|
end
|
115
119
|
|
116
120
|
def returned_body
|
117
|
-
compiler.returns(
|
121
|
+
compiler.returns(stmts || s(:nil))
|
118
122
|
end
|
119
123
|
|
120
124
|
def has_top_level_mlhs_arg?
|
data/lib/opal/nodes/literal.rb
CHANGED
@@ -326,7 +326,7 @@ module Opal
|
|
326
326
|
children :value
|
327
327
|
|
328
328
|
def compile
|
329
|
-
push "
|
329
|
+
push "#{top_scope.absolute_const}('Rational').$new(#{value.numerator}, #{value.denominator})"
|
330
330
|
end
|
331
331
|
end
|
332
332
|
|
@@ -338,7 +338,7 @@ module Opal
|
|
338
338
|
children :value
|
339
339
|
|
340
340
|
def compile
|
341
|
-
push "
|
341
|
+
push "#{top_scope.absolute_const}('Complex').$new(#{value.real}, #{value.imag})"
|
342
342
|
end
|
343
343
|
end
|
344
344
|
end
|
data/lib/opal/nodes/masgn.rb
CHANGED
@@ -11,24 +11,22 @@ module Opal
|
|
11
11
|
children :lhs, :rhs
|
12
12
|
|
13
13
|
def compile
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
14
|
+
with_temp do |array|
|
15
|
+
if rhs.type == :array
|
16
|
+
push "#{array} = ", expr(rhs)
|
17
|
+
rhs_len = rhs.children.any? { |c| c.type == :splat } ? nil : rhs.children.size
|
18
|
+
compile_masgn(lhs.children, array, rhs_len)
|
19
|
+
push ", #{array}" # a mass assignment evaluates to the RHS
|
20
|
+
else
|
21
|
+
helper :to_ary
|
22
|
+
with_temp do |retval|
|
23
|
+
push "#{retval} = ", expr(rhs)
|
24
|
+
push ", #{array} = $to_ary(#{retval})"
|
25
|
+
compile_masgn(lhs.children, array)
|
26
|
+
push ", #{retval}"
|
27
|
+
end
|
28
|
+
end
|
29
29
|
end
|
30
|
-
|
31
|
-
scope.queue_temp(array)
|
32
30
|
end
|
33
31
|
|
34
32
|
# 'len' is how many rhs items are we sure we have
|
@@ -0,0 +1,100 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Opal
|
4
|
+
module Nodes
|
5
|
+
class NodeWithArgs < ScopeNode
|
6
|
+
# Shortcuts for the simplest kinds of methods
|
7
|
+
Shortcut = Struct.new(:name, :for, :when, :transform) do
|
8
|
+
def match?(node)
|
9
|
+
node.instance_exec(&self.when)
|
10
|
+
end
|
11
|
+
|
12
|
+
def compile(node)
|
13
|
+
node.helper name
|
14
|
+
node.instance_exec(&transform)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
@shortcuts = []
|
19
|
+
@shortcuts_for = {}
|
20
|
+
def self.define_shortcut(name, **kwargs, &block)
|
21
|
+
kwargs[:for] ||= :def
|
22
|
+
@shortcuts << Shortcut.new(name, kwargs[:for], kwargs[:when], block)
|
23
|
+
end
|
24
|
+
|
25
|
+
def self.shortcuts_for(node_type)
|
26
|
+
@shortcuts_for[node_type] ||=
|
27
|
+
@shortcuts.select do |shortcut|
|
28
|
+
[node_type, :*].include? shortcut.for
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def compile_body_or_shortcut
|
33
|
+
# The shortcuts don't check arity. If we want to check arity,
|
34
|
+
# we can't use them.
|
35
|
+
return compile_body if compiler.arity_check?
|
36
|
+
|
37
|
+
node_type = is_a?(DefNode) ? :def : :iter
|
38
|
+
|
39
|
+
NodeWithArgs.shortcuts_for(node_type).each do |shortcut|
|
40
|
+
if shortcut.match?(self)
|
41
|
+
if ENV['OPAL_DEBUG_SHORTCUTS']
|
42
|
+
node_desc = node_type == :def ? "def #{mid}" : "iter"
|
43
|
+
warn "* shortcut #{shortcut.name} used for #{node_desc}"
|
44
|
+
end
|
45
|
+
|
46
|
+
return shortcut.compile(self)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
compile_body
|
51
|
+
end
|
52
|
+
|
53
|
+
# Shortcut definitions
|
54
|
+
# --------------------
|
55
|
+
|
56
|
+
# def a; self; end
|
57
|
+
define_shortcut :return_self, when: -> { stmts.type == :self } do
|
58
|
+
push '$return_self'
|
59
|
+
end
|
60
|
+
|
61
|
+
def simple_value?(node = stmts)
|
62
|
+
%i[true false nil int float str sym].include?(node.type)
|
63
|
+
end
|
64
|
+
|
65
|
+
# def a; 123; end
|
66
|
+
define_shortcut :return_val, for: :*, when: -> { simple_value? } do
|
67
|
+
push '$return_val(', expr(stmts), ')'
|
68
|
+
end
|
69
|
+
|
70
|
+
# def a; @x; end
|
71
|
+
define_shortcut :return_ivar, when: -> { stmts.type == :ivar } do
|
72
|
+
name = stmts.children.first.to_s[1..-1].to_sym
|
73
|
+
push '$return_ivar(', expr(stmts.updated(:sym, [name])), ')'
|
74
|
+
end
|
75
|
+
|
76
|
+
# def a; @x = 5; end
|
77
|
+
define_shortcut :assign_ivar, when: -> {
|
78
|
+
stmts.type == :ivasgn &&
|
79
|
+
inline_args.children.length == 1 &&
|
80
|
+
inline_args.children.last.type == :arg &&
|
81
|
+
stmts.children.last.type == :lvar &&
|
82
|
+
stmts.children.last.children.last == inline_args.children.last.children.last
|
83
|
+
} do
|
84
|
+
name = stmts.children.first.to_s[1..-1].to_sym
|
85
|
+
name = expr(stmts.updated(:sym, [name]))
|
86
|
+
push '$assign_ivar(', name, ')'
|
87
|
+
end
|
88
|
+
|
89
|
+
# def a(x); @x = x; end
|
90
|
+
define_shortcut :assign_ivar_val, when: -> {
|
91
|
+
stmts.type == :ivasgn &&
|
92
|
+
simple_value?(stmts.children.last)
|
93
|
+
} do
|
94
|
+
name = stmts.children.first.to_s[1..-1].to_sym
|
95
|
+
name = expr(stmts.updated(:sym, [name]))
|
96
|
+
push '$assign_ivar_val(', name, ', ', expr(stmts.children.last), ')'
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
data/lib/opal/nodes/top.rb
CHANGED
@@ -14,14 +14,22 @@ module Opal
|
|
14
14
|
|
15
15
|
def compile
|
16
16
|
compiler.top_scope = self
|
17
|
+
compiler.dynamic_cache_result = true if sexp.meta[:dynamic_cache_result]
|
17
18
|
|
18
19
|
push version_comment
|
19
20
|
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
21
|
+
helper :return_val if compiler.eof_content
|
22
|
+
|
23
|
+
if body == s(:nil)
|
24
|
+
# A shortpath for empty (stub?) modules.
|
25
|
+
if compiler.requirable? || compiler.esm? || compiler.eval?
|
26
|
+
unshift 'Opal.return_val(Opal.nil); '
|
27
|
+
definition
|
24
28
|
else
|
29
|
+
unshift 'Opal.nil; '
|
30
|
+
end
|
31
|
+
else
|
32
|
+
in_scope do
|
25
33
|
line '"use strict";' if compiler.use_strict?
|
26
34
|
|
27
35
|
body_code = stmt(stmts)
|
@@ -47,20 +55,28 @@ module Opal
|
|
47
55
|
|
48
56
|
line body_code
|
49
57
|
end
|
58
|
+
|
59
|
+
opening
|
60
|
+
definition
|
61
|
+
closing
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
def definition
|
66
|
+
if compiler.requirable?
|
67
|
+
unshift "Opal.modules[#{Opal::Compiler.module_name(compiler.file).inspect}] = "
|
68
|
+
elsif compiler.esm?
|
69
|
+
unshift 'export default '
|
50
70
|
end
|
51
|
-
opening
|
52
|
-
closing
|
53
71
|
end
|
54
72
|
|
55
73
|
def opening
|
56
74
|
async_prefix = "async " if await_encountered
|
57
75
|
|
58
76
|
if compiler.requirable?
|
59
|
-
unshift "
|
77
|
+
unshift "#{async_prefix}function(Opal) {"
|
60
78
|
elsif compiler.eval?
|
61
79
|
unshift "(#{async_prefix}function(Opal, self) {"
|
62
|
-
elsif compiler.esm?
|
63
|
-
unshift "export default Opal.queue(#{async_prefix}function(Opal) {"
|
64
80
|
else
|
65
81
|
unshift "Opal.queue(#{async_prefix}function(Opal) {"
|
66
82
|
end
|
@@ -108,7 +124,7 @@ module Opal
|
|
108
124
|
def compile_end_construct
|
109
125
|
if content = compiler.eof_content
|
110
126
|
line 'var $__END__ = Opal.Object.$new();'
|
111
|
-
line "$__END__.$read =
|
127
|
+
line "$__END__.$read = $return_val(#{content.inspect});"
|
112
128
|
end
|
113
129
|
end
|
114
130
|
|
data/lib/opal/nodes.rb
CHANGED
data/lib/opal/repl.rb
CHANGED
data/lib/opal/rewriter.rb
CHANGED
@@ -2,7 +2,6 @@
|
|
2
2
|
|
3
3
|
require 'opal/rewriters/opal_engine_check'
|
4
4
|
require 'opal/rewriters/for_rewriter'
|
5
|
-
require 'opal/rewriters/explicit_writer_return'
|
6
5
|
require 'opal/rewriters/js_reserved_words'
|
7
6
|
require 'opal/rewriters/block_to_iter'
|
8
7
|
require 'opal/rewriters/dot_js_syntax'
|
@@ -19,6 +18,8 @@ require 'opal/rewriters/forward_args'
|
|
19
18
|
|
20
19
|
module Opal
|
21
20
|
class Rewriter
|
21
|
+
@disabled = false
|
22
|
+
|
22
23
|
class << self
|
23
24
|
def list
|
24
25
|
@list ||= []
|
@@ -32,15 +33,21 @@ module Opal
|
|
32
33
|
list.delete(rewriter)
|
33
34
|
end
|
34
35
|
|
35
|
-
def disable
|
36
|
-
|
36
|
+
def disable(except: nil)
|
37
|
+
old_disabled = @disabled
|
38
|
+
@disabled = except || true
|
37
39
|
yield
|
38
40
|
ensure
|
39
|
-
@disabled =
|
41
|
+
@disabled = old_disabled
|
40
42
|
end
|
41
43
|
|
42
44
|
def disabled?
|
43
|
-
@disabled
|
45
|
+
@disabled == true
|
46
|
+
end
|
47
|
+
|
48
|
+
def rewritter_disabled?(rewriter)
|
49
|
+
return false if @disabled == false
|
50
|
+
@disabled != rewriter
|
44
51
|
end
|
45
52
|
end
|
46
53
|
|
@@ -54,7 +61,6 @@ module Opal
|
|
54
61
|
use Rewriters::JsReservedWords
|
55
62
|
use Rewriters::LogicalOperatorAssignment
|
56
63
|
use Rewriters::BinaryOperatorAssignment
|
57
|
-
use Rewriters::ExplicitWriterReturn
|
58
64
|
use Rewriters::Hashes::KeyDuplicatesRewriter
|
59
65
|
use Rewriters::ReturnableLogic
|
60
66
|
use Rewriters::DumpArgs
|
@@ -69,6 +75,7 @@ module Opal
|
|
69
75
|
return @sexp if self.class.disabled?
|
70
76
|
|
71
77
|
self.class.list.each do |rewriter_class|
|
78
|
+
next if self.class.rewritter_disabled?(rewriter_class)
|
72
79
|
rewriter = rewriter_class.new
|
73
80
|
@sexp = rewriter.process(@sexp)
|
74
81
|
end
|