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,378 @@
1
+ """Tests for MIR validation and verification."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from machine_dialect.mir.basic_block import BasicBlock
6
+ from machine_dialect.mir.mir_function import MIRFunction
7
+ from machine_dialect.mir.mir_instructions import (
8
+ BinaryOp,
9
+ Call,
10
+ ConditionalJump,
11
+ Jump,
12
+ LoadConst,
13
+ Phi,
14
+ Return,
15
+ )
16
+ from machine_dialect.mir.mir_module import MIRModule
17
+ from machine_dialect.mir.mir_types import MIRType
18
+ from machine_dialect.mir.mir_validation import MIRValidator, validate_function, validate_module
19
+ from machine_dialect.mir.mir_values import Constant, FunctionRef, Variable
20
+
21
+
22
+ class TestMIRValidation:
23
+ """Test MIR validation and verification."""
24
+
25
+ def setup_method(self) -> None:
26
+ """Set up test fixtures."""
27
+ self.validator = MIRValidator()
28
+
29
+ def test_valid_module(self) -> None:
30
+ """Test validation of a valid module."""
31
+ # Create valid module
32
+ module = MIRModule("test_module")
33
+
34
+ # Add main function
35
+ main_func = MIRFunction("main", [], MIRType.EMPTY)
36
+ entry = BasicBlock("entry")
37
+ main_func.cfg.add_block(entry)
38
+ main_func.cfg.entry_block = entry
39
+ entry.add_instruction(Return((1, 1)))
40
+
41
+ module.add_function(main_func)
42
+ module.set_main_function("main")
43
+
44
+ # Should validate successfully
45
+ success, errors, _warnings = validate_module(module)
46
+ assert success
47
+ assert len(errors) == 0
48
+
49
+ def test_module_without_name(self) -> None:
50
+ """Test validation fails for module without name."""
51
+ module = MIRModule("")
52
+
53
+ success, errors, _warnings = validate_module(module)
54
+ assert not success
55
+ assert any("name" in error.lower() for error in errors)
56
+
57
+ def test_module_with_invalid_main(self) -> None:
58
+ """Test validation fails when main function doesn't exist."""
59
+ module = MIRModule("test")
60
+ module.set_main_function("nonexistent")
61
+
62
+ success, errors, _warnings = validate_module(module)
63
+ assert not success
64
+ assert any("main" in error.lower() and "not found" in error.lower() for error in errors)
65
+
66
+ def test_function_name_mismatch(self) -> None:
67
+ """Test validation fails when function name doesn't match."""
68
+ func = MIRFunction("foo", [], MIRType.EMPTY)
69
+ # Set up minimal valid CFG
70
+ from machine_dialect.mir.basic_block import BasicBlock
71
+
72
+ entry = BasicBlock("entry")
73
+ from machine_dialect.mir.mir_instructions import Return
74
+
75
+ entry.add_instruction(Return((1, 1)))
76
+ func.cfg.entry_block = entry
77
+ func.cfg.add_block(entry)
78
+
79
+ # Validate with different name
80
+ success, errors, _warnings = validate_function(func)
81
+ assert success # Should pass when validating directly
82
+
83
+ # But fail when in module with wrong name
84
+ module = MIRModule("test")
85
+ module.functions["bar"] = func # Wrong name in dict
86
+
87
+ success, errors, _warnings = validate_module(module)
88
+ assert not success
89
+ assert any("mismatch" in error.lower() for error in errors)
90
+
91
+ def test_duplicate_parameters(self) -> None:
92
+ """Test validation fails with duplicate parameter names."""
93
+ # Create function with duplicate parameters
94
+ param1 = Variable("x", MIRType.INT)
95
+ param2 = Variable("x", MIRType.INT) # Duplicate name
96
+
97
+ func = MIRFunction("test", [param1, param2], MIRType.EMPTY)
98
+
99
+ success, errors, _warnings = validate_function(func)
100
+ assert not success
101
+ assert any("duplicate" in error.lower() for error in errors)
102
+
103
+ def test_cfg_without_entry(self) -> None:
104
+ """Test validation fails when CFG has no entry block."""
105
+ func = MIRFunction("test", [], MIRType.EMPTY)
106
+ # Don't set entry block
107
+
108
+ success, errors, _warnings = validate_function(func)
109
+ assert not success
110
+ assert any("entry" in error.lower() for error in errors)
111
+
112
+ def test_inconsistent_cfg_edges(self) -> None:
113
+ """Test validation fails with inconsistent CFG edges."""
114
+ func = MIRFunction("test", [], MIRType.EMPTY)
115
+
116
+ block1 = BasicBlock("block1")
117
+ block2 = BasicBlock("block2")
118
+
119
+ func.cfg.add_block(block1)
120
+ func.cfg.add_block(block2)
121
+ func.cfg.entry_block = block1
122
+
123
+ # Create inconsistent edge (only one direction)
124
+ block1.successors.append(block2)
125
+ # Don't add block1 to block2's predecessors
126
+
127
+ success, errors, _warnings = validate_function(func)
128
+ assert not success
129
+ assert any("inconsistent" in error.lower() for error in errors)
130
+
131
+ def test_unreachable_blocks_warning(self) -> None:
132
+ """Test validation warns about unreachable blocks."""
133
+ func = MIRFunction("test", [], MIRType.EMPTY)
134
+
135
+ entry = BasicBlock("entry")
136
+ unreachable = BasicBlock("unreachable")
137
+
138
+ func.cfg.add_block(entry)
139
+ func.cfg.add_block(unreachable)
140
+ func.cfg.entry_block = entry
141
+
142
+ entry.add_instruction(Return((1, 1)))
143
+
144
+ success, _errors, warnings = validate_function(func)
145
+ assert success # Should still pass
146
+ assert any("unreachable" in warning.lower() for warning in warnings)
147
+
148
+ def test_invalid_binary_operator(self) -> None:
149
+ """Test validation fails with invalid binary operator."""
150
+ func = MIRFunction("test", [], MIRType.EMPTY)
151
+
152
+ entry = BasicBlock("entry")
153
+ func.cfg.add_block(entry)
154
+ func.cfg.entry_block = entry
155
+
156
+ # Create binary op with invalid operator
157
+ t1 = func.new_temp(MIRType.INT)
158
+ t2 = func.new_temp(MIRType.INT)
159
+ result = func.new_temp(MIRType.INT)
160
+
161
+ entry.add_instruction(BinaryOp(result, "invalid_op", t1, t2, (1, 1)))
162
+ entry.add_instruction(Return((1, 1)))
163
+
164
+ success, errors, _warnings = validate_function(func)
165
+ assert not success
166
+ assert any("invalid" in error.lower() and "operator" in error.lower() for error in errors)
167
+
168
+ def test_jump_to_nonexistent_block(self) -> None:
169
+ """Test validation fails with jump to nonexistent block."""
170
+ func = MIRFunction("test", [], MIRType.EMPTY)
171
+
172
+ entry = BasicBlock("entry")
173
+ func.cfg.add_block(entry)
174
+ func.cfg.entry_block = entry
175
+
176
+ # Jump to block that doesn't exist
177
+ entry.add_instruction(Jump("nonexistent", (1, 1)))
178
+
179
+ success, errors, _warnings = validate_function(func)
180
+ assert not success
181
+ assert any("not found" in error.lower() for error in errors)
182
+
183
+ def test_conditional_jump_validation(self) -> None:
184
+ """Test validation of conditional jumps."""
185
+ func = MIRFunction("test", [], MIRType.EMPTY)
186
+
187
+ entry = BasicBlock("entry")
188
+ then_block = BasicBlock("then")
189
+
190
+ func.cfg.add_block(entry)
191
+ func.cfg.add_block(then_block)
192
+ func.cfg.entry_block = entry
193
+
194
+ cond = func.new_temp(MIRType.BOOL)
195
+
196
+ # Invalid: false_label doesn't exist
197
+ entry.add_instruction(ConditionalJump(cond, "then", (1, 1), "nonexistent"))
198
+
199
+ success, errors, _warnings = validate_function(func)
200
+ assert not success
201
+ assert any("not found" in error.lower() for error in errors)
202
+
203
+ def test_phi_node_validation(self) -> None:
204
+ """Test validation of phi nodes."""
205
+ func = MIRFunction("test", [], MIRType.EMPTY)
206
+
207
+ # Create diamond CFG
208
+ entry = BasicBlock("entry")
209
+ then_block = BasicBlock("then")
210
+ else_block = BasicBlock("else")
211
+ merge = BasicBlock("merge")
212
+
213
+ func.cfg.add_block(entry)
214
+ func.cfg.add_block(then_block)
215
+ func.cfg.add_block(else_block)
216
+ func.cfg.add_block(merge)
217
+ func.cfg.entry_block = entry
218
+
219
+ func.cfg.connect(entry, then_block)
220
+ func.cfg.connect(entry, else_block)
221
+ func.cfg.connect(then_block, merge)
222
+ func.cfg.connect(else_block, merge)
223
+
224
+ # Add terminators
225
+ cond = func.new_temp(MIRType.BOOL)
226
+ entry.add_instruction(ConditionalJump(cond, "then", (1, 1), "else"))
227
+ then_block.add_instruction(Jump("merge", (1, 1)))
228
+ else_block.add_instruction(Jump("merge", (1, 1)))
229
+
230
+ # Add phi with wrong predecessor
231
+ result = func.new_temp(MIRType.INT)
232
+ val1 = Constant(1, MIRType.INT)
233
+ val2 = Constant(2, MIRType.INT)
234
+
235
+ # Invalid: "wrong_block" is not a predecessor
236
+ phi = Phi(result, [(val1, "then"), (val2, "wrong_block")], (1, 1))
237
+ merge.add_instruction(phi)
238
+ merge.add_instruction(Return((1, 1)))
239
+
240
+ success, errors, _warnings = validate_function(func)
241
+ assert not success
242
+ assert any("not a predecessor" in error.lower() for error in errors)
243
+
244
+ def test_phi_missing_predecessor_warning(self) -> None:
245
+ """Test warning for phi node missing predecessor."""
246
+ func = MIRFunction("test", [], MIRType.EMPTY)
247
+
248
+ # Create diamond CFG
249
+ entry = BasicBlock("entry")
250
+ then_block = BasicBlock("then")
251
+ else_block = BasicBlock("else")
252
+ merge = BasicBlock("merge")
253
+
254
+ func.cfg.add_block(entry)
255
+ func.cfg.add_block(then_block)
256
+ func.cfg.add_block(else_block)
257
+ func.cfg.add_block(merge)
258
+ func.cfg.entry_block = entry
259
+
260
+ func.cfg.connect(entry, then_block)
261
+ func.cfg.connect(entry, else_block)
262
+ func.cfg.connect(then_block, merge)
263
+ func.cfg.connect(else_block, merge)
264
+
265
+ # Add terminators
266
+ cond = func.new_temp(MIRType.BOOL)
267
+ entry.add_instruction(ConditionalJump(cond, "then", (1, 1), "else"))
268
+ then_block.add_instruction(Jump("merge", (1, 1)))
269
+ else_block.add_instruction(Jump("merge", (1, 1)))
270
+
271
+ # Phi missing value from "else"
272
+ result = func.new_temp(MIRType.INT)
273
+ val1 = Constant(1, MIRType.INT)
274
+ phi = Phi(result, [(val1, "then")], (1, 1)) # Missing "else"
275
+ merge.add_instruction(phi)
276
+ merge.add_instruction(Return((1, 1)))
277
+
278
+ success, _errors, warnings = validate_function(func)
279
+ assert success # Should pass with warning
280
+ assert any("missing" in warning.lower() for warning in warnings)
281
+
282
+ def test_return_type_mismatch_warning(self) -> None:
283
+ """Test warning for return type mismatch."""
284
+ # Function that returns EMPTY but has return with value
285
+ func = MIRFunction("test", [], MIRType.EMPTY)
286
+
287
+ entry = BasicBlock("entry")
288
+ func.cfg.add_block(entry)
289
+ func.cfg.entry_block = entry
290
+
291
+ val = func.new_temp(MIRType.INT)
292
+ entry.add_instruction(Return((1, 1), val))
293
+
294
+ success, _errors, warnings = validate_function(func)
295
+ assert success # Should pass with warning
296
+ assert any("return" in warning.lower() for warning in warnings)
297
+
298
+ def test_block_with_successors_but_no_terminator(self) -> None:
299
+ """Test warning for block with successors but no terminator."""
300
+ func = MIRFunction("test", [], MIRType.EMPTY)
301
+
302
+ block1 = BasicBlock("block1")
303
+ block2 = BasicBlock("block2")
304
+
305
+ func.cfg.add_block(block1)
306
+ func.cfg.add_block(block2)
307
+ func.cfg.entry_block = block1
308
+ func.cfg.connect(block1, block2)
309
+
310
+ # block1 has successor but no jump instruction
311
+ t = func.new_temp(MIRType.INT)
312
+ block1.add_instruction(LoadConst(t, 1, (1, 1)))
313
+ # No terminator!
314
+
315
+ block2.add_instruction(Return((1, 1)))
316
+
317
+ success, _errors, warnings = validate_function(func)
318
+ assert success # Should pass with warning
319
+ assert any("terminator" in warning.lower() for warning in warnings)
320
+
321
+ def test_call_validation(self) -> None:
322
+ """Test validation of call instructions."""
323
+ func = MIRFunction("test", [], MIRType.EMPTY)
324
+
325
+ entry = BasicBlock("entry")
326
+ func.cfg.add_block(entry)
327
+ func.cfg.entry_block = entry
328
+
329
+ # Valid call
330
+ func_ref = FunctionRef("helper")
331
+ arg = func.new_temp(MIRType.INT)
332
+ result = func.new_temp(MIRType.INT)
333
+
334
+ entry.add_instruction(Call(result, func_ref, [arg], (1, 1)))
335
+ entry.add_instruction(Return((1, 1)))
336
+
337
+ success, _errors, _warnings = validate_function(func)
338
+ assert success
339
+
340
+ def test_complete_validation_integration(self) -> None:
341
+ """Test complete validation of a complex module."""
342
+ module = MIRModule("complex_module")
343
+
344
+ # Add multiple functions
345
+ main = MIRFunction("main", [], MIRType.EMPTY)
346
+ entry = BasicBlock("entry")
347
+ main.cfg.add_block(entry)
348
+ main.cfg.entry_block = entry
349
+
350
+ # Call helper function
351
+ helper_ref = FunctionRef("helper")
352
+ arg = Constant(42, MIRType.INT)
353
+ result = main.new_temp(MIRType.INT)
354
+ entry.add_instruction(Call(result, helper_ref, [arg], (1, 1)))
355
+ entry.add_instruction(Return((1, 1)))
356
+
357
+ # Add helper function
358
+ param = Variable("x", MIRType.INT)
359
+ helper = MIRFunction("helper", [param], MIRType.INT)
360
+
361
+ helper_entry = BasicBlock("entry")
362
+ helper.cfg.add_block(helper_entry)
363
+ helper.cfg.entry_block = helper_entry
364
+
365
+ # Double the parameter
366
+ doubled = helper.new_temp(MIRType.INT)
367
+ two = Constant(2, MIRType.INT)
368
+ helper_entry.add_instruction(BinaryOp(doubled, "*", param, two, (1, 1)))
369
+ helper_entry.add_instruction(Return((1, 1), doubled))
370
+
371
+ module.add_function(main)
372
+ module.add_function(helper)
373
+ module.set_main_function("main")
374
+
375
+ # Should validate successfully
376
+ success, errors, _warnings = validate_module(module)
377
+ assert success
378
+ assert len(errors) == 0
@@ -0,0 +1,168 @@
1
+ """Tests for MIR value representations."""
2
+
3
+ from machine_dialect.mir.mir_types import MIRType
4
+ from machine_dialect.mir.mir_values import Constant, FunctionRef, Temp, Variable
5
+
6
+
7
+ class TestMIRValues:
8
+ """Test MIR value types."""
9
+
10
+ def setup_method(self) -> None:
11
+ """Reset temp counter before each test."""
12
+ Temp.reset_counter()
13
+
14
+ def test_temp_creation(self) -> None:
15
+ """Test temporary value creation."""
16
+ t1 = Temp(MIRType.INT)
17
+ t2 = Temp(MIRType.FLOAT)
18
+ t3 = Temp(MIRType.STRING, temp_id=10)
19
+
20
+ assert str(t1) == "t0"
21
+ assert str(t2) == "t1"
22
+ assert str(t3) == "t10"
23
+ assert t1.type == MIRType.INT
24
+ assert t2.type == MIRType.FLOAT
25
+ assert t3.type == MIRType.STRING
26
+
27
+ def test_temp_equality_and_hash(self) -> None:
28
+ """Test temporary equality and hashing."""
29
+ t1 = Temp(MIRType.INT, temp_id=5)
30
+ t2 = Temp(MIRType.FLOAT, temp_id=5) # Same ID, different type
31
+ t3 = Temp(MIRType.INT, temp_id=6)
32
+
33
+ # Equality is based on ID only
34
+ assert t1 == t2
35
+ assert t1 != t3
36
+
37
+ # Can be used in sets/dicts
38
+ temp_set = {t1, t2, t3}
39
+ assert len(temp_set) == 2 # t1 and t2 are same
40
+
41
+ def test_temp_counter_reset(self) -> None:
42
+ """Test temporary counter reset."""
43
+ t1 = Temp(MIRType.INT)
44
+ assert t1.id == 0
45
+
46
+ Temp.reset_counter()
47
+ t2 = Temp(MIRType.INT)
48
+ assert t2.id == 0
49
+
50
+ def test_variable_creation(self) -> None:
51
+ """Test variable creation."""
52
+ v1 = Variable("x", MIRType.INT)
53
+ v2 = Variable("y", MIRType.STRING, version=1)
54
+ v3 = Variable("x", MIRType.INT, version=2)
55
+
56
+ assert str(v1) == "x"
57
+ assert str(v2) == "y.1"
58
+ assert str(v3) == "x.2"
59
+ assert v1.type == MIRType.INT
60
+ assert v2.type == MIRType.STRING
61
+
62
+ def test_variable_equality_and_hash(self) -> None:
63
+ """Test variable equality and hashing."""
64
+ v1 = Variable("x", MIRType.INT, version=1)
65
+ v2 = Variable("x", MIRType.INT, version=1)
66
+ v3 = Variable("x", MIRType.INT, version=2)
67
+ v4 = Variable("y", MIRType.INT, version=1)
68
+
69
+ assert v1 == v2
70
+ assert v1 != v3 # Different version
71
+ assert v1 != v4 # Different name
72
+
73
+ # Can be used in sets/dicts
74
+ var_set = {v1, v2, v3, v4}
75
+ assert len(var_set) == 3 # v1 and v2 are same
76
+
77
+ def test_variable_versioning(self) -> None:
78
+ """Test variable versioning for SSA."""
79
+ v1 = Variable("x", MIRType.INT, version=1)
80
+ v2 = v1.with_version(2)
81
+ v3 = v1.with_version(3)
82
+
83
+ assert v1.name == v2.name
84
+ assert v1.type == v2.type
85
+ assert v2.version == 2
86
+ assert v3.version == 3
87
+ assert str(v2) == "x.2"
88
+ assert str(v3) == "x.3"
89
+
90
+ def test_constant_creation(self) -> None:
91
+ """Test constant creation."""
92
+ c1 = Constant(42)
93
+ c2 = Constant(3.14)
94
+ c3 = Constant("hello")
95
+ c4 = Constant(True)
96
+ c5 = Constant(None)
97
+ c6 = Constant(100, MIRType.FLOAT) # Explicit type
98
+
99
+ assert str(c1) == "42"
100
+ assert str(c2) == "3.14"
101
+ assert str(c3) == '"hello"'
102
+ assert str(c4) == "True"
103
+ assert str(c5) == "null"
104
+ assert str(c6) == "100"
105
+
106
+ assert c1.type == MIRType.INT
107
+ assert c2.type == MIRType.FLOAT
108
+ assert c3.type == MIRType.STRING
109
+ assert c4.type == MIRType.BOOL
110
+ assert c5.type == MIRType.EMPTY
111
+ assert c6.type == MIRType.FLOAT
112
+
113
+ def test_constant_equality_and_hash(self) -> None:
114
+ """Test constant equality and hashing."""
115
+ c1 = Constant(42, MIRType.INT)
116
+ c2 = Constant(42, MIRType.INT)
117
+ c3 = Constant(42, MIRType.FLOAT) # Same value, different type
118
+ c4 = Constant(43, MIRType.INT)
119
+
120
+ assert c1 == c2
121
+ assert c1 != c3 # Different type
122
+ assert c1 != c4 # Different value
123
+
124
+ # Can be used in sets/dicts
125
+ const_set = {c1, c2, c3, c4}
126
+ assert len(const_set) == 3 # c1 and c2 are same
127
+
128
+ def test_function_ref_creation(self) -> None:
129
+ """Test function reference creation."""
130
+ f1 = FunctionRef("main")
131
+ f2 = FunctionRef("helper")
132
+
133
+ assert str(f1) == "@main"
134
+ assert str(f2) == "@helper"
135
+ assert f1.type == MIRType.FUNCTION
136
+ assert f1.name == "main"
137
+
138
+ def test_function_ref_equality_and_hash(self) -> None:
139
+ """Test function reference equality and hashing."""
140
+ f1 = FunctionRef("foo")
141
+ f2 = FunctionRef("foo")
142
+ f3 = FunctionRef("bar")
143
+
144
+ assert f1 == f2
145
+ assert f1 != f3
146
+
147
+ # Can be used in sets/dicts
148
+ func_set = {f1, f2, f3}
149
+ assert len(func_set) == 2 # f1 and f2 are same
150
+
151
+ def test_mixed_value_comparisons(self) -> None:
152
+ """Test that different value types are not equal."""
153
+ temp = Temp(MIRType.INT, temp_id=1)
154
+ var = Variable("t1", MIRType.INT) # Same string repr
155
+ const = Constant(1, MIRType.INT)
156
+ func = FunctionRef("t1")
157
+
158
+ # All should be different despite similar representations
159
+ assert temp != var
160
+ assert temp != const
161
+ assert temp != func
162
+ assert var != const
163
+ assert var != func
164
+ assert const != func
165
+
166
+ # All can coexist in a set
167
+ value_set = {temp, var, const, func}
168
+ assert len(value_set) == 4