ripper_ruby_parser 1.1.2 → 1.2.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 (40) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +19 -0
  3. data/README.md +2 -2
  4. data/Rakefile +1 -1
  5. data/lib/ripper_ruby_parser.rb +0 -7
  6. data/lib/ripper_ruby_parser/commenting_ripper_parser.rb +112 -34
  7. data/lib/ripper_ruby_parser/parser.rb +26 -12
  8. data/lib/ripper_ruby_parser/sexp_handlers.rb +4 -1
  9. data/lib/ripper_ruby_parser/sexp_handlers/arguments.rb +7 -6
  10. data/lib/ripper_ruby_parser/sexp_handlers/arrays.rb +4 -2
  11. data/lib/ripper_ruby_parser/sexp_handlers/assignment.rb +39 -43
  12. data/lib/ripper_ruby_parser/sexp_handlers/blocks.rb +93 -69
  13. data/lib/ripper_ruby_parser/sexp_handlers/conditionals.rb +30 -24
  14. data/lib/ripper_ruby_parser/sexp_handlers/hashes.rb +7 -9
  15. data/lib/ripper_ruby_parser/sexp_handlers/helper_methods.rb +51 -71
  16. data/lib/ripper_ruby_parser/sexp_handlers/literals.rb +72 -56
  17. data/lib/ripper_ruby_parser/sexp_handlers/loops.rb +14 -13
  18. data/lib/ripper_ruby_parser/sexp_handlers/method_calls.rb +19 -13
  19. data/lib/ripper_ruby_parser/sexp_handlers/methods.rb +19 -22
  20. data/lib/ripper_ruby_parser/sexp_handlers/operators.rb +47 -35
  21. data/lib/ripper_ruby_parser/sexp_processor.rb +72 -85
  22. data/lib/ripper_ruby_parser/version.rb +1 -1
  23. data/test/end_to_end/line_numbering_test.rb +1 -1
  24. data/test/end_to_end/samples_comparison_test.rb +0 -1
  25. data/test/pt_testcase/pt_test.rb +4 -6
  26. data/test/{unit → ripper_ruby_parser}/commenting_ripper_parser_test.rb +82 -25
  27. data/test/{unit → ripper_ruby_parser}/parser_test.rb +37 -170
  28. data/test/{unit/parser_assignment_test.rb → ripper_ruby_parser/sexp_handlers/assignment_test.rb} +1 -1
  29. data/test/{unit/parser_blocks_test.rb → ripper_ruby_parser/sexp_handlers/blocks_test.rb} +267 -2
  30. data/test/{unit/parser_conditionals_test.rb → ripper_ruby_parser/sexp_handlers/conditionals_test.rb} +125 -17
  31. data/test/{unit/parser_literals_test.rb → ripper_ruby_parser/sexp_handlers/literals_test.rb} +10 -12
  32. data/test/{unit/parser_loops_test.rb → ripper_ruby_parser/sexp_handlers/loops_test.rb} +1 -1
  33. data/test/{unit/parser_method_calls_test.rb → ripper_ruby_parser/sexp_handlers/method_calls_test.rb} +10 -10
  34. data/test/{unit/parser_operators_test.rb → ripper_ruby_parser/sexp_handlers/operators_test.rb} +22 -2
  35. data/test/{unit → ripper_ruby_parser}/sexp_processor_test.rb +49 -48
  36. data/test/{unit → ripper_ruby_parser}/version_test.rb +0 -0
  37. data/test/samples/misc.rb +4 -0
  38. data/test/test_helper.rb +4 -4
  39. metadata +28 -42
  40. data/test/end_to_end/error_conditions_test.rb +0 -51
@@ -1,11 +1,12 @@
1
1
  module RipperRubyParser
2
2
  module SexpHandlers
3
+ # Sexp handlers for operators
3
4
  module Operators
4
5
  BINARY_OPERATOR_MAP = {
5
- :"&&" => :and,
6
- :"||" => :or,
7
- :and => :and,
8
- :or => :or
6
+ '&&': :and,
7
+ '||': :or,
8
+ and: :and,
9
+ or: :or
9
10
  }.freeze
10
11
 
11
12
  UNARY_OPERATOR_MAP = {
@@ -13,10 +14,12 @@ module RipperRubyParser
13
14
  }.freeze
14
15
 
15
16
  NEGATED_BINARY_OPERATOR_MAP = {
16
- :"!~" => :=~
17
+ '!~': :=~
17
18
  }.freeze
18
19
 
19
- def process_binary exp
20
+ SHIFT_OPERATORS = [:<<, :>>].freeze
21
+
22
+ def process_binary(exp)
20
23
  _, left, op, right = exp.shift 4
21
24
 
22
25
  if op == :=~
@@ -25,37 +28,21 @@ module RipperRubyParser
25
28
  s(:not, make_regexp_match_operator(mapped, left, right))
26
29
  elsif (mapped = BINARY_OPERATOR_MAP[op])
27
30
  make_boolean_operator(mapped, left, right)
28
- else
31
+ elsif SHIFT_OPERATORS.include? op
29
32
  s(:call, process(left), op, process(right))
30
- end
31
- end
32
-
33
- def make_boolean_operator op, left, right
34
- if left.first == :paren
35
- s(op, process(left), process(right))
36
- else
37
- rebalance_binary(s(op, process(left), process(right)))
38
- end
39
- end
40
-
41
- def make_regexp_match_operator op, left, right
42
- if left.sexp_type == :regexp_literal
43
- s(:match2, process(left), process(right))
44
- elsif right.sexp_type == :regexp_literal
45
- s(:match3, process(right), process(left))
46
33
  else
47
- s(:call, process(left), op, process(right))
34
+ s(:call, handle_operator_argument(left), op, handle_operator_argument(right))
48
35
  end
49
36
  end
50
37
 
51
- def process_unary exp
38
+ def process_unary(exp)
52
39
  _, op, arg = exp.shift 3
53
- arg = process(arg)
40
+ arg = handle_operator_argument(arg)
54
41
  op = UNARY_OPERATOR_MAP[op] || op
55
42
  s(:call, arg, op)
56
43
  end
57
44
 
58
- def process_dot2 exp
45
+ def process_dot2(exp)
59
46
  _, left, right = exp.shift 3
60
47
  left = process(left)
61
48
  right = process(right)
@@ -66,7 +53,7 @@ module RipperRubyParser
66
53
  end
67
54
  end
68
55
 
69
- def process_dot3 exp
56
+ def process_dot3(exp)
70
57
  _, left, right = exp.shift 3
71
58
  left = process(left)
72
59
  right = process(right)
@@ -77,20 +64,45 @@ module RipperRubyParser
77
64
  end
78
65
  end
79
66
 
80
- def process_ifop exp
67
+ def process_ifop(exp)
81
68
  _, cond, truepart, falsepart = exp.shift 4
82
- s(:if, process(cond), process(truepart), process(falsepart))
69
+ s(:if,
70
+ handle_operator_argument(cond),
71
+ handle_operator_argument(truepart),
72
+ handle_operator_argument(falsepart))
83
73
  end
84
74
 
85
75
  private
86
76
 
87
- def rebalance_binary exp
88
- op, left, right = exp
77
+ def make_boolean_operator(op, left, right)
78
+ _, left, _, right = rebalance_binary(s(:binary, left, op, right))
79
+ s(op, process(left), handle_operator_argument(right))
80
+ end
81
+
82
+ def make_regexp_match_operator(op, left, right)
83
+ if left.sexp_type == :regexp_literal
84
+ s(:match2, process(left), process(right))
85
+ elsif right.sexp_type == :regexp_literal
86
+ s(:match3, process(right), process(left))
87
+ else
88
+ s(:call, process(left), op, process(right))
89
+ end
90
+ end
91
+
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
89
100
 
90
- if op == left.sexp_type
91
- s(op, left[1], rebalance_binary(s(op, left[2], right)))
101
+ def handle_operator_argument(exp)
102
+ if exp.sexp_type == :begin
103
+ s(:begin, process(exp))
92
104
  else
93
- s(op, left, right)
105
+ process(exp)
94
106
  end
95
107
  end
96
108
  end
@@ -3,12 +3,13 @@ require 'ripper_ruby_parser/sexp_handlers'
3
3
 
4
4
  module RipperRubyParser
5
5
  # Processes the sexp created by Ripper to what RubyParser would produce.
6
+ #
7
+ # @api private
6
8
  class SexpProcessor < ::SexpProcessor
7
- attr_accessor :filename
8
- attr_accessor :extra_compatible
9
+ attr_reader :filename
9
10
 
10
- def initialize
11
- super
11
+ def initialize(filename: nil)
12
+ super()
12
13
 
13
14
  # TODO: Find these automatically
14
15
 
@@ -28,36 +29,29 @@ module RipperRubyParser
28
29
 
29
30
  @processors[:@tstring_content] = :process_at_tstring_content
30
31
 
32
+ @filename = filename
33
+
31
34
  @errors = []
32
35
 
33
36
  @in_method_body = false
34
37
  end
35
38
 
36
- def process exp
37
- return nil if exp.nil?
38
-
39
- result = super
40
- trickle_up_line_numbers result
41
- trickle_down_line_numbers result
42
- end
43
-
44
39
  include SexpHandlers
45
40
 
46
- def process_program exp
41
+ def process_program(exp)
47
42
  _, content = exp.shift 2
48
43
 
49
- statements = content.map { |sub_exp| process(sub_exp) }
50
- safe_wrap_in_block statements
44
+ process content
51
45
  end
52
46
 
53
- def process_module exp
47
+ def process_module(exp)
54
48
  _, const_ref, body = exp.shift 3
55
49
  const, line = const_ref_to_const_with_line_number const_ref
56
50
  with_line_number(line,
57
51
  s(:module, const, *class_or_module_body(body)))
58
52
  end
59
53
 
60
- def process_class exp
54
+ def process_class(exp)
61
55
  _, const_ref, parent, body = exp.shift 4
62
56
  const, line = const_ref_to_const_with_line_number const_ref
63
57
  parent = process(parent)
@@ -65,125 +59,144 @@ module RipperRubyParser
65
59
  s(:class, const, parent, *class_or_module_body(body)))
66
60
  end
67
61
 
68
- def process_sclass exp
62
+ def process_sclass(exp)
69
63
  _, klass, block = exp.shift 3
70
64
  s(:sclass, process(klass), *class_or_module_body(block))
71
65
  end
72
66
 
73
- def process_var_ref exp
67
+ def process_stmts(exp)
68
+ _, *statements = shift_all(exp)
69
+ statements = reject_void_stmt map_process_list statements
70
+ case statements.count
71
+ when 0
72
+ s(:void_stmt)
73
+ when 1
74
+ statements.first
75
+ else
76
+ first = statements.shift
77
+ if first.sexp_type == :block
78
+ first.shift
79
+ s(:block, *first, *statements)
80
+ else
81
+ s(:block, first, *statements)
82
+ end
83
+ end
84
+ end
85
+
86
+ def process_var_ref(exp)
74
87
  _, contents = exp.shift 2
75
88
  process(contents)
76
89
  end
77
90
 
78
- def process_var_field exp
91
+ def process_var_field(exp)
79
92
  _, contents = exp.shift 2
80
93
  process(contents)
81
94
  end
82
95
 
83
- def process_var_alias exp
96
+ def process_var_alias(exp)
84
97
  _, left, right = exp.shift 3
85
98
  s(:valias, left[1].to_sym, right[1].to_sym)
86
99
  end
87
100
 
88
- def process_const_path_ref exp
101
+ def process_const_path_ref(exp)
89
102
  _, left, right = exp.shift 3
90
103
  s(:colon2, process(left), extract_node_symbol(right))
91
104
  end
92
105
 
93
- def process_const_path_field exp
106
+ def process_const_path_field(exp)
94
107
  s(:const, process_const_path_ref(exp))
95
108
  end
96
109
 
97
- def process_const_ref exp
110
+ def process_const_ref(exp)
98
111
  _, ref = exp.shift 3
99
112
  process(ref)
100
113
  end
101
114
 
102
- def process_top_const_ref exp
115
+ def process_top_const_ref(exp)
103
116
  _, ref = exp.shift 2
104
117
  s(:colon3, extract_node_symbol(ref))
105
118
  end
106
119
 
107
- def process_top_const_field exp
120
+ def process_top_const_field(exp)
108
121
  s(:const, process_top_const_ref(exp))
109
122
  end
110
123
 
111
- def process_paren exp
124
+ def process_paren(exp)
112
125
  _, body = exp.shift 2
113
- if body.empty?
114
- s()
115
- elsif body.first.is_a? Symbol
116
- process body
126
+ result = process body
127
+ if result.sexp_type == :void_stmt
128
+ s(:nil)
117
129
  else
118
- body.map! { |it| convert_void_stmt_to_nil process it }
119
- safe_wrap_in_block body
130
+ result
120
131
  end
121
132
  end
122
133
 
123
- def process_comment exp
134
+ def process_comment(exp)
124
135
  _, comment, inner = exp.shift 3
125
136
  sexp = process(inner)
126
137
  sexp.comments = comment
127
138
  sexp
128
139
  end
129
140
 
130
- def process_BEGIN exp
141
+ def process_BEGIN(exp)
131
142
  _, body = exp.shift 2
132
- s(:iter, s(:preexe), s(:args), *map_body(body))
143
+ s(:iter, s(:preexe), s(:args), *map_process_sexp_body_compact(body))
133
144
  end
134
145
 
135
- def process_END exp
146
+ def process_END(exp)
136
147
  _, body = exp.shift 2
137
- s(:iter, s(:postexe), 0, *map_body(body))
148
+ s(:iter, s(:postexe), 0, *map_process_sexp_body_compact(body))
138
149
  end
139
150
 
140
151
  # number literals
141
- def process_at_int exp
152
+ def process_at_int(exp)
142
153
  make_literal(exp) { |val| Integer(val) }
143
154
  end
144
155
 
145
- def process_at_float exp
156
+ def process_at_float(exp)
146
157
  make_literal(exp, &:to_f)
147
158
  end
148
159
 
149
160
  # character literals
150
- def process_at_CHAR exp
161
+ def process_at_CHAR(exp)
151
162
  _, val, pos = exp.shift 3
152
163
  with_position(pos, s(:str, unescape(val[1..-1])))
153
164
  end
154
165
 
155
- def process_at_label exp
166
+ def process_at_label(exp)
156
167
  make_literal(exp) { |val| val.chop.to_sym }
157
168
  end
158
169
 
159
170
  # symbol-like sexps
160
- def process_at_const exp
171
+ def process_at_const(exp)
161
172
  make_identifier(:const, exp)
162
173
  end
163
174
 
164
- def process_at_cvar exp
175
+ def process_at_cvar(exp)
165
176
  make_identifier(:cvar, exp)
166
177
  end
167
178
 
168
- def process_at_gvar exp
179
+ def process_at_gvar(exp)
169
180
  make_identifier(:gvar, exp)
170
181
  end
171
182
 
172
- def process_at_ivar exp
183
+ def process_at_ivar(exp)
173
184
  make_identifier(:ivar, exp)
174
185
  end
175
186
 
176
- def process_at_ident exp
187
+ def process_at_ident(exp)
177
188
  make_identifier(:lvar, exp)
178
189
  end
179
190
 
180
- def process_at_op exp
191
+ def process_at_op(exp)
181
192
  make_identifier(:op, exp)
182
193
  end
183
194
 
184
- def process_at_kw exp
195
+ def process_at_kw(exp)
185
196
  sym, pos = extract_node_symbol_with_position(exp)
186
197
  result = case sym
198
+ when :__ENCODING__
199
+ s(:colon2, s(:const, :Encoding), :UTF_8)
187
200
  when :__FILE__
188
201
  s(:str, @filename)
189
202
  when :__LINE__
@@ -194,7 +207,7 @@ module RipperRubyParser
194
207
  with_position(pos, result)
195
208
  end
196
209
 
197
- def process_at_backref exp
210
+ def process_at_backref(exp)
198
211
  _, str, pos = exp.shift 3
199
212
  name = str[1..-1]
200
213
  with_position pos do
@@ -208,59 +221,33 @@ module RipperRubyParser
208
221
 
209
222
  private
210
223
 
211
- def const_ref_to_const_with_line_number const_ref
224
+ def const_ref_to_const_with_line_number(const_ref)
212
225
  const = process(const_ref)
213
226
  line = const.line
214
227
  const = const[1] if const.sexp_type == :const
215
228
  return const, line
216
229
  end
217
230
 
218
- def class_or_module_body exp
231
+ def class_or_module_body(exp)
219
232
  body = process(exp)
220
233
 
221
- if body.length == 1 && body.first.sexp_type == :block
222
- body = body.first
223
- body.shift
234
+ return body if body.empty?
235
+ if body.sexp_type == :block
236
+ body.sexp_body
237
+ else
238
+ [body]
224
239
  end
225
-
226
- body
227
240
  end
228
241
 
229
- def make_identifier type, exp
242
+ def make_identifier(type, exp)
230
243
  with_position_from_node_symbol(exp) do |ident|
231
244
  s(type, ident)
232
245
  end
233
246
  end
234
247
 
235
- def make_literal exp
248
+ def make_literal(exp)
236
249
  _, val, pos = exp.shift 3
237
250
  with_position(pos, s(:lit, yield(val)))
238
251
  end
239
-
240
- def trickle_up_line_numbers exp
241
- exp.each do |sub_exp|
242
- if sub_exp.is_a? Sexp
243
- trickle_up_line_numbers sub_exp
244
- exp.line ||= sub_exp.line
245
- end
246
- end
247
- end
248
-
249
- def trickle_down_line_numbers exp
250
- exp.each do |sub_exp|
251
- if sub_exp.is_a? Sexp
252
- sub_exp.line ||= exp.line
253
- trickle_down_line_numbers sub_exp
254
- end
255
- end
256
- end
257
-
258
- def convert_void_stmt_to_nil sexp
259
- if sexp == s(:void_stmt)
260
- s(:nil)
261
- else
262
- sexp
263
- end
264
- end
265
252
  end
266
253
  end
@@ -1,3 +1,3 @@
1
1
  module RipperRubyParser
2
- VERSION = '1.1.2'.freeze
2
+ VERSION = '1.2.0'.freeze
3
3
  end