ruby-next-core 0.10.1 → 0.11.0
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/CHANGELOG.md +31 -1
- data/README.md +12 -14
- data/bin/reparse +19 -0
- data/bin/transform +22 -8
- data/lib/.rbnext/2.3/ruby-next/commands/nextify.rb +5 -2
- data/lib/.rbnext/2.3/ruby-next/language/eval.rb +4 -4
- data/lib/.rbnext/2.3/ruby-next/language/rewriters/base.rb +25 -10
- data/lib/.rbnext/2.3/ruby-next/language/rewriters/endless_range.rb +1 -1
- data/lib/.rbnext/2.3/ruby-next/language/rewriters/pattern_matching.rb +133 -103
- data/lib/.rbnext/2.3/ruby-next/utils.rb +1 -1
- data/lib/.rbnext/2.7/ruby-next/core.rb +203 -0
- data/lib/ruby-next.rb +5 -38
- data/lib/ruby-next/commands/nextify.rb +4 -1
- data/lib/ruby-next/config.rb +45 -0
- data/lib/ruby-next/core.rb +5 -4
- data/lib/ruby-next/core/array/deconstruct.rb +1 -1
- data/lib/ruby-next/core/constants/no_matching_pattern_error.rb +1 -1
- data/lib/ruby-next/core/hash/deconstruct_keys.rb +1 -1
- data/lib/ruby-next/core/struct/deconstruct_keys.rb +3 -3
- data/lib/ruby-next/core_ext.rb +2 -0
- data/lib/ruby-next/language.rb +16 -5
- data/lib/ruby-next/language/bootsnap.rb +1 -1
- data/lib/ruby-next/language/edge.rb +0 -6
- data/lib/ruby-next/language/eval.rb +3 -3
- data/lib/ruby-next/language/parser.rb +19 -0
- data/lib/ruby-next/language/rewriters/args_forward.rb +8 -4
- data/lib/ruby-next/language/rewriters/args_forward_leading.rb +75 -0
- data/lib/ruby-next/language/rewriters/base.rb +21 -6
- data/lib/ruby-next/language/rewriters/in_pattern.rb +56 -0
- data/lib/ruby-next/language/rewriters/numbered_params.rb +6 -2
- data/lib/ruby-next/language/rewriters/pattern_matching.rb +131 -101
- data/lib/ruby-next/language/rewriters/safe_navigation.rb +30 -26
- data/lib/ruby-next/language/setup.rb +6 -3
- data/lib/ruby-next/language/unparser.rb +10 -0
- data/lib/ruby-next/rubocop.rb +79 -12
- data/lib/ruby-next/setup_self.rb +2 -2
- data/lib/ruby-next/version.rb +1 -1
- metadata +15 -6
- data/lib/.rbnext/2.3/ruby-next/language/rewriters/right_hand_assignment.rb +0 -107
- data/lib/ruby-next/language/rewriters/right_hand_assignment.rb +0 -107
@@ -13,7 +13,7 @@ load_iseq = RubyVM::InstructionSequence.method(:load_iseq)
|
|
13
13
|
if load_iseq.source_location[0].include?("/bootsnap/")
|
14
14
|
Bootsnap::CompileCache::ISeq.singleton_class.prepend(
|
15
15
|
Module.new do
|
16
|
-
def input_to_storage(source, path)
|
16
|
+
def input_to_storage(source, path, *)
|
17
17
|
return super unless RubyNext::Language.transformable?(path)
|
18
18
|
source = RubyNext::Language.transform(source, rewriters: RubyNext::Language.current_rewriters)
|
19
19
|
|
@@ -1,9 +1,3 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
# Load edge Ruby features
|
4
|
-
|
5
|
-
require "ruby-next/language/rewriters/endless_method"
|
6
|
-
RubyNext::Language.rewriters << RubyNext::Language::Rewriters::EndlessMethod
|
7
|
-
|
8
|
-
require "ruby-next/language/rewriters/right_hand_assignment"
|
9
|
-
RubyNext::Language.rewriters << RubyNext::Language::Rewriters::RightHandAssignment
|
@@ -20,7 +20,7 @@ module RubyNext
|
|
20
20
|
module InstanceEval # :nodoc:
|
21
21
|
refine Object do
|
22
22
|
def instance_eval(*args, &block)
|
23
|
-
return super(*args, &block) if
|
23
|
+
return super(*args, &block) if block
|
24
24
|
|
25
25
|
source = args.shift
|
26
26
|
new_source = ::RubyNext::Language::Runtime.transform(source, using: false)
|
@@ -33,7 +33,7 @@ module RubyNext
|
|
33
33
|
module ClassEval
|
34
34
|
refine Module do
|
35
35
|
def module_eval(*args, &block)
|
36
|
-
return super(*args, &block) if
|
36
|
+
return super(*args, &block) if block
|
37
37
|
|
38
38
|
source = args.shift
|
39
39
|
new_source = ::RubyNext::Language::Runtime.transform(source, using: false)
|
@@ -42,7 +42,7 @@ module RubyNext
|
|
42
42
|
end
|
43
43
|
|
44
44
|
def class_eval(*args, &block)
|
45
|
-
return super(*args, &block) if
|
45
|
+
return super(*args, &block) if block
|
46
46
|
|
47
47
|
source = args.shift
|
48
48
|
new_source = ::RubyNext::Language::Runtime.transform(source, using: false)
|
@@ -4,8 +4,27 @@ require "parser/rubynext"
|
|
4
4
|
|
5
5
|
module RubyNext
|
6
6
|
module Language
|
7
|
+
module BuilderExt
|
8
|
+
def match_pattern(lhs, match_t, rhs)
|
9
|
+
n(:match_pattern, [lhs, rhs],
|
10
|
+
binary_op_map(lhs, match_t, rhs))
|
11
|
+
end
|
12
|
+
|
13
|
+
def match_pattern_p(lhs, match_t, rhs)
|
14
|
+
n(:match_pattern_p, [lhs, rhs],
|
15
|
+
binary_op_map(lhs, match_t, rhs))
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
7
19
|
class Builder < ::Parser::Builders::Default
|
8
20
|
modernize
|
21
|
+
|
22
|
+
# Unparser doesn't support kwargs node yet
|
23
|
+
self.emit_kwargs = false if respond_to?(:emit_kwargs=)
|
24
|
+
|
25
|
+
unless method_defined?(:match_pattern_p)
|
26
|
+
include BuilderExt
|
27
|
+
end
|
9
28
|
end
|
10
29
|
|
11
30
|
class << self
|
@@ -5,8 +5,8 @@ module RubyNext
|
|
5
5
|
module Rewriters
|
6
6
|
class ArgsForward < Base
|
7
7
|
NAME = "args-forward"
|
8
|
-
SYNTAX_PROBE = "obj = Object.new; def obj.foo(...) super(
|
9
|
-
MIN_SUPPORTED_VERSION = Gem::Version.new("2.7.
|
8
|
+
SYNTAX_PROBE = "obj = Object.new; def obj.foo(...) super(...); end"
|
9
|
+
MIN_SUPPORTED_VERSION = Gem::Version.new("2.7.0")
|
10
10
|
|
11
11
|
REST = :__rest__
|
12
12
|
BLOCK = :__block__
|
@@ -28,14 +28,14 @@ module RubyNext
|
|
28
28
|
end
|
29
29
|
|
30
30
|
def on_send(node)
|
31
|
-
fargs = node
|
31
|
+
fargs = extract_fargs(node)
|
32
32
|
return super(node) unless fargs
|
33
33
|
|
34
34
|
process_fargs(node, fargs)
|
35
35
|
end
|
36
36
|
|
37
37
|
def on_super(node)
|
38
|
-
fargs = node
|
38
|
+
fargs = extract_fargs(node)
|
39
39
|
return super(node) unless fargs
|
40
40
|
|
41
41
|
process_fargs(node, fargs)
|
@@ -43,6 +43,10 @@ module RubyNext
|
|
43
43
|
|
44
44
|
private
|
45
45
|
|
46
|
+
def extract_fargs(node)
|
47
|
+
node.children.find { |child| child.is_a?(::Parser::AST::Node) && child.type == :forwarded_args }
|
48
|
+
end
|
49
|
+
|
46
50
|
def process_fargs(node, fargs)
|
47
51
|
replace(fargs.loc.expression, "*#{REST}, &#{BLOCK}")
|
48
52
|
|
@@ -0,0 +1,75 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RubyNext
|
4
|
+
module Language
|
5
|
+
module Rewriters
|
6
|
+
class ArgsForwardLeading < ArgsForward
|
7
|
+
NAME = "args-forward-leading"
|
8
|
+
SYNTAX_PROBE = "obj = Object.new; def obj.foo(...) super(1, ...); end"
|
9
|
+
MIN_SUPPORTED_VERSION = Gem::Version.new("3.0.0")
|
10
|
+
|
11
|
+
attr_reader :leading_farg
|
12
|
+
alias leading_farg? leading_farg
|
13
|
+
|
14
|
+
def on_def(node)
|
15
|
+
@leading_farg = method_with_leading_arg(node)
|
16
|
+
|
17
|
+
super
|
18
|
+
end
|
19
|
+
|
20
|
+
def on_defs(node)
|
21
|
+
@leading_farg = method_with_leading_arg(node)
|
22
|
+
|
23
|
+
super
|
24
|
+
end
|
25
|
+
|
26
|
+
def on_forward_arg(node)
|
27
|
+
return super if leading_farg?
|
28
|
+
|
29
|
+
node
|
30
|
+
end
|
31
|
+
|
32
|
+
def on_send(node)
|
33
|
+
return super if leading_farg?
|
34
|
+
|
35
|
+
node
|
36
|
+
end
|
37
|
+
|
38
|
+
def on_super(node)
|
39
|
+
return super if leading_farg?
|
40
|
+
|
41
|
+
node
|
42
|
+
end
|
43
|
+
|
44
|
+
private
|
45
|
+
|
46
|
+
def send_with_leading_farg(node)
|
47
|
+
return false unless node.type == :send || node.type == :super
|
48
|
+
|
49
|
+
fargs = extract_fargs(node)
|
50
|
+
|
51
|
+
return false unless fargs
|
52
|
+
|
53
|
+
node.children.index(fargs) > (node.type == :send ? 2 : 0)
|
54
|
+
end
|
55
|
+
|
56
|
+
def method_with_leading_arg(node)
|
57
|
+
find_child(node) { |child| child.type == :forward_arg } &&
|
58
|
+
(
|
59
|
+
def_with_leading_farg(node) ||
|
60
|
+
find_child(node) { |child| send_with_leading_farg(child) }
|
61
|
+
)
|
62
|
+
end
|
63
|
+
|
64
|
+
def def_with_leading_farg(node)
|
65
|
+
args = node.type == :defs ? node.children[2] : node.children[1]
|
66
|
+
args = args.children
|
67
|
+
|
68
|
+
farg = args.detect { |child| child.type == :forward_arg }
|
69
|
+
|
70
|
+
args.index(farg) > 0
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
@@ -61,7 +61,7 @@ module RubyNext
|
|
61
61
|
eval_mid = Kernel.respond_to?(:eval_without_ruby_next) ? :eval_without_ruby_next : :eval
|
62
62
|
Kernel.send eval_mid, self::SYNTAX_PROBE, nil, __FILE__, __LINE__
|
63
63
|
false
|
64
|
-
rescue SyntaxError,
|
64
|
+
rescue SyntaxError, StandardError
|
65
65
|
true
|
66
66
|
ensure
|
67
67
|
$VERBOSE = save_verbose
|
@@ -73,10 +73,6 @@ module RubyNext
|
|
73
73
|
self::MIN_SUPPORTED_VERSION > version
|
74
74
|
end
|
75
75
|
|
76
|
-
def min_supported_minor_version
|
77
|
-
Gem::Version.new(self::MIN_SUPPORTED_VERSION.segments[0..1].join(".") + ".0")
|
78
|
-
end
|
79
|
-
|
80
76
|
private
|
81
77
|
|
82
78
|
def transform(source)
|
@@ -98,6 +94,24 @@ module RubyNext
|
|
98
94
|
|
99
95
|
private
|
100
96
|
|
97
|
+
# BFS with predicate block
|
98
|
+
def find_child(node)
|
99
|
+
queue = [node]
|
100
|
+
|
101
|
+
loop do
|
102
|
+
break if queue.empty?
|
103
|
+
|
104
|
+
child = queue.shift
|
105
|
+
next unless child.is_a?(::Parser::AST::Node)
|
106
|
+
|
107
|
+
return child if yield child
|
108
|
+
|
109
|
+
queue.push(*child.children)
|
110
|
+
end
|
111
|
+
|
112
|
+
nil
|
113
|
+
end
|
114
|
+
|
101
115
|
def replace(range, ast)
|
102
116
|
@source_rewriter&.replace(range, unparse(ast))
|
103
117
|
end
|
@@ -116,7 +130,8 @@ module RubyNext
|
|
116
130
|
|
117
131
|
def unparse(ast)
|
118
132
|
return ast if ast.is_a?(String)
|
119
|
-
|
133
|
+
|
134
|
+
Unparser.unparse(ast).chomp
|
120
135
|
end
|
121
136
|
|
122
137
|
attr_reader :context
|
@@ -0,0 +1,56 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "ruby-next/language/rewriters/pattern_matching"
|
4
|
+
|
5
|
+
module RubyNext
|
6
|
+
module Language
|
7
|
+
module Rewriters
|
8
|
+
using RubyNext
|
9
|
+
|
10
|
+
# Separate pattern matching rewriter for Ruby 2.7 to
|
11
|
+
# transpile only `in` patterns
|
12
|
+
class InPattern < PatternMatching
|
13
|
+
NAME = "pattern-matching-in"
|
14
|
+
SYNTAX_PROBE = "1 in 2"
|
15
|
+
MIN_SUPPORTED_VERSION = Gem::Version.new("3.0.0")
|
16
|
+
|
17
|
+
# Make case-match no-op
|
18
|
+
def on_case_match(node)
|
19
|
+
node
|
20
|
+
end
|
21
|
+
|
22
|
+
def on_match_pattern_p(node)
|
23
|
+
context.track! self
|
24
|
+
|
25
|
+
@deconstructed_keys = {}
|
26
|
+
@predicates = Predicates::Noop.new
|
27
|
+
|
28
|
+
matchee =
|
29
|
+
s(:begin, s(:lvasgn, MATCHEE, node.children[0]))
|
30
|
+
|
31
|
+
pattern =
|
32
|
+
locals.with(
|
33
|
+
matchee: MATCHEE,
|
34
|
+
arr: MATCHEE_ARR,
|
35
|
+
hash: MATCHEE_HASH
|
36
|
+
) do
|
37
|
+
send(
|
38
|
+
:"#{node.children[1].type}_clause",
|
39
|
+
node.children[1]
|
40
|
+
)
|
41
|
+
end
|
42
|
+
|
43
|
+
node.updated(
|
44
|
+
:and,
|
45
|
+
[
|
46
|
+
matchee,
|
47
|
+
pattern
|
48
|
+
]
|
49
|
+
).tap do |new_node|
|
50
|
+
replace(node.loc.expression, inline_blocks(unparse(new_node)))
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
@@ -16,9 +16,9 @@ module RubyNext
|
|
16
16
|
proc_or_lambda, num, body = *node.children
|
17
17
|
|
18
18
|
if proc_or_lambda.type == :lambda
|
19
|
-
insert_before(node.loc.begin, "(#{
|
19
|
+
insert_before(node.loc.begin, "(#{proc_args_str(num)})")
|
20
20
|
else
|
21
|
-
insert_after(node.loc.begin, " |#{
|
21
|
+
insert_after(node.loc.begin, " |#{proc_args_str(num)}|")
|
22
22
|
end
|
23
23
|
|
24
24
|
node.updated(
|
@@ -33,6 +33,10 @@ module RubyNext
|
|
33
33
|
|
34
34
|
private
|
35
35
|
|
36
|
+
def proc_args_str(n)
|
37
|
+
(1..n).map { |numero| "_#{numero}" }.join(", ")
|
38
|
+
end
|
39
|
+
|
36
40
|
def proc_args(n)
|
37
41
|
return s(:args, s(:procarg0, s(:arg, :_1))) if n == 1
|
38
42
|
|
@@ -13,12 +13,12 @@ module RubyNext
|
|
13
13
|
|
14
14
|
# Useful to generate simple operation nodes
|
15
15
|
# (e.g., 'a + b')
|
16
|
-
def -(
|
17
|
-
::Parser::AST::Node.new(:send, [self, :-,
|
16
|
+
def -(other)
|
17
|
+
::Parser::AST::Node.new(:send, [self, :-, other.to_ast_node])
|
18
18
|
end
|
19
19
|
|
20
|
-
def +(
|
21
|
-
::Parser::AST::Node.new(:send, [self, :+,
|
20
|
+
def +(other)
|
21
|
+
::Parser::AST::Node.new(:send, [self, :+, other.to_ast_node])
|
22
22
|
end
|
23
23
|
end
|
24
24
|
|
@@ -218,9 +218,10 @@ module RubyNext
|
|
218
218
|
predicate_clause(:respond_to_deconstruct_keys, node)
|
219
219
|
end
|
220
220
|
|
221
|
-
def
|
222
|
-
|
223
|
-
|
221
|
+
def hash_keys(node, keys)
|
222
|
+
keys = keys.map { |key| key.is_a?(::Parser::AST::Node) ? key.children.first : key }
|
223
|
+
|
224
|
+
predicate_clause(:"hash_keys_#{keys.join("_p_")}", node)
|
224
225
|
end
|
225
226
|
end
|
226
227
|
end
|
@@ -244,7 +245,7 @@ module RubyNext
|
|
244
245
|
@predicates = Predicates::CaseIn.new
|
245
246
|
|
246
247
|
matchee_ast =
|
247
|
-
s(:lvasgn, MATCHEE, node.children[0])
|
248
|
+
s(:begin, s(:lvasgn, MATCHEE, node.children[0]))
|
248
249
|
|
249
250
|
patterns = locals.with(
|
250
251
|
matchee: MATCHEE,
|
@@ -266,14 +267,14 @@ module RubyNext
|
|
266
267
|
)
|
267
268
|
end
|
268
269
|
|
269
|
-
def
|
270
|
+
def on_match_pattern(node)
|
270
271
|
context.track! self
|
271
272
|
|
272
273
|
@deconstructed_keys = {}
|
273
274
|
@predicates = Predicates::Noop.new
|
274
275
|
|
275
276
|
matchee =
|
276
|
-
s(:lvasgn, MATCHEE, node.children[0])
|
277
|
+
s(:begin, s(:lvasgn, MATCHEE, node.children[0]))
|
277
278
|
|
278
279
|
pattern =
|
279
280
|
locals.with(
|
@@ -285,9 +286,10 @@ module RubyNext
|
|
285
286
|
:"#{node.children[1].type}_clause",
|
286
287
|
node.children[1]
|
287
288
|
).then do |node|
|
288
|
-
s(:
|
289
|
-
|
290
|
-
|
289
|
+
s(:begin,
|
290
|
+
s(:or,
|
291
|
+
node,
|
292
|
+
no_matching_pattern))
|
291
293
|
end
|
292
294
|
end
|
293
295
|
|
@@ -302,6 +304,8 @@ module RubyNext
|
|
302
304
|
end
|
303
305
|
end
|
304
306
|
|
307
|
+
alias on_in_match on_match_pattern
|
308
|
+
|
305
309
|
private
|
306
310
|
|
307
311
|
def rewrite_case_in!(node, matchee, new_node)
|
@@ -378,9 +382,10 @@ module RubyNext
|
|
378
382
|
predicates.const(case_eq_clause(const, right), const).then do |node|
|
379
383
|
next node if pattern.nil?
|
380
384
|
|
381
|
-
s(:
|
382
|
-
|
383
|
-
|
385
|
+
s(:begin,
|
386
|
+
s(:and,
|
387
|
+
node,
|
388
|
+
send(:"#{pattern.type}_clause", pattern)))
|
384
389
|
end
|
385
390
|
end
|
386
391
|
|
@@ -391,13 +396,14 @@ module RubyNext
|
|
391
396
|
send :"#{child.type}_clause", child
|
392
397
|
end
|
393
398
|
end
|
394
|
-
s(:or, *children)
|
399
|
+
s(:begin, s(:or, *children))
|
395
400
|
end
|
396
401
|
|
397
402
|
def match_as_clause(node, right = s(:lvar, locals[:matchee]))
|
398
|
-
s(:
|
399
|
-
|
400
|
-
|
403
|
+
s(:begin,
|
404
|
+
s(:and,
|
405
|
+
send(:"#{node.children[0].type}_clause", node.children[0], right),
|
406
|
+
match_var_clause(node.children[1], right)))
|
401
407
|
end
|
402
408
|
|
403
409
|
def match_var_clause(node, left = s(:lvar, locals[:matchee]))
|
@@ -405,9 +411,10 @@ module RubyNext
|
|
405
411
|
|
406
412
|
check_match_var_alternation! node.children[0]
|
407
413
|
|
408
|
-
s(:
|
409
|
-
s(:
|
410
|
-
|
414
|
+
s(:begin,
|
415
|
+
s(:or,
|
416
|
+
s(:begin, s(:lvasgn, node.children[0], left)),
|
417
|
+
s(:true)))
|
411
418
|
end
|
412
419
|
|
413
420
|
def pin_clause(node, right = s(:lvar, locals[:matchee]))
|
@@ -417,8 +424,8 @@ module RubyNext
|
|
417
424
|
|
418
425
|
def case_eq_clause(node, right = s(:lvar, locals[:matchee]))
|
419
426
|
predicates.terminate!
|
420
|
-
s(:send,
|
421
|
-
process(node), :===, right)
|
427
|
+
s(:begin, s(:send,
|
428
|
+
process(node), :===, right))
|
422
429
|
end
|
423
430
|
|
424
431
|
#=========== ARRAY PATTERN (START) ===============
|
@@ -429,10 +436,11 @@ module RubyNext
|
|
429
436
|
# if there is no rest or tail, match the size first
|
430
437
|
unless node.type == :array_pattern_with_tail || node.children.any? { |n| n.type == :match_rest }
|
431
438
|
size_check = predicates.array_size(
|
432
|
-
s(:
|
433
|
-
|
434
|
-
|
435
|
-
|
439
|
+
s(:begin,
|
440
|
+
s(:send,
|
441
|
+
node.children.size.to_ast_node,
|
442
|
+
:==,
|
443
|
+
s(:send, s(:lvar, locals[:arr]), :size))),
|
436
444
|
node.children.size
|
437
445
|
)
|
438
446
|
end
|
@@ -448,9 +456,10 @@ module RubyNext
|
|
448
456
|
|
449
457
|
right = s(:and, size_check, right) if size_check
|
450
458
|
|
451
|
-
s(:
|
452
|
-
|
453
|
-
|
459
|
+
s(:begin,
|
460
|
+
s(:and,
|
461
|
+
dnode,
|
462
|
+
right))
|
454
463
|
end
|
455
464
|
end
|
456
465
|
|
@@ -468,14 +477,17 @@ module RubyNext
|
|
468
477
|
predicates.array_deconstructed(
|
469
478
|
s(:and,
|
470
479
|
respond_check,
|
471
|
-
s(:
|
472
|
-
s(:
|
473
|
-
s(:
|
474
|
-
|
475
|
-
|
476
|
-
|
477
|
-
|
478
|
-
|
480
|
+
s(:begin,
|
481
|
+
s(:and,
|
482
|
+
s(:begin,
|
483
|
+
s(:or,
|
484
|
+
s(:begin, s(:lvasgn, locals[:arr], right)),
|
485
|
+
s(:true))),
|
486
|
+
s(:begin,
|
487
|
+
s(:or,
|
488
|
+
s(:send,
|
489
|
+
s(:const, nil, :Array), :===, s(:lvar, locals[:arr])),
|
490
|
+
raise_error(:TypeError, "#deconstruct must return Array"))))))
|
479
491
|
)
|
480
492
|
end
|
481
493
|
|
@@ -485,9 +497,10 @@ module RubyNext
|
|
485
497
|
send("#{head.type}_array_element", head, index).then do |node|
|
486
498
|
next node if tail.empty?
|
487
499
|
|
488
|
-
s(:
|
489
|
-
|
490
|
-
|
500
|
+
s(:begin,
|
501
|
+
s(:and,
|
502
|
+
node,
|
503
|
+
array_element(index + 1, *tail)))
|
491
504
|
end
|
492
505
|
end
|
493
506
|
|
@@ -526,15 +539,17 @@ module RubyNext
|
|
526
539
|
|
527
540
|
pattern = array_rest_element(*nodes, index).then do |needle|
|
528
541
|
next needle unless head_match
|
529
|
-
s(:
|
530
|
-
|
531
|
-
|
542
|
+
s(:begin,
|
543
|
+
s(:and,
|
544
|
+
needle,
|
545
|
+
head_match))
|
532
546
|
end.then do |headed_needle|
|
533
547
|
next headed_needle unless tail_match
|
534
548
|
|
535
|
-
s(:
|
536
|
-
|
537
|
-
|
549
|
+
s(:begin,
|
550
|
+
s(:and,
|
551
|
+
headed_needle,
|
552
|
+
tail_match))
|
538
553
|
end
|
539
554
|
|
540
555
|
s(:block,
|
@@ -550,13 +565,14 @@ module RubyNext
|
|
550
565
|
next block if match_vars.empty?
|
551
566
|
|
552
567
|
# We need to declare match vars outside of `find` block
|
553
|
-
locals_declare = s(:masgn,
|
568
|
+
locals_declare = s(:begin, s(:masgn,
|
554
569
|
s(:mlhs, *match_vars),
|
555
|
-
s(:nil))
|
570
|
+
s(:nil)))
|
556
571
|
|
557
|
-
s(:
|
558
|
-
|
559
|
-
|
572
|
+
s(:begin,
|
573
|
+
s(:or,
|
574
|
+
locals_declare,
|
575
|
+
block))
|
560
576
|
end
|
561
577
|
end
|
562
578
|
|
@@ -575,18 +591,20 @@ module RubyNext
|
|
575
591
|
|
576
592
|
return rest if tail.empty?
|
577
593
|
|
578
|
-
s(:
|
579
|
-
|
580
|
-
|
594
|
+
s(:begin,
|
595
|
+
s(:and,
|
596
|
+
rest,
|
597
|
+
array_rest_element(*tail, -(size - 1))))
|
581
598
|
end
|
582
599
|
|
583
600
|
def array_rest_element(head, *tail, index)
|
584
601
|
send("#{head.type}_array_element", head, index).then do |node|
|
585
602
|
next node if tail.empty?
|
586
603
|
|
587
|
-
s(:
|
588
|
-
|
589
|
-
|
604
|
+
s(:begin,
|
605
|
+
s(:and,
|
606
|
+
node,
|
607
|
+
array_rest_element(*tail, index + 1)))
|
590
608
|
end
|
591
609
|
end
|
592
610
|
|
@@ -610,7 +628,7 @@ module RubyNext
|
|
610
628
|
children = node.children.map do |child, i|
|
611
629
|
send :"#{child.type}_array_element", child, index
|
612
630
|
end
|
613
|
-
s(:or, *children)
|
631
|
+
s(:begin, s(:or, *children))
|
614
632
|
end
|
615
633
|
|
616
634
|
def match_var_array_element(node, index)
|
@@ -661,18 +679,20 @@ module RubyNext
|
|
661
679
|
elsif specified_key_names.empty?
|
662
680
|
hash_element(*node.children)
|
663
681
|
else
|
664
|
-
s(:
|
665
|
-
|
666
|
-
|
682
|
+
s(:begin,
|
683
|
+
s(:and,
|
684
|
+
having_hash_keys(specified_key_names),
|
685
|
+
hash_element(*node.children)))
|
667
686
|
end
|
668
687
|
|
669
688
|
predicates.pop
|
670
689
|
|
671
690
|
next dnode if right.nil?
|
672
691
|
|
673
|
-
s(:
|
674
|
-
|
675
|
-
|
692
|
+
s(:begin,
|
693
|
+
s(:and,
|
694
|
+
dnode,
|
695
|
+
right))
|
676
696
|
end
|
677
697
|
end
|
678
698
|
|
@@ -715,7 +735,7 @@ module RubyNext
|
|
715
735
|
# Duplicate the source hash when matching **rest, 'cause we mutate it
|
716
736
|
hash_dup =
|
717
737
|
if @hash_match_rest
|
718
|
-
s(:lvasgn, locals[:hash], s(:send, s(:lvar, locals[:hash, :src]), :dup))
|
738
|
+
s(:begin, s(:lvasgn, locals[:hash], s(:send, s(:lvar, locals[:hash, :src]), :dup)))
|
719
739
|
else
|
720
740
|
s(:true)
|
721
741
|
end
|
@@ -728,29 +748,33 @@ module RubyNext
|
|
728
748
|
key_names = keys.children.map { |node| node.children.last }
|
729
749
|
predicates.push locals[:hash]
|
730
750
|
|
731
|
-
s(:lvasgn, deconstruct_name,
|
751
|
+
s(:begin, s(:lvasgn, deconstruct_name,
|
732
752
|
s(:send,
|
733
|
-
matchee, :deconstruct_keys, keys)).then do |dnode|
|
753
|
+
matchee, :deconstruct_keys, keys))).then do |dnode|
|
734
754
|
next dnode if respond_to_checked
|
735
755
|
|
736
756
|
s(:and,
|
737
757
|
respond_check,
|
738
|
-
s(:
|
739
|
-
s(:
|
740
|
-
|
741
|
-
|
742
|
-
|
743
|
-
|
744
|
-
|
745
|
-
|
758
|
+
s(:begin,
|
759
|
+
s(:and,
|
760
|
+
s(:begin,
|
761
|
+
s(:or,
|
762
|
+
dnode,
|
763
|
+
s(:true))),
|
764
|
+
s(:begin,
|
765
|
+
s(:or,
|
766
|
+
s(:send,
|
767
|
+
s(:const, nil, :Hash), :===, s(:lvar, deconstruct_name)),
|
768
|
+
raise_error(:TypeError, "#deconstruct_keys must return Hash"))))))
|
746
769
|
end.then do |dnode|
|
747
770
|
predicates.hash_deconstructed(dnode, key_names)
|
748
771
|
end.then do |dnode|
|
749
772
|
next dnode unless @hash_match_rest
|
750
773
|
|
751
|
-
s(:
|
752
|
-
|
753
|
-
|
774
|
+
s(:begin,
|
775
|
+
s(:and,
|
776
|
+
dnode,
|
777
|
+
hash_dup))
|
754
778
|
end
|
755
779
|
end
|
756
780
|
|
@@ -780,9 +804,10 @@ module RubyNext
|
|
780
804
|
|
781
805
|
next node if right.nil?
|
782
806
|
|
783
|
-
s(:
|
784
|
-
|
785
|
-
|
807
|
+
s(:begin,
|
808
|
+
s(:and,
|
809
|
+
node,
|
810
|
+
right))
|
786
811
|
end
|
787
812
|
end
|
788
813
|
|
@@ -792,7 +817,7 @@ module RubyNext
|
|
792
817
|
end
|
793
818
|
|
794
819
|
def match_alt_hash_element(node, key)
|
795
|
-
element_node = s(:lvasgn, locals[:hash, :el], hash_value_at(key))
|
820
|
+
element_node = s(:begin, s(:lvasgn, locals[:hash, :el], hash_value_at(key)))
|
796
821
|
|
797
822
|
children = locals.with(hash_element: locals[:hash, :el]) do
|
798
823
|
node.children.map do |child, i|
|
@@ -800,11 +825,14 @@ module RubyNext
|
|
800
825
|
end
|
801
826
|
end
|
802
827
|
|
803
|
-
s(:
|
804
|
-
s(:
|
805
|
-
|
806
|
-
|
807
|
-
|
828
|
+
s(:begin,
|
829
|
+
s(:and,
|
830
|
+
s(:begin,
|
831
|
+
s(:or,
|
832
|
+
element_node,
|
833
|
+
s(:true))),
|
834
|
+
s(:begin,
|
835
|
+
s(:or, *children))))
|
808
836
|
end
|
809
837
|
|
810
838
|
def match_as_hash_element(node, key)
|
@@ -858,13 +886,14 @@ module RubyNext
|
|
858
886
|
end
|
859
887
|
|
860
888
|
def having_hash_keys(keys, hash = s(:lvar, locals[:hash]))
|
861
|
-
|
862
|
-
|
889
|
+
keys.reduce(nil) do |acc, key|
|
890
|
+
pnode = hash_has_key(key, hash)
|
891
|
+
next pnode unless acc
|
863
892
|
|
864
|
-
|
865
|
-
|
866
|
-
|
867
|
-
|
893
|
+
s(:begin,
|
894
|
+
s(:and, acc, pnode))
|
895
|
+
end.then do |node|
|
896
|
+
predicates.hash_keys(node, keys)
|
868
897
|
end
|
869
898
|
end
|
870
899
|
|
@@ -873,9 +902,10 @@ module RubyNext
|
|
873
902
|
def with_guard(node, guard)
|
874
903
|
return node unless guard
|
875
904
|
|
876
|
-
s(:
|
877
|
-
|
878
|
-
|
905
|
+
s(:begin,
|
906
|
+
s(:and,
|
907
|
+
node,
|
908
|
+
guard.children[0])).then do |expr|
|
879
909
|
next expr unless guard.type == :unless_guard
|
880
910
|
s(:send, expr, :!)
|
881
911
|
end
|
@@ -933,10 +963,10 @@ module RubyNext
|
|
933
963
|
deconstructed_keys[key] = :"k#{deconstructed_keys.size}"
|
934
964
|
end
|
935
965
|
|
936
|
-
# Unparser generates `do .. end`
|
966
|
+
# Unparser generates `do .. end` or `{ ... }` multiline blocks, we want to
|
937
967
|
# have single-line blocks with `{ ... }`.
|
938
968
|
def inline_blocks(source)
|
939
|
-
source.gsub(/do \|_, __i__\|\n\s*([^\n]+)\n\s*end/, '{ |_, __i__| \1 }')
|
969
|
+
source.gsub(/(?:do|{) \|_, __i__\|\n\s*([^\n]+)\n\s*(?:end|})/, '{ |_, __i__| \1 }')
|
940
970
|
end
|
941
971
|
end
|
942
972
|
end
|