lib/rbi/parser.rb in rbi-0.1.1 vs lib/rbi/parser.rb in rbi-0.1.2
- old
+ new
@@ -1,9 +1,9 @@
# typed: strict
# frozen_string_literal: true
-require "yarp"
+require "prism"
module RBI
class ParseError < StandardError
extend T::Sig
@@ -91,39 +91,37 @@
private
sig { params(source: String, file: String).returns(Tree) }
def parse(source, file:)
- result = YARP.parse(source)
+ result = Prism.parse(source)
unless result.success?
message = result.errors.map { |e| "#{e.message}." }.join(" ")
error = result.errors.first
location = Loc.new(file: file, begin_line: error.location.start_line, begin_column: error.location.start_column)
raise ParseError.new(message, location)
end
visitor = TreeBuilder.new(source, comments: result.comments, file: file)
visitor.visit(result.value)
visitor.tree
- rescue YARP::ParseError => e
- raise ParseError.new(e.message, Loc.from_yarp(file, e.location))
rescue ParseError => e
raise e
rescue => e
last_node = visitor&.last_node
last_location = if last_node
- Loc.from_yarp(file, last_node.location)
+ Loc.from_prism(file, last_node.location)
else
Loc.new(file: file)
end
exception = UnexpectedParserError.new(e, last_location)
exception.print_debug
raise exception
end
- class Visitor < YARP::Visitor
+ class Visitor < Prism::Visitor
extend T::Sig
sig { params(source: String, file: String).void }
def initialize(source, file:)
super()
@@ -132,23 +130,23 @@
@file = file
end
private
- sig { params(node: YARP::Node).returns(Loc) }
+ sig { params(node: Prism::Node).returns(Loc) }
def node_loc(node)
- Loc.from_yarp(@file, node.location)
+ Loc.from_prism(@file, node.location)
end
- sig { params(node: T.nilable(YARP::Node)).returns(T.nilable(String)) }
+ sig { params(node: T.nilable(Prism::Node)).returns(T.nilable(String)) }
def node_string(node)
return unless node
node.slice
end
- sig { params(node: YARP::Node).returns(String) }
+ sig { params(node: Prism::Node).returns(String) }
def node_string!(node)
T.must(node_string(node))
end
end
@@ -156,36 +154,29 @@
extend T::Sig
sig { returns(Tree) }
attr_reader :tree
- sig { returns(T.nilable(YARP::Node)) }
+ sig { returns(T.nilable(Prism::Node)) }
attr_reader :last_node
- sig { params(source: String, comments: T::Array[YARP::Comment], file: String).void }
+ sig { params(source: String, comments: T::Array[Prism::Comment], file: String).void }
def initialize(source, comments:, file:)
super(source, file: file)
- @comments_by_line = T.let(comments.to_h { |c| [c.location.start_line, c] }, T::Hash[Integer, YARP::Comment])
+ @comments_by_line = T.let(comments.to_h { |c| [c.location.start_line, c] }, T::Hash[Integer, Prism::Comment])
@tree = T.let(Tree.new, Tree)
@scopes_stack = T.let([@tree], T::Array[Tree])
- @last_node = T.let(nil, T.nilable(YARP::Node))
+ @last_node = T.let(nil, T.nilable(Prism::Node))
@last_sigs = T.let([], T::Array[RBI::Sig])
@last_sigs_comments = T.let([], T::Array[Comment])
end
- sig { override.params(node: T.nilable(YARP::Node)).void }
- def visit(node)
- return unless node
-
- @last_node = node
- super
- end
-
- sig { override.params(node: YARP::ClassNode).void }
+ sig { override.params(node: Prism::ClassNode).void }
def visit_class_node(node)
+ @last_node = node
scope = Class.new(
node_string!(node.constant_path),
superclass_name: node_string(node.superclass),
loc: node_loc(node),
comments: node_comments(node),
@@ -194,69 +185,77 @@
current_scope << scope
@scopes_stack << scope
visit(node.body)
collect_dangling_comments(node)
@scopes_stack.pop
+ @last_node = nil
end
- sig { override.params(node: YARP::ConstantWriteNode).void }
+ sig { override.params(node: Prism::ConstantWriteNode).void }
def visit_constant_write_node(node)
+ @last_node = node
visit_constant_assign(node)
+ @last_node = nil
end
- sig { override.params(node: YARP::ConstantPathWriteNode).void }
+ sig { override.params(node: Prism::ConstantPathWriteNode).void }
def visit_constant_path_write_node(node)
+ @last_node = node
visit_constant_assign(node)
+ @last_node = nil
end
- sig { params(node: T.any(YARP::ConstantWriteNode, YARP::ConstantPathWriteNode)).void }
+ sig { params(node: T.any(Prism::ConstantWriteNode, Prism::ConstantPathWriteNode)).void }
def visit_constant_assign(node)
struct = parse_struct(node)
current_scope << if struct
struct
elsif type_variable_definition?(node.value)
TypeMember.new(
case node
- when YARP::ConstantWriteNode
+ when Prism::ConstantWriteNode
node.name.to_s
- when YARP::ConstantPathWriteNode
+ when Prism::ConstantPathWriteNode
node_string!(node.target)
end,
node_string!(node.value),
loc: node_loc(node),
comments: node_comments(node),
)
else
Const.new(
case node
- when YARP::ConstantWriteNode
+ when Prism::ConstantWriteNode
node.name.to_s
- when YARP::ConstantPathWriteNode
+ when Prism::ConstantPathWriteNode
node_string!(node.target)
end,
node_string!(node.value),
loc: node_loc(node),
comments: node_comments(node),
)
end
end
- sig { override.params(node: YARP::DefNode).void }
+ sig { override.params(node: Prism::DefNode).void }
def visit_def_node(node)
+ @last_node = node
current_scope << Method.new(
node.name.to_s,
params: parse_params(node.parameters),
sigs: current_sigs,
loc: node_loc(node),
comments: current_sigs_comments + node_comments(node),
is_singleton: !!node.receiver,
)
+ @last_node = nil
end
- sig { override.params(node: YARP::ModuleNode).void }
+ sig { override.params(node: Prism::ModuleNode).void }
def visit_module_node(node)
+ @last_node = node
scope = Module.new(
node_string!(node.constant_path),
loc: node_loc(node),
comments: node_comments(node),
)
@@ -264,140 +263,186 @@
current_scope << scope
@scopes_stack << scope
visit(node.body)
collect_dangling_comments(node)
@scopes_stack.pop
+ @last_node = nil
end
- sig { override.params(node: YARP::ProgramNode).void }
+ sig { override.params(node: Prism::ProgramNode).void }
def visit_program_node(node)
+ @last_node = node
super
collect_orphan_comments
separate_header_comments
set_root_tree_loc
+ @last_node = nil
end
- sig { override.params(node: YARP::SingletonClassNode).void }
+ sig { override.params(node: Prism::SingletonClassNode).void }
def visit_singleton_class_node(node)
+ @last_node = node
scope = SingletonClass.new(
loc: node_loc(node),
comments: node_comments(node),
)
current_scope << scope
@scopes_stack << scope
visit(node.body)
collect_dangling_comments(node)
@scopes_stack.pop
+ @last_node = nil
end
- sig { params(node: YARP::CallNode).void }
+ sig { params(node: Prism::CallNode).void }
def visit_call_node(node)
- message = node.name
+ @last_node = node
+ message = node.name.to_s
case message
when "abstract!", "sealed!", "interface!"
current_scope << Helper.new(
message.delete_suffix("!"),
loc: node_loc(node),
comments: node_comments(node),
)
when "attr_reader"
args = node.arguments
- return unless args.is_a?(YARP::ArgumentsNode) && args.arguments.any?
+ unless args.is_a?(Prism::ArgumentsNode) && args.arguments.any?
+ @last_node = nil
+ return
+ end
+
current_scope << AttrReader.new(
*T.unsafe(args.arguments.map { |arg| node_string!(arg).delete_prefix(":").to_sym }),
sigs: current_sigs,
loc: node_loc(node),
comments: current_sigs_comments + node_comments(node),
)
when "attr_writer"
args = node.arguments
- return unless args.is_a?(YARP::ArgumentsNode) && args.arguments.any?
+ unless args.is_a?(Prism::ArgumentsNode) && args.arguments.any?
+ @last_node = nil
+ return
+ end
+
current_scope << AttrWriter.new(
*T.unsafe(args.arguments.map { |arg| node_string!(arg).delete_prefix(":").to_sym }),
sigs: current_sigs,
loc: node_loc(node),
comments: current_sigs_comments + node_comments(node),
)
when "attr_accessor"
args = node.arguments
- return unless args.is_a?(YARP::ArgumentsNode) && args.arguments.any?
+ unless args.is_a?(Prism::ArgumentsNode) && args.arguments.any?
+ @last_node = nil
+ return
+ end
+
current_scope << AttrAccessor.new(
*T.unsafe(args.arguments.map { |arg| node_string!(arg).delete_prefix(":").to_sym }),
sigs: current_sigs,
loc: node_loc(node),
comments: current_sigs_comments + node_comments(node),
)
when "enums"
block = node.block
- return unless block.is_a?(YARP::BlockNode)
+ unless block.is_a?(Prism::BlockNode)
+ @last_node = nil
+ return
+ end
+
body = block.body
- return unless body.is_a?(YARP::StatementsNode)
+ unless body.is_a?(Prism::StatementsNode)
+ @last_node = nil
+ return
+ end
+
current_scope << TEnumBlock.new(
- body.body.map { |stmt| T.cast(stmt, YARP::ConstantWriteNode).name.to_s },
+ body.body.map { |stmt| T.cast(stmt, Prism::ConstantWriteNode).name.to_s },
loc: node_loc(node),
comments: node_comments(node),
)
when "extend"
args = node.arguments
- return unless args.is_a?(YARP::ArgumentsNode) && args.arguments.any?
+ unless args.is_a?(Prism::ArgumentsNode) && args.arguments.any?
+ @last_node = nil
+ return
+ end
+
current_scope << Extend.new(
*T.unsafe(args.arguments.map { |arg| node_string!(arg) }),
loc: node_loc(node),
comments: node_comments(node),
)
when "include"
args = node.arguments
- return unless args.is_a?(YARP::ArgumentsNode) && args.arguments.any?
+ unless args.is_a?(Prism::ArgumentsNode) && args.arguments.any?
+ @last_node = nil
+ return
+ end
+
current_scope << Include.new(
*T.unsafe(args.arguments.map { |arg| node_string!(arg) }),
loc: node_loc(node),
comments: node_comments(node),
)
when "mixes_in_class_methods"
args = node.arguments
- return unless args.is_a?(YARP::ArgumentsNode) && args.arguments.any?
+ unless args.is_a?(Prism::ArgumentsNode) && args.arguments.any?
+ @last_node = nil
+ return
+ end
+
current_scope << MixesInClassMethods.new(
*T.unsafe(args.arguments.map { |arg| node_string!(arg) }),
loc: node_loc(node),
comments: node_comments(node),
)
when "private", "protected", "public"
args = node.arguments
- if args.is_a?(YARP::ArgumentsNode) && args.arguments.any?
+ if args.is_a?(Prism::ArgumentsNode) && args.arguments.any?
visit(node.arguments)
last_node = @scopes_stack.last&.nodes&.last
case last_node
when Method, Attr
- last_node.visibility = parse_visibility(node.name, node)
+ last_node.visibility = parse_visibility(node.name.to_s, node)
else
raise ParseError.new(
"Unexpected token `#{node.message}` before `#{last_node&.string&.strip}`",
node_loc(node),
)
end
else
- current_scope << parse_visibility(node.name, node)
+ current_scope << parse_visibility(node.name.to_s, node)
end
when "prop", "const"
parse_tstruct_field(node)
when "requires_ancestor"
block = node.block
- return unless block.is_a?(YARP::BlockNode)
+ unless block.is_a?(Prism::BlockNode)
+ @last_node = nil
+ return
+ end
+
body = block.body
- return unless body.is_a?(YARP::StatementsNode)
+ unless body.is_a?(Prism::StatementsNode)
+ @last_node = nil
+ return
+ end
+
current_scope << RequiresAncestor.new(
node_string!(body),
loc: node_loc(node),
comments: node_comments(node),
)
@@ -409,16 +454,18 @@
parse_send_args(node.arguments),
loc: node_loc(node),
comments: node_comments(node),
)
end
+
+ @last_node = nil
end
private
# Collect all the remaining comments within a node
- sig { params(node: YARP::Node).void }
+ sig { params(node: Prism::Node).void }
def collect_dangling_comments(node)
first_line = node.location.start_line
last_line = node.location.end_line
last_node_last_line = node.child_nodes.last&.location&.end_line
@@ -447,11 +494,11 @@
@tree.comments
end
# Preserve blank lines in comments
if last_line && line > last_line + 1
- recv << BlankLine.new(loc: Loc.from_yarp(@file, comment.location))
+ recv << BlankLine.new(loc: Loc.from_prism(@file, comment.location))
end
recv << parse_comment(comment)
last_line = line
end
@@ -474,11 +521,11 @@
comments = @last_sigs_comments.dup
@last_sigs_comments.clear
comments
end
- sig { params(node: YARP::Node).returns(T::Array[Comment]) }
+ sig { params(node: Prism::Node).returns(T::Array[Comment]) }
def node_comments(node)
comments = []
start_line = node.location.start_line
start_line -= 1 unless @comments_by_line.key?(start_line)
@@ -492,25 +539,25 @@
end
comments
end
- sig { params(node: YARP::Comment).returns(Comment) }
+ sig { params(node: Prism::Comment).returns(Comment) }
def parse_comment(node)
- Comment.new(node.location.slice.gsub(/^# ?/, "").rstrip, loc: Loc.from_yarp(@file, node.location))
+ Comment.new(node.location.slice.gsub(/^# ?/, "").rstrip, loc: Loc.from_prism(@file, node.location))
end
- sig { params(node: T.nilable(YARP::Node)).returns(T::Array[Arg]) }
+ sig { params(node: T.nilable(Prism::Node)).returns(T::Array[Arg]) }
def parse_send_args(node)
args = T.let([], T::Array[Arg])
- return args unless node.is_a?(YARP::ArgumentsNode)
+ return args unless node.is_a?(Prism::ArgumentsNode)
node.arguments.each do |arg|
case arg
- when YARP::KeywordHashNode
+ when Prism::KeywordHashNode
arg.elements.each do |assoc|
- next unless assoc.is_a?(YARP::AssocNode)
+ next unless assoc.is_a?(Prism::AssocNode)
args << KwArg.new(
node_string!(assoc.key).delete_suffix(":"),
T.must(node_string(assoc.value)),
)
@@ -521,47 +568,47 @@
end
args
end
- sig { params(node: T.nilable(YARP::Node)).returns(T::Array[Param]) }
+ sig { params(node: T.nilable(Prism::Node)).returns(T::Array[Param]) }
def parse_params(node)
params = []
- return params unless node.is_a?(YARP::ParametersNode)
+ return params unless node.is_a?(Prism::ParametersNode)
node.requireds.each do |param|
- next unless param.is_a?(YARP::RequiredParameterNode)
+ next unless param.is_a?(Prism::RequiredParameterNode)
params << ReqParam.new(
param.name.to_s,
loc: node_loc(param),
comments: node_comments(param),
)
end
node.optionals.each do |param|
- next unless param.is_a?(YARP::OptionalParameterNode)
+ next unless param.is_a?(Prism::OptionalParameterNode)
params << OptParam.new(
param.name.to_s,
node_string!(param.value),
loc: node_loc(param),
comments: node_comments(param),
)
end
rest = node.rest
- if rest.is_a?(YARP::RestParameterNode)
+ if rest.is_a?(Prism::RestParameterNode)
params << RestParam.new(
rest.name&.to_s || "*args",
loc: node_loc(rest),
comments: node_comments(rest),
)
end
node.keywords.each do |param|
- next unless param.is_a?(YARP::KeywordParameterNode)
+ next unless param.is_a?(Prism::KeywordParameterNode)
value = param.value
params << if value
KwOptParam.new(
param.name.to_s.delete_suffix(":"),
@@ -577,62 +624,62 @@
)
end
end
rest_kw = node.keyword_rest
- if rest_kw.is_a?(YARP::KeywordRestParameterNode)
+ if rest_kw.is_a?(Prism::KeywordRestParameterNode)
params << KwRestParam.new(
rest_kw.name&.to_s || "**kwargs",
loc: node_loc(rest_kw),
comments: node_comments(rest_kw),
)
end
block = node.block
- if block.is_a?(YARP::BlockParameterNode)
+ if block.is_a?(Prism::BlockParameterNode)
params << BlockParam.new(
block.name&.to_s || "&block",
loc: node_loc(block),
comments: node_comments(block),
)
end
params
end
- sig { params(node: YARP::CallNode).returns(Sig) }
+ sig { params(node: Prism::CallNode).returns(Sig) }
def parse_sig(node)
@last_sigs_comments = node_comments(node)
builder = SigBuilder.new(@source, file: @file)
builder.current.loc = node_loc(node)
builder.visit_call_node(node)
builder.current
end
- sig { params(node: T.any(YARP::ConstantWriteNode, YARP::ConstantPathWriteNode)).returns(T.nilable(Struct)) }
+ sig { params(node: T.any(Prism::ConstantWriteNode, Prism::ConstantPathWriteNode)).returns(T.nilable(Struct)) }
def parse_struct(node)
send = node.value
- return unless send.is_a?(YARP::CallNode)
+ return unless send.is_a?(Prism::CallNode)
return unless send.message == "new"
recv = send.receiver
return unless recv
return unless node_string(recv) =~ /(::)?Struct/
members = []
keyword_init = T.let(false, T::Boolean)
args = send.arguments
- if args.is_a?(YARP::ArgumentsNode)
+ if args.is_a?(Prism::ArgumentsNode)
args.arguments.each do |arg|
case arg
- when YARP::SymbolNode
+ when Prism::SymbolNode
members << arg.value
- when YARP::KeywordHashNode
+ when Prism::KeywordHashNode
arg.elements.each do |assoc|
- next unless assoc.is_a?(YARP::AssocNode)
+ next unless assoc.is_a?(Prism::AssocNode)
key = node_string!(assoc.key)
val = node_string(assoc.value)
keyword_init = val == "true" if key == "keyword_init:"
@@ -642,13 +689,13 @@
end
end
end
name = case node
- when YARP::ConstantWriteNode
+ when Prism::ConstantWriteNode
node.name.to_s
- when YARP::ConstantPathWriteNode
+ when Prism::ConstantPathWriteNode
node_string!(node.target)
end
loc = node_loc(node)
comments = node_comments(node)
@@ -657,14 +704,14 @@
visit(send.block)
@scopes_stack.pop
struct
end
- sig { params(send: YARP::CallNode).void }
+ sig { params(send: Prism::CallNode).void }
def parse_tstruct_field(send)
args = send.arguments
- return unless args.is_a?(YARP::ArgumentsNode)
+ return unless args.is_a?(Prism::ArgumentsNode)
name_arg, type_arg, *rest = args.arguments
return unless name_arg
return unless type_arg
@@ -673,14 +720,14 @@
loc = node_loc(send)
comments = node_comments(send)
default_value = T.let(nil, T.nilable(String))
rest&.each do |arg|
- next unless arg.is_a?(YARP::KeywordHashNode)
+ next unless arg.is_a?(Prism::KeywordHashNode)
arg.elements.each do |assoc|
- next unless assoc.is_a?(YARP::AssocNode)
+ next unless assoc.is_a?(Prism::AssocNode)
if node_string(assoc.key) == "default:"
default_value = node_string(assoc.value)
end
end
@@ -694,11 +741,11 @@
else
raise ParseError.new("Unexpected message `#{send.message}`", loc)
end
end
- sig { params(name: String, node: YARP::Node).returns(Visibility) }
+ sig { params(name: String, node: Prism::Node).returns(Visibility) }
def parse_visibility(name, node)
case name
when "public"
Public.new(loc: node_loc(node))
when "protected"
@@ -732,13 +779,13 @@
end_line: last_loc&.end_line || 0,
end_column: last_loc&.end_column || 0,
)
end
- sig { params(node: T.nilable(YARP::Node)).returns(T::Boolean) }
+ sig { params(node: T.nilable(Prism::Node)).returns(T::Boolean) }
def type_variable_definition?(node)
- return false unless node.is_a?(YARP::CallNode)
+ return false unless node.is_a?(Prism::CallNode)
return false unless node.block
node.message == "type_member" || node.message == "type_template"
end
end
@@ -754,25 +801,25 @@
super
@current = T.let(Sig.new, Sig)
end
- sig { override.params(node: YARP::CallNode).void }
+ sig { override.params(node: Prism::CallNode).void }
def visit_call_node(node)
case node.message
when "sig"
args = node.arguments
- if args.is_a?(YARP::ArgumentsNode)
+ if args.is_a?(Prism::ArgumentsNode)
args.arguments.each do |arg|
@current.is_final = node_string(arg) == ":final"
end
end
when "abstract"
@current.is_abstract = true
when "checked"
args = node.arguments
- if args.is_a?(YARP::ArgumentsNode)
+ if args.is_a?(Prism::ArgumentsNode)
arg = node_string(args.arguments.first)
@current.checked = arg&.delete_prefix(":")&.to_sym
end
when "override"
@current.is_override = true
@@ -780,17 +827,17 @@
@current.is_overridable = true
when "params"
visit(node.arguments)
when "returns"
args = node.arguments
- if args.is_a?(YARP::ArgumentsNode)
+ if args.is_a?(Prism::ArgumentsNode)
first = args.arguments.first
@current.return_type = node_string!(first) if first
end
when "type_parameters"
args = node.arguments
- if args.is_a?(YARP::ArgumentsNode)
+ if args.is_a?(Prism::ArgumentsNode)
args.arguments.each do |arg|
@current.type_params << node_string!(arg).delete_prefix(":")
end
end
when "void"
@@ -799,10 +846,10 @@
visit(node.receiver)
visit(node.block)
end
- sig { override.params(node: YARP::AssocNode).void }
+ sig { override.params(node: Prism::AssocNode).void }
def visit_assoc_node(node)
@current.params << SigParam.new(
node_string!(node.key).delete_suffix(":"),
node_string!(T.must(node.value)),
)