ripper_ruby_parser 1.4.2 → 1.5.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.
Files changed (51) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +33 -1
  3. data/README.md +41 -9
  4. data/Rakefile +2 -0
  5. data/lib/ripper_ruby_parser.rb +2 -0
  6. data/lib/ripper_ruby_parser/commenting_ripper_parser.rb +23 -45
  7. data/lib/ripper_ruby_parser/parser.rb +11 -1
  8. data/lib/ripper_ruby_parser/sexp_handlers.rb +2 -6
  9. data/lib/ripper_ruby_parser/sexp_handlers/assignment.rb +49 -35
  10. data/lib/ripper_ruby_parser/sexp_handlers/blocks.rb +78 -39
  11. data/lib/ripper_ruby_parser/sexp_handlers/conditionals.rb +16 -15
  12. data/lib/ripper_ruby_parser/sexp_handlers/helper_methods.rb +19 -15
  13. data/lib/ripper_ruby_parser/sexp_handlers/literals.rb +138 -30
  14. data/lib/ripper_ruby_parser/sexp_handlers/loops.rb +10 -6
  15. data/lib/ripper_ruby_parser/sexp_handlers/method_calls.rb +59 -14
  16. data/lib/ripper_ruby_parser/sexp_handlers/methods.rb +56 -32
  17. data/lib/ripper_ruby_parser/sexp_handlers/operators.rb +20 -27
  18. data/lib/ripper_ruby_parser/sexp_processor.rb +40 -10
  19. data/lib/ripper_ruby_parser/syntax_error.rb +2 -0
  20. data/lib/ripper_ruby_parser/unescape.rb +32 -11
  21. data/lib/ripper_ruby_parser/version.rb +3 -1
  22. data/test/end_to_end/comments_test.rb +2 -0
  23. data/test/end_to_end/comparison_test.rb +2 -0
  24. data/test/end_to_end/lib_comparison_test.rb +2 -0
  25. data/test/end_to_end/line_numbering_test.rb +2 -0
  26. data/test/end_to_end/samples_comparison_test.rb +5 -29
  27. data/test/end_to_end/test_comparison_test.rb +2 -0
  28. data/test/pt_testcase/pt_test.rb +2 -0
  29. data/test/ripper_ruby_parser/commenting_ripper_parser_test.rb +16 -2
  30. data/test/ripper_ruby_parser/parser_test.rb +17 -688
  31. data/test/ripper_ruby_parser/sexp_handlers/assignment_test.rb +459 -26
  32. data/test/ripper_ruby_parser/sexp_handlers/blocks_test.rb +152 -82
  33. data/test/ripper_ruby_parser/sexp_handlers/conditionals_test.rb +91 -0
  34. data/test/ripper_ruby_parser/sexp_handlers/literals_test.rb +331 -24
  35. data/test/ripper_ruby_parser/sexp_handlers/loops_test.rb +88 -0
  36. data/test/ripper_ruby_parser/sexp_handlers/method_calls_test.rb +58 -5
  37. data/test/ripper_ruby_parser/sexp_handlers/methods_test.rb +392 -0
  38. data/test/ripper_ruby_parser/sexp_handlers/operators_test.rb +174 -12
  39. data/test/ripper_ruby_parser/sexp_processor_test.rb +8 -18
  40. data/test/ripper_ruby_parser/version_test.rb +2 -0
  41. data/test/samples/comments.rb +13 -0
  42. data/test/samples/conditionals.rb +23 -0
  43. data/test/samples/loops.rb +36 -0
  44. data/test/samples/misc.rb +157 -5
  45. data/test/samples/number.rb +7 -0
  46. data/test/samples/strings.rb +39 -0
  47. data/test/test_helper.rb +22 -1
  48. metadata +18 -12
  49. data/lib/ripper_ruby_parser/sexp_handlers/arguments.rb +0 -29
  50. data/lib/ripper_ruby_parser/sexp_handlers/arrays.rb +0 -21
  51. data/lib/ripper_ruby_parser/sexp_handlers/hashes.rb +0 -48
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module RipperRubyParser
2
4
  module SexpHandlers
3
5
  # Sexp handlers for loops
@@ -21,12 +23,14 @@ module RipperRubyParser
21
23
  def process_for(exp)
22
24
  _, var, coll, block = exp.shift 4
23
25
  coll = process(coll)
24
- assgn = s(:lasgn, process(var)[1])
26
+ var = process(var)
27
+
28
+ var.sexp_type = :lasgn if var.sexp_type == :lvar
25
29
  block = unwrap_nil process(block)
26
30
  if block
27
- s(:for, coll, assgn, block)
31
+ s(:for, coll, var, block)
28
32
  else
29
- s(:for, coll, assgn)
33
+ s(:for, coll, var)
30
34
  end
31
35
  end
32
36
 
@@ -40,7 +44,7 @@ module RipperRubyParser
40
44
  _, cond, body = exp.shift 3
41
45
 
42
46
  construct_conditional_loop(type, negated_type,
43
- process(cond),
47
+ unwrap_begin(process(cond)),
44
48
  unwrap_nil(process(body)),
45
49
  true)
46
50
  end
@@ -50,8 +54,8 @@ module RipperRubyParser
50
54
 
51
55
  check_at_start = check_at_start?(body)
52
56
  construct_conditional_loop(type, negated_type,
53
- process(cond),
54
- process(body),
57
+ unwrap_begin(process(cond)),
58
+ unwrap_begin(process(body)),
55
59
  check_at_start)
56
60
  end
57
61
 
@@ -1,18 +1,38 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module RipperRubyParser
2
4
  module SexpHandlers
3
5
  # Sexp handlers for method calls
4
6
  module MethodCalls
7
+ def process_args_add_star(exp)
8
+ generic_add_star exp
9
+ end
10
+
11
+ def process_args_add_block(exp)
12
+ _, regular, block = exp.shift 3
13
+ args = process(regular)
14
+ args << s(:block_pass, process(block)) if block
15
+ args
16
+ end
17
+
18
+ def process_arg_paren(exp)
19
+ _, args = exp.shift 2
20
+ return s() if args.nil?
21
+
22
+ process(args)
23
+ end
24
+
5
25
  def process_method_add_arg(exp)
6
26
  _, call, parens = exp.shift 3
7
27
  call = process(call)
8
- unless parens.empty?
9
- parens = process(parens)
10
- parens.shift
11
- end
12
- parens.each do |arg|
13
- call << arg
14
- end
15
- call
28
+ parens = process(parens)
29
+ call.push(*parens.sexp_body)
30
+ end
31
+
32
+ # Handle implied hashes, such as at the end of argument lists.
33
+ def process_bare_assoc_hash(exp)
34
+ _, elems = exp.shift 2
35
+ s(:hash, *make_hash_items(elems))
16
36
  end
17
37
 
18
38
  CALL_OP_MAP = {
@@ -23,13 +43,13 @@ module RipperRubyParser
23
43
 
24
44
  def process_call(exp)
25
45
  _, receiver, op, ident = exp.shift 4
26
- type = CALL_OP_MAP.fetch op
46
+ type = map_call_op op
27
47
  case ident
28
48
  when :call
29
49
  s(type, process(receiver), :call)
30
50
  else
31
51
  with_position_from_node_symbol(ident) do |method|
32
- s(type, process(receiver), method)
52
+ s(type, unwrap_begin(process(receiver)), method)
33
53
  end
34
54
  end
35
55
  end
@@ -37,24 +57,33 @@ module RipperRubyParser
37
57
  def process_command(exp)
38
58
  _, ident, arglist = exp.shift 3
39
59
  with_position_from_node_symbol(ident) do |method|
40
- args = handle_argument_list(arglist)
60
+ args = process(arglist).sexp_body
41
61
  s(:call, nil, method, *args)
42
62
  end
43
63
  end
44
64
 
45
65
  def process_command_call(exp)
46
66
  _, receiver, op, ident, arguments = exp.shift 5
47
- type = CALL_OP_MAP.fetch op
67
+ type = map_call_op op
48
68
  with_position_from_node_symbol(ident) do |method|
49
- args = handle_argument_list(arguments)
69
+ args = process(arguments).sexp_body
50
70
  s(type, process(receiver), method, *args)
51
71
  end
52
72
  end
53
73
 
74
+ def map_call_op(call_op)
75
+ call_op = call_op.sexp_body.first.to_sym if call_op.is_a? Sexp
76
+ CALL_OP_MAP.fetch(call_op)
77
+ end
78
+
54
79
  def process_vcall(exp)
55
80
  _, ident = exp.shift 2
56
81
  with_position_from_node_symbol(ident) do |method|
57
- s(:call, nil, method)
82
+ if replace_kwrest_arg_call? method
83
+ s(:lvar, method)
84
+ else
85
+ s(:call, nil, method)
86
+ end
58
87
  end
59
88
  end
60
89
 
@@ -65,12 +94,28 @@ module RipperRubyParser
65
94
  end
66
95
  end
67
96
 
97
+ def process_aref(exp)
98
+ _, coll, idx = exp.shift 3
99
+
100
+ coll = process(coll)
101
+ idx = process(idx) || []
102
+ idx.shift
103
+ s(:call, coll, :[], *idx)
104
+ end
105
+
68
106
  def process_super(exp)
69
107
  _, args = exp.shift 2
70
108
  args = process(args)
71
109
  args.shift
72
110
  s(:super, *args)
73
111
  end
112
+
113
+ private
114
+
115
+ def replace_kwrest_arg_call?(method)
116
+ method_kwrest_arg?(method) ||
117
+ !extra_compatible && block_kwrest_arg?(method)
118
+ end
74
119
  end
75
120
  end
76
121
  end
@@ -1,23 +1,36 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module RipperRubyParser
2
4
  module SexpHandlers
3
5
  # Sexp handers for method definitions and related constructs
4
6
  module Methods
5
7
  def process_def(exp)
6
8
  _, ident, params, body = exp.shift 4
9
+
7
10
  ident, pos = extract_node_symbol_with_position ident
8
- params = convert_special_args(process(params))
9
- with_position(pos,
10
- s(:defn, ident, params, *method_body(body)))
11
+
12
+ in_method do
13
+ params = convert_method_args(process(params))
14
+ kwrest = kwrest_param(params)
15
+ body = with_kwrest(kwrest) { method_body(body) }
16
+ end
17
+
18
+ with_position(pos, s(:defn, ident, params, *body))
11
19
  end
12
20
 
13
21
  def process_defs(exp)
14
22
  _, receiver, _, method, params, body = exp.shift 6
15
- params = convert_special_args(process(params))
23
+
24
+ in_method do
25
+ params = convert_method_args(process(params))
26
+ kwrest = kwrest_param(params)
27
+ body = with_kwrest(kwrest) { method_body(body) }
28
+ end
16
29
 
17
30
  s(:defs,
18
31
  process(receiver),
19
- extract_node_symbol(method),
20
- params, *method_body(body))
32
+ extract_node_symbol(process(method)),
33
+ params, *body)
21
34
  end
22
35
 
23
36
  def process_return(exp)
@@ -26,17 +39,17 @@ module RipperRubyParser
26
39
  end
27
40
 
28
41
  def process_return0(exp)
29
- _ = exp.shift
42
+ exp.shift
30
43
  s(:return)
31
44
  end
32
45
 
33
46
  def process_yield(exp)
34
47
  _, arglist = exp.shift 2
35
- s(:yield, *handle_argument_list(arglist))
48
+ s(:yield, *process(arglist).sexp_body)
36
49
  end
37
50
 
38
51
  def process_yield0(exp)
39
- _ = exp.shift
52
+ exp.shift
40
53
  s(:yield)
41
54
  end
42
55
 
@@ -44,11 +57,11 @@ module RipperRubyParser
44
57
  _, args = exp.shift 2
45
58
 
46
59
  args.map! do |sub_exp|
47
- s(:undef, make_method_name_literal(sub_exp))
60
+ s(:undef, process(sub_exp))
48
61
  end
49
62
 
50
63
  if args.size == 1
51
- args[0]
64
+ args.first
52
65
  else
53
66
  s(:block, *args)
54
67
  end
@@ -57,9 +70,7 @@ module RipperRubyParser
57
70
  def process_alias(exp)
58
71
  _, left, right = exp.shift 3
59
72
 
60
- s(:alias,
61
- make_method_name_literal(left),
62
- make_method_name_literal(right))
73
+ s(:alias, process(left), process(right))
63
74
  end
64
75
 
65
76
  private
@@ -71,12 +82,8 @@ module RipperRubyParser
71
82
  result
72
83
  end
73
84
 
74
- def make_method_name_literal(exp)
75
- process(exp).tap { |it| it[0] = :lit }
76
- end
77
-
78
85
  def method_body(exp)
79
- block = in_method { process exp }
86
+ block = process exp
80
87
  case block.length
81
88
  when 0
82
89
  [s(:nil)]
@@ -95,27 +102,17 @@ module RipperRubyParser
95
102
  blockarg: '&'
96
103
  }.freeze
97
104
 
98
- def convert_special_args(args)
105
+ def convert_method_args(args)
99
106
  args.map! do |item|
100
107
  if item.is_a? Symbol
101
108
  item
102
109
  else
103
110
  case item.sexp_type
104
111
  when :lvar
105
- item[1]
106
- when :masgn
107
- args = item[1]
108
- args.shift
109
- s(:masgn, *convert_special_args(args))
110
- when :lasgn
111
- if item.length == 2
112
- item[1]
113
- else
114
- item
115
- end
112
+ item.last
116
113
  when *SPECIAL_ARG_MARKER.keys
117
114
  marker = SPECIAL_ARG_MARKER[item.sexp_type]
118
- name = extract_node_symbol item[1]
115
+ name = extract_node_symbol item.last
119
116
  :"#{marker}#{name}"
120
117
  else
121
118
  item
@@ -123,6 +120,33 @@ module RipperRubyParser
123
120
  end
124
121
  end
125
122
  end
123
+
124
+ def kwrest_param(params)
125
+ found = params.find { |param| param.to_s =~ /^\*\*(.+)/ }
126
+ Regexp.last_match[1].to_sym if found
127
+ end
128
+
129
+ def with_kwrest(kwrest)
130
+ @kwrest.push kwrest
131
+ result = yield
132
+ @kwrest.pop
133
+ result
134
+ end
135
+
136
+ def with_block_kwrest(kwrest)
137
+ @block_kwrest.push kwrest
138
+ result = yield
139
+ @block_kwrest.pop
140
+ result
141
+ end
142
+
143
+ def method_kwrest_arg?(method)
144
+ @kwrest.include?(method)
145
+ end
146
+
147
+ def block_kwrest_arg?(method)
148
+ @block_kwrest.include?(method)
149
+ end
126
150
  end
127
151
  end
128
152
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module RipperRubyParser
2
4
  module SexpHandlers
3
5
  # Sexp handlers for operators
@@ -23,21 +25,21 @@ module RipperRubyParser
23
25
  _, left, op, right = exp.shift 4
24
26
 
25
27
  if op == :=~
26
- make_regexp_match_operator(op, left, right)
28
+ make_regexp_match_operator(left, op, right)
27
29
  elsif (mapped = NEGATED_BINARY_OPERATOR_MAP[op])
28
- s(:not, make_regexp_match_operator(mapped, left, right))
30
+ s(:not, make_regexp_match_operator(left, mapped, right))
29
31
  elsif (mapped = BINARY_OPERATOR_MAP[op])
30
- make_boolean_operator(mapped, left, right)
32
+ make_boolean_operator(left, mapped, right)
31
33
  elsif SHIFT_OPERATORS.include? op
32
- s(:call, process(left), op, process(right))
34
+ s(:call, unwrap_begin(process(left)), op, unwrap_begin(process(right)))
33
35
  else
34
- s(:call, handle_operator_argument(left), op, handle_operator_argument(right))
36
+ s(:call, process(left), op, process(right))
35
37
  end
36
38
  end
37
39
 
38
40
  def process_unary(exp)
39
41
  _, op, arg = exp.shift 3
40
- arg = handle_operator_argument(arg)
42
+ arg = process(arg)
41
43
  op = UNARY_OPERATOR_MAP[op] || op
42
44
  s(:call, arg, op)
43
45
  end
@@ -67,19 +69,19 @@ module RipperRubyParser
67
69
  def process_ifop(exp)
68
70
  _, cond, truepart, falsepart = exp.shift 4
69
71
  s(:if,
70
- handle_operator_argument(cond),
71
- handle_operator_argument(truepart),
72
- handle_operator_argument(falsepart))
72
+ process(cond),
73
+ process(truepart),
74
+ process(falsepart))
73
75
  end
74
76
 
75
77
  private
76
78
 
77
- def make_boolean_operator(operator, left, right)
78
- _, left, _, right = rebalance_binary(s(:binary, left, operator, right))
79
- s(operator, process(left), handle_operator_argument(right))
79
+ def make_boolean_operator(left, operator, right)
80
+ _, left, _, right = rebalance_binary(left, operator, right)
81
+ s(operator, unwrap_begin(process(left)), process(right))
80
82
  end
81
83
 
82
- def make_regexp_match_operator(operator, left, right)
84
+ def make_regexp_match_operator(left, operator, right)
83
85
  if left.sexp_type == :regexp_literal
84
86
  s(:match2, process(left), process(right))
85
87
  elsif right.sexp_type == :regexp_literal
@@ -89,21 +91,12 @@ module RipperRubyParser
89
91
  end
90
92
  end
91
93
 
92
- def rebalance_binary(exp)
93
- _, left, op, right = exp
94
- if left.sexp_type == :binary && BINARY_OPERATOR_MAP[op] == BINARY_OPERATOR_MAP[left[2]]
95
- _, left, _, middle = rebalance_binary(left)
96
- right = rebalance_binary(s(:binary, middle, op, right))
97
- end
98
- s(:binary, left, op, right)
99
- end
100
-
101
- def handle_operator_argument(exp)
102
- if exp.sexp_type == :begin
103
- s(:begin, process(exp))
104
- else
105
- process(exp)
94
+ def rebalance_binary(left, operator, right)
95
+ if BINARY_OPERATOR_MAP[operator] == BINARY_OPERATOR_MAP[left[2]]
96
+ _, left, _, middle = rebalance_binary(*left.sexp_body)
97
+ right = rebalance_binary(middle, operator, right)
106
98
  end
99
+ s(:binary, left, operator, right)
107
100
  end
108
101
  end
109
102
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'sexp_processor'
2
4
  require 'ripper_ruby_parser/sexp_handlers'
3
5
  require 'ripper_ruby_parser/unescape'
@@ -7,15 +9,17 @@ module RipperRubyParser
7
9
  #
8
10
  # @api private
9
11
  class SexpProcessor < ::SexpProcessor
12
+ include Unescape
13
+
10
14
  attr_reader :filename
15
+ attr_reader :extra_compatible
11
16
 
12
- def initialize(filename: nil)
17
+ def initialize(filename: nil, extra_compatible: nil)
13
18
  super()
14
19
 
15
- # TODO: Find these automatically
16
-
17
20
  @processors[:@int] = :process_at_int
18
21
  @processors[:@float] = :process_at_float
22
+ @processors[:@rational] = :process_at_rational
19
23
  @processors[:@CHAR] = :process_at_CHAR
20
24
  @processors[:@label] = :process_at_label
21
25
 
@@ -27,14 +31,18 @@ module RipperRubyParser
27
31
  @processors[:@kw] = :process_at_kw
28
32
  @processors[:@op] = :process_at_op
29
33
  @processors[:@backref] = :process_at_backref
34
+ @processors[:@period] = :process_at_period
30
35
 
31
36
  @processors[:@tstring_content] = :process_at_tstring_content
32
37
 
33
38
  @filename = filename
39
+ @extra_compatible = extra_compatible
34
40
 
35
41
  @errors = []
36
42
 
37
43
  @in_method_body = false
44
+ @kwrest = []
45
+ @block_kwrest = []
38
46
  end
39
47
 
40
48
  include SexpHandlers
@@ -67,7 +75,7 @@ module RipperRubyParser
67
75
 
68
76
  def process_stmts(exp)
69
77
  _, *statements = shift_all(exp)
70
- statements = reject_void_stmt map_process_list statements
78
+ statements = map_process_list_compact statements
71
79
  case statements.count
72
80
  when 0
73
81
  s(:void_stmt)
@@ -101,7 +109,7 @@ module RipperRubyParser
101
109
 
102
110
  def process_const_path_ref(exp)
103
111
  _, left, right = exp.shift 3
104
- s(:colon2, process(left), extract_node_symbol(right))
112
+ s(:colon2, process(left), extract_node_symbol(process(right)))
105
113
  end
106
114
 
107
115
  def process_const_path_field(exp)
@@ -115,7 +123,7 @@ module RipperRubyParser
115
123
 
116
124
  def process_top_const_ref(exp)
117
125
  _, ref = exp.shift 2
118
- s(:colon3, extract_node_symbol(ref))
126
+ s(:colon3, extract_node_symbol(process(ref)))
119
127
  end
120
128
 
121
129
  def process_top_const_field(exp)
@@ -141,12 +149,14 @@ module RipperRubyParser
141
149
 
142
150
  def process_BEGIN(exp)
143
151
  _, body = exp.shift 2
144
- s(:iter, s(:preexe), s(:args), *map_process_sexp_body_compact(body))
152
+ body = reject_void_stmt map_process_list body.sexp_body
153
+ s(:iter, s(:preexe), s(:args), *body)
145
154
  end
146
155
 
147
156
  def process_END(exp)
148
157
  _, body = exp.shift 2
149
- s(:iter, s(:postexe), 0, *map_process_sexp_body_compact(body))
158
+ body = map_process_list_compact body.sexp_body
159
+ s(:iter, s(:postexe), 0, *body)
150
160
  end
151
161
 
152
162
  # number literals
@@ -158,10 +168,14 @@ module RipperRubyParser
158
168
  make_literal(exp, &:to_f)
159
169
  end
160
170
 
171
+ def process_at_rational(exp)
172
+ make_literal(exp, &:to_r)
173
+ end
174
+
161
175
  # character literals
162
176
  def process_at_CHAR(exp)
163
177
  _, val, pos = exp.shift 3
164
- with_position(pos, s(:str, Unescape.unescape(val[1..-1])))
178
+ with_position(pos, s(:str, unescape(val[1..-1])))
165
179
  end
166
180
 
167
181
  def process_at_label(exp)
@@ -186,7 +200,13 @@ module RipperRubyParser
186
200
  end
187
201
 
188
202
  def process_at_ident(exp)
189
- make_identifier(:lvar, exp)
203
+ with_position_from_node_symbol(exp) do |ident|
204
+ if replace_kwrest_arg_lvar? ident
205
+ s(:call, nil, ident)
206
+ else
207
+ s(:lvar, ident)
208
+ end
209
+ end
190
210
  end
191
211
 
192
212
  def process_at_op(exp)
@@ -220,6 +240,11 @@ module RipperRubyParser
220
240
  end
221
241
  end
222
242
 
243
+ def process_at_period(exp)
244
+ _, period, = exp.shift 3
245
+ s(:period, period)
246
+ end
247
+
223
248
  private
224
249
 
225
250
  def const_ref_to_const_with_line_number(const_ref)
@@ -233,6 +258,7 @@ module RipperRubyParser
233
258
  body = process(exp)
234
259
 
235
260
  return body if body.empty?
261
+
236
262
  if body.sexp_type == :block
237
263
  body.sexp_body
238
264
  else
@@ -250,5 +276,9 @@ module RipperRubyParser
250
276
  _, val, pos = exp.shift 3
251
277
  with_position(pos, s(:lit, yield(val)))
252
278
  end
279
+
280
+ def replace_kwrest_arg_lvar?(ident)
281
+ extra_compatible && @block_kwrest.include?(ident)
282
+ end
253
283
  end
254
284
  end