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,389 @@
1
+ """Comprehensive tests for HIR to MIR lowering with full AST coverage."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from machine_dialect.ast import (
6
+ ActionStatement,
7
+ BlockStatement,
8
+ ConditionalExpression,
9
+ ErrorExpression,
10
+ ErrorStatement,
11
+ ExpressionStatement,
12
+ Identifier,
13
+ IfStatement,
14
+ InfixExpression,
15
+ InteractionStatement,
16
+ Parameter,
17
+ PrefixExpression,
18
+ Program,
19
+ ReturnStatement,
20
+ SayStatement,
21
+ SetStatement,
22
+ StringLiteral,
23
+ URLLiteral,
24
+ UtilityStatement,
25
+ WholeNumberLiteral,
26
+ YesNoLiteral,
27
+ )
28
+ from machine_dialect.lexer import Token, TokenType
29
+ from machine_dialect.mir.hir_to_mir import HIRToMIRLowering, lower_to_mir
30
+ from machine_dialect.mir.mir_instructions import (
31
+ Assert,
32
+ BinaryOp,
33
+ ConditionalJump,
34
+ LoadConst,
35
+ MIRInstruction,
36
+ Print,
37
+ Scope,
38
+ Select,
39
+ UnaryOp,
40
+ )
41
+ from machine_dialect.mir.mir_types import MIRType
42
+ from machine_dialect.mir.mir_values import Constant
43
+
44
+
45
+ class TestHIRToMIRComplete:
46
+ """Test complete HIR to MIR lowering with all AST node types."""
47
+
48
+ def setup_method(self) -> None:
49
+ """Set up test fixtures."""
50
+ self.lowerer = HIRToMIRLowering()
51
+
52
+ def _dummy_token(self, literal: str = "", token_type: TokenType = TokenType.MISC_IDENT) -> Token:
53
+ """Create a dummy token for testing."""
54
+ return Token(token_type, literal, 0, 0)
55
+
56
+ def test_error_statement_lowering(self) -> None:
57
+ """Test lowering of ErrorStatement."""
58
+ # Create error statement
59
+ error_stmt = ErrorStatement(
60
+ self._dummy_token("error"), skipped_tokens=[], message="Syntax error: unexpected token"
61
+ )
62
+
63
+ # Create program with error
64
+ program = Program([error_stmt])
65
+
66
+ # Lower to MIR
67
+ mir = lower_to_mir(program)
68
+
69
+ # Should have main function
70
+ assert mir.get_function("__main__") is not None
71
+ main = mir.get_function("__main__")
72
+
73
+ # Should have entry block with Assert instruction
74
+ assert main is not None
75
+ entry = main.cfg.entry_block
76
+ assert entry is not None
77
+
78
+ # Find Assert instruction
79
+ assert entry is not None
80
+ asserts = [inst for inst in entry.instructions if isinstance(inst, Assert)]
81
+ assert len(asserts) == 1
82
+ assert asserts[0].message is not None
83
+ assert "Parse error" in asserts[0].message
84
+
85
+ # Should have entry block with Assert instruction
86
+ entry2 = main.cfg.entry_block
87
+ assert entry2 is not None
88
+
89
+ # Find Assert instruction
90
+ assert entry2 is not None
91
+ asserts2 = [inst for inst in entry2.instructions if isinstance(inst, Assert)]
92
+ assert len(asserts2) == 1
93
+ assert asserts2[0].message is not None
94
+ assert "Parse error" in asserts2[0].message
95
+
96
+ def test_error_expression_lowering(self) -> None:
97
+ """Test lowering of ErrorExpression."""
98
+ # Create error expression in a statement
99
+ error_expr = ErrorExpression(self._dummy_token("error"), message="Invalid expression")
100
+ expr_stmt = ExpressionStatement(self._dummy_token(), error_expr)
101
+
102
+ # Create program
103
+ program = Program([expr_stmt])
104
+
105
+ # Lower to MIR
106
+ mir = lower_to_mir(program)
107
+
108
+ # Should have Assert for error expression
109
+ main = mir.get_function("__main__")
110
+ assert main is not None
111
+ entry = main.cfg.entry_block
112
+ assert entry is not None
113
+ asserts = [inst for inst in entry.instructions if isinstance(inst, Assert)]
114
+ assert any(a.message and "Expression error" in a.message for a in asserts)
115
+
116
+ def test_conditional_expression_lowering(self) -> None:
117
+ """Test lowering of ConditionalExpression (ternary)."""
118
+ # Create: x = true ? 1 : 2
119
+ condition = YesNoLiteral(self._dummy_token("true"), True)
120
+ true_val = WholeNumberLiteral(self._dummy_token("1"), 1)
121
+ false_val = WholeNumberLiteral(self._dummy_token("2"), 2)
122
+
123
+ cond_expr = ConditionalExpression(self._dummy_token(), true_val)
124
+ cond_expr.condition = condition
125
+ cond_expr.alternative = false_val
126
+
127
+ set_stmt = SetStatement(self._dummy_token("set"), Identifier(self._dummy_token("x"), "x"), cond_expr)
128
+
129
+ program = Program([set_stmt])
130
+ mir = lower_to_mir(program)
131
+
132
+ # Should have Select instruction
133
+ main = mir.get_function("__main__")
134
+ assert main is not None
135
+ entry = main.cfg.entry_block
136
+ assert entry is not None
137
+ selects = [inst for inst in entry.instructions if isinstance(inst, Select)]
138
+ assert len(selects) == 1
139
+
140
+ def test_say_statement_lowering(self) -> None:
141
+ """Test lowering of SayStatement."""
142
+ # Create: Say "Hello"
143
+ say_stmt = SayStatement(self._dummy_token("say"), StringLiteral(self._dummy_token('"Hello"'), "Hello"))
144
+
145
+ program = Program([say_stmt])
146
+ mir = lower_to_mir(program)
147
+
148
+ # Should have Print instruction
149
+ main = mir.get_function("__main__")
150
+ assert main is not None
151
+ entry = main.cfg.entry_block
152
+ assert entry is not None
153
+ prints = [inst for inst in entry.instructions if isinstance(inst, Print)]
154
+ assert len(prints) == 1
155
+
156
+ def test_block_statement_with_scope(self) -> None:
157
+ """Test that BlockStatement generates scope instructions."""
158
+ # Create block with statements
159
+ stmt1 = SetStatement(
160
+ self._dummy_token("set"),
161
+ Identifier(self._dummy_token("x"), "x"),
162
+ WholeNumberLiteral(self._dummy_token("1"), 1),
163
+ )
164
+
165
+ block = BlockStatement(self._dummy_token(), depth=1)
166
+ block.statements = [stmt1]
167
+
168
+ program = Program([block])
169
+ mir = lower_to_mir(program)
170
+
171
+ # Should have Scope instructions
172
+ main = mir.get_function("__main__")
173
+ assert main is not None
174
+ entry = main.cfg.entry_block
175
+ assert entry is not None
176
+ scopes = [inst for inst in entry.instructions if isinstance(inst, Scope)]
177
+
178
+ # Should have begin and end scope
179
+ assert len(scopes) == 2
180
+ assert scopes[0].is_begin
181
+ assert not scopes[1].is_begin
182
+
183
+ def test_action_statement_lowering(self) -> None:
184
+ """Test lowering of ActionStatement (private method)."""
185
+ # Create action
186
+ body_block = BlockStatement(self._dummy_token())
187
+ body_block.statements = [ReturnStatement(self._dummy_token("return"), None)]
188
+ action = ActionStatement(
189
+ self._dummy_token("action"),
190
+ name=Identifier(self._dummy_token("doWork"), "doWork"),
191
+ inputs=[],
192
+ outputs=None,
193
+ body=body_block,
194
+ )
195
+
196
+ program = Program([action])
197
+ mir = lower_to_mir(program)
198
+
199
+ # Should have function with EMPTY return type
200
+ func = mir.get_function("doWork")
201
+ assert func is not None
202
+ assert func is not None
203
+ assert func.return_type == MIRType.EMPTY
204
+
205
+ def test_interaction_statement_lowering(self) -> None:
206
+ """Test lowering of InteractionStatement (public method)."""
207
+ # Create interaction
208
+ body_block = BlockStatement(self._dummy_token())
209
+ body_block.statements = []
210
+ interaction = InteractionStatement(
211
+ self._dummy_token("interaction"),
212
+ name=Identifier(self._dummy_token("handleRequest"), "handleRequest"),
213
+ inputs=[
214
+ Parameter(self._dummy_token("input"), Identifier(self._dummy_token("input"), "input"), "", True, None)
215
+ ],
216
+ outputs=None,
217
+ body=body_block,
218
+ )
219
+
220
+ program = Program([interaction])
221
+ mir = lower_to_mir(program)
222
+
223
+ # Should have function with parameter
224
+ func = mir.get_function("handleRequest")
225
+ assert func is not None
226
+ assert func is not None
227
+ assert len(func.params) == 1
228
+ assert func.params[0].name == "input"
229
+
230
+ def test_utility_statement_lowering(self) -> None:
231
+ """Test lowering of UtilityStatement (function with return)."""
232
+ # Create utility that returns a value
233
+ body_block = BlockStatement(self._dummy_token())
234
+ body_block.statements = [
235
+ ReturnStatement(self._dummy_token("return"), WholeNumberLiteral(self._dummy_token("42"), 42))
236
+ ]
237
+ utility = UtilityStatement(
238
+ self._dummy_token("utility"),
239
+ name=Identifier(self._dummy_token("calculate"), "calculate"),
240
+ inputs=[],
241
+ outputs=None,
242
+ body=body_block,
243
+ )
244
+
245
+ program = Program([utility])
246
+ mir = lower_to_mir(program)
247
+
248
+ # Should have function with UNKNOWN return type (can return values)
249
+ func = mir.get_function("calculate")
250
+ assert func is not None
251
+ assert func is not None
252
+ assert func.return_type == MIRType.UNKNOWN
253
+
254
+ def test_url_literal_lowering(self) -> None:
255
+ """Test lowering of URLLiteral."""
256
+ # Create: x = https://example.com
257
+ url = URLLiteral(self._dummy_token("https://example.com"), "https://example.com")
258
+ set_stmt = SetStatement(self._dummy_token("set"), Identifier(self._dummy_token("x"), "x"), url)
259
+
260
+ program = Program([set_stmt])
261
+ mir = lower_to_mir(program)
262
+
263
+ # Should create constant with URL type
264
+ main = mir.get_function("__main__")
265
+ assert main is not None
266
+
267
+ # Check for LoadConst with URL
268
+ main = mir.get_function("__main__")
269
+ assert main is not None
270
+ assert main is not None
271
+ entry = main.cfg.entry_block
272
+ assert entry is not None
273
+ loads = [inst for inst in entry.instructions if isinstance(inst, LoadConst)]
274
+ assert any(
275
+ isinstance(inst.constant, Constant) and inst.constant.value == "https://example.com" for inst in loads
276
+ )
277
+
278
+ def test_complex_control_flow(self) -> None:
279
+ """Test complex control flow with nested if statements."""
280
+ # Create nested if: if (x > 0) { if (x < 10) { y = x } else { y = 10 } }
281
+ x_ident = Identifier(self._dummy_token("x"), "x")
282
+ y_ident = Identifier(self._dummy_token("y"), "y")
283
+
284
+ # Outer condition: x > 0
285
+ outer_cond = InfixExpression(self._dummy_token(">"), ">", x_ident)
286
+ outer_cond.right = WholeNumberLiteral(self._dummy_token("0"), 0)
287
+
288
+ # Inner condition: x < 10
289
+ inner_cond = InfixExpression(self._dummy_token("<"), "<", x_ident)
290
+ inner_cond.right = WholeNumberLiteral(self._dummy_token("10"), 10)
291
+
292
+ # Inner then: y = x
293
+ inner_then = BlockStatement(self._dummy_token())
294
+ inner_then.statements = [SetStatement(self._dummy_token("set"), y_ident, x_ident)]
295
+
296
+ # Inner else: y = 10
297
+ inner_else = BlockStatement(self._dummy_token())
298
+ inner_else.statements = [
299
+ SetStatement(self._dummy_token("set"), y_ident, WholeNumberLiteral(self._dummy_token("10"), 10))
300
+ ]
301
+
302
+ # Inner if
303
+ inner_if = IfStatement(self._dummy_token("if"), inner_cond)
304
+ inner_if.consequence = inner_then
305
+ inner_if.alternative = inner_else
306
+
307
+ # Outer then contains inner if
308
+ outer_then = BlockStatement(self._dummy_token())
309
+ outer_then.statements = [inner_if]
310
+
311
+ # Outer if
312
+ outer_if = IfStatement(self._dummy_token("if"), outer_cond)
313
+ outer_if.consequence = outer_then
314
+ outer_if.alternative = None
315
+
316
+ # Initialize x
317
+ init_x = SetStatement(self._dummy_token("set"), x_ident, WholeNumberLiteral(self._dummy_token("5"), 5))
318
+
319
+ program = Program([init_x, outer_if])
320
+ mir = lower_to_mir(program)
321
+
322
+ # Should have multiple basic blocks
323
+ main = mir.get_function("__main__")
324
+ assert main is not None
325
+ assert len(main.cfg.blocks) > 3 # At least entry + branches
326
+
327
+ # Should have conditional jumps
328
+ all_instructions: list[MIRInstruction] = []
329
+ for block in main.cfg.blocks.values():
330
+ all_instructions.extend(block.instructions)
331
+
332
+ cond_jumps = [inst for inst in all_instructions if isinstance(inst, ConditionalJump)]
333
+ assert len(cond_jumps) >= 2 # At least 2 for nested ifs
334
+
335
+ def test_all_binary_operators(self) -> None:
336
+ """Test all binary operators are properly lowered."""
337
+ operators = ["+", "-", "*", "/", "%", "^", "==", "!=", "<", ">", "<=", ">=", "and", "or"]
338
+
339
+ for op in operators:
340
+ # Create: result = 10 op 5
341
+ expr = InfixExpression(self._dummy_token(op), op, WholeNumberLiteral(self._dummy_token("10"), 10))
342
+ expr.right = WholeNumberLiteral(self._dummy_token("5"), 5)
343
+
344
+ set_stmt = SetStatement(self._dummy_token("set"), Identifier(self._dummy_token("result"), "result"), expr)
345
+
346
+ program = Program([set_stmt])
347
+ mir = lower_to_mir(program)
348
+
349
+ # Should have BinaryOp with correct operator
350
+ main = mir.get_function("__main__")
351
+ assert main is not None, f"Failed for operator {op}"
352
+ entry = main.cfg.entry_block
353
+ assert entry is not None, f"Failed for operator {op}"
354
+ binops = [inst for inst in entry.instructions if isinstance(inst, BinaryOp)]
355
+ # ^ in AST becomes ** in MIR
356
+ expected_op = "**" if op == "^" else op
357
+ assert any(inst.op == expected_op for inst in binops), f"Failed for operator {op}"
358
+
359
+ def test_unary_operators(self) -> None:
360
+ """Test unary operators are properly lowered."""
361
+ # Test negation: -5
362
+ neg_expr = PrefixExpression(self._dummy_token("-"), "-")
363
+ neg_expr.right = WholeNumberLiteral(self._dummy_token("5"), 5)
364
+
365
+ # Test not: not true
366
+ not_expr = PrefixExpression(self._dummy_token("not"), "not")
367
+ not_expr.right = YesNoLiteral(self._dummy_token("true"), True)
368
+
369
+ program = Program(
370
+ [
371
+ SetStatement(self._dummy_token("set"), Identifier(self._dummy_token("x"), "x"), neg_expr),
372
+ SetStatement(self._dummy_token("set"), Identifier(self._dummy_token("y"), "y"), not_expr),
373
+ ]
374
+ )
375
+
376
+ mir = lower_to_mir(program)
377
+ main = mir.get_function("__main__")
378
+ assert main is not None
379
+ entry = main.cfg.entry_block
380
+ assert entry is not None
381
+
382
+ # Should have UnaryOp instructions
383
+ unaryops = [inst for inst in entry.instructions if isinstance(inst, UnaryOp)]
384
+ assert len(unaryops) == 2
385
+
386
+ # Check operators
387
+ ops = {inst.op for inst in unaryops}
388
+ assert "-" in ops
389
+ assert "not" in ops
@@ -0,0 +1,130 @@
1
+ """Simplified tests for HIR to MIR lowering without token dependencies."""
2
+
3
+ from machine_dialect.mir.hir_to_mir import HIRToMIRLowering
4
+ from machine_dialect.mir.mir_types import MIRType
5
+
6
+
7
+ class TestHIRToMIRSimple:
8
+ """Simplified tests for HIR to MIR lowering."""
9
+
10
+ def test_lowering_initialization(self) -> None:
11
+ """Test that the lowering class can be initialized."""
12
+ lowerer = HIRToMIRLowering()
13
+ assert lowerer.module is None
14
+ assert lowerer.current_function is None
15
+ assert lowerer.current_block is None
16
+ assert lowerer.variable_map == {}
17
+ assert lowerer.label_counter == 0
18
+
19
+ def test_generate_label(self) -> None:
20
+ """Test label generation."""
21
+ lowerer = HIRToMIRLowering()
22
+
23
+ label1 = lowerer.generate_label("test")
24
+ assert label1 == "test_0"
25
+
26
+ label2 = lowerer.generate_label("test")
27
+ assert label2 == "test_1"
28
+
29
+ label3 = lowerer.generate_label("loop")
30
+ assert label3 == "loop_2"
31
+
32
+ def test_mir_module_creation(self) -> None:
33
+ """Test that a MIR module can be created."""
34
+ from machine_dialect.mir.mir_module import MIRModule
35
+
36
+ module = MIRModule("test_module")
37
+ assert module.name == "test_module"
38
+ assert len(module.functions) == 0
39
+ assert module.main_function is None
40
+
41
+ def test_mir_function_creation(self) -> None:
42
+ """Test that a MIR function can be created."""
43
+ from machine_dialect.mir.mir_function import MIRFunction
44
+ from machine_dialect.mir.mir_values import Variable
45
+
46
+ params = [Variable("x", MIRType.INT), Variable("y", MIRType.INT)]
47
+ func = MIRFunction("add", params, MIRType.INT)
48
+
49
+ assert func.name == "add"
50
+ assert len(func.params) == 2
51
+ assert func.return_type == MIRType.INT
52
+ assert func.cfg is not None
53
+
54
+ def test_basic_lowering_flow(self) -> None:
55
+ """Test the basic flow of lowering without actual AST nodes."""
56
+ from machine_dialect.mir.basic_block import BasicBlock
57
+ from machine_dialect.mir.mir_function import MIRFunction
58
+ from machine_dialect.mir.mir_instructions import LoadConst, Return
59
+ from machine_dialect.mir.mir_module import MIRModule
60
+
61
+ # Create a simple module with one function manually
62
+ module = MIRModule("test")
63
+
64
+ # Create a simple function
65
+ func = MIRFunction("main", [], MIRType.INT)
66
+
67
+ # Create entry block
68
+ entry = BasicBlock("entry")
69
+ func.cfg.add_block(entry)
70
+ func.cfg.set_entry_block(entry)
71
+
72
+ # Add some instructions
73
+ t0 = func.new_temp(MIRType.INT)
74
+ entry.add_instruction(LoadConst(t0, 42, (1, 1)))
75
+ entry.add_instruction(Return((1, 1), t0))
76
+
77
+ # Add function to module
78
+ module.add_function(func)
79
+ module.set_main_function("main")
80
+
81
+ # Verify structure
82
+ assert module.name == "test"
83
+ assert len(module.functions) == 1
84
+ assert module.main_function == "main"
85
+
86
+ main_func = module.get_function("main")
87
+ assert main_func is not None
88
+ assert main_func.cfg.entry_block is not None
89
+
90
+ assert len(main_func.cfg.entry_block.instructions) == 2
91
+ assert isinstance(main_func.cfg.entry_block.instructions[0], LoadConst)
92
+ assert isinstance(main_func.cfg.entry_block.instructions[1], Return)
93
+
94
+ def test_control_flow_structure(self) -> None:
95
+ """Test creating control flow structures in MIR."""
96
+ from machine_dialect.mir.basic_block import BasicBlock
97
+ from machine_dialect.mir.mir_function import MIRFunction
98
+ from machine_dialect.mir.mir_instructions import ConditionalJump, LoadConst
99
+ from machine_dialect.mir.mir_types import MIRType
100
+
101
+ func = MIRFunction("test_cf", [], MIRType.INT)
102
+
103
+ # Create blocks
104
+ entry = BasicBlock("entry")
105
+ then_block = BasicBlock("then")
106
+ else_block = BasicBlock("else")
107
+ merge_block = BasicBlock("merge")
108
+
109
+ # Add blocks to CFG
110
+ func.cfg.add_block(entry)
111
+ func.cfg.add_block(then_block)
112
+ func.cfg.add_block(else_block)
113
+ func.cfg.add_block(merge_block)
114
+ func.cfg.set_entry_block(entry)
115
+
116
+ # Create condition
117
+ cond = func.new_temp(MIRType.BOOL)
118
+ entry.add_instruction(LoadConst(cond, True, (1, 1)))
119
+ entry.add_instruction(ConditionalJump(cond, "then", (1, 1), "else"))
120
+
121
+ # Connect blocks
122
+ func.cfg.connect(entry, then_block)
123
+ func.cfg.connect(entry, else_block)
124
+ func.cfg.connect(then_block, merge_block)
125
+ func.cfg.connect(else_block, merge_block)
126
+
127
+ # Verify structure
128
+ assert len(func.cfg.blocks) == 4
129
+ assert len(entry.successors) == 2
130
+ assert len(merge_block.predecessors) == 2