ruby_parser 3.14.0 → 3.16.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 7293d43033177f04deb6a7f28ebd39a495b56360e8ddd8386e468b76f931f367
4
- data.tar.gz: 46aaa402559b7b037d2309cc721f6c3664ec6998dd1a6a2d0cd6cb4fc266bcb1
3
+ metadata.gz: 229868c7db5e2ab8106bc746973fd349d0c656c6886a3dcf9e772c88108a5e62
4
+ data.tar.gz: 583b39eb3c6834e9de3567bae2300bfdfc96101f5c5fe73f483db63229e73282
5
5
  SHA512:
6
- metadata.gz: d4f7a1cab958547867b0ba7d6905b3845b19eca923cf01b16329668f7185ab500b90efd8b9bf04278d747f270a75ad2e5099e7e3a3e39bc25bf883189d7ecd5f
7
- data.tar.gz: a7ed89f3cc668ed8c04912e97145130e5b7a2014bec06680c29a6baadeae0ad17559fed244d38670ef62b49bb749ff1b25553e652217d7c6c8fc7c2ecf56b63b
6
+ metadata.gz: ce7d8b3e670dc37e9c7c215f47fd1ec8642f6ddab8648f6e502f507295be01ba976914c1dd6c7a727cb7075085e42dc7f252a08912337d0e43479bb664ec2e65
7
+ data.tar.gz: a59038ca6c27c24cfb4161ae2366df61cdc4e6c4e77f8201a463e4c21bc676517f80e6d9a9798113d60d497b216eed66796fc2fabf1ea4d9de0e15d0eaa6c5a9
checksums.yaml.gz.sig CHANGED
Binary file
data.tar.gz.sig CHANGED
Binary file
data/History.rdoc CHANGED
@@ -1,3 +1,81 @@
1
+ === 3.16.0 / 2021-05-15
2
+
3
+ * 1 major enhancement:
4
+
5
+ * Added tentative 3.0 support.
6
+
7
+ * 3 minor enhancements:
8
+
9
+ * Added lexing for "beginless range" (bdots).
10
+ * Added parsing for bdots.
11
+ * Updated rake compare task to download xz files, bumped versions, etc
12
+
13
+ * 4 bug fixes:
14
+
15
+ * Bump rake dependency to >= 10, < 15. (presidentbeef)
16
+ * Bump sexp_processor dependency to 4.15.1+. (pravi)
17
+ * Fixed minor state mismatch at the end of parsing to make diffing a little cleaner.
18
+ * Fixed normalizer to deal with new bison token syntax
19
+
20
+ === 3.15.1 / 2021-01-10
21
+
22
+ * 1 bug fix:
23
+
24
+ * Bumped ruby version to include < 4 (trunk).
25
+
26
+ === 3.15.0 / 2020-08-31
27
+
28
+ * 1 major enhancement:
29
+
30
+ * Added tentative 2.7 support.
31
+
32
+ * 1 minor enhancement:
33
+
34
+ * Improved ruby_parse_extract_error's handling of moving slow files out.
35
+
36
+ * 22 bug fixes:
37
+
38
+ * Bumped ruby version to include 3.0 (trunk).
39
+ * Fix an error related to empty ensure bodies. (presidentbeef)
40
+ * Fix handling of bad magic encoding comment.
41
+ * Fixed SystemStackError when parsing a huoooge hash, caused by a splat arg.
42
+ * Fixed a number of errors parsing do blocks in strange edge cases.
43
+ * Fixed a string backslash lexing bug when the string is an invalid encoding. (nijikon, gmcgibbon)
44
+ * Fixed bug assigning line number to some arg nodes.
45
+ * Fixed bug concatinating string literals with differing encodings.
46
+ * Fixed bug lexing heredoc w/ nasty mix of \r\n and \n.
47
+ * Fixed bug lexing multiple codepoints in \u{0000 1111 2222} forms.
48
+ * Fixed bug setting line numbers in empty xstrings in some contexts.
49
+ * Fixed edge case on call w/ begin + do block as an arg.
50
+ * Fixed handling of UTF BOM.
51
+ * Fixed handling of lexer state across string interpolation braces.
52
+ * Fixed infinite loop when lexing backslash+cr+newline (aka dos-files)
53
+ * Fixed lambda + do block edge case.
54
+ * Fixed lexing of some ?\M... and ?\C... edge cases.
55
+ * Fixed more do/brace block edge case failures.
56
+ * Fixed parsing bug where splat was used in the middle of a list.
57
+ * Fixed parsing of interpolation in heredoc-like strings. (presidentbeef)
58
+ * Fixed parsing some esoteric edge cases in op_asgn.
59
+ * Fixed unicode processing in ident chars so now they better mix.
60
+
61
+ === 3.14.2 / 2020-02-06
62
+
63
+ * 1 minor enhancement:
64
+
65
+ * Cleaned up call_args and removed arg_blk_pass from ruby_parser_extras.rb! Yay!
66
+
67
+ === 3.14.1 / 2019-10-29
68
+
69
+ * 1 minor enhancement:
70
+
71
+ * Declared that ruby_parser supports ruby 2.2 and up.
72
+
73
+ * 3 bug fixes:
74
+
75
+ * Fixed a problem with %W with a null-byte terminator. (wtf?) (spohlenz)
76
+ * Fixed line numbering for command (eg methods without parentheses) arguments. (mvz)
77
+ * Fixed lineno on new dxstrs. (presidentbeef)
78
+
1
79
  === 3.14.0 / 2019-09-24
2
80
 
3
81
  * 8 minor enhancements:
data/Manifest.txt CHANGED
@@ -24,6 +24,10 @@ lib/ruby25_parser.rb
24
24
  lib/ruby25_parser.y
25
25
  lib/ruby26_parser.rb
26
26
  lib/ruby26_parser.y
27
+ lib/ruby27_parser.rb
28
+ lib/ruby27_parser.y
29
+ lib/ruby30_parser.rb
30
+ lib/ruby30_parser.y
27
31
  lib/ruby_lexer.rb
28
32
  lib/ruby_lexer.rex
29
33
  lib/ruby_lexer.rex.rb
data/Rakefile CHANGED
@@ -8,11 +8,12 @@ Hoe.plugin :racc
8
8
  Hoe.plugin :isolate
9
9
  Hoe.plugin :rdoc
10
10
 
11
+ Hoe.add_include_dirs "lib"
11
12
  Hoe.add_include_dirs "../../sexp_processor/dev/lib"
12
13
  Hoe.add_include_dirs "../../minitest/dev/lib"
13
14
  Hoe.add_include_dirs "../../oedipus_lex/dev/lib"
14
15
 
15
- V2 = %w[20 21 22 23 24 25 26]
16
+ V2 = %w[20 21 22 23 24 25 26 27 30]
16
17
  V2.replace [V2.last] if ENV["FAST"] # HACK
17
18
 
18
19
  Hoe.spec "ruby_parser" do
@@ -20,10 +21,19 @@ Hoe.spec "ruby_parser" do
20
21
 
21
22
  license "MIT"
22
23
 
23
- dependency "sexp_processor", "~> 4.9"
24
- dependency "rake", "< 11", :developer
24
+ dependency "sexp_processor", ["~> 4.15", ">= 4.15.1"]
25
+ dependency "rake", [">= 10", "< 15"], :developer
25
26
  dependency "oedipus_lex", "~> 2.5", :developer
26
27
 
28
+ # NOTE: Ryan!!! Stop trying to fix this dependency! Isolate just
29
+ # can't handle having a faux-gem half-installed! Stop! Just `gem
30
+ # install racc` and move on. Revisit this ONLY once racc-compiler
31
+ # gets split out.
32
+
33
+ dependency "racc", "~> 1.5", :developer
34
+
35
+ require_ruby_version [">= 2.1", "< 4"]
36
+
27
37
  if plugin? :perforce then # generated files
28
38
  V2.each do |n|
29
39
  self.perforce_ignore << "lib/ruby#{n}_parser.rb"
@@ -54,6 +64,8 @@ end
54
64
 
55
65
  file "lib/ruby_lexer.rex.rb" => "lib/ruby_lexer.rex"
56
66
 
67
+ task :generate => [:lexer, :parser]
68
+
57
69
  task :clean do
58
70
  rm_rf(Dir["**/*~"] +
59
71
  Dir["diff.diff"] + # not all diffs. bit me too many times
@@ -87,7 +99,7 @@ end
87
99
 
88
100
  def dl v
89
101
  dir = v[/^\d+\.\d+/]
90
- url = "https://cache.ruby-lang.org/pub/ruby/#{dir}/ruby-#{v}.tar.bz2"
102
+ url = "https://cache.ruby-lang.org/pub/ruby/#{dir}/ruby-#{v}.tar.xz"
91
103
  path = File.basename url
92
104
  unless File.exist? path then
93
105
  system "curl -O #{url}"
@@ -99,7 +111,7 @@ def ruby_parse version
99
111
  rp_txt = "rp#{v}.txt"
100
112
  mri_txt = "mri#{v}.txt"
101
113
  parse_y = "parse#{v}.y"
102
- tarball = "ruby-#{version}.tar.bz2"
114
+ tarball = "ruby-#{version}.tar.xz"
103
115
  ruby_dir = "ruby-#{version}"
104
116
  diff = "diff#{v}.diff"
105
117
  rp_out = "lib/ruby#{v}_parser.output"
@@ -119,23 +131,40 @@ def ruby_parse version
119
131
  end
120
132
  end
121
133
 
134
+ desc "fetch all tarballs"
135
+ task :fetch => c_tarball
136
+
122
137
  file c_parse_y => c_tarball do
123
138
  in_compare do
124
- system "tar yxf #{tarball} #{ruby_dir}/{id.h,parse.y,tool/{id2token.rb,vpath.rb}}"
139
+ extract_glob = case version
140
+ when /2\.7|3\.0/
141
+ "{id.h,parse.y,tool/{id2token.rb,lib/vpath.rb}}"
142
+ else
143
+ "{id.h,parse.y,tool/{id2token.rb,vpath.rb}}"
144
+ end
145
+ system "tar Jxf #{tarball} #{ruby_dir}/#{extract_glob}"
146
+
125
147
  Dir.chdir ruby_dir do
126
148
  if File.exist? "tool/id2token.rb" then
127
149
  sh "ruby tool/id2token.rb --path-separator=.:./ id.h parse.y | expand > ../#{parse_y}"
128
150
  else
129
151
  sh "expand parse.y > ../#{parse_y}"
130
152
  end
153
+
154
+ ruby "-pi", "-e", 'gsub(/^%define\s+api\.pure/, "%pure-parser")', "../#{parse_y}"
131
155
  end
132
156
  sh "rm -rf #{ruby_dir}"
133
157
  end
134
158
  end
135
159
 
160
+ bison = Dir["/opt/homebrew/opt/bison/bin/bison",
161
+ "/usr/local/opt/bison/bin/bison",
162
+ `which bison`.chomp,
163
+ ].first
164
+
136
165
  file c_mri_txt => [c_parse_y, normalize] do
137
166
  in_compare do
138
- sh "bison -r all #{parse_y}"
167
+ sh "#{bison} -r all #{parse_y}"
139
168
  sh "./normalize.rb parse#{v}.output > #{mri_txt}"
140
169
  rm ["parse#{v}.output", "parse#{v}.tab.c"]
141
170
  end
@@ -180,16 +209,18 @@ ruby_parse "2.0.0-p648"
180
209
  ruby_parse "2.1.9"
181
210
  ruby_parse "2.2.9"
182
211
  ruby_parse "2.3.8"
183
- ruby_parse "2.4.5"
184
- ruby_parse "2.5.3"
185
- ruby_parse "2.6.1"
212
+ ruby_parse "2.4.10"
213
+ ruby_parse "2.5.9"
214
+ ruby_parse "2.6.7"
215
+ ruby_parse "2.7.3"
216
+ ruby_parse "3.0.1"
186
217
 
187
218
  task :debug => :isolate do
188
219
  ENV["V"] ||= V2.last
189
220
  Rake.application[:parser].invoke # this way we can have DEBUG set
190
221
  Rake.application[:lexer].invoke # this way we can have DEBUG set
191
222
 
192
- $: << "lib"
223
+ $:.unshift "lib"
193
224
  require "ruby_parser"
194
225
  require "pp"
195
226
 
@@ -212,8 +243,9 @@ task :debug => :isolate do
212
243
 
213
244
  begin
214
245
  pp parser.process(ruby, file, time)
215
- rescue Racc::ParseError => e
246
+ rescue ArgumentError, Racc::ParseError => e
216
247
  p e
248
+ puts e.backtrace.join "\n "
217
249
  ss = parser.lexer.ss
218
250
  src = ss.string
219
251
  lines = src[0..ss.pos].split(/\n/)
@@ -230,12 +262,17 @@ task :debug3 do
230
262
 
231
263
  ENV.delete "V"
232
264
 
265
+ sh "ruby -v"
233
266
  sh "ruby -y #{file} 2>&1 | #{munge} > tmp/ruby"
234
267
  sh "./tools/ripper.rb -d #{file} | #{munge} > tmp/rip"
235
- sh "rake debug F=#{file} DEBUG=1 V=25 2>&1 | #{munge} > tmp/rp"
268
+ sh "rake debug F=#{file} DEBUG=1 2>&1 | #{munge} > tmp/rp"
236
269
  sh "diff -U 999 -d tmp/{rip,rp}"
237
270
  end
238
271
 
272
+ task :cmp do
273
+ sh %(emacsclient --eval '(ediff-files "tmp/ruby" "tmp/rp")')
274
+ end
275
+
239
276
  task :cmp3 do
240
277
  sh %(emacsclient --eval '(ediff-files3 "tmp/ruby" "tmp/rip" "tmp/rp")')
241
278
  end
@@ -104,9 +104,14 @@ rescue Timeout::Error
104
104
  warn "TIMEOUT parsing #{file}. Skipping."
105
105
 
106
106
  if $m then
107
- dir = File.join $m, File.dirname(file)
108
- FileUtils.mkdir_p dir
109
- FileUtils.move file, dir
107
+ base_dir, *rest = file.split("/")
108
+ base_dir.sub!(/\.slow\.?.*/, "")
109
+ base_dir += ".slow.#{time}"
110
+
111
+ new_file = File.join(base_dir, *rest)
112
+
113
+ FileUtils.mkdir_p File.dirname(new_file)
114
+ FileUtils.move file, new_file, verbose:true
110
115
  elsif $t then
111
116
  File.unlink file
112
117
  end
data/compare/normalize.rb CHANGED
@@ -8,6 +8,10 @@ order = []
8
8
 
9
9
  def munge s
10
10
  renames = [
11
+ # unquote... wtf?
12
+ /`(.+?)'/, proc { $1 },
13
+ /"'(.+?)'"/, proc { "\"#{$1}\"" },
14
+
11
15
  "'='", "tEQL",
12
16
  "'!'", "tBANG",
13
17
  "'%'", "tPERCENT",
@@ -100,6 +104,43 @@ def munge s
100
104
 
101
105
  "kVARIABLE", "keyword_variable", # ugh: this is a rule name
102
106
 
107
+ # 2.7 changes:
108
+
109
+ '"global variable"', "tGVAR",
110
+ '"operator-assignment"', "tOP_ASGN",
111
+ '"back reference"', "tBACK_REF",
112
+ '"numbered reference"', "tNTH_REF",
113
+ '"local variable or method"', "tIDENTIFIER",
114
+ '"constant"', "tCONSTANT",
115
+
116
+ '"(.."', "tBDOT2",
117
+ '"(..."', "tBDOT3",
118
+ '"char literal"', "tCHAR",
119
+ '"literal content"', "tSTRING_CONTENT",
120
+ '"string literal"', "tSTRING_BEG",
121
+ '"symbol literal"', "tSYMBEG",
122
+ '"backtick literal"', "tXSTRING_BEG",
123
+ '"regexp literal"', "tREGEXP_BEG",
124
+ '"word list"', "tWORDS_BEG",
125
+ '"verbatim word list"', "tQWORDS_BEG",
126
+ '"symbol list"', "tSYMBOLS_BEG",
127
+ '"verbatim symbol list"', "tQSYMBOLS_BEG",
128
+
129
+ '"float literal"', "tFLOAT",
130
+ '"imaginary literal"', "tIMAGINARY",
131
+ '"integer literal"', "tINTEGER",
132
+ '"rational literal"', "tRATIONAL",
133
+
134
+ '"instance variable"', "tIVAR",
135
+ '"class variable"', "tCVAR",
136
+ '"terminator"', "tSTRING_END", # TODO: switch this?
137
+ '"method"', "tFID",
138
+ '"}"', "tSTRING_DEND",
139
+
140
+ '"do for block"', "kDO_BLOCK",
141
+ '"do for condition"', "kDO_COND",
142
+ '"do for lambda"', "kDO_LAMBDA",
143
+
103
144
  # UGH
104
145
  "k_LINE__", "k__LINE__",
105
146
  "k_FILE__", "k__FILE__",
@@ -107,13 +148,12 @@ def munge s
107
148
 
108
149
  '"defined?"', "kDEFINED",
109
150
 
110
-
111
151
  '"do (for condition)"', "kDO_COND",
112
152
  '"do (for lambda)"', "kDO_LAMBDA",
113
153
  '"do (for block)"', "kDO_BLOCK",
114
154
 
115
- /\"(\w+) \(modifier\)\"/, proc { |x| "k#{$1.upcase}_MOD" },
116
- /\"(\w+)\"/, proc { |x| "k#{$1.upcase}" },
155
+ /\"(\w+) \(?modifier\)?\"/, proc { |x| "k#{$1.upcase}_MOD" },
156
+ /\"(\w+)\"/, proc { |x| "k#{$1.upcase}" },
117
157
 
118
158
  /@(\d+)(\s+|$)/, "",
119
159
  ]
@@ -134,7 +174,7 @@ ARGF.each_line do |line|
134
174
 
135
175
  case line.strip
136
176
  when /^$/ then
137
- when /^(\d+) (\$?\w+): (.*)/ then # yacc
177
+ when /^(\d+) (\$?[@\w]+): (.*)/ then # yacc
138
178
  rule = $2
139
179
  order << rule unless rules.has_key? rule
140
180
  rules[rule] << munge($3)
@@ -159,7 +199,7 @@ ARGF.each_line do |line|
159
199
  when /^\cL/ then # byacc
160
200
  break
161
201
  else
162
- warn "unparsed: #{$.}: #{line.chomp}"
202
+ warn "unparsed: #{$.}: #{line.strip.inspect}"
163
203
  end
164
204
  end
165
205
 
data/debugging.md CHANGED
@@ -1,5 +1,44 @@
1
1
  # Quick Notes to Help with Debugging
2
2
 
3
+ ## Reducing
4
+
5
+ One of the most important steps is reducing the code sample to a
6
+ minimal reproduction. For example, one thing I'm debugging right now
7
+ was reported as:
8
+
9
+ ```ruby
10
+ a, b, c, d, e, f, g, h, i, j = 1, *[p1, p2, p3], *[p1, p2, p3], *[p4, p5, p6]
11
+ ```
12
+
13
+ This original sample has 10 items on the left-hand-side (LHS) and 1 +
14
+ 3 groups of 3 (calls) on the RHS + 3 arrays + 3 splats. That's a lot.
15
+
16
+ It's already been reported (perhaps incorrectly) that this has to do
17
+ with multiple splats on the RHS, so let's focus on that. At a minimum
18
+ the code can be reduced to 2 splats on the RHS and some
19
+ experimentation shows that it needs a non-splat item to fail:
20
+
21
+ ```
22
+ _, _, _ = 1, *[2], *[3]
23
+ ```
24
+
25
+ and some intuition further removed the arrays:
26
+
27
+ ```
28
+ _, _, _ = 1, *2, *3
29
+ ```
30
+
31
+ the difference is huge and will make a ton of difference when
32
+ debugging.
33
+
34
+ ## Getting something to compare
35
+
36
+ ```
37
+ % rake debug3 F=file.rb
38
+ ```
39
+
40
+ TODO
41
+
3
42
  ## Comparing against ruby / ripper:
4
43
 
5
44
  ```
@@ -16,3 +55,136 @@ From there? Good luck. I'm currently trying to backtrack from rule
16
55
  reductions to state change differences. I'd like to figure out a way
17
56
  to go from this sort of diff to a reasonable test that checks state
18
57
  changes but I don't have that set up at this point.
58
+
59
+ ## Adding New Grammar Productions
60
+
61
+ Ruby adds stuff to the parser ALL THE TIME. It's actually hard to keep
62
+ up with, but I've added some tools and shown what a typical workflow
63
+ looks like. Let's say you want to add ruby 2.7's "beginless range" (eg
64
+ `..42`).
65
+
66
+ Whenever there's a language feature missing, I start with comparing
67
+ the parse trees between MRI and RP:
68
+
69
+ ### Structural Comparing
70
+
71
+ There's a bunch of rake tasks `compare27`, `compare26`, etc that try
72
+ to normalize and diff MRI's parse.y parse tree (just the structure of
73
+ the tree in yacc) to ruby\_parser's parse tree (racc). It's the first
74
+ thing I do when I'm adding a new version. Stub out all the version
75
+ differences, and then start to diff the structure and move
76
+ ruby\_parser towards the new changes.
77
+
78
+ Some differences are just gonna be there... but here's an example of a
79
+ real diff between MRI 2.7 and ruby_parser as of today:
80
+
81
+ ```diff
82
+ arg tDOT3 arg
83
+ arg tDOT2
84
+ arg tDOT3
85
+ - tBDOT2 arg
86
+ - tBDOT3 arg
87
+ arg tPLUS arg
88
+ arg tMINUS arg
89
+ arg tSTAR2 arg
90
+ ```
91
+
92
+ This is a new language feature that ruby_parser doesn't handle yet.
93
+ It's in MRI (the left hand side of the diff) but not ruby\_parser (the
94
+ right hand side) so it is a `-` or missing line.
95
+
96
+ Some other diffs will have both `+` and `-` lines. That usually
97
+ happens when MRI has been refactoring the grammar. Sometimes I choose
98
+ to adapt those refactorings and sometimes it starts to get too
99
+ difficult to maintain multiple versions of ruby parsing in a single
100
+ file.
101
+
102
+ But! This structural comparing is always a place you should look when
103
+ ruby_parser is failing to parse something. Maybe it just hasn't been
104
+ implemented yet and the easiest place to look is the diff.
105
+
106
+ ### Starting Test First
107
+
108
+ The next thing I do is to add a parser test to cover that feature. I
109
+ usually start with the parser and work backwards towards the lexer as
110
+ needed, as I find it structures things properly and keeps things goal
111
+ oriented.
112
+
113
+ So, make a new parser test, usually in the versioned section of the
114
+ parser tests.
115
+
116
+ ```
117
+ def test_beginless2
118
+ rb = "..10\n; ..a\n; c"
119
+ pt = s(:block,
120
+ s(:dot2, nil, s(:lit, 0).line(1)).line(1),
121
+ s(:dot2, nil, s(:call, nil, :a).line(2)).line(2),
122
+ s(:call, nil, :c).line(3)).line(1)
123
+
124
+ assert_parse_line rb, pt, 1
125
+
126
+ flunk "not done yet"
127
+ end
128
+ ```
129
+
130
+ (In this case copied and modified the tests for open ranges from 2.6)
131
+ and run it to get my first error:
132
+
133
+ ```
134
+ % rake N=/beginless/
135
+
136
+ ...
137
+
138
+ E
139
+
140
+ Finished in 0.021814s, 45.8421 runs/s, 0.0000 assertions/s.
141
+
142
+ 1) Error:
143
+ TestRubyParserV27#test_whatevs:
144
+ Racc::ParseError: (string):1 :: parse error on value ".." (tDOT2)
145
+ GEMS/2.7.0/gems/racc-1.5.0/lib/racc/parser.rb:538:in `on_error'
146
+ WORK/ruby_parser/dev/lib/ruby_parser_extras.rb:1304:in `on_error'
147
+ (eval):3:in `_racc_do_parse_c'
148
+ (eval):3:in `do_parse'
149
+ WORK/ruby_parser/dev/lib/ruby_parser_extras.rb:1329:in `block in process'
150
+ RUBY/lib/ruby/2.7.0/timeout.rb:95:in `block in timeout'
151
+ RUBY/lib/ruby/2.7.0/timeout.rb:33:in `block in catch'
152
+ RUBY/lib/ruby/2.7.0/timeout.rb:33:in `catch'
153
+ RUBY/lib/ruby/2.7.0/timeout.rb:33:in `catch'
154
+ RUBY/lib/ruby/2.7.0/timeout.rb:110:in `timeout'
155
+ WORK/ruby_parser/dev/lib/ruby_parser_extras.rb:1317:in `process'
156
+ WORK/ruby_parser/dev/test/test_ruby_parser.rb:4198:in `assert_parse'
157
+ WORK/ruby_parser/dev/test/test_ruby_parser.rb:4221:in `assert_parse_line'
158
+ WORK/ruby_parser/dev/test/test_ruby_parser.rb:4451:in `test_whatevs'
159
+ ```
160
+
161
+ For starters, we know the missing production is for `tBDOT2 arg`. It
162
+ is currently blowing up because it is getting `tDOT2` and simply
163
+ doesn't know what to do with it, so it raises the error. As the diff
164
+ suggests, that's the wrong token to begin with, so it is probably time
165
+ to also create a lexer test:
166
+
167
+ ```
168
+ def test_yylex_bdot2
169
+ assert_lex3("..42",
170
+ s(:dot2, nil, s(:lit, 42)),
171
+
172
+ :tBDOT2, "..", EXPR_BEG,
173
+ :tINTEGER, "42", EXPR_NUM)
174
+
175
+ flunk "not done yet"
176
+ end
177
+ ```
178
+
179
+ This one is mostly speculative at this point. It says "if we're lexing
180
+ this string, we should get this sexp if we fully parse it, and the
181
+ lexical stream should look like this"... That last bit is mostly made
182
+ up at this point. Sometimes I don't know exactly what expression state
183
+ things should be in until I start really digging in.
184
+
185
+ At this point, I have 2 failing tests that are directing me in the
186
+ right direction. It's now a matter of digging through
187
+ `compare/parse26.y` to see how the lexer differs and implementing
188
+ it...
189
+
190
+ But this is a good start to the doco for now. I'll add more later.