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