ruby_mod_kit 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (69) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE.txt +21 -0
  3. data/README.md +99 -0
  4. data/examples/user.rb +83 -0
  5. data/examples/user.rbm +47 -0
  6. data/exe/ruby_mod_kit +5 -0
  7. data/lib/ruby_mod_kit/cli.rb +27 -0
  8. data/lib/ruby_mod_kit/generation.rb +170 -0
  9. data/lib/ruby_mod_kit/memo/class.rb +27 -0
  10. data/lib/ruby_mod_kit/memo/ivar.rb +42 -0
  11. data/lib/ruby_mod_kit/memo/method.rb +49 -0
  12. data/lib/ruby_mod_kit/memo/offset_memo.rb +26 -0
  13. data/lib/ruby_mod_kit/memo/parameter.rb +39 -0
  14. data/lib/ruby_mod_kit/memo.rb +73 -0
  15. data/lib/ruby_mod_kit/mission/fix_parse_error.rb +213 -0
  16. data/lib/ruby_mod_kit/mission/ivar_arg.rb +42 -0
  17. data/lib/ruby_mod_kit/mission/overload.rb +73 -0
  18. data/lib/ruby_mod_kit/mission/type_attr.rb +75 -0
  19. data/lib/ruby_mod_kit/mission/type_parameter.rb +39 -0
  20. data/lib/ruby_mod_kit/mission/type_return.rb +33 -0
  21. data/lib/ruby_mod_kit/mission.rb +40 -0
  22. data/lib/ruby_mod_kit/node/call_node.rb +30 -0
  23. data/lib/ruby_mod_kit/node/class_node.rb +37 -0
  24. data/lib/ruby_mod_kit/node/def_node.rb +57 -0
  25. data/lib/ruby_mod_kit/node/parameter_node.rb +42 -0
  26. data/lib/ruby_mod_kit/node/program_node.rb +23 -0
  27. data/lib/ruby_mod_kit/node/statements_node.rb +27 -0
  28. data/lib/ruby_mod_kit/node/symbol_node.rb +34 -0
  29. data/lib/ruby_mod_kit/node/untyped_node.rb +25 -0
  30. data/lib/ruby_mod_kit/node.rb +164 -0
  31. data/lib/ruby_mod_kit/offset_diff.rb +37 -0
  32. data/lib/ruby_mod_kit/transpiler.rb +20 -0
  33. data/lib/ruby_mod_kit/version.rb +7 -0
  34. data/lib/ruby_mod_kit.rb +59 -0
  35. data/ruby_mod_kit.gemspec +51 -0
  36. data/sig/generated/examples/user.rbs +60 -0
  37. data/sig/generated/ruby_mod_kit/cli.rbs +14 -0
  38. data/sig/generated/ruby_mod_kit/generation.rbs +101 -0
  39. data/sig/generated/ruby_mod_kit/memo/class.rbs +20 -0
  40. data/sig/generated/ruby_mod_kit/memo/ivar.rbs +30 -0
  41. data/sig/generated/ruby_mod_kit/memo/located.rbs +14 -0
  42. data/sig/generated/ruby_mod_kit/memo/method.rbs +37 -0
  43. data/sig/generated/ruby_mod_kit/memo/offset_memo.rbs +20 -0
  44. data/sig/generated/ruby_mod_kit/memo/parameter.rbs +33 -0
  45. data/sig/generated/ruby_mod_kit/memo/parameter_type.rbs +14 -0
  46. data/sig/generated/ruby_mod_kit/memo.rbs +41 -0
  47. data/sig/generated/ruby_mod_kit/mission/fix_parse_error.rbs +73 -0
  48. data/sig/generated/ruby_mod_kit/mission/ivar_arg.rbs +19 -0
  49. data/sig/generated/ruby_mod_kit/mission/overload.rbs +20 -0
  50. data/sig/generated/ruby_mod_kit/mission/type_attr.rbs +18 -0
  51. data/sig/generated/ruby_mod_kit/mission/type_parameter.rbs +18 -0
  52. data/sig/generated/ruby_mod_kit/mission/type_return.rbs +18 -0
  53. data/sig/generated/ruby_mod_kit/mission.rbs +25 -0
  54. data/sig/generated/ruby_mod_kit/node/call_node.rbs +25 -0
  55. data/sig/generated/ruby_mod_kit/node/class_node.rbs +29 -0
  56. data/sig/generated/ruby_mod_kit/node/def_node.rbs +39 -0
  57. data/sig/generated/ruby_mod_kit/node/parameter_node.rbs +26 -0
  58. data/sig/generated/ruby_mod_kit/node/program_node.rbs +16 -0
  59. data/sig/generated/ruby_mod_kit/node/statements_node.rbs +21 -0
  60. data/sig/generated/ruby_mod_kit/node/symbol_node.rbs +24 -0
  61. data/sig/generated/ruby_mod_kit/node/untyped_node.rbs +21 -0
  62. data/sig/generated/ruby_mod_kit/node.rbs +63 -0
  63. data/sig/generated/ruby_mod_kit/offset_diff.rbs +20 -0
  64. data/sig/generated/ruby_mod_kit/transpiler.rbs +11 -0
  65. data/sig/generated/ruby_mod_kit/version.rbs +5 -0
  66. data/sig/generated/ruby_mod_kit.rbs +33 -0
  67. data/sig/sorted_set.rbs +8 -0
  68. data/sig/thor.rbs +3 -0
  69. metadata +157 -0
@@ -0,0 +1,73 @@
1
+ # frozen_string_literal: true
2
+
3
+ # rbs_inline: enabled
4
+
5
+ module RubyModKit
6
+ # The class of transpiler generation.
7
+ class Memo
8
+ # @rbs @classes_memo: Hash[Integer, Memo::Class]
9
+ # @rbs @methods_memo: Hash[Integer, Memo::Method]
10
+ # @rbs @parameters_memo: Hash[Integer, Memo::Parameter]
11
+
12
+ attr_reader :classes_memo #: Hash[Integer, Memo::Class]
13
+ attr_reader :methods_memo #: Hash[Integer, Memo::Method]
14
+ attr_reader :parameters_memo #: Hash[Integer, Memo::Parameter]
15
+
16
+ # @rbs return: void
17
+ def initialize
18
+ @classes_memo = {}
19
+ @methods_memo = {}
20
+ @parameters_memo = {}
21
+ end
22
+
23
+ # @rbs offset_diff: OffsetDiff
24
+ # @rbs return: void
25
+ def succ(offset_diff)
26
+ [@methods_memo, @parameters_memo, @classes_memo].each do |offset_node_memo|
27
+ new_offset_node_memo = {}
28
+ offset_node_memo.each_value do |node_memo|
29
+ node_memo.succ(offset_diff)
30
+ new_offset_node_memo[node_memo.offset] = node_memo
31
+ end
32
+ offset_node_memo.replace(new_offset_node_memo)
33
+ end
34
+ self
35
+ end
36
+
37
+ # @rbs class_node: Node::ClassNode
38
+ # @rbs return: Memo::Class
39
+ def class_memo(class_node)
40
+ @classes_memo[class_node.offset] ||= Memo::Class.new(class_node)
41
+ end
42
+
43
+ # @rbs def_node: Node::DefNode
44
+ # @rbs return: Memo::Method
45
+ def method_memo(def_node)
46
+ @methods_memo[def_node.offset] ||= Memo::Method.new(def_node)
47
+ end
48
+
49
+ # @rbs node: Node
50
+ # @rbs return: Memo::Parameter
51
+ def parameter_memo(node)
52
+ memo = @parameters_memo[node.offset] ||= Memo::Parameter.new(node.offset)
53
+ def_node = node.def_node_at(node.offset)
54
+ raise RubyModKit::Error unless def_node.is_a?(Node::DefNode)
55
+
56
+ method_memo(def_node).add_parameter(memo)
57
+ end
58
+
59
+ class << self
60
+ # @rbs type: String
61
+ # @rbs return: String
62
+ def unify_type(type)
63
+ type[/\A\(([^()]*)\)\z/, 1] || type
64
+ end
65
+ end
66
+ end
67
+ end
68
+
69
+ require_relative "memo/offset_memo"
70
+ require_relative "memo/class"
71
+ require_relative "memo/ivar"
72
+ require_relative "memo/method"
73
+ require_relative "memo/parameter"
@@ -0,0 +1,213 @@
1
+ # frozen_string_literal: true
2
+
3
+ # rbs_inline: enabled
4
+
5
+ module RubyModKit
6
+ class Mission
7
+ # The mission for parameter types
8
+ class FixParseError < Mission
9
+ # @rbs @previous_error_messages: Array[String]
10
+
11
+ # @rbs return: void
12
+ def initialize
13
+ super(0)
14
+ @previous_error_messages = []
15
+ end
16
+
17
+ # @rbs generation: Generation
18
+ # @rbs root_node: Node
19
+ # @rbs parse_result: Prism::ParseResult
20
+ # @rbs memo: Memo
21
+ # @rbs return: bool
22
+ def perform(generation, root_node, parse_result, memo)
23
+ return true if parse_result.errors.empty?
24
+
25
+ check_prev_errors(generation, parse_result)
26
+ @previous_error_messages = parse_result.errors.map(&:message)
27
+
28
+ parse_result.errors.each do |parse_error|
29
+ case parse_error.type
30
+ when :argument_formal_ivar
31
+ fix_argument_formal_ivar(parse_error, generation, root_node, memo)
32
+ when :argument_formal_constant
33
+ fix_argument_formal_constant(parse_error, generation)
34
+ when :unexpected_token_ignore
35
+ case parse_error.location.slice
36
+ when "=>"
37
+ fix_unexpected_assoc(parse_error, generation, root_node, memo)
38
+ when ":"
39
+ fix_unexpected_colon(parse_error, generation, root_node, memo)
40
+ end
41
+ when :def_params_term_paren
42
+ fix_def_params_term_paren(parse_error, generation, root_node, memo)
43
+ end
44
+ end
45
+
46
+ false
47
+ end
48
+
49
+ # @rbs generation: Generation
50
+ # @rbs parse_result: Prism::ParseResult
51
+ # @rbs return: void
52
+ def check_prev_errors(generation, parse_result)
53
+ return if @previous_error_messages.empty?
54
+ return if parse_result.errors.empty?
55
+ return if @previous_error_messages != parse_result.errors.map(&:message)
56
+
57
+ message = +""
58
+ parse_result.errors.each do |parse_error|
59
+ message << "\n" unless message.empty?
60
+ message << "#{generation.name}:#{parse_error.location.start_line}:#{parse_error.message} "
61
+ message << "(#{parse_error.type})\n"
62
+ message << parse_result.source.lines[parse_error.location.start_line - 1].chomp << "\n"
63
+ message << "#{" " * parse_error.location.start_column}^#{"~" * [parse_error.location.length - 1, 0].max}"
64
+ end
65
+ raise RubyModKit::SyntaxError, message
66
+ end
67
+
68
+ # @rbs parse_error: Prism::ParseError
69
+ # @rbs generation: Generation
70
+ # @rbs root_node: Node
71
+ # @rbs memo: Memo
72
+ # @rbs return: void
73
+ def fix_def_params_term_paren(parse_error, generation, root_node, memo)
74
+ column = parse_error.location.start_column - 1
75
+ return if column < 0
76
+
77
+ line = generation.line(parse_error)[column..] || return
78
+ line =~ /\A\*(.*?)\s*=>\s*/
79
+ length = ::Regexp.last_match(0)&.length || return
80
+ type = ::Regexp.last_match(1) || return
81
+ offset = parse_error.location.start_offset - 1
82
+ parameter_position_node = root_node.node_at(offset + length) || return
83
+
84
+ generation[parse_error.location.start_offset, length - 1] = ""
85
+ parameter_memo = memo.parameter_memo(parameter_position_node)
86
+ parameter_memo.type = type
87
+ parameter_memo.qualifier = "*"
88
+ end
89
+
90
+ # @rbs parse_error: Prism::ParseError
91
+ # @rbs generation: Generation
92
+ # @rbs root_node: Node
93
+ # @rbs memo: Memo
94
+ # @rbs return: void
95
+ def fix_argument_formal_ivar(parse_error, generation, root_node, memo)
96
+ src_offset = parse_error.location.start_offset
97
+
98
+ name = parse_error.location.slice[1..]
99
+ raise RubyModKit::Error unless name
100
+
101
+ parameter_position_node = root_node.node_at(src_offset)
102
+ raise RubyModKit::Error unless parameter_position_node
103
+
104
+ generation[src_offset, parse_error.location.length] = name
105
+ parameter_memo = memo.parameter_memo(parameter_position_node)
106
+ parameter_memo.ivar_parameter = true
107
+ generation.add_mission(Mission::IvarArg.new(src_offset))
108
+
109
+ return unless parameter_memo.untyped?
110
+
111
+ class_node = root_node.class_node_at(parse_error.location.start_offset) || return
112
+ ivar_memo_type = memo.class_memo(class_node).ivar_memo(name.to_sym).type || return
113
+ parameter_memo.type = ivar_memo_type
114
+ end
115
+
116
+ # @rbs parse_error: Prism::ParseError
117
+ # @rbs generation: Generation
118
+ # @rbs return: void
119
+ def fix_argument_formal_constant(parse_error, generation)
120
+ line = generation.line(parse_error)
121
+ line = line[parse_error.location.start_column..] || return
122
+ parameter_type = line[/(\A[A-Z]\w*(?:::[A-Z]\w*)+)(?:\s*=>\s*)/, 1] || return
123
+ src_offset = parse_error.location.start_offset
124
+ generation[src_offset, parameter_type.length] = "(#{parameter_type})"
125
+ end
126
+
127
+ # @rbs parse_error: Prism::ParseError
128
+ # @rbs generation: Generation
129
+ # @rbs root_node: Node
130
+ # @rbs memo: Memo
131
+ # @rbs return: void
132
+ def fix_unexpected_assoc(parse_error, generation, root_node, memo)
133
+ def_node = root_node.def_node_at(parse_error.location.start_offset) || return
134
+ def_parent_node = def_node.parent
135
+ parameters_node, body_node, = def_node.children
136
+ return if !def_parent_node || !parameters_node || !body_node
137
+
138
+ last_parameter_node = parameters_node.children.max_by(&:offset) || return
139
+ last_parameter_offset = last_parameter_node.offset
140
+
141
+ right_node = body_node.children.find { _1.offset >= parse_error.location.end_offset } || return
142
+ right_offset = right_node.offset
143
+ parameter_type = generation[last_parameter_offset...right_offset] || raise(RubyModKit::Error)
144
+ parameter_type = parameter_type.sub(/\s*=>\s*\z/, "")
145
+ generation[last_parameter_offset, right_offset - last_parameter_offset] = ""
146
+ memo.parameter_memo(last_parameter_node).type = parameter_type
147
+ end
148
+
149
+ # @rbs parse_error: Prism::ParseError
150
+ # @rbs generation: Generation
151
+ # @rbs root_node: Node
152
+ # @rbs memo: Memo
153
+ # @rbs return: void
154
+ def fix_unexpected_colon(parse_error, generation, root_node, memo)
155
+ parent_node = root_node.statements_node_at(parse_error.location.start_offset)&.parent
156
+ case parent_node
157
+ when Node::DefNode
158
+ fix_unexpected_colon_in_def(parse_error, generation, root_node, parent_node, memo)
159
+ when Node::ClassNode
160
+ fix_unexpected_colon_in_module(parse_error, generation, parent_node, memo)
161
+ end
162
+ end
163
+
164
+ # @rbs parse_error: Prism::ParseError
165
+ # @rbs generation: Generation
166
+ # @rbs root_node: Node
167
+ # @rbs def_node: Node::DefNode
168
+ # @rbs memo: Memo
169
+ # @rbs return: void
170
+ def fix_unexpected_colon_in_def(parse_error, generation, root_node, def_node, memo)
171
+ lparen_loc = def_node.lparen_loc
172
+ rparen_loc = def_node.rparen_loc
173
+ if !lparen_loc && !rparen_loc
174
+ src_offset = def_node.name_loc.end_offset
175
+ elsif lparen_loc && rparen_loc && lparen_loc.slice == "(" && rparen_loc.slice == ")"
176
+ src_offset = rparen_loc.end_offset
177
+ else
178
+ return
179
+ end
180
+ return if generation[src_offset...parse_error.location.start_offset] !~ /\A\s*\z/
181
+
182
+ return_type_location = root_node.node_at(parse_error.location.end_offset + 1)&.location || return_type_location
183
+ generation[src_offset, return_type_location.end_offset - src_offset] = ""
184
+ memo.method_memo(def_node).type = return_type_location.slice
185
+ end
186
+
187
+ # @rbs parse_error: Prism::ParseError
188
+ # @rbs generation: Generation
189
+ # @rbs class_node: Node::ClassNode
190
+ # @rbs memo: Memo
191
+ # @rbs return: void
192
+ def fix_unexpected_colon_in_module(parse_error, generation, class_node, memo)
193
+ line = generation.line(parse_error)
194
+ line_offset = generation.src_offset(parse_error) || return
195
+ attr_patterns = %i[attr_reader reader getter attr_writer writer setter attr_accessor accessor property]
196
+ return if line !~ /(\A\s*)(?:(#{attr_patterns.join("|")}) )?@(\w*)\s*:\s*(.*)/
197
+
198
+ length = ::Regexp.last_match(0)&.length
199
+ indent = ::Regexp.last_match(1)
200
+ attr_kind = ::Regexp.last_match(2)
201
+ ivar_name = ::Regexp.last_match(3)
202
+ type = ::Regexp.last_match(4)
203
+ return if !length || !indent || !ivar_name || !type
204
+
205
+ ivar_memo = memo.class_memo(class_node).ivar_memo(ivar_name.to_sym)
206
+ ivar_memo.type = type
207
+ ivar_memo.attr_kind = attr_kind if attr_kind
208
+
209
+ generation[line_offset, length] = "#{indent}# @rbs @#{ivar_name}: #{Memo.unify_type(type)}"
210
+ end
211
+ end
212
+ end
213
+ end
@@ -0,0 +1,42 @@
1
+ # frozen_string_literal: true
2
+
3
+ # rbs_inline: enabled
4
+
5
+ module RubyModKit
6
+ class Mission
7
+ # The mission for instance variable arguments
8
+ class IvarArg < Mission
9
+ # @rbs @assignment: String
10
+
11
+ attr_reader :assignment #: String
12
+
13
+ # @rbs generation: Generation
14
+ # @rbs root_node: Node
15
+ # @rbs _parse_result: Prism::ParseResult
16
+ # @rbs _memo: Memo
17
+ # @rbs return: bool
18
+ def perform(generation, root_node, _parse_result, _memo)
19
+ parameter_node = root_node.parameter_node_at(@offset)
20
+ raise RubyModKit::Error unless parameter_node
21
+
22
+ def_node = root_node.def_node_at(@offset)
23
+ raise RubyModKit::Error, "DefNode not found" unless def_node
24
+
25
+ def_body_location = def_node.body_location
26
+ end_loc = def_node.end_keyword_loc
27
+ if def_body_location
28
+ indent = def_body_location.start_column
29
+ src_offset = def_body_location.start_offset - indent
30
+ elsif end_loc
31
+ indent = end_loc.start_column + 2
32
+ src_offset = end_loc.start_offset - indent + 2
33
+ end
34
+ raise RubyModKit::Error if !src_offset || !indent
35
+
36
+ name = parameter_node.name
37
+ generation[src_offset, 0] = "#{" " * indent}@#{name} = #{name}\n"
38
+ true
39
+ end
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,73 @@
1
+ # frozen_string_literal: true
2
+
3
+ # rbs_inline: enabled
4
+
5
+ module RubyModKit
6
+ class Mission
7
+ # The mission for overload
8
+ class Overload < Mission
9
+ OVERLOAD_METHOD_MAP = {
10
+ "*": "_mul",
11
+ }.freeze #: Hash[Symbol, String]
12
+
13
+ # @rbs return: void
14
+ def initialize
15
+ super(0)
16
+ end
17
+
18
+ # @rbs generation: Generation
19
+ # @rbs root_node: Node
20
+ # @rbs parse_result: Prism::ParseResult
21
+ # @rbs memo: Memo
22
+ # @rbs return: bool
23
+ def perform(generation, root_node, parse_result, memo)
24
+ method_memo_groups = memo.methods_memo.each_value.group_by do |method_memo|
25
+ [root_node.class_node_at(method_memo.offset), method_memo.name]
26
+ end
27
+ method_memo_groups.each_value do |method_memos|
28
+ next if method_memos.length <= 1
29
+
30
+ first_method_memo = method_memos.first
31
+ name = first_method_memo.name
32
+ first_def_node = root_node.def_node_at(first_method_memo.offset)
33
+ raise RubyModKit::Error unless first_def_node.is_a?(Node::DefNode)
34
+ raise RubyModKit::Error unless name.is_a?(Symbol)
35
+
36
+ start_line = first_def_node.location.start_line - 1
37
+ indent = parse_result.source.lines[start_line][/\A */] || ""
38
+ start_line -= 1 while parse_result.source.lines[start_line - 1] =~ /^ *# *@rbs /
39
+ src_offset = parse_result.source.offsets[start_line]
40
+ script = +""
41
+
42
+ method_memos.each do |method_memo|
43
+ script << if script.empty?
44
+ "# @rbs"
45
+ else
46
+ "# |"
47
+ end
48
+ type = method_memo.type
49
+ type = "(#{type})" if type.include?(" ")
50
+ script << " (#{method_memo.parameters.map(&:type).join(", ")}) -> #{type}\n"
51
+ end
52
+ script << "def #{name}(*args)\n case args\n"
53
+ overload_prefix = +"#{OVERLOAD_METHOD_MAP[name] || name}_"
54
+ method_memos.each_with_index do |method_memo, i|
55
+ overload_name = "#{overload_prefix}_overload#{i}"
56
+ def_node = root_node.def_node_at(method_memo.offset)
57
+ raise RubyModKit::Error if !def_node || !def_node.is_a?(Node::DefNode)
58
+
59
+ name_loc = def_node.name_loc
60
+ generation[name_loc.start_offset, name_loc.length] = overload_name
61
+ script << " in [#{method_memo.parameters.map(&:type).join(", ")}]\n"
62
+ script << " #{overload_name}(*args)\n"
63
+ end
64
+ script << " end\nend\n\n"
65
+
66
+ script.gsub!(/^(?=.)/, indent)
67
+ generation[src_offset, 0] = script
68
+ end
69
+ true
70
+ end
71
+ end
72
+ end
73
+ end
@@ -0,0 +1,75 @@
1
+ # frozen_string_literal: true
2
+
3
+ # rbs_inline: enabled
4
+
5
+ module RubyModKit
6
+ class Mission
7
+ # The mission for parameter types
8
+ class TypeAttr < Mission
9
+ # @rbs return: void
10
+ def initialize
11
+ super(0)
12
+ end
13
+
14
+ # @rbs generation: Generation
15
+ # @rbs root_node: Node
16
+ # @rbs _parse_result: Prism::ParseResult
17
+ # @rbs memo: Memo
18
+ # @rbs return: bool
19
+ def perform(generation, root_node, _parse_result, memo)
20
+ memo.classes_memo.each_value do |class_memo|
21
+ ivars_memo = class_memo.ivars_memo.dup
22
+ class_node = root_node.class_node_at(class_memo.offset) || raise(RubyModKit::Error)
23
+ attr_adding_line = 0
24
+ class_node.body_node&.children&.each do |call_node|
25
+ break if ivars_memo.empty?
26
+ next unless call_node.is_a?(Node::CallNode)
27
+ next unless %i[attr_reader attr_writer attr_accessor].include?(call_node.name)
28
+
29
+ attr_adding_line = call_node.location.end_line
30
+ argument_nodes = call_node.children[0].children
31
+ next if argument_nodes.size != 1 || !argument_nodes[0].is_a?(Node::SymbolNode)
32
+
33
+ name = argument_nodes[0].value || next
34
+ ivar_memo = ivars_memo.delete(name) || next
35
+ line = generation.line(call_node)
36
+ length = line[/\A\s*(#{call_node.name}\s+:#{name})(?=\n\z)/, 1]&.length || next
37
+ generation[call_node.location.start_offset + length, 0] = " #: #{ivar_memo.type}"
38
+ end
39
+
40
+ ivars_memo.keep_if { |_, ivar_memo| ivar_memo.attr_kind }
41
+ next if ivars_memo.empty?
42
+
43
+ add_first_separator_line = false
44
+ if attr_adding_line == 0
45
+ attr_adding_line = class_node.location.start_line
46
+ prev_line = nil
47
+ while generation.line(attr_adding_line) =~ /\A\s*#.*|\A$/
48
+ prev_line = ::Regexp.last_match(0)
49
+ attr_adding_line += 1
50
+ end
51
+ add_first_separator_line = prev_line != ""
52
+ end
53
+ line = generation.line(attr_adding_line) || next
54
+ add_separator_line = line != "\n" && line !~ /\A\s*end$/
55
+ offset = generation.src_offset(attr_adding_line) || next
56
+
57
+ if class_node.body_node
58
+ first_line = generation.line(class_node.body_node)
59
+ indent = first_line[/\A\s*/] || raise(RubyModKit::Error)
60
+ else
61
+ class_line = generation.line(class_node)
62
+ indent = " #{class_line[/\A\s*/]}"
63
+ end
64
+
65
+ generation[offset, 0] = "\n" if add_first_separator_line
66
+ ivars_memo.each do |name, ivar_memo|
67
+ generation[offset, 0] = "#{indent}#{ivar_memo.attr_kind} :#{name} #: #{ivar_memo.type}\n"
68
+ end
69
+ generation[offset, 0] = "\n" if add_separator_line
70
+ end
71
+ true
72
+ end
73
+ end
74
+ end
75
+ end
@@ -0,0 +1,39 @@
1
+ # frozen_string_literal: true
2
+
3
+ # rbs_inline: enabled
4
+
5
+ module RubyModKit
6
+ class Mission
7
+ # The mission for parameter types
8
+ class TypeParameter < Mission
9
+ # @rbs return: void
10
+ def initialize
11
+ super(0)
12
+ end
13
+
14
+ # @rbs generation: Generation
15
+ # @rbs root_node: Node
16
+ # @rbs parse_result: Prism::ParseResult
17
+ # @rbs memo: Memo
18
+ # @rbs return: bool
19
+ def perform(generation, root_node, parse_result, memo)
20
+ memo.parameters_memo.each do |offset, parameter_memo|
21
+ next if parameter_memo.untyped?
22
+
23
+ def_node = root_node.def_node_at(offset)
24
+ raise RubyModKit::Error, "DefNode not found" if !def_node || !def_node.is_a?(Node::DefNode)
25
+
26
+ parameter_node = root_node.parameter_node_at(offset)
27
+ raise RubyModKit::Error, "ParameterNode not found" unless parameter_node
28
+
29
+ type = parameter_memo.type
30
+ src_offset = parse_result.source.offsets[def_node.location.start_line - 1]
31
+ indent = def_node.offset - src_offset
32
+ qualified_name = "#{parameter_memo.qualifier}#{parameter_node.name}"
33
+ generation[src_offset, 0] = "#{" " * indent}# @rbs #{qualified_name}: #{type}\n"
34
+ end
35
+ true
36
+ end
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,33 @@
1
+ # frozen_string_literal: true
2
+
3
+ # rbs_inline: enabled
4
+
5
+ module RubyModKit
6
+ class Mission
7
+ # The mission for parameter types
8
+ class TypeReturn < Mission
9
+ # @rbs return: void
10
+ def initialize
11
+ super(0)
12
+ end
13
+
14
+ # @rbs generation: Generation
15
+ # @rbs root_node: Node
16
+ # @rbs parse_result: Prism::ParseResult
17
+ # @rbs memo: Memo
18
+ # @rbs return: bool
19
+ def perform(generation, root_node, parse_result, memo)
20
+ memo.methods_memo.each do |offset, method_memo|
21
+ def_node = root_node.def_node_at(offset)
22
+ raise RubyModKit::Error, "DefNode not found" if !def_node || !def_node.is_a?(Node::DefNode)
23
+ next if method_memo.untyped?
24
+
25
+ src_offset = parse_result.source.offsets[def_node.location.start_line - 1]
26
+ indent = offset - src_offset
27
+ generation[src_offset, 0] = "#{" " * indent}# @rbs return: #{method_memo.type}\n"
28
+ end
29
+ true
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,40 @@
1
+ # frozen_string_literal: true
2
+
3
+ # rbs_inline: enabled
4
+
5
+ module RubyModKit
6
+ # The class of transpiler mission.
7
+ class Mission
8
+ # @rbs @offset: Integer
9
+
10
+ attr_accessor :offset #: Integer
11
+
12
+ # @rbs offset: Integer
13
+ # @rbs return: void
14
+ def initialize(offset)
15
+ @offset = offset
16
+ end
17
+
18
+ # @rbs _generation: Generation
19
+ # @rbs _root_node: Node
20
+ # @rbs _parse_result: Prism::ParseResult
21
+ # @rbs _memo: Memo
22
+ # @rbs return: void
23
+ def perform(_generation, _root_node, _parse_result, _memo)
24
+ raise RubyModKit::Error, "Unexpected type #{self.class}"
25
+ end
26
+
27
+ # @rbs offset_diff: OffsetDiff
28
+ # @rbs return: void
29
+ def succ(offset_diff)
30
+ @offset = offset_diff[@offset]
31
+ end
32
+ end
33
+ end
34
+
35
+ require_relative "mission/ivar_arg"
36
+ require_relative "mission/type_attr"
37
+ require_relative "mission/type_parameter"
38
+ require_relative "mission/type_return"
39
+ require_relative "mission/fix_parse_error"
40
+ require_relative "mission/overload"
@@ -0,0 +1,30 @@
1
+ # frozen_string_literal: true
2
+
3
+ # rbs_inline: enabled
4
+
5
+ module RubyModKit
6
+ class Node
7
+ # Transpiler method call node
8
+ class CallNode < Node
9
+ # @rbs @prism_node: Prism::CallNode
10
+ # @rbs @name: Symbol
11
+ # @rbs @parent: Node
12
+
13
+ attr_reader :prism_node #: Prism::CallNode
14
+ attr_reader :name #: Symbol
15
+ attr_reader :parent #: Node
16
+
17
+ # @rbs prism_node: Prism::CallNode
18
+ # @rbs parent: Node
19
+ # @rbs return: void
20
+ def initialize(prism_node, parent:)
21
+ @prism_node = prism_node
22
+ @parent = parent
23
+ raise RubyModKit::Error unless prism_node.is_a?(Prism::CallNode)
24
+
25
+ @name = prism_node.name.to_sym
26
+ super()
27
+ end
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,37 @@
1
+ # frozen_string_literal: true
2
+
3
+ # rbs_inline: enabled
4
+
5
+ module RubyModKit
6
+ class Node
7
+ # Transpiler program node
8
+ class ClassNode < Node
9
+ # @rbs @prism_node: Prism::ClassNode
10
+ # @rbs @body_node: nil | Node::StatementsNode
11
+ # @rbs @parent: Node
12
+
13
+ attr_reader :prism_node #: Prism::ClassNode
14
+ attr_reader :body_node #: nil | Node::StatementsNode
15
+ attr_reader :parent #: Node
16
+
17
+ # @rbs prism_node: Prism::ClassNode
18
+ # @rbs parent: Node
19
+ # @rbs return: void
20
+ def initialize(prism_node, parent:)
21
+ @prism_node = prism_node
22
+ @parent = parent
23
+ raise RubyModKit::Error unless prism_node.is_a?(Prism::ClassNode)
24
+
25
+ super()
26
+ end
27
+
28
+ # @rbs child_prism_node: Prism::Node
29
+ # @rbs return: Node
30
+ def wrap(child_prism_node)
31
+ node = super
32
+ @body_node = node if child_prism_node == prism_node.body && node.is_a?(Node::StatementsNode)
33
+ node
34
+ end
35
+ end
36
+ end
37
+ end