ripper_ruby_parser 0.0.1 → 0.0.2

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.
@@ -0,0 +1,48 @@
1
+ require 'ripper'
2
+ module RipperRubyParser
3
+ class CommentingSexpBuilder < Ripper::SexpBuilderPP
4
+ def initialize *args
5
+ super
6
+ @comment = nil
7
+ @comment_stack = []
8
+ end
9
+
10
+ def on_comment tok
11
+ @comment ||= ""
12
+ @comment += tok
13
+ super
14
+ end
15
+
16
+ def on_kw tok
17
+ case tok
18
+ when "class", "def", "module"
19
+ @comment_stack.push @comment
20
+ @comment = nil
21
+ end
22
+ super
23
+ end
24
+
25
+ def on_class *args
26
+ commentize(super)
27
+ end
28
+
29
+ def on_def *args
30
+ commentize(super)
31
+ end
32
+
33
+ def on_module *args
34
+ commentize(super)
35
+ end
36
+
37
+ private
38
+
39
+ def commentize exp
40
+ comment = @comment_stack.pop
41
+ if comment.nil?
42
+ [:comment, "", exp]
43
+ else
44
+ [:comment, comment, exp]
45
+ end
46
+ end
47
+ end
48
+ end
@@ -1,4 +1,4 @@
1
- require 'ripper'
1
+ require 'ripper_ruby_parser/commenting_sexp_builder'
2
2
  require 'ripper_ruby_parser/sexp_processor'
3
3
 
4
4
  module RipperRubyParser
@@ -9,8 +9,9 @@ module RipperRubyParser
9
9
  @processor = processor
10
10
  end
11
11
 
12
- def parse source
13
- exp = Sexp.from_array(Ripper.sexp source)
12
+ def parse source, filename='-', lineno=1
13
+ parser = CommentingSexpBuilder.new(source, filename, lineno)
14
+ exp = Sexp.from_array(parser.parse)
14
15
  @processor.process exp
15
16
  end
16
17
  end
@@ -2,8 +2,12 @@ module RipperRubyParser
2
2
  module SexpHandlers
3
3
  module Arguments
4
4
  def process_args_add_block exp
5
- _, content, _ = exp.shift 3
6
- s(:arglist, *handle_list_with_optional_splat(content))
5
+ _, regular, block = exp.shift 3
6
+ args = handle_potentially_typeless_sexp(regular)
7
+ if block
8
+ args << s(:block_pass, process(block))
9
+ end
10
+ s(:arglist, *args)
7
11
  end
8
12
 
9
13
  def process_args_add_star exp
@@ -3,7 +3,7 @@ module RipperRubyParser
3
3
  module Arrays
4
4
  def process_array exp
5
5
  _, elems = exp.shift 2
6
- s(:array, *handle_list_with_optional_splat(elems))
6
+ s(:array, *handle_potentially_typeless_sexp(elems))
7
7
  end
8
8
 
9
9
  def process_aref exp
@@ -7,23 +7,22 @@ module RipperRubyParser
7
7
  lvalue = process(lvalue)
8
8
  value = process(value)
9
9
 
10
- create_assignment_sub_type lvalue, value
10
+ with_line_number(lvalue.line,
11
+ create_regular_assignment_sub_type(lvalue, value))
11
12
  end
12
13
 
13
14
  def process_massign exp
14
15
  _, left, right = exp.shift 3
15
16
 
16
- left = handle_list_with_optional_splat left
17
+ left = handle_potentially_typeless_sexp left
17
18
 
18
- left.each do |item|
19
- case item.sexp_type
20
- when :splat
21
- item[1][0] = :lasgn
22
- else
23
- item[0] = :lasgn
24
- end
19
+ if left.first == :masgn
20
+ left = left[1]
21
+ left.shift
25
22
  end
26
23
 
24
+ left = create_multiple_assignement_sub_types left
25
+
27
26
  right = process(right)
28
27
 
29
28
  unless right.sexp_type == :array
@@ -44,36 +43,90 @@ module RipperRubyParser
44
43
  generic_add_star exp
45
44
  end
46
45
 
46
+ def process_mlhs_paren exp
47
+ _, contents = exp.shift 2
48
+ items = handle_potentially_typeless_sexp(contents)
49
+
50
+ items = create_multiple_assignement_sub_types items
51
+
52
+ s(:masgn, s(:array, *items))
53
+ end
54
+
47
55
  def process_opassign exp
48
56
  _, lvalue, operator, value = exp.shift 4
49
57
 
50
58
  lvalue = process(lvalue)
51
59
  value = process(value)
52
60
  operator = operator[1].gsub(/=/, '').to_sym
53
- operator_call = s(:call, lvalue, operator, s(:arglist, value))
54
61
 
62
+ create_operator_assignment_sub_type lvalue, value, operator
63
+ end
64
+
65
+ private
66
+
67
+ def create_multiple_assignement_sub_types sexp_list
68
+ sexp_list.map! do |item|
69
+ if item.sexp_type == :splat
70
+ s(:splat, create_valueless_assignment_sub_type(item[1]))
71
+ else
72
+ create_valueless_assignment_sub_type item
73
+ end
74
+ end
75
+ end
76
+
77
+ def create_valueless_assignment_sub_type(item)
78
+ item = with_line_number(item.line,
79
+ create_regular_assignment_sub_type(item, nil))
80
+ if item.sexp_type == :attrasgn
81
+ item.last.pop
82
+ else
83
+ item.pop
84
+ end
85
+ return item
86
+ end
87
+
88
+ def create_operator_assignment_sub_type lvalue, value, operator
55
89
  case lvalue.sexp_type
56
- when :ivar
57
- s(:iasgn, lvalue[1], operator_call)
58
90
  when :aref_field
59
91
  s(:op_asgn1, lvalue[1], s(:arglist, lvalue[2][1]), operator, value)
92
+ when :field
93
+ s(:op_asgn2, lvalue[1], :"#{lvalue[3][1]}=", operator, value)
60
94
  else
61
- s(:lasgn, lvalue[1], operator_call)
95
+ if operator == :"||"
96
+ s(:op_asgn_or, lvalue, create_assignment_sub_type(lvalue, value))
97
+ else
98
+ operator_call = s(:call, lvalue, operator, s(:arglist, value))
99
+ create_assignment_sub_type lvalue, operator_call
100
+ end
62
101
  end
63
102
  end
64
103
 
65
- def create_assignment_sub_type lvalue, value
104
+ def create_regular_assignment_sub_type lvalue, value
66
105
  case lvalue.sexp_type
67
- when :ivar
68
- s(:iasgn, lvalue[1], value)
69
106
  when :aref_field
70
107
  s(:attrasgn, lvalue[1], :[]=, s(:arglist, lvalue[2][1], value))
71
- when :const
72
- s(:cdecl, lvalue[1], value)
108
+ when :field
109
+ s(:attrasgn, lvalue[1], :"#{lvalue[3][1]}=", s(:arglist, value))
73
110
  else
74
- s(:lasgn, lvalue[1], value)
111
+ create_assignment_sub_type lvalue, value
75
112
  end
76
113
  end
114
+
115
+ ASSIGNMENT_SUB_TYPE_MAP = {
116
+ :ivar => :iasgn,
117
+ :const => :cdecl,
118
+ :lvar => :lasgn,
119
+ :cvar => :cvdecl,
120
+ :gvar => :gasgn
121
+ }
122
+
123
+ def create_assignment_sub_type lvalue, value
124
+ s(map_assignment_lvalue_type(lvalue.sexp_type), lvalue[1], value)
125
+ end
126
+
127
+ def map_assignment_lvalue_type type
128
+ ASSIGNMENT_SUB_TYPE_MAP[type] || type
129
+ end
77
130
  end
78
131
  end
79
132
  end
@@ -18,32 +18,96 @@ module RipperRubyParser
18
18
  end
19
19
 
20
20
  def process_params exp
21
- _, normal, defaults, *_ = exp.shift 6
21
+ _, normal, defaults, rest, _, block = exp.shift 6
22
22
 
23
23
  args = [*normal].map do |id|
24
- identifier_node_to_symbol id
24
+ extract_node_symbol id
25
25
  end
26
26
 
27
27
  assigns = [*defaults].map do |pair|
28
- sym = identifier_node_to_symbol pair[0]
28
+ sym = extract_node_symbol pair[0]
29
+ args << sym
29
30
  val = process pair[1]
30
31
  s(:lasgn, sym, val)
31
32
  end
32
33
 
34
+ add_arg_unless_nil(rest, args) {|name| :"*#{name}" }
35
+
36
+ add_arg_unless_nil(block, args) {|name| :"&#{name}" }
37
+
33
38
  if assigns.length > 0
34
- args += assigns.map {|lasgn| lasgn[1]}
35
39
  args << s(:block, *assigns)
36
40
  end
37
41
 
38
42
  s(:args, *args)
39
43
  end
40
44
 
45
+ def process_begin exp
46
+ _, body = exp.shift 2
47
+
48
+ block = process(body)[1]
49
+
50
+ strip_wrapping_block(block)
51
+ end
52
+
53
+ def process_rescue exp
54
+ _, eclass, evar, block, _ = exp.shift 5
55
+ rescue_block = s(*map_body(block))
56
+
57
+ arr = []
58
+ if eclass
59
+ eclass = handle_potentially_typeless_sexp eclass
60
+ if eclass.first.is_a? Symbol
61
+ arr += eclass[1..-1]
62
+ else
63
+ arr << eclass[0]
64
+ end
65
+ end
66
+
67
+ if evar
68
+ evar = process(evar)[1]
69
+ easgn = s(:lasgn, :e, s(:gvar, :$!))
70
+ arr << easgn
71
+ end
72
+
73
+ s(:resbody, s(:array, *arr),
74
+ wrap_in_block(rescue_block))
75
+ end
76
+
77
+ def process_rescue_mod exp
78
+ _, scary, safe = exp.shift 3
79
+ s(:rescue, process(scary), s(:resbody, s(:array), process(safe)))
80
+ end
81
+
82
+ def process_ensure exp
83
+ _, block = exp.shift 2
84
+ wrap_in_block s(*map_body(block))
85
+ end
86
+
41
87
  private
42
88
 
43
89
  def handle_generic_block exp
44
90
  _, args, stmts = exp.shift 3
45
91
  s(:block, process(args), s(handle_statement_list(stmts)))
46
92
  end
93
+
94
+ def strip_wrapping_block(block)
95
+ case block.length
96
+ when 1
97
+ s(:nil)
98
+ when 2
99
+ block[1]
100
+ else
101
+ block
102
+ end
103
+ end
104
+
105
+ def add_arg_unless_nil(item, args)
106
+ unless item.nil?
107
+ name = extract_node_symbol item[1]
108
+ args << yield(name)
109
+ end
110
+ end
47
111
  end
48
112
  end
49
113
  end
@@ -1,13 +1,13 @@
1
1
  module RipperRubyParser
2
2
  module SexpHandlers
3
3
  module HelperMethods
4
- def handle_list_with_optional_splat exp
4
+ def handle_potentially_typeless_sexp exp
5
5
  if exp.nil?
6
- []
6
+ s()
7
7
  elsif exp.first.is_a? Symbol
8
8
  process(exp)
9
9
  else
10
- exp.map { |sub_exp| process(sub_exp) }
10
+ exp.map! { |sub_exp| process(sub_exp) }
11
11
  end
12
12
  end
13
13
 
@@ -16,24 +16,38 @@ module RipperRubyParser
16
16
  end
17
17
 
18
18
  def handle_statement_list exp
19
- statements = exp.
20
- map { |sub_exp| process(sub_exp) }.
21
- reject { |sub_exp| sub_exp.sexp_type == :void_stmt }
19
+ statements = map_body exp
22
20
 
23
- if statements.length == 1
24
- statements.first
25
- else
26
- s(:block, *statements)
27
- end
21
+ wrap_in_block(statements)
28
22
  end
29
23
 
30
- def identifier_node_to_symbol exp
31
- assert_type exp, :@ident
32
- _, ident, _ = exp.shift 3
24
+ def extract_node_symbol_with_position exp
25
+ return nil if exp.nil?
26
+ _, ident, pos = exp.shift 3
27
+ return ident.to_sym, pos
28
+ end
33
29
 
30
+ def extract_node_symbol exp
31
+ return nil if exp.nil?
32
+ _, ident, _ = exp.shift 3
34
33
  ident.to_sym
35
34
  end
36
35
 
36
+ def with_position pos, exp
37
+ (line, _) = pos
38
+ with_line_number line, exp
39
+ end
40
+
41
+ def with_line_number line, exp
42
+ exp.line = line
43
+ exp
44
+ end
45
+
46
+ def with_position_from_node_symbol exp
47
+ sym, pos = extract_node_symbol_with_position exp
48
+ with_position(pos, yield(sym))
49
+ end
50
+
37
51
  def generic_add_star exp
38
52
  _, args, splatarg = exp.shift 3
39
53
  items = args.map { |sub| process(sub) }
@@ -44,6 +58,20 @@ module RipperRubyParser
44
58
  def is_literal? exp
45
59
  exp.sexp_type == :lit
46
60
  end
61
+
62
+ def map_body body
63
+ body.
64
+ map { |sub_exp| process(sub_exp) }.
65
+ reject { |sub_exp| sub_exp.sexp_type == :void_stmt }
66
+ end
67
+
68
+ def wrap_in_block statements
69
+ if statements.length == 1
70
+ statements.first
71
+ else
72
+ s(:block, *statements)
73
+ end
74
+ end
47
75
  end
48
76
  end
49
77
  end
@@ -7,27 +7,9 @@ module RipperRubyParser
7
7
  end
8
8
 
9
9
  def process_string_content exp
10
- _, inner = exp.shift 2
10
+ exp.shift
11
11
 
12
- string = extract_inner_string(inner)
13
- rest = []
14
-
15
- if string.sexp_type == :str
16
- string = string[1]
17
- else
18
- rest << string
19
- string = ""
20
- end
21
-
22
- string = unescape(string)
23
-
24
- until exp.empty? do
25
- result = process(exp.shift)
26
- if result.sexp_type == :str
27
- result[1] = unescape(result[1])
28
- end
29
- rest << result
30
- end
12
+ string, rest = extract_string_parts exp
31
13
 
32
14
  if rest.empty?
33
15
  s(:str, string)
@@ -51,15 +33,23 @@ module RipperRubyParser
51
33
 
52
34
  def process_symbol_literal exp
53
35
  _, symbol = exp.shift 2
54
- sym = symbol[1]
55
- s(:lit, extract_node_symbol(sym))
36
+ process(symbol)
37
+ end
38
+
39
+ def process_symbol exp
40
+ _, node = exp.shift 2
41
+ with_position_from_node_symbol(node) {|sym| s(:lit, sym) }
56
42
  end
57
43
 
58
44
  def process_dyna_symbol exp
59
45
  _, list = exp.shift 2
60
46
 
61
- string = process list[0]
62
- s(:lit, string[1].to_sym)
47
+ string, rest = extract_string_parts list
48
+ if rest.empty?
49
+ s(:lit, string.to_sym)
50
+ else
51
+ s(:dsym, string, *rest)
52
+ end
63
53
  end
64
54
 
65
55
  def process_at_tstring_content exp
@@ -73,8 +63,34 @@ module RipperRubyParser
73
63
  process(exp) || s(:str, "")
74
64
  end
75
65
 
66
+ def extract_string_parts exp
67
+ inner = exp.shift
68
+
69
+ string = extract_inner_string(inner)
70
+ rest = []
71
+
72
+ if string.sexp_type == :str
73
+ string = string[1]
74
+ else
75
+ rest << string
76
+ string = ""
77
+ end
78
+
79
+ string = unescape(string)
80
+
81
+ until exp.empty? do
82
+ result = process(exp.shift)
83
+ if result.sexp_type == :str
84
+ result[1] = unescape(result[1])
85
+ end
86
+ rest << result
87
+ end
88
+
89
+ return string, rest
90
+ end
91
+
76
92
  def unescape string
77
- string.gsub /(\\[n\\"])/ do
93
+ string.gsub(/(\\[n\\"])/) do
78
94
  eval "\"#{$1}\""
79
95
  end
80
96
  end