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.
- data/lib/ripper_ruby_parser/commenting_sexp_builder.rb +48 -0
- data/lib/ripper_ruby_parser/parser.rb +4 -3
- data/lib/ripper_ruby_parser/sexp_handlers/arguments.rb +6 -2
- data/lib/ripper_ruby_parser/sexp_handlers/arrays.rb +1 -1
- data/lib/ripper_ruby_parser/sexp_handlers/assignment.rb +72 -19
- data/lib/ripper_ruby_parser/sexp_handlers/blocks.rb +68 -4
- data/lib/ripper_ruby_parser/sexp_handlers/helper_methods.rb +42 -14
- data/lib/ripper_ruby_parser/sexp_handlers/literals.rb +41 -25
- data/lib/ripper_ruby_parser/sexp_handlers/loops.rb +20 -0
- data/lib/ripper_ruby_parser/sexp_handlers/method_calls.rb +17 -21
- data/lib/ripper_ruby_parser/sexp_handlers/methods.rb +28 -4
- data/lib/ripper_ruby_parser/sexp_handlers/operators.rb +39 -10
- data/lib/ripper_ruby_parser/sexp_processor.rb +109 -38
- data/lib/ripper_ruby_parser/version.rb +1 -1
- data/test/end_to_end/comments_test.rb +73 -0
- data/test/end_to_end/comparison_test.rb +60 -0
- data/test/end_to_end/line_numbering_test.rb +63 -0
- data/test/test_helper.rb +16 -4
- data/test/unit/commenting_sexp_builder_test.rb +75 -0
- data/test/unit/parser_test.rb +810 -15
- data/test/unit/sexp_processor_test.rb +23 -5
- metadata +19 -12
@@ -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 '
|
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
|
-
|
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
|
-
_,
|
6
|
-
|
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
|
@@ -7,23 +7,22 @@ module RipperRubyParser
|
|
7
7
|
lvalue = process(lvalue)
|
8
8
|
value = process(value)
|
9
9
|
|
10
|
-
|
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 =
|
17
|
+
left = handle_potentially_typeless_sexp left
|
17
18
|
|
18
|
-
left.
|
19
|
-
|
20
|
-
|
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
|
-
|
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
|
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 :
|
72
|
-
s(:
|
108
|
+
when :field
|
109
|
+
s(:attrasgn, lvalue[1], :"#{lvalue[3][1]}=", s(:arglist, value))
|
73
110
|
else
|
74
|
-
|
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,
|
21
|
+
_, normal, defaults, rest, _, block = exp.shift 6
|
22
22
|
|
23
23
|
args = [*normal].map do |id|
|
24
|
-
|
24
|
+
extract_node_symbol id
|
25
25
|
end
|
26
26
|
|
27
27
|
assigns = [*defaults].map do |pair|
|
28
|
-
sym =
|
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
|
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
|
-
|
24
|
-
statements.first
|
25
|
-
else
|
26
|
-
s(:block, *statements)
|
27
|
-
end
|
21
|
+
wrap_in_block(statements)
|
28
22
|
end
|
29
23
|
|
30
|
-
def
|
31
|
-
|
32
|
-
_, ident,
|
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
|
-
|
10
|
+
exp.shift
|
11
11
|
|
12
|
-
string =
|
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
|
-
|
55
|
-
|
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 =
|
62
|
-
|
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
|
93
|
+
string.gsub(/(\\[n\\"])/) do
|
78
94
|
eval "\"#{$1}\""
|
79
95
|
end
|
80
96
|
end
|