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,455 @@
1
+ """MIR validation and verification framework.
2
+
3
+ This module provides validation and verification for MIR programs,
4
+ ensuring correctness and well-formedness of the intermediate representation.
5
+ """
6
+
7
+ from machine_dialect.mir.basic_block import CFG, BasicBlock
8
+ from machine_dialect.mir.mir_function import MIRFunction
9
+ from machine_dialect.mir.mir_instructions import (
10
+ BinaryOp,
11
+ Call,
12
+ ConditionalJump,
13
+ Copy,
14
+ Jump,
15
+ LoadConst,
16
+ LoadVar,
17
+ MIRInstruction,
18
+ Phi,
19
+ Return,
20
+ StoreVar,
21
+ UnaryOp,
22
+ )
23
+ from machine_dialect.mir.mir_module import MIRModule
24
+ from machine_dialect.mir.mir_types import MIRType
25
+ from machine_dialect.mir.mir_values import FunctionRef, Temp, Variable
26
+
27
+
28
+ class ValidationError(Exception):
29
+ """Exception raised for validation errors."""
30
+
31
+ pass
32
+
33
+
34
+ class MIRValidator:
35
+ """Validates MIR modules, functions, and instructions."""
36
+
37
+ def __init__(self) -> None:
38
+ """Initialize the validator."""
39
+ self.errors: list[str] = []
40
+ self.warnings: list[str] = []
41
+
42
+ def validate_module(self, module: MIRModule) -> bool:
43
+ """Validate an entire MIR module.
44
+
45
+ Args:
46
+ module: The module to validate.
47
+
48
+ Returns:
49
+ True if validation passes, False otherwise.
50
+ """
51
+ self.errors.clear()
52
+ self.warnings.clear()
53
+
54
+ # Check module structure
55
+ if not module.name:
56
+ self.errors.append("Module must have a name")
57
+
58
+ # Validate each function
59
+ for func_name, func in module.functions.items():
60
+ if not self._validate_function(func, func_name):
61
+ self.errors.append(f"Function '{func_name}' validation failed")
62
+
63
+ # Check main function if specified
64
+ if module.main_function:
65
+ if module.main_function not in module.functions:
66
+ self.errors.append(f"Main function '{module.main_function}' not found in module")
67
+
68
+ return len(self.errors) == 0
69
+
70
+ def _validate_function(self, func: MIRFunction, name: str) -> bool:
71
+ """Validate a MIR function.
72
+
73
+ Args:
74
+ func: The function to validate.
75
+ name: The function name.
76
+
77
+ Returns:
78
+ True if validation passes, False otherwise.
79
+ """
80
+ func_errors = []
81
+
82
+ # Check function name matches
83
+ if func.name != name:
84
+ func_errors.append(f"Function name mismatch: {func.name} vs {name}")
85
+
86
+ # Validate parameters
87
+ param_names = set()
88
+ for param in func.params:
89
+ if not isinstance(param, Variable):
90
+ func_errors.append(f"Parameter must be Variable, got {type(param)}")
91
+ elif param.name in param_names:
92
+ func_errors.append(f"Duplicate parameter name: {param.name}")
93
+ else:
94
+ param_names.add(param.name)
95
+
96
+ # Validate CFG
97
+ if not self._validate_cfg(func.cfg):
98
+ func_errors.append("CFG validation failed")
99
+
100
+ # Validate each block
101
+ for block_label, block in func.cfg.blocks.items():
102
+ if not self._validate_block(block, block_label, func):
103
+ func_errors.append(f"Block '{block_label}' validation failed")
104
+
105
+ # Check that all locals are defined
106
+ for local in func.locals.values():
107
+ if not isinstance(local, Variable):
108
+ func_errors.append(f"Local must be Variable, got {type(local)}")
109
+
110
+ # Check that all temporaries are valid
111
+ for temp in func.temporaries:
112
+ if not isinstance(temp, Temp):
113
+ func_errors.append(f"Temporary must be Temp, got {type(temp)}")
114
+
115
+ if func_errors:
116
+ self.errors.extend(func_errors)
117
+ return False
118
+ return True
119
+
120
+ def _validate_cfg(self, cfg: CFG) -> bool:
121
+ """Validate a control flow graph.
122
+
123
+ Args:
124
+ cfg: The CFG to validate.
125
+
126
+ Returns:
127
+ True if validation passes, False otherwise.
128
+ """
129
+ cfg_errors = []
130
+
131
+ # Check entry block exists
132
+ if cfg.entry_block is None:
133
+ cfg_errors.append("CFG must have an entry block")
134
+ elif cfg.entry_block not in cfg.blocks.values():
135
+ cfg_errors.append("Entry block not in CFG blocks")
136
+
137
+ # Check block connectivity
138
+ for block_label, block in cfg.blocks.items():
139
+ if block.label != block_label:
140
+ cfg_errors.append(f"Block label mismatch: {block.label} vs {block_label}")
141
+
142
+ # Check predecessors
143
+ for pred in block.predecessors:
144
+ if block not in pred.successors:
145
+ cfg_errors.append(f"Inconsistent CFG: {pred.label} -> {block.label} not bidirectional")
146
+
147
+ # Check successors
148
+ for succ in block.successors:
149
+ if block not in succ.predecessors:
150
+ cfg_errors.append(f"Inconsistent CFG: {block.label} -> {succ.label} not bidirectional")
151
+
152
+ # Check for unreachable blocks
153
+ if cfg.entry_block:
154
+ reachable = self._compute_reachable_blocks(cfg)
155
+ for block in cfg.blocks.values():
156
+ if block not in reachable:
157
+ self.warnings.append(f"Block '{block.label}' is unreachable")
158
+
159
+ if cfg_errors:
160
+ self.errors.extend(cfg_errors)
161
+ return False
162
+ return True
163
+
164
+ def _compute_reachable_blocks(self, cfg: CFG) -> set[BasicBlock]:
165
+ """Compute reachable blocks from entry.
166
+
167
+ Args:
168
+ cfg: The control flow graph.
169
+
170
+ Returns:
171
+ Set of reachable blocks.
172
+ """
173
+ if not cfg.entry_block:
174
+ return set()
175
+
176
+ reachable = set()
177
+ worklist = [cfg.entry_block]
178
+
179
+ while worklist:
180
+ block = worklist.pop()
181
+ if block in reachable:
182
+ continue
183
+ reachable.add(block)
184
+
185
+ # Add successors to worklist
186
+ for succ in block.successors:
187
+ if succ not in reachable:
188
+ worklist.append(succ)
189
+
190
+ return reachable
191
+
192
+ def _validate_block(self, block: BasicBlock, label: str, func: MIRFunction) -> bool:
193
+ """Validate a basic block.
194
+
195
+ Args:
196
+ block: The block to validate.
197
+ label: Expected block label.
198
+ func: The containing function.
199
+
200
+ Returns:
201
+ True if validation passes, False otherwise.
202
+ """
203
+ block_errors = []
204
+
205
+ # Check label
206
+ if block.label != label:
207
+ block_errors.append(f"Block label mismatch: {block.label} vs {label}")
208
+
209
+ # Validate instructions
210
+ for i, inst in enumerate(block.instructions):
211
+ if not self._validate_instruction(inst, block, func):
212
+ block_errors.append(f"Instruction {i} validation failed: {inst}")
213
+
214
+ # Check terminator
215
+ if block.instructions:
216
+ last_inst = block.instructions[-1]
217
+ if isinstance(last_inst, Jump | ConditionalJump | Return):
218
+ # Valid terminator
219
+ pass
220
+ else:
221
+ # Check if block has successors
222
+ if block.successors:
223
+ self.warnings.append(f"Block '{block.label}' has successors but no terminator")
224
+
225
+ # Validate phi nodes
226
+ for phi in block.phi_nodes:
227
+ if not self._validate_instruction(phi, block, func):
228
+ return False
229
+
230
+ # Check that no phi nodes are in regular instructions (they should be in phi_nodes)
231
+ for inst in block.instructions:
232
+ if isinstance(inst, Phi):
233
+ block_errors.append("Phi nodes must be in phi_nodes list, not instructions")
234
+
235
+ if block_errors:
236
+ self.errors.extend(block_errors)
237
+ return False
238
+ return True
239
+
240
+ def _validate_instruction(self, inst: MIRInstruction, block: BasicBlock, func: MIRFunction) -> bool:
241
+ """Validate a single instruction.
242
+
243
+ Args:
244
+ inst: The instruction to validate.
245
+ block: The containing block.
246
+ func: The containing function.
247
+
248
+ Returns:
249
+ True if validation passes, False otherwise.
250
+ """
251
+ # Type-specific validation
252
+ if isinstance(inst, BinaryOp):
253
+ return self._validate_binary_op(inst)
254
+ elif isinstance(inst, UnaryOp):
255
+ return self._validate_unary_op(inst)
256
+ elif isinstance(inst, Call):
257
+ return self._validate_call(inst, func)
258
+ elif isinstance(inst, Jump):
259
+ return self._validate_jump(inst, func)
260
+ elif isinstance(inst, ConditionalJump):
261
+ return self._validate_conditional_jump(inst, func)
262
+ elif isinstance(inst, Phi):
263
+ return self._validate_phi(inst, block, func)
264
+ elif isinstance(inst, Return):
265
+ return self._validate_return(inst, func)
266
+ elif isinstance(inst, Copy | LoadConst | LoadVar | StoreVar):
267
+ # These are generally valid if their operands are valid
268
+ return True
269
+ else:
270
+ # Unknown instruction type is valid (for extensibility)
271
+ return True
272
+
273
+ def _validate_binary_op(self, inst: BinaryOp) -> bool:
274
+ """Validate a binary operation.
275
+
276
+ Args:
277
+ inst: The binary operation.
278
+
279
+ Returns:
280
+ True if valid.
281
+ """
282
+ valid_ops = {
283
+ "+",
284
+ "-",
285
+ "*",
286
+ "/",
287
+ "%",
288
+ "^",
289
+ "==",
290
+ "!=",
291
+ "<",
292
+ ">",
293
+ "<=",
294
+ ">=",
295
+ "and",
296
+ "or",
297
+ }
298
+ if inst.op not in valid_ops:
299
+ self.errors.append(f"Invalid binary operator: {inst.op}")
300
+ return False
301
+ return True
302
+
303
+ def _validate_unary_op(self, inst: UnaryOp) -> bool:
304
+ """Validate a unary operation.
305
+
306
+ Args:
307
+ inst: The unary operation.
308
+
309
+ Returns:
310
+ True if valid.
311
+ """
312
+ valid_ops = {"-", "not"}
313
+ if inst.op not in valid_ops:
314
+ self.errors.append(f"Invalid unary operator: {inst.op}")
315
+ return False
316
+ return True
317
+
318
+ def _validate_call(self, inst: Call, func: MIRFunction) -> bool:
319
+ """Validate a call instruction.
320
+
321
+ Args:
322
+ inst: The call instruction.
323
+ func: The containing function.
324
+
325
+ Returns:
326
+ True if valid.
327
+ """
328
+ if not isinstance(inst.func, FunctionRef):
329
+ self.errors.append(f"Call target must be FunctionRef, got {type(inst.func)}")
330
+ return False
331
+ return True
332
+
333
+ def _validate_jump(self, inst: Jump, func: MIRFunction) -> bool:
334
+ """Validate a jump instruction.
335
+
336
+ Args:
337
+ inst: The jump instruction.
338
+ func: The containing function.
339
+
340
+ Returns:
341
+ True if valid.
342
+ """
343
+ if inst.label not in func.cfg.blocks:
344
+ self.errors.append(f"Jump target '{inst.label}' not found")
345
+ return False
346
+ return True
347
+
348
+ def _validate_conditional_jump(self, inst: ConditionalJump, func: MIRFunction) -> bool:
349
+ """Validate a conditional jump instruction.
350
+
351
+ Args:
352
+ inst: The conditional jump instruction.
353
+ func: The containing function.
354
+
355
+ Returns:
356
+ True if valid.
357
+ """
358
+ if inst.true_label not in func.cfg.blocks:
359
+ self.errors.append(f"Jump target '{inst.true_label}' not found")
360
+ return False
361
+ if inst.false_label and inst.false_label not in func.cfg.blocks:
362
+ self.errors.append(f"Jump target '{inst.false_label}' not found")
363
+ return False
364
+ return True
365
+
366
+ def _validate_phi(self, inst: Phi, block: BasicBlock, func: MIRFunction) -> bool:
367
+ """Validate a phi node.
368
+
369
+ Args:
370
+ inst: The phi node.
371
+ block: The containing block.
372
+ func: The containing function.
373
+
374
+ Returns:
375
+ True if valid.
376
+ """
377
+ # Check that incoming blocks are predecessors
378
+ incoming_labels = {label for _, label in inst.incoming}
379
+ pred_labels = {pred.label for pred in block.predecessors}
380
+
381
+ for label in incoming_labels:
382
+ if label not in pred_labels:
383
+ self.errors.append(f"Phi node has incoming from '{label}' which is not a predecessor")
384
+ return False
385
+
386
+ # Warn if missing predecessors
387
+ for pred_label in pred_labels:
388
+ if pred_label not in incoming_labels:
389
+ self.warnings.append(f"Phi node missing incoming value from predecessor '{pred_label}'")
390
+
391
+ return True
392
+
393
+ def _validate_return(self, inst: Return, func: MIRFunction) -> bool:
394
+ """Validate a return instruction.
395
+
396
+ Args:
397
+ inst: The return instruction.
398
+ func: The containing function.
399
+
400
+ Returns:
401
+ True if valid.
402
+ """
403
+ # Check return type consistency
404
+ if func.return_type == MIRType.EMPTY:
405
+ if inst.value is not None:
406
+ self.warnings.append("Function returns EMPTY but return has value")
407
+ else:
408
+ if inst.value is None:
409
+ self.warnings.append(f"Function returns {func.return_type} but return has no value")
410
+
411
+ return True
412
+
413
+ def get_errors(self) -> list[str]:
414
+ """Get validation errors.
415
+
416
+ Returns:
417
+ List of error messages.
418
+ """
419
+ return self.errors.copy()
420
+
421
+ def get_warnings(self) -> list[str]:
422
+ """Get validation warnings.
423
+
424
+ Returns:
425
+ List of warning messages.
426
+ """
427
+ return self.warnings.copy()
428
+
429
+
430
+ def validate_module(module: MIRModule) -> tuple[bool, list[str], list[str]]:
431
+ """Validate a MIR module.
432
+
433
+ Args:
434
+ module: The module to validate.
435
+
436
+ Returns:
437
+ Tuple of (success, errors, warnings).
438
+ """
439
+ validator = MIRValidator()
440
+ success = validator.validate_module(module)
441
+ return success, validator.get_errors(), validator.get_warnings()
442
+
443
+
444
+ def validate_function(func: MIRFunction) -> tuple[bool, list[str], list[str]]:
445
+ """Validate a MIR function.
446
+
447
+ Args:
448
+ func: The function to validate.
449
+
450
+ Returns:
451
+ Tuple of (success, errors, warnings).
452
+ """
453
+ validator = MIRValidator()
454
+ success = validator._validate_function(func, func.name)
455
+ return success, validator.get_errors(), validator.get_warnings()