t-ruby 0.0.34 → 0.0.36
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 +4 -4
- data/README.md +71 -9
- data/lib/t_ruby/benchmark.rb +16 -16
- data/lib/t_ruby/bundler_integration.rb +33 -35
- data/lib/t_ruby/cache.rb +46 -43
- data/lib/t_ruby/cli.rb +3 -3
- data/lib/t_ruby/compiler.rb +25 -27
- data/lib/t_ruby/config.rb +15 -11
- data/lib/t_ruby/constraint_checker.rb +14 -8
- data/lib/t_ruby/declaration_generator.rb +8 -8
- data/lib/t_ruby/doc_generator.rb +33 -33
- data/lib/t_ruby/docs_badge_generator.rb +8 -8
- data/lib/t_ruby/docs_example_verifier.rb +5 -6
- data/lib/t_ruby/error_handler.rb +21 -22
- data/lib/t_ruby/generic_type_parser.rb +3 -3
- data/lib/t_ruby/intersection_type_parser.rb +2 -2
- data/lib/t_ruby/ir.rb +21 -24
- data/lib/t_ruby/lsp_server.rb +128 -138
- data/lib/t_ruby/package_manager.rb +16 -18
- data/lib/t_ruby/parser.rb +7 -7
- data/lib/t_ruby/parser_combinator.rb +22 -22
- data/lib/t_ruby/rbs_generator.rb +2 -4
- data/lib/t_ruby/runtime_validator.rb +41 -37
- data/lib/t_ruby/smt_solver.rb +31 -29
- data/lib/t_ruby/type_alias_registry.rb +1 -0
- data/lib/t_ruby/type_checker.rb +64 -63
- data/lib/t_ruby/type_erasure.rb +2 -4
- data/lib/t_ruby/type_inferencer.rb +22 -26
- data/lib/t_ruby/union_type_parser.rb +3 -3
- data/lib/t_ruby/version.rb +1 -1
- data/lib/t_ruby/watcher.rb +18 -14
- metadata +4 -3
data/lib/t_ruby/error_handler.rb
CHANGED
|
@@ -69,7 +69,7 @@ module TRuby
|
|
|
69
69
|
next unless line.match?(/^\s*def\s+/)
|
|
70
70
|
|
|
71
71
|
# Check for unclosed parenthesis
|
|
72
|
-
if line.match?(/def\s+\w+\([^)]*$/) &&
|
|
72
|
+
if line.match?(/def\s+\w+\([^)]*$/) && @lines[(idx + 1)..].none? { |l| l.match?(/\)/) }
|
|
73
73
|
@errors << "Line #{idx + 1}: Potential unclosed parenthesis in function definition"
|
|
74
74
|
end
|
|
75
75
|
|
|
@@ -84,6 +84,7 @@ module TRuby
|
|
|
84
84
|
def check_method_signature_errors
|
|
85
85
|
@lines.each_with_index do |line, idx|
|
|
86
86
|
next unless line.match?(/^\s*def\s+/)
|
|
87
|
+
|
|
87
88
|
check_single_method_signature(line, idx)
|
|
88
89
|
end
|
|
89
90
|
end
|
|
@@ -96,7 +97,7 @@ module TRuby
|
|
|
96
97
|
end
|
|
97
98
|
|
|
98
99
|
# Pattern 2: Check for text after closing paren without colon (e.g., "def test() something")
|
|
99
|
-
if match = line.match(/def\s+\w+\s*\([^)]*\)\s*([^:\s].+?)\s*$/)
|
|
100
|
+
if (match = line.match(/def\s+\w+\s*\([^)]*\)\s*([^:\s].+?)\s*$/))
|
|
100
101
|
trailing = match[1].strip
|
|
101
102
|
# Allow if it's just end-of-line content or a valid Ruby block start
|
|
102
103
|
unless trailing.empty? || trailing.start_with?("#") || trailing == "end"
|
|
@@ -112,13 +113,13 @@ module TRuby
|
|
|
112
113
|
end
|
|
113
114
|
|
|
114
115
|
# Pattern 4: Extract and validate return type
|
|
115
|
-
if match = line.match(/def\s+\w+\s*\([^)]*\)\s*:\s*(.+?)\s*$/)
|
|
116
|
+
if (match = line.match(/def\s+\w+\s*\([^)]*\)\s*:\s*(.+?)\s*$/))
|
|
116
117
|
return_type_str = match[1].strip
|
|
117
118
|
validate_type_expression(return_type_str, idx, "return type")
|
|
118
119
|
end
|
|
119
120
|
|
|
120
121
|
# Pattern 5: Extract and validate parameter types
|
|
121
|
-
if match = line.match(/def\s+\w+\s*\(([^)]+)\)/)
|
|
122
|
+
if (match = line.match(/def\s+\w+\s*\(([^)]+)\)/))
|
|
122
123
|
params_str = match[1]
|
|
123
124
|
validate_parameter_types_expression(params_str, idx)
|
|
124
125
|
end
|
|
@@ -189,7 +190,7 @@ module TRuby
|
|
|
189
190
|
# Use TypeParser to validate
|
|
190
191
|
result = @type_parser.parse(type_str)
|
|
191
192
|
if result[:success]
|
|
192
|
-
remaining = type_str[result[:position] || 0..]&.strip
|
|
193
|
+
remaining = type_str[(result[:position] || 0)..]&.strip
|
|
193
194
|
if remaining && !remaining.empty? && result[:remaining] && !result[:remaining].strip.empty?
|
|
194
195
|
@errors << "Line #{line_idx + 1}: Unexpected token after #{context} '#{type_str}'"
|
|
195
196
|
end
|
|
@@ -207,17 +208,17 @@ module TRuby
|
|
|
207
208
|
next if param.empty?
|
|
208
209
|
|
|
209
210
|
# Check for param: Type pattern
|
|
210
|
-
|
|
211
|
-
param_name = match[1]
|
|
212
|
-
type_str = match[2].strip
|
|
211
|
+
next unless (match = param.match(/^(\w+)\s*:\s*(.+)$/))
|
|
213
212
|
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
next
|
|
217
|
-
end
|
|
213
|
+
param_name = match[1]
|
|
214
|
+
type_str = match[2].strip
|
|
218
215
|
|
|
219
|
-
|
|
216
|
+
if type_str.empty?
|
|
217
|
+
@errors << "Line #{line_idx + 1}: Expected type after colon for parameter '#{param_name}'"
|
|
218
|
+
next
|
|
220
219
|
end
|
|
220
|
+
|
|
221
|
+
validate_type_expression(type_str, line_idx, "parameter type for '#{param_name}'")
|
|
221
222
|
end
|
|
222
223
|
end
|
|
223
224
|
|
|
@@ -235,7 +236,7 @@ module TRuby
|
|
|
235
236
|
depth -= 1
|
|
236
237
|
current += char
|
|
237
238
|
when ","
|
|
238
|
-
if depth
|
|
239
|
+
if depth.zero?
|
|
239
240
|
result << current.strip
|
|
240
241
|
current = ""
|
|
241
242
|
else
|
|
@@ -262,10 +263,8 @@ module TRuby
|
|
|
262
263
|
return_type = match[2]&.strip
|
|
263
264
|
|
|
264
265
|
# Check return type if it's a simple type name
|
|
265
|
-
if return_type && return_type.
|
|
266
|
-
|
|
267
|
-
@errors << "Line #{idx + 1}: Unknown return type '#{return_type}'"
|
|
268
|
-
end
|
|
266
|
+
if return_type&.match?(/^\w+$/) && !(VALID_TYPES.include?(return_type) || @type_aliases.key?(return_type))
|
|
267
|
+
@errors << "Line #{idx + 1}: Unknown return type '#{return_type}'"
|
|
269
268
|
end
|
|
270
269
|
|
|
271
270
|
# Check parameter types
|
|
@@ -286,10 +285,10 @@ module TRuby
|
|
|
286
285
|
next unless param_type
|
|
287
286
|
|
|
288
287
|
# Only check simple type names against VALID_TYPES
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
288
|
+
next unless param_type.match?(/^\w+$/)
|
|
289
|
+
next if VALID_TYPES.include?(param_type) || @type_aliases.key?(param_type)
|
|
290
|
+
|
|
291
|
+
@errors << "Line #{line_idx + 1}: Unknown parameter type '#{param_type}'"
|
|
293
292
|
end
|
|
294
293
|
end
|
|
295
294
|
|
|
@@ -30,7 +30,7 @@ module TRuby
|
|
|
30
30
|
{
|
|
31
31
|
type: :generic,
|
|
32
32
|
base: base_name,
|
|
33
|
-
params: params
|
|
33
|
+
params: params,
|
|
34
34
|
}
|
|
35
35
|
end
|
|
36
36
|
|
|
@@ -50,7 +50,7 @@ module TRuby
|
|
|
50
50
|
depth -= 1
|
|
51
51
|
current += char
|
|
52
52
|
when ","
|
|
53
|
-
if depth
|
|
53
|
+
if depth.zero?
|
|
54
54
|
params << current.strip
|
|
55
55
|
current = ""
|
|
56
56
|
else
|
|
@@ -61,7 +61,7 @@ module TRuby
|
|
|
61
61
|
end
|
|
62
62
|
end
|
|
63
63
|
|
|
64
|
-
params << current.strip if current.length
|
|
64
|
+
params << current.strip if current.length.positive?
|
|
65
65
|
params
|
|
66
66
|
end
|
|
67
67
|
end
|
|
@@ -17,13 +17,13 @@ module TRuby
|
|
|
17
17
|
private
|
|
18
18
|
|
|
19
19
|
def parse_intersection
|
|
20
|
-
members = @type_string.split("&").map
|
|
20
|
+
members = @type_string.split("&").map(&:strip).compact
|
|
21
21
|
|
|
22
22
|
{
|
|
23
23
|
type: :intersection,
|
|
24
24
|
members: members,
|
|
25
25
|
has_duplicates: members.length != members.uniq.length,
|
|
26
|
-
unique_members: members.uniq
|
|
26
|
+
unique_members: members.uniq,
|
|
27
27
|
}
|
|
28
28
|
end
|
|
29
29
|
end
|
data/lib/t_ruby/ir.rb
CHANGED
|
@@ -314,7 +314,7 @@ module TRuby
|
|
|
314
314
|
attr_accessor :kind, :condition, :body
|
|
315
315
|
|
|
316
316
|
# kind: :while, :until, :loop
|
|
317
|
-
def initialize(kind:, condition: nil,
|
|
317
|
+
def initialize(kind:, body:, condition: nil, **opts)
|
|
318
318
|
super(**opts)
|
|
319
319
|
@kind = kind
|
|
320
320
|
@condition = condition
|
|
@@ -424,7 +424,7 @@ module TRuby
|
|
|
424
424
|
class Lambda < Node
|
|
425
425
|
attr_accessor :params, :body, :return_type
|
|
426
426
|
|
|
427
|
-
def initialize(params: [],
|
|
427
|
+
def initialize(body:, params: [], return_type: nil, **opts)
|
|
428
428
|
super(**opts)
|
|
429
429
|
@params = params
|
|
430
430
|
@body = body
|
|
@@ -457,7 +457,7 @@ module TRuby
|
|
|
457
457
|
class RescueClause < Node
|
|
458
458
|
attr_accessor :exception_types, :variable, :body
|
|
459
459
|
|
|
460
|
-
def initialize(exception_types: [], variable: nil,
|
|
460
|
+
def initialize(body:, exception_types: [], variable: nil, **opts)
|
|
461
461
|
super(**opts)
|
|
462
462
|
@exception_types = exception_types
|
|
463
463
|
@variable = variable
|
|
@@ -523,11 +523,11 @@ module TRuby
|
|
|
523
523
|
end
|
|
524
524
|
|
|
525
525
|
def to_rbs
|
|
526
|
-
"#{@base}[#{@type_args.map(&:to_rbs).join(
|
|
526
|
+
"#{@base}[#{@type_args.map(&:to_rbs).join(", ")}]"
|
|
527
527
|
end
|
|
528
528
|
|
|
529
529
|
def to_trb
|
|
530
|
-
"#{@base}<#{@type_args.map(&:to_trb).join(
|
|
530
|
+
"#{@base}<#{@type_args.map(&:to_trb).join(", ")}>"
|
|
531
531
|
end
|
|
532
532
|
end
|
|
533
533
|
|
|
@@ -571,7 +571,7 @@ module TRuby
|
|
|
571
571
|
class FunctionType < TypeNode
|
|
572
572
|
attr_accessor :param_types, :return_type
|
|
573
573
|
|
|
574
|
-
def initialize(param_types: [],
|
|
574
|
+
def initialize(return_type:, param_types: [], **opts)
|
|
575
575
|
super(**opts)
|
|
576
576
|
@param_types = param_types
|
|
577
577
|
@return_type = return_type
|
|
@@ -598,11 +598,11 @@ module TRuby
|
|
|
598
598
|
end
|
|
599
599
|
|
|
600
600
|
def to_rbs
|
|
601
|
-
"[#{@element_types.map(&:to_rbs).join(
|
|
601
|
+
"[#{@element_types.map(&:to_rbs).join(", ")}]"
|
|
602
602
|
end
|
|
603
603
|
|
|
604
604
|
def to_trb
|
|
605
|
-
"[#{@element_types.map(&:to_trb).join(
|
|
605
|
+
"[#{@element_types.map(&:to_trb).join(", ")}]"
|
|
606
606
|
end
|
|
607
607
|
end
|
|
608
608
|
|
|
@@ -648,7 +648,7 @@ module TRuby
|
|
|
648
648
|
|
|
649
649
|
class Visitor
|
|
650
650
|
def visit(node)
|
|
651
|
-
method_name = "visit_#{node.class.name.split(
|
|
651
|
+
method_name = "visit_#{node.class.name.split("::").last.gsub(/([A-Z])/, '_\1').downcase.sub(/^_/, "")}"
|
|
652
652
|
if respond_to?(method_name)
|
|
653
653
|
send(method_name, node)
|
|
654
654
|
else
|
|
@@ -676,11 +676,9 @@ module TRuby
|
|
|
676
676
|
|
|
677
677
|
# Build IR from parser output
|
|
678
678
|
def build(parse_result, source: nil)
|
|
679
|
-
declarations = []
|
|
680
|
-
|
|
681
679
|
# Build type aliases
|
|
682
|
-
(parse_result[:type_aliases] || []).
|
|
683
|
-
|
|
680
|
+
declarations = (parse_result[:type_aliases] || []).map do |alias_info|
|
|
681
|
+
build_type_alias(alias_info)
|
|
684
682
|
end
|
|
685
683
|
|
|
686
684
|
# Build interfaces
|
|
@@ -802,7 +800,7 @@ module TRuby
|
|
|
802
800
|
depth -= 1
|
|
803
801
|
current += char
|
|
804
802
|
when ","
|
|
805
|
-
if depth
|
|
803
|
+
if depth.zero?
|
|
806
804
|
args << parse_type(current.strip)
|
|
807
805
|
current = ""
|
|
808
806
|
else
|
|
@@ -912,7 +910,7 @@ module TRuby
|
|
|
912
910
|
private
|
|
913
911
|
|
|
914
912
|
def emit(text)
|
|
915
|
-
@output << (" " * @indent + text)
|
|
913
|
+
@output << ((" " * @indent) + text)
|
|
916
914
|
end
|
|
917
915
|
|
|
918
916
|
def emit_comment(text)
|
|
@@ -1008,7 +1006,7 @@ module TRuby
|
|
|
1008
1006
|
private
|
|
1009
1007
|
|
|
1010
1008
|
def emit(text)
|
|
1011
|
-
@output << (" " * @indent + text)
|
|
1009
|
+
@output << ((" " * @indent) + text)
|
|
1012
1010
|
end
|
|
1013
1011
|
end
|
|
1014
1012
|
|
|
@@ -1141,12 +1139,11 @@ module TRuby
|
|
|
1141
1139
|
when "+" then left + right
|
|
1142
1140
|
when "-" then left - right
|
|
1143
1141
|
when "*" then left * right
|
|
1144
|
-
when "/" then right
|
|
1145
|
-
when "%" then right
|
|
1146
|
-
when "**" then left
|
|
1147
|
-
else nil
|
|
1142
|
+
when "/" then right.zero? ? nil : left / right
|
|
1143
|
+
when "%" then right.zero? ? nil : left % right
|
|
1144
|
+
when "**" then left**right
|
|
1148
1145
|
end
|
|
1149
|
-
rescue
|
|
1146
|
+
rescue StandardError
|
|
1150
1147
|
nil
|
|
1151
1148
|
end
|
|
1152
1149
|
end
|
|
@@ -1176,7 +1173,7 @@ module TRuby
|
|
|
1176
1173
|
|
|
1177
1174
|
private
|
|
1178
1175
|
|
|
1179
|
-
def redundant_annotation?(
|
|
1176
|
+
def redundant_annotation?(_param)
|
|
1180
1177
|
# Consider annotation redundant if it matches the default/inferred type
|
|
1181
1178
|
false
|
|
1182
1179
|
end
|
|
@@ -1264,7 +1261,7 @@ module TRuby
|
|
|
1264
1261
|
Passes::DeadCodeElimination,
|
|
1265
1262
|
Passes::ConstantFolding,
|
|
1266
1263
|
Passes::TypeAnnotationCleanup,
|
|
1267
|
-
Passes::UnusedDeclarationRemoval
|
|
1264
|
+
Passes::UnusedDeclarationRemoval,
|
|
1268
1265
|
].freeze
|
|
1269
1266
|
|
|
1270
1267
|
attr_reader :passes, :stats
|
|
@@ -1291,7 +1288,7 @@ module TRuby
|
|
|
1291
1288
|
end
|
|
1292
1289
|
|
|
1293
1290
|
@stats[:total_changes] += changes_this_iteration
|
|
1294
|
-
break if changes_this_iteration
|
|
1291
|
+
break if changes_this_iteration.zero?
|
|
1295
1292
|
end
|
|
1296
1293
|
|
|
1297
1294
|
{ program: program, stats: @stats }
|