Module: Optimize::RbsParser
- Defined in:
- lib/optimize/rbs_parser.rb
Overview
Minimal parser for inline ‘@rbs` comments.
Recognized form (one-line signature immediately preceding a def):
# @rbs (Type, Type, ...) -> Type
def method_name(args...)
Multi-line signatures, generics, block types, and rbs-inline’s other forms are out of scope for this plan.
Defined Under Namespace
Classes: Signature
Constant Summary collapse
- SIG_RE =
/\A#\s*@rbs\s*\((.*?)\)\s*->\s*(\S+)/
Class Method Summary collapse
- .parse(source, file) ⇒ Object
- .scan_back_for_rbs(comment_by_line, def_line) ⇒ Object
- .split_arg_types(inside_parens) ⇒ Object
- .walk(node, class_ctx, &block) ⇒ Object
Class Method Details
.parse(source, file) ⇒ Object
24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 |
# File 'lib/optimize/rbs_parser.rb', line 24 def parse(source, file) result = Prism.parse(source) comment_by_line = {} result.comments.each do |c| comment_by_line[c.location.start_line] = c.slice end signatures = [] walk(result.value, nil) do |node, class_ctx| next unless node.is_a?(Prism::DefNode) def_line = node.location.start_line rbs_text = scan_back_for_rbs(comment_by_line, def_line) next unless rbs_text match = SIG_RE.match(rbs_text) next unless match arg_types = split_arg_types(match[1]) signatures << Signature.new( method_name: node.name, receiver_class: class_ctx, arg_types: arg_types, return_type: match[2], file: file, line: def_line, ) end signatures end |
.scan_back_for_rbs(comment_by_line, def_line) ⇒ Object
64 65 66 67 68 69 70 71 72 73 |
# File 'lib/optimize/rbs_parser.rb', line 64 def scan_back_for_rbs(comment_by_line, def_line) line = def_line - 1 while line >= 1 text = comment_by_line[line] return nil if text.nil? return text if text =~ /@rbs/ line -= 1 end nil end |
.split_arg_types(inside_parens) ⇒ Object
75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 |
# File 'lib/optimize/rbs_parser.rb', line 75 def split_arg_types(inside_parens) return [] if inside_parens.strip.empty? depth = 0 buf = +"" parts = [] inside_parens.each_char do |ch| case ch when "(", "[", "<" then depth += 1; buf << ch when ")", "]", ">" then depth -= 1; buf << ch when "," if depth.zero? parts << buf.strip buf = +"" else buf << ch end else buf << ch end end parts << buf.strip unless buf.empty? parts end |
.walk(node, class_ctx, &block) ⇒ Object
52 53 54 55 56 57 58 59 60 61 62 |
# File 'lib/optimize/rbs_parser.rb', line 52 def walk(node, class_ctx, &block) return unless node.is_a?(Prism::Node) if node.is_a?(Prism::ClassNode) new_ctx = node.constant_path.slice yield node, class_ctx node.compact_child_nodes.each { |c| walk(c, new_ctx, &block) } else yield node, class_ctx node.compact_child_nodes.each { |c| walk(c, class_ctx, &block) } end end |