rubocop-ast 0.5.1 → 1.0.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/lib/rubocop/ast.rb +17 -0
- data/lib/rubocop/ast/builder.rb +1 -0
- data/lib/rubocop/ast/node.rb +44 -125
- data/lib/rubocop/ast/node/array_node.rb +1 -0
- data/lib/rubocop/ast/node/block_node.rb +1 -0
- data/lib/rubocop/ast/node/def_node.rb +5 -0
- data/lib/rubocop/ast/node/keyword_splat_node.rb +1 -0
- data/lib/rubocop/ast/node/mixin/collection_node.rb +1 -0
- data/lib/rubocop/ast/node/mixin/descendence.rb +116 -0
- data/lib/rubocop/ast/node/mixin/method_dispatch_node.rb +2 -0
- data/lib/rubocop/ast/node/mixin/method_identifier_predicates.rb +9 -0
- data/lib/rubocop/ast/node/mixin/numeric_node.rb +1 -0
- data/lib/rubocop/ast/node/mixin/predicate_operator_node.rb +7 -3
- data/lib/rubocop/ast/node/pair_node.rb +4 -0
- data/lib/rubocop/ast/node/regexp_node.rb +9 -4
- data/lib/rubocop/ast/node_pattern.rb +44 -870
- data/lib/rubocop/ast/node_pattern/builder.rb +72 -0
- data/lib/rubocop/ast/node_pattern/comment.rb +45 -0
- data/lib/rubocop/ast/node_pattern/compiler.rb +104 -0
- data/lib/rubocop/ast/node_pattern/compiler/atom_subcompiler.rb +56 -0
- data/lib/rubocop/ast/node_pattern/compiler/binding.rb +78 -0
- data/lib/rubocop/ast/node_pattern/compiler/debug.rb +168 -0
- data/lib/rubocop/ast/node_pattern/compiler/node_pattern_subcompiler.rb +146 -0
- data/lib/rubocop/ast/node_pattern/compiler/sequence_subcompiler.rb +420 -0
- data/lib/rubocop/ast/node_pattern/compiler/subcompiler.rb +57 -0
- data/lib/rubocop/ast/node_pattern/lexer.rb +70 -0
- data/lib/rubocop/ast/node_pattern/lexer.rex +39 -0
- data/lib/rubocop/ast/node_pattern/lexer.rex.rb +182 -0
- data/lib/rubocop/ast/node_pattern/method_definer.rb +143 -0
- data/lib/rubocop/ast/node_pattern/node.rb +275 -0
- data/lib/rubocop/ast/node_pattern/parser.racc.rb +470 -0
- data/lib/rubocop/ast/node_pattern/parser.rb +66 -0
- data/lib/rubocop/ast/node_pattern/parser.y +103 -0
- data/lib/rubocop/ast/node_pattern/sets.rb +37 -0
- data/lib/rubocop/ast/node_pattern/with_meta.rb +111 -0
- data/lib/rubocop/ast/processed_source.rb +5 -1
- data/lib/rubocop/ast/traversal.rb +149 -172
- data/lib/rubocop/ast/version.rb +1 -1
- metadata +37 -3
@@ -0,0 +1,66 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'parser.racc'
|
4
|
+
|
5
|
+
module RuboCop
|
6
|
+
module AST
|
7
|
+
class NodePattern
|
8
|
+
# Parser for NodePattern
|
9
|
+
# Note: class reopened in `parser.racc`
|
10
|
+
#
|
11
|
+
# Doc on how this fits in the compiling process:
|
12
|
+
# /doc/modules/ROOT/pages/node_pattern.md
|
13
|
+
class Parser < Racc::Parser
|
14
|
+
extend Forwardable
|
15
|
+
|
16
|
+
Builder = NodePattern::Builder
|
17
|
+
Lexer = NodePattern::Lexer
|
18
|
+
|
19
|
+
def initialize(builder = self.class::Builder.new)
|
20
|
+
super()
|
21
|
+
@builder = builder
|
22
|
+
end
|
23
|
+
|
24
|
+
##
|
25
|
+
# (Similar API to `parser` gem)
|
26
|
+
# Parses a source and returns the AST.
|
27
|
+
#
|
28
|
+
# @param [Parser::Source::Buffer, String] source_buffer The source buffer to parse.
|
29
|
+
# @return [NodePattern::Node]
|
30
|
+
#
|
31
|
+
def parse(source)
|
32
|
+
@lexer = self.class::Lexer.new(source)
|
33
|
+
do_parse
|
34
|
+
rescue Lexer::Error => e
|
35
|
+
raise NodePattern::Invalid, e.message
|
36
|
+
ensure
|
37
|
+
@lexer = nil # Don't keep references
|
38
|
+
end
|
39
|
+
|
40
|
+
def inspect
|
41
|
+
"<##{self.class}>"
|
42
|
+
end
|
43
|
+
|
44
|
+
private
|
45
|
+
|
46
|
+
def_delegators :@builder, :emit_list, :emit_unary_op, :emit_atom, :emit_capture,
|
47
|
+
:emit_call, :emit_union
|
48
|
+
def_delegators :@lexer, :next_token
|
49
|
+
|
50
|
+
def enforce_unary(node)
|
51
|
+
return node if node.arity == 1
|
52
|
+
|
53
|
+
detail = node.loc&.expression&.source || node.to_s
|
54
|
+
raise NodePattern::Invalid, 'parse error, expected unary node pattern ' \
|
55
|
+
"but got expression matching multiple elements: #{detail}"
|
56
|
+
end
|
57
|
+
|
58
|
+
# Overrides Racc::Parser's method:
|
59
|
+
def on_error(token, val, _vstack)
|
60
|
+
detail = token_to_str(token) || '?'
|
61
|
+
raise NodePattern::Invalid, "parse error on value #{val.inspect} (#{detail})"
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
@@ -0,0 +1,103 @@
|
|
1
|
+
class RuboCop::AST::NodePattern::Parser
|
2
|
+
options no_result_var
|
3
|
+
token tSYMBOL tNUMBER tSTRING tWILDCARD tPARAM_NAMED tPARAM_CONST tPARAM_NUMBER
|
4
|
+
tFUNCTION_CALL tPREDICATE tNODE_TYPE tARG_LIST tUNIFY tREGEXP
|
5
|
+
rule
|
6
|
+
node_pattern # @return Node
|
7
|
+
: node_pattern_no_union
|
8
|
+
| union { enforce_unary(val[0]) }
|
9
|
+
;
|
10
|
+
|
11
|
+
node_pattern_no_union # @return Node
|
12
|
+
: '(' variadic_pattern_list ')' { emit_list :sequence, *val }
|
13
|
+
| '[' node_pattern_list ']' { emit_list :intersection, *val }
|
14
|
+
| '!' node_pattern { emit_unary_op :negation, *val }
|
15
|
+
| '^' node_pattern { emit_unary_op :ascend, *val }
|
16
|
+
| '`' node_pattern { emit_unary_op :descend, *val }
|
17
|
+
| '$' node_pattern { emit_capture(*val) }
|
18
|
+
| tFUNCTION_CALL args { emit_call :function_call, *val }
|
19
|
+
| tPREDICATE args { emit_call :predicate, *val }
|
20
|
+
| tNODE_TYPE { emit_call :node_type, *val }
|
21
|
+
| atom
|
22
|
+
;
|
23
|
+
|
24
|
+
atom # @return Node
|
25
|
+
: tSYMBOL { emit_atom :symbol, *val }
|
26
|
+
| tNUMBER { emit_atom :number, *val }
|
27
|
+
| tSTRING { emit_atom :string, *val }
|
28
|
+
| tPARAM_CONST { emit_atom :const, *val }
|
29
|
+
| tPARAM_NAMED { emit_atom :named_parameter, *val }
|
30
|
+
| tPARAM_NUMBER { emit_atom :positional_parameter, *val }
|
31
|
+
| tREGEXP { emit_atom :regexp, *val }
|
32
|
+
| tWILDCARD { emit_atom :wildcard, *val }
|
33
|
+
| tUNIFY { emit_atom :unify, *val }
|
34
|
+
;
|
35
|
+
|
36
|
+
union # @return Node
|
37
|
+
: '{' separated_variadic_patterns '}' { emit_union(*val) }
|
38
|
+
;
|
39
|
+
|
40
|
+
variadic_pattern # @return Node
|
41
|
+
: node_pattern_no_union
|
42
|
+
| union
|
43
|
+
| node_pattern repetition
|
44
|
+
{
|
45
|
+
main, repeat_t = val
|
46
|
+
emit_unary_op(:repetition, repeat_t, main, repeat_t)
|
47
|
+
}
|
48
|
+
| opt_capture '<' node_pattern_list opt_rest '>'
|
49
|
+
{
|
50
|
+
opt_capture, bracket, node_pattern_list, opt_rest, close_bracket = val
|
51
|
+
node_pattern_list << opt_rest if opt_rest
|
52
|
+
main = emit_list :any_order, bracket, node_pattern_list, close_bracket
|
53
|
+
emit_capture(opt_capture, main)
|
54
|
+
}
|
55
|
+
| rest
|
56
|
+
;
|
57
|
+
|
58
|
+
repetition # @return Token
|
59
|
+
: '?'
|
60
|
+
| '*'
|
61
|
+
| '+'
|
62
|
+
;
|
63
|
+
|
64
|
+
opt_capture # @return Token | nil
|
65
|
+
:
|
66
|
+
| '$'
|
67
|
+
;
|
68
|
+
|
69
|
+
rest # @return Node
|
70
|
+
: opt_capture '...' { emit_capture(val[0], emit_atom(:rest, val[1])) }
|
71
|
+
;
|
72
|
+
|
73
|
+
opt_rest # @return Node | nil
|
74
|
+
:
|
75
|
+
| rest
|
76
|
+
;
|
77
|
+
|
78
|
+
args # @return [Token, Array<Node>, Token] | nil
|
79
|
+
:
|
80
|
+
| tARG_LIST arg_list ')' { val }
|
81
|
+
;
|
82
|
+
|
83
|
+
arg_list # @return Array<Node>
|
84
|
+
: node_pattern { val }
|
85
|
+
| arg_list ',' node_pattern { val[0] << val[2] }
|
86
|
+
;
|
87
|
+
|
88
|
+
node_pattern_list # @return Array<Node>
|
89
|
+
: node_pattern { val }
|
90
|
+
| node_pattern_list node_pattern { val[0] << val[1] }
|
91
|
+
;
|
92
|
+
|
93
|
+
variadic_pattern_list # @return Array<Node>
|
94
|
+
: variadic_pattern { val }
|
95
|
+
| variadic_pattern_list variadic_pattern { val[0] << val[1] }
|
96
|
+
;
|
97
|
+
|
98
|
+
separated_variadic_patterns # @return Array<Array<Node>>
|
99
|
+
: { [[]] }
|
100
|
+
| separated_variadic_patterns variadic_pattern { val[0].last << val[1]; val[0] }
|
101
|
+
| separated_variadic_patterns '|' { val[0] << [] }
|
102
|
+
;
|
103
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module AST
|
5
|
+
class NodePattern
|
6
|
+
# Utility to assign a set of values to a constant
|
7
|
+
module Sets
|
8
|
+
REGISTRY = Hash.new do |h, set|
|
9
|
+
name = Sets.name(set).freeze
|
10
|
+
Sets.const_set(name, set)
|
11
|
+
h[set] = "::RuboCop::AST::NodePattern::Sets::#{name}"
|
12
|
+
end
|
13
|
+
|
14
|
+
MAX = 4
|
15
|
+
def self.name(set)
|
16
|
+
elements = set
|
17
|
+
elements = set.first(MAX - 1) << :etc if set.size > MAX
|
18
|
+
name = elements.to_a.join('_').upcase.gsub(/[^A-Z0-9_]/, '')
|
19
|
+
uniq("SET_#{name}")
|
20
|
+
end
|
21
|
+
|
22
|
+
def self.uniq(name)
|
23
|
+
return name unless Sets.const_defined?(name)
|
24
|
+
|
25
|
+
(2..Float::INFINITY).each do |i|
|
26
|
+
uniq = "#{name}_#{i}"
|
27
|
+
return uniq unless Sets.const_defined?(uniq)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def self.[](set)
|
32
|
+
REGISTRY[set]
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,111 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module AST
|
5
|
+
class NodePattern
|
6
|
+
class Parser
|
7
|
+
# Overrides Parser to use `WithMeta` variants and provide additional methods
|
8
|
+
class WithMeta < Parser
|
9
|
+
# Overrides Lexer to token locations and comments
|
10
|
+
class Lexer < NodePattern::Lexer
|
11
|
+
attr_reader :source_buffer
|
12
|
+
|
13
|
+
def initialize(str_or_buffer)
|
14
|
+
@source_buffer = if str_or_buffer.respond_to?(:source)
|
15
|
+
str_or_buffer
|
16
|
+
else
|
17
|
+
::Parser::Source::Buffer.new('(string)', source: str_or_buffer)
|
18
|
+
end
|
19
|
+
@comments = []
|
20
|
+
super(@source_buffer.source)
|
21
|
+
end
|
22
|
+
|
23
|
+
def token(type, value)
|
24
|
+
super(type, [value, pos])
|
25
|
+
end
|
26
|
+
|
27
|
+
def emit_comment
|
28
|
+
@comments << Comment.new(pos)
|
29
|
+
super
|
30
|
+
end
|
31
|
+
|
32
|
+
# @return [::Parser::Source::Range] last match's position
|
33
|
+
def pos
|
34
|
+
::Parser::Source::Range.new(source_buffer, ss.pos - ss.matched_size, ss.pos)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
# Overrides Builder to emit nodes with locations
|
39
|
+
class Builder < NodePattern::Builder
|
40
|
+
def emit_atom(type, token)
|
41
|
+
value, loc = token
|
42
|
+
begin_l = loc.resize(1)
|
43
|
+
end_l = loc.end.adjust(begin_pos: -1)
|
44
|
+
begin_l = nil if begin_l.source.match?(/\w/)
|
45
|
+
end_l = nil if end_l.source.match?(/\w/)
|
46
|
+
n(type, [value], source_map(token, begin_t: begin_l, end_t: end_l))
|
47
|
+
end
|
48
|
+
|
49
|
+
def emit_unary_op(type, operator_t = nil, *children)
|
50
|
+
children[-1] = children[-1].first if children[-1].is_a?(Array) # token?
|
51
|
+
map = source_map(children.first.loc.expression, operator_t: operator_t)
|
52
|
+
n(type, children, map)
|
53
|
+
end
|
54
|
+
|
55
|
+
def emit_list(type, begin_t, children, end_t)
|
56
|
+
expr = children.first.loc.expression.join(children.last.loc.expression)
|
57
|
+
map = source_map(expr, begin_t: begin_t, end_t: end_t)
|
58
|
+
n(type, children, map)
|
59
|
+
end
|
60
|
+
|
61
|
+
def emit_call(type, selector_t, args = nil)
|
62
|
+
selector, = selector_t
|
63
|
+
begin_t, arg_nodes, end_t = args
|
64
|
+
|
65
|
+
map = source_map(selector_t, begin_t: begin_t, end_t: end_t, selector_t: selector_t)
|
66
|
+
n(type, [selector, *arg_nodes], map)
|
67
|
+
end
|
68
|
+
|
69
|
+
private
|
70
|
+
|
71
|
+
def n(type, children, source_map)
|
72
|
+
super(type, children, { location: source_map })
|
73
|
+
end
|
74
|
+
|
75
|
+
def loc(token_or_range)
|
76
|
+
return token_or_range[1] if token_or_range.is_a?(Array)
|
77
|
+
|
78
|
+
token_or_range
|
79
|
+
end
|
80
|
+
|
81
|
+
def join_exprs(left_expr, right_expr)
|
82
|
+
left_expr.loc.expression
|
83
|
+
.join(right_expr.loc.expression)
|
84
|
+
end
|
85
|
+
|
86
|
+
def source_map(token_or_range, begin_t: nil, end_t: nil, operator_t: nil, selector_t: nil)
|
87
|
+
expression_l = loc(token_or_range)
|
88
|
+
expression_l = expression_l.expression if expression_l.respond_to?(:expression)
|
89
|
+
locs = [begin_t, end_t, operator_t, selector_t].map { |token| loc(token) }
|
90
|
+
begin_l, end_l, operator_l, selector_l = locs
|
91
|
+
|
92
|
+
expression_l = locs.compact.inject(expression_l, :join)
|
93
|
+
|
94
|
+
::Parser::Source::Map::Send.new(_dot_l = nil, selector_l, begin_l, end_l, expression_l)
|
95
|
+
.with_operator(operator_l)
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
attr_reader :comments, :tokens
|
100
|
+
|
101
|
+
def do_parse
|
102
|
+
r = super
|
103
|
+
@comments = @lexer.comments
|
104
|
+
@tokens = @lexer.tokens
|
105
|
+
r
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
@@ -9,6 +9,7 @@ module RuboCop
|
|
9
9
|
# and other information such as disabled lines for cops.
|
10
10
|
# It also provides a convenient way to access source lines.
|
11
11
|
class ProcessedSource
|
12
|
+
# @api private
|
12
13
|
STRING_SOURCE_NAME = '(string)'
|
13
14
|
|
14
15
|
attr_reader :path, :buffer, :ast, :comments, :tokens, :diagnostics,
|
@@ -19,6 +20,9 @@ module RuboCop
|
|
19
20
|
new(file, ruby_version, path)
|
20
21
|
end
|
21
22
|
|
23
|
+
INVALID_LEVELS = %i[error fatal].freeze
|
24
|
+
private_constant :INVALID_LEVELS
|
25
|
+
|
22
26
|
def initialize(source, ruby_version, path = nil)
|
23
27
|
# Defaults source encoding to UTF-8, regardless of the encoding it has
|
24
28
|
# been read with, which could be non-utf8 depending on the default
|
@@ -63,7 +67,7 @@ module RuboCop
|
|
63
67
|
def valid_syntax?
|
64
68
|
return false if @parser_error
|
65
69
|
|
66
|
-
@diagnostics.none? { |d|
|
70
|
+
@diagnostics.none? { |d| INVALID_LEVELS.include?(d.level) }
|
67
71
|
end
|
68
72
|
|
69
73
|
# Raw source checksum for tracking infinite loops.
|
@@ -1,6 +1,5 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
# rubocop:disable Metrics/ModuleLength
|
4
3
|
module RuboCop
|
5
4
|
module AST
|
6
5
|
# Provides methods for traversing an AST.
|
@@ -8,197 +7,175 @@ module RuboCop
|
|
8
7
|
# Override methods to perform custom processing. Remember to call `super`
|
9
8
|
# if you want to recursively process descendant nodes.
|
10
9
|
module Traversal
|
10
|
+
# Only for debugging.
|
11
|
+
# @api private
|
12
|
+
class DebugError < RuntimeError
|
13
|
+
end
|
14
|
+
|
15
|
+
TYPE_TO_METHOD = Hash.new { |h, type| h[type] = :"on_#{type}" }
|
16
|
+
|
11
17
|
def walk(node)
|
12
18
|
return if node.nil?
|
13
19
|
|
14
|
-
send(
|
20
|
+
send(TYPE_TO_METHOD[node.type], node)
|
15
21
|
nil
|
16
22
|
end
|
17
23
|
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
SECOND_CHILD_ONLY = %i[lvasgn ivasgn cvasgn gvasgn optarg kwarg
|
40
|
-
kwoptarg].freeze
|
41
|
-
|
42
|
-
NO_CHILD_NODES.each do |type|
|
43
|
-
module_eval("def on_#{type}(node); end", __FILE__, __LINE__)
|
44
|
-
end
|
45
|
-
|
46
|
-
ONE_CHILD_NODE.each do |type|
|
47
|
-
module_eval(<<~RUBY, __FILE__, __LINE__ + 1)
|
48
|
-
def on_#{type}(node)
|
49
|
-
if (child = node.children[0])
|
50
|
-
send(:"on_\#{child.type}", child)
|
24
|
+
# @api private
|
25
|
+
module CallbackCompiler
|
26
|
+
SEND = 'send(TYPE_TO_METHOD[child.type], child)'
|
27
|
+
assign_code = 'child = node.children[%<index>i]'
|
28
|
+
code = "#{assign_code}\n#{SEND}"
|
29
|
+
TEMPLATE = {
|
30
|
+
skip: '',
|
31
|
+
always: code,
|
32
|
+
nil?: "#{code} if child"
|
33
|
+
}.freeze
|
34
|
+
|
35
|
+
def def_callback(type, *signature,
|
36
|
+
arity: signature.size..signature.size,
|
37
|
+
arity_check: ENV['RUBOCOP_DEBUG'] && self.arity_check(arity),
|
38
|
+
body: self.body(signature, arity_check))
|
39
|
+
type, *aliases = type
|
40
|
+
lineno = caller_locations(1, 1).first.lineno
|
41
|
+
module_eval(<<~RUBY, __FILE__, lineno) # rubocop:disable Style/EvalWithLocation
|
42
|
+
def on_#{type}(node)
|
43
|
+
#{body}
|
44
|
+
nil
|
51
45
|
end
|
46
|
+
RUBY
|
47
|
+
aliases.each do |m|
|
48
|
+
alias_method "on_#{m}", "on_#{type}"
|
52
49
|
end
|
53
|
-
|
54
|
-
end
|
55
|
-
|
56
|
-
MANY_CHILD_NODES.each do |type|
|
57
|
-
module_eval(<<~RUBY, __FILE__, __LINE__ + 1)
|
58
|
-
def on_#{type}(node)
|
59
|
-
node.children.each { |child| send(:"on_\#{child.type}", child) }
|
60
|
-
nil
|
61
|
-
end
|
62
|
-
RUBY
|
63
|
-
end
|
50
|
+
end
|
64
51
|
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
if (child = node.children[1])
|
70
|
-
send(:"on_\#{child.type}", child)
|
52
|
+
def body(signature, prelude)
|
53
|
+
signature
|
54
|
+
.map.with_index do |arg, i|
|
55
|
+
TEMPLATE[arg].gsub('%<index>i', i.to_s)
|
71
56
|
end
|
72
|
-
|
73
|
-
|
74
|
-
end
|
75
|
-
|
76
|
-
def on_const(node)
|
77
|
-
return unless (child = node.children[0])
|
78
|
-
|
79
|
-
send(:"on_#{child.type}", child)
|
80
|
-
end
|
81
|
-
|
82
|
-
def on_casgn(node)
|
83
|
-
children = node.children
|
84
|
-
if (child = children[0]) # always const???
|
85
|
-
send(:"on_#{child.type}", child)
|
57
|
+
.unshift(prelude)
|
58
|
+
.join("\n")
|
86
59
|
end
|
87
|
-
return unless (child = children[2])
|
88
|
-
|
89
|
-
send(:"on_#{child.type}", child)
|
90
|
-
end
|
91
60
|
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
61
|
+
def arity_check(range)
|
62
|
+
<<~RUBY
|
63
|
+
n = node.children.size
|
64
|
+
raise DebugError, [
|
65
|
+
'Expected #{range} children, got',
|
66
|
+
n, 'for', node.inspect
|
67
|
+
].join(' ') unless (#{range}).cover?(node.children.size)
|
68
|
+
RUBY
|
98
69
|
end
|
99
|
-
return unless (child = children[2])
|
100
|
-
|
101
|
-
send(:"on_#{child.type}", child)
|
102
|
-
end
|
103
|
-
|
104
|
-
def on_def(node)
|
105
|
-
children = node.children
|
106
|
-
on_args(children[1])
|
107
|
-
return unless (child = children[2])
|
108
|
-
|
109
|
-
send(:"on_#{child.type}", child)
|
110
70
|
end
|
111
|
-
|
112
|
-
|
71
|
+
private_constant :CallbackCompiler
|
72
|
+
extend CallbackCompiler
|
73
|
+
send_code = CallbackCompiler::SEND
|
74
|
+
|
75
|
+
### arity == 0
|
76
|
+
no_children = %i[true false nil self cbase zsuper redo retry
|
77
|
+
forward_args forwarded_args match_nil_pattern
|
78
|
+
forward_arg lambda empty_else kwnilarg
|
79
|
+
__FILE__ __LINE__ __ENCODING__]
|
80
|
+
|
81
|
+
### arity == 0..1
|
82
|
+
opt_symbol_child = %i[restarg kwrestarg]
|
83
|
+
opt_node_child = %i[splat kwsplat match_rest]
|
84
|
+
|
85
|
+
### arity == 1
|
86
|
+
literal_child = %i[int float complex
|
87
|
+
rational str sym lvar
|
88
|
+
ivar cvar gvar nth_ref back_ref
|
89
|
+
arg blockarg shadowarg
|
90
|
+
kwarg match_var]
|
91
|
+
|
92
|
+
many_symbol_children = %i[regopt]
|
93
|
+
|
94
|
+
node_child = %i[block_pass not
|
95
|
+
match_current_line defined?
|
96
|
+
arg_expr pin if_guard unless_guard
|
97
|
+
match_with_trailing_comma]
|
98
|
+
node_or_nil_child = %i[preexe postexe]
|
99
|
+
|
100
|
+
NO_CHILD_NODES = (no_children + opt_symbol_child + literal_child).to_set.freeze
|
101
|
+
private_constant :NO_CHILD_NODES # Used by Commissioner
|
102
|
+
|
103
|
+
### arity > 1
|
104
|
+
symbol_then_opt_node = %i[lvasgn ivasgn cvasgn gvasgn]
|
105
|
+
symbol_then_node_or_nil = %i[optarg kwoptarg]
|
106
|
+
node_then_opt_node = %i[while until module sclass]
|
107
|
+
|
108
|
+
### variable arity
|
109
|
+
many_node_children = %i[dstr dsym xstr regexp array hash pair
|
110
|
+
mlhs masgn or_asgn and_asgn rasgn mrasgn
|
111
|
+
undef alias args super yield or and
|
112
|
+
while_post until_post iflipflop eflipflop
|
113
|
+
match_with_lvasgn begin kwbegin return
|
114
|
+
in_match match_alt break next
|
115
|
+
match_as array_pattern array_pattern_with_tail
|
116
|
+
hash_pattern const_pattern find_pattern
|
117
|
+
index indexasgn procarg0]
|
118
|
+
many_opt_node_children = %i[case rescue resbody ensure for when
|
119
|
+
case_match in_pattern irange erange]
|
120
|
+
|
121
|
+
### Callbacks for above
|
122
|
+
def_callback no_children
|
123
|
+
def_callback opt_symbol_child, :skip, arity: 0..1
|
124
|
+
def_callback opt_node_child, :nil?, arity: 0..1
|
125
|
+
|
126
|
+
def_callback literal_child, :skip
|
127
|
+
def_callback node_child, :always
|
128
|
+
def_callback node_or_nil_child, :nil?
|
129
|
+
|
130
|
+
def_callback symbol_then_opt_node, :skip, :nil?, arity: 1..2
|
131
|
+
def_callback symbol_then_node_or_nil, :skip, :nil?
|
132
|
+
def_callback node_then_opt_node, :always, :nil?
|
133
|
+
|
134
|
+
def_callback many_symbol_children, :skip, arity_check: nil
|
135
|
+
def_callback many_node_children, body: <<~RUBY
|
136
|
+
node.children.each { |child| #{send_code} }
|
137
|
+
RUBY
|
138
|
+
def_callback many_opt_node_children,
|
139
|
+
body: <<~RUBY
|
140
|
+
node.children.each { |child| #{send_code} if child }
|
141
|
+
RUBY
|
142
|
+
|
143
|
+
### Other particular cases
|
144
|
+
def_callback :const, :nil?, :skip
|
145
|
+
def_callback :casgn, :nil?, :skip, :nil?, arity: 2..3
|
146
|
+
def_callback :class, :always, :nil?, :nil?
|
147
|
+
def_callback :def, :skip, :always, :nil?
|
148
|
+
def_callback :op_asgn, :always, :skip, :always
|
149
|
+
def_callback :if, :always, :nil?, :nil?
|
150
|
+
def_callback :block, :always, :always, :nil?
|
151
|
+
def_callback :numblock, :always, :skip, :nil?
|
152
|
+
def_callback :defs, :always, :skip, :always, :nil?
|
153
|
+
|
154
|
+
def_callback %i[send csend], body: <<~RUBY
|
113
155
|
node.children.each_with_index do |child, i|
|
114
156
|
next if i == 1
|
115
157
|
|
116
|
-
|
158
|
+
#{send_code} if child
|
117
159
|
end
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
def on_defs(node)
|
132
|
-
children = node.children
|
133
|
-
child = children[0]
|
134
|
-
send(:"on_#{child.type}", child)
|
135
|
-
on_args(children[2])
|
136
|
-
return unless (child = children[3])
|
137
|
-
|
138
|
-
send(:"on_#{child.type}", child)
|
139
|
-
end
|
140
|
-
|
141
|
-
def on_if(node)
|
142
|
-
children = node.children
|
143
|
-
child = children[0]
|
144
|
-
send(:"on_#{child.type}", child)
|
145
|
-
if (child = children[1])
|
146
|
-
send(:"on_#{child.type}", child)
|
147
|
-
end
|
148
|
-
return unless (child = children[2])
|
149
|
-
|
150
|
-
send(:"on_#{child.type}", child)
|
151
|
-
end
|
152
|
-
|
153
|
-
def on_while(node)
|
154
|
-
children = node.children
|
155
|
-
child = children[0]
|
156
|
-
send(:"on_#{child.type}", child)
|
157
|
-
return unless (child = children[1])
|
158
|
-
|
159
|
-
send(:"on_#{child.type}", child)
|
160
|
-
end
|
161
|
-
|
162
|
-
alias on_until on_while
|
163
|
-
alias on_module on_while
|
164
|
-
alias on_sclass on_while
|
165
|
-
|
166
|
-
def on_block(node)
|
167
|
-
children = node.children
|
168
|
-
child = children[0]
|
169
|
-
send(:"on_#{child.type}", child) # can be send, zsuper...
|
170
|
-
on_args(children[1])
|
171
|
-
return unless (child = children[2])
|
172
|
-
|
173
|
-
send(:"on_#{child.type}", child)
|
174
|
-
end
|
175
|
-
|
176
|
-
def on_case(node)
|
160
|
+
RUBY
|
161
|
+
|
162
|
+
### generic processing of any other node (forward compatibility)
|
163
|
+
defined = instance_methods(false)
|
164
|
+
.grep(/^on_/)
|
165
|
+
.map { |s| s.to_s[3..-1].to_sym } # :on_foo => :foo
|
166
|
+
|
167
|
+
to_define = ::Parser::Meta::NODE_TYPES.to_a
|
168
|
+
to_define -= defined
|
169
|
+
to_define -= %i[numargs ident] # transient
|
170
|
+
to_define -= %i[blockarg_expr restarg_expr] # obsolete
|
171
|
+
to_define -= %i[objc_kwarg objc_restarg objc_varargs] # mac_ruby
|
172
|
+
def_callback to_define, body: <<~RUBY
|
177
173
|
node.children.each do |child|
|
178
|
-
|
174
|
+
next unless child.class == Node
|
175
|
+
#{send_code}
|
179
176
|
end
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
alias on_rescue on_case
|
184
|
-
alias on_resbody on_case
|
185
|
-
alias on_ensure on_case
|
186
|
-
alias on_for on_case
|
187
|
-
alias on_when on_case
|
188
|
-
alias on_case_match on_case
|
189
|
-
alias on_in_pattern on_case
|
190
|
-
alias on_irange on_case
|
191
|
-
alias on_erange on_case
|
192
|
-
|
193
|
-
def on_numblock(node)
|
194
|
-
children = node.children
|
195
|
-
child = children[0]
|
196
|
-
send(:"on_#{child.type}", child)
|
197
|
-
return unless (child = children[2])
|
198
|
-
|
199
|
-
send(:"on_#{child.type}", child)
|
200
|
-
end
|
177
|
+
RUBY
|
178
|
+
MISSING = to_define if ENV['RUBOCOP_DEBUG']
|
201
179
|
end
|
202
180
|
end
|
203
181
|
end
|
204
|
-
# rubocop:enable Metrics/ModuleLength
|