Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support beginless and endless ranges in parser #1549

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions lib/yard/parser/ruby/ast_node.rb
Original file line number Diff line number Diff line change
Expand Up @@ -271,7 +271,7 @@ def has_line?

# @return [Fixnum] the starting line number of the node
def line
line_range && line_range.first
line_range && (line_range.begin || line_range.end)
end

# @return [String] the first line of source represented by the node.
Expand Down Expand Up @@ -345,8 +345,8 @@ def reset_line_info
elsif !children.empty?
f = children.first
l = children.last
self.line_range = Range.new(f.line_range.first, l.line_range.last)
self.source_range = Range.new(f.source_range.first, l.source_range.last)
self.line_range = Range.new(f.line_range.begin, l.line_range.end)
self.source_range = Range.new(f.source_range.begin, l.source_range.end)
elsif @fallback_line || @fallback_source
self.line_range = @fallback_line
self.source_range = @fallback_source
Expand Down
38 changes: 20 additions & 18 deletions lib/yard/parser/ruby/ruby_parser.rb
Original file line number Diff line number Diff line change
Expand Up @@ -242,8 +242,8 @@ def visit_event(node)
if node.respond_to?(:block)
sr = node.block.source_range
lr = node.block.line_range
node.block.source_range = Range.new(sr.first, @tokens.last[2][1] - 1)
node.block.line_range = Range.new(lr.first, @tokens.last[2][0])
node.block.source_range = Range.new(sr.begin, @tokens.last[2][1] - 1)
node.block.line_range = Range.new(lr.begin, @tokens.last[2][0])
end
node
end
Expand Down Expand Up @@ -272,14 +272,14 @@ def add_token(token, data)
if @percent_ary
if token == :words_sep && data !~ /\s\z/
rng = @percent_ary.source_range
rng = Range.new(rng.first, rng.last + data.length)
rng = Range.new(rng.begin, rng.end.to_i + data.length)
@percent_ary.source_range = rng
@tokens << [token, data, [lineno, charno]]
@percent_ary = nil
return
elsif token == :tstring_end && data =~ /\A\s/
rng = @percent_ary.source_range
rng = Range.new(rng.first, rng.last + data.length)
rng = Range.new(rng.begin, rng.end.to_i + data.length)
@percent_ary.source_range = rng
@tokens << [token, data, [lineno, charno]]
@percent_ary = nil
Expand Down Expand Up @@ -377,8 +377,8 @@ def on_unary(op, val)
def on_aref(*args)
@map[:lbracket].pop
ll, lc = *@map[:aref].shift
sr = args.first.source_range.first..lc
lr = args.first.line_range.first..ll
sr = args.first.source_range.begin..lc
lr = args.first.line_range.begin..ll
AstNode.new(:aref, args, :char => sr, :line => lr)
end

Expand Down Expand Up @@ -449,8 +449,8 @@ def on_const_path_ref(*args)
def on_#{kw}(*args)
mapping = @map[#{kw.to_s.sub(/_mod$/, '').inspect}]
mapping.pop if mapping
sr = args.last.source_range.first..args.first.source_range.last
lr = args.last.line_range.first..args.first.line_range.last
sr = args.last.source_range.begin..args.first.source_range.end
lr = args.last.line_range.begin..args.first.line_range.end
#{node_class}.new(:#{kw}, args, :line => lr, :char => sr)
end
eof
Expand All @@ -473,8 +473,8 @@ def on_#{kw}_new(*args)
begin; undef on_#{kw}_add; rescue NameError; end
def on_#{kw}_add(list, item)
last = @source[@ns_charno,1] == "\n" ? @ns_charno - 1 : @ns_charno
list.source_range = (list.source_range.first..last)
list.line_range = (list.line_range.first..lineno)
list.source_range = (list.source_range.begin..last)
list.line_range = (list.line_range.begin..lineno)
list.push(item)
list
end
Expand All @@ -485,9 +485,9 @@ def on_string_literal(*args)
node = visit_event_arr(LiteralNode.new(:string_literal, args))
if args.size == 1
r = args[0].source_range
if node.source_range != Range.new(r.first - 1, r.last + 1)
if node.source_range != Range.new(r.begin - 1, r.end + 1)
klass = AstNode.node_class_for(node[0].type)
r = Range.new(node.source_range.first + 1, node.source_range.last - 1)
r = Range.new(node.source_range.begin + 1, node.source_range.end - 1)
node[0] = klass.new(node[0].type, [@source[r]], :line => node.line_range, :char => r)
end
end
Expand Down Expand Up @@ -573,7 +573,7 @@ def on_comment(comment)
@comments_flags[lineno] = @comments_flags[lineno - 1]
@comments_flags.delete(lineno - 1)
range = @comments_range.delete(lineno - 1)
source_range = range.first..source_range.last
source_range = range.begin..source_range.end
comment = append_comment + "\n" + comment
end

Expand Down Expand Up @@ -627,11 +627,13 @@ def insert_comments
end

# check upwards from line before node; check node's line at the end
((node.line - 1).downto(node.line - 2).to_a + [node.line]).each do |line|
comment = @comments[line]
if comment && !comment.empty?
add_comment(line, node)
break
if (n_l = node.line)
((n_l - 1).downto(n_l - 2).to_a + [n_l]).each do |line|
comment = @comments[line]
if comment && !comment.empty?
add_comment(line, node)
break
end
end
end

Expand Down
33 changes: 33 additions & 0 deletions spec/parser/ruby/ast_node_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -30,4 +30,37 @@
" source: 4..6))\n"
end
end unless YARD.ruby31?

describe "#line" do
it "does not break on beginless or endless ranges" do
skip "Unsupported ruby version" if Gem::Version.new(RUBY_VERSION) < Gem::Version.new('2.7')

obj = YARD::Parser::Ruby::RubyParser.parse("# x\nbye", "x").ast
# obj.range returns (2..2) in this case, but sometimes, this range is set
# to a beginless or endless one.
obj.line_range = Range.new(nil, 2)
expect(obj.line).to eq 2
obj.line_range = Range.new(2, nil)
expect(obj.line).to eq 2
end
end

describe "#reset_line_info" do
it "does not break on beginless or endless ranges" do
skip "Unsupported ruby version" if Gem::Version.new(RUBY_VERSION) < Gem::Version.new('2.7')

obj = YARD::Parser::Ruby::RubyParser.parse("# x\ndef fn(arg); 42; end", "x").ast
obj = obj.first
expect(obj.children.size).to eq 3
fst = obj.children.first
lst = obj.children.last
fst.line_range = Range.new(nil, 10)
fst.source_range = Range.new(nil, 10)
lst.line_range = Range.new(2, nil)
lst.source_range = Range.new(2, nil)
obj.send(:reset_line_info)
expect(obj.line_range).to eq Range.new(nil, nil)
expect(obj.source_range).to eq Range.new(nil, nil)
end
end
end if HAVE_RIPPER