Skip to content

Commit 87147ba

Browse files
Earlopainmatzbot
authored andcommitted
[ruby/prism] Make the ripper shim work with rdoc
The filter class is a 1:1 copy of ruby. rdoc has 32 test failures. It seems to expect `on_sp` in some cases to render code as written. ruby/prism@74bb12c825
1 parent 1c7e19f commit 87147ba

File tree

5 files changed

+83
-20
lines changed

5 files changed

+83
-20
lines changed

lib/prism/prism.gemspec

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,7 @@ Gem::Specification.new do |spec|
104104
"lib/prism/translation/parser/compiler.rb",
105105
"lib/prism/translation/parser/lexer.rb",
106106
"lib/prism/translation/ripper.rb",
107+
"lib/prism/translation/ripper/filter.rb",
107108
"lib/prism/translation/ripper/lexer.rb",
108109
"lib/prism/translation/ripper/sexp.rb",
109110
"lib/prism/translation/ripper/shim.rb",

lib/prism/translation/ripper.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -437,6 +437,7 @@ def self.sexp_raw(src, filename = "-", lineno = 1, raise_errors: false)
437437
end
438438
end
439439

440+
autoload :Filter, "prism/translation/ripper/filter"
440441
autoload :Lexer, "prism/translation/ripper/lexer"
441442
autoload :SexpBuilder, "prism/translation/ripper/sexp"
442443
autoload :SexpBuilderPP, "prism/translation/ripper/sexp"
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
# frozen_string_literal: true
2+
3+
module Prism
4+
module Translation
5+
class Ripper
6+
class Filter # :nodoc:
7+
# :stopdoc:
8+
def initialize(src, filename = '-', lineno = 1)
9+
@__lexer = Lexer.new(src, filename, lineno)
10+
@__line = nil
11+
@__col = nil
12+
@__state = nil
13+
end
14+
15+
def filename
16+
@__lexer.filename
17+
end
18+
19+
def lineno
20+
@__line
21+
end
22+
23+
def column
24+
@__col
25+
end
26+
27+
def state
28+
@__state
29+
end
30+
31+
def parse(init = nil)
32+
data = init
33+
@__lexer.lex.each do |pos, event, tok, state|
34+
@__line, @__col = *pos
35+
@__state = state
36+
data = if respond_to?(event, true)
37+
then __send__(event, tok, data)
38+
else on_default(event, tok, data)
39+
end
40+
end
41+
data
42+
end
43+
44+
private
45+
46+
def on_default(event, token, data)
47+
data
48+
end
49+
# :startdoc:
50+
end
51+
end
52+
end
53+
end

lib/prism/translation/ripper/lexer.rb

Lines changed: 6 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -100,21 +100,17 @@ def to_a
100100
end
101101
end
102102

103-
def initialize(...)
104-
super
105-
@lex_compat = Prism.lex_compat(@source, filepath: filename, line: lineno)
103+
# Pretty much just the same as Prism.lex_compat.
104+
def lex(raise_errors: false)
105+
Ripper.lex(@source, filename, lineno, raise_errors: raise_errors)
106106
end
107107

108108
# Returns the lex_compat result wrapped in `Elem`. Errors are omitted.
109109
# Since ripper is a streaming parser, tokens are expected to be emitted in the order
110110
# that the parser encounters them. This is not implemented.
111-
def parse(raise_errors: false)
112-
if @lex_compat.failure? && raise_errors
113-
raise SyntaxError, @lex_compat.errors.first.message
114-
else
115-
@lex_compat.value.map do |position, event, token, state|
116-
Elem.new(position, event, token, state.to_int)
117-
end
111+
def parse(...)
112+
lex(...).map do |position, event, token, state|
113+
Elem.new(position, event, token, state.to_int)
118114
end
119115
end
120116

test/prism/ruby/ripper_test.rb

Lines changed: 22 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ class RipperTest < TestCase
5959
"whitequark/slash_newline_in_heredocs.txt"
6060
]
6161

62-
omitted_lexer_parse = [
62+
omitted_lex = [
6363
"comments.txt",
6464
"heredoc_percent_q_newline_delimiter.txt",
6565
"heredoc_with_escaped_newline_at_start.txt",
@@ -80,8 +80,20 @@ class RipperTest < TestCase
8080
define_method("#{fixture.test_name}_sexp_raw") { assert_ripper_sexp_raw(fixture.read) }
8181
end
8282

83-
Fixture.each_for_current_ruby(except: incorrect | omitted_lexer_parse) do |fixture|
84-
define_method("#{fixture.test_name}_lexer_parse") { assert_ripper_lexer_parse(fixture.read) }
83+
Fixture.each_for_current_ruby(except: incorrect | omitted_lex) do |fixture|
84+
define_method("#{fixture.test_name}_lex") { assert_ripper_lex(fixture.read) }
85+
end
86+
87+
def test_lexer
88+
lexer = Translation::Ripper::Lexer.new("foo")
89+
expected = [[1, 0], :on_ident, "foo", Translation::Ripper::EXPR_CMDARG]
90+
91+
assert_equal([expected], lexer.lex)
92+
assert_equal(expected, lexer.parse[0].to_a)
93+
assert_equal(lexer.parse[0].to_a, lexer.scan[0].to_a)
94+
95+
assert_equal(%i[on_int on_op], Translation::Ripper::Lexer.new("1 +").lex.map(&:event))
96+
assert_raise(SyntaxError) { Translation::Ripper::Lexer.new("1 +").lex(raise_errors: true) }
8597
end
8698

8799
def test_tokenize
@@ -106,15 +118,15 @@ def assert_ripper_sexp_raw(source)
106118
assert_equal Ripper.sexp_raw(source), Prism::Translation::Ripper.sexp_raw(source)
107119
end
108120

109-
def assert_ripper_lexer_parse(source)
110-
prism = Translation::Ripper::Lexer.new(source).parse
111-
ripper = Ripper::Lexer.new(source).parse
112-
ripper.reject! { |elem| elem.event == :on_sp } # Prism doesn't emit on_sp
113-
ripper.sort_by!(&:pos) # Prism emits tokens by their order in the code, not in parse order
121+
def assert_ripper_lex(source)
122+
prism = Translation::Ripper.lex(source)
123+
ripper = Ripper.lex(source)
124+
ripper.reject! { |elem| elem[1] == :on_sp } # Prism doesn't emit on_sp
125+
ripper.sort_by! { |elem| elem[0] } # Prism emits tokens by their order in the code, not in parse order
114126

115127
[prism.size, ripper.size].max.times do |i|
116-
expected = ripper[i].to_a
117-
actual = prism[i].to_a
128+
expected = ripper[i]
129+
actual = prism[i]
118130
# Since tokens related to heredocs are not emitted in the same order,
119131
# the state also doesn't line up.
120132
if expected[1] == :on_heredoc_end && actual[1] == :on_heredoc_end

0 commit comments

Comments
 (0)