t-ruby 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 +21 -0
- data/README.md +221 -0
- data/bin/trc +6 -0
- data/lib/t_ruby/benchmark.rb +592 -0
- data/lib/t_ruby/bundler_integration.rb +569 -0
- data/lib/t_ruby/cache.rb +774 -0
- data/lib/t_ruby/cli.rb +106 -0
- data/lib/t_ruby/compiler.rb +299 -0
- data/lib/t_ruby/config.rb +53 -0
- data/lib/t_ruby/constraint_checker.rb +441 -0
- data/lib/t_ruby/declaration_generator.rb +298 -0
- data/lib/t_ruby/doc_generator.rb +474 -0
- data/lib/t_ruby/error_handler.rb +132 -0
- data/lib/t_ruby/generic_type_parser.rb +68 -0
- data/lib/t_ruby/intersection_type_parser.rb +30 -0
- data/lib/t_ruby/ir.rb +1301 -0
- data/lib/t_ruby/lsp_server.rb +994 -0
- data/lib/t_ruby/package_manager.rb +735 -0
- data/lib/t_ruby/parser.rb +245 -0
- data/lib/t_ruby/parser_combinator.rb +942 -0
- data/lib/t_ruby/rbs_generator.rb +71 -0
- data/lib/t_ruby/runtime_validator.rb +367 -0
- data/lib/t_ruby/smt_solver.rb +1076 -0
- data/lib/t_ruby/type_alias_registry.rb +102 -0
- data/lib/t_ruby/type_checker.rb +770 -0
- data/lib/t_ruby/type_erasure.rb +26 -0
- data/lib/t_ruby/type_inferencer.rb +580 -0
- data/lib/t_ruby/union_type_parser.rb +38 -0
- data/lib/t_ruby/version.rb +5 -0
- data/lib/t_ruby/watcher.rb +320 -0
- data/lib/t_ruby.rb +42 -0
- metadata +87 -0
|
@@ -0,0 +1,298 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module TRuby
|
|
4
|
+
# Generator for .d.trb type declaration files
|
|
5
|
+
# Similar to TypeScript's .d.ts files
|
|
6
|
+
class DeclarationGenerator
|
|
7
|
+
DECLARATION_EXTENSION = ".d.trb"
|
|
8
|
+
|
|
9
|
+
def initialize
|
|
10
|
+
@parser = nil
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
# Generate declaration content from source code
|
|
14
|
+
def generate(source)
|
|
15
|
+
@parser = Parser.new(source)
|
|
16
|
+
result = @parser.parse
|
|
17
|
+
|
|
18
|
+
declarations = []
|
|
19
|
+
|
|
20
|
+
# Add header comment
|
|
21
|
+
declarations << "# Auto-generated type declaration file"
|
|
22
|
+
declarations << "# Do not edit manually"
|
|
23
|
+
declarations << ""
|
|
24
|
+
|
|
25
|
+
# Generate type alias declarations
|
|
26
|
+
(result[:type_aliases] || []).each do |type_alias|
|
|
27
|
+
declarations << generate_type_alias(type_alias)
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
# Generate interface declarations
|
|
31
|
+
(result[:interfaces] || []).each do |interface|
|
|
32
|
+
declarations << generate_interface(interface)
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
# Generate function declarations
|
|
36
|
+
(result[:functions] || []).each do |function|
|
|
37
|
+
declarations << generate_function(function)
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
declarations.join("\n")
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
# Generate declaration file from a .trb source file
|
|
44
|
+
def generate_file(input_path, output_dir = nil)
|
|
45
|
+
unless File.exist?(input_path)
|
|
46
|
+
raise ArgumentError, "File not found: #{input_path}"
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
unless input_path.end_with?(".trb")
|
|
50
|
+
raise ArgumentError, "Expected .trb file, got: #{input_path}"
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
source = File.read(input_path)
|
|
54
|
+
content = generate(source)
|
|
55
|
+
|
|
56
|
+
# Determine output path
|
|
57
|
+
output_dir ||= File.dirname(input_path)
|
|
58
|
+
FileUtils.mkdir_p(output_dir)
|
|
59
|
+
|
|
60
|
+
base_name = File.basename(input_path, ".trb")
|
|
61
|
+
output_path = File.join(output_dir, "#{base_name}#{DECLARATION_EXTENSION}")
|
|
62
|
+
|
|
63
|
+
File.write(output_path, content)
|
|
64
|
+
output_path
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
private
|
|
68
|
+
|
|
69
|
+
def generate_type_alias(type_alias)
|
|
70
|
+
"type #{type_alias[:name]} = #{type_alias[:definition]}"
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
def generate_interface(interface)
|
|
74
|
+
lines = []
|
|
75
|
+
lines << "interface #{interface[:name]}"
|
|
76
|
+
|
|
77
|
+
interface[:members].each do |member|
|
|
78
|
+
lines << " #{member[:name]}: #{member[:type]}"
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
lines << "end"
|
|
82
|
+
lines.join("\n")
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
def generate_function(function)
|
|
86
|
+
params = function[:params].map do |param|
|
|
87
|
+
if param[:type]
|
|
88
|
+
"#{param[:name]}: #{param[:type]}"
|
|
89
|
+
else
|
|
90
|
+
param[:name]
|
|
91
|
+
end
|
|
92
|
+
end.join(", ")
|
|
93
|
+
|
|
94
|
+
return_type = function[:return_type] ? ": #{function[:return_type]}" : ""
|
|
95
|
+
|
|
96
|
+
"def #{function[:name]}(#{params})#{return_type}"
|
|
97
|
+
end
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
# Parser for .d.trb declaration files
|
|
101
|
+
class DeclarationParser
|
|
102
|
+
attr_reader :type_aliases, :interfaces, :functions
|
|
103
|
+
|
|
104
|
+
def initialize
|
|
105
|
+
@type_aliases = {}
|
|
106
|
+
@interfaces = {}
|
|
107
|
+
@functions = {}
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
# Parse a declaration file content (resets existing data)
|
|
111
|
+
def parse(content)
|
|
112
|
+
@type_aliases = {}
|
|
113
|
+
@interfaces = {}
|
|
114
|
+
@functions = {}
|
|
115
|
+
|
|
116
|
+
parse_and_merge(content)
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
# Parse content and merge with existing data
|
|
120
|
+
def parse_and_merge(content)
|
|
121
|
+
parser = Parser.new(content)
|
|
122
|
+
result = parser.parse
|
|
123
|
+
|
|
124
|
+
# Process type aliases
|
|
125
|
+
(result[:type_aliases] || []).each do |type_alias|
|
|
126
|
+
@type_aliases[type_alias[:name]] = type_alias[:definition]
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
# Process interfaces
|
|
130
|
+
(result[:interfaces] || []).each do |interface|
|
|
131
|
+
@interfaces[interface[:name]] = interface
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
# Process functions
|
|
135
|
+
(result[:functions] || []).each do |function|
|
|
136
|
+
@functions[function[:name]] = function
|
|
137
|
+
end
|
|
138
|
+
|
|
139
|
+
self
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
# Parse a declaration file from path
|
|
143
|
+
def parse_file(file_path)
|
|
144
|
+
unless File.exist?(file_path)
|
|
145
|
+
raise ArgumentError, "Declaration file not found: #{file_path}"
|
|
146
|
+
end
|
|
147
|
+
|
|
148
|
+
unless file_path.end_with?(DeclarationGenerator::DECLARATION_EXTENSION)
|
|
149
|
+
raise ArgumentError, "Expected #{DeclarationGenerator::DECLARATION_EXTENSION} file, got: #{file_path}"
|
|
150
|
+
end
|
|
151
|
+
|
|
152
|
+
content = File.read(file_path)
|
|
153
|
+
parse(content)
|
|
154
|
+
end
|
|
155
|
+
|
|
156
|
+
# Load multiple declaration files from a directory
|
|
157
|
+
def load_directory(dir_path, recursive: false)
|
|
158
|
+
unless Dir.exist?(dir_path)
|
|
159
|
+
raise ArgumentError, "Directory not found: #{dir_path}"
|
|
160
|
+
end
|
|
161
|
+
|
|
162
|
+
pattern = recursive ? "**/*#{DeclarationGenerator::DECLARATION_EXTENSION}" : "*#{DeclarationGenerator::DECLARATION_EXTENSION}"
|
|
163
|
+
files = Dir.glob(File.join(dir_path, pattern))
|
|
164
|
+
|
|
165
|
+
files.each do |file|
|
|
166
|
+
content = File.read(file)
|
|
167
|
+
parse_and_merge(content)
|
|
168
|
+
end
|
|
169
|
+
|
|
170
|
+
self
|
|
171
|
+
end
|
|
172
|
+
|
|
173
|
+
# Check if a type is defined
|
|
174
|
+
def type_defined?(name)
|
|
175
|
+
@type_aliases.key?(name) || @interfaces.key?(name)
|
|
176
|
+
end
|
|
177
|
+
|
|
178
|
+
# Resolve a type alias
|
|
179
|
+
def resolve_type(name)
|
|
180
|
+
@type_aliases[name]
|
|
181
|
+
end
|
|
182
|
+
|
|
183
|
+
# Get an interface definition
|
|
184
|
+
def get_interface(name)
|
|
185
|
+
@interfaces[name]
|
|
186
|
+
end
|
|
187
|
+
|
|
188
|
+
# Get a function signature
|
|
189
|
+
def get_function(name)
|
|
190
|
+
@functions[name]
|
|
191
|
+
end
|
|
192
|
+
|
|
193
|
+
# Get all declarations as a hash
|
|
194
|
+
def to_h
|
|
195
|
+
{
|
|
196
|
+
type_aliases: @type_aliases,
|
|
197
|
+
interfaces: @interfaces,
|
|
198
|
+
functions: @functions
|
|
199
|
+
}
|
|
200
|
+
end
|
|
201
|
+
|
|
202
|
+
# Merge another parser's declarations into this one
|
|
203
|
+
def merge(other_parser)
|
|
204
|
+
@type_aliases.merge!(other_parser.type_aliases)
|
|
205
|
+
@interfaces.merge!(other_parser.interfaces)
|
|
206
|
+
@functions.merge!(other_parser.functions)
|
|
207
|
+
self
|
|
208
|
+
end
|
|
209
|
+
end
|
|
210
|
+
|
|
211
|
+
# Loader for managing declaration files
|
|
212
|
+
class DeclarationLoader
|
|
213
|
+
attr_reader :search_paths
|
|
214
|
+
|
|
215
|
+
def initialize
|
|
216
|
+
@search_paths = []
|
|
217
|
+
@loaded_declarations = DeclarationParser.new
|
|
218
|
+
@loaded_files = Set.new
|
|
219
|
+
end
|
|
220
|
+
|
|
221
|
+
# Add a search path for declaration files
|
|
222
|
+
def add_search_path(path)
|
|
223
|
+
@search_paths << path unless @search_paths.include?(path)
|
|
224
|
+
self
|
|
225
|
+
end
|
|
226
|
+
|
|
227
|
+
# Load a specific declaration file by name (without extension)
|
|
228
|
+
def load(name)
|
|
229
|
+
file_name = "#{name}#{DeclarationGenerator::DECLARATION_EXTENSION}"
|
|
230
|
+
|
|
231
|
+
@search_paths.each do |path|
|
|
232
|
+
full_path = File.join(path, file_name)
|
|
233
|
+
if File.exist?(full_path) && !@loaded_files.include?(full_path)
|
|
234
|
+
parser = DeclarationParser.new
|
|
235
|
+
parser.parse_file(full_path)
|
|
236
|
+
@loaded_declarations.merge(parser)
|
|
237
|
+
@loaded_files.add(full_path)
|
|
238
|
+
return true
|
|
239
|
+
end
|
|
240
|
+
end
|
|
241
|
+
|
|
242
|
+
false
|
|
243
|
+
end
|
|
244
|
+
|
|
245
|
+
# Load all declaration files from search paths
|
|
246
|
+
def load_all
|
|
247
|
+
@search_paths.each do |path|
|
|
248
|
+
next unless Dir.exist?(path)
|
|
249
|
+
|
|
250
|
+
Dir.glob(File.join(path, "*#{DeclarationGenerator::DECLARATION_EXTENSION}")).each do |file|
|
|
251
|
+
next if @loaded_files.include?(file)
|
|
252
|
+
|
|
253
|
+
parser = DeclarationParser.new
|
|
254
|
+
parser.parse_file(file)
|
|
255
|
+
@loaded_declarations.merge(parser)
|
|
256
|
+
@loaded_files.add(file)
|
|
257
|
+
end
|
|
258
|
+
end
|
|
259
|
+
|
|
260
|
+
self
|
|
261
|
+
end
|
|
262
|
+
|
|
263
|
+
# Get the combined declarations
|
|
264
|
+
def declarations
|
|
265
|
+
@loaded_declarations
|
|
266
|
+
end
|
|
267
|
+
|
|
268
|
+
# Check if a type is defined in any loaded declaration
|
|
269
|
+
def type_defined?(name)
|
|
270
|
+
@loaded_declarations.type_defined?(name)
|
|
271
|
+
end
|
|
272
|
+
|
|
273
|
+
# Resolve a type from loaded declarations
|
|
274
|
+
def resolve_type(name)
|
|
275
|
+
@loaded_declarations.resolve_type(name)
|
|
276
|
+
end
|
|
277
|
+
|
|
278
|
+
# Get all loaded type aliases
|
|
279
|
+
def type_aliases
|
|
280
|
+
@loaded_declarations.type_aliases
|
|
281
|
+
end
|
|
282
|
+
|
|
283
|
+
# Get all loaded interfaces
|
|
284
|
+
def interfaces
|
|
285
|
+
@loaded_declarations.interfaces
|
|
286
|
+
end
|
|
287
|
+
|
|
288
|
+
# Get all loaded functions
|
|
289
|
+
def functions
|
|
290
|
+
@loaded_declarations.functions
|
|
291
|
+
end
|
|
292
|
+
|
|
293
|
+
# Get list of loaded files
|
|
294
|
+
def loaded_files
|
|
295
|
+
@loaded_files.to_a
|
|
296
|
+
end
|
|
297
|
+
end
|
|
298
|
+
end
|