parser 2.3.0.6 → 2.3.0.7
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.travis.yml +1 -0
- data/CHANGELOG.md +15 -1
- data/README.md +2 -8
- data/lib/parser/base.rb +17 -5
- data/lib/parser/builders/default.rb +17 -5
- data/lib/parser/diagnostic.rb +15 -12
- data/lib/parser/lexer.rl +17 -2
- data/lib/parser/messages.rb +3 -0
- data/lib/parser/source/rewriter.rb +50 -5
- data/lib/parser/source/rewriter/action.rb +15 -3
- data/lib/parser/version.rb +1 -1
- data/test/test_diagnostic.rb +22 -0
- data/test/test_lexer.rb +20 -0
- data/test/test_parser.rb +87 -0
- data/test/test_source_rewriter.rb +61 -0
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 5a26d867d04edc904373d219c6b5a1e96ef04d4d
|
4
|
+
data.tar.gz: 85ac7d2151c8f28584ff798c7e23e12ae1500afe
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ffa1d0b020bcb5802d13cb69477427d9f95d303a53de4addc37acdc82b03ac6abd2cc061e5a1a9fbf1cf6c2407a10c1dbb821ec0ce5c45b8ec103f5138d0894d
|
7
|
+
data.tar.gz: e75209c9674253351150671eed73530c052bbfc122cac1f199163f23cbd77420a2cd7ae7cf8268c059ca12c68a5750acdb74e81433328c5472b8bb81db4b2237
|
data/.travis.yml
CHANGED
data/CHANGELOG.md
CHANGED
@@ -1,6 +1,20 @@
|
|
1
1
|
Changelog
|
2
2
|
=========
|
3
3
|
|
4
|
+
v2.3.0.7 (2016-03-25)
|
5
|
+
---------------------
|
6
|
+
|
7
|
+
API modifications:
|
8
|
+
* Source::Diagnostic: handle ranges pointing to newlines (#273). (whitequark)
|
9
|
+
|
10
|
+
Features implemented:
|
11
|
+
* Parser::Base#tokenize: allow recovery from syntax errors. (whitequark)
|
12
|
+
* lexer.rl: "a=1; a b: 1": allow label after command clashing with local. (whitequark)
|
13
|
+
* lexer.rl: "undef %s(x)": emit %s literals in expr_fname in 2.3 mode. (whitequark)
|
14
|
+
|
15
|
+
Bugs fixed:
|
16
|
+
* Builders::Default: reject non-UTF-8 compatible literals. (whitequark)
|
17
|
+
|
4
18
|
v2.3.0.6 (2016-02-14)
|
5
19
|
---------------------
|
6
20
|
|
@@ -29,7 +43,7 @@ Bugs fixed:
|
|
29
43
|
* Add :csend to Parser::Meta::NODE_TYPES (Markus Schirp)
|
30
44
|
* lexer/dedenter: "\<\<x\n y\\n z\nx": don't dedent after escaped newline. (whitequark)
|
31
45
|
|
32
|
-
v2.3.0.
|
46
|
+
v2.3.0.7 (2016-01-16)
|
33
47
|
---------------------
|
34
48
|
|
35
49
|
v2.3.0.1 (2016-01-14)
|
data/README.md
CHANGED
@@ -227,9 +227,9 @@ issue](https://github.com/whitequark/parser/issues/72).
|
|
227
227
|
|
228
228
|
It is unknown whether any gems are affected by this issue.
|
229
229
|
|
230
|
-
### Invalid characters inside comments
|
230
|
+
### Invalid characters inside comments and literals
|
231
231
|
|
232
|
-
Ruby MRI permits arbitrary non-7-bit
|
232
|
+
Ruby MRI permits arbitrary non-7-bit byte sequences to appear in comments, as well as in string or symbol literals in form of escape sequences, regardless of source encoding. Parser requires all source code, including the expanded escape sequences, to consist of valid byte sequences in the source encoding that are convertible to UTF-8.
|
233
233
|
|
234
234
|
As of 2013-07-25, there are about 180 affected gems.
|
235
235
|
|
@@ -239,12 +239,6 @@ Ruby MRI 1.8 permits to specify a bare `\u` escape sequence in a string; it trea
|
|
239
239
|
|
240
240
|
As of 2013-07-25, affected gems are: activerdf, activerdf_net7, fastreader, gkellog-reddy.
|
241
241
|
|
242
|
-
### Invalid Unicode escape sequences
|
243
|
-
|
244
|
-
Ruby MRI 1.9+ permits to specify invalid Unicode codepoints in Unicode escape sequences, such as `\u{d800}`.
|
245
|
-
|
246
|
-
As of 2013-07-25, affected gems are: aws_cloud_search.
|
247
|
-
|
248
242
|
### Dollar-dash
|
249
243
|
|
250
244
|
(This one is so obscure I couldn't even think of a saner name for this issue.) Pre-2.1 Ruby allows
|
data/lib/parser/base.rb
CHANGED
@@ -167,8 +167,7 @@ module Parser
|
|
167
167
|
end
|
168
168
|
|
169
169
|
##
|
170
|
-
# Parses a source buffer and returns the AST
|
171
|
-
# Ruby source code.
|
170
|
+
# Parses a source buffer and returns the AST and the source code comments.
|
172
171
|
#
|
173
172
|
# @see #parse
|
174
173
|
# @see Parser::Source::Comment#associate
|
@@ -183,6 +182,12 @@ module Parser
|
|
183
182
|
end
|
184
183
|
|
185
184
|
##
|
185
|
+
# Parses a source buffer and returns the AST, the source code comments,
|
186
|
+
# and the tokens emitted by the lexer. If `recover` is true and a fatal
|
187
|
+
# {SyntaxError} is encountered, `nil` is returned instead of the AST, and
|
188
|
+
# comments as well as tokens are only returned up to the location of
|
189
|
+
# the error.
|
190
|
+
#
|
186
191
|
# Currently, token stream format returned by #tokenize is not documented,
|
187
192
|
# but is considered part of a public API and only changed according
|
188
193
|
# to Semantic Versioning.
|
@@ -193,16 +198,23 @@ module Parser
|
|
193
198
|
# `:tSTRING "foo"`; such details must not be relied upon.
|
194
199
|
#
|
195
200
|
# @param [Parser::Source::Buffer] source_buffer
|
201
|
+
# @param [Boolean] recover If true, recover from syntax errors. False by default.
|
196
202
|
# @return [Array]
|
197
203
|
#
|
198
|
-
def tokenize(source_buffer)
|
204
|
+
def tokenize(source_buffer, recover=false)
|
199
205
|
@lexer.tokens = []
|
206
|
+
@lexer.comments = []
|
200
207
|
|
201
|
-
|
208
|
+
begin
|
209
|
+
ast = parse(source_buffer)
|
210
|
+
rescue Parser::SyntaxError
|
211
|
+
raise if !recover
|
212
|
+
end
|
202
213
|
|
203
|
-
[ ast, comments, @lexer.tokens ]
|
214
|
+
[ ast, @lexer.comments, @lexer.tokens ]
|
204
215
|
ensure
|
205
216
|
@lexer.tokens = nil
|
217
|
+
@lexer.comments = nil
|
206
218
|
end
|
207
219
|
|
208
220
|
##
|
@@ -120,12 +120,12 @@ module Parser
|
|
120
120
|
# Strings
|
121
121
|
|
122
122
|
def string(string_t)
|
123
|
-
n(:str, [
|
123
|
+
n(:str, [ string_value(string_t) ],
|
124
124
|
delimited_string_map(string_t))
|
125
125
|
end
|
126
126
|
|
127
127
|
def string_internal(string_t)
|
128
|
-
n(:str, [
|
128
|
+
n(:str, [ string_value(string_t) ],
|
129
129
|
unquoted_map(string_t))
|
130
130
|
end
|
131
131
|
|
@@ -144,7 +144,7 @@ module Parser
|
|
144
144
|
end
|
145
145
|
|
146
146
|
def character(char_t)
|
147
|
-
n(:str, [
|
147
|
+
n(:str, [ string_value(char_t) ],
|
148
148
|
prefix_string_map(char_t))
|
149
149
|
end
|
150
150
|
|
@@ -156,12 +156,12 @@ module Parser
|
|
156
156
|
# Symbols
|
157
157
|
|
158
158
|
def symbol(symbol_t)
|
159
|
-
n(:sym, [
|
159
|
+
n(:sym, [ string_value(symbol_t).to_sym ],
|
160
160
|
prefix_string_map(symbol_t))
|
161
161
|
end
|
162
162
|
|
163
163
|
def symbol_internal(symbol_t)
|
164
|
-
n(:sym, [
|
164
|
+
n(:sym, [ string_value(symbol_t).to_sym ],
|
165
165
|
unquoted_map(symbol_t))
|
166
166
|
end
|
167
167
|
|
@@ -1534,6 +1534,18 @@ module Parser
|
|
1534
1534
|
token[0]
|
1535
1535
|
end
|
1536
1536
|
|
1537
|
+
if defined?(Encoding)
|
1538
|
+
def string_value(token)
|
1539
|
+
unless token[0].valid_encoding?
|
1540
|
+
diagnostic(:error, :invalid_encoding, nil, token[1])
|
1541
|
+
end
|
1542
|
+
|
1543
|
+
token[0]
|
1544
|
+
end
|
1545
|
+
else
|
1546
|
+
alias string_value value
|
1547
|
+
end
|
1548
|
+
|
1537
1549
|
def loc(token)
|
1538
1550
|
# Pass through `nil`s and return nil for tNL.
|
1539
1551
|
token[1] if token && token[0]
|
data/lib/parser/diagnostic.rb
CHANGED
@@ -82,18 +82,19 @@ module Parser
|
|
82
82
|
# @return [Array<String>]
|
83
83
|
#
|
84
84
|
def render
|
85
|
-
if @location.line
|
85
|
+
if @location.line == @location.last_line || @location.is?("\n")
|
86
|
+
["#{@location}: #{@level}: #{message}"] + render_line(@location)
|
87
|
+
else
|
86
88
|
# multi-line diagnostic
|
87
89
|
first_line = first_line_only(@location)
|
88
90
|
last_line = last_line_only(@location)
|
91
|
+
num_lines = (@location.last_line - @location.line) + 1
|
89
92
|
buffer = @location.source_buffer
|
90
93
|
|
91
94
|
last_lineno, last_column = buffer.decompose_position(@location.end_pos)
|
92
95
|
["#{@location}-#{last_lineno}:#{last_column}: #{@level}: #{message}"] +
|
93
|
-
render_line(first_line,
|
96
|
+
render_line(first_line, num_lines > 2, false) +
|
94
97
|
render_line(last_line, false, true)
|
95
|
-
else
|
96
|
-
["#{@location}: #{@level}: #{message}"] + render_line(@location)
|
97
98
|
end
|
98
99
|
end
|
99
100
|
|
@@ -104,7 +105,7 @@ module Parser
|
|
104
105
|
#
|
105
106
|
# @return [Array<String>]
|
106
107
|
#
|
107
|
-
def render_line(range,
|
108
|
+
def render_line(range, ellipsis=false, range_end=false)
|
108
109
|
source_line = range.source_line
|
109
110
|
highlight_line = ' ' * source_line.length
|
110
111
|
|
@@ -115,15 +116,17 @@ module Parser
|
|
115
116
|
end
|
116
117
|
end
|
117
118
|
|
118
|
-
if
|
119
|
-
highlight_line
|
119
|
+
if range.is?("\n")
|
120
|
+
highlight_line += "^"
|
120
121
|
else
|
121
|
-
|
122
|
+
if !range_end && range.size >= 1
|
123
|
+
highlight_line[range.column_range] = '^' + '~' * (range.size - 1)
|
124
|
+
else
|
125
|
+
highlight_line[range.column_range] = '~' * range.size
|
126
|
+
end
|
122
127
|
end
|
123
128
|
|
124
|
-
if
|
125
|
-
highlight_line += '...'
|
126
|
-
end
|
129
|
+
highlight_line += '...' if ellipsis
|
127
130
|
|
128
131
|
[source_line, highlight_line].
|
129
132
|
map { |line| "#{range.source_buffer.name}:#{range.line}: #{line}" }
|
@@ -150,7 +153,7 @@ module Parser
|
|
150
153
|
def last_line_only(range)
|
151
154
|
if range.line != range.last_line
|
152
155
|
Source::Range.new(range.source_buffer,
|
153
|
-
range.begin_pos + (range.source =~ /[^\n]*\
|
156
|
+
range.begin_pos + (range.source =~ /[^\n]*\z/),
|
154
157
|
range.end_pos)
|
155
158
|
else
|
156
159
|
range
|
data/lib/parser/lexer.rl
CHANGED
@@ -1197,7 +1197,7 @@ class Parser::Lexer
|
|
1197
1197
|
emit(:tIDENTIFIER)
|
1198
1198
|
|
1199
1199
|
if !@static_env.nil? && @static_env.declared?(tok)
|
1200
|
-
fnext
|
1200
|
+
fnext expr_endfn; fbreak;
|
1201
1201
|
else
|
1202
1202
|
fnext *arg_or_cmdarg; fbreak;
|
1203
1203
|
end
|
@@ -1282,6 +1282,17 @@ class Parser::Lexer
|
|
1282
1282
|
':'
|
1283
1283
|
=> { fhold; fgoto expr_beg; };
|
1284
1284
|
|
1285
|
+
'%s' c_any
|
1286
|
+
=> {
|
1287
|
+
if version?(23)
|
1288
|
+
type, delimiter = tok[0..-2], tok[-1].chr
|
1289
|
+
fgoto *push_literal(type, delimiter, @ts);
|
1290
|
+
else
|
1291
|
+
p = @ts - 1
|
1292
|
+
fgoto expr_end;
|
1293
|
+
end
|
1294
|
+
};
|
1295
|
+
|
1285
1296
|
w_any;
|
1286
1297
|
|
1287
1298
|
c_any
|
@@ -1697,7 +1708,11 @@ class Parser::Lexer
|
|
1697
1708
|
value = @escape || tok(@ts + 1)
|
1698
1709
|
|
1699
1710
|
if version?(18)
|
1700
|
-
|
1711
|
+
if defined?(Encoding)
|
1712
|
+
emit(:tINTEGER, value.dup.force_encoding(Encoding::BINARY)[0].ord)
|
1713
|
+
else
|
1714
|
+
emit(:tINTEGER, value[0].ord)
|
1715
|
+
end
|
1701
1716
|
else
|
1702
1717
|
emit(:tCHARACTER, value)
|
1703
1718
|
end
|
data/lib/parser/messages.rb
CHANGED
@@ -59,6 +59,9 @@ module Parser
|
|
59
59
|
# Parser warnings
|
60
60
|
:useless_else => 'else without rescue is useless',
|
61
61
|
|
62
|
+
# Parser errors that are not Ruby errors
|
63
|
+
:invalid_encoding => 'literal contains escape sequences incompatible with UTF-8',
|
64
|
+
|
62
65
|
# Rewriter diagnostics
|
63
66
|
:invalid_action => 'cannot %{action}',
|
64
67
|
:clobbered => 'clobbered by: %{action}',
|
@@ -39,6 +39,9 @@ module Parser
|
|
39
39
|
@queue = []
|
40
40
|
@clobber = 0
|
41
41
|
@insertions = 0 # clobbered zero-length positions; index 0 is the far left
|
42
|
+
|
43
|
+
@insert_before_multi_order = 0
|
44
|
+
@insert_after_multi_order = 0
|
42
45
|
end
|
43
46
|
|
44
47
|
##
|
@@ -64,6 +67,28 @@ module Parser
|
|
64
67
|
append Rewriter::Action.new(range.begin, content)
|
65
68
|
end
|
66
69
|
|
70
|
+
##
|
71
|
+
# Inserts new code before the given source range by allowing other
|
72
|
+
# insertions at the same position.
|
73
|
+
# Note that an insertion with latter invocation comes _before_ earlier
|
74
|
+
# insertion at the same position in the rewritten source.
|
75
|
+
#
|
76
|
+
# @example Inserting '[('
|
77
|
+
# rewriter.
|
78
|
+
# insert_before_multi(range, '(').
|
79
|
+
# insert_before_multi(range, '[').
|
80
|
+
# process
|
81
|
+
#
|
82
|
+
# @param [Range] range
|
83
|
+
# @param [String] content
|
84
|
+
# @return [Rewriter] self
|
85
|
+
# @raise [ClobberingError] when clobbering is detected
|
86
|
+
#
|
87
|
+
def insert_before_multi(range, content)
|
88
|
+
@insert_before_multi_order -= 1
|
89
|
+
append Rewriter::Action.new(range.begin, content, true, @insert_before_multi_order)
|
90
|
+
end
|
91
|
+
|
67
92
|
##
|
68
93
|
# Inserts new code after the given source range.
|
69
94
|
#
|
@@ -76,6 +101,28 @@ module Parser
|
|
76
101
|
append Rewriter::Action.new(range.end, content)
|
77
102
|
end
|
78
103
|
|
104
|
+
##
|
105
|
+
# Inserts new code after the given source range by allowing other
|
106
|
+
# insertions at the same position.
|
107
|
+
# Note that an insertion with latter invocation comes _after_ earlier
|
108
|
+
# insertion at the same position in the rewritten source.
|
109
|
+
#
|
110
|
+
# @example Inserting ')]'
|
111
|
+
# rewriter.
|
112
|
+
# insert_after_multi(range, ')').
|
113
|
+
# insert_after_multi(range, ']').
|
114
|
+
# process
|
115
|
+
#
|
116
|
+
# @param [Range] range
|
117
|
+
# @param [String] content
|
118
|
+
# @return [Rewriter] self
|
119
|
+
# @raise [ClobberingError] when clobbering is detected
|
120
|
+
#
|
121
|
+
def insert_after_multi(range, content)
|
122
|
+
@insert_after_multi_order += 1
|
123
|
+
append Rewriter::Action.new(range.end, content, true, @insert_after_multi_order)
|
124
|
+
end
|
125
|
+
|
79
126
|
##
|
80
127
|
# Replaces the code of the source range `range` with `content`.
|
81
128
|
#
|
@@ -102,9 +149,7 @@ module Parser
|
|
102
149
|
adjustment = 0
|
103
150
|
source = @source_buffer.source.dup
|
104
151
|
|
105
|
-
|
106
|
-
|
107
|
-
sorted_queue.each do |action|
|
152
|
+
@queue.sort.each do |action|
|
108
153
|
begin_pos = action.range.begin_pos + adjustment
|
109
154
|
end_pos = begin_pos + action.range.length
|
110
155
|
|
@@ -205,7 +250,7 @@ module Parser
|
|
205
250
|
# Replacing nothing with... nothing?
|
206
251
|
return self if action.replacement.empty?
|
207
252
|
|
208
|
-
if (conflicting = clobbered_insertion?(range))
|
253
|
+
if !action.allow_multiple_insertions? && (conflicting = clobbered_insertion?(range))
|
209
254
|
raise_clobber_error(action, [conflicting])
|
210
255
|
end
|
211
256
|
|
@@ -331,7 +376,7 @@ module Parser
|
|
331
376
|
actions = existing.push(action).sort_by do |a|
|
332
377
|
[a.range.begin_pos, a.range.end_pos]
|
333
378
|
end
|
334
|
-
range = actions.first.range.join(actions.
|
379
|
+
range = actions.first.range.join(actions.max_by { |a| a.range.end_pos }.range)
|
335
380
|
|
336
381
|
Rewriter::Action.new(range, merge_replacements(actions))
|
337
382
|
end
|
@@ -5,14 +5,26 @@ module Parser
|
|
5
5
|
# @api private
|
6
6
|
#
|
7
7
|
class Rewriter::Action
|
8
|
-
|
8
|
+
include Comparable
|
9
9
|
|
10
|
-
|
11
|
-
|
10
|
+
attr_reader :range, :replacement, :allow_multiple_insertions, :order
|
11
|
+
alias_method :allow_multiple_insertions?, :allow_multiple_insertions
|
12
|
+
|
13
|
+
def initialize(range, replacement='', allow_multiple_insertions = false, order = 0)
|
14
|
+
@range = range
|
15
|
+
@replacement = replacement
|
16
|
+
@allow_multiple_insertions = allow_multiple_insertions
|
17
|
+
@order = order
|
12
18
|
|
13
19
|
freeze
|
14
20
|
end
|
15
21
|
|
22
|
+
def <=>(other)
|
23
|
+
result = range.begin_pos <=> other.range.begin_pos
|
24
|
+
return result unless result.zero?
|
25
|
+
order <=> other.order
|
26
|
+
end
|
27
|
+
|
16
28
|
def to_s
|
17
29
|
if @range.length == 0 && @replacement.empty?
|
18
30
|
'do nothing'
|
data/lib/parser/version.rb
CHANGED
data/test/test_diagnostic.rb
CHANGED
@@ -69,4 +69,26 @@ class TestDiagnostic < Minitest::Test
|
|
69
69
|
'(string):3: ~~~ ~~~ '
|
70
70
|
], diag.render)
|
71
71
|
end
|
72
|
+
|
73
|
+
def test_bug_error_on_newline
|
74
|
+
# regression test; see GitHub issue 273
|
75
|
+
source = <<-CODE
|
76
|
+
{
|
77
|
+
foo: ->() # I forgot my brace
|
78
|
+
}
|
79
|
+
}
|
80
|
+
CODE
|
81
|
+
@buffer = Parser::Source::Buffer.new('(string)')
|
82
|
+
@buffer.source = source
|
83
|
+
|
84
|
+
location = Parser::Source::Range.new(@buffer, 33, 34)
|
85
|
+
diag = Parser::Diagnostic.new(:error, :unexpected_token, { :token => 'tNL' },
|
86
|
+
location)
|
87
|
+
|
88
|
+
assert_equal([
|
89
|
+
'(string):2:32: error: unexpected token tNL',
|
90
|
+
'(string):2: foo: ->() # I forgot my brace',
|
91
|
+
'(string):2: ^'
|
92
|
+
], diag.render)
|
93
|
+
end
|
72
94
|
end
|
data/test/test_lexer.rb
CHANGED
@@ -2349,6 +2349,26 @@ class TestLexer < Minitest::Test
|
|
2349
2349
|
:tSYMBOL, 'b', [10, 12])
|
2350
2350
|
end
|
2351
2351
|
|
2352
|
+
def test_fname_pct_s__22
|
2353
|
+
setup_lexer 22
|
2354
|
+
@lex.state = :expr_fname
|
2355
|
+
assert_scanned("%s(a)",
|
2356
|
+
:tPERCENT, '%', [0, 1],
|
2357
|
+
:tIDENTIFIER, 's', [1, 2],
|
2358
|
+
:tLPAREN2, '(', [2, 3],
|
2359
|
+
:tIDENTIFIER, 'a', [3, 4],
|
2360
|
+
:tRPAREN, ')', [4, 5])
|
2361
|
+
end
|
2362
|
+
|
2363
|
+
def test_fname_pct_s__23
|
2364
|
+
setup_lexer 23
|
2365
|
+
@lex.state = :expr_fname
|
2366
|
+
assert_scanned("%s(a)",
|
2367
|
+
:tSYMBEG, '%s(', [0, 3],
|
2368
|
+
:tSTRING_CONTENT, 'a', [3, 4],
|
2369
|
+
:tSTRING_END, ')', [4, 5])
|
2370
|
+
end
|
2371
|
+
|
2352
2372
|
def test_static_env
|
2353
2373
|
env = Parser::StaticEnvironment.new
|
2354
2374
|
env.declare "a"
|
data/test/test_parser.rb
CHANGED
@@ -5114,6 +5114,31 @@ class TestParser < Minitest::Test
|
|
5114
5114
|
end
|
5115
5115
|
end
|
5116
5116
|
|
5117
|
+
def test_tokenize_recover
|
5118
|
+
with_versions(ALL_VERSIONS) do |_ver, parser|
|
5119
|
+
source_file = Parser::Source::Buffer.new('(tokenize)')
|
5120
|
+
source_file.source = "1 + # foo\n "
|
5121
|
+
|
5122
|
+
range = lambda do |from, to|
|
5123
|
+
Parser::Source::Range.new(source_file, from, to)
|
5124
|
+
end
|
5125
|
+
|
5126
|
+
ast, comments, tokens = parser.tokenize(source_file, true)
|
5127
|
+
|
5128
|
+
assert_equal nil, ast
|
5129
|
+
|
5130
|
+
assert_equal [
|
5131
|
+
Parser::Source::Comment.new(range.call(4, 9))
|
5132
|
+
], comments
|
5133
|
+
|
5134
|
+
assert_equal [
|
5135
|
+
[:tINTEGER, [ 1, range.call(0, 1) ]],
|
5136
|
+
[:tPLUS, [ '+', range.call(2, 3) ]],
|
5137
|
+
[:tCOMMENT, [ '# foo', range.call(4, 9) ]],
|
5138
|
+
], tokens
|
5139
|
+
end
|
5140
|
+
end
|
5141
|
+
|
5117
5142
|
#
|
5118
5143
|
# Bug-specific tests
|
5119
5144
|
#
|
@@ -5200,6 +5225,53 @@ class TestParser < Minitest::Test
|
|
5200
5225
|
%Q{f <<-TABLE do\nTABLE\nend})
|
5201
5226
|
end
|
5202
5227
|
|
5228
|
+
def test_bug_ascii_8bit_in_literal
|
5229
|
+
if defined?(Encoding)
|
5230
|
+
assert_diagnoses(
|
5231
|
+
[:error, :invalid_encoding],
|
5232
|
+
%q{".\xc3."},
|
5233
|
+
%q{^^^^^^^^ location},
|
5234
|
+
ALL_VERSIONS)
|
5235
|
+
|
5236
|
+
assert_diagnoses(
|
5237
|
+
[:error, :invalid_encoding],
|
5238
|
+
%q{%W"x .\xc3."},
|
5239
|
+
%q{ ^^^^^^ location},
|
5240
|
+
ALL_VERSIONS)
|
5241
|
+
|
5242
|
+
assert_diagnoses(
|
5243
|
+
[:error, :invalid_encoding],
|
5244
|
+
%q{:".\xc3."},
|
5245
|
+
%q{ ^^^^^^ location},
|
5246
|
+
ALL_VERSIONS)
|
5247
|
+
end
|
5248
|
+
|
5249
|
+
assert_diagnoses(
|
5250
|
+
[:error, :invalid_encoding],
|
5251
|
+
%q{%I"x .\xc3."},
|
5252
|
+
%q{ ^^^^^^ location},
|
5253
|
+
ALL_VERSIONS - %w(1.8 1.9 ios mac))
|
5254
|
+
|
5255
|
+
assert_parses(
|
5256
|
+
s(:int, 0xc3),
|
5257
|
+
%q{?\xc3},
|
5258
|
+
%q{},
|
5259
|
+
%w(1.8))
|
5260
|
+
|
5261
|
+
assert_diagnoses(
|
5262
|
+
[:error, :invalid_encoding],
|
5263
|
+
%q{?\xc3},
|
5264
|
+
%q{^^^^^ location},
|
5265
|
+
ALL_VERSIONS - %w(1.8))
|
5266
|
+
|
5267
|
+
assert_parses(
|
5268
|
+
s(:str, "проверка"),
|
5269
|
+
%q{# coding:utf-8
|
5270
|
+
"\xD0\xBF\xD1\x80\xD0\xBE\xD0\xB2\xD0\xB5\xD1\x80\xD0\xBA\xD0\xB0"},
|
5271
|
+
%q{},
|
5272
|
+
ALL_VERSIONS - %w(1.8))
|
5273
|
+
end
|
5274
|
+
|
5203
5275
|
def test_ruby_bug_9669
|
5204
5276
|
assert_parses(
|
5205
5277
|
s(:def, :a, s(:args, s(:kwarg, :b)), s(:return)),
|
@@ -5318,6 +5390,21 @@ class TestParser < Minitest::Test
|
|
5318
5390
|
ALL_VERSIONS - %w(1.8 1.9 2.0 2.1 2.2 ios mac))
|
5319
5391
|
end
|
5320
5392
|
|
5393
|
+
def test_ruby_bug_12073
|
5394
|
+
assert_parses(
|
5395
|
+
s(:begin,
|
5396
|
+
s(:lvasgn, :a,
|
5397
|
+
s(:int, 1)),
|
5398
|
+
s(:send, nil, :a,
|
5399
|
+
s(:hash,
|
5400
|
+
s(:pair,
|
5401
|
+
s(:sym, :b),
|
5402
|
+
s(:int, 1))))),
|
5403
|
+
%q{a = 1; a b: 1},
|
5404
|
+
%q{},
|
5405
|
+
ALL_VERSIONS - %w(1.8))
|
5406
|
+
end
|
5407
|
+
|
5321
5408
|
def test_parser_bug_198
|
5322
5409
|
assert_parses(
|
5323
5410
|
s(:array,
|
@@ -135,6 +135,16 @@ class TestSourceRewriter < Minitest::Test
|
|
135
135
|
end
|
136
136
|
end
|
137
137
|
|
138
|
+
def test_intentional_multiple_insertions_at_same_location
|
139
|
+
assert_equal 'foo [(bar)] baz',
|
140
|
+
@rewriter.
|
141
|
+
insert_before_multi(range(4, 0), '(').
|
142
|
+
insert_after_multi(range(7, 0), ')').
|
143
|
+
insert_before_multi(range(4, 0), '[').
|
144
|
+
insert_after_multi(range(7, 0), ']').
|
145
|
+
process
|
146
|
+
end
|
147
|
+
|
138
148
|
def test_insertion_within_replace_clobber
|
139
149
|
silence_diagnostics
|
140
150
|
|
@@ -175,6 +185,46 @@ class TestSourceRewriter < Minitest::Test
|
|
175
185
|
end
|
176
186
|
end
|
177
187
|
|
188
|
+
def test_multi_insertion_within_replace_clobber
|
189
|
+
silence_diagnostics
|
190
|
+
|
191
|
+
assert_raises Parser::ClobberingError do
|
192
|
+
@rewriter.
|
193
|
+
replace(range(3, 2), '<').
|
194
|
+
insert_after_multi(range(3, 1), '>')
|
195
|
+
end
|
196
|
+
end
|
197
|
+
|
198
|
+
def test_multi_insertion_within_remove_clobber
|
199
|
+
silence_diagnostics
|
200
|
+
|
201
|
+
assert_raises Parser::ClobberingError do
|
202
|
+
@rewriter.
|
203
|
+
remove(range(3, 2)).
|
204
|
+
insert_after_multi(range(3, 1), '>')
|
205
|
+
end
|
206
|
+
end
|
207
|
+
|
208
|
+
def test_replace_overlapping_multi_insertion_clobber
|
209
|
+
silence_diagnostics
|
210
|
+
|
211
|
+
assert_raises Parser::ClobberingError do
|
212
|
+
@rewriter.
|
213
|
+
insert_after_multi(range(3, 1), '>').
|
214
|
+
replace(range(3, 2), '<')
|
215
|
+
end
|
216
|
+
end
|
217
|
+
|
218
|
+
def test_remove_overlapping_multi_insertion_clobber
|
219
|
+
silence_diagnostics
|
220
|
+
|
221
|
+
assert_raises Parser::ClobberingError do
|
222
|
+
@rewriter.
|
223
|
+
insert_after_multi(range(3, 1), '>').
|
224
|
+
remove(range(3, 2))
|
225
|
+
end
|
226
|
+
end
|
227
|
+
|
178
228
|
def test_insertion_on_merged_insertion_clobber
|
179
229
|
# 2 insertions at the same point clobber each other, even if the 1st one
|
180
230
|
# was merged with an adjacent edit, and even if the same text is being
|
@@ -314,6 +364,17 @@ class TestSourceRewriter < Minitest::Test
|
|
314
364
|
end
|
315
365
|
end
|
316
366
|
|
367
|
+
def test_replaced_ranges_merge_when_furthest_right_range_is_not_furthest_left
|
368
|
+
# regression test; previously, when actions were merged, the resulting
|
369
|
+
# replaced range could be too small sometimes
|
370
|
+
assert_equal 'foo_***_***',
|
371
|
+
@rewriter.
|
372
|
+
replace(range(3, 1), '_').
|
373
|
+
replace(range(7, 1), '_').
|
374
|
+
replace(range(4, 7), '***_***').
|
375
|
+
process
|
376
|
+
end
|
377
|
+
|
317
378
|
def test_clobber
|
318
379
|
diagnostics = []
|
319
380
|
@rewriter.diagnostics.consumer = lambda do |diag|
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: parser
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.3.0.
|
4
|
+
version: 2.3.0.7
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- whitequark
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2016-
|
11
|
+
date: 2016-03-25 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: ast
|