parser 2.3.0.pre.6 → 2.3.0.0
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.
- checksums.yaml +4 -4
- data/.travis.yml +3 -2
- data/LICENSE.txt +1 -1
- data/README.md +0 -1
- data/lib/parser.rb +1 -0
- data/lib/parser/builders/default.rb +24 -0
- data/lib/parser/current.rb +28 -13
- data/lib/parser/lexer.rl +86 -61
- data/lib/parser/lexer/dedenter.rb +48 -0
- data/lib/parser/lexer/literal.rb +24 -2
- data/lib/parser/meta.rb +1 -1
- data/lib/parser/ruby23.y +6 -3
- data/lib/parser/source/buffer.rb +29 -10
- data/lib/parser/version.rb +1 -1
- data/test/test_current.rb +2 -0
- data/test/test_lexer.rb +49 -0
- data/test/test_parser.rb +175 -0
- data/test/test_source_buffer.rb +25 -0
- metadata +6 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 8fcc0b8421a588c61ea9d3969ec4f0e1f13c7d8e
|
4
|
+
data.tar.gz: 241d5a150edb29c9f95c7ecd4361d6e2fd4bc4d3
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a4f18eb04354a0230053a4b11db78aef983aebcad4a5edd65688a55b42e3410e9ff73d7f2a1ccb95b249c4e9ed210fdd194168aaa2bb9977a3b4d13eb0521ad2
|
7
|
+
data.tar.gz: 3125b274c9f3040d30494112d95c3788800be632508068421b583d22e04851e45b8a886cdc73bc4359648494847d3e76920682fde0d868f26cc7d660335ca840
|
data/.travis.yml
CHANGED
data/LICENSE.txt
CHANGED
data/README.md
CHANGED
@@ -2,7 +2,6 @@
|
|
2
2
|
|
3
3
|
[](https://badge.fury.io/rb/parser)
|
4
4
|
[](https://travis-ci.org/whitequark/parser)
|
5
|
-
[](https://codeclimate.com/github/whitequark/parser)
|
6
5
|
[](https://coveralls.io/r/whitequark/parser)
|
7
6
|
|
8
7
|
_Parser_ is a production-ready Ruby parser written in pure Ruby. It recognizes as
|
data/lib/parser.rb
CHANGED
@@ -186,6 +186,30 @@ module Parser
|
|
186
186
|
string_map(begin_t, parts, end_t))
|
187
187
|
end
|
188
188
|
|
189
|
+
# Indented (interpolated, noninterpolated, executable) strings
|
190
|
+
|
191
|
+
def dedent_string(node, dedent_level)
|
192
|
+
if !dedent_level.nil?
|
193
|
+
dedenter = Lexer::Dedenter.new(dedent_level)
|
194
|
+
|
195
|
+
if node.type == :str
|
196
|
+
str = node.children.first
|
197
|
+
dedenter.dedent(str)
|
198
|
+
elsif node.type == :dstr || node.type == :xstr
|
199
|
+
node.children.each do |str_node|
|
200
|
+
if str_node.type == :str
|
201
|
+
str = str_node.children.first
|
202
|
+
dedenter.dedent(str)
|
203
|
+
else
|
204
|
+
dedenter.interrupt
|
205
|
+
end
|
206
|
+
end
|
207
|
+
end
|
208
|
+
end
|
209
|
+
|
210
|
+
node
|
211
|
+
end
|
212
|
+
|
189
213
|
# Regular expressions
|
190
214
|
|
191
215
|
def regexp_options(regopt_t)
|
data/lib/parser/current.rb
CHANGED
@@ -10,48 +10,63 @@ module Parser
|
|
10
10
|
|
11
11
|
case RUBY_VERSION
|
12
12
|
when /^1\.8\./
|
13
|
-
|
14
|
-
|
13
|
+
current_version = '1.8.7'
|
14
|
+
if RUBY_VERSION != current_version
|
15
|
+
warn_syntax_deviation 'parser/ruby18', current_version
|
15
16
|
end
|
16
17
|
|
17
18
|
require 'parser/ruby18'
|
18
19
|
CurrentRuby = Ruby18
|
19
20
|
|
20
21
|
when /^1\.9\./
|
21
|
-
|
22
|
-
|
22
|
+
current_version = '1.9.3'
|
23
|
+
if RUBY_VERSION != current_version
|
24
|
+
warn_syntax_deviation 'parser/ruby19', current_version
|
23
25
|
end
|
24
26
|
|
25
27
|
require 'parser/ruby19'
|
26
28
|
CurrentRuby = Ruby19
|
27
29
|
|
28
30
|
when /^2\.0\./
|
29
|
-
|
30
|
-
|
31
|
+
current_version = '2.0.0'
|
32
|
+
if RUBY_VERSION != current_version
|
33
|
+
warn_syntax_deviation 'parser/ruby20', current_version
|
31
34
|
end
|
32
35
|
|
33
36
|
require 'parser/ruby20'
|
34
37
|
CurrentRuby = Ruby20
|
35
38
|
|
36
39
|
when /^2\.1\./
|
37
|
-
|
38
|
-
|
40
|
+
current_version = '2.1.8'
|
41
|
+
if RUBY_VERSION != current_version
|
42
|
+
warn_syntax_deviation 'parser/ruby21', current_version
|
39
43
|
end
|
40
44
|
|
41
45
|
require 'parser/ruby21'
|
42
46
|
CurrentRuby = Ruby21
|
43
47
|
|
44
48
|
when /^2\.2\./
|
45
|
-
|
46
|
-
|
49
|
+
current_version = '2.2.4'
|
50
|
+
if RUBY_VERSION != current_version
|
51
|
+
warn_syntax_deviation 'parser/ruby22', current_version
|
47
52
|
end
|
48
53
|
|
49
54
|
require 'parser/ruby22'
|
50
55
|
CurrentRuby = Ruby22
|
51
56
|
|
52
57
|
when /^2\.3\./
|
53
|
-
|
54
|
-
|
58
|
+
current_version = '2.3.0'
|
59
|
+
if RUBY_VERSION != current_version
|
60
|
+
warn_syntax_deviation 'parser/ruby23', current_version
|
61
|
+
end
|
62
|
+
|
63
|
+
require 'parser/ruby23'
|
64
|
+
CurrentRuby = Ruby23
|
65
|
+
|
66
|
+
when /^2\.4\./
|
67
|
+
current_version = 'HEAD'
|
68
|
+
if RUBY_VERSION != current_version
|
69
|
+
warn_syntax_deviation 'parser/ruby23', current_version
|
55
70
|
end
|
56
71
|
|
57
72
|
require 'parser/ruby23'
|
@@ -59,7 +74,7 @@ module Parser
|
|
59
74
|
|
60
75
|
else # :nocov:
|
61
76
|
# Keep this in sync with released Ruby.
|
62
|
-
warn_syntax_deviation 'parser/
|
77
|
+
warn_syntax_deviation 'parser/ruby23', '2.3.x'
|
63
78
|
require 'parser/ruby22'
|
64
79
|
CurrentRuby = Ruby22
|
65
80
|
end
|
data/lib/parser/lexer.rl
CHANGED
@@ -134,7 +134,7 @@ class Parser::Lexer
|
|
134
134
|
@source = nil # source string
|
135
135
|
@source_pts = nil # @source as a codepoint array
|
136
136
|
@encoding = nil # target encoding for output strings
|
137
|
-
@need_encode
|
137
|
+
@need_encode = nil
|
138
138
|
|
139
139
|
@p = 0 # stream position (saved manually in #advance)
|
140
140
|
@ts = nil # token start
|
@@ -161,15 +161,21 @@ class Parser::Lexer
|
|
161
161
|
@escape_s = nil # starting position of current sequence
|
162
162
|
@escape = nil # last escaped sequence, as string
|
163
163
|
|
164
|
-
#
|
165
|
-
@heredoc_e = nil
|
166
|
-
@herebody_s = nil
|
164
|
+
@herebody_s = nil # starting position of current heredoc line
|
167
165
|
|
168
166
|
# Ruby 1.9 ->() lambdas emit a distinct token if do/{ is
|
169
167
|
# encountered after a matching closing parenthesis.
|
170
168
|
@paren_nest = 0
|
171
169
|
@lambda_stack = []
|
172
170
|
|
171
|
+
# After encountering the closing line of <<~SQUIGGLY_HEREDOC,
|
172
|
+
# we store the indentation level and give it out to the parser
|
173
|
+
# on request. It is not possible to infer indentation level just
|
174
|
+
# from the AST because escape sequences such as `\ ` or `\t` are
|
175
|
+
# expanded inside the lexer, but count as non-whitespace for
|
176
|
+
# indentation purposes.
|
177
|
+
@dedent_level = nil
|
178
|
+
|
173
179
|
# If the lexer is in `command state' (aka expr_value)
|
174
180
|
# at the entry to #advance, it will transition to expr_cmdarg
|
175
181
|
# instead of expr_arg at certain points.
|
@@ -184,26 +190,21 @@ class Parser::Lexer
|
|
184
190
|
|
185
191
|
if @source_buffer
|
186
192
|
@source = @source_buffer.source
|
193
|
+
@need_encode = false
|
187
194
|
|
188
|
-
if
|
195
|
+
if @has_encode
|
189
196
|
@encoding = @source.encoding
|
190
|
-
|
191
|
-
# This is a workaround for 1.9.2, which (without force_encoding)
|
192
|
-
# would convert the result to UTF-8 (source encoding of lexer.rl).
|
193
|
-
@source += "\0".dup.force_encoding(@encoding)
|
194
|
-
else
|
195
|
-
@source += "\0"
|
196
197
|
end
|
197
198
|
|
198
|
-
if
|
199
|
+
if @has_encode && @source.encoding == Encoding::UTF_8
|
199
200
|
@source_pts = @source.unpack('U*')
|
200
|
-
@need_encode = @has_encode && @encoding != Encoding::UTF_8
|
201
201
|
else
|
202
202
|
@source_pts = @source.unpack('C*')
|
203
203
|
end
|
204
204
|
|
205
|
-
if
|
206
|
-
|
205
|
+
if @has_encode &&
|
206
|
+
(@source_pts.size > 1_000_000 || @force_utf32) &&
|
207
|
+
@encoding != Encoding::UTF_32LE
|
207
208
|
# A heuristic: if the buffer is larger than 1M, then
|
208
209
|
# store it in UTF-32 and convert the tokens as they're
|
209
210
|
# going out. If it's smaller, the conversion overhead
|
@@ -216,7 +217,7 @@ class Parser::Lexer
|
|
216
217
|
#
|
217
218
|
# Patches accepted.
|
218
219
|
@source = @source.encode(Encoding::UTF_32LE)
|
219
|
-
@need_encode =
|
220
|
+
@need_encode = true
|
220
221
|
end
|
221
222
|
|
222
223
|
if @source_pts[0] == 0xfeff
|
@@ -275,6 +276,13 @@ class Parser::Lexer
|
|
275
276
|
@cond = @cond_stack.pop
|
276
277
|
end
|
277
278
|
|
279
|
+
def dedent_level
|
280
|
+
# We erase @dedent_level as a precaution to avoid accidentally
|
281
|
+
# using a stale value.
|
282
|
+
dedent_level, @dedent_level = @dedent_level, nil
|
283
|
+
dedent_level
|
284
|
+
end
|
285
|
+
|
278
286
|
# Return next token: [type, value].
|
279
287
|
def advance
|
280
288
|
if @token_queue.any?
|
@@ -293,7 +301,7 @@ class Parser::Lexer
|
|
293
301
|
_lex_from_state_actions = klass.send :_lex_from_state_actions
|
294
302
|
_lex_eof_trans = klass.send :_lex_eof_trans
|
295
303
|
|
296
|
-
pe = @
|
304
|
+
pe = @source_pts.size + 2
|
297
305
|
p, eof = @p, pe
|
298
306
|
|
299
307
|
@command_state = (@cs == klass.lex_en_expr_value ||
|
@@ -309,7 +317,7 @@ class Parser::Lexer
|
|
309
317
|
elsif @cs == klass.lex_error
|
310
318
|
[ false, [ '$error', range(p - 1, p) ] ]
|
311
319
|
else
|
312
|
-
eof = @
|
320
|
+
eof = @source_pts.size + 1
|
313
321
|
[ false, [ '$eof', range(eof, eof) ] ]
|
314
322
|
end
|
315
323
|
end
|
@@ -434,6 +442,8 @@ class Parser::Lexer
|
|
434
442
|
def pop_literal
|
435
443
|
old_literal = @literal_stack.pop
|
436
444
|
|
445
|
+
@dedent_level = old_literal.dedent_level
|
446
|
+
|
437
447
|
if old_literal.type == :tREGEXP_BEG
|
438
448
|
# Fetch modifiers.
|
439
449
|
self.class.lex_en_regexp_modifiers
|
@@ -739,10 +749,10 @@ class Parser::Lexer
|
|
739
749
|
|
740
750
|
# %q[\u123] %q[\u{12]
|
741
751
|
| 'u' ( c_any{0,4} -
|
742
|
-
xdigit{4} -
|
743
|
-
( '{' xdigit{1,3}
|
744
|
-
| '{' xdigit [ \t}] any # \u{1. \u{1} are valid
|
745
|
-
| '{' xdigit{2} [ \t}]
|
752
|
+
xdigit{4} - # \u1234 is valid
|
753
|
+
( '{' xdigit{1,3} # \u{1 \u{12 \u{123 are valid
|
754
|
+
| '{' xdigit [ \t}] any? # \u{1. \u{1} are valid
|
755
|
+
| '{' xdigit{2} [ \t}] # \u{12. \u{12} are valid
|
746
756
|
)
|
747
757
|
)
|
748
758
|
% {
|
@@ -818,10 +828,10 @@ class Parser::Lexer
|
|
818
828
|
# the result is: " i am a heredoc\n"
|
819
829
|
#
|
820
830
|
# To parse them, lexer refers to two kinds (remember, nested heredocs)
|
821
|
-
# of positions in the input stream, namely
|
831
|
+
# of positions in the input stream, namely heredoc_e
|
822
832
|
# (HEREDOC declaration End) and @herebody_s (HEREdoc BODY line Start).
|
823
833
|
#
|
824
|
-
#
|
834
|
+
# heredoc_e is simply contained inside the corresponding Literal, and
|
825
835
|
# when the heredoc is closed, the lexing is restarted from that position.
|
826
836
|
#
|
827
837
|
# @herebody_s is quite more complex. First, @herebody_s changes after each
|
@@ -844,7 +854,7 @@ class Parser::Lexer
|
|
844
854
|
};
|
845
855
|
|
846
856
|
action extend_string {
|
847
|
-
string =
|
857
|
+
string = tok
|
848
858
|
string = string.encode(@encoding) if @need_encode
|
849
859
|
|
850
860
|
# tLABEL_END is only possible in non-cond context on >= 2.2
|
@@ -950,6 +960,9 @@ class Parser::Lexer
|
|
950
960
|
p = current_literal.heredoc_e - 1
|
951
961
|
fnext *pop_literal; fbreak;
|
952
962
|
else
|
963
|
+
# Calculate indentation level for <<~HEREDOCs.
|
964
|
+
current_literal.infer_indent_level(line)
|
965
|
+
|
953
966
|
# Ditto.
|
954
967
|
@herebody_s = @te
|
955
968
|
end
|
@@ -1288,7 +1301,7 @@ class Parser::Lexer
|
|
1288
1301
|
#
|
1289
1302
|
expr_fname := |*
|
1290
1303
|
keyword
|
1291
|
-
=> {
|
1304
|
+
=> { emit_table(KEYWORDS_BEGIN);
|
1292
1305
|
fnext expr_endfn; fbreak; };
|
1293
1306
|
|
1294
1307
|
constant
|
@@ -1642,21 +1655,21 @@ class Parser::Lexer
|
|
1642
1655
|
# /=/ (disambiguation with /=)
|
1643
1656
|
'/' c_any
|
1644
1657
|
=> {
|
1645
|
-
type = delimiter =
|
1658
|
+
type = delimiter = @source[@ts].chr
|
1646
1659
|
fhold; fgoto *push_literal(type, delimiter, @ts);
|
1647
1660
|
};
|
1648
1661
|
|
1649
1662
|
# %<string>
|
1650
1663
|
'%' ( any - [A-Za-z] )
|
1651
1664
|
=> {
|
1652
|
-
type, delimiter =
|
1665
|
+
type, delimiter = @source[@ts].chr, tok[-1].chr
|
1653
1666
|
fgoto *push_literal(type, delimiter, @ts);
|
1654
1667
|
};
|
1655
1668
|
|
1656
1669
|
# %w(we are the people)
|
1657
1670
|
'%' [A-Za-z]+ c_any
|
1658
1671
|
=> {
|
1659
|
-
type, delimiter = tok[0..-2],
|
1672
|
+
type, delimiter = tok[0..-2], @source[@te - 1].chr
|
1660
1673
|
fgoto *push_literal(type, delimiter, @ts);
|
1661
1674
|
};
|
1662
1675
|
|
@@ -1666,27 +1679,36 @@ class Parser::Lexer
|
|
1666
1679
|
};
|
1667
1680
|
|
1668
1681
|
# Heredoc start.
|
1669
|
-
# <<
|
1670
|
-
'
|
1682
|
+
# <<END | <<'END' | <<"END" | <<`END` |
|
1683
|
+
# <<-END | <<-'END' | <<-"END" | <<-`END` |
|
1684
|
+
# <<~END | <<~'END' | <<~"END" | <<~`END`
|
1685
|
+
'<<' [~\-]?
|
1671
1686
|
( '"' ( c_line - '"' )* '"'
|
1672
1687
|
| "'" ( c_line - "'" )* "'"
|
1673
1688
|
| "`" ( c_line - "`" )* "`"
|
1674
|
-
| bareword ) % {
|
1689
|
+
| bareword ) % { heredoc_e = p }
|
1675
1690
|
c_line* c_nl % { new_herebody_s = p }
|
1676
1691
|
=> {
|
1677
|
-
tok(@ts,
|
1692
|
+
tok(@ts, heredoc_e) =~ /^<<(-?)(~?)(["'`]?)(.*)\3$/
|
1678
1693
|
|
1679
|
-
indent
|
1680
|
-
|
1681
|
-
|
1694
|
+
indent = !$1.empty? || !$2.empty?
|
1695
|
+
dedent_body = !$2.empty?
|
1696
|
+
type = '<<' + ($3.empty? ? '"' : $3)
|
1697
|
+
delimiter = $4
|
1682
1698
|
|
1683
|
-
|
1699
|
+
if dedent_body && version?(18, 19, 20, 21, 22)
|
1700
|
+
emit(:tLSHFT, '<<', @ts, @ts + 2)
|
1701
|
+
p = @ts + 1
|
1702
|
+
fnext expr_beg; fbreak;
|
1703
|
+
else
|
1704
|
+
fnext *push_literal(type, delimiter, @ts, heredoc_e, indent, dedent_body);
|
1684
1705
|
|
1685
|
-
|
1686
|
-
|
1687
|
-
|
1706
|
+
if @herebody_s.nil?
|
1707
|
+
@herebody_s = new_herebody_s
|
1708
|
+
end
|
1688
1709
|
|
1689
|
-
|
1710
|
+
p = @herebody_s - 1
|
1711
|
+
end
|
1690
1712
|
};
|
1691
1713
|
|
1692
1714
|
#
|
@@ -1696,7 +1718,7 @@ class Parser::Lexer
|
|
1696
1718
|
# :"bar", :'baz'
|
1697
1719
|
':' ['"] # '
|
1698
1720
|
=> {
|
1699
|
-
type, delimiter = tok,
|
1721
|
+
type, delimiter = tok, @source[@te - 1].chr
|
1700
1722
|
fgoto *push_literal(type, delimiter, @ts);
|
1701
1723
|
};
|
1702
1724
|
|
@@ -1718,7 +1740,9 @@ class Parser::Lexer
|
|
1718
1740
|
# AMBIGUOUS TERNARY OPERATOR
|
1719
1741
|
#
|
1720
1742
|
|
1721
|
-
|
1743
|
+
# Character constant, like ?a, ?\n, ?\u1000, and so on
|
1744
|
+
# Don't accept \u escape with multiple codepoints, like \u{1 2 3}
|
1745
|
+
'?' ( e_bs ( escape - ( '\u{' (xdigit+ [ \t]+)+ xdigit+ '}' ))
|
1722
1746
|
| (c_any - c_space_nl - e_bs) % { @escape = nil }
|
1723
1747
|
)
|
1724
1748
|
=> {
|
@@ -1739,7 +1763,7 @@ class Parser::Lexer
|
|
1739
1763
|
'?' c_space_nl
|
1740
1764
|
=> {
|
1741
1765
|
escape = { " " => '\s', "\r" => '\r', "\n" => '\n', "\t" => '\t',
|
1742
|
-
"\v" => '\v', "\f" => '\f' }[
|
1766
|
+
"\v" => '\v', "\f" => '\f' }[@source[@ts + 1]]
|
1743
1767
|
diagnostic :warning, :invalid_escape_use, { :escape => escape }, range
|
1744
1768
|
|
1745
1769
|
p = @ts - 1
|
@@ -1769,16 +1793,19 @@ class Parser::Lexer
|
|
1769
1793
|
@lambda_stack.pop
|
1770
1794
|
emit(:tLAMBEG)
|
1771
1795
|
else
|
1772
|
-
|
1796
|
+
emit(:tLBRACE)
|
1773
1797
|
end
|
1774
1798
|
fbreak;
|
1775
1799
|
};
|
1776
1800
|
|
1777
1801
|
# a([1, 2])
|
1778
|
-
e_lbrack
|
1802
|
+
e_lbrack
|
1803
|
+
=> { emit(:tLBRACK)
|
1804
|
+
fbreak; };
|
1805
|
+
|
1779
1806
|
# a()
|
1780
1807
|
e_lparen
|
1781
|
-
=> {
|
1808
|
+
=> { emit(:tLPAREN)
|
1782
1809
|
fbreak; };
|
1783
1810
|
|
1784
1811
|
# a(+b)
|
@@ -1789,7 +1816,7 @@ class Parser::Lexer
|
|
1789
1816
|
# rescue Exception => e: Block rescue.
|
1790
1817
|
# Special because it should transition to expr_mid.
|
1791
1818
|
'rescue' %{ tm = p } '=>'?
|
1792
|
-
=> {
|
1819
|
+
=> { emit(:kRESCUE, tok(@ts, tm), @ts, tm)
|
1793
1820
|
p = tm - 1
|
1794
1821
|
fnext expr_mid; fbreak; };
|
1795
1822
|
|
@@ -1809,7 +1836,7 @@ class Parser::Lexer
|
|
1809
1836
|
if version?(18)
|
1810
1837
|
ident = tok(@ts, @te - 2)
|
1811
1838
|
|
1812
|
-
emit((
|
1839
|
+
emit((@source[@ts] =~ /[A-Z]/) ? :tCONSTANT : :tIDENTIFIER,
|
1813
1840
|
ident, @ts, @te - 2)
|
1814
1841
|
fhold; # continue as a symbol
|
1815
1842
|
|
@@ -1898,7 +1925,7 @@ class Parser::Lexer
|
|
1898
1925
|
# "bar", 'baz'
|
1899
1926
|
['"] # '
|
1900
1927
|
=> {
|
1901
|
-
fgoto *push_literal(tok, tok, @ts
|
1928
|
+
fgoto *push_literal(tok, tok, @ts);
|
1902
1929
|
};
|
1903
1930
|
|
1904
1931
|
w_space_comment;
|
@@ -1919,7 +1946,7 @@ class Parser::Lexer
|
|
1919
1946
|
|
1920
1947
|
'->'
|
1921
1948
|
=> {
|
1922
|
-
|
1949
|
+
emit(:tLAMBDA, tok(@ts, @ts + 2), @ts, @ts + 2)
|
1923
1950
|
|
1924
1951
|
@lambda_stack.push @paren_nest
|
1925
1952
|
fnext expr_endfn; fbreak;
|
@@ -1937,7 +1964,7 @@ class Parser::Lexer
|
|
1937
1964
|
end
|
1938
1965
|
else
|
1939
1966
|
if tok == '{'
|
1940
|
-
|
1967
|
+
emit(:tLCURLY)
|
1941
1968
|
else # 'do'
|
1942
1969
|
emit_do
|
1943
1970
|
end
|
@@ -1989,13 +2016,11 @@ class Parser::Lexer
|
|
1989
2016
|
if version?(18)
|
1990
2017
|
emit(:tIDENTIFIER)
|
1991
2018
|
|
1992
|
-
|
1993
|
-
fnext expr_end;
|
1994
|
-
else
|
2019
|
+
unless !@static_env.nil? && @static_env.declared?(tok)
|
1995
2020
|
fnext *arg_or_cmdarg;
|
1996
2021
|
end
|
1997
2022
|
else
|
1998
|
-
|
2023
|
+
emit(:k__ENCODING__)
|
1999
2024
|
end
|
2000
2025
|
fbreak;
|
2001
2026
|
};
|
@@ -2093,8 +2118,8 @@ class Parser::Lexer
|
|
2093
2118
|
# `echo foo`, "bar", 'baz'
|
2094
2119
|
'`' | ['"] # '
|
2095
2120
|
=> {
|
2096
|
-
type, delimiter = tok,
|
2097
|
-
fgoto *push_literal(type, delimiter, @ts, nil, false, true);
|
2121
|
+
type, delimiter = tok, @source[@te - 1].chr
|
2122
|
+
fgoto *push_literal(type, delimiter, @ts, nil, false, false, true);
|
2098
2123
|
};
|
2099
2124
|
|
2100
2125
|
#
|
@@ -2166,11 +2191,11 @@ class Parser::Lexer
|
|
2166
2191
|
fnext expr_beg; fbreak; };
|
2167
2192
|
|
2168
2193
|
'?'
|
2169
|
-
=> {
|
2194
|
+
=> { emit(:tEH)
|
2170
2195
|
fnext expr_value; fbreak; };
|
2171
2196
|
|
2172
2197
|
e_lbrack
|
2173
|
-
=> {
|
2198
|
+
=> { emit(:tLBRACK2)
|
2174
2199
|
fnext expr_beg; fbreak; };
|
2175
2200
|
|
2176
2201
|
punctuation_end
|
@@ -2187,7 +2212,7 @@ class Parser::Lexer
|
|
2187
2212
|
=> { fgoto leading_dot; };
|
2188
2213
|
|
2189
2214
|
';'
|
2190
|
-
=> {
|
2215
|
+
=> { emit(:tSEMI)
|
2191
2216
|
fnext expr_value; fbreak; };
|
2192
2217
|
|
2193
2218
|
'\\' c_line {
|
@@ -0,0 +1,48 @@
|
|
1
|
+
module Parser
|
2
|
+
|
3
|
+
class Lexer::Dedenter
|
4
|
+
def initialize(dedent_level)
|
5
|
+
@dedent_level = dedent_level
|
6
|
+
@at_line_begin = true
|
7
|
+
@indent_level = 0
|
8
|
+
end
|
9
|
+
|
10
|
+
def dedent(string)
|
11
|
+
space_begin = space_end = offset = 0
|
12
|
+
string.chars.each_with_index do |char, index|
|
13
|
+
if @at_line_begin
|
14
|
+
if char == ?\n || @indent_level >= @dedent_level
|
15
|
+
string.slice!(space_begin...space_end)
|
16
|
+
offset += space_end - space_begin - 1
|
17
|
+
@at_line_begin = false
|
18
|
+
redo if char == ?\n
|
19
|
+
end
|
20
|
+
|
21
|
+
case char
|
22
|
+
when ?\s
|
23
|
+
@indent_level += 1
|
24
|
+
space_end += 1
|
25
|
+
when ?\t
|
26
|
+
@indent_level += 8 - @indent_level % 8
|
27
|
+
space_end += 1
|
28
|
+
end
|
29
|
+
elsif char == ?\n
|
30
|
+
@at_line_begin = true
|
31
|
+
@indent_level = 0
|
32
|
+
space_begin = space_end = index - offset + 1
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
if @at_line_begin
|
37
|
+
string.slice!(space_begin..space_end)
|
38
|
+
end
|
39
|
+
|
40
|
+
nil
|
41
|
+
end
|
42
|
+
|
43
|
+
def interrupt
|
44
|
+
@at_line_begin = false
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
end
|
data/lib/parser/lexer/literal.rb
CHANGED
@@ -34,11 +34,11 @@ module Parser
|
|
34
34
|
'<<`' => [ :tXSTRING_BEG, true ],
|
35
35
|
}
|
36
36
|
|
37
|
-
attr_reader :heredoc_e, :str_s
|
37
|
+
attr_reader :heredoc_e, :str_s, :dedent_level
|
38
38
|
attr_accessor :saved_herebody_s
|
39
39
|
|
40
40
|
def initialize(lexer, str_type, delimiter, str_s, heredoc_e = nil,
|
41
|
-
indent = false, label_allowed = false)
|
41
|
+
indent = false, dedent_body = false, label_allowed = false)
|
42
42
|
@lexer = lexer
|
43
43
|
@nesting = 1
|
44
44
|
|
@@ -65,6 +65,9 @@ module Parser
|
|
65
65
|
@indent = indent
|
66
66
|
@label_allowed = label_allowed
|
67
67
|
|
68
|
+
@dedent_body = dedent_body
|
69
|
+
@dedent_level = nil
|
70
|
+
|
68
71
|
@interp_braces = 0
|
69
72
|
|
70
73
|
@space_emitted = true
|
@@ -150,6 +153,25 @@ module Parser
|
|
150
153
|
end
|
151
154
|
end
|
152
155
|
|
156
|
+
def infer_indent_level(line)
|
157
|
+
return if !@dedent_body
|
158
|
+
|
159
|
+
indent_level = 0
|
160
|
+
line.each_char do |char|
|
161
|
+
case char
|
162
|
+
when ?\s
|
163
|
+
indent_level += 1
|
164
|
+
when ?\t
|
165
|
+
indent_level += (8 - indent_level % 8)
|
166
|
+
else
|
167
|
+
if @dedent_level.nil? || @dedent_level > indent_level
|
168
|
+
@dedent_level = indent_level
|
169
|
+
end
|
170
|
+
break
|
171
|
+
end
|
172
|
+
end
|
173
|
+
end
|
174
|
+
|
153
175
|
def start_interp_brace
|
154
176
|
@interp_braces += 1
|
155
177
|
end
|
data/lib/parser/meta.rb
CHANGED
@@ -6,7 +6,7 @@ module Parser
|
|
6
6
|
# will be able to produce every possible node.
|
7
7
|
NODE_TYPES =
|
8
8
|
%w(
|
9
|
-
true false nil int float str dstr
|
9
|
+
true false nil int float str dstr
|
10
10
|
sym dsym xstr regopt regexp array splat
|
11
11
|
array pair kwsplat hash irange erange self
|
12
12
|
lvar ivar cvar gvar const defined? lvasgn
|
data/lib/parser/ruby23.y
CHANGED
@@ -1676,11 +1676,13 @@ opt_block_args_tail:
|
|
1676
1676
|
|
1677
1677
|
string1: tSTRING_BEG string_contents tSTRING_END
|
1678
1678
|
{
|
1679
|
-
|
1679
|
+
string = @builder.string_compose(val[0], val[1], val[2])
|
1680
|
+
result = @builder.dedent_string(string, @lexer.dedent_level)
|
1680
1681
|
}
|
1681
1682
|
| tSTRING
|
1682
1683
|
{
|
1683
|
-
|
1684
|
+
string = @builder.string(val[0])
|
1685
|
+
result = @builder.dedent_string(string, @lexer.dedent_level)
|
1684
1686
|
}
|
1685
1687
|
| tCHARACTER
|
1686
1688
|
{
|
@@ -1689,7 +1691,8 @@ opt_block_args_tail:
|
|
1689
1691
|
|
1690
1692
|
xstring: tXSTRING_BEG xstring_contents tSTRING_END
|
1691
1693
|
{
|
1692
|
-
|
1694
|
+
string = @builder.xstring_compose(val[0], val[1], val[2])
|
1695
|
+
result = @builder.dedent_string(string, @lexer.dedent_level)
|
1693
1696
|
}
|
1694
1697
|
|
1695
1698
|
regexp: tREGEXP_BEG regexp_contents tSTRING_END tREGEXP_OPT
|
data/lib/parser/source/buffer.rb
CHANGED
@@ -190,6 +190,25 @@ module Parser
|
|
190
190
|
[ @first_line + line_no, position - line_begin ]
|
191
191
|
end
|
192
192
|
|
193
|
+
##
|
194
|
+
# Return an `Array` of source code lines.
|
195
|
+
#
|
196
|
+
# @return [Array<String>]
|
197
|
+
#
|
198
|
+
def source_lines
|
199
|
+
@lines ||= begin
|
200
|
+
lines = @source.lines.to_a
|
201
|
+
lines << '' if @source.end_with?("\n")
|
202
|
+
|
203
|
+
lines.each do |line|
|
204
|
+
line.chomp!(NEW_LINE)
|
205
|
+
line.freeze
|
206
|
+
end
|
207
|
+
|
208
|
+
lines.freeze
|
209
|
+
end
|
210
|
+
end
|
211
|
+
|
193
212
|
##
|
194
213
|
# Extract line `lineno` from source, taking `first_line` into account.
|
195
214
|
#
|
@@ -198,16 +217,7 @@ module Parser
|
|
198
217
|
# @raise [IndexError] if `lineno` is out of bounds
|
199
218
|
#
|
200
219
|
def source_line(lineno)
|
201
|
-
|
202
|
-
@lines = @source.lines.to_a
|
203
|
-
@lines.each { |line| line.chomp!(NEW_LINE) }
|
204
|
-
|
205
|
-
# If a file ends with a newline, the EOF token will appear
|
206
|
-
# to be one line further than the end of file.
|
207
|
-
@lines << ""
|
208
|
-
end
|
209
|
-
|
210
|
-
@lines.fetch(lineno - @first_line).dup
|
220
|
+
source_lines.fetch(lineno - @first_line).dup
|
211
221
|
end
|
212
222
|
|
213
223
|
##
|
@@ -230,6 +240,15 @@ module Parser
|
|
230
240
|
end
|
231
241
|
end
|
232
242
|
|
243
|
+
##
|
244
|
+
# Number of last line in the buffer
|
245
|
+
#
|
246
|
+
# @return [Integer]
|
247
|
+
#
|
248
|
+
def last_line
|
249
|
+
line_begins.size + @first_line - 1
|
250
|
+
end
|
251
|
+
|
233
252
|
private
|
234
253
|
|
235
254
|
def line_begins
|
data/lib/parser/version.rb
CHANGED
data/test/test_current.rb
CHANGED
@@ -16,6 +16,8 @@ class TestCurrent < Minitest::Test
|
|
16
16
|
assert_equal Parser::Ruby22, Parser::CurrentRuby
|
17
17
|
when /^2\.3\.\d+/
|
18
18
|
assert_equal Parser::Ruby23, Parser::CurrentRuby
|
19
|
+
when /^2\.4\.\d+/
|
20
|
+
assert_equal Parser::Ruby23, Parser::CurrentRuby
|
19
21
|
else
|
20
22
|
flunk "Update test_current for #{RUBY_VERSION}"
|
21
23
|
end
|
data/test/test_lexer.rb
CHANGED
@@ -1107,6 +1107,55 @@ class TestLexer < Minitest::Test
|
|
1107
1107
|
assert_scanned '?\M-\C-a', :tCHARACTER, "\M-\C-a"
|
1108
1108
|
end
|
1109
1109
|
|
1110
|
+
def test_question_eh_escape_u_1_digit
|
1111
|
+
setup_lexer 19
|
1112
|
+
|
1113
|
+
refute_scanned '?\\u1'
|
1114
|
+
end
|
1115
|
+
|
1116
|
+
def test_question_eh_escape_u_2_digits
|
1117
|
+
setup_lexer 19
|
1118
|
+
|
1119
|
+
refute_scanned '?\\u12'
|
1120
|
+
end
|
1121
|
+
|
1122
|
+
def test_question_eh_escape_u_3_digits
|
1123
|
+
setup_lexer 19
|
1124
|
+
|
1125
|
+
refute_scanned '?\\u123'
|
1126
|
+
end
|
1127
|
+
|
1128
|
+
def test_question_eh_escape_u_4_digits
|
1129
|
+
if RUBY_VERSION >= '1.9'
|
1130
|
+
setup_lexer 19
|
1131
|
+
assert_scanned '?\\u0001', :tCHARACTER, "\u0001"
|
1132
|
+
end
|
1133
|
+
end
|
1134
|
+
|
1135
|
+
def test_question_eh_single_unicode_point
|
1136
|
+
if RUBY_VERSION >= '1.9'
|
1137
|
+
setup_lexer 19
|
1138
|
+
assert_scanned '?\\u{123}', :tCHARACTER, "\u0123"
|
1139
|
+
|
1140
|
+
setup_lexer 19
|
1141
|
+
assert_scanned '?\\u{a}', :tCHARACTER, "\n"
|
1142
|
+
end
|
1143
|
+
end
|
1144
|
+
|
1145
|
+
def test_question_eh_multiple_unicode_points
|
1146
|
+
setup_lexer 19
|
1147
|
+
refute_scanned '?\\u{1 2 3}'
|
1148
|
+
|
1149
|
+
setup_lexer 19
|
1150
|
+
refute_scanned '?\\u{a b}'
|
1151
|
+
end
|
1152
|
+
|
1153
|
+
def test_question_eh_escape_u_unclosed_bracket
|
1154
|
+
setup_lexer 19
|
1155
|
+
|
1156
|
+
refute_scanned '?\\u{123'
|
1157
|
+
end
|
1158
|
+
|
1110
1159
|
def test_integer_hex
|
1111
1160
|
assert_scanned "0x2a", :tINTEGER, 42
|
1112
1161
|
end
|
data/test/test_parser.rb
CHANGED
@@ -262,6 +262,159 @@ class TestParser < Minitest::Test
|
|
262
262
|
| ~~~~ heredoc_end})
|
263
263
|
end
|
264
264
|
|
265
|
+
def test_dedenting_heredoc
|
266
|
+
assert_parses(
|
267
|
+
s(:begin,
|
268
|
+
s(:send,
|
269
|
+
s(:send, nil, :p), :<<,
|
270
|
+
s(:send,
|
271
|
+
s(:const, nil, :E), :~)),
|
272
|
+
s(:const, nil, :E)),
|
273
|
+
%Q{p <<~E\nE},
|
274
|
+
%q{},
|
275
|
+
%w(1.8 1.9 2.0 2.1 2.2 ios mac))
|
276
|
+
|
277
|
+
assert_parses(
|
278
|
+
s(:send, nil, :p,
|
279
|
+
s(:dstr)),
|
280
|
+
%Q{p <<~E\nE},
|
281
|
+
%q{},
|
282
|
+
ALL_VERSIONS - %w(1.8 1.9 2.0 2.1 2.2 ios mac))
|
283
|
+
|
284
|
+
assert_parses(
|
285
|
+
s(:send, nil, :p,
|
286
|
+
s(:dstr)),
|
287
|
+
%Q{p <<~E\n E},
|
288
|
+
%q{},
|
289
|
+
ALL_VERSIONS - %w(1.8 1.9 2.0 2.1 2.2 ios mac))
|
290
|
+
|
291
|
+
assert_parses(
|
292
|
+
s(:send, nil, :p,
|
293
|
+
s(:str, "x\n")),
|
294
|
+
%Q{p <<~E\n x\nE},
|
295
|
+
%q{},
|
296
|
+
ALL_VERSIONS - %w(1.8 1.9 2.0 2.1 2.2 ios mac))
|
297
|
+
|
298
|
+
assert_parses(
|
299
|
+
s(:send, nil, :p,
|
300
|
+
s(:dstr,
|
301
|
+
s(:str, "x\n"),
|
302
|
+
s(:str, " y\n"))),
|
303
|
+
%Q{p <<~E\n x\n y\nE},
|
304
|
+
%q{},
|
305
|
+
ALL_VERSIONS - %w(1.8 1.9 2.0 2.1 2.2 ios mac))
|
306
|
+
|
307
|
+
assert_parses(
|
308
|
+
s(:send, nil, :p,
|
309
|
+
s(:dstr,
|
310
|
+
s(:str, "x\n"),
|
311
|
+
s(:str, "y\n"))),
|
312
|
+
%Q{p <<~E\n\tx\n y\nE},
|
313
|
+
%q{},
|
314
|
+
ALL_VERSIONS - %w(1.8 1.9 2.0 2.1 2.2 ios mac))
|
315
|
+
|
316
|
+
assert_parses(
|
317
|
+
s(:send, nil, :p,
|
318
|
+
s(:dstr,
|
319
|
+
s(:str, "x\n"),
|
320
|
+
s(:str, "y\n"))),
|
321
|
+
%Q{p <<~E\n\tx\n y\nE},
|
322
|
+
%q{},
|
323
|
+
ALL_VERSIONS - %w(1.8 1.9 2.0 2.1 2.2 ios mac))
|
324
|
+
|
325
|
+
assert_parses(
|
326
|
+
s(:send, nil, :p,
|
327
|
+
s(:dstr,
|
328
|
+
s(:str, "x\n"),
|
329
|
+
s(:str, "y\n"))),
|
330
|
+
%Q{p <<~E\n \tx\n y\nE},
|
331
|
+
%q{},
|
332
|
+
ALL_VERSIONS - %w(1.8 1.9 2.0 2.1 2.2 ios mac))
|
333
|
+
|
334
|
+
assert_parses(
|
335
|
+
s(:send, nil, :p,
|
336
|
+
s(:dstr,
|
337
|
+
s(:str, "\tx\n"),
|
338
|
+
s(:str, "y\n"))),
|
339
|
+
%Q{p <<~E\n \tx\n\ty\nE},
|
340
|
+
%q{},
|
341
|
+
ALL_VERSIONS - %w(1.8 1.9 2.0 2.1 2.2 ios mac))
|
342
|
+
|
343
|
+
assert_parses(
|
344
|
+
s(:send, nil, :p,
|
345
|
+
s(:dstr,
|
346
|
+
s(:str, " x\n"),
|
347
|
+
s(:str, "\n"),
|
348
|
+
s(:str, "y\n"))),
|
349
|
+
%Q{p <<~E\n x\n\ny\nE},
|
350
|
+
%q{},
|
351
|
+
ALL_VERSIONS - %w(1.8 1.9 2.0 2.1 2.2 ios mac))
|
352
|
+
|
353
|
+
assert_parses(
|
354
|
+
s(:send, nil, :p,
|
355
|
+
s(:dstr,
|
356
|
+
s(:str, "x\n"),
|
357
|
+
s(:str, " \n"),
|
358
|
+
s(:str, "y\n"))),
|
359
|
+
%Q{p <<~E\n x\n \n y\nE},
|
360
|
+
%q{},
|
361
|
+
ALL_VERSIONS - %w(1.8 1.9 2.0 2.1 2.2 ios mac))
|
362
|
+
|
363
|
+
assert_parses(
|
364
|
+
s(:send, nil, :p,
|
365
|
+
s(:dstr,
|
366
|
+
s(:str, " x\n"),
|
367
|
+
s(:str, " y\n"))),
|
368
|
+
%Q{p <<~E\n x\n \\ y\nE},
|
369
|
+
%q{},
|
370
|
+
ALL_VERSIONS - %w(1.8 1.9 2.0 2.1 2.2 ios mac))
|
371
|
+
|
372
|
+
assert_parses(
|
373
|
+
s(:send, nil, :p,
|
374
|
+
s(:dstr,
|
375
|
+
s(:str, " x\n"),
|
376
|
+
s(:str, "\ty\n"))),
|
377
|
+
%Q{p <<~E\n x\n \\\ty\nE},
|
378
|
+
%q{},
|
379
|
+
ALL_VERSIONS - %w(1.8 1.9 2.0 2.1 2.2 ios mac))
|
380
|
+
|
381
|
+
assert_parses(
|
382
|
+
s(:send, nil, :p,
|
383
|
+
s(:dstr,
|
384
|
+
s(:str, " x\n"),
|
385
|
+
s(:str, ""),
|
386
|
+
s(:begin,
|
387
|
+
s(:lvar, :foo)),
|
388
|
+
s(:str, "\n"))),
|
389
|
+
%Q{p <<~"E"\n x\n \#{foo}\nE},
|
390
|
+
%q{},
|
391
|
+
ALL_VERSIONS - %w(1.8 1.9 2.0 2.1 2.2 ios mac))
|
392
|
+
|
393
|
+
assert_parses(
|
394
|
+
s(:send, nil, :p,
|
395
|
+
s(:xstr,
|
396
|
+
s(:str, " x\n"),
|
397
|
+
s(:str, ""),
|
398
|
+
s(:begin,
|
399
|
+
s(:lvar, :foo)),
|
400
|
+
s(:str, "\n"))),
|
401
|
+
%Q{p <<~`E`\n x\n \#{foo}\nE},
|
402
|
+
%q{},
|
403
|
+
ALL_VERSIONS - %w(1.8 1.9 2.0 2.1 2.2 ios mac))
|
404
|
+
|
405
|
+
assert_parses(
|
406
|
+
s(:send, nil, :p,
|
407
|
+
s(:dstr,
|
408
|
+
s(:str, " x\n"),
|
409
|
+
s(:str, ""),
|
410
|
+
s(:begin,
|
411
|
+
s(:str, " y")),
|
412
|
+
s(:str, "\n"))),
|
413
|
+
%Q{p <<~"E"\n x\n \#{" y"}\nE},
|
414
|
+
%q{},
|
415
|
+
ALL_VERSIONS - %w(1.8 1.9 2.0 2.1 2.2 ios mac))
|
416
|
+
end
|
417
|
+
|
265
418
|
# Symbols
|
266
419
|
|
267
420
|
def test_symbol_plain
|
@@ -5124,6 +5277,28 @@ class TestParser < Minitest::Test
|
|
5124
5277
|
ALL_VERSIONS - %w(1.8 1.9 mac ios 2.0)) # no 1.9 backport
|
5125
5278
|
end
|
5126
5279
|
|
5280
|
+
# We implement broken behavior, and Ruby is not fixed as of 2016-01-14.
|
5281
|
+
def test_ruby_bug_11989
|
5282
|
+
assert_parses(
|
5283
|
+
s(:send, nil, :p,
|
5284
|
+
s(:str, "x\n y\n")),
|
5285
|
+
%Q{p <<~"E"\n x\\n y\nE},
|
5286
|
+
%q{},
|
5287
|
+
ALL_VERSIONS - %w(1.8 1.9 2.0 2.1 2.2 ios mac))
|
5288
|
+
end
|
5289
|
+
|
5290
|
+
# We implement correct behavior, but Ruby is not fixed as of 2016-01-14.
|
5291
|
+
def test_ruby_bug_11990
|
5292
|
+
assert_parses(
|
5293
|
+
s(:send, nil, :p,
|
5294
|
+
s(:dstr,
|
5295
|
+
s(:str, "x\n"),
|
5296
|
+
s(:str, " y"))),
|
5297
|
+
%Q{p <<~E " y"\n x\nE},
|
5298
|
+
%q{},
|
5299
|
+
ALL_VERSIONS - %w(1.8 1.9 2.0 2.1 2.2 ios mac))
|
5300
|
+
end
|
5301
|
+
|
5127
5302
|
def test_parser_bug_198
|
5128
5303
|
assert_parses(
|
5129
5304
|
s(:array,
|
data/test/test_source_buffer.rb
CHANGED
@@ -116,4 +116,29 @@ class TestSourceBuffer < Minitest::Test
|
|
116
116
|
@buffer.line_range(9)
|
117
117
|
end
|
118
118
|
end
|
119
|
+
|
120
|
+
def test_last_line
|
121
|
+
@buffer.source = "1\nfoo\nbar"
|
122
|
+
assert_equal 3, @buffer.last_line
|
123
|
+
|
124
|
+
@buffer = Parser::Source::Buffer.new('(string)', 5)
|
125
|
+
@buffer.source = ""
|
126
|
+
assert_equal 5, @buffer.last_line
|
127
|
+
|
128
|
+
@buffer = Parser::Source::Buffer.new('(string)', 5)
|
129
|
+
@buffer.source = "abc\n"
|
130
|
+
assert_equal 6, @buffer.last_line
|
131
|
+
end
|
132
|
+
|
133
|
+
def test_source_lines
|
134
|
+
@buffer.source = "1\nfoo\nbar\n"
|
135
|
+
|
136
|
+
assert_equal ['1', 'foo', 'bar', ''], @buffer.source_lines
|
137
|
+
assert @buffer.source_lines.frozen?
|
138
|
+
assert @buffer.source_lines.all?(&:frozen?)
|
139
|
+
|
140
|
+
@buffer = Parser::Source::Buffer.new('(string)', 5)
|
141
|
+
@buffer.source = "foo\nbar"
|
142
|
+
assert_equal ['foo', 'bar'], @buffer.source_lines
|
143
|
+
end
|
119
144
|
end
|
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.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- whitequark
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2016-01-14 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: ast
|
@@ -260,6 +260,7 @@ files:
|
|
260
260
|
- lib/parser/diagnostic/engine.rb
|
261
261
|
- lib/parser/lexer.rb
|
262
262
|
- lib/parser/lexer.rl
|
263
|
+
- lib/parser/lexer/dedenter.rb
|
263
264
|
- lib/parser/lexer/explanation.rb
|
264
265
|
- lib/parser/lexer/literal.rb
|
265
266
|
- lib/parser/lexer/stack_state.rb
|
@@ -348,12 +349,12 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
348
349
|
version: '0'
|
349
350
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
350
351
|
requirements:
|
351
|
-
- - "
|
352
|
+
- - ">="
|
352
353
|
- !ruby/object:Gem::Version
|
353
|
-
version:
|
354
|
+
version: '0'
|
354
355
|
requirements: []
|
355
356
|
rubyforge_project:
|
356
|
-
rubygems_version: 2.
|
357
|
+
rubygems_version: 2.5.1
|
357
358
|
signing_key:
|
358
359
|
specification_version: 4
|
359
360
|
summary: A Ruby parser written in pure Ruby.
|