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.
- 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
|