ripper_ruby_parser 1.10.0 → 1.11.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +54 -0
- data/README.md +7 -5
- data/lib/ripper_ruby_parser/commenting_ripper_parser.rb +45 -14
- data/lib/ripper_ruby_parser/sexp_handlers/assignment.rb +43 -19
- data/lib/ripper_ruby_parser/sexp_handlers/blocks.rb +15 -8
- data/lib/ripper_ruby_parser/sexp_handlers/conditionals.rb +89 -0
- data/lib/ripper_ruby_parser/sexp_handlers/helper_methods.rb +11 -2
- data/lib/ripper_ruby_parser/sexp_handlers/literals.rb +5 -1
- data/lib/ripper_ruby_parser/sexp_handlers/methods.rb +12 -9
- data/lib/ripper_ruby_parser/sexp_handlers/operators.rb +29 -15
- data/lib/ripper_ruby_parser/sexp_handlers/string_literals.rb +15 -14
- data/lib/ripper_ruby_parser/sexp_processor.rb +5 -8
- data/lib/ripper_ruby_parser/unescape.rb +6 -2
- data/lib/ripper_ruby_parser/version.rb +1 -1
- metadata +16 -16
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 568f21d8800cba790d212bb45e96554f93a271da3d9bae483fbf101385906d8d
|
4
|
+
data.tar.gz: fa4393288ca29703405077d9da524a51cb0d7575c08b8dcabcc9be3bcbe5d6d0
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 5dcfda84f25d0351b0351e06eb231deaab73d6377991a6b1939dc9c4df268c8cfb0960c22ca50a0d3a5dec432a855ef2ddb8a66171b321855ae2732c1f2d5518
|
7
|
+
data.tar.gz: 7c68ec079fe840e6990d1555b1751639b46113f636fcc4e90429af4a3c36382f19ba6fbd6c3c0016271e1082412dd6f9001c7f8fb7c20858aec06d1d88a4af59
|
data/CHANGELOG.md
CHANGED
@@ -6,6 +6,58 @@ This project adheres to [Semantic Versioning 2.0.0][1].
|
|
6
6
|
|
7
7
|
This document is formatted based on [Keep A CHANGELOG][2].
|
8
8
|
|
9
|
+
## 1.11.0 / 2024-01-05
|
10
|
+
|
11
|
+
* Support Ruby 3.0 through 3.3, dropping support for Ruby 2.6 and 2.7
|
12
|
+
([#218], [#219], [#233] and [#246] by [mvz])
|
13
|
+
* Target compatibility with `ruby_parser` version 3.20.2
|
14
|
+
([#199], [#216] and [#230] by [mvz])
|
15
|
+
* Support single-line pattern matching ([#188] by [mvz])
|
16
|
+
* Support rightward assignment ([#189] by [mvz])
|
17
|
+
* Support endless methods with Ruby 3.0 syntax ([#191] by [mvz])
|
18
|
+
* Support arguments without parentheses in endless method body ([#193] by [mvz])
|
19
|
+
* Add support for pattern matching ([#172] by [mvz])
|
20
|
+
* Add tentative support for numbered parameters ([#163] by [mvz])
|
21
|
+
* Support several new Ruby 3.1 syntax features ([#196] by [mvz])
|
22
|
+
* Support negative rational and imaginary literals ([#197] by [mvz])
|
23
|
+
* Correctly handle match operator with regexp literals in parentheses
|
24
|
+
([#200] by [mvz])
|
25
|
+
* Improve operator assignment handling ([#201] by [mvz])
|
26
|
+
* Handle literal Ctrl-? (DEL) character correctly ([#202] by [mvz])
|
27
|
+
* Handle method names that are keywords in method definitions ([#204] by [mvz])
|
28
|
+
* Improve dsym handling compatibility ([#203], [#210] by [mvz])
|
29
|
+
* Add support for Ruby 3.2's splat and kwsplat argument forwarding ([#231] by [mvz])
|
30
|
+
* Improve handling of the case .. in construction ([#234] by [mvz])
|
31
|
+
|
32
|
+
[mvz]: https://github.com/mvz
|
33
|
+
|
34
|
+
[#163]: https://github.com/mvz/ripper_ruby_parser/pull/163
|
35
|
+
[#172]: https://github.com/mvz/ripper_ruby_parser/pull/172
|
36
|
+
[#188]: https://github.com/mvz/ripper_ruby_parser/pull/188
|
37
|
+
[#189]: https://github.com/mvz/ripper_ruby_parser/pull/189
|
38
|
+
[#191]: https://github.com/mvz/ripper_ruby_parser/pull/191
|
39
|
+
[#193]: https://github.com/mvz/ripper_ruby_parser/pull/193
|
40
|
+
[#196]: https://github.com/mvz/ripper_ruby_parser/pull/196
|
41
|
+
[#197]: https://github.com/mvz/ripper_ruby_parser/pull/197
|
42
|
+
[#199]: https://github.com/mvz/ripper_ruby_parser/pull/199
|
43
|
+
[#200]: https://github.com/mvz/ripper_ruby_parser/pull/200
|
44
|
+
[#201]: https://github.com/mvz/ripper_ruby_parser/pull/201
|
45
|
+
[#202]: https://github.com/mvz/ripper_ruby_parser/pull/202
|
46
|
+
[#203]: https://github.com/mvz/ripper_ruby_parser/pull/203
|
47
|
+
[#204]: https://github.com/mvz/ripper_ruby_parser/pull/204
|
48
|
+
[#205]: https://github.com/mvz/ripper_ruby_parser/pull/205
|
49
|
+
[#210]: https://github.com/mvz/ripper_ruby_parser/pull/210
|
50
|
+
[#216]: https://github.com/mvz/ripper_ruby_parser/pull/216
|
51
|
+
[#218]: https://github.com/mvz/ripper_ruby_parser/pull/218
|
52
|
+
[#219]: https://github.com/mvz/ripper_ruby_parser/pull/219
|
53
|
+
[#230]: https://github.com/mvz/ripper_ruby_parser/pull/230
|
54
|
+
[#231]: https://github.com/mvz/ripper_ruby_parser/pull/231
|
55
|
+
[#232]: https://github.com/mvz/ripper_ruby_parser/pull/232
|
56
|
+
[#233]: https://github.com/mvz/ripper_ruby_parser/pull/233
|
57
|
+
[#234]: https://github.com/mvz/ripper_ruby_parser/pull/234
|
58
|
+
[#235]: https://github.com/mvz/ripper_ruby_parser/pull/235
|
59
|
+
[#246]: https://github.com/mvz/ripper_ruby_parser/pull/246
|
60
|
+
|
9
61
|
## 1.10.0 / 2022-03-13
|
10
62
|
|
11
63
|
* Handle shadow arguments ([#161])
|
@@ -233,6 +285,8 @@ This document is formatted based on [Keep A CHANGELOG][2].
|
|
233
285
|
|
234
286
|
<!-- Pull request links -->
|
235
287
|
[#180]: https://github.com/mvz/ripper_ruby_parser/pull/180
|
288
|
+
[#172]: https://github.com/mvz/ripper_ruby_parser/pull/172
|
289
|
+
[#163]: https://github.com/mvz/ripper_ruby_parser/pull/163
|
236
290
|
[#165]: https://github.com/mvz/ripper_ruby_parser/pull/165
|
237
291
|
[#161]: https://github.com/mvz/ripper_ruby_parser/pull/161
|
238
292
|
[#155]: https://github.com/mvz/ripper_ruby_parser/pull/155
|
data/README.md
CHANGED
@@ -10,8 +10,8 @@ Parse with Ripper, produce sexps that are compatible with RubyParser.
|
|
10
10
|
|
11
11
|
* Drop-in replacement for RubyParser
|
12
12
|
* Should handle 1.9 and later syntax gracefully
|
13
|
-
* Requires Ruby
|
14
|
-
* Compatible with RubyParser 3.
|
13
|
+
* Requires Ruby 3.0 or higher
|
14
|
+
* Compatible with RubyParser 3.20.2
|
15
15
|
|
16
16
|
## Known incompatibilities
|
17
17
|
|
@@ -25,7 +25,9 @@ RipperRubyParser has a few incompatibilities with RubyParser.
|
|
25
25
|
|
26
26
|
## Install
|
27
27
|
|
28
|
-
|
28
|
+
```bash
|
29
|
+
gem install ripper_ruby_parser
|
30
|
+
```
|
29
31
|
|
30
32
|
## Synopsis
|
31
33
|
|
@@ -44,7 +46,7 @@ parser.parse "foo[bar] += baz qux"
|
|
44
46
|
|
45
47
|
## Requirements
|
46
48
|
|
47
|
-
* Ruby 2.
|
49
|
+
* Ruby 2.7 or higher
|
48
50
|
* `sexp_processor`
|
49
51
|
|
50
52
|
## Hacking and contributing
|
@@ -64,7 +66,7 @@ If you want to send pull requests or patches, please:
|
|
64
66
|
|
65
67
|
(The MIT License)
|
66
68
|
|
67
|
-
Copyright (c) 2012, 2014-
|
69
|
+
Copyright (c) 2012, 2014-2024 Matijs van Zuijlen
|
68
70
|
|
69
71
|
Permission is hereby granted, free of charge, to any person obtaining
|
70
72
|
a copy of this software and associated documentation files (the
|
@@ -8,6 +8,7 @@ module RipperRubyParser
|
|
8
8
|
# Variant of Ripper's SexpBuilder parser class that inserts comments as
|
9
9
|
# Sexps into the built parse tree.
|
10
10
|
#
|
11
|
+
# rubocop: disable Metrics/ClassLength
|
11
12
|
# @api private
|
12
13
|
class CommentingRipperParser < Ripper::SexpBuilder
|
13
14
|
def initialize(*args)
|
@@ -35,7 +36,16 @@ module RipperRubyParser
|
|
35
36
|
end
|
36
37
|
|
37
38
|
def on_begin(*args)
|
38
|
-
|
39
|
+
result = super
|
40
|
+
|
41
|
+
# Some begin blocks are not created by the 'begin' keyword. Skip
|
42
|
+
# commenting for those kinds of blocks.
|
43
|
+
(_, kw,), = @comment_stack.last
|
44
|
+
if kw == "begin"
|
45
|
+
commentize("begin", result)
|
46
|
+
else
|
47
|
+
result
|
48
|
+
end
|
39
49
|
end
|
40
50
|
|
41
51
|
def on_void_stmt
|
@@ -72,23 +82,25 @@ module RipperRubyParser
|
|
72
82
|
end
|
73
83
|
|
74
84
|
def on_module(*args)
|
75
|
-
commentize(
|
85
|
+
commentize("module", super)
|
76
86
|
end
|
77
87
|
|
78
88
|
def on_class(*args)
|
79
|
-
commentize(
|
89
|
+
commentize("class", super)
|
80
90
|
end
|
81
91
|
|
82
92
|
def on_sclass(*args)
|
83
|
-
commentize(
|
93
|
+
commentize("class", super)
|
84
94
|
end
|
85
95
|
|
86
|
-
def on_def(*args)
|
87
|
-
|
96
|
+
def on_def(name, *args)
|
97
|
+
(_, _, loc) = name
|
98
|
+
commentize("def", super, loc)
|
88
99
|
end
|
89
100
|
|
90
|
-
def on_defs(*
|
91
|
-
|
101
|
+
def on_defs(receiver, period, name, *rest)
|
102
|
+
(_, _, loc) = name
|
103
|
+
commentize("def", super, loc)
|
92
104
|
end
|
93
105
|
|
94
106
|
def on_args_new
|
@@ -254,6 +266,11 @@ module RipperRubyParser
|
|
254
266
|
@seen_space = true
|
255
267
|
end
|
256
268
|
|
269
|
+
def on_imaginary(_token)
|
270
|
+
@space_before = @seen_space
|
271
|
+
super
|
272
|
+
end
|
273
|
+
|
257
274
|
def on_int(_token)
|
258
275
|
@space_before = @seen_space
|
259
276
|
super
|
@@ -264,7 +281,12 @@ module RipperRubyParser
|
|
264
281
|
super
|
265
282
|
end
|
266
283
|
|
267
|
-
|
284
|
+
def on_rational(_token)
|
285
|
+
@space_before = @seen_space
|
286
|
+
super
|
287
|
+
end
|
288
|
+
|
289
|
+
NUMBER_LITERAL_TYPES = [:@imaginary, :@int, :@float, :@rational].freeze
|
268
290
|
|
269
291
|
def on_unary(operator, value)
|
270
292
|
if !@space_before && operator == :-@ && NUMBER_LITERAL_TYPES.include?(value.first)
|
@@ -300,15 +322,16 @@ module RipperRubyParser
|
|
300
322
|
end
|
301
323
|
|
302
324
|
def on_BEGIN(*args)
|
303
|
-
commentize(
|
325
|
+
commentize("BEGIN", super)
|
304
326
|
end
|
305
327
|
|
306
328
|
def on_END(*args)
|
307
|
-
commentize(
|
329
|
+
commentize("END", super)
|
308
330
|
end
|
309
331
|
|
310
332
|
def on_parse_error(message)
|
311
|
-
|
333
|
+
super
|
334
|
+
raise SyntaxError, message if message.start_with?("syntax error,")
|
312
335
|
end
|
313
336
|
|
314
337
|
def on_class_name_error(message, *)
|
@@ -327,11 +350,19 @@ module RipperRubyParser
|
|
327
350
|
raise SyntaxError, message
|
328
351
|
end
|
329
352
|
|
330
|
-
def commentize(
|
331
|
-
|
353
|
+
def commentize(name, exp, target_loc = nil)
|
354
|
+
if target_loc
|
355
|
+
(_, kw, loc), comment = @comment_stack.pop until (loc <=> target_loc) == -1
|
356
|
+
else
|
357
|
+
(_, kw, loc), comment = @comment_stack.pop
|
358
|
+
end
|
359
|
+
|
360
|
+
warn "Comment stack mismatch: expected #{kw} to equal #{name}" unless kw == name
|
361
|
+
|
332
362
|
@comment = ""
|
333
363
|
exp.push loc
|
334
364
|
[:comment, comment, exp]
|
335
365
|
end
|
336
366
|
end
|
367
|
+
# rubocop: enable Metrics/ClassLength
|
337
368
|
end
|
@@ -95,50 +95,74 @@ module RipperRubyParser
|
|
95
95
|
def process_opassign(exp)
|
96
96
|
_, lvalue, (_, operator,), value = exp.shift 4
|
97
97
|
|
98
|
+
value_type = value.sexp_type
|
99
|
+
|
98
100
|
lvalue = process(lvalue)
|
99
101
|
value = process(value)
|
100
102
|
operator = operator.chop.to_sym
|
101
103
|
|
102
|
-
|
104
|
+
case lvalue.sexp_type
|
105
|
+
when :aref_field
|
106
|
+
create_aref_operator_assignment_sub_type(lvalue, value, operator)
|
107
|
+
when :field
|
108
|
+
create_field_operator_assignment_sub_type(lvalue, value, operator, value_type)
|
109
|
+
else
|
110
|
+
create_regular_operator_assignment_sub_type(lvalue, value, operator)
|
111
|
+
end
|
103
112
|
end
|
104
113
|
|
105
114
|
private
|
106
115
|
|
107
116
|
def create_multiple_assignment_sub_types(sexp_list)
|
108
117
|
sexp_list.map! do |item|
|
109
|
-
|
118
|
+
create_valueless_regular_assignment_sub_type item
|
110
119
|
end
|
111
120
|
end
|
112
121
|
|
113
|
-
def
|
122
|
+
def create_valueless_regular_assignment_sub_type(item)
|
114
123
|
item = with_line_number(item.line,
|
115
124
|
create_regular_assignment_sub_type(item, nil))
|
116
125
|
item.pop
|
117
126
|
item
|
118
127
|
end
|
119
128
|
|
129
|
+
def create_valueless_assignment_sub_type(item)
|
130
|
+
item = with_line_number(item.line,
|
131
|
+
create_assignment_sub_type(item, nil))
|
132
|
+
item.pop
|
133
|
+
item
|
134
|
+
end
|
135
|
+
|
136
|
+
def create_aref_operator_assignment_sub_type(lvalue, value, operator)
|
137
|
+
_, arr, arglist = lvalue
|
138
|
+
arglist.sexp_type = :arglist
|
139
|
+
s(:op_asgn1, arr, arglist, operator, value)
|
140
|
+
end
|
141
|
+
|
142
|
+
def create_field_operator_assignment_sub_type(lvalue, value, operator, value_type)
|
143
|
+
# Structure of lvalue will be something like this:
|
144
|
+
# s(:field, receiver, s(:period, "."), s(:lvar, field))
|
145
|
+
_, receiver, _, (_, field) = lvalue
|
146
|
+
case value_type
|
147
|
+
when :command, :command_call
|
148
|
+
s(:op_asgn, receiver, value, field, operator)
|
149
|
+
else
|
150
|
+
s(:op_asgn2, receiver, :"#{field}=", operator, value)
|
151
|
+
end
|
152
|
+
end
|
153
|
+
|
120
154
|
OPERATOR_ASSIGNMENT_MAP = {
|
121
155
|
"||": :op_asgn_or,
|
122
156
|
"&&": :op_asgn_and
|
123
157
|
}.freeze
|
124
158
|
|
125
|
-
def
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
arglist.sexp_type = :arglist
|
130
|
-
s(:op_asgn1, arr, arglist, operator, value)
|
131
|
-
when :field
|
132
|
-
_, obj, _, (_, field) = lvalue
|
133
|
-
s(:op_asgn2, obj, :"#{field}=", operator, value)
|
159
|
+
def create_regular_operator_assignment_sub_type(lvalue, value, operator)
|
160
|
+
value = unwrap_begin(value)
|
161
|
+
if (mapped = OPERATOR_ASSIGNMENT_MAP[operator])
|
162
|
+
s(mapped, lvalue, create_assignment_sub_type(lvalue, value))
|
134
163
|
else
|
135
|
-
|
136
|
-
|
137
|
-
s(mapped, lvalue, create_assignment_sub_type(lvalue, value))
|
138
|
-
else
|
139
|
-
operator_call = s(:call, lvalue, operator, value)
|
140
|
-
create_assignment_sub_type lvalue, operator_call
|
141
|
-
end
|
164
|
+
operator_call = s(:call, lvalue, operator, value)
|
165
|
+
create_assignment_sub_type lvalue, operator_call
|
142
166
|
end
|
143
167
|
end
|
144
168
|
|
@@ -10,7 +10,7 @@ module RipperRubyParser
|
|
10
10
|
call = process(call)
|
11
11
|
args = process(args)
|
12
12
|
kwrest = kwrest_param(args) if args
|
13
|
-
stmt =
|
13
|
+
stmt = with_new_lvar_scope(kwrest) { process(stmt) }
|
14
14
|
make_iter call, args, safe_unwrap_void_stmt(stmt)
|
15
15
|
end
|
16
16
|
|
@@ -153,16 +153,13 @@ module RipperRubyParser
|
|
153
153
|
|
154
154
|
defaults.map do |sym, val|
|
155
155
|
s(:lasgn,
|
156
|
-
|
156
|
+
make_symbol(process(sym)),
|
157
157
|
process(val))
|
158
158
|
end
|
159
159
|
end
|
160
160
|
|
161
161
|
def handle_splat(splat)
|
162
|
-
if splat
|
163
|
-
# Only relevant for Ruby < 2.6
|
164
|
-
[s(:excessed_comma)]
|
165
|
-
elsif splat
|
162
|
+
if splat
|
166
163
|
[process(splat)]
|
167
164
|
else
|
168
165
|
[]
|
@@ -173,7 +170,7 @@ module RipperRubyParser
|
|
173
170
|
return [] unless kwargs
|
174
171
|
|
175
172
|
kwargs.map do |sym, val|
|
176
|
-
symbol =
|
173
|
+
symbol = make_symbol process(sym)
|
177
174
|
if val
|
178
175
|
s(:kwarg, symbol, process(val))
|
179
176
|
else
|
@@ -217,15 +214,25 @@ module RipperRubyParser
|
|
217
214
|
end
|
218
215
|
end
|
219
216
|
|
217
|
+
LVAR_MATCHER = Sexp::Matcher.new(:lvar, Sexp._)
|
218
|
+
NUMBERED_PARAMS = (1..9).map { |it| :"_#{it}" }.freeze
|
219
|
+
|
220
220
|
def make_iter(call, args, stmt)
|
221
221
|
args[-1] = nil if args && args.last == s(:excessed_comma)
|
222
|
-
|
222
|
+
|
223
|
+
args ||= count_numbered_lvars(stmt)
|
224
|
+
|
223
225
|
if stmt.empty?
|
224
226
|
s(:iter, call, args)
|
225
227
|
else
|
226
228
|
s(:iter, call, args, stmt)
|
227
229
|
end
|
228
230
|
end
|
231
|
+
|
232
|
+
def count_numbered_lvars(stmt)
|
233
|
+
lvar_names = (LVAR_MATCHER / stmt).map { |it| it[1] }
|
234
|
+
(NUMBERED_PARAMS & lvar_names).length
|
235
|
+
end
|
229
236
|
end
|
230
237
|
end
|
231
238
|
end
|
@@ -64,11 +64,78 @@ module RipperRubyParser
|
|
64
64
|
*falsepart)
|
65
65
|
end
|
66
66
|
|
67
|
+
def process_in(exp)
|
68
|
+
_, pattern, truepart, falsepart = exp.shift 4
|
69
|
+
|
70
|
+
falsepart = process(falsepart)
|
71
|
+
falsepart = if falsepart.nil?
|
72
|
+
[nil]
|
73
|
+
else
|
74
|
+
falsepart.sexp_body
|
75
|
+
end
|
76
|
+
pattern = process(pattern)
|
77
|
+
adjust_rightward_assignment_pattern(pattern)
|
78
|
+
|
79
|
+
truepart = process(truepart)
|
80
|
+
truepart = unwrap_nil(truepart) if truepart
|
81
|
+
|
82
|
+
s(:case_body,
|
83
|
+
s(:in, pattern, truepart),
|
84
|
+
*falsepart)
|
85
|
+
end
|
86
|
+
|
67
87
|
def process_else(exp)
|
68
88
|
_, body = exp.shift 2
|
69
89
|
process(body)
|
70
90
|
end
|
71
91
|
|
92
|
+
def process_aryptn(exp)
|
93
|
+
_, _, body, rest, = exp.shift 5
|
94
|
+
|
95
|
+
elements = body.map do |elem|
|
96
|
+
if elem.sexp_type == :var_field
|
97
|
+
create_valueless_assignment_sub_type process(elem)
|
98
|
+
else
|
99
|
+
unwrap_begin process(elem)
|
100
|
+
end
|
101
|
+
end
|
102
|
+
if rest
|
103
|
+
rest_var = handle_pattern(rest)
|
104
|
+
elements << convert_marked_argument(s(:splat, rest_var))
|
105
|
+
end
|
106
|
+
s(:array_pat, nil, *elements)
|
107
|
+
end
|
108
|
+
|
109
|
+
def process_hshptn(exp)
|
110
|
+
_, _, body, = exp.shift 4
|
111
|
+
|
112
|
+
elements = body.flat_map do |key, value|
|
113
|
+
if value
|
114
|
+
[process(key), process(value)]
|
115
|
+
else
|
116
|
+
[handle_pattern(key), nil]
|
117
|
+
end
|
118
|
+
end
|
119
|
+
s(:hash_pat, nil, *elements)
|
120
|
+
end
|
121
|
+
|
122
|
+
def process_fndptn(exp)
|
123
|
+
_, wrapper, before, patterns, after = exp.shift 5
|
124
|
+
|
125
|
+
wrapper = process(wrapper)
|
126
|
+
before = make_splat process(before)
|
127
|
+
after = make_splat process(after)
|
128
|
+
patterns = patterns.map do |elem|
|
129
|
+
if elem.sexp_type == :var_field
|
130
|
+
create_valueless_assignment_sub_type process(elem)
|
131
|
+
else
|
132
|
+
unwrap_begin process(elem)
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
136
|
+
s(:find_pat, wrapper, before, *patterns, after)
|
137
|
+
end
|
138
|
+
|
72
139
|
private
|
73
140
|
|
74
141
|
def handle_condition(cond)
|
@@ -88,6 +155,24 @@ module RipperRubyParser
|
|
88
155
|
unwrap_nil process(exp) if exp
|
89
156
|
end
|
90
157
|
|
158
|
+
def handle_pattern(exp)
|
159
|
+
pattern = process(exp)
|
160
|
+
case pattern.sexp_type
|
161
|
+
when :lvar, :lit
|
162
|
+
@local_variables << pattern[1]
|
163
|
+
end
|
164
|
+
pattern
|
165
|
+
end
|
166
|
+
|
167
|
+
def adjust_rightward_assignment_pattern(exp)
|
168
|
+
case exp.sexp_type
|
169
|
+
when :lvar
|
170
|
+
exp.sexp_type = :lasgn
|
171
|
+
when :lasgn
|
172
|
+
adjust_rightward_assignment_pattern(exp.sexp_body.last)
|
173
|
+
end
|
174
|
+
end
|
175
|
+
|
91
176
|
def construct_conditional(cond, truepart, falsepart)
|
92
177
|
if cond.sexp_type == :not
|
93
178
|
_, inner = cond
|
@@ -107,6 +192,10 @@ module RipperRubyParser
|
|
107
192
|
[exp]
|
108
193
|
end
|
109
194
|
end
|
195
|
+
|
196
|
+
def make_splat(exp)
|
197
|
+
:"*#{exp[1]}"
|
198
|
+
end
|
110
199
|
end
|
111
200
|
end
|
112
201
|
end
|
@@ -4,12 +4,17 @@ module RipperRubyParser
|
|
4
4
|
module SexpHandlers
|
5
5
|
# Utility methods used in several of the sexp handler modules
|
6
6
|
module HelperMethods
|
7
|
+
def extract_node_symbol(exp)
|
8
|
+
ident, = extract_node_symbol_with_position(exp)
|
9
|
+
ident
|
10
|
+
end
|
11
|
+
|
7
12
|
def extract_node_symbol_with_position(exp)
|
8
13
|
_, ident, pos = exp.shift 3
|
9
14
|
return ident.to_sym, pos
|
10
15
|
end
|
11
16
|
|
12
|
-
def
|
17
|
+
def make_symbol(exp)
|
13
18
|
return nil if exp.nil?
|
14
19
|
raise "Unexpected number of children: #{exp.length}" if exp.length != 2
|
15
20
|
|
@@ -36,7 +41,11 @@ module RipperRubyParser
|
|
36
41
|
def generic_add_star(exp)
|
37
42
|
_, args, splatarg, *rest = shift_all exp
|
38
43
|
items = process args
|
39
|
-
|
44
|
+
if splatarg
|
45
|
+
items.push s(:splat, unwrap_begin(process(splatarg)))
|
46
|
+
else
|
47
|
+
items.push s(:splat)
|
48
|
+
end
|
40
49
|
items.push(*map_process_list(rest))
|
41
50
|
end
|
42
51
|
|
@@ -36,7 +36,11 @@ module RipperRubyParser
|
|
36
36
|
# s(:assoc_splat, s(:vcall, s(:@ident, "bar")))
|
37
37
|
def process_assoc_splat(exp)
|
38
38
|
_, param = exp.shift 2
|
39
|
-
|
39
|
+
if param
|
40
|
+
s(:kwsplat, process(param))
|
41
|
+
else
|
42
|
+
s(:kwsplat)
|
43
|
+
end
|
40
44
|
end
|
41
45
|
|
42
46
|
# number literals
|
@@ -7,12 +7,12 @@ module RipperRubyParser
|
|
7
7
|
def process_def(exp)
|
8
8
|
_, ident, params, body, pos = exp.shift 5
|
9
9
|
|
10
|
-
ident
|
10
|
+
ident = extract_node_symbol ident
|
11
11
|
|
12
12
|
in_method do
|
13
13
|
params = convert_arguments(process(params))
|
14
14
|
kwrest = kwrest_param(params)
|
15
|
-
body =
|
15
|
+
body = with_new_lvar_scope(kwrest) { method_body(body) }
|
16
16
|
end
|
17
17
|
|
18
18
|
with_position(pos, s(:defn, ident, params, *body))
|
@@ -21,12 +21,12 @@ module RipperRubyParser
|
|
21
21
|
def process_defs(exp)
|
22
22
|
_, receiver, _, ident, params, body, = exp.shift 7
|
23
23
|
|
24
|
-
ident
|
24
|
+
ident = extract_node_symbol ident
|
25
25
|
|
26
26
|
in_method do
|
27
27
|
params = convert_arguments(process(params))
|
28
28
|
kwrest = kwrest_param(params)
|
29
|
-
body =
|
29
|
+
body = with_new_lvar_scope(kwrest) { method_body(body) }
|
30
30
|
end
|
31
31
|
|
32
32
|
s(:defs, process(receiver), ident, params, *body)
|
@@ -103,6 +103,8 @@ module RipperRubyParser
|
|
103
103
|
}.freeze
|
104
104
|
|
105
105
|
def convert_arguments(args)
|
106
|
+
return s(:args) if args.nil?
|
107
|
+
|
106
108
|
args.line ||= args.sexp_body.first&.line
|
107
109
|
args.sexp_body = args.sexp_body.map { |item| convert_argument item }
|
108
110
|
args
|
@@ -123,7 +125,7 @@ module RipperRubyParser
|
|
123
125
|
|
124
126
|
def convert_marked_argument(item)
|
125
127
|
marker = SPECIAL_ARG_MARKER[item.sexp_type]
|
126
|
-
name =
|
128
|
+
name = make_symbol item.last
|
127
129
|
:"#{marker}#{name}"
|
128
130
|
end
|
129
131
|
|
@@ -151,15 +153,16 @@ module RipperRubyParser
|
|
151
153
|
Regexp.last_match[1].to_sym if found
|
152
154
|
end
|
153
155
|
|
154
|
-
def
|
155
|
-
@
|
156
|
+
def with_new_lvar_scope(extra_variable)
|
157
|
+
old_lvars = @local_variables.dup
|
158
|
+
@local_variables.push extra_variable if extra_variable
|
156
159
|
result = yield
|
157
|
-
@
|
160
|
+
@local_variables = old_lvars
|
158
161
|
result
|
159
162
|
end
|
160
163
|
|
161
164
|
def kwrest_arg?(method)
|
162
|
-
@
|
165
|
+
@local_variables.include?(method)
|
163
166
|
end
|
164
167
|
end
|
165
168
|
end
|
@@ -11,27 +11,28 @@ module RipperRubyParser
|
|
11
11
|
or: :or
|
12
12
|
}.freeze
|
13
13
|
|
14
|
+
BINARY_LOGICAL_OPERATORS = BINARY_OPERATOR_MAP.keys.freeze
|
15
|
+
|
14
16
|
UNARY_OPERATOR_MAP = {
|
15
17
|
not: :!
|
16
18
|
}.freeze
|
17
19
|
|
18
|
-
NEGATED_BINARY_OPERATOR_MAP = {
|
19
|
-
"!~": :=~
|
20
|
-
}.freeze
|
21
|
-
|
22
20
|
SHIFT_OPERATORS = [:<<, :>>].freeze
|
23
21
|
|
24
22
|
def process_binary(exp)
|
25
23
|
_, left, op, right = exp.shift 4
|
26
24
|
|
27
|
-
|
25
|
+
case op
|
26
|
+
when :=~
|
28
27
|
make_regexp_match_operator(left, op, right)
|
29
|
-
|
30
|
-
s(:not, make_regexp_match_operator(left,
|
31
|
-
|
32
|
-
make_boolean_operator(left,
|
33
|
-
|
28
|
+
when :!~
|
29
|
+
s(:not, make_regexp_match_operator(left, :=~, right))
|
30
|
+
when *BINARY_LOGICAL_OPERATORS
|
31
|
+
make_boolean_operator(left, op, right)
|
32
|
+
when *SHIFT_OPERATORS
|
34
33
|
s(:call, unwrap_begin(process(left)), op, unwrap_begin(process(right)))
|
34
|
+
when :"=>"
|
35
|
+
make_rightward_assignment(left, right)
|
35
36
|
else
|
36
37
|
s(:call, process(left), op, process(right))
|
37
38
|
end
|
@@ -77,20 +78,33 @@ module RipperRubyParser
|
|
77
78
|
private
|
78
79
|
|
79
80
|
def make_boolean_operator(left, operator, right)
|
81
|
+
operator = BINARY_OPERATOR_MAP[operator]
|
80
82
|
_, left, _, right = rebalance_binary(left, operator, right)
|
81
83
|
s(operator, unwrap_begin(process(left)), process(right))
|
82
84
|
end
|
83
85
|
|
84
86
|
def make_regexp_match_operator(left, operator, right)
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
87
|
+
left = process(left)
|
88
|
+
right = process(right)
|
89
|
+
|
90
|
+
if regexp? left
|
91
|
+
s(:match2, left, right)
|
92
|
+
elsif regexp? right
|
93
|
+
s(:match3, right, left)
|
89
94
|
else
|
90
|
-
s(:call,
|
95
|
+
s(:call, left, operator, right)
|
91
96
|
end
|
92
97
|
end
|
93
98
|
|
99
|
+
def regexp?(exp)
|
100
|
+
exp.sexp_type == :dregx ||
|
101
|
+
exp.sexp_type == :lit && exp.sexp_body.first.is_a?(Regexp)
|
102
|
+
end
|
103
|
+
|
104
|
+
def make_rightward_assignment(left, right)
|
105
|
+
s(:lasgn, process(right)[1], process(left))
|
106
|
+
end
|
107
|
+
|
94
108
|
def rebalance_binary(left, operator, right)
|
95
109
|
if BINARY_OPERATOR_MAP[operator] == BINARY_OPERATOR_MAP[left[2]]
|
96
110
|
_, left, _, middle = rebalance_binary(*left.sexp_body)
|
@@ -83,7 +83,7 @@ module RipperRubyParser
|
|
83
83
|
return with_line_number(content.line, s(:lit, Regexp.new(content.last, numflags)))
|
84
84
|
end
|
85
85
|
|
86
|
-
content.sexp_type = :dregx_once if
|
86
|
+
content.sexp_type = :dregx_once if flags.include?("o")
|
87
87
|
content << numflags unless numflags == 0
|
88
88
|
content
|
89
89
|
end
|
@@ -123,7 +123,7 @@ module RipperRubyParser
|
|
123
123
|
|
124
124
|
def process_at_tstring_content(exp)
|
125
125
|
_, content, pos, delim = exp.shift 4
|
126
|
-
string =
|
126
|
+
string = handle_string_unescaping(content, delim)
|
127
127
|
with_position(pos, s(:str, string))
|
128
128
|
end
|
129
129
|
|
@@ -180,11 +180,11 @@ module RipperRubyParser
|
|
180
180
|
def character_flags_to_numerical(flags)
|
181
181
|
numflags = 0
|
182
182
|
|
183
|
-
numflags = Regexp::MULTILINE if
|
184
|
-
numflags |= Regexp::EXTENDED if
|
185
|
-
numflags |= Regexp::IGNORECASE if
|
183
|
+
numflags = Regexp::MULTILINE if flags.include?("m")
|
184
|
+
numflags |= Regexp::EXTENDED if flags.include?("x")
|
185
|
+
numflags |= Regexp::IGNORECASE if flags.include?("i")
|
186
186
|
|
187
|
-
numflags |= Regexp::NOENCODING if
|
187
|
+
numflags |= Regexp::NOENCODING if flags.include?("n")
|
188
188
|
numflags |= Regexp::FIXEDENCODING if /[ues]/.match?(flags)
|
189
189
|
|
190
190
|
numflags
|
@@ -227,22 +227,23 @@ module RipperRubyParser
|
|
227
227
|
end
|
228
228
|
end
|
229
229
|
|
230
|
-
INTERPOLATING_HEREDOC = /^<<[-~]?[^-~']
|
231
|
-
NON_INTERPOLATING_HEREDOC = /^<<[-~]?'
|
232
|
-
INTERPOLATING_STRINGS = ['"', "`",
|
230
|
+
INTERPOLATING_HEREDOC = /^<<[-~]?[^-~']/
|
231
|
+
NON_INTERPOLATING_HEREDOC = /^<<[-~]?'/
|
232
|
+
INTERPOLATING_STRINGS = ['"', "`", /^%Q.$/, /^%.$/].freeze
|
233
|
+
INTERPOLATING_DSYM = ':"'
|
233
234
|
NON_INTERPOLATING_STRINGS = ["'", ":'", /^%q.$/].freeze
|
234
|
-
INTERPOLATING_WORD_LIST = /^%[WI]
|
235
|
-
NON_INTERPOLATING_WORD_LIST = /^%[wi]
|
235
|
+
INTERPOLATING_WORD_LIST = /^%[WI].$/
|
236
|
+
NON_INTERPOLATING_WORD_LIST = /^%[wi].$/
|
236
237
|
REGEXP_LITERALS = ["/", /^%r.$/].freeze
|
237
238
|
|
238
239
|
def handle_string_unescaping(content, delim)
|
239
240
|
case delim
|
240
|
-
when INTERPOLATING_HEREDOC, *INTERPOLATING_STRINGS
|
241
|
+
when INTERPOLATING_HEREDOC, INTERPOLATING_DSYM, *INTERPOLATING_STRINGS
|
241
242
|
unescape(content)
|
242
243
|
when INTERPOLATING_WORD_LIST
|
243
|
-
unescape_wordlist_word(content)
|
244
|
+
fix_encoding unescape_wordlist_word(content)
|
244
245
|
when *NON_INTERPOLATING_STRINGS
|
245
|
-
simple_unescape(content, delim)
|
246
|
+
fix_encoding simple_unescape(content, delim)
|
246
247
|
when *REGEXP_LITERALS
|
247
248
|
unescape_regexp(content)
|
248
249
|
when NON_INTERPOLATING_WORD_LIST
|
@@ -17,9 +17,7 @@ module RipperRubyParser
|
|
17
17
|
super()
|
18
18
|
|
19
19
|
public_methods.each do |name|
|
20
|
-
if name =~ /^process_at_(.*)/
|
21
|
-
@processors["@#{Regexp.last_match(1)}".to_sym] = name.to_sym
|
22
|
-
end
|
20
|
+
@processors[:"@#{Regexp.last_match(1)}"] = name.to_sym if name =~ /^process_at_(.*)/
|
23
21
|
end
|
24
22
|
|
25
23
|
@filename = filename
|
@@ -28,8 +26,7 @@ module RipperRubyParser
|
|
28
26
|
@errors = []
|
29
27
|
|
30
28
|
@in_method_body = false
|
31
|
-
@
|
32
|
-
@block_kwrest = []
|
29
|
+
@local_variables = []
|
33
30
|
|
34
31
|
@kept_comment = nil
|
35
32
|
end
|
@@ -77,7 +74,7 @@ module RipperRubyParser
|
|
77
74
|
|
78
75
|
def process_var_field(exp)
|
79
76
|
_, contents = exp.shift 2
|
80
|
-
process(contents)
|
77
|
+
process(contents) || s(:lvar, nil)
|
81
78
|
end
|
82
79
|
|
83
80
|
def process_var_alias(exp)
|
@@ -92,7 +89,7 @@ module RipperRubyParser
|
|
92
89
|
|
93
90
|
def process_const_path_ref(exp)
|
94
91
|
_, left, right = exp.shift 3
|
95
|
-
s(:colon2, process(left),
|
92
|
+
s(:colon2, process(left), make_symbol(process(right)))
|
96
93
|
end
|
97
94
|
|
98
95
|
def process_const_path_field(exp)
|
@@ -106,7 +103,7 @@ module RipperRubyParser
|
|
106
103
|
|
107
104
|
def process_top_const_ref(exp)
|
108
105
|
_, ref = exp.shift 2
|
109
|
-
s(:colon3,
|
106
|
+
s(:colon3, make_symbol(process(ref)))
|
110
107
|
end
|
111
108
|
|
112
109
|
def process_top_const_field(exp)
|
@@ -20,7 +20,7 @@ module RipperRubyParser
|
|
20
20
|
M-. | # meta
|
21
21
|
\n | # line break
|
22
22
|
. # other single character
|
23
|
-
)/x
|
23
|
+
)/x
|
24
24
|
|
25
25
|
SINGLE_LETTER_ESCAPES = {
|
26
26
|
"a" => "\a",
|
@@ -74,7 +74,7 @@ module RipperRubyParser
|
|
74
74
|
def unescape(string)
|
75
75
|
string = string.dup if string.frozen?
|
76
76
|
string.force_encoding("ASCII-8BIT")
|
77
|
-
string.gsub(ESCAPE_SEQUENCE_REGEXP) do
|
77
|
+
result = string.gsub(ESCAPE_SEQUENCE_REGEXP) do
|
78
78
|
bare = Regexp.last_match[1]
|
79
79
|
if bare == "\n"
|
80
80
|
""
|
@@ -82,6 +82,7 @@ module RipperRubyParser
|
|
82
82
|
unescaped_value(bare).force_encoding("ASCII-8BIT")
|
83
83
|
end
|
84
84
|
end
|
85
|
+
fix_encoding result
|
85
86
|
end
|
86
87
|
|
87
88
|
def unescape_wordlist_word(string)
|
@@ -169,6 +170,9 @@ module RipperRubyParser
|
|
169
170
|
end
|
170
171
|
|
171
172
|
def control(val)
|
173
|
+
# Special case the \C-? or DEL sequence
|
174
|
+
return 127 if val == 63
|
175
|
+
|
172
176
|
val & 0b1001_1111
|
173
177
|
end
|
174
178
|
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ripper_ruby_parser
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.11.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Matijs van Zuijlen
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2024-01-05 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: sexp_processor
|
@@ -106,70 +106,70 @@ dependencies:
|
|
106
106
|
requirements:
|
107
107
|
- - "~>"
|
108
108
|
- !ruby/object:Gem::Version
|
109
|
-
version: '1.
|
109
|
+
version: '1.56'
|
110
110
|
type: :development
|
111
111
|
prerelease: false
|
112
112
|
version_requirements: !ruby/object:Gem::Requirement
|
113
113
|
requirements:
|
114
114
|
- - "~>"
|
115
115
|
- !ruby/object:Gem::Version
|
116
|
-
version: '1.
|
116
|
+
version: '1.56'
|
117
117
|
- !ruby/object:Gem::Dependency
|
118
118
|
name: rubocop-minitest
|
119
119
|
requirement: !ruby/object:Gem::Requirement
|
120
120
|
requirements:
|
121
121
|
- - "~>"
|
122
122
|
- !ruby/object:Gem::Version
|
123
|
-
version: 0.
|
123
|
+
version: 0.34.1
|
124
124
|
type: :development
|
125
125
|
prerelease: false
|
126
126
|
version_requirements: !ruby/object:Gem::Requirement
|
127
127
|
requirements:
|
128
128
|
- - "~>"
|
129
129
|
- !ruby/object:Gem::Version
|
130
|
-
version: 0.
|
130
|
+
version: 0.34.1
|
131
131
|
- !ruby/object:Gem::Dependency
|
132
132
|
name: rubocop-packaging
|
133
133
|
requirement: !ruby/object:Gem::Requirement
|
134
134
|
requirements:
|
135
135
|
- - "~>"
|
136
136
|
- !ruby/object:Gem::Version
|
137
|
-
version: 0.5.
|
137
|
+
version: 0.5.2
|
138
138
|
type: :development
|
139
139
|
prerelease: false
|
140
140
|
version_requirements: !ruby/object:Gem::Requirement
|
141
141
|
requirements:
|
142
142
|
- - "~>"
|
143
143
|
- !ruby/object:Gem::Version
|
144
|
-
version: 0.5.
|
144
|
+
version: 0.5.2
|
145
145
|
- !ruby/object:Gem::Dependency
|
146
146
|
name: rubocop-performance
|
147
147
|
requirement: !ruby/object:Gem::Requirement
|
148
148
|
requirements:
|
149
149
|
- - "~>"
|
150
150
|
- !ruby/object:Gem::Version
|
151
|
-
version: '1.
|
151
|
+
version: '1.19'
|
152
152
|
type: :development
|
153
153
|
prerelease: false
|
154
154
|
version_requirements: !ruby/object:Gem::Requirement
|
155
155
|
requirements:
|
156
156
|
- - "~>"
|
157
157
|
- !ruby/object:Gem::Version
|
158
|
-
version: '1.
|
158
|
+
version: '1.19'
|
159
159
|
- !ruby/object:Gem::Dependency
|
160
160
|
name: ruby_parser
|
161
161
|
requirement: !ruby/object:Gem::Requirement
|
162
162
|
requirements:
|
163
163
|
- - "~>"
|
164
164
|
- !ruby/object:Gem::Version
|
165
|
-
version:
|
165
|
+
version: 3.20.2
|
166
166
|
type: :development
|
167
167
|
prerelease: false
|
168
168
|
version_requirements: !ruby/object:Gem::Requirement
|
169
169
|
requirements:
|
170
170
|
- - "~>"
|
171
171
|
- !ruby/object:Gem::Version
|
172
|
-
version:
|
172
|
+
version: 3.20.2
|
173
173
|
- !ruby/object:Gem::Dependency
|
174
174
|
name: sexp_processor
|
175
175
|
requirement: !ruby/object:Gem::Requirement
|
@@ -190,14 +190,14 @@ dependencies:
|
|
190
190
|
requirements:
|
191
191
|
- - "~>"
|
192
192
|
- !ruby/object:Gem::Version
|
193
|
-
version: 0.
|
193
|
+
version: 0.22.0
|
194
194
|
type: :development
|
195
195
|
prerelease: false
|
196
196
|
version_requirements: !ruby/object:Gem::Requirement
|
197
197
|
requirements:
|
198
198
|
- - "~>"
|
199
199
|
- !ruby/object:Gem::Version
|
200
|
-
version: 0.
|
200
|
+
version: 0.22.0
|
201
201
|
description: |
|
202
202
|
RipperRubyParser is a parser for Ruby based on Ripper that aims to be a
|
203
203
|
drop-in replacement for RubyParser.
|
@@ -246,14 +246,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
246
246
|
requirements:
|
247
247
|
- - ">="
|
248
248
|
- !ruby/object:Gem::Version
|
249
|
-
version:
|
249
|
+
version: 3.0.0
|
250
250
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
251
251
|
requirements:
|
252
252
|
- - ">="
|
253
253
|
- !ruby/object:Gem::Version
|
254
254
|
version: '0'
|
255
255
|
requirements: []
|
256
|
-
rubygems_version: 3.
|
256
|
+
rubygems_version: 3.5.3
|
257
257
|
signing_key:
|
258
258
|
specification_version: 4
|
259
259
|
summary: Parse with Ripper, produce sexps that are compatible with RubyParser.
|