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.
@@ -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
- _, item, idx = exp.shift 3
11
- s(:call, process(item), :[], process(idx))
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 operator == :"||"
111
- s(:op_asgn_or, lvalue, create_assignment_sub_type(lvalue, value))
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
@@ -81,7 +81,7 @@ module RipperRubyParser
81
81
 
82
82
  if evar
83
83
  evar = process(evar)[1]
84
- easgn = s(:lasgn, :e, s(:gvar, :$!))
84
+ easgn = s(:lasgn, evar, s(:gvar, :$!))
85
85
  arr << easgn
86
86
  end
87
87
 
@@ -20,7 +20,35 @@ module RipperRubyParser
20
20
 
21
21
  def process_string_embexpr exp
22
22
  _, list = exp.shift 2
23
- s(:evstr, process(list.first))
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(/(\\[^)])/) do
126
- eval "\"#{$1}\""
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
- s(:until, process(cond), handle_statement_list(block), true)
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.sexp_type != :begin
13
+ check_at_start = check_at_start?(block)
13
14
 
14
- s(:until, process(cond), process(block), check_at_start)
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
- s(:while, process(cond), handle_statement_list(block), true)
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
- left = process(left)
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
- if content.length == 1
52
- process(content.first)
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
@@ -1,3 +1,3 @@
1
1
  module RipperRubyParser
2
- VERSION = '0.0.5'
2
+ VERSION = '0.0.6'
3
3
  end
@@ -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
@@ -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 single-quoted string representing a regex literal with escaped right bracket" do
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 references" do
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.5
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-02 00:00:00.000000000 Z
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: &18762580 !ruby/object:Gem::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: *18762580
24
+ version_requirements: *21062800
25
25
  - !ruby/object:Gem::Dependency
26
26
  name: minitest
27
- requirement: &18762060 !ruby/object:Gem::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: *18762060
35
+ version_requirements: *21062280
36
36
  - !ruby/object:Gem::Dependency
37
37
  name: rake
38
- requirement: &18761580 !ruby/object:Gem::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: *18761580
46
+ version_requirements: *21061800
47
47
  - !ruby/object:Gem::Dependency
48
48
  name: ruby_parser
49
- requirement: &18761100 !ruby/object:Gem::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: *18761100
57
+ version_requirements: *21061320
58
58
  - !ruby/object:Gem::Dependency
59
59
  name: simplecov
60
- requirement: &18760720 !ruby/object:Gem::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: *18760720
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