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.
data/lib/t_ruby/ir.rb ADDED
@@ -0,0 +1,1301 @@
1
+ # frozen_string_literal: true
2
+
3
+ module TRuby
4
+ module IR
5
+ # Base class for all IR nodes
6
+ class Node
7
+ attr_accessor :location, :type_info, :metadata
8
+
9
+ def initialize(location: nil)
10
+ @location = location
11
+ @type_info = nil
12
+ @metadata = {}
13
+ end
14
+
15
+ def accept(visitor)
16
+ visitor.visit(self)
17
+ end
18
+
19
+ def children
20
+ []
21
+ end
22
+
23
+ def transform(&block)
24
+ block.call(self)
25
+ end
26
+ end
27
+
28
+ # Program - root node containing all top-level declarations
29
+ class Program < Node
30
+ attr_accessor :declarations, :source_file
31
+
32
+ def initialize(declarations: [], source_file: nil, **opts)
33
+ super(**opts)
34
+ @declarations = declarations
35
+ @source_file = source_file
36
+ end
37
+
38
+ def children
39
+ @declarations
40
+ end
41
+ end
42
+
43
+ # Type alias declaration: type Name = Definition
44
+ class TypeAlias < Node
45
+ attr_accessor :name, :definition, :type_params
46
+
47
+ def initialize(name:, definition:, type_params: [], **opts)
48
+ super(**opts)
49
+ @name = name
50
+ @definition = definition
51
+ @type_params = type_params
52
+ end
53
+ end
54
+
55
+ # Interface declaration
56
+ class Interface < Node
57
+ attr_accessor :name, :members, :extends, :type_params
58
+
59
+ def initialize(name:, members: [], extends: [], type_params: [], **opts)
60
+ super(**opts)
61
+ @name = name
62
+ @members = members
63
+ @extends = extends
64
+ @type_params = type_params
65
+ end
66
+
67
+ def children
68
+ @members
69
+ end
70
+ end
71
+
72
+ # Interface member (method signature)
73
+ class InterfaceMember < Node
74
+ attr_accessor :name, :type_signature, :optional
75
+
76
+ def initialize(name:, type_signature:, optional: false, **opts)
77
+ super(**opts)
78
+ @name = name
79
+ @type_signature = type_signature
80
+ @optional = optional
81
+ end
82
+ end
83
+
84
+ # Class declaration
85
+ class ClassDecl < Node
86
+ attr_accessor :name, :superclass, :implements, :type_params, :body
87
+
88
+ def initialize(name:, superclass: nil, implements: [], type_params: [], body: [], **opts)
89
+ super(**opts)
90
+ @name = name
91
+ @superclass = superclass
92
+ @implements = implements
93
+ @type_params = type_params
94
+ @body = body
95
+ end
96
+
97
+ def children
98
+ @body
99
+ end
100
+ end
101
+
102
+ # Module declaration
103
+ class ModuleDecl < Node
104
+ attr_accessor :name, :body
105
+
106
+ def initialize(name:, body: [], **opts)
107
+ super(**opts)
108
+ @name = name
109
+ @body = body
110
+ end
111
+
112
+ def children
113
+ @body
114
+ end
115
+ end
116
+
117
+ # Method definition
118
+ class MethodDef < Node
119
+ attr_accessor :name, :params, :return_type, :body, :visibility, :type_params
120
+
121
+ def initialize(name:, params: [], return_type: nil, body: nil, visibility: :public, type_params: [], **opts)
122
+ super(**opts)
123
+ @name = name
124
+ @params = params
125
+ @return_type = return_type
126
+ @body = body
127
+ @visibility = visibility
128
+ @type_params = type_params
129
+ end
130
+
131
+ def children
132
+ [@body].compact
133
+ end
134
+ end
135
+
136
+ # Method parameter
137
+ class Parameter < Node
138
+ attr_accessor :name, :type_annotation, :default_value, :kind
139
+
140
+ # kind: :required, :optional, :rest, :keyrest, :block
141
+ def initialize(name:, type_annotation: nil, default_value: nil, kind: :required, **opts)
142
+ super(**opts)
143
+ @name = name
144
+ @type_annotation = type_annotation
145
+ @default_value = default_value
146
+ @kind = kind
147
+ end
148
+ end
149
+
150
+ # Block of statements
151
+ class Block < Node
152
+ attr_accessor :statements
153
+
154
+ def initialize(statements: [], **opts)
155
+ super(**opts)
156
+ @statements = statements
157
+ end
158
+
159
+ def children
160
+ @statements
161
+ end
162
+ end
163
+
164
+ # Variable assignment
165
+ class Assignment < Node
166
+ attr_accessor :target, :value, :type_annotation
167
+
168
+ def initialize(target:, value:, type_annotation: nil, **opts)
169
+ super(**opts)
170
+ @target = target
171
+ @value = value
172
+ @type_annotation = type_annotation
173
+ end
174
+
175
+ def children
176
+ [@value]
177
+ end
178
+ end
179
+
180
+ # Variable reference
181
+ class VariableRef < Node
182
+ attr_accessor :name, :scope
183
+
184
+ # scope: :local, :instance, :class, :global
185
+ def initialize(name:, scope: :local, **opts)
186
+ super(**opts)
187
+ @name = name
188
+ @scope = scope
189
+ end
190
+ end
191
+
192
+ # Method call
193
+ class MethodCall < Node
194
+ attr_accessor :receiver, :method_name, :arguments, :block, :type_args
195
+
196
+ def initialize(method_name:, receiver: nil, arguments: [], block: nil, type_args: [], **opts)
197
+ super(**opts)
198
+ @receiver = receiver
199
+ @method_name = method_name
200
+ @arguments = arguments
201
+ @block = block
202
+ @type_args = type_args
203
+ end
204
+
205
+ def children
206
+ ([@receiver, @block] + @arguments).compact
207
+ end
208
+ end
209
+
210
+ # Literal values
211
+ class Literal < Node
212
+ attr_accessor :value, :literal_type
213
+
214
+ def initialize(value:, literal_type:, **opts)
215
+ super(**opts)
216
+ @value = value
217
+ @literal_type = literal_type
218
+ end
219
+ end
220
+
221
+ # Array literal
222
+ class ArrayLiteral < Node
223
+ attr_accessor :elements, :element_type
224
+
225
+ def initialize(elements: [], element_type: nil, **opts)
226
+ super(**opts)
227
+ @elements = elements
228
+ @element_type = element_type
229
+ end
230
+
231
+ def children
232
+ @elements
233
+ end
234
+ end
235
+
236
+ # Hash literal
237
+ class HashLiteral < Node
238
+ attr_accessor :pairs, :key_type, :value_type
239
+
240
+ def initialize(pairs: [], key_type: nil, value_type: nil, **opts)
241
+ super(**opts)
242
+ @pairs = pairs
243
+ @key_type = key_type
244
+ @value_type = value_type
245
+ end
246
+ end
247
+
248
+ # Hash pair (key => value)
249
+ class HashPair < Node
250
+ attr_accessor :key, :value
251
+
252
+ def initialize(key:, value:, **opts)
253
+ super(**opts)
254
+ @key = key
255
+ @value = value
256
+ end
257
+
258
+ def children
259
+ [@key, @value]
260
+ end
261
+ end
262
+
263
+ # Conditional (if/unless)
264
+ class Conditional < Node
265
+ attr_accessor :condition, :then_branch, :else_branch, :kind
266
+
267
+ # kind: :if, :unless, :ternary
268
+ def initialize(condition:, then_branch:, else_branch: nil, kind: :if, **opts)
269
+ super(**opts)
270
+ @condition = condition
271
+ @then_branch = then_branch
272
+ @else_branch = else_branch
273
+ @kind = kind
274
+ end
275
+
276
+ def children
277
+ [@condition, @then_branch, @else_branch].compact
278
+ end
279
+ end
280
+
281
+ # Case/when expression
282
+ class CaseExpr < Node
283
+ attr_accessor :subject, :when_clauses, :else_clause
284
+
285
+ def initialize(subject: nil, when_clauses: [], else_clause: nil, **opts)
286
+ super(**opts)
287
+ @subject = subject
288
+ @when_clauses = when_clauses
289
+ @else_clause = else_clause
290
+ end
291
+
292
+ def children
293
+ ([@subject, @else_clause] + @when_clauses).compact
294
+ end
295
+ end
296
+
297
+ # When clause
298
+ class WhenClause < Node
299
+ attr_accessor :patterns, :body
300
+
301
+ def initialize(patterns:, body:, **opts)
302
+ super(**opts)
303
+ @patterns = patterns
304
+ @body = body
305
+ end
306
+
307
+ def children
308
+ [@body] + @patterns
309
+ end
310
+ end
311
+
312
+ # Loop constructs
313
+ class Loop < Node
314
+ attr_accessor :kind, :condition, :body
315
+
316
+ # kind: :while, :until, :loop
317
+ def initialize(kind:, condition: nil, body:, **opts)
318
+ super(**opts)
319
+ @kind = kind
320
+ @condition = condition
321
+ @body = body
322
+ end
323
+
324
+ def children
325
+ [@condition, @body].compact
326
+ end
327
+ end
328
+
329
+ # For loop / each iteration
330
+ class ForLoop < Node
331
+ attr_accessor :variable, :iterable, :body
332
+
333
+ def initialize(variable:, iterable:, body:, **opts)
334
+ super(**opts)
335
+ @variable = variable
336
+ @iterable = iterable
337
+ @body = body
338
+ end
339
+
340
+ def children
341
+ [@iterable, @body]
342
+ end
343
+ end
344
+
345
+ # Return statement
346
+ class Return < Node
347
+ attr_accessor :value
348
+
349
+ def initialize(value: nil, **opts)
350
+ super(**opts)
351
+ @value = value
352
+ end
353
+
354
+ def children
355
+ [@value].compact
356
+ end
357
+ end
358
+
359
+ # Binary operation
360
+ class BinaryOp < Node
361
+ attr_accessor :operator, :left, :right
362
+
363
+ def initialize(operator:, left:, right:, **opts)
364
+ super(**opts)
365
+ @operator = operator
366
+ @left = left
367
+ @right = right
368
+ end
369
+
370
+ def children
371
+ [@left, @right]
372
+ end
373
+ end
374
+
375
+ # Unary operation
376
+ class UnaryOp < Node
377
+ attr_accessor :operator, :operand
378
+
379
+ def initialize(operator:, operand:, **opts)
380
+ super(**opts)
381
+ @operator = operator
382
+ @operand = operand
383
+ end
384
+
385
+ def children
386
+ [@operand]
387
+ end
388
+ end
389
+
390
+ # Type cast / assertion
391
+ class TypeCast < Node
392
+ attr_accessor :expression, :target_type, :kind
393
+
394
+ # kind: :as, :assert
395
+ def initialize(expression:, target_type:, kind: :as, **opts)
396
+ super(**opts)
397
+ @expression = expression
398
+ @target_type = target_type
399
+ @kind = kind
400
+ end
401
+
402
+ def children
403
+ [@expression]
404
+ end
405
+ end
406
+
407
+ # Type guard (is_a?, respond_to?)
408
+ class TypeGuard < Node
409
+ attr_accessor :expression, :type_check, :narrowed_type
410
+
411
+ def initialize(expression:, type_check:, narrowed_type: nil, **opts)
412
+ super(**opts)
413
+ @expression = expression
414
+ @type_check = type_check
415
+ @narrowed_type = narrowed_type
416
+ end
417
+
418
+ def children
419
+ [@expression]
420
+ end
421
+ end
422
+
423
+ # Lambda/Proc definition
424
+ class Lambda < Node
425
+ attr_accessor :params, :body, :return_type
426
+
427
+ def initialize(params: [], body:, return_type: nil, **opts)
428
+ super(**opts)
429
+ @params = params
430
+ @body = body
431
+ @return_type = return_type
432
+ end
433
+
434
+ def children
435
+ [@body]
436
+ end
437
+ end
438
+
439
+ # Begin/rescue/ensure block
440
+ class BeginBlock < Node
441
+ attr_accessor :body, :rescue_clauses, :else_clause, :ensure_clause
442
+
443
+ def initialize(body:, rescue_clauses: [], else_clause: nil, ensure_clause: nil, **opts)
444
+ super(**opts)
445
+ @body = body
446
+ @rescue_clauses = rescue_clauses
447
+ @else_clause = else_clause
448
+ @ensure_clause = ensure_clause
449
+ end
450
+
451
+ def children
452
+ [@body, @else_clause, @ensure_clause].compact + @rescue_clauses
453
+ end
454
+ end
455
+
456
+ # Rescue clause
457
+ class RescueClause < Node
458
+ attr_accessor :exception_types, :variable, :body
459
+
460
+ def initialize(exception_types: [], variable: nil, body:, **opts)
461
+ super(**opts)
462
+ @exception_types = exception_types
463
+ @variable = variable
464
+ @body = body
465
+ end
466
+
467
+ def children
468
+ [@body]
469
+ end
470
+ end
471
+
472
+ # Raw Ruby code (for passthrough)
473
+ class RawCode < Node
474
+ attr_accessor :code
475
+
476
+ def initialize(code:, **opts)
477
+ super(**opts)
478
+ @code = code
479
+ end
480
+ end
481
+
482
+ #==========================================================================
483
+ # Type Representation Nodes
484
+ #==========================================================================
485
+
486
+ # Base type node
487
+ class TypeNode < Node
488
+ def to_rbs
489
+ raise NotImplementedError
490
+ end
491
+
492
+ def to_trb
493
+ raise NotImplementedError
494
+ end
495
+ end
496
+
497
+ # Simple type (String, Integer, etc.)
498
+ class SimpleType < TypeNode
499
+ attr_accessor :name
500
+
501
+ def initialize(name:, **opts)
502
+ super(**opts)
503
+ @name = name
504
+ end
505
+
506
+ def to_rbs
507
+ @name
508
+ end
509
+
510
+ def to_trb
511
+ @name
512
+ end
513
+ end
514
+
515
+ # Generic type (Array<String>, Map<K, V>)
516
+ class GenericType < TypeNode
517
+ attr_accessor :base, :type_args
518
+
519
+ def initialize(base:, type_args: [], **opts)
520
+ super(**opts)
521
+ @base = base
522
+ @type_args = type_args
523
+ end
524
+
525
+ def to_rbs
526
+ "#{@base}[#{@type_args.map(&:to_rbs).join(', ')}]"
527
+ end
528
+
529
+ def to_trb
530
+ "#{@base}<#{@type_args.map(&:to_trb).join(', ')}>"
531
+ end
532
+ end
533
+
534
+ # Union type (String | Integer | nil)
535
+ class UnionType < TypeNode
536
+ attr_accessor :types
537
+
538
+ def initialize(types: [], **opts)
539
+ super(**opts)
540
+ @types = types
541
+ end
542
+
543
+ def to_rbs
544
+ @types.map(&:to_rbs).join(" | ")
545
+ end
546
+
547
+ def to_trb
548
+ @types.map(&:to_trb).join(" | ")
549
+ end
550
+ end
551
+
552
+ # Intersection type (Readable & Writable)
553
+ class IntersectionType < TypeNode
554
+ attr_accessor :types
555
+
556
+ def initialize(types: [], **opts)
557
+ super(**opts)
558
+ @types = types
559
+ end
560
+
561
+ def to_rbs
562
+ @types.map(&:to_rbs).join(" & ")
563
+ end
564
+
565
+ def to_trb
566
+ @types.map(&:to_trb).join(" & ")
567
+ end
568
+ end
569
+
570
+ # Function/Proc type ((String, Integer) -> Boolean)
571
+ class FunctionType < TypeNode
572
+ attr_accessor :param_types, :return_type
573
+
574
+ def initialize(param_types: [], return_type:, **opts)
575
+ super(**opts)
576
+ @param_types = param_types
577
+ @return_type = return_type
578
+ end
579
+
580
+ def to_rbs
581
+ params = @param_types.map(&:to_rbs).join(", ")
582
+ "^(#{params}) -> #{@return_type.to_rbs}"
583
+ end
584
+
585
+ def to_trb
586
+ params = @param_types.map(&:to_trb).join(", ")
587
+ "(#{params}) -> #{@return_type.to_trb}"
588
+ end
589
+ end
590
+
591
+ # Tuple type ([String, Integer, Boolean])
592
+ class TupleType < TypeNode
593
+ attr_accessor :element_types
594
+
595
+ def initialize(element_types: [], **opts)
596
+ super(**opts)
597
+ @element_types = element_types
598
+ end
599
+
600
+ def to_rbs
601
+ "[#{@element_types.map(&:to_rbs).join(', ')}]"
602
+ end
603
+
604
+ def to_trb
605
+ "[#{@element_types.map(&:to_trb).join(', ')}]"
606
+ end
607
+ end
608
+
609
+ # Nullable type (String?)
610
+ class NullableType < TypeNode
611
+ attr_accessor :inner_type
612
+
613
+ def initialize(inner_type:, **opts)
614
+ super(**opts)
615
+ @inner_type = inner_type
616
+ end
617
+
618
+ def to_rbs
619
+ "#{@inner_type.to_rbs}?"
620
+ end
621
+
622
+ def to_trb
623
+ "#{@inner_type.to_trb}?"
624
+ end
625
+ end
626
+
627
+ # Literal type (literal value as type)
628
+ class LiteralType < TypeNode
629
+ attr_accessor :value
630
+
631
+ def initialize(value:, **opts)
632
+ super(**opts)
633
+ @value = value
634
+ end
635
+
636
+ def to_rbs
637
+ @value.inspect
638
+ end
639
+
640
+ def to_trb
641
+ @value.inspect
642
+ end
643
+ end
644
+
645
+ #==========================================================================
646
+ # Visitor Pattern
647
+ #==========================================================================
648
+
649
+ class Visitor
650
+ def visit(node)
651
+ method_name = "visit_#{node.class.name.split('::').last.gsub(/([A-Z])/, '_\1').downcase.sub(/^_/, '')}"
652
+ if respond_to?(method_name)
653
+ send(method_name, node)
654
+ else
655
+ visit_default(node)
656
+ end
657
+ end
658
+
659
+ def visit_default(node)
660
+ node.children.each { |child| visit(child) }
661
+ end
662
+
663
+ def visit_children(node)
664
+ node.children.each { |child| visit(child) }
665
+ end
666
+ end
667
+
668
+ #==========================================================================
669
+ # IR Builder - Converts parsed AST to IR
670
+ #==========================================================================
671
+
672
+ class Builder
673
+ def initialize
674
+ @type_registry = {}
675
+ end
676
+
677
+ # Build IR from parser output
678
+ def build(parse_result, source: nil)
679
+ declarations = []
680
+
681
+ # Build type aliases
682
+ (parse_result[:type_aliases] || []).each do |alias_info|
683
+ declarations << build_type_alias(alias_info)
684
+ end
685
+
686
+ # Build interfaces
687
+ (parse_result[:interfaces] || []).each do |interface_info|
688
+ declarations << build_interface(interface_info)
689
+ end
690
+
691
+ # Build functions/methods
692
+ (parse_result[:functions] || []).each do |func_info|
693
+ declarations << build_method(func_info)
694
+ end
695
+
696
+ Program.new(declarations: declarations, source_file: source)
697
+ end
698
+
699
+ # Build from source code
700
+ def build_from_source(source)
701
+ parser = Parser.new(source)
702
+ result = parser.parse
703
+ build(result, source: source)
704
+ end
705
+
706
+ private
707
+
708
+ def build_type_alias(info)
709
+ TypeAlias.new(
710
+ name: info[:name],
711
+ definition: parse_type(info[:definition])
712
+ )
713
+ end
714
+
715
+ def build_interface(info)
716
+ members = (info[:members] || []).map do |member|
717
+ InterfaceMember.new(
718
+ name: member[:name],
719
+ type_signature: parse_type(member[:type])
720
+ )
721
+ end
722
+
723
+ Interface.new(
724
+ name: info[:name],
725
+ members: members
726
+ )
727
+ end
728
+
729
+ def build_method(info)
730
+ params = (info[:params] || []).map do |param|
731
+ Parameter.new(
732
+ name: param[:name],
733
+ type_annotation: param[:type] ? parse_type(param[:type]) : nil
734
+ )
735
+ end
736
+
737
+ MethodDef.new(
738
+ name: info[:name],
739
+ params: params,
740
+ return_type: info[:return_type] ? parse_type(info[:return_type]) : nil
741
+ )
742
+ end
743
+
744
+ def parse_type(type_str)
745
+ return nil unless type_str
746
+
747
+ type_str = type_str.strip
748
+
749
+ # Union type
750
+ if type_str.include?("|")
751
+ types = type_str.split("|").map { |t| parse_type(t.strip) }
752
+ return UnionType.new(types: types)
753
+ end
754
+
755
+ # Intersection type
756
+ if type_str.include?("&")
757
+ types = type_str.split("&").map { |t| parse_type(t.strip) }
758
+ return IntersectionType.new(types: types)
759
+ end
760
+
761
+ # Nullable type
762
+ if type_str.end_with?("?")
763
+ inner = parse_type(type_str[0..-2])
764
+ return NullableType.new(inner_type: inner)
765
+ end
766
+
767
+ # Generic type
768
+ if type_str.include?("<") && type_str.include?(">")
769
+ match = type_str.match(/^(\w+)<(.+)>$/)
770
+ if match
771
+ base = match[1]
772
+ args = parse_generic_args(match[2])
773
+ return GenericType.new(base: base, type_args: args)
774
+ end
775
+ end
776
+
777
+ # Function type
778
+ if type_str.include?("->")
779
+ match = type_str.match(/^\((.*)?\)\s*->\s*(.+)$/)
780
+ if match
781
+ param_types = match[1] ? match[1].split(",").map { |t| parse_type(t.strip) } : []
782
+ return_type = parse_type(match[2])
783
+ return FunctionType.new(param_types: param_types, return_type: return_type)
784
+ end
785
+ end
786
+
787
+ # Simple type
788
+ SimpleType.new(name: type_str)
789
+ end
790
+
791
+ def parse_generic_args(args_str)
792
+ args = []
793
+ current = ""
794
+ depth = 0
795
+
796
+ args_str.each_char do |char|
797
+ case char
798
+ when "<"
799
+ depth += 1
800
+ current += char
801
+ when ">"
802
+ depth -= 1
803
+ current += char
804
+ when ","
805
+ if depth == 0
806
+ args << parse_type(current.strip)
807
+ current = ""
808
+ else
809
+ current += char
810
+ end
811
+ else
812
+ current += char
813
+ end
814
+ end
815
+
816
+ args << parse_type(current.strip) unless current.empty?
817
+ args
818
+ end
819
+ end
820
+
821
+ #==========================================================================
822
+ # Code Generator - Converts IR to Ruby code
823
+ #==========================================================================
824
+
825
+ class CodeGenerator < Visitor
826
+ attr_reader :output
827
+
828
+ def initialize
829
+ @output = []
830
+ @indent = 0
831
+ end
832
+
833
+ def generate(program)
834
+ @output = []
835
+ visit(program)
836
+ @output.join("\n")
837
+ end
838
+
839
+ def visit_program(node)
840
+ node.declarations.each do |decl|
841
+ visit(decl)
842
+ @output << ""
843
+ end
844
+ end
845
+
846
+ def visit_type_alias(node)
847
+ # Type aliases are erased in Ruby output
848
+ emit_comment("type #{node.name} = #{node.definition.to_trb}")
849
+ end
850
+
851
+ def visit_interface(node)
852
+ # Interfaces are erased in Ruby output
853
+ emit_comment("interface #{node.name}")
854
+ node.members.each do |member|
855
+ emit_comment(" #{member.name}: #{member.type_signature.to_trb}")
856
+ end
857
+ emit_comment("end")
858
+ end
859
+
860
+ def visit_method_def(node)
861
+ params_str = node.params.map(&:name).join(", ")
862
+ emit("def #{node.name}(#{params_str})")
863
+ @indent += 1
864
+
865
+ if node.body
866
+ visit(node.body)
867
+ end
868
+
869
+ @indent -= 1
870
+ emit("end")
871
+ end
872
+
873
+ def visit_block(node)
874
+ node.statements.each { |stmt| visit(stmt) }
875
+ end
876
+
877
+ def visit_assignment(node)
878
+ emit("#{node.target} = #{generate_expression(node.value)}")
879
+ end
880
+
881
+ def visit_return(node)
882
+ if node.value
883
+ emit("return #{generate_expression(node.value)}")
884
+ else
885
+ emit("return")
886
+ end
887
+ end
888
+
889
+ def visit_conditional(node)
890
+ keyword = node.kind == :unless ? "unless" : "if"
891
+ emit("#{keyword} #{generate_expression(node.condition)}")
892
+ @indent += 1
893
+ visit(node.then_branch) if node.then_branch
894
+ @indent -= 1
895
+
896
+ if node.else_branch
897
+ emit("else")
898
+ @indent += 1
899
+ visit(node.else_branch)
900
+ @indent -= 1
901
+ end
902
+
903
+ emit("end")
904
+ end
905
+
906
+ def visit_raw_code(node)
907
+ node.code.each_line do |line|
908
+ emit(line.rstrip)
909
+ end
910
+ end
911
+
912
+ private
913
+
914
+ def emit(text)
915
+ @output << (" " * @indent + text)
916
+ end
917
+
918
+ def emit_comment(text)
919
+ emit("# #{text}")
920
+ end
921
+
922
+ def generate_expression(node)
923
+ case node
924
+ when Literal
925
+ node.value.inspect
926
+ when VariableRef
927
+ node.name
928
+ when MethodCall
929
+ args = node.arguments.map { |a| generate_expression(a) }.join(", ")
930
+ if node.receiver
931
+ "#{generate_expression(node.receiver)}.#{node.method_name}(#{args})"
932
+ else
933
+ "#{node.method_name}(#{args})"
934
+ end
935
+ when BinaryOp
936
+ "(#{generate_expression(node.left)} #{node.operator} #{generate_expression(node.right)})"
937
+ when UnaryOp
938
+ "#{node.operator}#{generate_expression(node.operand)}"
939
+ else
940
+ node.to_s
941
+ end
942
+ end
943
+ end
944
+
945
+ #==========================================================================
946
+ # RBS Generator - Converts IR to RBS type definitions
947
+ #==========================================================================
948
+
949
+ class RBSGenerator < Visitor
950
+ attr_reader :output
951
+
952
+ def initialize
953
+ @output = []
954
+ @indent = 0
955
+ end
956
+
957
+ def generate(program)
958
+ @output = []
959
+ visit(program)
960
+ @output.join("\n")
961
+ end
962
+
963
+ def visit_program(node)
964
+ node.declarations.each do |decl|
965
+ visit(decl)
966
+ @output << ""
967
+ end
968
+ end
969
+
970
+ def visit_type_alias(node)
971
+ emit("type #{node.name} = #{node.definition.to_rbs}")
972
+ end
973
+
974
+ def visit_interface(node)
975
+ emit("interface _#{node.name}")
976
+ @indent += 1
977
+
978
+ node.members.each do |member|
979
+ visit(member)
980
+ end
981
+
982
+ @indent -= 1
983
+ emit("end")
984
+ end
985
+
986
+ def visit_interface_member(node)
987
+ emit("def #{node.name}: #{node.type_signature.to_rbs}")
988
+ end
989
+
990
+ def visit_method_def(node)
991
+ params = node.params.map do |param|
992
+ type = param.type_annotation&.to_rbs || "untyped"
993
+ "#{type} #{param.name}"
994
+ end.join(", ")
995
+
996
+ return_type = node.return_type&.to_rbs || "untyped"
997
+ emit("def #{node.name}: (#{params}) -> #{return_type}")
998
+ end
999
+
1000
+ def visit_class_decl(node)
1001
+ emit("class #{node.name}")
1002
+ @indent += 1
1003
+ node.body.each { |member| visit(member) }
1004
+ @indent -= 1
1005
+ emit("end")
1006
+ end
1007
+
1008
+ private
1009
+
1010
+ def emit(text)
1011
+ @output << (" " * @indent + text)
1012
+ end
1013
+ end
1014
+
1015
+ #==========================================================================
1016
+ # Optimization Passes
1017
+ #==========================================================================
1018
+
1019
+ module Passes
1020
+ # Base class for optimization passes
1021
+ class Pass
1022
+ attr_reader :name, :changes_made
1023
+
1024
+ def initialize(name)
1025
+ @name = name
1026
+ @changes_made = 0
1027
+ end
1028
+
1029
+ def run(program)
1030
+ @changes_made = 0
1031
+ transform(program)
1032
+ { program: program, changes: @changes_made }
1033
+ end
1034
+
1035
+ def transform(node)
1036
+ raise NotImplementedError
1037
+ end
1038
+ end
1039
+
1040
+ # Dead code elimination
1041
+ class DeadCodeElimination < Pass
1042
+ def initialize
1043
+ super("dead_code_elimination")
1044
+ end
1045
+
1046
+ def transform(node)
1047
+ case node
1048
+ when Program
1049
+ node.declarations = node.declarations.map { |d| transform(d) }.compact
1050
+ when Block
1051
+ node.statements = eliminate_dead_statements(node.statements)
1052
+ node.statements.each { |stmt| transform(stmt) }
1053
+ when MethodDef
1054
+ transform(node.body) if node.body
1055
+ end
1056
+
1057
+ node
1058
+ end
1059
+
1060
+ private
1061
+
1062
+ def eliminate_dead_statements(statements)
1063
+ result = []
1064
+ found_return = false
1065
+
1066
+ statements.each do |stmt|
1067
+ if found_return
1068
+ @changes_made += 1
1069
+ next
1070
+ end
1071
+
1072
+ result << stmt
1073
+ found_return = true if stmt.is_a?(Return)
1074
+ end
1075
+
1076
+ result
1077
+ end
1078
+ end
1079
+
1080
+ # Constant folding
1081
+ class ConstantFolding < Pass
1082
+ def initialize
1083
+ super("constant_folding")
1084
+ end
1085
+
1086
+ def transform(node)
1087
+ case node
1088
+ when Program
1089
+ node.declarations.each { |d| transform(d) }
1090
+ when MethodDef
1091
+ transform(node.body) if node.body
1092
+ when Block
1093
+ node.statements = node.statements.map { |s| fold_constants(s) }
1094
+ when BinaryOp
1095
+ fold_binary_op(node)
1096
+ end
1097
+
1098
+ node
1099
+ end
1100
+
1101
+ private
1102
+
1103
+ def fold_constants(node)
1104
+ case node
1105
+ when BinaryOp
1106
+ fold_binary_op(node)
1107
+ when Assignment
1108
+ node.value = fold_constants(node.value)
1109
+ node
1110
+ when Return
1111
+ node.value = fold_constants(node.value) if node.value
1112
+ node
1113
+ else
1114
+ node
1115
+ end
1116
+ end
1117
+
1118
+ def fold_binary_op(node)
1119
+ return node unless node.is_a?(BinaryOp)
1120
+
1121
+ left = fold_constants(node.left)
1122
+ right = fold_constants(node.right)
1123
+
1124
+ if left.is_a?(Literal) && right.is_a?(Literal)
1125
+ result = evaluate_op(node.operator, left.value, right.value)
1126
+ if result
1127
+ @changes_made += 1
1128
+ return Literal.new(value: result, literal_type: result.class.to_s.downcase.to_sym)
1129
+ end
1130
+ end
1131
+
1132
+ node.left = left
1133
+ node.right = right
1134
+ node
1135
+ end
1136
+
1137
+ def evaluate_op(op, left, right)
1138
+ return nil unless left.is_a?(Numeric) && right.is_a?(Numeric)
1139
+
1140
+ case op
1141
+ when "+" then left + right
1142
+ when "-" then left - right
1143
+ when "*" then left * right
1144
+ when "/" then right != 0 ? left / right : nil
1145
+ when "%" then right != 0 ? left % right : nil
1146
+ when "**" then left ** right
1147
+ else nil
1148
+ end
1149
+ rescue
1150
+ nil
1151
+ end
1152
+ end
1153
+
1154
+ # Type annotation cleanup
1155
+ class TypeAnnotationCleanup < Pass
1156
+ def initialize
1157
+ super("type_annotation_cleanup")
1158
+ end
1159
+
1160
+ def transform(node)
1161
+ case node
1162
+ when Program
1163
+ node.declarations.each { |d| transform(d) }
1164
+ when MethodDef
1165
+ # Remove redundant type annotations
1166
+ node.params.each do |param|
1167
+ if param.type_annotation && redundant_annotation?(param)
1168
+ param.type_annotation = nil
1169
+ @changes_made += 1
1170
+ end
1171
+ end
1172
+ end
1173
+
1174
+ node
1175
+ end
1176
+
1177
+ private
1178
+
1179
+ def redundant_annotation?(param)
1180
+ # Consider annotation redundant if it matches the default/inferred type
1181
+ false
1182
+ end
1183
+ end
1184
+
1185
+ # Unused declaration removal
1186
+ class UnusedDeclarationRemoval < Pass
1187
+ def initialize
1188
+ super("unused_declaration_removal")
1189
+ end
1190
+
1191
+ def transform(node)
1192
+ return node unless node.is_a?(Program)
1193
+
1194
+ used_types = collect_used_types(node)
1195
+
1196
+ node.declarations = node.declarations.select do |decl|
1197
+ case decl
1198
+ when TypeAlias
1199
+ if used_types.include?(decl.name)
1200
+ true
1201
+ else
1202
+ @changes_made += 1
1203
+ false
1204
+ end
1205
+ else
1206
+ true
1207
+ end
1208
+ end
1209
+
1210
+ node
1211
+ end
1212
+
1213
+ private
1214
+
1215
+ def collect_used_types(program)
1216
+ used = Set.new
1217
+
1218
+ program.declarations.each do |decl|
1219
+ case decl
1220
+ when MethodDef
1221
+ collect_types_from_method(decl, used)
1222
+ when Interface
1223
+ decl.members.each do |member|
1224
+ collect_types_from_type(member.type_signature, used)
1225
+ end
1226
+ end
1227
+ end
1228
+
1229
+ used
1230
+ end
1231
+
1232
+ def collect_types_from_method(method, used)
1233
+ method.params.each do |param|
1234
+ collect_types_from_type(param.type_annotation, used) if param.type_annotation
1235
+ end
1236
+ collect_types_from_type(method.return_type, used) if method.return_type
1237
+ end
1238
+
1239
+ def collect_types_from_type(type_node, used)
1240
+ case type_node
1241
+ when SimpleType
1242
+ used.add(type_node.name)
1243
+ when GenericType
1244
+ used.add(type_node.base)
1245
+ type_node.type_args.each { |arg| collect_types_from_type(arg, used) }
1246
+ when UnionType, IntersectionType
1247
+ type_node.types.each { |t| collect_types_from_type(t, used) }
1248
+ when NullableType
1249
+ collect_types_from_type(type_node.inner_type, used)
1250
+ when FunctionType
1251
+ type_node.param_types.each { |t| collect_types_from_type(t, used) }
1252
+ collect_types_from_type(type_node.return_type, used)
1253
+ end
1254
+ end
1255
+ end
1256
+ end
1257
+
1258
+ #==========================================================================
1259
+ # Optimizer - Runs optimization passes
1260
+ #==========================================================================
1261
+
1262
+ class Optimizer
1263
+ DEFAULT_PASSES = [
1264
+ Passes::DeadCodeElimination,
1265
+ Passes::ConstantFolding,
1266
+ Passes::TypeAnnotationCleanup,
1267
+ Passes::UnusedDeclarationRemoval
1268
+ ].freeze
1269
+
1270
+ attr_reader :passes, :stats
1271
+
1272
+ def initialize(passes: DEFAULT_PASSES)
1273
+ @passes = passes.map(&:new)
1274
+ @stats = {}
1275
+ end
1276
+
1277
+ def optimize(program, max_iterations: 10)
1278
+ @stats = { iterations: 0, total_changes: 0, pass_stats: {} }
1279
+
1280
+ max_iterations.times do |i|
1281
+ @stats[:iterations] = i + 1
1282
+ changes_this_iteration = 0
1283
+
1284
+ @passes.each do |pass|
1285
+ result = pass.run(program)
1286
+ program = result[:program]
1287
+ changes_this_iteration += result[:changes]
1288
+
1289
+ @stats[:pass_stats][pass.name] ||= 0
1290
+ @stats[:pass_stats][pass.name] += result[:changes]
1291
+ end
1292
+
1293
+ @stats[:total_changes] += changes_this_iteration
1294
+ break if changes_this_iteration == 0
1295
+ end
1296
+
1297
+ { program: program, stats: @stats }
1298
+ end
1299
+ end
1300
+ end
1301
+ end