lib/rbi/parser.rb in rbi-0.0.7 vs lib/rbi/parser.rb in rbi-0.0.8
- old
+ new
@@ -41,15 +41,27 @@
sig { params(path: String).returns(Tree) }
def self.parse_file(path)
Parser.new.parse_file(path)
end
+ sig { params(paths: T::Array[String]).returns(T::Array[Tree]) }
+ def self.parse_files(paths)
+ parser = Parser.new
+ paths.map { |path| parser.parse_file(path) }
+ end
+
sig { params(string: String).returns(Tree) }
def parse_string(string)
parse(string, file: "-")
end
+ sig { params(strings: T::Array[String]).returns(T::Array[Tree]) }
+ def self.parse_strings(strings)
+ parser = Parser.new
+ strings.map { |string| parser.parse_string(string) }
+ end
+
sig { params(path: String).returns(Tree) }
def parse_file(path)
parse(::File.read(path), file: path)
end
@@ -57,14 +69,13 @@
sig { params(content: String, file: String).returns(Tree) }
def parse(content, file:)
node, comments = Unparser.parse_with_comments(content)
assoc = ::Parser::Source::Comment.associate_locations(node, comments)
- builder = TreeBuilder.new(file: file, comments: assoc)
- builder.separate_header_comments
+ builder = TreeBuilder.new(file: file, comments: comments, nodes_comments_assoc: assoc)
builder.visit(node)
- builder.assoc_dangling_comments(comments)
+ builder.post_process
builder.tree
rescue ::Parser::SyntaxError => e
raise ParseError.new(e.message, Loc.from_ast_loc(file, e.diagnostic.location))
end
end
@@ -103,22 +114,32 @@
attr_reader :tree
sig do
params(
file: String,
- comments: T::Hash[::Parser::Source::Map, T::Array[::Parser::Source::Comment]]
+ comments: T::Array[::Parser::Source::Comment],
+ nodes_comments_assoc: T::Hash[::Parser::Source::Map, T::Array[::Parser::Source::Comment]]
).void
end
- def initialize(file:, comments: {})
+ def initialize(file:, comments: [], nodes_comments_assoc: {})
super()
@file = file
@comments = comments
+ @nodes_comments_assoc = nodes_comments_assoc
@tree = T.let(Tree.new, Tree)
@scopes_stack = T.let([@tree], T::Array[Tree])
@last_sigs = T.let([], T::Array[RBI::Sig])
+
+ separate_header_comments
end
+ sig { void }
+ def post_process
+ assoc_dangling_comments
+ set_root_tree_loc
+ end
+
sig { override.params(node: T.nilable(Object)).void }
def visit(node)
return unless node.is_a?(AST::Node)
case node.type
when :module, :class, :sclass
@@ -144,50 +165,10 @@
else
visit_all(node.children)
end
end
- sig { void }
- def separate_header_comments
- return if @comments.empty?
-
- keep = []
- node = T.must(@comments.keys.first)
- comments = T.must(@comments.values.first)
-
- last_line = T.let(nil, T.nilable(Integer))
- comments.reverse.each do |comment|
- comment_line = comment.location.last_line
-
- break if last_line && comment_line < last_line - 1 ||
- !last_line && comment_line < node.first_line - 1
-
- keep << comment
- last_line = comment_line
- end
-
- @comments[node] = keep.reverse
- end
-
- sig { params(comments: T::Array[::Parser::Source::Comment]).void }
- def assoc_dangling_comments(comments)
- last_line = T.let(nil, T.nilable(Integer))
- (comments - @comments.values.flatten).each do |comment|
- comment_line = comment.location.last_line
- text = comment.text[1..-1].strip
- loc = Loc.from_ast_loc(@file, comment.location)
-
- if last_line && comment_line > last_line + 1
- # Preserve empty lines in file headers
- tree.comments << BlankLine.new(loc: loc)
- end
-
- tree.comments << Comment.new(text, loc: loc)
- last_line = comment_line
- end
- end
-
private
sig { params(node: AST::Node).returns(Scope) }
def parse_scope(node)
loc = node_loc(node)
@@ -330,14 +311,32 @@
TStructProp.new(name, type, default: default_value, loc: loc, comments: comments)
when :const
name, type, default_value = parse_tstruct_prop(node)
TStructConst.new(name, type, default: default_value, loc: loc, comments: comments)
else
- raise ParseError.new("Unsupported send node with name `#{method_name}`", loc)
+ args = parse_send_args(node)
+ Send.new(method_name.to_s, args, loc: loc, comments: comments)
end
end
+ sig { params(node: AST::Node).returns(T::Array[Arg]) }
+ def parse_send_args(node)
+ args = T.let([], T::Array[Arg])
+ node.children[2..-1].each do |child|
+ if child.type == :kwargs
+ child.children.each do |pair|
+ keyword = pair.children.first.children.last.to_s
+ value = parse_expr(pair.children.last)
+ args << KwArg.new(keyword, value)
+ end
+ else
+ args << Arg.new(parse_expr(child))
+ end
+ end
+ args
+ end
+
sig { params(node: AST::Node).returns(T.nilable(RBI::Node)) }
def parse_block(node)
name = node.children[0].children[1]
case name
@@ -433,11 +432,11 @@
Loc.from_ast_loc(@file, node.location)
end
sig { params(node: AST::Node).returns(T::Array[Comment]) }
def node_comments(node)
- comments = @comments[node.location]
+ comments = @nodes_comments_assoc[node.location]
return [] unless comments
comments.map do |comment|
text = comment.text[1..-1].strip
loc = Loc.from_ast_loc(@file, comment.location)
Comment.new(text, loc: loc)
@@ -452,9 +451,63 @@
sig { returns(T::Array[Sig]) }
def current_sigs
sigs = @last_sigs.dup
@last_sigs.clear
sigs
+ end
+
+ sig { void }
+ def assoc_dangling_comments
+ last_line = T.let(nil, T.nilable(Integer))
+ (@comments - @nodes_comments_assoc.values.flatten).each do |comment|
+ comment_line = comment.location.last_line
+ text = comment.text[1..-1].strip
+ loc = Loc.from_ast_loc(@file, comment.location)
+
+ if last_line && comment_line > last_line + 1
+ # Preserve empty lines in file headers
+ tree.comments << BlankLine.new(loc: loc)
+ end
+
+ tree.comments << Comment.new(text, loc: loc)
+ last_line = comment_line
+ end
+ end
+
+ sig { void }
+ def separate_header_comments
+ return if @nodes_comments_assoc.empty?
+
+ keep = []
+ node = T.must(@nodes_comments_assoc.keys.first)
+ comments = T.must(@nodes_comments_assoc.values.first)
+
+ last_line = T.let(nil, T.nilable(Integer))
+ comments.reverse.each do |comment|
+ comment_line = comment.location.last_line
+
+ break if last_line && comment_line < last_line - 1 ||
+ !last_line && comment_line < node.first_line - 1
+
+ keep << comment
+ last_line = comment_line
+ end
+
+ @nodes_comments_assoc[node] = keep.reverse
+ end
+
+ sig { void }
+ def set_root_tree_loc
+ first_loc = tree.nodes.first&.loc
+ last_loc = tree.nodes.last&.loc
+
+ @tree.loc = Loc.new(
+ file: @file,
+ begin_line: first_loc&.begin_line || 0,
+ begin_column: first_loc&.begin_column || 0,
+ end_line: last_loc&.end_line || 0,
+ end_column: last_loc&.end_column || 0
+ )
end
end
class ConstBuilder < ASTVisitor
extend T::Sig