ripper_ruby_parser 1.4.2 → 1.5.0

Sign up to get free protection for your applications and to get access to all the features.
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