ripper_ruby_parser 0.0.8 → 1.0.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 (31) hide show
  1. checksums.yaml +7 -0
  2. data/{README.rdoc → README.md} +17 -17
  3. data/Rakefile +3 -1
  4. data/lib/ripper_ruby_parser/{commenting_sexp_builder.rb → commenting_ripper_parser.rb} +22 -6
  5. data/lib/ripper_ruby_parser/parser.rb +3 -18
  6. data/lib/ripper_ruby_parser/sexp_handlers/arrays.rb +2 -1
  7. data/lib/ripper_ruby_parser/sexp_handlers/assignment.rb +6 -10
  8. data/lib/ripper_ruby_parser/sexp_handlers/blocks.rb +37 -60
  9. data/lib/ripper_ruby_parser/sexp_handlers/conditionals.rb +31 -25
  10. data/lib/ripper_ruby_parser/sexp_handlers/helper_methods.rb +18 -8
  11. data/lib/ripper_ruby_parser/sexp_handlers/literals.rb +22 -18
  12. data/lib/ripper_ruby_parser/sexp_handlers/loops.rb +12 -23
  13. data/lib/ripper_ruby_parser/sexp_handlers/method_calls.rb +16 -8
  14. data/lib/ripper_ruby_parser/sexp_handlers/methods.rb +41 -15
  15. data/lib/ripper_ruby_parser/sexp_handlers/operators.rb +40 -23
  16. data/lib/ripper_ruby_parser/sexp_processor.rb +38 -19
  17. data/lib/ripper_ruby_parser/version.rb +1 -1
  18. data/test/pt_testcase/pt_test.rb +15 -1
  19. data/test/test_helper.rb +6 -3
  20. data/test/unit/commenting_ripper_parser_test.rb +121 -0
  21. data/test/unit/parser_assignment_test.rb +23 -24
  22. data/test/unit/parser_blocks_test.rb +207 -35
  23. data/test/unit/parser_conditionals_test.rb +251 -9
  24. data/test/unit/parser_literals_test.rb +348 -8
  25. data/test/unit/parser_loops_test.rb +20 -21
  26. data/test/unit/parser_method_calls_test.rb +132 -8
  27. data/test/unit/parser_operators_test.rb +97 -7
  28. data/test/unit/parser_test.rb +631 -1231
  29. data/test/unit/sexp_processor_test.rb +26 -28
  30. metadata +28 -38
  31. data/test/unit/commenting_sexp_builder_test.rb +0 -113
@@ -13,7 +13,7 @@ module RipperRubyParser
13
13
 
14
14
  def handle_potentially_typeless_sexp_with_fallback_type type, exp
15
15
  if exp.nil?
16
- s()
16
+ s(type)
17
17
  elsif exp.first.is_a? Symbol
18
18
  process(exp)
19
19
  else
@@ -23,14 +23,10 @@ module RipperRubyParser
23
23
  end
24
24
  end
25
25
 
26
- def handle_statement_list exp
27
- statements = map_body exp
28
-
29
- wrap_in_block(statements)
30
- end
31
-
32
26
  def extract_node_symbol_with_position exp
33
27
  return nil if exp.nil?
28
+ return exp if exp.is_a? Symbol
29
+
34
30
  _, ident, pos = exp.shift 3
35
31
  return ident.to_sym, pos
36
32
  end
@@ -61,6 +57,9 @@ module RipperRubyParser
61
57
  _, args, splatarg = exp.shift 3
62
58
  items = handle_potentially_typeless_sexp args
63
59
  items << s(:splat, process(splatarg))
60
+ until exp.empty?
61
+ items << process(exp.shift)
62
+ end
64
63
  items
65
64
  end
66
65
 
@@ -81,10 +80,21 @@ module RipperRubyParser
81
80
  when 1
82
81
  statements.first
83
82
  else
84
- s(:block, *statements)
83
+ first = statements.shift
84
+ if first.sexp_type == :block
85
+ first.shift
86
+ s(:block, *first, *statements)
87
+ else
88
+ s(:block, first, *statements)
89
+ end
85
90
  end
86
91
  end
87
92
 
93
+ def safe_wrap_in_block statements
94
+ result = wrap_in_block statements
95
+ result ? result : s()
96
+ end
97
+
88
98
  def handle_return_argument_list arglist
89
99
  arglist = process(arglist)
90
100
  args = arglist[1..-1]
@@ -1,3 +1,4 @@
1
+ # coding: utf-8
1
2
  module RipperRubyParser
2
3
  module SexpHandlers
3
4
  module Literals
@@ -21,17 +22,20 @@ module RipperRubyParser
21
22
  def process_string_embexpr exp
22
23
  _, list = exp.shift 2
23
24
  val = process(list.first)
24
- if val.sexp_type == :str
25
+ case val.sexp_type
26
+ when :str
25
27
  val
28
+ when :void_stmt
29
+ s(:dstr, "", s(:evstr))
26
30
  else
27
- s(:evstr, val)
31
+ s(:dstr, "", s(:evstr, val))
28
32
  end
29
33
  end
30
34
 
31
35
  def process_string_dvar exp
32
36
  _, list = exp.shift 2
33
37
  val = process(list)
34
- s(:evstr, val)
38
+ s(:dstr, "", s(:evstr, val))
35
39
  end
36
40
 
37
41
  def process_string_concat exp
@@ -45,7 +49,7 @@ module RipperRubyParser
45
49
  right
46
50
  else # Expecting left.sexp_type == :dstr
47
51
  _, first, *rest = right
48
- left.push s(:str, first)
52
+ left.push s(:str, first) unless first.empty?
49
53
  left.push(*rest)
50
54
  left
51
55
  end
@@ -109,20 +113,9 @@ module RipperRubyParser
109
113
  private
110
114
 
111
115
  def extract_string_parts exp
112
- inner = exp.shift
113
-
114
- string = process(inner)
116
+ string = ""
115
117
  rest = []
116
118
 
117
- if string.nil?
118
- string = ""
119
- elsif string.sexp_type == :str
120
- string = string[1]
121
- else
122
- rest << string
123
- string = ""
124
- end
125
-
126
119
  until exp.empty? do
127
120
  result = process(exp.shift)
128
121
  rest << result
@@ -133,6 +126,8 @@ module RipperRubyParser
133
126
  string += str[1]
134
127
  end
135
128
 
129
+ rest = rest.map { |se| se.sexp_type == :dstr ? se.last : se }
130
+
136
131
  return string, rest
137
132
  end
138
133
 
@@ -170,8 +165,13 @@ module RipperRubyParser
170
165
  [0-7]{1,3} | # octal character
171
166
  x[0-9a-fA-F]{1,2} | # hex byte
172
167
  u[0-9a-fA-F]{4} | # unicode character
168
+ M-\\C-. | # meta-ctrl
169
+ C-\\M-. | # ctrl-meta
170
+ M-\\c. | # meta-ctrl (shorthand)
171
+ c\\M-. | # ctrl-meta (shorthand)
173
172
  C-. | # control (regular)
174
173
  c. | # control (shorthand)
174
+ M-. | # meta
175
175
  . # single-character
176
176
  )/x) do
177
177
  bare = $1
@@ -182,8 +182,12 @@ module RipperRubyParser
182
182
  bare[1..-1].to_i(16).chr
183
183
  when /^u/
184
184
  bare[1..-1].to_i(16).chr(Encoding::UTF_8)
185
- when /^(c|C-)(.)$/
186
- ($2.ord & 0b1001_1111).chr
185
+ when /^(?:c|C-)(.)$/
186
+ ($1.ord & 0b1001_1111).chr
187
+ when /^M-(.)$/
188
+ ($1.ord | 0b1000_0000).chr
189
+ when /^(?:M-\\C-|C-\\M-|M-\\c|c\\M-)(.)$/
190
+ ($1.ord & 0b1001_1111 | 0b1000_0000).chr
187
191
  when /^[0-7]+/
188
192
  bare.to_i(8).chr
189
193
  else
@@ -4,7 +4,7 @@ module RipperRubyParser
4
4
  def process_until exp
5
5
  _, cond, block = exp.shift 3
6
6
 
7
- make_until(process(cond), handle_statement_list(block), true)
7
+ s(:until, process(cond), wrap_in_block(map_body(block)), true)
8
8
  end
9
9
 
10
10
  def process_until_mod exp
@@ -12,13 +12,13 @@ module RipperRubyParser
12
12
 
13
13
  check_at_start = check_at_start?(block)
14
14
 
15
- make_until(process(cond), process(block), check_at_start)
15
+ s(:until, process(cond), process(block), check_at_start)
16
16
  end
17
17
 
18
18
  def process_while exp
19
19
  _, cond, block = exp.shift 3
20
20
 
21
- make_while(process(cond), handle_statement_list(block), true)
21
+ s(:while, process(cond), wrap_in_block(map_body(block)), true)
22
22
  end
23
23
 
24
24
  def process_while_mod exp
@@ -26,33 +26,22 @@ module RipperRubyParser
26
26
 
27
27
  check_at_start = check_at_start?(block)
28
28
 
29
- make_while(process(cond), process(block), check_at_start)
29
+ s(:while, process(cond), process(block), check_at_start)
30
30
  end
31
31
 
32
32
  def process_for exp
33
33
  _, var, coll, block = exp.shift 4
34
- s(:for, process(coll),
35
- s(:lasgn, process(var)[1]),
36
- handle_statement_list(block))
37
- end
38
-
39
- private
40
-
41
- def make_guarded_block(type, inverse, cond, block, check_at_start)
42
- if cond.sexp_type == :not
43
- type = inverse
44
- cond = cond[1]
34
+ coll = process(coll)
35
+ assgn = s(:lasgn, process(var)[1])
36
+ block = wrap_in_block(map_body(block))
37
+ if block.nil?
38
+ s(:for, coll, assgn)
39
+ else
40
+ s(:for, coll, assgn, block)
45
41
  end
46
- s(type, cond, block, check_at_start)
47
42
  end
48
43
 
49
- def make_until(cond, block, check_at_start)
50
- make_guarded_block(:until, :while, cond, block, check_at_start)
51
- end
52
-
53
- def make_while(cond, block, check_at_start)
54
- make_guarded_block(:while, :until, cond, block, check_at_start)
55
- end
44
+ private
56
45
 
57
46
  def check_at_start?(block)
58
47
  block.sexp_type != :begin
@@ -4,42 +4,50 @@ module RipperRubyParser
4
4
  def process_method_add_arg exp
5
5
  _, call, parens = exp.shift 3
6
6
  call = process(call)
7
- call[3] = process(parens) unless parens.empty?
7
+ unless parens.empty?
8
+ parens = process(parens)
9
+ parens.shift
10
+ end
11
+ parens.each do |arg|
12
+ call << arg
13
+ end
8
14
  call
9
15
  end
10
16
 
11
17
  def process_call exp
12
18
  _, receiver, _, ident = exp.shift 4
13
19
  with_position_from_node_symbol(ident) {|method|
14
- s(:call, process(receiver), method, s(:arglist)) }
20
+ s(:call, process(receiver), method) }
15
21
  end
16
22
 
17
23
  def process_command exp
18
24
  _, ident, arglist = exp.shift 3
19
25
  with_position_from_node_symbol(ident) {|method|
20
- s(:call, nil, method,
21
- handle_potentially_typeless_sexp_with_fallback_type(:arglist, arglist))
26
+ args = handle_potentially_typeless_sexp_with_fallback_type(:arglist, arglist)
27
+ args.shift
28
+ s(:call, nil, method, *args)
22
29
  }
23
30
  end
24
31
 
25
32
  def process_command_call exp
26
33
  _, receiver, _, ident, arguments = exp.shift 5
27
34
  with_position_from_node_symbol(ident) {|method|
28
- s(:call, process(receiver), method,
29
- handle_potentially_typeless_sexp_with_fallback_type(:arglist, arguments))
35
+ args = handle_potentially_typeless_sexp_with_fallback_type(:arglist, arguments)
36
+ args.shift
37
+ s(:call, process(receiver), method, *args)
30
38
  }
31
39
  end
32
40
 
33
41
  def process_vcall exp
34
42
  _, ident = exp.shift 2
35
43
  with_position_from_node_symbol(ident) {|method|
36
- s(:call, nil, method, s(:arglist)) }
44
+ s(:call, nil, method) }
37
45
  end
38
46
 
39
47
  def process_fcall exp
40
48
  _, ident = exp.shift 2
41
49
  with_position_from_node_symbol(ident) {|method|
42
- s(:call, nil, method, s(:arglist)) }
50
+ s(:call, nil, method) }
43
51
  end
44
52
 
45
53
  def process_super exp
@@ -6,15 +6,26 @@ module RipperRubyParser
6
6
  ident, pos = extract_node_symbol_with_position ident
7
7
  params = convert_special_args(process(params))
8
8
  with_position(pos,
9
- s(:defn, ident, params, method_body(body)))
9
+ s(:defn, ident, params, *method_body(body)))
10
10
  end
11
11
 
12
12
  def process_defs exp
13
13
  _, receiver, _, method, params, body = exp.shift 6
14
14
  params = convert_special_args(process(params))
15
- s(:defs, process(receiver),
15
+
16
+ body = in_method do
17
+ process(body)
18
+ end
19
+
20
+ if body.length == 1 && body.first.sexp_type == :block
21
+ body = body.first
22
+ body.shift
23
+ end
24
+
25
+ s(:defs,
26
+ process(receiver),
16
27
  extract_node_symbol(method),
17
- params, in_method { process(body) })
28
+ params, *body)
18
29
  end
19
30
 
20
31
  def process_return exp
@@ -53,13 +64,11 @@ module RipperRubyParser
53
64
  end
54
65
 
55
66
  def process_alias exp
56
- _, *args = exp.shift 3
67
+ _, left, right = exp.shift 3
57
68
 
58
- args.map! do |sub_exp|
59
- make_method_name_literal sub_exp
60
- end
61
-
62
- s(:alias, *args)
69
+ s(:alias,
70
+ make_method_name_literal(left),
71
+ make_method_name_literal(right))
63
72
  end
64
73
 
65
74
  private
@@ -76,12 +85,17 @@ module RipperRubyParser
76
85
  end
77
86
 
78
87
  def method_body exp
79
- scope = in_method { process exp }
80
- block = scope[1]
81
- if block.length == 1
88
+ block = in_method { process exp }
89
+ case block.length
90
+ when 0
82
91
  block.push s(:nil)
92
+ when 1
93
+ if block.first.sexp_type == :block
94
+ block = block.first
95
+ block.shift
96
+ end
83
97
  end
84
- scope
98
+ block
85
99
  end
86
100
 
87
101
  SPECIAL_ARG_MARKER = {
@@ -94,11 +108,23 @@ module RipperRubyParser
94
108
  if item.is_a? Symbol
95
109
  item
96
110
  else
97
- if (marker = SPECIAL_ARG_MARKER[item.sexp_type])
111
+ case item.sexp_type
112
+ when *SPECIAL_ARG_MARKER.keys
113
+ marker = SPECIAL_ARG_MARKER[item.sexp_type]
98
114
  name = extract_node_symbol item[1]
99
115
  :"#{marker}#{name}"
100
- elsif item.sexp_type == :lvar
116
+ when :lvar
101
117
  item[1]
118
+ when :masgn
119
+ args = item[1]
120
+ args.shift
121
+ s(:masgn, *convert_special_args(args))
122
+ when :lasgn
123
+ if item.length == 2
124
+ item[1]
125
+ else
126
+ item
127
+ end
102
128
  else
103
129
  item
104
130
  end
@@ -2,54 +2,60 @@ module RipperRubyParser
2
2
  module SexpHandlers
3
3
  module Operators
4
4
  BINARY_OPERATOR_MAP = {
5
- "&&".to_sym => :and,
6
- "||".to_sym => :or,
5
+ :"&&" => :and,
6
+ :"||" => :or,
7
7
  :and => :and,
8
8
  :or => :or
9
9
  }
10
10
 
11
11
  UNARY_OPERATOR_MAP = {
12
- :"!" => :not,
13
- :not => :not
12
+ :not => :!
14
13
  }
15
14
 
16
15
  NEGATED_BINARY_OPERATOR_MAP = {
17
16
  :"!~" => :=~,
18
- :"!=" => :==
19
17
  }
20
18
 
21
19
  def process_binary exp
22
20
  _, left, op, right = exp.shift 4
23
21
 
24
22
  if op == :=~
25
- if left.sexp_type == :regexp_literal
26
- s(:match2, process(left), process(right))
27
- elsif right.sexp_type == :regexp_literal
28
- s(:match3, process(right), process(left))
29
- else
30
- s(:call, process(left), op, s(:arglist, process(right)))
31
- end
23
+ make_regexp_match_operator(op, left, right)
32
24
  elsif (mapped = NEGATED_BINARY_OPERATOR_MAP[op])
33
- s(:not, process(s(:binary, left, mapped, right)))
25
+ s(:not, make_regexp_match_operator(mapped, left, right))
34
26
  elsif (mapped = BINARY_OPERATOR_MAP[op])
35
- rebalance_binary(s(mapped, process(left), process(right)))
27
+ make_boolean_operator(mapped, left, right)
36
28
  else
37
- s(:call, process(left), op, s(:arglist, process(right)))
29
+ 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
+ else
47
+ s(:call, process(left), op, process(right))
38
48
  end
39
49
  end
40
50
 
41
51
  def process_unary exp
42
52
  _, op, arg = exp.shift 3
43
53
  arg = process(arg)
44
- mapped = UNARY_OPERATOR_MAP[op]
45
- if mapped
46
- s(mapped, arg)
54
+ op = UNARY_OPERATOR_MAP[op] || op
55
+ if is_literal?(arg) && op != :!
56
+ s(:lit, arg[1].send(op))
47
57
  else
48
- if is_literal? arg
49
- s(:lit, arg[1].send(op))
50
- else
51
- s(:call, arg, op, s(:arglist))
52
- end
58
+ s(:call, arg, op)
53
59
  end
54
60
  end
55
61
 
@@ -64,6 +70,17 @@ module RipperRubyParser
64
70
  end
65
71
  end
66
72
 
73
+ def process_dot3 exp
74
+ _, left, right = exp.shift 3
75
+ left = process(left)
76
+ right = process(right)
77
+ if is_literal?(left) && is_literal?(right)
78
+ s(:lit, Range.new(left[1], right[1], true))
79
+ else
80
+ s(:dot3, left, right)
81
+ end
82
+ end
83
+
67
84
  def process_ifop exp
68
85
  _, cond, truepart, falsepart = exp.shift 4
69
86
  s(:if, process(cond), process(truepart), process(falsepart))