ruby_mod_kit 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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