Skip to content

Commit 92fbe35

Browse files
committed
Support Ruby 2.7.0
Follow up of lsegal#1290 (comment). This is a workaround path for Ruby 2.7.0. `irb/slex` internal API has been removed in the following commits. ruby/ruby@45bb6f2 This PR copies the above file to lib/yard/parser/ruby/legacy/irb/slex.rb. Hopefully this workaround patch will be dropped along with legacy Ruby code in the future. And E2MM (e2mmap gem) is no longer bundled gems. https://www.ruby-lang.org/en/news/2019/12/25/ruby-2-7-0-released/ ```console % cd path/to/repo/yard % ruby -v ruby 2.7.0p0 (2019-12-25 revision 647ee6f091) [x86_64-darwin17] % bundle exec rake (snip) LoadError: cannot load such file -- e2mmap # ./lib/yard/parser/ruby/legacy/ruby_lex.rb:1:in `require' # ./lib/yard/parser/ruby/legacy/ruby_lex.rb:1:in `<top (required)>' ``` This dependency on `e2mmap` could be removed when `irb/slex` is removed in the future.
1 parent ebd6269 commit 92fbe35

5 files changed

Lines changed: 289 additions & 1 deletion

File tree

.travis.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ rvm:
1616
- "2.4"
1717
- "2.5"
1818
- "2.6"
19+
- "2.7"
1920
# - ruby-head
2021
# - jruby
2122

Gemfile

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
# frozen_string_literal: true
22
source 'https://rubygems.org'
33

4+
gemspec
5+
46
group :development do
57
gem 'rspec'
68
gem 'rake'
Lines changed: 282 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,282 @@
1+
# frozen_string_literal: false
2+
#
3+
# irb/slex.rb - simple lex analyzer
4+
# $Release Version: 0.9.6$
5+
# $Revision$
6+
# by Keiju ISHITSUKA(keiju@ruby-lang.org)
7+
#
8+
# --
9+
#
10+
#
11+
#
12+
13+
require "e2mmap"
14+
require "irb/notifier"
15+
16+
# :stopdoc:
17+
module IRB
18+
class SLex
19+
20+
extend Exception2MessageMapper
21+
def_exception :ErrNodeNothing, "node nothing"
22+
def_exception :ErrNodeAlreadyExists, "node already exists"
23+
24+
DOUT = Notifier::def_notifier("SLex::")
25+
D_WARN = DOUT::def_notifier(1, "Warn: ")
26+
D_DEBUG = DOUT::def_notifier(2, "Debug: ")
27+
D_DETAIL = DOUT::def_notifier(4, "Detail: ")
28+
29+
DOUT.level = Notifier::D_NOMSG
30+
31+
def initialize
32+
@head = Node.new("")
33+
end
34+
35+
def def_rule(token, preproc = nil, postproc = nil, &block)
36+
D_DETAIL.pp token
37+
38+
postproc = block if block_given?
39+
create(token, preproc, postproc)
40+
end
41+
42+
def def_rules(*tokens, &block)
43+
if block_given?
44+
p = block
45+
end
46+
for token in tokens
47+
def_rule(token, nil, p)
48+
end
49+
end
50+
51+
def preproc(token, proc)
52+
node = search(token)
53+
node.preproc=proc
54+
end
55+
56+
# need a check?
57+
def postproc(token)
58+
node = search(token, proc)
59+
node.postproc=proc
60+
end
61+
62+
def search(token)
63+
@head.search(token.split(//))
64+
end
65+
66+
def create(token, preproc = nil, postproc = nil)
67+
@head.create_subnode(token.split(//), preproc, postproc)
68+
end
69+
70+
def match(token)
71+
case token
72+
when Array
73+
when String
74+
return match(token.split(//))
75+
else
76+
return @head.match_io(token)
77+
end
78+
ret = @head.match(token)
79+
D_DETAIL.exec_if{D_DETAIL.printf "match end: %s:%s\n", ret, token.inspect}
80+
ret
81+
end
82+
83+
def inspect
84+
format("<SLex: @head = %s>", @head.inspect)
85+
end
86+
87+
#----------------------------------------------------------------------
88+
#
89+
# class Node -
90+
#
91+
#----------------------------------------------------------------------
92+
class Node
93+
# if postproc is nil, this node is an abstract node.
94+
# if postproc is non-nil, this node is a real node.
95+
def initialize(preproc = nil, postproc = nil)
96+
@Tree = {}
97+
@preproc = preproc
98+
@postproc = postproc
99+
end
100+
101+
attr_accessor :preproc
102+
attr_accessor :postproc
103+
104+
def search(chrs, opt = nil)
105+
return self if chrs.empty?
106+
ch = chrs.shift
107+
if node = @Tree[ch]
108+
node.search(chrs, opt)
109+
else
110+
if opt
111+
chrs.unshift ch
112+
self.create_subnode(chrs)
113+
else
114+
SLex.fail ErrNodeNothing
115+
end
116+
end
117+
end
118+
119+
def create_subnode(chrs, preproc = nil, postproc = nil)
120+
if chrs.empty?
121+
if @postproc
122+
D_DETAIL.pp node
123+
SLex.fail ErrNodeAlreadyExists
124+
else
125+
D_DEBUG.puts "change abstract node to real node."
126+
@preproc = preproc
127+
@postproc = postproc
128+
end
129+
return self
130+
end
131+
132+
ch = chrs.shift
133+
if node = @Tree[ch]
134+
if chrs.empty?
135+
if node.postproc
136+
DebugLogger.pp node
137+
DebugLogger.pp self
138+
DebugLogger.pp ch
139+
DebugLogger.pp chrs
140+
SLex.fail ErrNodeAlreadyExists
141+
else
142+
D_WARN.puts "change abstract node to real node"
143+
node.preproc = preproc
144+
node.postproc = postproc
145+
end
146+
else
147+
node.create_subnode(chrs, preproc, postproc)
148+
end
149+
else
150+
if chrs.empty?
151+
node = Node.new(preproc, postproc)
152+
else
153+
node = Node.new
154+
node.create_subnode(chrs, preproc, postproc)
155+
end
156+
@Tree[ch] = node
157+
end
158+
node
159+
end
160+
161+
#
162+
# chrs: String
163+
# character array
164+
# io must have getc()/ungetc(); and ungetc() must be
165+
# able to be called arbitrary number of times.
166+
#
167+
def match(chrs, op = "")
168+
D_DETAIL.print "match>: ", chrs, "op:", op, "\n"
169+
if chrs.empty?
170+
if @preproc.nil? || @preproc.call(op, chrs)
171+
DOUT.printf(D_DETAIL, "op1: %s\n", op)
172+
@postproc.call(op, chrs)
173+
else
174+
nil
175+
end
176+
else
177+
ch = chrs.shift
178+
if node = @Tree[ch]
179+
if ret = node.match(chrs, op+ch)
180+
return ret
181+
else
182+
chrs.unshift ch
183+
if @postproc and @preproc.nil? || @preproc.call(op, chrs)
184+
DOUT.printf(D_DETAIL, "op2: %s\n", op.inspect)
185+
ret = @postproc.call(op, chrs)
186+
return ret
187+
else
188+
return nil
189+
end
190+
end
191+
else
192+
chrs.unshift ch
193+
if @postproc and @preproc.nil? || @preproc.call(op, chrs)
194+
DOUT.printf(D_DETAIL, "op3: %s\n", op)
195+
@postproc.call(op, chrs)
196+
return ""
197+
else
198+
return nil
199+
end
200+
end
201+
end
202+
end
203+
204+
def match_io(io, op = "")
205+
if op == ""
206+
ch = io.getc
207+
if ch == nil
208+
return nil
209+
end
210+
else
211+
ch = io.getc_of_rests
212+
end
213+
if ch.nil?
214+
if @preproc.nil? || @preproc.call(op, io)
215+
D_DETAIL.printf("op1: %s\n", op)
216+
@postproc.call(op, io)
217+
else
218+
nil
219+
end
220+
else
221+
if node = @Tree[ch]
222+
if ret = node.match_io(io, op+ch)
223+
ret
224+
else
225+
io.ungetc ch
226+
if @postproc and @preproc.nil? || @preproc.call(op, io)
227+
DOUT.exec_if{D_DETAIL.printf "op2: %s\n", op.inspect}
228+
@postproc.call(op, io)
229+
else
230+
nil
231+
end
232+
end
233+
else
234+
io.ungetc ch
235+
if @postproc and @preproc.nil? || @preproc.call(op, io)
236+
D_DETAIL.printf("op3: %s\n", op)
237+
@postproc.call(op, io)
238+
else
239+
nil
240+
end
241+
end
242+
end
243+
end
244+
end
245+
end
246+
end
247+
# :startdoc:
248+
249+
if $0 == __FILE__
250+
case $1
251+
when "1"
252+
tr = SLex.new
253+
print "0: ", tr.inspect, "\n"
254+
tr.def_rule("=") {print "=\n"}
255+
print "1: ", tr.inspect, "\n"
256+
tr.def_rule("==") {print "==\n"}
257+
print "2: ", tr.inspect, "\n"
258+
259+
print "case 1:\n"
260+
print tr.match("="), "\n"
261+
print "case 2:\n"
262+
print tr.match("=="), "\n"
263+
print "case 3:\n"
264+
print tr.match("=>"), "\n"
265+
266+
when "2"
267+
tr = SLex.new
268+
print "0: ", tr.inspect, "\n"
269+
tr.def_rule("=") {print "=\n"}
270+
print "1: ", tr.inspect, "\n"
271+
tr.def_rule("==", proc{false}) {print "==\n"}
272+
print "2: ", tr.inspect, "\n"
273+
274+
print "case 1:\n"
275+
print tr.match("="), "\n"
276+
print "case 2:\n"
277+
print tr.match("=="), "\n"
278+
print "case 3:\n"
279+
print tr.match("=>"), "\n"
280+
end
281+
exit
282+
end

lib/yard/parser/ruby/legacy/ruby_lex.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
require "e2mmap"
2-
require "irb/slex"
2+
require_relative "irb/slex"
33

44
module YARD
55
module Parser::Ruby::Legacy

yard.gemspec

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,4 +21,7 @@ Gem::Specification.new do |s|
2121
s.executables = ['yard', 'yardoc', 'yri']
2222
s.license = 'MIT' if s.respond_to?(:license=)
2323
s.metadata['yard.run'] = 'yri'
24+
25+
# FIXME: The following dependency can be removed when dropping legacy Ruby support.
26+
s.add_runtime_dependency('e2mmap')
2427
end

0 commit comments

Comments
 (0)