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.
@@ -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