ruby_mod_kit 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- 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
|