ruby_parser 3.14.0 → 3.16.0

Sign up to get free protection for your applications and to get access to all the features.
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.