rubocop-ast 0.6.0 → 0.7.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/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 +1 -0
- 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 +69 -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 +1 -0
- data/lib/rubocop/ast/traversal.rb +1 -0
- data/lib/rubocop/ast/version.rb +1 -1
- metadata +36 -2
@@ -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,
|
@@ -38,6 +38,7 @@ module RuboCop
|
|
38
38
|
index indexasgn].freeze
|
39
39
|
SECOND_CHILD_ONLY = %i[lvasgn ivasgn cvasgn gvasgn optarg kwarg
|
40
40
|
kwoptarg].freeze
|
41
|
+
private_constant :NO_CHILD_NODES, :ONE_CHILD_NODE, :MANY_CHILD_NODES, :SECOND_CHILD_ONLY
|
41
42
|
|
42
43
|
NO_CHILD_NODES.each do |type|
|
43
44
|
module_eval("def on_#{type}(node); end", __FILE__, __LINE__)
|
data/lib/rubocop/ast/version.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rubocop-ast
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.7.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Bozhidar Batsov
|
@@ -10,7 +10,7 @@ authors:
|
|
10
10
|
autorequire:
|
11
11
|
bindir: bin
|
12
12
|
cert_chain: []
|
13
|
-
date: 2020-09-
|
13
|
+
date: 2020-09-28 00:00:00.000000000 Z
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
16
16
|
name: parser
|
@@ -26,6 +26,20 @@ dependencies:
|
|
26
26
|
- - ">="
|
27
27
|
- !ruby/object:Gem::Version
|
28
28
|
version: 2.7.1.5
|
29
|
+
- !ruby/object:Gem::Dependency
|
30
|
+
name: strscan
|
31
|
+
requirement: !ruby/object:Gem::Requirement
|
32
|
+
requirements:
|
33
|
+
- - ">="
|
34
|
+
- !ruby/object:Gem::Version
|
35
|
+
version: 1.0.0
|
36
|
+
type: :runtime
|
37
|
+
prerelease: false
|
38
|
+
version_requirements: !ruby/object:Gem::Requirement
|
39
|
+
requirements:
|
40
|
+
- - ">="
|
41
|
+
- !ruby/object:Gem::Version
|
42
|
+
version: 1.0.0
|
29
43
|
- !ruby/object:Gem::Dependency
|
30
44
|
name: bundler
|
31
45
|
requirement: !ruby/object:Gem::Requirement
|
@@ -89,6 +103,7 @@ files:
|
|
89
103
|
- lib/rubocop/ast/node/mixin/binary_operator_node.rb
|
90
104
|
- lib/rubocop/ast/node/mixin/collection_node.rb
|
91
105
|
- lib/rubocop/ast/node/mixin/conditional_node.rb
|
106
|
+
- lib/rubocop/ast/node/mixin/descendence.rb
|
92
107
|
- lib/rubocop/ast/node/mixin/hash_element_node.rb
|
93
108
|
- lib/rubocop/ast/node/mixin/method_dispatch_node.rb
|
94
109
|
- lib/rubocop/ast/node/mixin/method_identifier_predicates.rb
|
@@ -115,6 +130,25 @@ files:
|
|
115
130
|
- lib/rubocop/ast/node/while_node.rb
|
116
131
|
- lib/rubocop/ast/node/yield_node.rb
|
117
132
|
- lib/rubocop/ast/node_pattern.rb
|
133
|
+
- lib/rubocop/ast/node_pattern/builder.rb
|
134
|
+
- lib/rubocop/ast/node_pattern/comment.rb
|
135
|
+
- lib/rubocop/ast/node_pattern/compiler.rb
|
136
|
+
- lib/rubocop/ast/node_pattern/compiler/atom_subcompiler.rb
|
137
|
+
- lib/rubocop/ast/node_pattern/compiler/binding.rb
|
138
|
+
- lib/rubocop/ast/node_pattern/compiler/debug.rb
|
139
|
+
- lib/rubocop/ast/node_pattern/compiler/node_pattern_subcompiler.rb
|
140
|
+
- lib/rubocop/ast/node_pattern/compiler/sequence_subcompiler.rb
|
141
|
+
- lib/rubocop/ast/node_pattern/compiler/subcompiler.rb
|
142
|
+
- lib/rubocop/ast/node_pattern/lexer.rb
|
143
|
+
- lib/rubocop/ast/node_pattern/lexer.rex
|
144
|
+
- lib/rubocop/ast/node_pattern/lexer.rex.rb
|
145
|
+
- lib/rubocop/ast/node_pattern/method_definer.rb
|
146
|
+
- lib/rubocop/ast/node_pattern/node.rb
|
147
|
+
- lib/rubocop/ast/node_pattern/parser.racc.rb
|
148
|
+
- lib/rubocop/ast/node_pattern/parser.rb
|
149
|
+
- lib/rubocop/ast/node_pattern/parser.y
|
150
|
+
- lib/rubocop/ast/node_pattern/sets.rb
|
151
|
+
- lib/rubocop/ast/node_pattern/with_meta.rb
|
118
152
|
- lib/rubocop/ast/processed_source.rb
|
119
153
|
- lib/rubocop/ast/rubocop_compatibility.rb
|
120
154
|
- lib/rubocop/ast/sexp.rb
|