machine-dialect 0.1.0a1__py3-none-any.whl

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.
Files changed (268) hide show
  1. machine_dialect/__main__.py +667 -0
  2. machine_dialect/agent/__init__.py +5 -0
  3. machine_dialect/agent/agent.py +360 -0
  4. machine_dialect/ast/__init__.py +95 -0
  5. machine_dialect/ast/ast_node.py +35 -0
  6. machine_dialect/ast/call_expression.py +82 -0
  7. machine_dialect/ast/dict_extraction.py +60 -0
  8. machine_dialect/ast/expressions.py +439 -0
  9. machine_dialect/ast/literals.py +309 -0
  10. machine_dialect/ast/program.py +35 -0
  11. machine_dialect/ast/statements.py +1433 -0
  12. machine_dialect/ast/tests/test_ast_string_representation.py +62 -0
  13. machine_dialect/ast/tests/test_boolean_literal.py +29 -0
  14. machine_dialect/ast/tests/test_collection_hir.py +138 -0
  15. machine_dialect/ast/tests/test_define_statement.py +142 -0
  16. machine_dialect/ast/tests/test_desugar.py +541 -0
  17. machine_dialect/ast/tests/test_foreach_desugar.py +245 -0
  18. machine_dialect/cfg/__init__.py +6 -0
  19. machine_dialect/cfg/config.py +156 -0
  20. machine_dialect/cfg/examples.py +221 -0
  21. machine_dialect/cfg/generate_with_ai.py +187 -0
  22. machine_dialect/cfg/openai_generation.py +200 -0
  23. machine_dialect/cfg/parser.py +94 -0
  24. machine_dialect/cfg/tests/__init__.py +1 -0
  25. machine_dialect/cfg/tests/test_cfg_parser.py +252 -0
  26. machine_dialect/cfg/tests/test_config.py +188 -0
  27. machine_dialect/cfg/tests/test_examples.py +391 -0
  28. machine_dialect/cfg/tests/test_generate_with_ai.py +354 -0
  29. machine_dialect/cfg/tests/test_openai_generation.py +256 -0
  30. machine_dialect/codegen/__init__.py +5 -0
  31. machine_dialect/codegen/bytecode_module.py +89 -0
  32. machine_dialect/codegen/bytecode_serializer.py +300 -0
  33. machine_dialect/codegen/opcodes.py +101 -0
  34. machine_dialect/codegen/register_codegen.py +1996 -0
  35. machine_dialect/codegen/symtab.py +208 -0
  36. machine_dialect/codegen/tests/__init__.py +1 -0
  37. machine_dialect/codegen/tests/test_array_operations_codegen.py +295 -0
  38. machine_dialect/codegen/tests/test_bytecode_serializer.py +185 -0
  39. machine_dialect/codegen/tests/test_register_codegen_ssa.py +324 -0
  40. machine_dialect/codegen/tests/test_symtab.py +418 -0
  41. machine_dialect/codegen/vm_serializer.py +621 -0
  42. machine_dialect/compiler/__init__.py +18 -0
  43. machine_dialect/compiler/compiler.py +197 -0
  44. machine_dialect/compiler/config.py +149 -0
  45. machine_dialect/compiler/context.py +149 -0
  46. machine_dialect/compiler/phases/__init__.py +19 -0
  47. machine_dialect/compiler/phases/bytecode_optimization.py +90 -0
  48. machine_dialect/compiler/phases/codegen.py +40 -0
  49. machine_dialect/compiler/phases/hir_generation.py +39 -0
  50. machine_dialect/compiler/phases/mir_generation.py +86 -0
  51. machine_dialect/compiler/phases/optimization.py +110 -0
  52. machine_dialect/compiler/phases/parsing.py +39 -0
  53. machine_dialect/compiler/pipeline.py +143 -0
  54. machine_dialect/compiler/tests/__init__.py +1 -0
  55. machine_dialect/compiler/tests/test_compiler.py +568 -0
  56. machine_dialect/compiler/vm_runner.py +173 -0
  57. machine_dialect/errors/__init__.py +32 -0
  58. machine_dialect/errors/exceptions.py +369 -0
  59. machine_dialect/errors/messages.py +82 -0
  60. machine_dialect/errors/tests/__init__.py +0 -0
  61. machine_dialect/errors/tests/test_expected_token_errors.py +188 -0
  62. machine_dialect/errors/tests/test_name_errors.py +118 -0
  63. machine_dialect/helpers/__init__.py +0 -0
  64. machine_dialect/helpers/stopwords.py +225 -0
  65. machine_dialect/helpers/validators.py +30 -0
  66. machine_dialect/lexer/__init__.py +9 -0
  67. machine_dialect/lexer/constants.py +23 -0
  68. machine_dialect/lexer/lexer.py +907 -0
  69. machine_dialect/lexer/tests/__init__.py +0 -0
  70. machine_dialect/lexer/tests/helpers.py +86 -0
  71. machine_dialect/lexer/tests/test_apostrophe_identifiers.py +122 -0
  72. machine_dialect/lexer/tests/test_backtick_identifiers.py +140 -0
  73. machine_dialect/lexer/tests/test_boolean_literals.py +108 -0
  74. machine_dialect/lexer/tests/test_case_insensitive_keywords.py +188 -0
  75. machine_dialect/lexer/tests/test_comments.py +200 -0
  76. machine_dialect/lexer/tests/test_double_asterisk_keywords.py +127 -0
  77. machine_dialect/lexer/tests/test_lexer_position.py +113 -0
  78. machine_dialect/lexer/tests/test_list_tokens.py +282 -0
  79. machine_dialect/lexer/tests/test_stopwords.py +80 -0
  80. machine_dialect/lexer/tests/test_strict_equality.py +129 -0
  81. machine_dialect/lexer/tests/test_token.py +41 -0
  82. machine_dialect/lexer/tests/test_tokenization.py +294 -0
  83. machine_dialect/lexer/tests/test_underscore_literals.py +343 -0
  84. machine_dialect/lexer/tests/test_url_literals.py +169 -0
  85. machine_dialect/lexer/tokens.py +487 -0
  86. machine_dialect/linter/__init__.py +10 -0
  87. machine_dialect/linter/__main__.py +144 -0
  88. machine_dialect/linter/linter.py +154 -0
  89. machine_dialect/linter/rules/__init__.py +8 -0
  90. machine_dialect/linter/rules/base.py +112 -0
  91. machine_dialect/linter/rules/statement_termination.py +99 -0
  92. machine_dialect/linter/tests/__init__.py +1 -0
  93. machine_dialect/linter/tests/mdrules/__init__.py +0 -0
  94. machine_dialect/linter/tests/mdrules/test_md101_statement_termination.py +181 -0
  95. machine_dialect/linter/tests/test_linter.py +81 -0
  96. machine_dialect/linter/tests/test_rules.py +110 -0
  97. machine_dialect/linter/tests/test_violations.py +71 -0
  98. machine_dialect/linter/violations.py +51 -0
  99. machine_dialect/mir/__init__.py +69 -0
  100. machine_dialect/mir/analyses/__init__.py +20 -0
  101. machine_dialect/mir/analyses/alias_analysis.py +315 -0
  102. machine_dialect/mir/analyses/dominance_analysis.py +49 -0
  103. machine_dialect/mir/analyses/escape_analysis.py +286 -0
  104. machine_dialect/mir/analyses/loop_analysis.py +272 -0
  105. machine_dialect/mir/analyses/tests/test_type_analysis.py +736 -0
  106. machine_dialect/mir/analyses/type_analysis.py +448 -0
  107. machine_dialect/mir/analyses/use_def_chains.py +232 -0
  108. machine_dialect/mir/basic_block.py +385 -0
  109. machine_dialect/mir/dataflow.py +445 -0
  110. machine_dialect/mir/debug_info.py +208 -0
  111. machine_dialect/mir/hir_to_mir.py +1738 -0
  112. machine_dialect/mir/mir_dumper.py +366 -0
  113. machine_dialect/mir/mir_function.py +167 -0
  114. machine_dialect/mir/mir_instructions.py +1877 -0
  115. machine_dialect/mir/mir_interpreter.py +556 -0
  116. machine_dialect/mir/mir_module.py +225 -0
  117. machine_dialect/mir/mir_printer.py +480 -0
  118. machine_dialect/mir/mir_transformer.py +410 -0
  119. machine_dialect/mir/mir_types.py +367 -0
  120. machine_dialect/mir/mir_validation.py +455 -0
  121. machine_dialect/mir/mir_values.py +268 -0
  122. machine_dialect/mir/optimization_config.py +233 -0
  123. machine_dialect/mir/optimization_pass.py +251 -0
  124. machine_dialect/mir/optimization_pipeline.py +355 -0
  125. machine_dialect/mir/optimizations/__init__.py +84 -0
  126. machine_dialect/mir/optimizations/algebraic_simplification.py +733 -0
  127. machine_dialect/mir/optimizations/branch_prediction.py +372 -0
  128. machine_dialect/mir/optimizations/constant_propagation.py +634 -0
  129. machine_dialect/mir/optimizations/cse.py +398 -0
  130. machine_dialect/mir/optimizations/dce.py +288 -0
  131. machine_dialect/mir/optimizations/inlining.py +551 -0
  132. machine_dialect/mir/optimizations/jump_threading.py +487 -0
  133. machine_dialect/mir/optimizations/licm.py +405 -0
  134. machine_dialect/mir/optimizations/loop_unrolling.py +366 -0
  135. machine_dialect/mir/optimizations/strength_reduction.py +422 -0
  136. machine_dialect/mir/optimizations/tail_call.py +207 -0
  137. machine_dialect/mir/optimizations/tests/test_loop_unrolling.py +483 -0
  138. machine_dialect/mir/optimizations/type_narrowing.py +397 -0
  139. machine_dialect/mir/optimizations/type_specialization.py +447 -0
  140. machine_dialect/mir/optimizations/type_specific.py +906 -0
  141. machine_dialect/mir/optimize_mir.py +89 -0
  142. machine_dialect/mir/pass_manager.py +391 -0
  143. machine_dialect/mir/profiling/__init__.py +26 -0
  144. machine_dialect/mir/profiling/profile_collector.py +318 -0
  145. machine_dialect/mir/profiling/profile_data.py +372 -0
  146. machine_dialect/mir/profiling/profile_reader.py +272 -0
  147. machine_dialect/mir/profiling/profile_writer.py +226 -0
  148. machine_dialect/mir/register_allocation.py +302 -0
  149. machine_dialect/mir/reporting/__init__.py +17 -0
  150. machine_dialect/mir/reporting/optimization_reporter.py +314 -0
  151. machine_dialect/mir/reporting/report_formatter.py +289 -0
  152. machine_dialect/mir/ssa_construction.py +342 -0
  153. machine_dialect/mir/tests/__init__.py +1 -0
  154. machine_dialect/mir/tests/test_algebraic_associativity.py +204 -0
  155. machine_dialect/mir/tests/test_algebraic_complex_patterns.py +221 -0
  156. machine_dialect/mir/tests/test_algebraic_division.py +126 -0
  157. machine_dialect/mir/tests/test_algebraic_simplification.py +863 -0
  158. machine_dialect/mir/tests/test_basic_block.py +425 -0
  159. machine_dialect/mir/tests/test_branch_prediction.py +459 -0
  160. machine_dialect/mir/tests/test_call_lowering.py +168 -0
  161. machine_dialect/mir/tests/test_collection_lowering.py +604 -0
  162. machine_dialect/mir/tests/test_cross_block_constant_propagation.py +255 -0
  163. machine_dialect/mir/tests/test_custom_passes.py +166 -0
  164. machine_dialect/mir/tests/test_debug_info.py +285 -0
  165. machine_dialect/mir/tests/test_dict_extraction_lowering.py +192 -0
  166. machine_dialect/mir/tests/test_dictionary_lowering.py +299 -0
  167. machine_dialect/mir/tests/test_double_negation.py +231 -0
  168. machine_dialect/mir/tests/test_escape_analysis.py +233 -0
  169. machine_dialect/mir/tests/test_hir_to_mir.py +465 -0
  170. machine_dialect/mir/tests/test_hir_to_mir_complete.py +389 -0
  171. machine_dialect/mir/tests/test_hir_to_mir_simple.py +130 -0
  172. machine_dialect/mir/tests/test_inlining.py +435 -0
  173. machine_dialect/mir/tests/test_licm.py +472 -0
  174. machine_dialect/mir/tests/test_mir_dumper.py +313 -0
  175. machine_dialect/mir/tests/test_mir_instructions.py +445 -0
  176. machine_dialect/mir/tests/test_mir_module.py +860 -0
  177. machine_dialect/mir/tests/test_mir_printer.py +387 -0
  178. machine_dialect/mir/tests/test_mir_types.py +123 -0
  179. machine_dialect/mir/tests/test_mir_types_enhanced.py +132 -0
  180. machine_dialect/mir/tests/test_mir_validation.py +378 -0
  181. machine_dialect/mir/tests/test_mir_values.py +168 -0
  182. machine_dialect/mir/tests/test_one_based_indexing.py +202 -0
  183. machine_dialect/mir/tests/test_optimization_helpers.py +60 -0
  184. machine_dialect/mir/tests/test_optimization_pipeline.py +554 -0
  185. machine_dialect/mir/tests/test_optimization_reporter.py +318 -0
  186. machine_dialect/mir/tests/test_pass_manager.py +294 -0
  187. machine_dialect/mir/tests/test_pass_registration.py +64 -0
  188. machine_dialect/mir/tests/test_profiling.py +356 -0
  189. machine_dialect/mir/tests/test_register_allocation.py +307 -0
  190. machine_dialect/mir/tests/test_report_formatters.py +372 -0
  191. machine_dialect/mir/tests/test_ssa_construction.py +433 -0
  192. machine_dialect/mir/tests/test_tail_call.py +236 -0
  193. machine_dialect/mir/tests/test_type_annotated_instructions.py +192 -0
  194. machine_dialect/mir/tests/test_type_narrowing.py +277 -0
  195. machine_dialect/mir/tests/test_type_specialization.py +421 -0
  196. machine_dialect/mir/tests/test_type_specific_optimization.py +545 -0
  197. machine_dialect/mir/tests/test_type_specific_optimization_advanced.py +382 -0
  198. machine_dialect/mir/type_inference.py +368 -0
  199. machine_dialect/parser/__init__.py +12 -0
  200. machine_dialect/parser/enums.py +45 -0
  201. machine_dialect/parser/parser.py +3655 -0
  202. machine_dialect/parser/protocols.py +11 -0
  203. machine_dialect/parser/symbol_table.py +169 -0
  204. machine_dialect/parser/tests/__init__.py +0 -0
  205. machine_dialect/parser/tests/helper_functions.py +193 -0
  206. machine_dialect/parser/tests/test_action_statements.py +334 -0
  207. machine_dialect/parser/tests/test_boolean_literal_expressions.py +152 -0
  208. machine_dialect/parser/tests/test_call_statements.py +154 -0
  209. machine_dialect/parser/tests/test_call_statements_errors.py +187 -0
  210. machine_dialect/parser/tests/test_collection_mutations.py +264 -0
  211. machine_dialect/parser/tests/test_conditional_expressions.py +343 -0
  212. machine_dialect/parser/tests/test_define_integration.py +468 -0
  213. machine_dialect/parser/tests/test_define_statements.py +311 -0
  214. machine_dialect/parser/tests/test_dict_extraction.py +115 -0
  215. machine_dialect/parser/tests/test_empty_literal.py +155 -0
  216. machine_dialect/parser/tests/test_float_literal_expressions.py +163 -0
  217. machine_dialect/parser/tests/test_identifier_expressions.py +57 -0
  218. machine_dialect/parser/tests/test_if_empty_block.py +61 -0
  219. machine_dialect/parser/tests/test_if_statements.py +299 -0
  220. machine_dialect/parser/tests/test_illegal_tokens.py +86 -0
  221. machine_dialect/parser/tests/test_infix_expressions.py +680 -0
  222. machine_dialect/parser/tests/test_integer_literal_expressions.py +137 -0
  223. machine_dialect/parser/tests/test_interaction_statements.py +269 -0
  224. machine_dialect/parser/tests/test_list_literals.py +277 -0
  225. machine_dialect/parser/tests/test_no_none_in_ast.py +94 -0
  226. machine_dialect/parser/tests/test_panic_mode_recovery.py +171 -0
  227. machine_dialect/parser/tests/test_parse_errors.py +114 -0
  228. machine_dialect/parser/tests/test_possessive_syntax.py +182 -0
  229. machine_dialect/parser/tests/test_prefix_expressions.py +415 -0
  230. machine_dialect/parser/tests/test_program.py +13 -0
  231. machine_dialect/parser/tests/test_return_statements.py +89 -0
  232. machine_dialect/parser/tests/test_set_statements.py +152 -0
  233. machine_dialect/parser/tests/test_strict_equality.py +258 -0
  234. machine_dialect/parser/tests/test_symbol_table.py +217 -0
  235. machine_dialect/parser/tests/test_url_literal_expressions.py +209 -0
  236. machine_dialect/parser/tests/test_utility_statements.py +423 -0
  237. machine_dialect/parser/token_buffer.py +159 -0
  238. machine_dialect/repl/__init__.py +3 -0
  239. machine_dialect/repl/repl.py +426 -0
  240. machine_dialect/repl/tests/__init__.py +0 -0
  241. machine_dialect/repl/tests/test_repl.py +606 -0
  242. machine_dialect/semantic/__init__.py +12 -0
  243. machine_dialect/semantic/analyzer.py +906 -0
  244. machine_dialect/semantic/error_messages.py +189 -0
  245. machine_dialect/semantic/tests/__init__.py +1 -0
  246. machine_dialect/semantic/tests/test_analyzer.py +364 -0
  247. machine_dialect/semantic/tests/test_error_messages.py +104 -0
  248. machine_dialect/tests/edge_cases/__init__.py +10 -0
  249. machine_dialect/tests/edge_cases/test_boundary_access.py +256 -0
  250. machine_dialect/tests/edge_cases/test_empty_collections.py +166 -0
  251. machine_dialect/tests/edge_cases/test_invalid_operations.py +243 -0
  252. machine_dialect/tests/edge_cases/test_named_list_edge_cases.py +295 -0
  253. machine_dialect/tests/edge_cases/test_nested_structures.py +313 -0
  254. machine_dialect/tests/edge_cases/test_type_mixing.py +277 -0
  255. machine_dialect/tests/integration/test_array_operations_emulation.py +248 -0
  256. machine_dialect/tests/integration/test_list_compilation.py +395 -0
  257. machine_dialect/tests/integration/test_lists_and_dictionaries.py +322 -0
  258. machine_dialect/type_checking/__init__.py +21 -0
  259. machine_dialect/type_checking/tests/__init__.py +1 -0
  260. machine_dialect/type_checking/tests/test_type_system.py +230 -0
  261. machine_dialect/type_checking/type_system.py +270 -0
  262. machine_dialect-0.1.0a1.dist-info/METADATA +128 -0
  263. machine_dialect-0.1.0a1.dist-info/RECORD +268 -0
  264. machine_dialect-0.1.0a1.dist-info/WHEEL +5 -0
  265. machine_dialect-0.1.0a1.dist-info/entry_points.txt +3 -0
  266. machine_dialect-0.1.0a1.dist-info/licenses/LICENSE +201 -0
  267. machine_dialect-0.1.0a1.dist-info/top_level.txt +2 -0
  268. machine_dialect_vm/__init__.pyi +15 -0
@@ -0,0 +1,860 @@
1
+ """Tests for MIR module and function containers."""
2
+
3
+ import json
4
+ from typing import Any
5
+
6
+ from machine_dialect.mir.basic_block import BasicBlock
7
+ from machine_dialect.mir.mir_function import MIRFunction
8
+ from machine_dialect.mir.mir_instructions import (
9
+ BinaryOp,
10
+ ConditionalJump,
11
+ Jump,
12
+ LoadConst,
13
+ LoadVar,
14
+ Return,
15
+ )
16
+ from machine_dialect.mir.mir_module import ConstantPool, MIRModule
17
+ from machine_dialect.mir.mir_types import MIRType
18
+ from machine_dialect.mir.mir_values import Constant, Temp, Variable
19
+
20
+
21
+ class TestConstantPool:
22
+ """Test constant pool functionality."""
23
+
24
+ def test_constant_pool_creation(self) -> None:
25
+ """Test creating constant pool."""
26
+ pool = ConstantPool()
27
+ assert pool.constants == []
28
+ assert pool.size() == 0
29
+
30
+ def test_add_constants(self) -> None:
31
+ """Test adding constants to pool."""
32
+ pool = ConstantPool()
33
+
34
+ c1 = Constant(42, MIRType.INT)
35
+ c2 = Constant(3.14, MIRType.FLOAT)
36
+ c3 = Constant("hello", MIRType.STRING)
37
+
38
+ idx1 = pool.add(c1)
39
+ idx2 = pool.add(c2)
40
+ idx3 = pool.add(c3)
41
+
42
+ assert idx1 == 0
43
+ assert idx2 == 1
44
+ assert idx3 == 2
45
+ assert pool.size() == 3
46
+
47
+ def test_deduplication(self) -> None:
48
+ """Test that identical constants are deduplicated."""
49
+ pool = ConstantPool()
50
+
51
+ c1 = Constant(42, MIRType.INT)
52
+ c2 = Constant(42, MIRType.INT) # Same value and type
53
+ c3 = Constant(42, MIRType.FLOAT) # Same value, different type
54
+
55
+ idx1 = pool.add(c1)
56
+ idx2 = pool.add(c2)
57
+ idx3 = pool.add(c3)
58
+
59
+ # c1 and c2 should map to same index
60
+ assert idx1 == idx2
61
+ # c3 should have different index
62
+ assert idx1 != idx3
63
+ assert pool.size() == 2
64
+
65
+ def test_deduplication_complex_types(self) -> None:
66
+ """Test deduplication with complex constants."""
67
+ pool = ConstantPool()
68
+
69
+ # Test string deduplication
70
+ s1 = Constant("hello world", MIRType.STRING)
71
+ s2 = Constant("hello world", MIRType.STRING)
72
+ s3 = Constant("hello", MIRType.STRING)
73
+
74
+ idx1 = pool.add(s1)
75
+ idx2 = pool.add(s2)
76
+ idx3 = pool.add(s3)
77
+
78
+ assert idx1 == idx2 # Same strings deduplicated
79
+ assert idx1 != idx3 # Different strings
80
+
81
+ # Test boolean deduplication
82
+ b1 = Constant(True, MIRType.BOOL)
83
+ b2 = Constant(True, MIRType.BOOL)
84
+ b3 = Constant(False, MIRType.BOOL)
85
+
86
+ idx4 = pool.add(b1)
87
+ idx5 = pool.add(b2)
88
+ idx6 = pool.add(b3)
89
+
90
+ assert idx4 == idx5 # Same booleans deduplicated
91
+ assert idx4 != idx6 # Different booleans
92
+
93
+ # Should have 4 unique constants total (2 strings, 2 booleans)
94
+ assert pool.size() == 4
95
+
96
+ def test_deduplication_preserves_insertion_order(self) -> None:
97
+ """Test that deduplication preserves the first insertion."""
98
+ pool = ConstantPool()
99
+
100
+ c1 = Constant(100, MIRType.INT)
101
+ c2 = Constant(200, MIRType.INT)
102
+ c3 = Constant(100, MIRType.INT) # Duplicate of c1
103
+
104
+ idx1 = pool.add(c1)
105
+ idx2 = pool.add(c2)
106
+ idx3 = pool.add(c3)
107
+
108
+ assert idx1 == 0
109
+ assert idx2 == 1
110
+ assert idx3 == 0 # Should reuse c1's index
111
+
112
+ # Check that the original constant is preserved
113
+ retrieved = pool.get(0)
114
+ assert retrieved == c1
115
+ assert retrieved is not None
116
+ if retrieved: # Type guard for mypy
117
+ assert retrieved.value == 100
118
+
119
+ def test_get_constant(self) -> None:
120
+ """Test retrieving constants from pool."""
121
+ pool = ConstantPool()
122
+
123
+ c1 = Constant(100)
124
+ c2 = Constant("test")
125
+
126
+ pool.add(c1)
127
+ pool.add(c2)
128
+
129
+ retrieved1 = pool.get(0)
130
+ retrieved2 = pool.get(1)
131
+ retrieved3 = pool.get(99) # Out of bounds
132
+
133
+ assert retrieved1 == c1
134
+ assert retrieved2 == c2
135
+ assert retrieved3 is None
136
+
137
+ def test_constant_pool_string_representation(self) -> None:
138
+ """Test string representation of constant pool."""
139
+ pool = ConstantPool()
140
+ pool.add(Constant(42))
141
+ pool.add(Constant("hello"))
142
+ pool.add(Constant(True))
143
+
144
+ result = str(pool)
145
+ assert "Constants:" in result
146
+ assert "[0] 42" in result
147
+ assert '[1] "hello"' in result
148
+ assert "[2] True" in result
149
+
150
+
151
+ class TestMIRFunction:
152
+ """Test MIR function functionality."""
153
+
154
+ def test_function_creation(self) -> None:
155
+ """Test creating MIR function."""
156
+ func = MIRFunction("main", return_type=MIRType.INT)
157
+ assert func.name == "main"
158
+ assert func.return_type == MIRType.INT
159
+ assert func.params == []
160
+ assert func.cfg is not None
161
+
162
+ def test_function_with_parameters(self) -> None:
163
+ """Test function with parameters."""
164
+ params = [
165
+ Variable("x", MIRType.INT),
166
+ Variable("y", MIRType.FLOAT),
167
+ ]
168
+ func = MIRFunction("add", params, MIRType.FLOAT)
169
+
170
+ assert func.params == params
171
+ assert len(func.params) == 2
172
+ assert func.params[0].name == "x"
173
+ assert func.params[1].type == MIRType.FLOAT
174
+
175
+ def test_add_local_variable(self) -> None:
176
+ """Test adding local variables."""
177
+ func = MIRFunction("compute")
178
+ v1 = Variable("temp", MIRType.INT)
179
+ v2 = Variable("result", MIRType.FLOAT)
180
+
181
+ func.add_local(v1)
182
+ func.add_local(v2)
183
+
184
+ assert len(func.locals) == 2
185
+ assert "temp" in func.locals
186
+ assert "result" in func.locals
187
+ assert func.locals["temp"] == v1
188
+
189
+ def test_get_local_variable(self) -> None:
190
+ """Test getting local variables."""
191
+ func = MIRFunction("test")
192
+ v = Variable("counter", MIRType.INT)
193
+ func.add_local(v)
194
+
195
+ retrieved = func.get_local("counter")
196
+ assert retrieved == v
197
+
198
+ none_var = func.get_local("nonexistent")
199
+ assert none_var is None
200
+
201
+ def test_function_string_representation(self) -> None:
202
+ """Test string representation of function."""
203
+ func = MIRFunction(
204
+ "factorial",
205
+ [Variable("n", MIRType.INT)],
206
+ MIRType.INT,
207
+ )
208
+
209
+ # Add some blocks
210
+ entry = BasicBlock("entry")
211
+ t0 = Temp(MIRType.INT, temp_id=0)
212
+ entry.add_instruction(LoadConst(t0, 1, (1, 1)))
213
+ entry.add_instruction(Return((1, 1), t0))
214
+
215
+ func.cfg.add_block(entry)
216
+ func.cfg.set_entry_block(entry)
217
+
218
+ result = str(func)
219
+ assert "function factorial(n: int) -> int" in result
220
+ assert "entry:" in result
221
+ assert "t0 = 1" in result
222
+ assert "return t0" in result
223
+
224
+ def test_function_without_return_type(self) -> None:
225
+ """Test function without return type (void)."""
226
+ func = MIRFunction("print_message", [Variable("msg", MIRType.STRING)])
227
+ result = str(func)
228
+ assert "function print_message(msg: string)" in result
229
+ assert "->" not in result
230
+
231
+
232
+ class TestModuleSerialization:
233
+ """Test module serialization/deserialization."""
234
+
235
+ def test_module_to_dict(self) -> None:
236
+ """Test converting module to dictionary representation."""
237
+ module = MIRModule("test_module")
238
+
239
+ # Add constants
240
+ module.constants.add(Constant(42, MIRType.INT))
241
+ module.constants.add(Constant("hello", MIRType.STRING))
242
+
243
+ # Add global
244
+ module.add_global(Variable("count", MIRType.INT))
245
+
246
+ # Add function
247
+ func = MIRFunction("main", return_type=MIRType.INT)
248
+ entry = BasicBlock("entry")
249
+ t0 = Temp(MIRType.INT, temp_id=0)
250
+ entry.add_instruction(LoadConst(t0, 0, (1, 1)))
251
+ entry.add_instruction(Return((1, 1), t0))
252
+ func.cfg.add_block(entry)
253
+ func.cfg.set_entry_block(entry)
254
+ module.add_function(func)
255
+ module.set_main_function("main")
256
+
257
+ # Convert to dict
258
+ module_dict: dict[str, Any] = {
259
+ "name": module.name,
260
+ "main_function": module.main_function,
261
+ "constants": [{"value": c.value, "type": str(c.type)} for c in module.constants.constants],
262
+ "globals": {name: str(var.type) for name, var in module.globals.items()},
263
+ "functions": list(module.functions.keys()),
264
+ }
265
+
266
+ assert module_dict["name"] == "test_module"
267
+ assert module_dict["main_function"] == "main"
268
+ constants = module_dict["constants"]
269
+ assert isinstance(constants, list)
270
+ assert len(constants) == 2
271
+ assert constants[0]["value"] == 42
272
+ globals_dict = module_dict["globals"]
273
+ assert isinstance(globals_dict, dict)
274
+ assert globals_dict["count"] == "int"
275
+ functions = module_dict["functions"]
276
+ assert isinstance(functions, list)
277
+ assert "main" in functions
278
+
279
+ def test_module_from_dict(self) -> None:
280
+ """Test reconstructing module from dictionary representation."""
281
+ module_data: dict[str, Any] = {
282
+ "name": "restored_module",
283
+ "main_function": "start",
284
+ "globals": {
285
+ "version": "string",
286
+ "debug": "bool",
287
+ },
288
+ }
289
+
290
+ # Reconstruct module
291
+ module_name: str = module_data["name"]
292
+ module = MIRModule(module_name)
293
+
294
+ globals_dict: dict[str, str] = module_data["globals"]
295
+ for var_name, type_str in globals_dict.items():
296
+ # Map string to MIRType
297
+ type_map = {
298
+ "int": MIRType.INT,
299
+ "float": MIRType.FLOAT,
300
+ "string": MIRType.STRING,
301
+ "bool": MIRType.BOOL,
302
+ }
303
+ mir_type = type_map[type_str]
304
+ module.add_global(Variable(var_name, mir_type))
305
+
306
+ main_func: str | None = module_data.get("main_function")
307
+ if main_func:
308
+ module.set_main_function(main_func)
309
+
310
+ # Verify reconstruction
311
+ assert module.name == "restored_module"
312
+ assert module.main_function == "start"
313
+ assert len(module.globals) == 2
314
+ version_var = module.get_global("version")
315
+ debug_var = module.get_global("debug")
316
+ assert version_var is not None
317
+ assert debug_var is not None
318
+ assert version_var is not None # Type guard for mypy
319
+ assert debug_var is not None # Type guard for mypy
320
+ assert version_var.type == MIRType.STRING
321
+ assert debug_var.type == MIRType.BOOL
322
+
323
+ def test_module_json_roundtrip(self) -> None:
324
+ """Test serializing module to JSON and back."""
325
+ # Create module
326
+ module = MIRModule("json_test")
327
+ module.constants.add(Constant(100, MIRType.INT))
328
+ module.constants.add(Constant(3.14, MIRType.FLOAT))
329
+ module.add_global(Variable("MAX", MIRType.INT))
330
+
331
+ # Serialize to JSON-compatible dict
332
+ module_dict = {
333
+ "name": module.name,
334
+ "constants_count": module.constants.size(),
335
+ "globals_count": len(module.globals),
336
+ "functions_count": len(module.functions),
337
+ }
338
+
339
+ # Convert to JSON and back
340
+ json_str = json.dumps(module_dict)
341
+ restored_dict = json.loads(json_str)
342
+
343
+ # Verify
344
+ assert restored_dict["name"] == "json_test"
345
+ assert restored_dict["constants_count"] == 2
346
+ assert restored_dict["globals_count"] == 1
347
+ assert restored_dict["functions_count"] == 0
348
+
349
+
350
+ class TestMIRModule:
351
+ """Test MIR module functionality."""
352
+
353
+ def test_module_creation(self) -> None:
354
+ """Test creating MIR module."""
355
+ module = MIRModule("test_module")
356
+ assert module.name == "test_module"
357
+ assert module.functions == {}
358
+ assert module.globals == {}
359
+ assert module.constants is not None
360
+ assert module.main_function is None
361
+
362
+ def test_add_function(self) -> None:
363
+ """Test adding functions to module."""
364
+ module = MIRModule("app")
365
+ func1 = MIRFunction("main", return_type=MIRType.INT)
366
+ func2 = MIRFunction("helper")
367
+
368
+ module.add_function(func1)
369
+ module.add_function(func2)
370
+
371
+ assert len(module.functions) == 2
372
+ assert "main" in module.functions
373
+ assert "helper" in module.functions
374
+
375
+ def test_get_function(self) -> None:
376
+ """Test getting functions from module."""
377
+ module = MIRModule("app")
378
+ func = MIRFunction("compute", return_type=MIRType.FLOAT)
379
+ module.add_function(func)
380
+
381
+ retrieved = module.get_function("compute")
382
+ assert retrieved == func
383
+
384
+ none_func = module.get_function("nonexistent")
385
+ assert none_func is None
386
+
387
+ def test_function_overwrite(self) -> None:
388
+ """Test that adding a function with same name overwrites the previous one."""
389
+ module = MIRModule("app")
390
+
391
+ func1 = MIRFunction("process", return_type=MIRType.INT)
392
+ func2 = MIRFunction("process", return_type=MIRType.STRING) # Same name, different signature
393
+
394
+ module.add_function(func1)
395
+ assert module.get_function("process") == func1
396
+
397
+ module.add_function(func2) # Should overwrite
398
+ retrieved_func = module.get_function("process")
399
+ assert retrieved_func == func2
400
+ assert retrieved_func is not None
401
+ assert retrieved_func is not None # Type guard for mypy
402
+ assert retrieved_func.return_type == MIRType.STRING
403
+ assert len(module.functions) == 1
404
+
405
+ def test_multiple_functions(self) -> None:
406
+ """Test managing multiple functions."""
407
+ module = MIRModule("app")
408
+
409
+ functions = [
410
+ MIRFunction("init"),
411
+ MIRFunction("compute", [Variable("x", MIRType.FLOAT)], MIRType.FLOAT),
412
+ MIRFunction("validate", [Variable("s", MIRType.STRING)], MIRType.BOOL),
413
+ MIRFunction("main", return_type=MIRType.INT),
414
+ MIRFunction("cleanup"),
415
+ ]
416
+
417
+ for func in functions:
418
+ module.add_function(func)
419
+
420
+ assert len(module.functions) == 5
421
+
422
+ # Verify each function
423
+ for func in functions:
424
+ retrieved = module.get_function(func.name)
425
+ assert retrieved == func
426
+ assert retrieved is not None
427
+ assert retrieved is not None # Type guard for mypy
428
+ assert retrieved.return_type == func.return_type
429
+
430
+ def test_function_lookup_case_sensitive(self) -> None:
431
+ """Test that function lookup is case-sensitive."""
432
+ module = MIRModule("app")
433
+
434
+ func_lower = MIRFunction("process")
435
+ func_upper = MIRFunction("PROCESS")
436
+ func_mixed = MIRFunction("Process")
437
+
438
+ module.add_function(func_lower)
439
+ module.add_function(func_upper)
440
+ module.add_function(func_mixed)
441
+
442
+ assert len(module.functions) == 3
443
+ assert module.get_function("process") == func_lower
444
+ assert module.get_function("PROCESS") == func_upper
445
+ assert module.get_function("Process") == func_mixed
446
+ assert module.get_function("pRoCeSs") is None
447
+
448
+ def test_add_global_variable(self) -> None:
449
+ """Test adding global variables."""
450
+ module = MIRModule("app")
451
+ v1 = Variable("global_count", MIRType.INT)
452
+ v2 = Variable("pi", MIRType.FLOAT)
453
+
454
+ module.add_global(v1)
455
+ module.add_global(v2)
456
+
457
+ assert len(module.globals) == 2
458
+ assert "global_count" in module.globals
459
+ assert "pi" in module.globals
460
+
461
+ def test_get_global_variable(self) -> None:
462
+ """Test getting global variables."""
463
+ module = MIRModule("app")
464
+ v = Variable("config", MIRType.STRING)
465
+ module.add_global(v)
466
+
467
+ retrieved = module.get_global("config")
468
+ assert retrieved == v
469
+
470
+ none_var = module.get_global("nonexistent")
471
+ assert none_var is None
472
+
473
+ def test_global_variable_overwrite(self) -> None:
474
+ """Test that adding a global with same name overwrites the previous one."""
475
+ module = MIRModule("app")
476
+
477
+ v1 = Variable("config", MIRType.STRING)
478
+ v2 = Variable("config", MIRType.INT) # Same name, different type
479
+
480
+ module.add_global(v1)
481
+ assert module.get_global("config") == v1
482
+
483
+ module.add_global(v2) # Should overwrite
484
+ retrieved_var = module.get_global("config")
485
+ assert retrieved_var == v2
486
+ assert retrieved_var is not None
487
+ assert retrieved_var is not None # Type guard for mypy
488
+ assert retrieved_var.type == MIRType.INT
489
+ assert len(module.globals) == 1
490
+
491
+ def test_multiple_global_variables(self) -> None:
492
+ """Test managing multiple global variables."""
493
+ module = MIRModule("app")
494
+
495
+ globals_to_add = [
496
+ Variable("MAX_SIZE", MIRType.INT),
497
+ Variable("VERSION", MIRType.STRING),
498
+ Variable("DEBUG", MIRType.BOOL),
499
+ Variable("EPSILON", MIRType.FLOAT),
500
+ ]
501
+
502
+ for var in globals_to_add:
503
+ module.add_global(var)
504
+
505
+ assert len(module.globals) == 4
506
+
507
+ # Verify each global
508
+ for var in globals_to_add:
509
+ retrieved = module.get_global(var.name)
510
+ assert retrieved == var
511
+ assert retrieved is not None
512
+ assert retrieved is not None # Type guard for mypy
513
+ assert retrieved.type == var.type
514
+
515
+ def test_main_function_handling(self) -> None:
516
+ """Test main function setting and retrieval."""
517
+ module = MIRModule("app")
518
+ main_func = MIRFunction("main", return_type=MIRType.INT)
519
+ module.add_function(main_func)
520
+
521
+ # No main function by default
522
+ assert module.main_function is None
523
+ retrieved = module.get_main_function()
524
+ assert retrieved is None
525
+
526
+ # Set main function
527
+ module.set_main_function("main")
528
+ assert module.main_function == "main"
529
+ retrieved = module.get_main_function()
530
+ assert retrieved == main_func
531
+
532
+ # Change main function name
533
+ module.set_main_function("start")
534
+ assert module.main_function == "start"
535
+
536
+ # Main function not found
537
+ retrieved = module.get_main_function()
538
+ assert retrieved is None
539
+
540
+ # Add new main
541
+ start_func = MIRFunction("start")
542
+ module.add_function(start_func)
543
+ retrieved = module.get_main_function()
544
+ assert retrieved == start_func
545
+
546
+ def test_main_function_validation_scenarios(self) -> None:
547
+ """Test various main function validation scenarios."""
548
+ module = MIRModule("app")
549
+
550
+ # Scenario 1: Set main to non-existent function
551
+ module.set_main_function("nonexistent_main")
552
+ errors = module.validate()
553
+ assert any("Main function 'nonexistent_main' not found" in err for err in errors)
554
+
555
+ # Scenario 2: Add the main function after setting
556
+ main_func = MIRFunction("nonexistent_main", return_type=MIRType.INT)
557
+ entry = BasicBlock("entry")
558
+ t0 = Temp(MIRType.INT, temp_id=0)
559
+ entry.add_instruction(LoadConst(t0, 0, (1, 1)))
560
+ entry.add_instruction(Return((1, 1), t0))
561
+ main_func.cfg.add_block(entry)
562
+ main_func.cfg.set_entry_block(entry)
563
+ module.add_function(main_func)
564
+
565
+ errors = module.validate()
566
+ assert errors == [] # Should now be valid
567
+
568
+ # Scenario 3: Change main to another function
569
+ other_func = MIRFunction("other")
570
+ other_entry = BasicBlock("entry")
571
+ t1 = Temp(MIRType.INT, temp_id=1)
572
+ other_entry.add_instruction(LoadConst(t1, 0, (1, 1)))
573
+ other_entry.add_instruction(Return((1, 1), t1))
574
+ other_func.cfg.add_block(other_entry)
575
+ other_func.cfg.set_entry_block(other_entry)
576
+ module.add_function(other_func)
577
+
578
+ module.set_main_function("other")
579
+ assert module.get_main_function() == other_func
580
+ errors = module.validate()
581
+ assert errors == []
582
+
583
+ def test_main_function_with_empty_name(self) -> None:
584
+ """Test setting main function with empty name."""
585
+ module = MIRModule("app")
586
+
587
+ # Setting empty string as main function
588
+ module.set_main_function("")
589
+ assert module.main_function == ""
590
+ assert module.get_main_function() is None
591
+
592
+ # Validation passes because empty string is falsy and won't trigger the check
593
+ errors = module.validate()
594
+ assert errors == []
595
+
596
+ def test_main_function_clear(self) -> None:
597
+ """Test clearing main function."""
598
+ module = MIRModule("app")
599
+
600
+ # Add and set main function
601
+ main_func = MIRFunction("main", return_type=MIRType.INT)
602
+ entry = BasicBlock("entry")
603
+ entry.add_instruction(Return((1, 1), Temp(MIRType.INT, temp_id=0)))
604
+ main_func.cfg.add_block(entry)
605
+ main_func.cfg.set_entry_block(entry)
606
+ module.add_function(main_func)
607
+ module.set_main_function("main")
608
+
609
+ assert module.get_main_function() == main_func
610
+
611
+ # Clear main function by setting to None
612
+ module.main_function = None
613
+ assert module.main_function is None
614
+ assert module.get_main_function() is None
615
+
616
+ # Module should still validate without main function
617
+ errors = module.validate()
618
+ assert errors == []
619
+
620
+ def test_module_validation_success(self) -> None:
621
+ """Test successful module validation."""
622
+ module = MIRModule("app")
623
+
624
+ # Create a valid function with proper CFG
625
+ main = MIRFunction("main", return_type=MIRType.INT)
626
+ entry = BasicBlock("entry")
627
+ t0 = Temp(MIRType.INT, temp_id=0)
628
+ entry.add_instruction(LoadConst(t0, 0, (1, 1)))
629
+ entry.add_instruction(Return((1, 1), t0))
630
+
631
+ main.cfg.add_block(entry)
632
+ main.cfg.set_entry_block(entry)
633
+ module.add_function(main)
634
+
635
+ errors = module.validate()
636
+ assert errors == []
637
+
638
+ def test_module_validation_missing_main(self) -> None:
639
+ """Test validation with missing main function."""
640
+ module = MIRModule("app")
641
+ module.main_function = "main" # Main is expected but not present
642
+
643
+ errors = module.validate()
644
+ assert len(errors) == 1
645
+ assert "Main function 'main' not found" in errors[0]
646
+
647
+ def test_module_validation_missing_entry_block(self) -> None:
648
+ """Test validation with function missing entry block."""
649
+ module = MIRModule("app")
650
+ func = MIRFunction("broken")
651
+ # Don't set entry block
652
+ module.add_function(func)
653
+
654
+ errors = module.validate()
655
+ assert len(errors) == 1
656
+ assert "Function 'broken' has no entry block" in errors[0]
657
+
658
+ def test_module_validation_unterminated_block(self) -> None:
659
+ """Test validation with unterminated block."""
660
+ module = MIRModule("app")
661
+ func = MIRFunction("incomplete")
662
+
663
+ entry = BasicBlock("entry")
664
+ bb1 = BasicBlock("bb1")
665
+ t0 = Temp(MIRType.INT, temp_id=0)
666
+
667
+ # Entry has terminator
668
+ entry.add_instruction(Jump("bb1", (1, 1)))
669
+
670
+ # bb1 has instructions but no terminator
671
+ bb1.add_instruction(LoadConst(t0, 42, (1, 1)))
672
+
673
+ func.cfg.add_block(entry)
674
+ func.cfg.add_block(bb1)
675
+ func.cfg.set_entry_block(entry)
676
+ module.add_function(func)
677
+
678
+ errors = module.validate()
679
+ assert len(errors) == 1
680
+ assert "Block 'bb1' in function 'incomplete' is not terminated" in errors[0]
681
+
682
+ def test_module_validation_invalid_jump_target(self) -> None:
683
+ """Test validation with jump to undefined label."""
684
+ module = MIRModule("app")
685
+ func = MIRFunction("bad_jump")
686
+
687
+ entry = BasicBlock("entry")
688
+ entry.add_instruction(Jump("nonexistent", (1, 1)))
689
+
690
+ func.cfg.add_block(entry)
691
+ func.cfg.set_entry_block(entry)
692
+ module.add_function(func)
693
+
694
+ errors = module.validate()
695
+ assert "Jump to undefined label 'nonexistent' in function 'bad_jump'" in errors[0]
696
+
697
+ def test_module_validation_invalid_conditional_jump(self) -> None:
698
+ """Test validation with conditional jump to undefined labels."""
699
+ module = MIRModule("app")
700
+ func = MIRFunction("bad_cjump")
701
+
702
+ entry = BasicBlock("entry")
703
+ t0 = Temp(MIRType.BOOL, temp_id=0)
704
+ entry.add_instruction(ConditionalJump(t0, "undefined1", (1, 1), "undefined2"))
705
+
706
+ func.cfg.add_block(entry)
707
+ func.cfg.set_entry_block(entry)
708
+ module.add_function(func)
709
+
710
+ errors = module.validate()
711
+ # Should have errors for both undefined labels
712
+ assert any("undefined1" in err for err in errors)
713
+ assert any("undefined2" in err for err in errors)
714
+
715
+ def test_module_string_representation(self) -> None:
716
+ """Test string representation of module."""
717
+ module = MIRModule("example")
718
+
719
+ # Add constants
720
+ module.constants.add(Constant(42))
721
+ module.constants.add(Constant("hello"))
722
+
723
+ # Add global
724
+ module.add_global(Variable("count", MIRType.INT))
725
+
726
+ # Add function
727
+ func = MIRFunction("main", return_type=MIRType.INT)
728
+ entry = BasicBlock("entry")
729
+ t0 = Temp(MIRType.INT, temp_id=0)
730
+ entry.add_instruction(LoadConst(t0, 0, (1, 1)))
731
+ entry.add_instruction(Return((1, 1), t0))
732
+ func.cfg.add_block(entry)
733
+ func.cfg.set_entry_block(entry)
734
+ module.add_function(func)
735
+
736
+ result = module.to_string()
737
+
738
+ assert "module example {" in result
739
+ assert "Constants:" in result
740
+ assert "[0] 42" in result
741
+ assert "globals:" in result
742
+ assert "count: int" in result
743
+ assert "functions:" in result
744
+ assert "function main()" in result
745
+
746
+ def test_module_string_representation_options(self) -> None:
747
+ """Test module string representation with options."""
748
+ module = MIRModule("test")
749
+ module.constants.add(Constant(100))
750
+ module.add_global(Variable("var", MIRType.STRING))
751
+
752
+ # Without constants
753
+ result = module.to_string(include_constants=False)
754
+ assert "Constants:" not in result
755
+
756
+ # Without globals
757
+ result = module.to_string(include_globals=False)
758
+ assert "globals:" not in result
759
+
760
+ # With both
761
+ result = module.to_string(include_constants=True, include_globals=True)
762
+ assert "Constants:" in result
763
+ assert "globals:" in result
764
+
765
+ def test_module_repr(self) -> None:
766
+ """Test module __repr__ method."""
767
+ module = MIRModule("debug_module")
768
+
769
+ # Empty module
770
+ repr_str = repr(module)
771
+ assert "MIRModule(debug_module" in repr_str
772
+ assert "functions=0" in repr_str
773
+ assert "globals=0" in repr_str
774
+
775
+ # Add functions and globals
776
+ module.add_function(MIRFunction("func1"))
777
+ module.add_function(MIRFunction("func2"))
778
+ module.add_global(Variable("var1", MIRType.INT))
779
+
780
+ repr_str = repr(module)
781
+ assert "functions=2" in repr_str
782
+ assert "globals=1" in repr_str
783
+
784
+ def test_empty_module_validation(self) -> None:
785
+ """Test validation of completely empty module."""
786
+ module = MIRModule("empty")
787
+ errors = module.validate()
788
+ assert errors == [] # Empty module should be valid
789
+
790
+ def test_constant_pool_boundary_cases(self) -> None:
791
+ """Test constant pool with boundary cases."""
792
+ pool = ConstantPool()
793
+
794
+ # Test negative index
795
+ assert pool.get(-1) is None
796
+
797
+ # Test very large index
798
+ assert pool.get(999999) is None
799
+
800
+ # Test empty pool size
801
+ assert pool.size() == 0
802
+
803
+ # Test adding and getting at boundary
804
+ c = Constant(42, MIRType.INT)
805
+ idx = pool.add(c)
806
+ assert idx == 0
807
+ assert pool.get(0) is not None
808
+ assert pool.get(1) is None
809
+
810
+
811
+ class TestIntegration:
812
+ """Test integration of module, functions, and CFG."""
813
+
814
+ def test_complete_module_example(self) -> None:
815
+ """Test creating a complete module with multiple functions."""
816
+ module = MIRModule("calculator")
817
+
818
+ # Add global variable
819
+ pi = Variable("pi", MIRType.FLOAT)
820
+ module.add_global(pi)
821
+
822
+ # Create add function
823
+ add_func = MIRFunction(
824
+ "add",
825
+ [Variable("a", MIRType.INT), Variable("b", MIRType.INT)],
826
+ MIRType.INT,
827
+ )
828
+ add_entry = BasicBlock("entry")
829
+ t0 = Temp(MIRType.INT, temp_id=0)
830
+ t1 = Temp(MIRType.INT, temp_id=1)
831
+ t2 = Temp(MIRType.INT, temp_id=2)
832
+ add_entry.add_instruction(LoadVar(t0, Variable("a", MIRType.INT), (1, 1)))
833
+ add_entry.add_instruction(LoadVar(t1, Variable("b", MIRType.INT), (1, 1)))
834
+ add_entry.add_instruction(BinaryOp(t2, "+", t0, t1, (1, 1)))
835
+ add_entry.add_instruction(Return((1, 1), t2))
836
+ add_func.cfg.add_block(add_entry)
837
+ add_func.cfg.set_entry_block(add_entry)
838
+
839
+ # Create main function
840
+ main_func = MIRFunction("main", return_type=MIRType.INT)
841
+ main_entry = BasicBlock("entry")
842
+ t3 = Temp(MIRType.INT, temp_id=3)
843
+ main_entry.add_instruction(LoadConst(t3, Constant(0, MIRType.INT), (1, 1)))
844
+ main_entry.add_instruction(Return((1, 1), t3))
845
+ main_func.cfg.add_block(main_entry)
846
+ main_func.cfg.set_entry_block(main_entry)
847
+
848
+ # Add functions to module
849
+ module.add_function(add_func)
850
+ module.add_function(main_func)
851
+
852
+ # Validate should pass
853
+ errors = module.validate()
854
+ assert errors == []
855
+
856
+ # Check string representation
857
+ result = str(module)
858
+ assert "module calculator" in result
859
+ assert "function add(a: int, b: int) -> int" in result
860
+ assert "function main() -> int" in result