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,1877 @@
1
+ """MIR Three-Address Code Instructions.
2
+
3
+ This module defines the TAC instruction set used in the MIR.
4
+ Each instruction follows the three-address code format where possible.
5
+ """
6
+
7
+ from abc import ABC, abstractmethod
8
+ from typing import Any
9
+
10
+ from .mir_types import MIRType, MIRUnionType
11
+ from .mir_values import Constant, FunctionRef, MIRValue, Temp, Variable
12
+
13
+
14
+ class MIRInstruction(ABC):
15
+ """Base class for all MIR instructions with rich metadata."""
16
+
17
+ def __init__(self, source_location: tuple[int, int]) -> None:
18
+ """Initialize instruction with metadata.
19
+
20
+ Args:
21
+ source_location: Required (line, column) from source code for error reporting.
22
+ """
23
+ # Rich metadata for optimization
24
+ self.result_type: MIRType | None = None # Inferred type of result
25
+ self.is_pure: bool = False # No side effects
26
+ self.can_throw: bool = False # Can raise exceptions
27
+ self.cost: int = 1 # Estimated execution cost
28
+ self.is_commutative: bool = False # Operands can be swapped
29
+ self.is_associative: bool = False # Can be regrouped
30
+ self.memory_effects: set[str] = set() # Memory locations affected
31
+ # Source location for error reporting (REQUIRED for proper error messages)
32
+ self.source_location: tuple[int, int] = source_location # (line, column)
33
+
34
+ @abstractmethod
35
+ def __str__(self) -> str:
36
+ """Return string representation of the instruction."""
37
+ pass
38
+
39
+ @abstractmethod
40
+ def get_uses(self) -> list[MIRValue]:
41
+ """Get values used (read) by this instruction.
42
+
43
+ Returns:
44
+ List of values that this instruction reads.
45
+ """
46
+ pass
47
+
48
+ @abstractmethod
49
+ def get_defs(self) -> list[MIRValue]:
50
+ """Get values defined (written) by this instruction.
51
+
52
+ Returns:
53
+ List of values that this instruction writes.
54
+ """
55
+ pass
56
+
57
+ def replace_use(self, old_value: MIRValue, new_value: MIRValue) -> None: # noqa: B027
58
+ """Replace uses of a value in this instruction.
59
+
60
+ Args:
61
+ old_value: The value to replace.
62
+ new_value: The replacement value.
63
+ """
64
+ # Default implementation does nothing - this is intentional
65
+ # Subclasses should override if they have uses
66
+ # Not abstract because many instructions don't use values
67
+ pass
68
+
69
+
70
+ class BinaryOp(MIRInstruction):
71
+ """Binary operation: dest = left op right."""
72
+
73
+ def __init__(
74
+ self, dest: MIRValue, op: str, left: MIRValue, right: MIRValue, source_location: tuple[int, int]
75
+ ) -> None:
76
+ """Initialize a binary operation.
77
+
78
+ Args:
79
+ dest: Destination to store result.
80
+ op: Operator (+, -, *, /, %, ^, ==, !=, <, >, <=, >=, and, or).
81
+ left: Left operand.
82
+ right: Right operand.
83
+ source_location: Source code location (line, column).
84
+ """
85
+ super().__init__(source_location)
86
+ self.dest = dest
87
+ self.op = op
88
+ self.left = left
89
+ self.right = right
90
+
91
+ # Set metadata based on operator
92
+ if op in ["+", "*", "==", "!=", "and", "or"]:
93
+ self.is_commutative = True
94
+ if op in ["+", "*", "and", "or"]:
95
+ self.is_associative = True
96
+ if op in ["+", "-", "*", "==", "!=", "<", ">", "<=", ">="]:
97
+ self.is_pure = True
98
+ if op == "/":
99
+ self.can_throw = True # Division by zero
100
+
101
+ # Set cost estimates
102
+ if op in ["*", "/", "%", "**"]:
103
+ self.cost = 3
104
+ elif op in ["+", "-"]:
105
+ self.cost = 1
106
+ else:
107
+ self.cost = 2
108
+
109
+ def __str__(self) -> str:
110
+ """Return string representation."""
111
+ return f"{self.dest} = {self.left} {self.op} {self.right}"
112
+
113
+ def get_uses(self) -> list[MIRValue]:
114
+ """Get operands used."""
115
+ return [self.left, self.right]
116
+
117
+ def get_defs(self) -> list[MIRValue]:
118
+ """Get destination defined."""
119
+ return [self.dest]
120
+
121
+ def replace_use(self, old_value: MIRValue, new_value: MIRValue) -> None:
122
+ """Replace uses of a value."""
123
+ if self.left == old_value:
124
+ self.left = new_value
125
+ if self.right == old_value:
126
+ self.right = new_value
127
+
128
+
129
+ class UnaryOp(MIRInstruction):
130
+ """Unary operation: dest = op operand."""
131
+
132
+ def __init__(self, dest: MIRValue, op: str, operand: MIRValue, source_location: tuple[int, int]) -> None:
133
+ """Initialize a unary operation.
134
+
135
+ Args:
136
+ dest: Destination to store result.
137
+ op: Operator (-, not, abs).
138
+ operand: Operand.
139
+ source_location: Source code location (line, column).
140
+ """
141
+ super().__init__(source_location)
142
+ self.dest = dest
143
+ self.op = op
144
+ self.operand = operand
145
+
146
+ # All unary ops are pure
147
+ self.is_pure = True
148
+ self.cost = 1
149
+
150
+ def __str__(self) -> str:
151
+ """Return string representation."""
152
+ return f"{self.dest} = {self.op} {self.operand}"
153
+
154
+ def get_uses(self) -> list[MIRValue]:
155
+ """Get operand used."""
156
+ return [self.operand]
157
+
158
+ def get_defs(self) -> list[MIRValue]:
159
+ """Get destination defined."""
160
+ return [self.dest]
161
+
162
+ def replace_use(self, old_value: MIRValue, new_value: MIRValue) -> None:
163
+ """Replace uses of a value."""
164
+ if self.operand == old_value:
165
+ self.operand = new_value
166
+
167
+
168
+ class ShiftOp(MIRInstruction):
169
+ """Bitwise shift operation: dest = left op right.
170
+
171
+ Used for strength reduction optimizations where multiply/divide
172
+ by powers of 2 are converted to shift operations.
173
+ """
174
+
175
+ def __init__(
176
+ self, dest: MIRValue, left: MIRValue, right: MIRValue, op: str, source_location: tuple[int, int]
177
+ ) -> None:
178
+ """Initialize a shift operation.
179
+
180
+ Args:
181
+ dest: Destination to store result.
182
+ left: Value to shift.
183
+ right: Shift amount.
184
+ op: Shift operator ('<<' for left shift, '>>' for right shift).
185
+ source_location: Source code location (line, column).
186
+ """
187
+ super().__init__(source_location)
188
+ self.dest = dest
189
+ self.left = left
190
+ self.right = right
191
+ self.op = op
192
+
193
+ def __str__(self) -> str:
194
+ """Return string representation."""
195
+ return f"{self.dest} = {self.left} {self.op} {self.right}"
196
+
197
+ def get_uses(self) -> list[MIRValue]:
198
+ """Get operands used."""
199
+ return [self.left, self.right]
200
+
201
+ def get_defs(self) -> list[MIRValue]:
202
+ """Get destination defined."""
203
+ return [self.dest]
204
+
205
+ def replace_use(self, old_value: MIRValue, new_value: MIRValue) -> None:
206
+ """Replace uses of a value."""
207
+ if self.left == old_value:
208
+ self.left = new_value
209
+ if self.right == old_value:
210
+ self.right = new_value
211
+
212
+
213
+ class Copy(MIRInstruction):
214
+ """Copy instruction: dest = source."""
215
+
216
+ def __init__(self, dest: MIRValue, source: MIRValue, source_location: tuple[int, int]) -> None:
217
+ """Initialize a copy instruction.
218
+
219
+ Args:
220
+ dest: Destination.
221
+ source: Source value.
222
+ source_location: Source code location (line, column).
223
+ """
224
+ super().__init__(source_location)
225
+ self.dest = dest
226
+ self.source = source
227
+
228
+ def __str__(self) -> str:
229
+ """Return string representation."""
230
+ return f"{self.dest} = {self.source}"
231
+
232
+ def get_uses(self) -> list[MIRValue]:
233
+ """Get source used."""
234
+ return [self.source]
235
+
236
+ def get_defs(self) -> list[MIRValue]:
237
+ """Get destination defined."""
238
+ return [self.dest]
239
+
240
+ def replace_use(self, old_value: MIRValue, new_value: MIRValue) -> None:
241
+ """Replace uses of a value."""
242
+ if self.source == old_value:
243
+ self.source = new_value
244
+
245
+
246
+ class LoadConst(MIRInstruction):
247
+ """Load constant: dest = constant."""
248
+
249
+ def __init__(self, dest: MIRValue, value: Any, source_location: tuple[int, int]) -> None:
250
+ """Initialize a load constant instruction.
251
+
252
+ Args:
253
+ dest: Destination.
254
+ value: Constant value to load.
255
+ source_location: Source code location (line, column).
256
+ """
257
+ super().__init__(source_location)
258
+ self.dest = dest
259
+ self.constant = Constant(value) if not isinstance(value, Constant) else value
260
+
261
+ def __str__(self) -> str:
262
+ """Return string representation."""
263
+ return f"{self.dest} = {self.constant}"
264
+
265
+ def get_uses(self) -> list[MIRValue]:
266
+ """Constants are not uses."""
267
+ return []
268
+
269
+ def get_defs(self) -> list[MIRValue]:
270
+ """Get destination defined."""
271
+ return [self.dest]
272
+
273
+
274
+ class LoadVar(MIRInstruction):
275
+ """Load variable: dest = variable."""
276
+
277
+ def __init__(self, dest: MIRValue, var: Variable, source_location: tuple[int, int]) -> None:
278
+ """Initialize a load variable instruction.
279
+
280
+ Args:
281
+ dest: Destination temporary.
282
+ var: Variable to load from.
283
+ source_location: Source code location (line, column).
284
+ """
285
+ super().__init__(source_location)
286
+ self.dest = dest
287
+ self.var = var
288
+
289
+ def __str__(self) -> str:
290
+ """Return string representation."""
291
+ return f"{self.dest} = {self.var}"
292
+
293
+ def get_uses(self) -> list[MIRValue]:
294
+ """Get variable used."""
295
+ return [self.var]
296
+
297
+ def get_defs(self) -> list[MIRValue]:
298
+ """Get destination defined."""
299
+ return [self.dest]
300
+
301
+ def replace_use(self, old_value: MIRValue, new_value: MIRValue) -> None:
302
+ """Replace uses of a value."""
303
+ if self.var == old_value and isinstance(new_value, Variable):
304
+ self.var = new_value
305
+
306
+
307
+ class StoreVar(MIRInstruction):
308
+ """Store to variable: variable = source."""
309
+
310
+ def __init__(self, var: Variable, source: MIRValue, source_location: tuple[int, int]) -> None:
311
+ """Initialize a store variable instruction.
312
+
313
+ Args:
314
+ var: Variable to store to.
315
+ source: Source value.
316
+ source_location: Source code location (line, column).
317
+ """
318
+ super().__init__(source_location)
319
+ self.var = var
320
+ self.source = source
321
+
322
+ def __str__(self) -> str:
323
+ """Return string representation."""
324
+ return f"{self.var} = {self.source}"
325
+
326
+ def get_uses(self) -> list[MIRValue]:
327
+ """Get source used."""
328
+ return [self.source]
329
+
330
+ def get_defs(self) -> list[MIRValue]:
331
+ """Get variable defined."""
332
+ return [self.var]
333
+
334
+ def replace_use(self, old_value: MIRValue, new_value: MIRValue) -> None:
335
+ """Replace uses of a value."""
336
+ if self.source == old_value:
337
+ self.source = new_value
338
+
339
+
340
+ class Call(MIRInstruction):
341
+ """Function call: dest = call func(args)."""
342
+
343
+ def __init__(
344
+ self,
345
+ dest: MIRValue | None,
346
+ func: FunctionRef | str,
347
+ args: list[MIRValue],
348
+ source_location: tuple[int, int],
349
+ is_tail_call: bool = False,
350
+ ) -> None:
351
+ """Initialize a function call.
352
+
353
+ Args:
354
+ dest: Optional destination for return value.
355
+ func: Function to call (FunctionRef or name string).
356
+ args: Arguments to pass.
357
+ source_location: Source code location (line, column).
358
+ is_tail_call: Whether this is a tail call that can be optimized.
359
+ """
360
+ super().__init__(source_location)
361
+ self.dest = dest
362
+ self.func = FunctionRef(func) if isinstance(func, str) else func
363
+ self.args = args
364
+ self.is_tail_call = is_tail_call
365
+
366
+ def __str__(self) -> str:
367
+ """Return string representation."""
368
+ args_str = ", ".join(str(arg) for arg in self.args)
369
+ tail_str = " [tail]" if self.is_tail_call else ""
370
+ if self.dest:
371
+ return f"{self.dest} = call {self.func}({args_str}){tail_str}"
372
+ else:
373
+ return f"call {self.func}({args_str}){tail_str}"
374
+
375
+ def get_uses(self) -> list[MIRValue]:
376
+ """Get arguments used."""
377
+ return self.args.copy()
378
+
379
+ def get_defs(self) -> list[MIRValue]:
380
+ """Get destination defined if any."""
381
+ return [self.dest] if self.dest else []
382
+
383
+ def replace_use(self, old_value: MIRValue, new_value: MIRValue) -> None:
384
+ """Replace uses of a value in arguments."""
385
+ self.args = [new_value if arg == old_value else arg for arg in self.args]
386
+
387
+
388
+ class Return(MIRInstruction):
389
+ """Return instruction: return value."""
390
+
391
+ def __init__(self, source_location: tuple[int, int], value: MIRValue | None = None) -> None:
392
+ """Initialize a return instruction.
393
+
394
+ Args:
395
+ source_location: Source code location (line, column).
396
+ value: Optional value to return.
397
+ """
398
+ super().__init__(source_location)
399
+ self.value = value
400
+
401
+ def __str__(self) -> str:
402
+ """Return string representation."""
403
+ if self.value:
404
+ return f"return {self.value}"
405
+ else:
406
+ return "return"
407
+
408
+ def get_uses(self) -> list[MIRValue]:
409
+ """Get value used if any."""
410
+ return [self.value] if self.value else []
411
+
412
+ def get_defs(self) -> list[MIRValue]:
413
+ """Return defines nothing."""
414
+ return []
415
+
416
+ def replace_use(self, old_value: MIRValue, new_value: MIRValue) -> None:
417
+ """Replace uses of a value."""
418
+ if self.value == old_value:
419
+ self.value = new_value
420
+
421
+
422
+ class Jump(MIRInstruction):
423
+ """Unconditional jump: goto label."""
424
+
425
+ def __init__(self, label: str, source_location: tuple[int, int]) -> None:
426
+ """Initialize a jump instruction.
427
+
428
+ Args:
429
+ label: Target label.
430
+ source_location: Source code location (line, column).
431
+ """
432
+ super().__init__(source_location)
433
+ self.label = label
434
+
435
+ def __str__(self) -> str:
436
+ """Return string representation."""
437
+ return f"goto {self.label}"
438
+
439
+ def get_uses(self) -> list[MIRValue]:
440
+ """Jump uses nothing."""
441
+ return []
442
+
443
+ def get_defs(self) -> list[MIRValue]:
444
+ """Jump defines nothing."""
445
+ return []
446
+
447
+
448
+ class ConditionalJump(MIRInstruction):
449
+ """Conditional jump: if condition goto true_label else false_label."""
450
+
451
+ def __init__(
452
+ self, condition: MIRValue, true_label: str, source_location: tuple[int, int], false_label: str | None = None
453
+ ) -> None:
454
+ """Initialize a conditional jump.
455
+
456
+ Args:
457
+ condition: Condition to test.
458
+ true_label: Label to jump to if true.
459
+ source_location: Source code location (line, column).
460
+ false_label: Optional label to jump to if false (falls through if None).
461
+ """
462
+ super().__init__(source_location)
463
+ self.condition = condition
464
+ self.true_label = true_label
465
+ self.false_label = false_label
466
+
467
+ def __str__(self) -> str:
468
+ """Return string representation."""
469
+ if self.false_label:
470
+ return f"if {self.condition} goto {self.true_label} else {self.false_label}"
471
+ else:
472
+ return f"if {self.condition} goto {self.true_label}"
473
+
474
+ def get_uses(self) -> list[MIRValue]:
475
+ """Get condition used."""
476
+ return [self.condition]
477
+
478
+ def get_defs(self) -> list[MIRValue]:
479
+ """Conditional jump defines nothing."""
480
+ return []
481
+
482
+ def replace_use(self, old_value: MIRValue, new_value: MIRValue) -> None:
483
+ """Replace uses of a value."""
484
+ if self.condition == old_value:
485
+ self.condition = new_value
486
+
487
+
488
+ class Phi(MIRInstruction):
489
+ """SSA phi node: dest = φ(value1, value2, ...).
490
+
491
+ Phi nodes are used at join points in SSA form to merge values
492
+ from different control flow paths.
493
+ """
494
+
495
+ def __init__(self, dest: MIRValue, incoming: list[tuple[MIRValue, str]], source_location: tuple[int, int]) -> None:
496
+ """Initialize a phi node.
497
+
498
+ Args:
499
+ dest: Destination to store merged value.
500
+ incoming: List of (value, predecessor_label) pairs.
501
+ source_location: Source code location (line, column).
502
+ """
503
+ super().__init__(source_location)
504
+ self.dest = dest
505
+ self.incoming = incoming
506
+
507
+ def __str__(self) -> str:
508
+ """Return string representation."""
509
+ args = ", ".join(f"{val}:{label}" for val, label in self.incoming)
510
+ return f"{self.dest} = φ({args})"
511
+
512
+ def get_uses(self) -> list[MIRValue]:
513
+ """Get all incoming values."""
514
+ return [val for val, _ in self.incoming]
515
+
516
+ def get_defs(self) -> list[MIRValue]:
517
+ """Get destination defined."""
518
+ return [self.dest]
519
+
520
+ def replace_use(self, old_value: MIRValue, new_value: MIRValue) -> None:
521
+ """Replace uses of a value in incoming values."""
522
+ self.incoming = [(new_value if val == old_value else val, label) for val, label in self.incoming]
523
+
524
+ def add_incoming(self, value: MIRValue, label: str) -> None:
525
+ """Add an incoming value from a predecessor.
526
+
527
+ Args:
528
+ value: The value from the predecessor.
529
+ label: The predecessor's label.
530
+ """
531
+ self.incoming.append((value, label))
532
+
533
+
534
+ class Label(MIRInstruction):
535
+ """Label pseudo-instruction: label_name:."""
536
+
537
+ def __init__(self, name: str, source_location: tuple[int, int]) -> None:
538
+ """Initialize a label.
539
+
540
+ Args:
541
+ name: Label name.
542
+ source_location: Source code location (line, column).
543
+ """
544
+ super().__init__(source_location)
545
+ self.name = name
546
+
547
+ def __str__(self) -> str:
548
+ """Return string representation."""
549
+ return f"{self.name}:"
550
+
551
+ def get_uses(self) -> list[MIRValue]:
552
+ """Labels use nothing."""
553
+ return []
554
+
555
+ def get_defs(self) -> list[MIRValue]:
556
+ """Labels define nothing."""
557
+ return []
558
+
559
+
560
+ class Print(MIRInstruction):
561
+ """Print instruction for Say/Tell statements: print value."""
562
+
563
+ def __init__(self, value: MIRValue, source_location: tuple[int, int]) -> None:
564
+ """Initialize a print instruction.
565
+
566
+ Args:
567
+ value: Value to print.
568
+ source_location: Source code location (line, column).
569
+ """
570
+ super().__init__(source_location)
571
+ self.value = value
572
+
573
+ def __str__(self) -> str:
574
+ """Return string representation."""
575
+ return f"print {self.value}"
576
+
577
+ def get_uses(self) -> list[MIRValue]:
578
+ """Get value used."""
579
+ return [self.value]
580
+
581
+ def get_defs(self) -> list[MIRValue]:
582
+ """Print defines nothing."""
583
+ return []
584
+
585
+ def replace_use(self, old_value: MIRValue, new_value: MIRValue) -> None:
586
+ """Replace uses of a value."""
587
+ if self.value == old_value:
588
+ self.value = new_value
589
+
590
+
591
+ class Nop(MIRInstruction):
592
+ """No-operation instruction."""
593
+
594
+ def __str__(self) -> str:
595
+ """Return string representation."""
596
+ return "nop"
597
+
598
+ def get_uses(self) -> list[MIRValue]:
599
+ """Nop uses nothing."""
600
+ return []
601
+
602
+ def get_defs(self) -> list[MIRValue]:
603
+ """Nop defines nothing."""
604
+ return []
605
+
606
+
607
+ class Assert(MIRInstruction):
608
+ """Assert instruction for runtime checks: assert condition."""
609
+
610
+ def __init__(self, condition: MIRValue, source_location: tuple[int, int], message: str | None = None) -> None:
611
+ """Initialize an assert instruction.
612
+
613
+ Args:
614
+ condition: Condition to check.
615
+ source_location: Source code location (line, column).
616
+ message: Optional error message.
617
+ """
618
+ super().__init__(source_location)
619
+ self.condition = condition
620
+ self.message = message
621
+
622
+ def __str__(self) -> str:
623
+ """Return string representation."""
624
+ if self.message:
625
+ return f'assert {self.condition}, "{self.message}"'
626
+ return f"assert {self.condition}"
627
+
628
+ def get_uses(self) -> list[MIRValue]:
629
+ """Get condition used."""
630
+ return [self.condition]
631
+
632
+ def get_defs(self) -> list[MIRValue]:
633
+ """Assert defines nothing."""
634
+ return []
635
+
636
+ def replace_use(self, old_value: MIRValue, new_value: MIRValue) -> None:
637
+ """Replace uses of a value."""
638
+ if self.condition == old_value:
639
+ self.condition = new_value
640
+
641
+
642
+ class Select(MIRInstruction):
643
+ """Select instruction (ternary): dest = condition ? true_val : false_val."""
644
+
645
+ def __init__(
646
+ self,
647
+ dest: MIRValue,
648
+ condition: MIRValue,
649
+ true_val: MIRValue,
650
+ false_val: MIRValue,
651
+ source_location: tuple[int, int],
652
+ ) -> None:
653
+ """Initialize a select instruction.
654
+
655
+ Args:
656
+ dest: Destination to store result.
657
+ condition: Condition to test.
658
+ true_val: Value when condition is true.
659
+ false_val: Value when condition is false.
660
+ source_location: Source code location (line, column).
661
+ """
662
+ super().__init__(source_location)
663
+ self.dest = dest
664
+ self.condition = condition
665
+ self.true_val = true_val
666
+ self.false_val = false_val
667
+
668
+ def __str__(self) -> str:
669
+ """Return string representation."""
670
+ return f"{self.dest} = select {self.condition}, {self.true_val}, {self.false_val}"
671
+
672
+ def get_uses(self) -> list[MIRValue]:
673
+ """Get values used."""
674
+ return [self.condition, self.true_val, self.false_val]
675
+
676
+ def get_defs(self) -> list[MIRValue]:
677
+ """Get destination defined."""
678
+ return [self.dest]
679
+
680
+ def replace_use(self, old_value: MIRValue, new_value: MIRValue) -> None:
681
+ """Replace uses of a value."""
682
+ if self.condition == old_value:
683
+ self.condition = new_value
684
+ if self.true_val == old_value:
685
+ self.true_val = new_value
686
+ if self.false_val == old_value:
687
+ self.false_val = new_value
688
+
689
+
690
+ class Scope(MIRInstruction):
691
+ """Scope instruction for block management: begin_scope/end_scope."""
692
+
693
+ def __init__(self, source_location: tuple[int, int], is_begin: bool = True) -> None:
694
+ """Initialize a scope instruction.
695
+
696
+ Args:
697
+ source_location: Source code location (line, column).
698
+ is_begin: True for begin_scope, False for end_scope.
699
+ """
700
+ super().__init__(source_location)
701
+ self.is_begin = is_begin
702
+
703
+ def __str__(self) -> str:
704
+ """Return string representation."""
705
+ return "begin_scope" if self.is_begin else "end_scope"
706
+
707
+ def get_uses(self) -> list[MIRValue]:
708
+ """Scope uses nothing."""
709
+ return []
710
+
711
+ def get_defs(self) -> list[MIRValue]:
712
+ """Scope defines nothing."""
713
+ return []
714
+
715
+
716
+ class GetAttr(MIRInstruction):
717
+ """Get attribute instruction: dest = object.attr."""
718
+
719
+ def __init__(self, dest: MIRValue, obj: MIRValue, attr: str) -> None:
720
+ """Initialize a get attribute instruction.
721
+
722
+ Args:
723
+ dest: Destination to store attribute value.
724
+ obj: Object to get attribute from.
725
+ attr: Attribute name.
726
+ """
727
+ super().__init__((0, 0)) # TODO: Add proper source_location
728
+ self.dest = dest
729
+ self.obj = obj
730
+ self.attr = attr
731
+
732
+ def __str__(self) -> str:
733
+ """Return string representation."""
734
+ return f"{self.dest} = {self.obj}.{self.attr}"
735
+
736
+ def get_uses(self) -> list[MIRValue]:
737
+ """Get object used."""
738
+ return [self.obj]
739
+
740
+ def get_defs(self) -> list[MIRValue]:
741
+ """Get destination defined."""
742
+ return [self.dest]
743
+
744
+ def replace_use(self, old_value: MIRValue, new_value: MIRValue) -> None:
745
+ """Replace uses of a value."""
746
+ if self.obj == old_value:
747
+ self.obj = new_value
748
+
749
+
750
+ class SetAttr(MIRInstruction):
751
+ """Set attribute instruction: object.attr = value."""
752
+
753
+ def __init__(self, obj: MIRValue, attr: str, value: MIRValue) -> None:
754
+ """Initialize a set attribute instruction.
755
+
756
+ Args:
757
+ obj: Object to set attribute on.
758
+ attr: Attribute name.
759
+ value: Value to set.
760
+ """
761
+ super().__init__((0, 0)) # TODO: Add proper source_location
762
+ self.obj = obj
763
+ self.attr = attr
764
+ self.value = value
765
+
766
+ def __str__(self) -> str:
767
+ """Return string representation."""
768
+ return f"{self.obj}.{self.attr} = {self.value}"
769
+
770
+ def get_uses(self) -> list[MIRValue]:
771
+ """Get object and value used."""
772
+ return [self.obj, self.value]
773
+
774
+ def get_defs(self) -> list[MIRValue]:
775
+ """SetAttr defines nothing directly."""
776
+ return []
777
+
778
+ def replace_use(self, old_value: MIRValue, new_value: MIRValue) -> None:
779
+ """Replace uses of a value."""
780
+ if self.obj == old_value:
781
+ self.obj = new_value
782
+ if self.value == old_value:
783
+ self.value = new_value
784
+
785
+
786
+ class Pop(MIRInstruction):
787
+ """Pop instruction to discard a value from the stack.
788
+
789
+ This instruction is used when an expression result is not needed,
790
+ such as in expression statements where the value is computed but
791
+ then discarded.
792
+ """
793
+
794
+ def __init__(self, value: MIRValue, source_location: tuple[int, int]) -> None:
795
+ """Initialize a pop instruction.
796
+
797
+ Args:
798
+ value: The value to pop/discard.
799
+ source_location: Source code location (line, column).
800
+ """
801
+ super().__init__(source_location)
802
+ self.value = value
803
+
804
+ def __str__(self) -> str:
805
+ """Return string representation."""
806
+ return f"pop {self.value}"
807
+
808
+ def get_uses(self) -> list[MIRValue]:
809
+ """Get values used by this instruction."""
810
+ return [self.value]
811
+
812
+ def get_defs(self) -> list[MIRValue]:
813
+ """Get values defined by this instruction."""
814
+ return [] # Pop doesn't define any values
815
+
816
+ def replace_use(self, old: MIRValue, new: MIRValue) -> None:
817
+ """Replace a used value."""
818
+ if self.value == old:
819
+ self.value = new
820
+
821
+
822
+ class TypeCast(MIRInstruction):
823
+ """Type cast instruction: dest = cast(value, target_type).
824
+
825
+ Explicit type conversion between compatible types.
826
+ """
827
+
828
+ def __init__(self, dest: MIRValue, value: MIRValue, target_type: MIRType | MIRUnionType) -> None:
829
+ """Initialize a type cast instruction.
830
+
831
+ Args:
832
+ dest: Destination to store cast result.
833
+ value: Value to cast.
834
+ target_type: Target type to cast to.
835
+ """
836
+ super().__init__((0, 0)) # TODO: Add proper source_location
837
+ self.dest = dest
838
+ self.value = value
839
+ self.target_type = target_type
840
+
841
+ def __str__(self) -> str:
842
+ """Return string representation."""
843
+ return f"{self.dest} = cast({self.value}, {self.target_type})"
844
+
845
+ def get_uses(self) -> list[MIRValue]:
846
+ """Get value used."""
847
+ return [self.value]
848
+
849
+ def get_defs(self) -> list[MIRValue]:
850
+ """Get destination defined."""
851
+ return [self.dest]
852
+
853
+ def replace_use(self, old: MIRValue, new: MIRValue) -> None:
854
+ """Replace uses of a value."""
855
+ if self.value == old:
856
+ self.value = new
857
+
858
+
859
+ class TypeCheck(MIRInstruction):
860
+ """Type check instruction: dest = is_type(value, type).
861
+
862
+ Runtime type checking for union types or dynamic typing.
863
+ """
864
+
865
+ def __init__(self, dest: MIRValue, value: MIRValue, check_type: MIRType | MIRUnionType) -> None:
866
+ """Initialize a type check instruction.
867
+
868
+ Args:
869
+ dest: Destination to store boolean result.
870
+ value: Value to check type of.
871
+ check_type: Type to check against.
872
+ """
873
+ super().__init__((0, 0)) # TODO: Add proper source_location
874
+ self.dest = dest
875
+ self.value = value
876
+ self.check_type = check_type
877
+
878
+ def __str__(self) -> str:
879
+ """Return string representation."""
880
+ return f"{self.dest} = is_type({self.value}, {self.check_type})"
881
+
882
+ def get_uses(self) -> list[MIRValue]:
883
+ """Get value used."""
884
+ return [self.value]
885
+
886
+ def get_defs(self) -> list[MIRValue]:
887
+ """Get destination defined."""
888
+ return [self.dest]
889
+
890
+ def replace_use(self, old: MIRValue, new: MIRValue) -> None:
891
+ """Replace uses of a value."""
892
+ if self.value == old:
893
+ self.value = new
894
+
895
+
896
+ class TypeAssert(MIRInstruction):
897
+ """Type assertion instruction: assert_type(value, type).
898
+
899
+ Assert that a value has a specific type at runtime.
900
+ Throws error if type mismatch.
901
+ """
902
+
903
+ def __init__(self, value: MIRValue, assert_type: MIRType | MIRUnionType) -> None:
904
+ """Initialize a type assertion instruction.
905
+
906
+ Args:
907
+ value: Value to assert type of.
908
+ assert_type: Expected type.
909
+ """
910
+ super().__init__((0, 0)) # TODO: Add proper source_location
911
+ self.value = value
912
+ self.assert_type = assert_type
913
+
914
+ def __str__(self) -> str:
915
+ """Return string representation."""
916
+ return f"assert_type({self.value}, {self.assert_type})"
917
+
918
+ def get_uses(self) -> list[MIRValue]:
919
+ """Get value used."""
920
+ return [self.value]
921
+
922
+ def get_defs(self) -> list[MIRValue]:
923
+ """No values defined."""
924
+ return []
925
+
926
+ def replace_use(self, old: MIRValue, new: MIRValue) -> None:
927
+ """Replace uses of a value."""
928
+ if self.value == old:
929
+ self.value = new
930
+
931
+
932
+ class NarrowType(MIRInstruction):
933
+ """Type narrowing instruction: dest = narrow(value, type).
934
+
935
+ Used after type checks to narrow union types to specific types.
936
+ This is a compile-time hint for optimization, not a runtime operation.
937
+ """
938
+
939
+ def __init__(self, dest: MIRValue, value: MIRValue, narrow_type: MIRType) -> None:
940
+ """Initialize a type narrowing instruction.
941
+
942
+ Args:
943
+ dest: Destination with narrowed type.
944
+ value: Value to narrow.
945
+ narrow_type: The specific type to narrow to.
946
+ """
947
+ super().__init__((0, 0)) # TODO: Add proper source_location
948
+ self.dest = dest
949
+ self.value = value
950
+ self.narrow_type = narrow_type
951
+ self.is_pure = True
952
+ self.cost = 0 # Compile-time only
953
+
954
+ def __str__(self) -> str:
955
+ """Return string representation."""
956
+ return f"{self.dest} = narrow({self.value}, {self.narrow_type})"
957
+
958
+ def get_uses(self) -> list[MIRValue]:
959
+ """Get value used."""
960
+ return [self.value]
961
+
962
+ def get_defs(self) -> list[MIRValue]:
963
+ """Get destination defined."""
964
+ return [self.dest]
965
+
966
+ def replace_use(self, old: MIRValue, new: MIRValue) -> None:
967
+ """Replace uses of a value."""
968
+ if self.value == old:
969
+ self.value = new
970
+
971
+
972
+ # New specialized instructions for better optimization
973
+
974
+
975
+ class SelectOp(MIRInstruction):
976
+ """Conditional select without branches: dest = cond ? true_val : false_val."""
977
+
978
+ def __init__(self, dest: MIRValue, cond: MIRValue, true_val: MIRValue, false_val: MIRValue) -> None:
979
+ """Initialize a select operation.
980
+
981
+ Args:
982
+ dest: Destination to store result.
983
+ cond: Condition to test.
984
+ true_val: Value if condition is true.
985
+ false_val: Value if condition is false.
986
+ """
987
+ super().__init__((0, 0)) # TODO: Add proper source_location
988
+ self.dest = dest
989
+ self.cond = cond
990
+ self.true_val = true_val
991
+ self.false_val = false_val
992
+ self.is_pure = True
993
+ self.cost = 1 # Branchless on modern CPUs
994
+
995
+ def __str__(self) -> str:
996
+ """Return string representation."""
997
+ return f"{self.dest} = select({self.cond}, {self.true_val}, {self.false_val})"
998
+
999
+ def get_uses(self) -> list[MIRValue]:
1000
+ """Get values used."""
1001
+ return [self.cond, self.true_val, self.false_val]
1002
+
1003
+ def get_defs(self) -> list[MIRValue]:
1004
+ """Get destination defined."""
1005
+ return [self.dest]
1006
+
1007
+ def replace_use(self, old: MIRValue, new: MIRValue) -> None:
1008
+ """Replace uses of a value."""
1009
+ if self.cond == old:
1010
+ self.cond = new
1011
+ if self.true_val == old:
1012
+ self.true_val = new
1013
+ if self.false_val == old:
1014
+ self.false_val = new
1015
+
1016
+
1017
+ class MinOp(MIRInstruction):
1018
+ """Minimum operation: dest = min(left, right)."""
1019
+
1020
+ def __init__(self, dest: MIRValue, left: MIRValue, right: MIRValue) -> None:
1021
+ """Initialize a min operation.
1022
+
1023
+ Args:
1024
+ dest: Destination to store result.
1025
+ left: Left operand.
1026
+ right: Right operand.
1027
+ """
1028
+ super().__init__((0, 0)) # TODO: Add proper source_location
1029
+ self.dest = dest
1030
+ self.left = left
1031
+ self.right = right
1032
+ self.is_pure = True
1033
+ self.is_commutative = True
1034
+ self.cost = 1
1035
+
1036
+ def __str__(self) -> str:
1037
+ """Return string representation."""
1038
+ return f"{self.dest} = min({self.left}, {self.right})"
1039
+
1040
+ def get_uses(self) -> list[MIRValue]:
1041
+ """Get operands used."""
1042
+ return [self.left, self.right]
1043
+
1044
+ def get_defs(self) -> list[MIRValue]:
1045
+ """Get destination defined."""
1046
+ return [self.dest]
1047
+
1048
+ def replace_use(self, old: MIRValue, new: MIRValue) -> None:
1049
+ """Replace uses of a value."""
1050
+ if self.left == old:
1051
+ self.left = new
1052
+ if self.right == old:
1053
+ self.right = new
1054
+
1055
+
1056
+ class MaxOp(MIRInstruction):
1057
+ """Maximum operation: dest = max(left, right)."""
1058
+
1059
+ def __init__(self, dest: MIRValue, left: MIRValue, right: MIRValue) -> None:
1060
+ """Initialize a max operation.
1061
+
1062
+ Args:
1063
+ dest: Destination to store result.
1064
+ left: Left operand.
1065
+ right: Right operand.
1066
+ """
1067
+ super().__init__((0, 0)) # TODO: Add proper source_location
1068
+ self.dest = dest
1069
+ self.left = left
1070
+ self.right = right
1071
+ self.is_pure = True
1072
+ self.is_commutative = True
1073
+ self.cost = 1
1074
+
1075
+ def __str__(self) -> str:
1076
+ """Return string representation."""
1077
+ return f"{self.dest} = max({self.left}, {self.right})"
1078
+
1079
+ def get_uses(self) -> list[MIRValue]:
1080
+ """Get operands used."""
1081
+ return [self.left, self.right]
1082
+
1083
+ def get_defs(self) -> list[MIRValue]:
1084
+ """Get destination defined."""
1085
+ return [self.dest]
1086
+
1087
+ def replace_use(self, old: MIRValue, new: MIRValue) -> None:
1088
+ """Replace uses of a value."""
1089
+ if self.left == old:
1090
+ self.left = new
1091
+ if self.right == old:
1092
+ self.right = new
1093
+
1094
+
1095
+ class SaturatingAddOp(MIRInstruction):
1096
+ """Saturating addition: dest = saturating_add(left, right, min, max)."""
1097
+
1098
+ def __init__(
1099
+ self,
1100
+ dest: MIRValue,
1101
+ left: MIRValue,
1102
+ right: MIRValue,
1103
+ min_val: MIRValue | None = None,
1104
+ max_val: MIRValue | None = None,
1105
+ ) -> None:
1106
+ """Initialize a saturating add operation.
1107
+
1108
+ Args:
1109
+ dest: Destination to store result.
1110
+ left: Left operand.
1111
+ right: Right operand.
1112
+ min_val: Minimum value (saturates to this).
1113
+ max_val: Maximum value (saturates to this).
1114
+ """
1115
+ super().__init__((0, 0)) # TODO: Add proper source_location
1116
+ self.dest = dest
1117
+ self.left = left
1118
+ self.right = right
1119
+ self.min_val = min_val
1120
+ self.max_val = max_val
1121
+ self.is_pure = True
1122
+ self.is_commutative = True
1123
+ self.cost = 2
1124
+
1125
+ def __str__(self) -> str:
1126
+ """Return string representation."""
1127
+ return f"{self.dest} = saturating_add({self.left}, {self.right})"
1128
+
1129
+ def get_uses(self) -> list[MIRValue]:
1130
+ """Get operands used."""
1131
+ uses = [self.left, self.right]
1132
+ if self.min_val:
1133
+ uses.append(self.min_val)
1134
+ if self.max_val:
1135
+ uses.append(self.max_val)
1136
+ return uses
1137
+
1138
+ def get_defs(self) -> list[MIRValue]:
1139
+ """Get destination defined."""
1140
+ return [self.dest]
1141
+
1142
+ def replace_use(self, old: MIRValue, new: MIRValue) -> None:
1143
+ """Replace uses of a value."""
1144
+ if self.left == old:
1145
+ self.left = new
1146
+ if self.right == old:
1147
+ self.right = new
1148
+ if self.min_val == old:
1149
+ self.min_val = new
1150
+ if self.max_val == old:
1151
+ self.max_val = new
1152
+
1153
+
1154
+ class PopCountOp(MIRInstruction):
1155
+ """Population count (count set bits): dest = popcount(value)."""
1156
+
1157
+ def __init__(self, dest: MIRValue, value: MIRValue) -> None:
1158
+ """Initialize a popcount operation.
1159
+
1160
+ Args:
1161
+ dest: Destination to store result.
1162
+ value: Value to count bits in.
1163
+ """
1164
+ super().__init__((0, 0)) # TODO: Add proper source_location
1165
+ self.dest = dest
1166
+ self.value = value
1167
+ self.is_pure = True
1168
+ self.cost = 1 # Hardware instruction on modern CPUs
1169
+
1170
+ def __str__(self) -> str:
1171
+ """Return string representation."""
1172
+ return f"{self.dest} = popcount({self.value})"
1173
+
1174
+ def get_uses(self) -> list[MIRValue]:
1175
+ """Get value used."""
1176
+ return [self.value]
1177
+
1178
+ def get_defs(self) -> list[MIRValue]:
1179
+ """Get destination defined."""
1180
+ return [self.dest]
1181
+
1182
+ def replace_use(self, old: MIRValue, new: MIRValue) -> None:
1183
+ """Replace uses of a value."""
1184
+ if self.value == old:
1185
+ self.value = new
1186
+
1187
+
1188
+ # Array/List operations
1189
+ class ArrayCreate(MIRInstruction):
1190
+ """Create a new array: dest = new_array(size)."""
1191
+
1192
+ def __init__(self, dest: MIRValue, size: MIRValue, source_location: tuple[int, int]) -> None:
1193
+ """Initialize array creation.
1194
+
1195
+ Args:
1196
+ dest: Destination to store array reference.
1197
+ size: Initial size of the array.
1198
+ source_location: Source location in original code.
1199
+ """
1200
+ super().__init__(source_location)
1201
+ self.dest = dest
1202
+ self.size = size
1203
+ self.cost = 2
1204
+
1205
+ def __str__(self) -> str:
1206
+ """Return string representation."""
1207
+ return f"{self.dest} = new_array({self.size})"
1208
+
1209
+ def get_uses(self) -> list[MIRValue]:
1210
+ """Get size value used."""
1211
+ return [self.size]
1212
+
1213
+ def get_defs(self) -> list[MIRValue]:
1214
+ """Get destination defined."""
1215
+ return [self.dest]
1216
+
1217
+ def replace_use(self, old: MIRValue, new: MIRValue) -> None:
1218
+ """Replace uses of a value."""
1219
+ if self.size == old:
1220
+ self.size = new
1221
+
1222
+
1223
+ class ArrayGet(MIRInstruction):
1224
+ """Get array element: dest = array[index]."""
1225
+
1226
+ def __init__(
1227
+ self,
1228
+ dest: MIRValue,
1229
+ array: MIRValue,
1230
+ index: MIRValue,
1231
+ source_location: tuple[int, int],
1232
+ ) -> None:
1233
+ """Initialize array get operation.
1234
+
1235
+ Args:
1236
+ dest: Destination to store the value.
1237
+ array: Array to get from.
1238
+ index: Index to access.
1239
+ source_location: Source location in original code.
1240
+ """
1241
+ super().__init__(source_location)
1242
+ self.dest = dest
1243
+ self.array = array
1244
+ self.index = index
1245
+ self.is_pure = True
1246
+ self.cost = 1
1247
+
1248
+ def __str__(self) -> str:
1249
+ """Return string representation."""
1250
+ return f"{self.dest} = {self.array}[{self.index}]"
1251
+
1252
+ def get_uses(self) -> list[MIRValue]:
1253
+ """Get operands used."""
1254
+ return [self.array, self.index]
1255
+
1256
+ def get_defs(self) -> list[MIRValue]:
1257
+ """Get destination defined."""
1258
+ return [self.dest]
1259
+
1260
+ def replace_use(self, old: MIRValue, new: MIRValue) -> None:
1261
+ """Replace uses of a value."""
1262
+ if self.array == old:
1263
+ self.array = new
1264
+ if self.index == old:
1265
+ self.index = new
1266
+
1267
+
1268
+ class ArraySet(MIRInstruction):
1269
+ """Set array element: array[index] = value."""
1270
+
1271
+ def __init__(
1272
+ self,
1273
+ array: MIRValue,
1274
+ index: MIRValue,
1275
+ value: MIRValue,
1276
+ source_location: tuple[int, int],
1277
+ ) -> None:
1278
+ """Initialize array set operation.
1279
+
1280
+ Args:
1281
+ array: Array to modify.
1282
+ index: Index to set.
1283
+ value: Value to store.
1284
+ source_location: Source location in original code.
1285
+ """
1286
+ super().__init__(source_location)
1287
+ self.array = array
1288
+ self.index = index
1289
+ self.value = value
1290
+ self.has_side_effects = True
1291
+ self.cost = 1
1292
+
1293
+ def __str__(self) -> str:
1294
+ """Return string representation."""
1295
+ return f"{self.array}[{self.index}] = {self.value}"
1296
+
1297
+ def get_uses(self) -> list[MIRValue]:
1298
+ """Get operands used."""
1299
+ return [self.array, self.index, self.value]
1300
+
1301
+ def get_defs(self) -> list[MIRValue]:
1302
+ """No direct defs, modifies array in place."""
1303
+ return []
1304
+
1305
+ def replace_use(self, old: MIRValue, new: MIRValue) -> None:
1306
+ """Replace uses of a value."""
1307
+ if self.array == old:
1308
+ self.array = new
1309
+ if self.index == old:
1310
+ self.index = new
1311
+ if self.value == old:
1312
+ self.value = new
1313
+
1314
+
1315
+ class ArrayLength(MIRInstruction):
1316
+ """Get array length: dest = len(array)."""
1317
+
1318
+ def __init__(self, dest: MIRValue, array: MIRValue, source_location: tuple[int, int]) -> None:
1319
+ """Initialize array length operation.
1320
+
1321
+ Args:
1322
+ dest: Destination to store length.
1323
+ array: Array to get length of.
1324
+ source_location: Source location in original code.
1325
+ """
1326
+ super().__init__(source_location)
1327
+ self.dest = dest
1328
+ self.array = array
1329
+ self.is_pure = True
1330
+ self.cost = 1
1331
+
1332
+ def __str__(self) -> str:
1333
+ """Return string representation."""
1334
+ return f"{self.dest} = len({self.array})"
1335
+
1336
+ def get_uses(self) -> list[MIRValue]:
1337
+ """Get array used."""
1338
+ return [self.array]
1339
+
1340
+ def get_defs(self) -> list[MIRValue]:
1341
+ """Get destination defined."""
1342
+ return [self.dest]
1343
+
1344
+ def replace_use(self, old: MIRValue, new: MIRValue) -> None:
1345
+ """Replace uses of a value."""
1346
+ if self.array == old:
1347
+ self.array = new
1348
+
1349
+
1350
+ class ArrayAppend(MIRInstruction):
1351
+ """Append to array: array.append(value)."""
1352
+
1353
+ def __init__(
1354
+ self,
1355
+ array: MIRValue,
1356
+ value: MIRValue,
1357
+ source_location: tuple[int, int],
1358
+ ) -> None:
1359
+ """Initialize array append operation.
1360
+
1361
+ Args:
1362
+ array: Array to append to.
1363
+ value: Value to append.
1364
+ source_location: Source location in original code.
1365
+ """
1366
+ super().__init__(source_location)
1367
+ self.array = array
1368
+ self.value = value
1369
+ self.has_side_effects = True
1370
+ self.cost = 2
1371
+
1372
+ def __str__(self) -> str:
1373
+ """Return string representation."""
1374
+ return f"{self.array}.append({self.value})"
1375
+
1376
+ def get_uses(self) -> list[MIRValue]:
1377
+ """Get operands used."""
1378
+ return [self.array, self.value]
1379
+
1380
+ def get_defs(self) -> list[MIRValue]:
1381
+ """No direct defs, modifies array in place."""
1382
+ return []
1383
+
1384
+ def replace_use(self, old: MIRValue, new: MIRValue) -> None:
1385
+ """Replace uses of a value."""
1386
+ if self.array == old:
1387
+ self.array = new
1388
+ if self.value == old:
1389
+ self.value = new
1390
+
1391
+
1392
+ class ArrayRemove(MIRInstruction):
1393
+ """Remove element from array at index: array.remove(index)."""
1394
+
1395
+ def __init__(
1396
+ self,
1397
+ array: MIRValue,
1398
+ index: MIRValue,
1399
+ source_location: tuple[int, int],
1400
+ ) -> None:
1401
+ """Initialize array remove operation.
1402
+
1403
+ Args:
1404
+ array: The array to remove from.
1405
+ index: The index to remove at.
1406
+ source_location: Source code location (line, column).
1407
+ """
1408
+ super().__init__(source_location)
1409
+ self.array = array
1410
+ self.index = index
1411
+
1412
+ def __str__(self) -> str:
1413
+ """Return string representation."""
1414
+ return f"{self.array}.remove({self.index})"
1415
+
1416
+ def get_uses(self) -> list[MIRValue]:
1417
+ """Get operands used."""
1418
+ return [self.array, self.index]
1419
+
1420
+ def get_defs(self) -> list[MIRValue]:
1421
+ """No direct defs, modifies array in place."""
1422
+ return []
1423
+
1424
+ def replace_use(self, old: MIRValue, new: MIRValue) -> None:
1425
+ """Replace uses of a value."""
1426
+ if self.array == old:
1427
+ self.array = new
1428
+ if self.index == old:
1429
+ self.index = new
1430
+
1431
+
1432
+ class ArrayInsert(MIRInstruction):
1433
+ """Insert element into array at index: array.insert(index, value)."""
1434
+
1435
+ def __init__(
1436
+ self,
1437
+ array: MIRValue,
1438
+ index: MIRValue,
1439
+ value: MIRValue,
1440
+ source_location: tuple[int, int],
1441
+ ) -> None:
1442
+ """Initialize array insert operation.
1443
+
1444
+ Args:
1445
+ array: The array to insert into.
1446
+ index: The index to insert at.
1447
+ value: The value to insert.
1448
+ source_location: Source code location (line, column).
1449
+ """
1450
+ super().__init__(source_location)
1451
+ self.array = array
1452
+ self.index = index
1453
+ self.value = value
1454
+
1455
+ def __str__(self) -> str:
1456
+ """Return string representation."""
1457
+ return f"{self.array}.insert({self.index}, {self.value})"
1458
+
1459
+ def get_uses(self) -> list[MIRValue]:
1460
+ """Get operands used."""
1461
+ return [self.array, self.index, self.value]
1462
+
1463
+ def get_defs(self) -> list[MIRValue]:
1464
+ """No direct defs, modifies array in place."""
1465
+ return []
1466
+
1467
+ def replace_use(self, old: MIRValue, new: MIRValue) -> None:
1468
+ """Replace uses of a value."""
1469
+ if self.array == old:
1470
+ self.array = new
1471
+ if self.index == old:
1472
+ self.index = new
1473
+ if self.value == old:
1474
+ self.value = new
1475
+
1476
+
1477
+ class ArrayFindIndex(MIRInstruction):
1478
+ """Find index of value in array: dest = array.index(value)."""
1479
+
1480
+ def __init__(
1481
+ self,
1482
+ dest: MIRValue,
1483
+ array: MIRValue,
1484
+ value: MIRValue,
1485
+ source_location: tuple[int, int],
1486
+ ) -> None:
1487
+ """Initialize array find index operation.
1488
+
1489
+ Args:
1490
+ dest: Destination for the index (-1 if not found).
1491
+ array: The array to search in.
1492
+ value: The value to find.
1493
+ source_location: Source code location (line, column).
1494
+ """
1495
+ super().__init__(source_location)
1496
+ self.dest = dest
1497
+ self.array = array
1498
+ self.value = value
1499
+
1500
+ def __str__(self) -> str:
1501
+ """Return string representation."""
1502
+ return f"{self.dest} = {self.array}.index({self.value})"
1503
+
1504
+ def get_uses(self) -> list[MIRValue]:
1505
+ """Get operands used."""
1506
+ return [self.array, self.value]
1507
+
1508
+ def get_defs(self) -> list[MIRValue]:
1509
+ """Get destination defined."""
1510
+ return [self.dest]
1511
+
1512
+ def replace_use(self, old: MIRValue, new: MIRValue) -> None:
1513
+ """Replace uses of a value."""
1514
+ if self.array == old:
1515
+ self.array = new
1516
+ if self.value == old:
1517
+ self.value = new
1518
+
1519
+
1520
+ class ArrayClear(MIRInstruction):
1521
+ """Clear all elements from array: array.clear()."""
1522
+
1523
+ def __init__(
1524
+ self,
1525
+ array: MIRValue,
1526
+ source_location: tuple[int, int],
1527
+ ) -> None:
1528
+ """Initialize array clear operation.
1529
+
1530
+ Args:
1531
+ array: The array to clear.
1532
+ source_location: Source code location (line, column).
1533
+ """
1534
+ super().__init__(source_location)
1535
+ self.array = array
1536
+
1537
+ def __str__(self) -> str:
1538
+ """Return string representation."""
1539
+ return f"{self.array}.clear()"
1540
+
1541
+ def get_uses(self) -> list[MIRValue]:
1542
+ """Get operands used."""
1543
+ return [self.array]
1544
+
1545
+ def get_defs(self) -> list[MIRValue]:
1546
+ """No direct defs, modifies array in place."""
1547
+ return []
1548
+
1549
+ def replace_use(self, old: MIRValue, new: MIRValue) -> None:
1550
+ """Replace uses of a value."""
1551
+ if self.array == old:
1552
+ self.array = new
1553
+
1554
+
1555
+ # Dictionary Operations
1556
+
1557
+
1558
+ class DictCreate(MIRInstruction):
1559
+ """Create a new dictionary: dest = {}."""
1560
+
1561
+ def __init__(
1562
+ self,
1563
+ dest: Temp,
1564
+ source_location: tuple[int, int],
1565
+ ) -> None:
1566
+ """Initialize dictionary creation.
1567
+
1568
+ Args:
1569
+ dest: Destination temp for the new dictionary.
1570
+ source_location: Source code location (line, column).
1571
+ """
1572
+ super().__init__(source_location)
1573
+ self.dest = dest
1574
+
1575
+ def __str__(self) -> str:
1576
+ """Return string representation."""
1577
+ return f"{self.dest} = {{}}"
1578
+
1579
+ def get_uses(self) -> list[MIRValue]:
1580
+ """DictCreate uses nothing."""
1581
+ return []
1582
+
1583
+ def get_defs(self) -> list[MIRValue]:
1584
+ """Get defined value."""
1585
+ return [self.dest]
1586
+
1587
+ def replace_use(self, old: MIRValue, new: MIRValue) -> None:
1588
+ """Replace uses of a value."""
1589
+ pass # No uses to replace
1590
+
1591
+
1592
+ class DictGet(MIRInstruction):
1593
+ """Get value from dictionary by key: dest = dict[key]."""
1594
+
1595
+ def __init__(
1596
+ self,
1597
+ dest: Temp,
1598
+ dict_val: MIRValue,
1599
+ key: MIRValue,
1600
+ source_location: tuple[int, int],
1601
+ ) -> None:
1602
+ """Initialize dictionary get operation.
1603
+
1604
+ Args:
1605
+ dest: Destination temp for the value.
1606
+ dict_val: The dictionary to get from.
1607
+ key: The key to look up.
1608
+ source_location: Source code location (line, column).
1609
+ """
1610
+ super().__init__(source_location)
1611
+ self.dest = dest
1612
+ self.dict_val = dict_val
1613
+ self.key = key
1614
+
1615
+ def __str__(self) -> str:
1616
+ """Return string representation."""
1617
+ return f"{self.dest} = {self.dict_val}[{self.key}]"
1618
+
1619
+ def get_uses(self) -> list[MIRValue]:
1620
+ """Get operands used."""
1621
+ return [self.dict_val, self.key]
1622
+
1623
+ def get_defs(self) -> list[MIRValue]:
1624
+ """Get defined value."""
1625
+ return [self.dest]
1626
+
1627
+ def replace_use(self, old: MIRValue, new: MIRValue) -> None:
1628
+ """Replace uses of a value."""
1629
+ if self.dict_val == old:
1630
+ self.dict_val = new
1631
+ if self.key == old:
1632
+ self.key = new
1633
+
1634
+
1635
+ class DictSet(MIRInstruction):
1636
+ """Set value in dictionary: dict[key] = value."""
1637
+
1638
+ def __init__(
1639
+ self,
1640
+ dict_val: MIRValue,
1641
+ key: MIRValue,
1642
+ value: MIRValue,
1643
+ source_location: tuple[int, int],
1644
+ ) -> None:
1645
+ """Initialize dictionary set operation.
1646
+
1647
+ Args:
1648
+ dict_val: The dictionary to modify.
1649
+ key: The key to set.
1650
+ value: The value to set.
1651
+ source_location: Source code location (line, column).
1652
+ """
1653
+ super().__init__(source_location)
1654
+ self.dict_val = dict_val
1655
+ self.key = key
1656
+ self.value = value
1657
+
1658
+ def __str__(self) -> str:
1659
+ """Return string representation."""
1660
+ return f"{self.dict_val}[{self.key}] = {self.value}"
1661
+
1662
+ def get_uses(self) -> list[MIRValue]:
1663
+ """Get operands used."""
1664
+ return [self.dict_val, self.key, self.value]
1665
+
1666
+ def get_defs(self) -> list[MIRValue]:
1667
+ """No direct defs, modifies dict in place."""
1668
+ return []
1669
+
1670
+ def replace_use(self, old: MIRValue, new: MIRValue) -> None:
1671
+ """Replace uses of a value."""
1672
+ if self.dict_val == old:
1673
+ self.dict_val = new
1674
+ if self.key == old:
1675
+ self.key = new
1676
+ if self.value == old:
1677
+ self.value = new
1678
+
1679
+
1680
+ class DictRemove(MIRInstruction):
1681
+ """Remove key from dictionary: del dict[key]."""
1682
+
1683
+ def __init__(
1684
+ self,
1685
+ dict_val: MIRValue,
1686
+ key: MIRValue,
1687
+ source_location: tuple[int, int],
1688
+ ) -> None:
1689
+ """Initialize dictionary remove operation.
1690
+
1691
+ Args:
1692
+ dict_val: The dictionary to modify.
1693
+ key: The key to remove.
1694
+ source_location: Source code location (line, column).
1695
+ """
1696
+ super().__init__(source_location)
1697
+ self.dict_val = dict_val
1698
+ self.key = key
1699
+
1700
+ def __str__(self) -> str:
1701
+ """Return string representation."""
1702
+ return f"del {self.dict_val}[{self.key}]"
1703
+
1704
+ def get_uses(self) -> list[MIRValue]:
1705
+ """Get operands used."""
1706
+ return [self.dict_val, self.key]
1707
+
1708
+ def get_defs(self) -> list[MIRValue]:
1709
+ """No direct defs, modifies dict in place."""
1710
+ return []
1711
+
1712
+ def replace_use(self, old: MIRValue, new: MIRValue) -> None:
1713
+ """Replace uses of a value."""
1714
+ if self.dict_val == old:
1715
+ self.dict_val = new
1716
+ if self.key == old:
1717
+ self.key = new
1718
+
1719
+
1720
+ class DictKeys(MIRInstruction):
1721
+ """Get all keys from a dictionary as an array: dest = dict.keys()."""
1722
+
1723
+ def __init__(
1724
+ self,
1725
+ dest: MIRValue,
1726
+ dict_val: MIRValue,
1727
+ source_location: tuple[int, int],
1728
+ ) -> None:
1729
+ """Initialize dictionary keys extraction.
1730
+
1731
+ Args:
1732
+ dest: Destination register for the keys array.
1733
+ dict_val: The dictionary to get keys from.
1734
+ source_location: Source code location (line, column).
1735
+ """
1736
+ super().__init__(source_location)
1737
+ self.dest = dest
1738
+ self.dict_val = dict_val
1739
+
1740
+ def __str__(self) -> str:
1741
+ """Return string representation."""
1742
+ return f"{self.dest} = {self.dict_val}.keys()"
1743
+
1744
+ def get_uses(self) -> list[MIRValue]:
1745
+ """Get operands used."""
1746
+ return [self.dict_val]
1747
+
1748
+ def get_defs(self) -> list[MIRValue]:
1749
+ """Get values defined."""
1750
+ return [self.dest]
1751
+
1752
+ def replace_use(self, old: MIRValue, new: MIRValue) -> None:
1753
+ """Replace uses of a value."""
1754
+ if self.dict_val == old:
1755
+ self.dict_val = new
1756
+ if self.dest == old:
1757
+ self.dest = new
1758
+
1759
+
1760
+ class DictValues(MIRInstruction):
1761
+ """Get all values from a dictionary as an array: dest = dict.values()."""
1762
+
1763
+ def __init__(
1764
+ self,
1765
+ dest: MIRValue,
1766
+ dict_val: MIRValue,
1767
+ source_location: tuple[int, int],
1768
+ ) -> None:
1769
+ """Initialize dictionary values extraction.
1770
+
1771
+ Args:
1772
+ dest: Destination register for the values array.
1773
+ dict_val: The dictionary to get values from.
1774
+ source_location: Source code location (line, column).
1775
+ """
1776
+ super().__init__(source_location)
1777
+ self.dest = dest
1778
+ self.dict_val = dict_val
1779
+
1780
+ def __str__(self) -> str:
1781
+ """Return string representation."""
1782
+ return f"{self.dest} = {self.dict_val}.values()"
1783
+
1784
+ def get_uses(self) -> list[MIRValue]:
1785
+ """Get operands used."""
1786
+ return [self.dict_val]
1787
+
1788
+ def get_defs(self) -> list[MIRValue]:
1789
+ """Get values defined."""
1790
+ return [self.dest]
1791
+
1792
+ def replace_use(self, old: MIRValue, new: MIRValue) -> None:
1793
+ """Replace uses of a value."""
1794
+ if self.dict_val == old:
1795
+ self.dict_val = new
1796
+ if self.dest == old:
1797
+ self.dest = new
1798
+
1799
+
1800
+ class DictContains(MIRInstruction):
1801
+ """Check if key exists in dictionary: dest = key in dict."""
1802
+
1803
+ def __init__(
1804
+ self,
1805
+ dest: Temp,
1806
+ dict_val: MIRValue,
1807
+ key: MIRValue,
1808
+ source_location: tuple[int, int],
1809
+ ) -> None:
1810
+ """Initialize dictionary contains check.
1811
+
1812
+ Args:
1813
+ dest: Destination temp for the boolean result.
1814
+ dict_val: The dictionary to check.
1815
+ key: The key to look for.
1816
+ source_location: Source code location (line, column).
1817
+ """
1818
+ super().__init__(source_location)
1819
+ self.dest = dest
1820
+ self.dict_val = dict_val
1821
+ self.key = key
1822
+
1823
+ def __str__(self) -> str:
1824
+ """Return string representation."""
1825
+ return f"{self.dest} = {self.key} in {self.dict_val}"
1826
+
1827
+ def get_uses(self) -> list[MIRValue]:
1828
+ """Get operands used."""
1829
+ return [self.dict_val, self.key]
1830
+
1831
+ def get_defs(self) -> list[MIRValue]:
1832
+ """Get defined value."""
1833
+ return [self.dest]
1834
+
1835
+ def replace_use(self, old: MIRValue, new: MIRValue) -> None:
1836
+ """Replace uses of a value."""
1837
+ if self.dict_val == old:
1838
+ self.dict_val = new
1839
+ if self.key == old:
1840
+ self.key = new
1841
+
1842
+
1843
+ class DictClear(MIRInstruction):
1844
+ """Clear all entries from dictionary: dict.clear()."""
1845
+
1846
+ def __init__(
1847
+ self,
1848
+ dict_val: MIRValue,
1849
+ source_location: tuple[int, int],
1850
+ ) -> None:
1851
+ """Initialize dictionary clear operation.
1852
+
1853
+ Args:
1854
+ dict_val: The dictionary to clear.
1855
+ source_location: Source code location (line, column).
1856
+ """
1857
+ super().__init__(source_location)
1858
+ self.dict_val = dict_val
1859
+ self.has_side_effects = True
1860
+ self.cost = 2
1861
+
1862
+ def __str__(self) -> str:
1863
+ """String representation for debugging."""
1864
+ return f"DictClear {self.dict_val}"
1865
+
1866
+ def get_uses(self) -> list[MIRValue]:
1867
+ """Get operands used."""
1868
+ return [self.dict_val]
1869
+
1870
+ def get_defs(self) -> list[MIRValue]:
1871
+ """Get defined values."""
1872
+ return [] # Modifies dict in-place
1873
+
1874
+ def replace_use(self, old: MIRValue, new: MIRValue) -> None:
1875
+ """Replace uses of a value."""
1876
+ if self.dict_val == old:
1877
+ self.dict_val = new