parser 2.3.0.1 → 2.3.0.2

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 452a2098780caf4b2b9d00870b2791ae4e1db7e4
4
- data.tar.gz: a3ec510fb0160c8bfa9f29b0f80edcd4705db85d
3
+ metadata.gz: 3cb2802760d71d558e9ab344e63deb18525be110
4
+ data.tar.gz: 32edc10c308de0d00030d4b9fbac6bd40bfff36f
5
5
  SHA512:
6
- metadata.gz: b3322d4861c4c33a1381791f977928cba01428ee3153fb489cc1aed0ec88bb5c03570cfa448b073b1f6dc5776eb4aed6ef796b81aa5a607dae18439fec36b6c4
7
- data.tar.gz: b490d684a3ee85df2ae7b9700195bee2792fe44273104535080bc22ab5ffbcd7ef351ec8d143e11829579005288606e4af2b5cbd2ff11a3bb824bbb6583d4908
6
+ metadata.gz: 365c674e6cf6b3fa43f81903a7f46ce787075eb927e4aecce9b59ff05d81b5c47d4304f063f2f31c528f8846faec1983736f7bbd169697e19950e03346b0e52a
7
+ data.tar.gz: 1504d14896c1cb0dde7a8bc46aa60b04036e03310b1f097e84e5f14587699f18b086184292fbb5fb1aaff4d201d172cd9c424d1b8bc11de725d2c64567893928
data/CHANGELOG.md CHANGED
@@ -1,6 +1,22 @@
1
1
  Changelog
2
2
  =========
3
3
 
4
+ v2.3.0.2 (2016-01-24)
5
+ ---------------------
6
+
7
+ Bugs fixed:
8
+ * Add :csend to Parser::Meta::NODE_TYPES (Markus Schirp)
9
+ * lexer/dedenter: "\<\<x\n y\\n z\nx": don't dedent after escaped newline. (whitequark)
10
+
11
+ v2.3.0.2 (2016-01-16)
12
+ ---------------------
13
+
14
+ v2.3.0.1 (2016-01-14)
15
+ ---------------------
16
+
17
+ Features implemented:
18
+ * ruby23.y: implement optional superclass (cremno)
19
+
4
20
  v2.3.0.0 (2016-01-14)
5
21
  ---------------------
6
22
 
data/README.md CHANGED
@@ -1,8 +1,8 @@
1
1
  # Parser
2
2
 
3
- [![Gem Version](https://badge.fury.io/rb/parser.png)](https://badge.fury.io/rb/parser)
4
- [![Build Status](https://travis-ci.org/whitequark/parser.png?branch=master)](https://travis-ci.org/whitequark/parser)
5
- [![Coverage Status](https://coveralls.io/repos/whitequark/parser/badge.png?branch=master)](https://coveralls.io/r/whitequark/parser)
3
+ [![Gem Version](https://badge.fury.io/rb/parser.svg)](https://badge.fury.io/rb/parser)
4
+ [![Build Status](https://travis-ci.org/whitequark/parser.svg?branch=master)](https://travis-ci.org/whitequark/parser)
5
+ [![Coverage Status](https://coveralls.io/repos/whitequark/parser/badge.svg?branch=master)](https://coveralls.io/r/whitequark/parser)
6
6
 
7
7
  _Parser_ is a production-ready Ruby parser written in pure Ruby. It recognizes as
8
8
  much or more code than Ripper, Melbourne, JRubyParser or ruby\_parser, and
data/lib/parser/lexer.rl CHANGED
@@ -92,7 +92,7 @@ class Parser::Lexer
92
92
  REGEXP_META_CHARACTERS = Regexp.union(*"\\$()*+.<>?[]^{|}".chars).freeze
93
93
  UNDERSCORE_STRING = '_'.freeze
94
94
 
95
- RBRACE_OR_RPAREN = %w"} ]".freeze
95
+ RBRACE_OR_RBRACK = %w"} ]".freeze
96
96
 
97
97
  attr_reader :source_buffer
98
98
  attr_reader :encoding
@@ -426,6 +426,12 @@ class Parser::Lexer
426
426
  else
427
427
  self.class.lex_en_plain_words
428
428
  end
429
+ elsif new_literal.backslash_delimited?
430
+ if new_literal.interpolate?
431
+ self.class.lex_en_interp_backslash_delimited
432
+ else
433
+ self.class.lex_en_plain_backslash_delimited
434
+ end
429
435
  else
430
436
  if new_literal.interpolate?
431
437
  self.class.lex_en_interp_string
@@ -645,10 +651,10 @@ class Parser::Lexer
645
651
  flo_pow = [eE] [+\-]? ( digit+ '_' )* digit+;
646
652
 
647
653
  int_suffix =
648
- '' % { @num_xfrm = lambda { |chars| emit(:tINTEGER, chars) } }
649
- | 'r' % { @num_xfrm = lambda { |chars| emit(:tRATIONAL, Rational(chars)) } }
650
- | 'i' % { @num_xfrm = lambda { |chars| emit(:tIMAGINARY, Complex(0, chars)) } }
651
- | 'ri' % { @num_xfrm = lambda { |chars| emit(:tIMAGINARY, Complex(0, Rational(chars))) } };
654
+ '' % { @num_xfrm = lambda { |chars| emit(:tINTEGER, chars) } }
655
+ | 'r' % { @num_xfrm = lambda { |chars| emit(:tRATIONAL, Rational(chars)) } }
656
+ | 'i' % { @num_xfrm = lambda { |chars| emit(:tIMAGINARY, Complex(0, chars)) } }
657
+ | 'ri' % { @num_xfrm = lambda { |chars| emit(:tIMAGINARY, Complex(0, Rational(chars))) } };
652
658
 
653
659
  flo_pow_suffix =
654
660
  '' % { @num_xfrm = lambda { |chars| emit(:tFLOAT, Float(chars)) } }
@@ -682,11 +688,8 @@ class Parser::Lexer
682
688
  codepoint = codepoint_str.to_i(16)
683
689
 
684
690
  if codepoint >= 0x110000
685
- @escape = lambda do
686
- diagnostic :error, :unicode_point_too_large, nil,
687
- range(codepoint_s, codepoint_s + codepoint_str.length)
688
- end
689
-
691
+ diagnostic :error, :unicode_point_too_large, nil,
692
+ range(codepoint_s, codepoint_s + codepoint_str.length)
690
693
  break
691
694
  end
692
695
 
@@ -701,9 +704,7 @@ class Parser::Lexer
701
704
  }
702
705
 
703
706
  action invalid_complex_escape {
704
- @escape = lambda do
705
- diagnostic :fatal, :invalid_escape
706
- end
707
+ diagnostic :fatal, :invalid_escape
707
708
  }
708
709
 
709
710
  action slash_c_char {
@@ -731,20 +732,17 @@ class Parser::Lexer
731
732
  % { @escape = encode_escape(tok(@escape_s, p).to_i(8) % 0x100) }
732
733
 
733
734
  # \xff
734
- | ( 'x' xdigit{1,2}
735
+ | 'x' xdigit{1,2}
735
736
  % { @escape = encode_escape(tok(@escape_s + 1, p).to_i(16)) }
737
+
736
738
  # \u263a
737
- | 'u' xdigit{4}
738
- % { @escape = tok(@escape_s + 1, p).to_i(16).chr(Encoding::UTF_8) }
739
- )
739
+ | 'u' xdigit{4}
740
+ % { @escape = tok(@escape_s + 1, p).to_i(16).chr(Encoding::UTF_8) }
740
741
 
741
742
  # %q[\x]
742
743
  | 'x' ( c_any - xdigit )
743
744
  % {
744
- @escape = lambda do
745
- diagnostic :fatal, :invalid_hex_escape, nil,
746
- range(@escape_s - 1, p + 2)
747
- end
745
+ diagnostic :fatal, :invalid_hex_escape, nil, range(@escape_s - 1, p + 2)
748
746
  }
749
747
 
750
748
  # %q[\u123] %q[\u{12]
@@ -756,10 +754,7 @@ class Parser::Lexer
756
754
  )
757
755
  )
758
756
  % {
759
- @escape = lambda do
760
- diagnostic :fatal, :invalid_unicode_escape, nil,
761
- range(@escape_s - 1, p)
762
- end
757
+ diagnostic :fatal, :invalid_unicode_escape, nil, range(@escape_s - 1, p)
763
758
  }
764
759
 
765
760
  # \u{123 456}
@@ -770,10 +765,7 @@ class Parser::Lexer
770
765
  | ( c_any - '}' )* c_eof
771
766
  | xdigit{7,}
772
767
  ) % {
773
- @escape = lambda do
774
- diagnostic :fatal, :unterminated_unicode, nil,
775
- range(p - 1, p)
776
- end
768
+ diagnostic :fatal, :unterminated_unicode, nil, range(p - 1, p)
777
769
  }
778
770
  )
779
771
 
@@ -881,53 +873,35 @@ class Parser::Lexer
881
873
 
882
874
  action extend_string_escaped {
883
875
  current_literal = literal
884
- if current_literal.nest_and_try_closing('\\', @ts, @ts + 1)
885
- # If the literal is actually closed by the backslash,
886
- # rewind the input prior to consuming the escape sequence.
887
- p = @escape_s - 1
888
- fnext *pop_literal; fbreak;
876
+ # Get the first character after the backslash.
877
+ escaped_char = @source[@escape_s].chr
878
+
879
+ if current_literal.munge_escape? escaped_char
880
+ # If this particular literal uses this character as an opening
881
+ # or closing delimiter, it is an escape sequence for that
882
+ # particular character. Write it without the backslash.
883
+
884
+ if current_literal.regexp? && REGEXP_META_CHARACTERS.match(escaped_char)
885
+ # Regular expressions should include escaped delimiters in their
886
+ # escaped form, except when the escaped character is
887
+ # a closing delimiter but not a regexp metacharacter.
888
+ #
889
+ # The backslash itself cannot be used as a closing delimiter
890
+ # at the same time as an escape symbol, but it is always munged,
891
+ # so this branch also executes for the non-closing-delimiter case
892
+ # for the backslash.
893
+ current_literal.extend_string(tok, @ts, @te)
894
+ else
895
+ current_literal.extend_string(escaped_char, @ts, @te)
896
+ end
889
897
  else
890
- # Get the first character after the backslash.
891
- escaped_char = @source[@escape_s].chr
892
-
893
- if current_literal.munge_escape? escaped_char
894
- # If this particular literal uses this character as an opening
895
- # or closing delimiter, it is an escape sequence for that
896
- # particular character. Write it without the backslash.
897
-
898
- if current_literal.regexp? && REGEXP_META_CHARACTERS.match(escaped_char)
899
- # Regular expressions should include escaped delimiters in their
900
- # escaped form, except when the escaped character is
901
- # a closing delimiter but not a regexp metacharacter.
902
- #
903
- # The backslash itself cannot be used as a closing delimiter
904
- # at the same time as an escape symbol, but it is always munged,
905
- # so this branch also executes for the non-closing-delimiter case
906
- # for the backslash.
907
- current_literal.extend_string(tok, @ts, @te)
908
- else
909
- current_literal.extend_string(escaped_char, @ts, @te)
910
- end
898
+ # It does not. So this is an actual escape sequence, yay!
899
+ if current_literal.regexp?
900
+ # Regular expressions should include escape sequences in their
901
+ # escaped form. On the other hand, escaped newlines are removed.
902
+ current_literal.extend_string(tok.gsub(ESCAPED_NEXT_LINE, BLANK_STRING), @ts, @te)
911
903
  else
912
- # It does not. So this is an actual escape sequence, yay!
913
- # Two things to consider here.
914
- #
915
- # 1. The `escape' rule should be pure and so won't raise any
916
- # errors by itself. Instead, it stores them in lambdas.
917
- #
918
- # 2. Non-interpolated literals do not go through the aforementioned
919
- # rule. As \\ and \' (and variants) are munged, the full token
920
- # should always be written for such literals.
921
-
922
- @escape.call if @escape.respond_to? :call
923
-
924
- if current_literal.regexp?
925
- # Regular expressions should include escape sequences in their
926
- # escaped form. On the other hand, escaped newlines are removed.
927
- current_literal.extend_string(tok.gsub(ESCAPED_NEXT_LINE, BLANK_STRING), @ts, @te)
928
- else
929
- current_literal.extend_string(@escape || tok, @ts, @te)
930
- end
904
+ current_literal.extend_string(@escape || tok, @ts, @te)
931
905
  end
932
906
  end
933
907
  }
@@ -1115,6 +1089,18 @@ class Parser::Lexer
1115
1089
  c_any => extend_string;
1116
1090
  *|;
1117
1091
 
1092
+ interp_backslash_delimited := |*
1093
+ interp_code => extend_interp_code;
1094
+ interp_var => extend_interp_var;
1095
+ c_eol => extend_string_eol;
1096
+ c_any => extend_string;
1097
+ *|;
1098
+
1099
+ plain_backslash_delimited := |*
1100
+ c_eol => extend_string_eol;
1101
+ c_any => extend_string;
1102
+ *|;
1103
+
1118
1104
  regexp_modifiers := |*
1119
1105
  [A-Za-z]+
1120
1106
  => {
@@ -1669,7 +1655,7 @@ class Parser::Lexer
1669
1655
  # %w(we are the people)
1670
1656
  '%' [A-Za-z]+ c_any
1671
1657
  => {
1672
- type, delimiter = tok[0..-2], @source[@te - 1].chr
1658
+ type, delimiter = @source[@ts...(@te - 1)], @source[@te - 1].chr
1673
1659
  fgoto *push_literal(type, delimiter, @ts);
1674
1660
  };
1675
1661
 
@@ -1746,9 +1732,6 @@ class Parser::Lexer
1746
1732
  | (c_any - c_space_nl - e_bs) % { @escape = nil }
1747
1733
  )
1748
1734
  => {
1749
- # Show an error if memorized.
1750
- @escape.call if @escape.respond_to? :call
1751
-
1752
1735
  value = @escape || tok(@ts + 1)
1753
1736
 
1754
1737
  if version?(18)
@@ -2177,7 +2160,7 @@ class Parser::Lexer
2177
2160
  emit_table(PUNCTUATION)
2178
2161
  @cond.lexpop; @cmdarg.lexpop
2179
2162
 
2180
- if RBRACE_OR_RPAREN.include?(tok)
2163
+ if RBRACE_OR_RBRACK.include?(tok)
2181
2164
  fnext expr_endarg;
2182
2165
  else # )
2183
2166
  # fnext expr_endfn; ?
@@ -9,6 +9,7 @@ module Parser
9
9
 
10
10
  def dedent(string)
11
11
  space_begin = space_end = offset = 0
12
+ last_index = string.length - 1
12
13
  string.chars.each_with_index do |char, index|
13
14
  if @at_line_begin
14
15
  if char == ?\n || @indent_level >= @dedent_level
@@ -26,7 +27,7 @@ module Parser
26
27
  @indent_level += 8 - @indent_level % 8
27
28
  space_end += 1
28
29
  end
29
- elsif char == ?\n
30
+ elsif char == ?\n && index == last_index
30
31
  @at_line_begin = true
31
32
  @indent_level = 0
32
33
  space_begin = space_end = index - offset + 1
@@ -4,7 +4,6 @@ module Parser
4
4
 
5
5
  class Lexer::Literal
6
6
  DELIMITERS = { '(' => ')', '[' => ']', '{' => '}', '<' => '>' }
7
- MONOLITHIC = { :tSTRING_BEG => :tSTRING }
8
7
 
9
8
  TYPES = {
10
9
  # type start token interpolate?
@@ -79,9 +78,7 @@ module Parser
79
78
  !heredoc?)
80
79
 
81
80
  # Capture opening delimiter in percent-literals.
82
- unless @heredoc_e || @str_type.end_with?(delimiter)
83
- @str_type << delimiter
84
- end
81
+ @str_type << delimiter if @str_type.start_with?('%')
85
82
 
86
83
  clear_buffer
87
84
 
@@ -105,6 +102,10 @@ module Parser
105
102
  !!@heredoc_e
106
103
  end
107
104
 
105
+ def backslash_delimited?
106
+ @end_delim == '\\'
107
+ end
108
+
108
109
  def type
109
110
  @start_tok
110
111
  end
@@ -141,7 +142,7 @@ module Parser
141
142
  emit(:tLABEL_END, @end_delim, ts, te + 1)
142
143
  elsif @monolithic
143
144
  # Emit the string as a single token.
144
- emit(MONOLITHIC[@start_tok], @buffer, @str_s, te)
145
+ emit(:tSTRING, @buffer, @str_s, te)
145
146
  else
146
147
  # If this is a heredoc, @buffer contains the sentinel now.
147
148
  # Just throw it out. Lexer flushes the heredoc after each
@@ -183,10 +184,7 @@ module Parser
183
184
  end
184
185
 
185
186
  def extend_string(string, ts, te)
186
- if @buffer_s.nil?
187
- @buffer_s = ts
188
- end
189
-
187
+ @buffer_s ||= ts
190
188
  @buffer_e = te
191
189
 
192
190
  @buffer << string
data/lib/parser/meta.rb CHANGED
@@ -16,7 +16,7 @@ module Parser
16
16
  match_with_lvasgn match_current_line
17
17
  module class sclass def defs undef alias args
18
18
  cbase arg optarg restarg blockarg block_pass args def kwarg kwoptarg
19
- kwrestarg send super zsuper yield block send
19
+ kwrestarg send csend super zsuper yield block
20
20
  and not or if when case while until while_post
21
21
  until_post for break next redo return resbody
22
22
  kwbegin begin retry preexe postexe iflipflop eflipflop
@@ -1,3 +1,3 @@
1
1
  module Parser
2
- VERSION = '2.3.0.1'
2
+ VERSION = '2.3.0.2'
3
3
  end
data/test/test_lexer.rb CHANGED
@@ -1796,6 +1796,14 @@ class TestLexer < Minitest::Test
1796
1796
  :tREGEXP_OPT, "")
1797
1797
  end
1798
1798
 
1799
+ def test_regexp_escape_other_meta
1800
+ assert_scanned("/\\.\\$\\*\\+\\.\\?\\|/",
1801
+ :tREGEXP_BEG, "/",
1802
+ :tSTRING_CONTENT, "\\.\\$\\*\\+\\.\\?\\|",
1803
+ :tSTRING_END, "/",
1804
+ :tREGEXP_OPT, "")
1805
+ end
1806
+
1799
1807
  def test_regexp_nm
1800
1808
  assert_scanned("/.*/nm",
1801
1809
  :tREGEXP_BEG, "/",
@@ -2097,7 +2105,7 @@ class TestLexer < Minitest::Test
2097
2105
 
2098
2106
  def test_string_pct_pct
2099
2107
  assert_scanned("%%blah%",
2100
- :tSTRING_BEG, '%',
2108
+ :tSTRING_BEG, '%%',
2101
2109
  :tSTRING_CONTENT, "blah",
2102
2110
  :tSTRING_END, '%')
2103
2111
  end
@@ -2159,6 +2167,48 @@ class TestLexer < Minitest::Test
2159
2167
  :tSTRING_END, ')')
2160
2168
  end
2161
2169
 
2170
+ def test_string_pct_backslash
2171
+ assert_scanned("%\\a\\",
2172
+ :tSTRING_BEG, "%\\",
2173
+ :tSTRING_CONTENT, "a",
2174
+ :tSTRING_END, "\\")
2175
+ end
2176
+
2177
+ def test_string_pct_backslash_with_bad_escape
2178
+ # No escapes are allowed in a backslash-delimited string
2179
+ refute_scanned("%\\a\\n\\",
2180
+ :tSTRING_BEG, "%\\",
2181
+ :tSTRING_CONTENT, "a",
2182
+ :tSTRING_END, "\\",
2183
+ :tIDENTIFIER, "n")
2184
+ end
2185
+
2186
+ def test_string_pct_intertwined_with_heredoc
2187
+ assert_scanned("<<-foo + %\\a\nbar\nfoo\nb\\",
2188
+ :tSTRING_BEG, "<<\"",
2189
+ :tSTRING_CONTENT, "bar\n",
2190
+ :tSTRING_END, "foo",
2191
+ :tPLUS, "+",
2192
+ :tSTRING_BEG, "%\\",
2193
+ :tSTRING_CONTENT, "a\n",
2194
+ :tSTRING_CONTENT, "b",
2195
+ :tSTRING_END, "\\")
2196
+ end
2197
+
2198
+ def test_string_pct_q_backslash
2199
+ assert_scanned("%q\\a\\",
2200
+ :tSTRING_BEG, "%q\\",
2201
+ :tSTRING_CONTENT, "a",
2202
+ :tSTRING_END, "\\")
2203
+ end
2204
+
2205
+ def test_string_pct_Q_backslash
2206
+ assert_scanned("%Q\\a\\",
2207
+ :tSTRING_BEG, "%Q\\",
2208
+ :tSTRING_CONTENT, "a",
2209
+ :tSTRING_END, "\\")
2210
+ end
2211
+
2162
2212
  def test_string_single
2163
2213
  assert_scanned("'string'",
2164
2214
  :tSTRING, "string")
data/test/test_parser.rb CHANGED
@@ -5286,17 +5286,15 @@ class TestParser < Minitest::Test
5286
5286
  ALL_VERSIONS - %w(1.8 1.9 mac ios 2.0)) # no 1.9 backport
5287
5287
  end
5288
5288
 
5289
- # We implement broken behavior, and Ruby is not fixed as of 2016-01-14.
5290
5289
  def test_ruby_bug_11989
5291
5290
  assert_parses(
5292
5291
  s(:send, nil, :p,
5293
- s(:str, "x\n y\n")),
5292
+ s(:str, "x\n y\n")),
5294
5293
  %Q{p <<~"E"\n x\\n y\nE},
5295
5294
  %q{},
5296
5295
  ALL_VERSIONS - %w(1.8 1.9 2.0 2.1 2.2 ios mac))
5297
5296
  end
5298
5297
 
5299
- # We implement correct behavior, but Ruby is not fixed as of 2016-01-14.
5300
5298
  def test_ruby_bug_11990
5301
5299
  assert_parses(
5302
5300
  s(:send, nil, :p,
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.1
4
+ version: 2.3.0.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - whitequark
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-01-14 00:00:00.000000000 Z
11
+ date: 2016-01-24 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: ast
@@ -354,7 +354,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
354
354
  version: '0'
355
355
  requirements: []
356
356
  rubyforge_project:
357
- rubygems_version: 2.4.1
357
+ rubygems_version: 2.5.1
358
358
  signing_key:
359
359
  specification_version: 4
360
360
  summary: A Ruby parser written in pure Ruby.