ripper_ruby_parser 0.0.1 → 0.0.2

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