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.
- checksums.yaml +7 -0
- data/LICENSE.txt +21 -0
- data/README.md +99 -0
- data/examples/user.rb +83 -0
- data/examples/user.rbm +47 -0
- data/exe/ruby_mod_kit +5 -0
- data/lib/ruby_mod_kit/cli.rb +27 -0
- data/lib/ruby_mod_kit/generation.rb +170 -0
- data/lib/ruby_mod_kit/memo/class.rb +27 -0
- data/lib/ruby_mod_kit/memo/ivar.rb +42 -0
- data/lib/ruby_mod_kit/memo/method.rb +49 -0
- data/lib/ruby_mod_kit/memo/offset_memo.rb +26 -0
- data/lib/ruby_mod_kit/memo/parameter.rb +39 -0
- data/lib/ruby_mod_kit/memo.rb +73 -0
- data/lib/ruby_mod_kit/mission/fix_parse_error.rb +213 -0
- data/lib/ruby_mod_kit/mission/ivar_arg.rb +42 -0
- data/lib/ruby_mod_kit/mission/overload.rb +73 -0
- data/lib/ruby_mod_kit/mission/type_attr.rb +75 -0
- data/lib/ruby_mod_kit/mission/type_parameter.rb +39 -0
- data/lib/ruby_mod_kit/mission/type_return.rb +33 -0
- data/lib/ruby_mod_kit/mission.rb +40 -0
- data/lib/ruby_mod_kit/node/call_node.rb +30 -0
- data/lib/ruby_mod_kit/node/class_node.rb +37 -0
- data/lib/ruby_mod_kit/node/def_node.rb +57 -0
- data/lib/ruby_mod_kit/node/parameter_node.rb +42 -0
- data/lib/ruby_mod_kit/node/program_node.rb +23 -0
- data/lib/ruby_mod_kit/node/statements_node.rb +27 -0
- data/lib/ruby_mod_kit/node/symbol_node.rb +34 -0
- data/lib/ruby_mod_kit/node/untyped_node.rb +25 -0
- data/lib/ruby_mod_kit/node.rb +164 -0
- data/lib/ruby_mod_kit/offset_diff.rb +37 -0
- data/lib/ruby_mod_kit/transpiler.rb +20 -0
- data/lib/ruby_mod_kit/version.rb +7 -0
- data/lib/ruby_mod_kit.rb +59 -0
- data/ruby_mod_kit.gemspec +51 -0
- data/sig/generated/examples/user.rbs +60 -0
- data/sig/generated/ruby_mod_kit/cli.rbs +14 -0
- data/sig/generated/ruby_mod_kit/generation.rbs +101 -0
- data/sig/generated/ruby_mod_kit/memo/class.rbs +20 -0
- data/sig/generated/ruby_mod_kit/memo/ivar.rbs +30 -0
- data/sig/generated/ruby_mod_kit/memo/located.rbs +14 -0
- data/sig/generated/ruby_mod_kit/memo/method.rbs +37 -0
- data/sig/generated/ruby_mod_kit/memo/offset_memo.rbs +20 -0
- data/sig/generated/ruby_mod_kit/memo/parameter.rbs +33 -0
- data/sig/generated/ruby_mod_kit/memo/parameter_type.rbs +14 -0
- data/sig/generated/ruby_mod_kit/memo.rbs +41 -0
- data/sig/generated/ruby_mod_kit/mission/fix_parse_error.rbs +73 -0
- data/sig/generated/ruby_mod_kit/mission/ivar_arg.rbs +19 -0
- data/sig/generated/ruby_mod_kit/mission/overload.rbs +20 -0
- data/sig/generated/ruby_mod_kit/mission/type_attr.rbs +18 -0
- data/sig/generated/ruby_mod_kit/mission/type_parameter.rbs +18 -0
- data/sig/generated/ruby_mod_kit/mission/type_return.rbs +18 -0
- data/sig/generated/ruby_mod_kit/mission.rbs +25 -0
- data/sig/generated/ruby_mod_kit/node/call_node.rbs +25 -0
- data/sig/generated/ruby_mod_kit/node/class_node.rbs +29 -0
- data/sig/generated/ruby_mod_kit/node/def_node.rbs +39 -0
- data/sig/generated/ruby_mod_kit/node/parameter_node.rbs +26 -0
- data/sig/generated/ruby_mod_kit/node/program_node.rbs +16 -0
- data/sig/generated/ruby_mod_kit/node/statements_node.rbs +21 -0
- data/sig/generated/ruby_mod_kit/node/symbol_node.rbs +24 -0
- data/sig/generated/ruby_mod_kit/node/untyped_node.rbs +21 -0
- data/sig/generated/ruby_mod_kit/node.rbs +63 -0
- data/sig/generated/ruby_mod_kit/offset_diff.rbs +20 -0
- data/sig/generated/ruby_mod_kit/transpiler.rbs +11 -0
- data/sig/generated/ruby_mod_kit/version.rbs +5 -0
- data/sig/generated/ruby_mod_kit.rbs +33 -0
- data/sig/sorted_set.rbs +8 -0
- data/sig/thor.rbs +3 -0
- 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
|