ripper_ruby_parser 0.0.5 → 0.0.6
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/parser.rb +7 -1
- data/lib/ripper_ruby_parser/sexp_handlers/arrays.rb +7 -2
- data/lib/ripper_ruby_parser/sexp_handlers/assignment.rb +7 -2
- data/lib/ripper_ruby_parser/sexp_handlers/blocks.rb +1 -1
- data/lib/ripper_ruby_parser/sexp_handlers/literals.rb +87 -8
- data/lib/ripper_ruby_parser/sexp_handlers/loops.rb +36 -4
- data/lib/ripper_ruby_parser/sexp_handlers/operators.rb +14 -7
- data/lib/ripper_ruby_parser/sexp_processor.rb +10 -6
- data/lib/ripper_ruby_parser/version.rb +1 -1
- data/test/end_to_end/comparison_test.rb +20 -0
- data/test/test_helper.rb +9 -0
- data/test/unit/parser_assignment_test.rb +22 -0
- data/test/unit/parser_blocks_test.rb +12 -0
- data/test/unit/parser_literals_test.rb +179 -0
- data/test/unit/parser_loops_test.rb +52 -0
- data/test/unit/parser_operators_test.rb +13 -0
- data/test/unit/parser_test.rb +28 -5
- metadata +16 -12
@@ -23,7 +23,13 @@ module RipperRubyParser
|
|
23
23
|
|
24
24
|
@processor.filename = filename
|
25
25
|
@processor.extra_compatible = extra_compatible
|
26
|
-
@processor.process exp
|
26
|
+
result = @processor.process exp
|
27
|
+
|
28
|
+
if result == s(:void_stmt)
|
29
|
+
nil
|
30
|
+
else
|
31
|
+
result
|
32
|
+
end
|
27
33
|
end
|
28
34
|
|
29
35
|
private
|
@@ -7,8 +7,13 @@ module RipperRubyParser
|
|
7
7
|
end
|
8
8
|
|
9
9
|
def process_aref exp
|
10
|
-
_,
|
11
|
-
|
10
|
+
_, coll, idx = exp.shift 3
|
11
|
+
|
12
|
+
coll = process(coll)
|
13
|
+
coll = nil if coll == s(:self)
|
14
|
+
|
15
|
+
idx = process(idx) || s(:arglist)
|
16
|
+
s(:call, coll, :[], idx)
|
12
17
|
end
|
13
18
|
end
|
14
19
|
end
|
@@ -98,6 +98,11 @@ module RipperRubyParser
|
|
98
98
|
return item
|
99
99
|
end
|
100
100
|
|
101
|
+
OPERATOR_ASSIGNMENT_MAP = {
|
102
|
+
:"||" => :op_asgn_or,
|
103
|
+
:"&&" => :op_asgn_and
|
104
|
+
}
|
105
|
+
|
101
106
|
def create_operator_assignment_sub_type lvalue, value, operator
|
102
107
|
case lvalue.sexp_type
|
103
108
|
when :aref_field
|
@@ -107,8 +112,8 @@ module RipperRubyParser
|
|
107
112
|
_, obj, _, (_, field) = lvalue
|
108
113
|
s(:op_asgn2, obj, :"#{field}=", operator, value)
|
109
114
|
else
|
110
|
-
if
|
111
|
-
s(
|
115
|
+
if (mapped = OPERATOR_ASSIGNMENT_MAP[operator])
|
116
|
+
s(mapped, lvalue, create_assignment_sub_type(lvalue, value))
|
112
117
|
else
|
113
118
|
operator_call = s(:call, lvalue, operator, s(:arglist, value))
|
114
119
|
create_assignment_sub_type lvalue, operator_call
|
@@ -20,7 +20,35 @@ module RipperRubyParser
|
|
20
20
|
|
21
21
|
def process_string_embexpr exp
|
22
22
|
_, list = exp.shift 2
|
23
|
-
|
23
|
+
val = process(list.first)
|
24
|
+
if val.sexp_type == :str
|
25
|
+
val
|
26
|
+
else
|
27
|
+
s(:evstr, val)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def process_string_dvar exp
|
32
|
+
_, list = exp.shift 2
|
33
|
+
val = process(list)
|
34
|
+
s(:evstr, val)
|
35
|
+
end
|
36
|
+
|
37
|
+
def process_string_concat exp
|
38
|
+
_, left, right = exp.shift 3
|
39
|
+
|
40
|
+
left = process(left)
|
41
|
+
right = process(right)
|
42
|
+
|
43
|
+
if left.sexp_type == :str
|
44
|
+
right[1] = left[1] + right[1]
|
45
|
+
right
|
46
|
+
else # Expecting left.sexp_type == :dstr
|
47
|
+
_, first, *rest = right
|
48
|
+
left.push s(:str, first)
|
49
|
+
left.push(*rest)
|
50
|
+
left
|
51
|
+
end
|
24
52
|
end
|
25
53
|
|
26
54
|
def process_xstring_literal exp
|
@@ -37,11 +65,7 @@ module RipperRubyParser
|
|
37
65
|
_, content, (_, flags, _) = exp.shift 3
|
38
66
|
|
39
67
|
string, rest = extract_string_parts content
|
40
|
-
|
41
|
-
numflags = 0
|
42
|
-
flags =~ /m/ and numflags |= Regexp::MULTILINE
|
43
|
-
flags =~ /x/ and numflags |= Regexp::EXTENDED
|
44
|
-
flags =~ /i/ and numflags |= Regexp::IGNORECASE
|
68
|
+
numflags = character_flags_to_numerical flags
|
45
69
|
|
46
70
|
if rest.empty?
|
47
71
|
s(:lit, Regexp.new(string, numflags))
|
@@ -104,6 +128,11 @@ module RipperRubyParser
|
|
104
128
|
rest << result
|
105
129
|
end
|
106
130
|
|
131
|
+
while not(rest.empty?) and rest.first.sexp_type == :str
|
132
|
+
str = rest.shift
|
133
|
+
string += str[1]
|
134
|
+
end
|
135
|
+
|
107
136
|
return string, rest
|
108
137
|
end
|
109
138
|
|
@@ -121,11 +150,61 @@ module RipperRubyParser
|
|
121
150
|
return string, rest
|
122
151
|
end
|
123
152
|
|
153
|
+
SINGLE_LETTER_ESCAPES = {
|
154
|
+
"a" => "\a",
|
155
|
+
"b" => "\b",
|
156
|
+
"e" => "\e",
|
157
|
+
"f" => "\f",
|
158
|
+
"n" => "\n",
|
159
|
+
"r" => "\r",
|
160
|
+
"s" => "\s",
|
161
|
+
"t" => "\t",
|
162
|
+
"v" => "\v",
|
163
|
+
}
|
164
|
+
|
165
|
+
SINGLE_LETTER_ESCAPES_REGEXP =
|
166
|
+
Regexp.new("^[#{SINGLE_LETTER_ESCAPES.keys.join}]$")
|
167
|
+
|
124
168
|
def unescape string
|
125
|
-
string.gsub(
|
126
|
-
|
169
|
+
string.gsub(/\\(
|
170
|
+
[0-7]{1,3} | # octal character
|
171
|
+
x[0-9a-fA-F]{1,2} | # hex byte
|
172
|
+
u[0-9a-fA-F]{4} | # unicode character
|
173
|
+
C-. | # control (regular)
|
174
|
+
c. | # control (shorthand)
|
175
|
+
. # single-character
|
176
|
+
)/x) do
|
177
|
+
bare = $1
|
178
|
+
case bare
|
179
|
+
when SINGLE_LETTER_ESCAPES_REGEXP
|
180
|
+
SINGLE_LETTER_ESCAPES[bare]
|
181
|
+
when /^x/
|
182
|
+
bare[1..-1].to_i(16).chr
|
183
|
+
when /^u/
|
184
|
+
bare[1..-1].to_i(16).chr(Encoding::UTF_8)
|
185
|
+
when /^(c|C-)(.)$/
|
186
|
+
($2.ord & 0b1001_1111).chr
|
187
|
+
when /^[0-7]+/
|
188
|
+
bare.to_i(8).chr
|
189
|
+
else
|
190
|
+
bare
|
191
|
+
end
|
127
192
|
end
|
128
193
|
end
|
194
|
+
|
195
|
+
def character_flags_to_numerical flags
|
196
|
+
numflags = 0
|
197
|
+
|
198
|
+
flags =~ /m/ and numflags |= Regexp::MULTILINE
|
199
|
+
flags =~ /x/ and numflags |= Regexp::EXTENDED
|
200
|
+
flags =~ /i/ and numflags |= Regexp::IGNORECASE
|
201
|
+
|
202
|
+
flags =~ /n/ and numflags |= Regexp::NOENCODING
|
203
|
+
flags =~ /[ues]/ and numflags |= Regexp::FIXEDENCODING
|
204
|
+
|
205
|
+
numflags
|
206
|
+
end
|
207
|
+
|
129
208
|
end
|
130
209
|
end
|
131
210
|
end
|
@@ -3,20 +3,30 @@ module RipperRubyParser
|
|
3
3
|
module Loops
|
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
8
|
end
|
8
9
|
|
9
10
|
def process_until_mod exp
|
10
11
|
_, cond, block = exp.shift 3
|
11
12
|
|
12
|
-
check_at_start = block
|
13
|
+
check_at_start = check_at_start?(block)
|
13
14
|
|
14
|
-
|
15
|
+
make_until(process(cond), process(block), check_at_start)
|
15
16
|
end
|
16
17
|
|
17
18
|
def process_while exp
|
18
19
|
_, cond, block = exp.shift 3
|
19
|
-
|
20
|
+
|
21
|
+
make_while(process(cond), handle_statement_list(block), true)
|
22
|
+
end
|
23
|
+
|
24
|
+
def process_while_mod exp
|
25
|
+
_, cond, block = exp.shift 3
|
26
|
+
|
27
|
+
check_at_start = check_at_start?(block)
|
28
|
+
|
29
|
+
make_while(process(cond), process(block), check_at_start)
|
20
30
|
end
|
21
31
|
|
22
32
|
def process_for exp
|
@@ -25,6 +35,28 @@ module RipperRubyParser
|
|
25
35
|
s(:lasgn, process(var)[1]),
|
26
36
|
handle_statement_list(block))
|
27
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]
|
45
|
+
end
|
46
|
+
s(type, cond, block, check_at_start)
|
47
|
+
end
|
48
|
+
|
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
|
56
|
+
|
57
|
+
def check_at_start?(block)
|
58
|
+
block.sexp_type != :begin
|
59
|
+
end
|
28
60
|
end
|
29
61
|
end
|
30
62
|
end
|
@@ -20,6 +20,7 @@ module RipperRubyParser
|
|
20
20
|
|
21
21
|
def process_binary exp
|
22
22
|
_, left, op, right = exp.shift 4
|
23
|
+
|
23
24
|
if op == :=~
|
24
25
|
if left.sexp_type == :regexp_literal
|
25
26
|
s(:match2, process(left), process(right))
|
@@ -31,13 +32,7 @@ module RipperRubyParser
|
|
31
32
|
elsif (mapped = NEGATED_BINARY_OPERATOR_MAP[op])
|
32
33
|
s(:not, process(s(:binary, left, mapped, right)))
|
33
34
|
elsif (mapped = BINARY_OPERATOR_MAP[op])
|
34
|
-
|
35
|
-
right = process(right)
|
36
|
-
if mapped == left.sexp_type
|
37
|
-
s(left.sexp_type, left[1], s(mapped, left[2], right))
|
38
|
-
else
|
39
|
-
s(mapped, left, right)
|
40
|
-
end
|
35
|
+
rebalance_binary(s(mapped, process(left), process(right)))
|
41
36
|
else
|
42
37
|
s(:call, process(left), op, s(:arglist, process(right)))
|
43
38
|
end
|
@@ -73,6 +68,18 @@ module RipperRubyParser
|
|
73
68
|
_, cond, truepart, falsepart = exp.shift 4
|
74
69
|
s(:if, process(cond), process(truepart), process(falsepart))
|
75
70
|
end
|
71
|
+
|
72
|
+
private
|
73
|
+
|
74
|
+
def rebalance_binary exp
|
75
|
+
op, left, right = exp
|
76
|
+
|
77
|
+
if op == left.sexp_type
|
78
|
+
s(op, left[1], rebalance_binary(s(op, left[2], right)))
|
79
|
+
else
|
80
|
+
s(op, left, right)
|
81
|
+
end
|
82
|
+
end
|
76
83
|
end
|
77
84
|
end
|
78
85
|
end
|
@@ -48,12 +48,8 @@ module RipperRubyParser
|
|
48
48
|
def process_program exp
|
49
49
|
_, content = exp.shift 2
|
50
50
|
|
51
|
-
|
52
|
-
|
53
|
-
else
|
54
|
-
statements = content.map { |sub_exp| process(sub_exp) }
|
55
|
-
s(:block, *statements)
|
56
|
-
end
|
51
|
+
statements = content.map { |sub_exp| process(sub_exp) }
|
52
|
+
wrap_in_block statements
|
57
53
|
end
|
58
54
|
|
59
55
|
def process_module exp
|
@@ -91,6 +87,10 @@ module RipperRubyParser
|
|
91
87
|
s(:colon2, process(left), extract_node_symbol(right))
|
92
88
|
end
|
93
89
|
|
90
|
+
def process_const_path_field exp
|
91
|
+
s(:const, process_const_path_ref(exp))
|
92
|
+
end
|
93
|
+
|
94
94
|
def process_const_ref exp
|
95
95
|
_, ref = exp.shift 3
|
96
96
|
process(ref)
|
@@ -101,6 +101,10 @@ module RipperRubyParser
|
|
101
101
|
s(:colon3, extract_node_symbol(ref))
|
102
102
|
end
|
103
103
|
|
104
|
+
def process_top_const_field exp
|
105
|
+
s(:const, process_top_const_ref(exp))
|
106
|
+
end
|
107
|
+
|
104
108
|
def process_paren exp
|
105
109
|
_, body = exp.shift 2
|
106
110
|
if body.size == 0
|
@@ -125,5 +125,25 @@ describe "Using RipperRubyParser and RubyParser" do
|
|
125
125
|
formatted(imitation).must_equal formatted(original)
|
126
126
|
end
|
127
127
|
end
|
128
|
+
|
129
|
+
describe "for an example with regular expressions with different encoding flags" do
|
130
|
+
it "gives the same result" do
|
131
|
+
program = <<-END
|
132
|
+
regular = /foo/
|
133
|
+
noenc = /foo/n
|
134
|
+
utf8 = /foo/u
|
135
|
+
euc = /foo/e
|
136
|
+
sjis = /foo/s
|
137
|
+
|
138
|
+
regular = /foo\#{bar}/
|
139
|
+
noenc = /foo\#{bar}/n
|
140
|
+
utf8 = /foo\#{bar}/u
|
141
|
+
euc = /foo\#{bar}/e
|
142
|
+
sjis = /foo\#{bar}/s
|
143
|
+
END
|
144
|
+
|
145
|
+
program.must_be_parsed_as_before
|
146
|
+
end
|
147
|
+
end
|
128
148
|
end
|
129
149
|
|
data/test/test_helper.rb
CHANGED
@@ -36,9 +36,18 @@ class MiniTest::Spec
|
|
36
36
|
result = parser.parse code
|
37
37
|
assert_equal sexp, result
|
38
38
|
end
|
39
|
+
|
40
|
+
def assert_parsed_as_before code
|
41
|
+
oldparser = RubyParser.new
|
42
|
+
newparser = RipperRubyParser::Parser.new
|
43
|
+
expected = oldparser.parse code.dup
|
44
|
+
result = newparser.parse code
|
45
|
+
assert_equal formatted(expected), formatted(result)
|
46
|
+
end
|
39
47
|
end
|
40
48
|
|
41
49
|
module MiniTest::Expectations
|
42
50
|
infect_an_assertion :assert_parsed_as, :must_be_parsed_as
|
51
|
+
infect_an_assertion :assert_parsed_as_before, :must_be_parsed_as_before, :unary
|
43
52
|
end
|
44
53
|
|
@@ -2,6 +2,22 @@ require File.expand_path('../test_helper.rb', File.dirname(__FILE__))
|
|
2
2
|
|
3
3
|
describe RipperRubyParser::Parser do
|
4
4
|
describe "#parse" do
|
5
|
+
describe "for single assignment" do
|
6
|
+
it "works when assigning to a namespaced constant" do
|
7
|
+
"Foo::Bar = baz".
|
8
|
+
must_be_parsed_as s(:cdecl,
|
9
|
+
s(:colon2, s(:const, :Foo), :Bar),
|
10
|
+
s(:call, nil, :baz, s(:arglist)))
|
11
|
+
end
|
12
|
+
|
13
|
+
it "works when assigning to constant in the root namespace" do
|
14
|
+
"::Foo = bar".
|
15
|
+
must_be_parsed_as s(:cdecl,
|
16
|
+
s(:colon3, :Foo),
|
17
|
+
s(:call, nil, :bar, s(:arglist)))
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
5
21
|
describe "for multiple assignment" do
|
6
22
|
specify do
|
7
23
|
"foo, * = bar".
|
@@ -45,6 +61,12 @@ describe RipperRubyParser::Parser do
|
|
45
61
|
:+,
|
46
62
|
s(:call, nil, :qux, s(:arglist)))
|
47
63
|
end
|
64
|
+
|
65
|
+
it "works with &&=" do
|
66
|
+
"foo &&= bar".
|
67
|
+
must_be_parsed_as s(:op_asgn_and,
|
68
|
+
s(:lvar, :foo), s(:lasgn, :foo, s(:call, nil, :bar, s(:arglist))))
|
69
|
+
end
|
48
70
|
end
|
49
71
|
end
|
50
72
|
|
@@ -68,5 +68,17 @@ describe RipperRubyParser::Parser do
|
|
68
68
|
s(:call, nil, :bar, s(:arglist)))
|
69
69
|
end
|
70
70
|
end
|
71
|
+
|
72
|
+
describe "for rescue" do
|
73
|
+
it "works with assignment to an error variable" do
|
74
|
+
"begin; foo; rescue => bar; baz; end".
|
75
|
+
must_be_parsed_as s(:rescue,
|
76
|
+
s(:call, nil, :foo, s(:arglist)),
|
77
|
+
s(:resbody,
|
78
|
+
s(:array,
|
79
|
+
s(:lasgn, :bar, s(:gvar, :$!))),
|
80
|
+
s(:call, nil, :baz, s(:arglist))))
|
81
|
+
end
|
82
|
+
end
|
71
83
|
end
|
72
84
|
end
|
@@ -0,0 +1,179 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
require File.expand_path('../test_helper.rb', File.dirname(__FILE__))
|
3
|
+
|
4
|
+
describe RipperRubyParser::Parser do
|
5
|
+
describe "#parse" do
|
6
|
+
describe "for regexp literals" do
|
7
|
+
it "works with the no-encoding flag" do
|
8
|
+
parser = RipperRubyParser::Parser.new
|
9
|
+
result = parser.parse "/foo/n"
|
10
|
+
# Use inspect since regular == finds no difference between /foo/n
|
11
|
+
# and /foo/
|
12
|
+
result.inspect.must_equal s(:lit, /foo/n).inspect
|
13
|
+
end
|
14
|
+
|
15
|
+
describe "with interpolations" do
|
16
|
+
it "works with the no-encoding flag" do
|
17
|
+
'/foo#{bar}/n'.
|
18
|
+
must_be_parsed_as s(:dregx,
|
19
|
+
"foo",
|
20
|
+
s(:evstr,
|
21
|
+
s(:call, nil, :bar, s(:arglist))), 32)
|
22
|
+
end
|
23
|
+
|
24
|
+
it "works with the unicode-encoding flag" do
|
25
|
+
'/foo#{bar}/u'.
|
26
|
+
must_be_parsed_as s(:dregx,
|
27
|
+
"foo",
|
28
|
+
s(:evstr,
|
29
|
+
s(:call, nil, :bar, s(:arglist))), 16)
|
30
|
+
end
|
31
|
+
|
32
|
+
it "works with the euc-encoding flag" do
|
33
|
+
'/foo#{bar}/e'.
|
34
|
+
must_be_parsed_as s(:dregx,
|
35
|
+
"foo",
|
36
|
+
s(:evstr,
|
37
|
+
s(:call, nil, :bar, s(:arglist))), 16)
|
38
|
+
end
|
39
|
+
|
40
|
+
it "works with the sjis-encoding flag" do
|
41
|
+
'/foo#{bar}/s'.
|
42
|
+
must_be_parsed_as s(:dregx,
|
43
|
+
"foo",
|
44
|
+
s(:evstr,
|
45
|
+
s(:call, nil, :bar, s(:arglist))), 16)
|
46
|
+
end
|
47
|
+
|
48
|
+
describe "containing just a literal string" do
|
49
|
+
it "performs the interpolation when it is at the end" do
|
50
|
+
'/foo#{"bar"}/'.must_be_parsed_as s(:lit, /foobar/)
|
51
|
+
end
|
52
|
+
|
53
|
+
it "performs the interpolation when it is in the middle" do
|
54
|
+
'/foo#{"bar"}baz/'.must_be_parsed_as s(:lit, /foobarbaz/)
|
55
|
+
end
|
56
|
+
|
57
|
+
it "performs the interpolation when it is at the start" do
|
58
|
+
'/#{"foo"}bar/'.must_be_parsed_as s(:lit, /foobar/)
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
describe "for string literals" do
|
65
|
+
describe "with escape sequences" do
|
66
|
+
it "works with hex escapes" do
|
67
|
+
"\"\\x36\"".must_be_parsed_as s(:str, "6")
|
68
|
+
"\"\\x4a\"".must_be_parsed_as s(:str, "J")
|
69
|
+
"\"\\x4A\"".must_be_parsed_as s(:str, "J")
|
70
|
+
"\"\\x3Z\"".must_be_parsed_as s(:str, "\x03Z")
|
71
|
+
end
|
72
|
+
|
73
|
+
it "works with single-letter escapes" do
|
74
|
+
"\"foo\\abar\"".must_be_parsed_as s(:str, "foo\abar")
|
75
|
+
"\"foo\\bbar\"".must_be_parsed_as s(:str, "foo\bbar")
|
76
|
+
"\"foo\\ebar\"".must_be_parsed_as s(:str, "foo\ebar")
|
77
|
+
"\"foo\\fbar\"".must_be_parsed_as s(:str, "foo\fbar")
|
78
|
+
"\"foo\\nbar\"".must_be_parsed_as s(:str, "foo\nbar")
|
79
|
+
"\"foo\\rbar\"".must_be_parsed_as s(:str, "foo\rbar")
|
80
|
+
"\"foo\\sbar\"".must_be_parsed_as s(:str, "foo\sbar")
|
81
|
+
"\"foo\\tbar\"".must_be_parsed_as s(:str, "foo\tbar")
|
82
|
+
"\"foo\\vbar\"".must_be_parsed_as s(:str, "foo\vbar")
|
83
|
+
end
|
84
|
+
|
85
|
+
it "works with octal number escapes" do
|
86
|
+
"\"foo\\123bar\"".must_be_parsed_as s(:str, "foo\123bar")
|
87
|
+
"\"foo\\23bar\"".must_be_parsed_as s(:str, "foo\023bar")
|
88
|
+
"\"foo\\3bar\"".must_be_parsed_as s(:str, "foo\003bar")
|
89
|
+
|
90
|
+
"\"foo\\118bar\"".must_be_parsed_as s(:str, "foo\0118bar")
|
91
|
+
"\"foo\\18bar\"".must_be_parsed_as s(:str, "foo\0018bar")
|
92
|
+
end
|
93
|
+
|
94
|
+
it "works with simple short hand control sequence escapes" do
|
95
|
+
"\"foo\\cabar\"".must_be_parsed_as s(:str, "foo\cabar")
|
96
|
+
"\"foo\\cZbar\"".must_be_parsed_as s(:str, "foo\cZbar")
|
97
|
+
end
|
98
|
+
|
99
|
+
it "works with simple regular control sequence escapes" do
|
100
|
+
"\"foo\\C-abar\"".must_be_parsed_as s(:str, "foo\C-abar")
|
101
|
+
"\"foo\\C-Zbar\"".must_be_parsed_as s(:str, "foo\C-Zbar")
|
102
|
+
end
|
103
|
+
|
104
|
+
# TODO: Implement remaining escape sequence cases.
|
105
|
+
|
106
|
+
# TODO: Behave differently in extra_compatible mode.
|
107
|
+
it "works with unicode escapes (unlike RubyParser)" do
|
108
|
+
"\"foo\\u273bbar\"".must_be_parsed_as s(:str, "foo✻bar")
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
describe "with interpolations" do
|
113
|
+
describe "containing just a literal string" do
|
114
|
+
it "performs the interpolation when it is at the end" do
|
115
|
+
'"foo#{"bar"}"'.must_be_parsed_as s(:str, "foobar")
|
116
|
+
end
|
117
|
+
|
118
|
+
it "performs the interpolation when it is in the middle" do
|
119
|
+
'"foo#{"bar"}baz"'.must_be_parsed_as s(:str, "foobarbaz")
|
120
|
+
end
|
121
|
+
|
122
|
+
it "performs the interpolation when it is at the start" do
|
123
|
+
'"#{"foo"}bar"'.must_be_parsed_as s(:str, "foobar")
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
describe "without braces" do
|
128
|
+
it "works for ivars" do
|
129
|
+
"\"foo\#@bar\"".must_be_parsed_as s(:dstr,
|
130
|
+
"foo",
|
131
|
+
s(:evstr, s(:ivar, :@bar)))
|
132
|
+
end
|
133
|
+
|
134
|
+
it "works for gvars" do
|
135
|
+
"\"foo\#$bar\"".must_be_parsed_as s(:dstr,
|
136
|
+
"foo",
|
137
|
+
s(:evstr, s(:gvar, :$bar)))
|
138
|
+
end
|
139
|
+
|
140
|
+
it "works for cvars" do
|
141
|
+
"\"foo\#@@bar\"".must_be_parsed_as s(:dstr,
|
142
|
+
"foo",
|
143
|
+
s(:evstr, s(:cvar, :@@bar)))
|
144
|
+
end
|
145
|
+
end
|
146
|
+
end
|
147
|
+
|
148
|
+
describe "with string concatenation" do
|
149
|
+
it "performs the concatenation in the case of two simple literal strings" do
|
150
|
+
"\"foo\" \"bar\"".must_be_parsed_as s(:str, "foobar")
|
151
|
+
end
|
152
|
+
|
153
|
+
it "performs the concatenation when the right string has interpolations" do
|
154
|
+
"\"foo\" \"bar\#{baz}\"".
|
155
|
+
must_be_parsed_as s(:dstr,
|
156
|
+
"foobar",
|
157
|
+
s(:evstr, s(:call, nil, :baz, s(:arglist))))
|
158
|
+
end
|
159
|
+
|
160
|
+
it "performs the concatenation when the left string has interpolations" do
|
161
|
+
"\"foo\#{bar}\" \"baz\"".
|
162
|
+
must_be_parsed_as s(:dstr,
|
163
|
+
"foo",
|
164
|
+
s(:evstr, s(:call, nil, :bar, s(:arglist))),
|
165
|
+
s(:str, "baz"))
|
166
|
+
end
|
167
|
+
|
168
|
+
it "performs the concatenation when both strings have interpolations" do
|
169
|
+
"\"foo\#{bar}\" \"baz\#{qux}\"".
|
170
|
+
must_be_parsed_as s(:dstr,
|
171
|
+
"foo",
|
172
|
+
s(:evstr, s(:call, nil, :bar, s(:arglist))),
|
173
|
+
s(:str, "baz"),
|
174
|
+
s(:evstr, s(:call, nil, :qux, s(:arglist))))
|
175
|
+
end
|
176
|
+
end
|
177
|
+
end
|
178
|
+
end
|
179
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
require File.expand_path('../test_helper.rb', File.dirname(__FILE__))
|
2
|
+
|
3
|
+
describe RipperRubyParser::Parser do
|
4
|
+
describe "#parse" do
|
5
|
+
describe "for the while statement" do
|
6
|
+
it "works in the single-line postfix case" do
|
7
|
+
"foo while bar".
|
8
|
+
must_be_parsed_as s(:while,
|
9
|
+
s(:call, nil, :bar, s(:arglist)),
|
10
|
+
s(:call, nil, :foo, s(:arglist)), true)
|
11
|
+
end
|
12
|
+
|
13
|
+
it "works in the block postfix case" do
|
14
|
+
"begin; foo; end while bar".
|
15
|
+
must_be_parsed_as s(:while,
|
16
|
+
s(:call, nil, :bar, s(:arglist)),
|
17
|
+
s(:call, nil, :foo, s(:arglist)), false)
|
18
|
+
end
|
19
|
+
|
20
|
+
it "normalizes a negative condition" do
|
21
|
+
"while not foo; bar; end".
|
22
|
+
must_be_parsed_as s(:until,
|
23
|
+
s(:call, nil, :foo, s(:arglist)),
|
24
|
+
s(:call, nil, :bar, s(:arglist)), true)
|
25
|
+
end
|
26
|
+
|
27
|
+
it "normalizes a negative condition in the postfix case" do
|
28
|
+
"foo while not bar".
|
29
|
+
must_be_parsed_as s(:until,
|
30
|
+
s(:call, nil, :bar, s(:arglist)),
|
31
|
+
s(:call, nil, :foo, s(:arglist)), true)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
describe "for the until statement" do
|
36
|
+
it "normalizes a negative condition" do
|
37
|
+
"until not foo; bar; end".
|
38
|
+
must_be_parsed_as s(:while,
|
39
|
+
s(:call, nil, :foo, s(:arglist)),
|
40
|
+
s(:call, nil, :bar, s(:arglist)), true)
|
41
|
+
|
42
|
+
end
|
43
|
+
|
44
|
+
it "normalizes a negative condition in the postfix case" do
|
45
|
+
"foo until not bar".
|
46
|
+
must_be_parsed_as s(:while,
|
47
|
+
s(:call, nil, :bar, s(:arglist)),
|
48
|
+
s(:call, nil, :foo, s(:arglist)), true)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
@@ -12,5 +12,18 @@ describe RipperRubyParser::Parser do
|
|
12
12
|
s(:call, nil, :bar, s(:arglist)))))
|
13
13
|
end
|
14
14
|
end
|
15
|
+
|
16
|
+
describe "for boolean operators" do
|
17
|
+
it "handles triple :and" do
|
18
|
+
"foo and bar and baz and qux".
|
19
|
+
must_be_parsed_as s(:and,
|
20
|
+
s(:call, nil, :foo, s(:arglist)),
|
21
|
+
s(:and,
|
22
|
+
s(:call, nil, :bar, s(:arglist)),
|
23
|
+
s(:and,
|
24
|
+
s(:call, nil, :baz, s(:arglist)),
|
25
|
+
s(:call, nil, :qux, s(:arglist)))))
|
26
|
+
end
|
27
|
+
end
|
15
28
|
end
|
16
29
|
end
|
data/test/unit/parser_test.rb
CHANGED
@@ -21,6 +21,12 @@ describe RipperRubyParser::Parser do
|
|
21
21
|
sexp_p.verify
|
22
22
|
end
|
23
23
|
|
24
|
+
describe "for an empty program" do
|
25
|
+
it "returns nil" do
|
26
|
+
"".must_be_parsed_as nil
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
24
30
|
describe "for a class declaration" do
|
25
31
|
it "works with a namespaced class name" do
|
26
32
|
result = parser.parse "class Foo::Bar; end"
|
@@ -576,6 +582,17 @@ describe RipperRubyParser::Parser do
|
|
576
582
|
:[],
|
577
583
|
s(:arglist, s(:call, nil, :bar, s(:arglist))))
|
578
584
|
end
|
585
|
+
|
586
|
+
it "works without any indexes" do
|
587
|
+
"foo[]".must_be_parsed_as s(:call, s(:call, nil, :foo, s(:arglist)),
|
588
|
+
:[], s(:arglist))
|
589
|
+
end
|
590
|
+
|
591
|
+
it "drops self from self[]" do
|
592
|
+
"self[foo]".must_be_parsed_as s(:call, nil, :[],
|
593
|
+
s(:arglist,
|
594
|
+
s(:call, nil, :foo, s(:arglist))))
|
595
|
+
end
|
579
596
|
end
|
580
597
|
|
581
598
|
describe "for method definitions" do
|
@@ -981,13 +998,13 @@ describe RipperRubyParser::Parser do
|
|
981
998
|
end
|
982
999
|
|
983
1000
|
it "works for a double-quoted string representing a regex literal with escaped right bracket" do
|
984
|
-
result = parser.parse "\"
|
1001
|
+
result = parser.parse "\"/\\\\)/\""
|
985
1002
|
result.must_equal s(:str, "/\\)/")
|
986
1003
|
end
|
987
1004
|
|
988
|
-
it "works for a
|
989
|
-
result = parser.parse "
|
990
|
-
result.must_equal s(:str, "
|
1005
|
+
it "works for a double-quoted string containing a uselessly escaped right bracket" do
|
1006
|
+
result = parser.parse "\"/\\)/\""
|
1007
|
+
result.must_equal s(:str, "/)/")
|
991
1008
|
end
|
992
1009
|
|
993
1010
|
it "works for a string containing escaped quotes" do
|
@@ -1153,7 +1170,7 @@ describe RipperRubyParser::Parser do
|
|
1153
1170
|
end
|
1154
1171
|
end
|
1155
1172
|
|
1156
|
-
describe "for constant
|
1173
|
+
describe "for constant lookups" do
|
1157
1174
|
it "works when explicitely starting from the root namespace" do
|
1158
1175
|
result = parser.parse "::Foo"
|
1159
1176
|
result.must_equal s(:colon3, :Foo)
|
@@ -1165,6 +1182,12 @@ describe RipperRubyParser::Parser do
|
|
1165
1182
|
s(:colon2, s(:const, :Foo), :Bar),
|
1166
1183
|
:Baz)
|
1167
1184
|
end
|
1185
|
+
|
1186
|
+
it "works looking up a constant in a non-constant" do
|
1187
|
+
"foo::Bar".must_be_parsed_as s(:colon2,
|
1188
|
+
s(:call, nil, :foo, s(:arglist)),
|
1189
|
+
:Bar)
|
1190
|
+
end
|
1168
1191
|
end
|
1169
1192
|
|
1170
1193
|
describe "for variable references" do
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ripper_ruby_parser
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.6
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,11 +9,11 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-04-
|
12
|
+
date: 2012-04-04 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: sexp_processor
|
16
|
-
requirement: &
|
16
|
+
requirement: &21062800 !ruby/object:Gem::Requirement
|
17
17
|
none: false
|
18
18
|
requirements:
|
19
19
|
- - ~>
|
@@ -21,10 +21,10 @@ dependencies:
|
|
21
21
|
version: '3.0'
|
22
22
|
type: :runtime
|
23
23
|
prerelease: false
|
24
|
-
version_requirements: *
|
24
|
+
version_requirements: *21062800
|
25
25
|
- !ruby/object:Gem::Dependency
|
26
26
|
name: minitest
|
27
|
-
requirement: &
|
27
|
+
requirement: &21062280 !ruby/object:Gem::Requirement
|
28
28
|
none: false
|
29
29
|
requirements:
|
30
30
|
- - ~>
|
@@ -32,10 +32,10 @@ dependencies:
|
|
32
32
|
version: 2.11.2
|
33
33
|
type: :development
|
34
34
|
prerelease: false
|
35
|
-
version_requirements: *
|
35
|
+
version_requirements: *21062280
|
36
36
|
- !ruby/object:Gem::Dependency
|
37
37
|
name: rake
|
38
|
-
requirement: &
|
38
|
+
requirement: &21061800 !ruby/object:Gem::Requirement
|
39
39
|
none: false
|
40
40
|
requirements:
|
41
41
|
- - ~>
|
@@ -43,10 +43,10 @@ dependencies:
|
|
43
43
|
version: 0.9.2
|
44
44
|
type: :development
|
45
45
|
prerelease: false
|
46
|
-
version_requirements: *
|
46
|
+
version_requirements: *21061800
|
47
47
|
- !ruby/object:Gem::Dependency
|
48
48
|
name: ruby_parser
|
49
|
-
requirement: &
|
49
|
+
requirement: &21061320 !ruby/object:Gem::Requirement
|
50
50
|
none: false
|
51
51
|
requirements:
|
52
52
|
- - ~>
|
@@ -54,10 +54,10 @@ dependencies:
|
|
54
54
|
version: 2.3.1
|
55
55
|
type: :development
|
56
56
|
prerelease: false
|
57
|
-
version_requirements: *
|
57
|
+
version_requirements: *21061320
|
58
58
|
- !ruby/object:Gem::Dependency
|
59
59
|
name: simplecov
|
60
|
-
requirement: &
|
60
|
+
requirement: &21060940 !ruby/object:Gem::Requirement
|
61
61
|
none: false
|
62
62
|
requirements:
|
63
63
|
- - ! '>='
|
@@ -65,7 +65,7 @@ dependencies:
|
|
65
65
|
version: '0'
|
66
66
|
type: :development
|
67
67
|
prerelease: false
|
68
|
-
version_requirements: *
|
68
|
+
version_requirements: *21060940
|
69
69
|
description:
|
70
70
|
email:
|
71
71
|
- matijs@matijs.net
|
@@ -102,6 +102,7 @@ files:
|
|
102
102
|
- test/end_to_end/test_comparison_test.rb
|
103
103
|
- test/end_to_end/line_numbering_test.rb
|
104
104
|
- test/end_to_end/error_conditions_test.rb
|
105
|
+
- test/unit/parser_literals_test.rb
|
105
106
|
- test/unit/parser_test.rb
|
106
107
|
- test/unit/parser_blocks_test.rb
|
107
108
|
- test/unit/sexp_processor_test.rb
|
@@ -110,6 +111,7 @@ files:
|
|
110
111
|
- test/unit/version_test.rb
|
111
112
|
- test/unit/parser_assignment_test.rb
|
112
113
|
- test/unit/parser_method_calls_test.rb
|
114
|
+
- test/unit/parser_loops_test.rb
|
113
115
|
- test/unit/commenting_sexp_builder_test.rb
|
114
116
|
- README.rdoc
|
115
117
|
- Rakefile
|
@@ -152,6 +154,8 @@ test_files:
|
|
152
154
|
- test/unit/parser_assignment_test.rb
|
153
155
|
- test/unit/parser_blocks_test.rb
|
154
156
|
- test/unit/parser_conditionals_test.rb
|
157
|
+
- test/unit/parser_literals_test.rb
|
158
|
+
- test/unit/parser_loops_test.rb
|
155
159
|
- test/unit/parser_method_calls_test.rb
|
156
160
|
- test/unit/parser_operators_test.rb
|
157
161
|
- test/unit/parser_test.rb
|