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,173 @@
1
+ """VM Runner - Manages Rust VM execution for Machine Dialectâ„¢.
2
+
3
+ This module provides the integration layer between the Python compiler
4
+ pipeline and the Rust VM for executing Machine Dialectâ„¢ programs.
5
+ """
6
+
7
+ from __future__ import annotations
8
+
9
+ import tempfile
10
+ from pathlib import Path
11
+ from typing import Any
12
+
13
+ from machine_dialect.codegen.register_codegen import (
14
+ RegisterBytecodeGenerator,
15
+ )
16
+ from machine_dialect.compiler.config import CompilerConfig
17
+ from machine_dialect.compiler.context import CompilationContext
18
+ from machine_dialect.compiler.phases.hir_generation import HIRGenerationPhase
19
+ from machine_dialect.compiler.phases.mir_generation import MIRGenerationPhase
20
+ from machine_dialect.mir.mir_module import MIRModule
21
+ from machine_dialect.mir.optimize_mir import optimize_mir
22
+ from machine_dialect.parser.parser import Parser
23
+
24
+
25
+ class VMRunner:
26
+ """Manages compilation and execution of Machine Dialectâ„¢ code on the Rust VM.
27
+
28
+ This class provides a high-level interface for:
29
+ 1. Compiling Machine Dialectâ„¢ source to bytecode
30
+ 2. Loading bytecode into the Rust VM
31
+ 3. Executing programs and returning results
32
+ """
33
+
34
+ def __init__(self, debug: bool = False, optimize: bool = False) -> None:
35
+ """Initialize the VM runner.
36
+
37
+ Args:
38
+ debug: Enable debug output
39
+ optimize: Enable MIR optimizations
40
+ """
41
+ self.debug = debug
42
+ self.optimize = optimize
43
+ self.vm: Any = None
44
+ self._init_vm()
45
+
46
+ def _init_vm(self) -> None:
47
+ """Initialize the Rust VM instance."""
48
+ try:
49
+ import machine_dialect_vm
50
+
51
+ self.vm = machine_dialect_vm.RustVM()
52
+ if self.debug:
53
+ self.vm.set_debug(True)
54
+ except ImportError as e:
55
+ raise RuntimeError(
56
+ "Rust VM module not available. Please build it first:\n"
57
+ " ./build_vm.sh\n"
58
+ "or manually:\n"
59
+ " cd machine_dialect_vm && maturin develop --features pyo3"
60
+ ) from e
61
+
62
+ def compile_to_bytecode(self, source: str, source_path: Path | None = None) -> bytes:
63
+ """Compile Machine Dialectâ„¢ source code to bytecode.
64
+
65
+ Args:
66
+ source: Machine Dialectâ„¢ source code
67
+ source_path: Optional path to source file
68
+
69
+ Returns:
70
+ Serialized bytecode ready for VM execution
71
+
72
+ Raises:
73
+ CompilationError: If compilation fails at any stage
74
+ """
75
+ if source_path is None:
76
+ source_path = Path("<repl>")
77
+
78
+ # Step 1: Parse to AST
79
+ parser = Parser()
80
+ ast = parser.parse(source)
81
+ if ast is None:
82
+ raise ValueError("Failed to parse source code")
83
+
84
+ # Step 2: Generate HIR
85
+ config = CompilerConfig(verbose=self.debug)
86
+ context = CompilationContext(source_path=source_path, config=config, source_content=source)
87
+ hir_phase = HIRGenerationPhase()
88
+ hir = hir_phase.run(context, ast)
89
+ if hir is None:
90
+ raise ValueError("Failed to generate HIR")
91
+
92
+ # Step 3: Generate MIR
93
+ mir_phase = MIRGenerationPhase()
94
+ mir_module = mir_phase.run(context, hir)
95
+ if mir_module is None:
96
+ raise ValueError("Failed to generate MIR")
97
+
98
+ # Step 4: Optimize MIR (if enabled)
99
+ if self.optimize:
100
+ mir_module, _ = optimize_mir(mir_module)
101
+
102
+ # Step 5: Generate bytecode
103
+ return self._mir_to_bytecode(mir_module)
104
+
105
+ def _mir_to_bytecode(self, mir_module: MIRModule) -> bytes:
106
+ """Convert MIR module to bytecode.
107
+
108
+ Args:
109
+ mir_module: The MIR module to convert
110
+
111
+ Returns:
112
+ Serialized bytecode
113
+ """
114
+ # Generate bytecode
115
+ generator = RegisterBytecodeGenerator()
116
+ bytecode_module = generator.generate(mir_module)
117
+
118
+ # Serialize to bytes
119
+ return bytecode_module.serialize()
120
+
121
+ def execute(self, source: str) -> Any:
122
+ """Compile and execute Machine Dialectâ„¢ source code.
123
+
124
+ Args:
125
+ source: Machine Dialectâ„¢ source code
126
+
127
+ Returns:
128
+ The result of program execution
129
+
130
+ Raises:
131
+ RuntimeError: If execution fails
132
+ """
133
+ # Compile to bytecode
134
+ bytecode = self.compile_to_bytecode(source)
135
+
136
+ # Write to temporary file (VM loads from file)
137
+ with tempfile.NamedTemporaryFile(suffix=".mdbc", delete=False) as f:
138
+ f.write(bytecode)
139
+ bytecode_path = f.name
140
+
141
+ try:
142
+ # Load and execute in VM
143
+ self.vm.load_bytecode(bytecode_path)
144
+ result = self.vm.execute()
145
+ return result
146
+ finally:
147
+ # Clean up temporary file
148
+ Path(bytecode_path).unlink(missing_ok=True)
149
+
150
+ def execute_bytecode(self, bytecode: bytes) -> Any:
151
+ """Execute pre-compiled bytecode.
152
+
153
+ Args:
154
+ bytecode: Serialized bytecode
155
+
156
+ Returns:
157
+ The result of program execution
158
+ """
159
+ # Write to temporary file
160
+ with tempfile.NamedTemporaryFile(suffix=".mdbc", delete=False) as f:
161
+ f.write(bytecode)
162
+ bytecode_path = f.name
163
+
164
+ try:
165
+ self.vm.load_bytecode(bytecode_path)
166
+ result = self.vm.execute()
167
+ return result
168
+ finally:
169
+ Path(bytecode_path).unlink(missing_ok=True)
170
+
171
+ def reset(self) -> None:
172
+ """Reset the VM to initial state."""
173
+ self._init_vm()
@@ -0,0 +1,32 @@
1
+ """Error handling for Machine Dialectâ„¢.
2
+
3
+ This package provides exception classes and error reporting utilities.
4
+ """
5
+
6
+ from machine_dialect.errors.exceptions import (
7
+ MDException,
8
+ MDNameError,
9
+ MDSyntaxError,
10
+ MDTypeError,
11
+ MDUninitializedError,
12
+ MDValueError,
13
+ )
14
+ from machine_dialect.errors.messages import (
15
+ EXPECTED_BLOCK_MARKER,
16
+ EXPECTED_EXPRESSION,
17
+ EXPECTED_PREFIX_OPERATOR,
18
+ UNEXPECTED_TOKEN,
19
+ )
20
+
21
+ __all__ = [
22
+ "EXPECTED_BLOCK_MARKER",
23
+ "EXPECTED_EXPRESSION",
24
+ "EXPECTED_PREFIX_OPERATOR",
25
+ "UNEXPECTED_TOKEN",
26
+ "MDException",
27
+ "MDNameError",
28
+ "MDSyntaxError",
29
+ "MDTypeError",
30
+ "MDUninitializedError",
31
+ "MDValueError",
32
+ ]
@@ -0,0 +1,369 @@
1
+ """Machine Dialectâ„¢ exception classes.
2
+
3
+ This module defines the exception hierarchy for the Machine Dialectâ„¢ language.
4
+ All exceptions inherit from MDBaseException, which provides a common base
5
+ for error handling throughout the system.
6
+ """
7
+
8
+ from abc import ABC, abstractmethod
9
+ from typing import Any
10
+
11
+ from machine_dialect.errors.messages import ErrorTemplate
12
+
13
+
14
+ class MDBaseException(ABC):
15
+ """Base Machine Dialectâ„¢ Exception.
16
+
17
+ The base class for all built-in Machine Dialectâ„¢ exceptions.
18
+ This is an abstract base class and should not be instantiated directly.
19
+
20
+ Attributes:
21
+ message (str): The error message.
22
+ line (int, optional): The line number where the error occurred.
23
+ column (int, optional): The column number where the error occurred.
24
+ filename (str, optional): The filename where the error occurred.
25
+
26
+ Note:
27
+ This is a pure ABC that does not inherit from Python's Exception.
28
+ These exceptions represent errors in Machine Dialectâ„¢ code, not Python code.
29
+ """
30
+
31
+ def __init__(
32
+ self, message: ErrorTemplate, line: int, column: int, filename: str | None = None, **kwargs: Any
33
+ ) -> None:
34
+ """Initialize the Machine Dialectâ„¢ exception.
35
+
36
+ Args:
37
+ message: The error message template.
38
+ line: The line number where the error occurred.
39
+ column: The column number where the error occurred.
40
+ filename: The filename where the error occurred.
41
+ **kwargs: Template substitution parameters.
42
+ """
43
+ # Format the message with any provided kwargs
44
+ # If no kwargs, call substitute with empty dict to get the template with no substitutions
45
+ self._message = message.format(**kwargs) if kwargs else message.substitute()
46
+ self._line = line
47
+ self._column = column
48
+ self._filename = filename or "<standard-input>"
49
+
50
+ def __str__(self) -> str:
51
+ """Return string representation of the exception.
52
+
53
+ Returns:
54
+ A formatted error message with location information if available.
55
+ """
56
+ parts = []
57
+ if self._filename:
58
+ parts.append(f'File "{self._filename}"')
59
+ if self._line is not None:
60
+ parts.append(f"line {self._line}")
61
+ if self._column is not None:
62
+ parts.append(f"column {self._column}")
63
+
64
+ location = ", ".join(parts)
65
+ if location:
66
+ return f"{location}: {self._message}"
67
+ return self._message
68
+
69
+ def __repr__(self) -> str:
70
+ """Return detailed representation of the exception.
71
+
72
+ Returns:
73
+ A string showing the exception class and all attributes.
74
+ """
75
+ mydict = {
76
+ "message": self._message.__repr__(),
77
+ "line": self._line,
78
+ "column": self._column,
79
+ "filename": self._filename.__repr__(),
80
+ }
81
+ concatenated = ", ".join([f"{k}={v}" for k, v in mydict.items()])
82
+ return f"{self.__class__.__name__}({concatenated})"
83
+
84
+ @abstractmethod
85
+ def error_type(self) -> str:
86
+ """Return the error type identifier for this exception.
87
+
88
+ This should return a string that identifies the type of error
89
+ in Machine Dialectâ„¢ terms (e.g., "SyntaxError", "NameError").
90
+
91
+ Returns:
92
+ The error type as a string.
93
+ """
94
+ pass
95
+
96
+
97
+ class MDException(MDBaseException):
98
+ """General Machine Dialectâ„¢ Exception.
99
+
100
+ This is the base class for all non-syntax Machine Dialectâ„¢ exceptions.
101
+ It provides a concrete implementation of MDBaseException that can be
102
+ instantiated directly for general errors.
103
+
104
+ Note:
105
+ Most specific error conditions should use a more specialized
106
+ exception subclass when available.
107
+ """
108
+
109
+ def error_type(self) -> str:
110
+ """Return the error type identifier.
111
+
112
+ Returns:
113
+ "Exception" for general Machine Dialectâ„¢ exceptions.
114
+ """
115
+ return "Exception"
116
+
117
+
118
+ class MDDivisionByZero(MDException):
119
+ """Raised when a division or modulo operation has zero as divisor.
120
+
121
+ This exception is raised when attempting to divide by zero or perform
122
+ a modulo operation with zero as the divisor.
123
+
124
+ Example:
125
+ >>> 10 / 0
126
+ Traceback (most recent call last):
127
+ ...
128
+ MDDivisionByZero: division by zero
129
+
130
+ >>> 10 % 0
131
+ Traceback (most recent call last):
132
+ ...
133
+ MDDivisionByZero: integer division or modulo by zero
134
+ """
135
+
136
+
137
+ class MDAssertionError(MDException):
138
+ """Raised when an assertion fails.
139
+
140
+ This exception is raised when an assert statement fails in Machine Dialectâ„¢ code.
141
+ It corresponds to Python's built-in AssertionError.
142
+
143
+ Example:
144
+ >>> assert False, "This will raise MDAssertionError"
145
+ Traceback (most recent call last):
146
+ ...
147
+ MDAssertionError: This will raise MDAssertionError
148
+ """
149
+
150
+
151
+ class MDSystemExit(MDException):
152
+ """Raised to exit from the Machine Dialectâ„¢ interpreter.
153
+
154
+ This exception is used to exit from the interpreter or terminate
155
+ program execution. It corresponds to Python's SystemExit.
156
+
157
+ Attributes:
158
+ code (int | str | None): The exit status code. If None, defaults to 0.
159
+ An integer gives the exit status (0 means success).
160
+ A string prints the message to stderr and exits with status 1.
161
+
162
+ Example:
163
+ >>> exit(0) # Normal termination
164
+ >>> exit(1) # Termination with error
165
+ >>> exit("Error message") # Print message and exit with status 1
166
+ """
167
+
168
+
169
+ class MDNameError(MDException):
170
+ """Raised when a name is not found in any scope.
171
+
172
+ This exception is raised when a local or global name is not found.
173
+ This applies to unqualified names within functions, methods, or
174
+ the global scope.
175
+
176
+ Attributes:
177
+ name (str, optional): The name that could not be found.
178
+
179
+ Example:
180
+ >>> print(undefined_variable)
181
+ Traceback (most recent call last):
182
+ ...
183
+ MDNameError: name 'undefined_variable' is not defined
184
+
185
+ >>> del nonexistent
186
+ Traceback (most recent call last):
187
+ ...
188
+ MDNameError: name 'nonexistent' is not defined
189
+ """
190
+
191
+ def __init__(self, message: str | ErrorTemplate, line: int = 0, column: int = 0, **kwargs: Any) -> None:
192
+ """Initialize name error.
193
+
194
+ Args:
195
+ message: Error message string or ErrorTemplate
196
+ line: Line number where error occurred
197
+ column: Column position where error occurred
198
+ **kwargs: Additional template parameters if message is ErrorTemplate
199
+ """
200
+ if isinstance(message, str):
201
+ # Create a simple ErrorTemplate from the string
202
+ from machine_dialect.errors.messages import ErrorTemplate
203
+
204
+ template = ErrorTemplate(message)
205
+ super().__init__(template, line, column, **kwargs)
206
+ else:
207
+ super().__init__(message, line, column, **kwargs)
208
+
209
+
210
+ class MDSyntaxError(MDException):
211
+ """Raised when a syntax error is encountered.
212
+
213
+ This exception is raised when the parser encounters syntactically
214
+ incorrect Machine Dialectâ„¢ code. This includes malformed expressions,
215
+ invalid statement structure, or improper use of keywords.
216
+
217
+ Example:
218
+ >>> if x = 5: # Should use 'is' for comparison
219
+ ... pass
220
+ Traceback (most recent call last):
221
+ ...
222
+ MDSyntaxError: invalid syntax
223
+
224
+ >>> def function(
225
+ ... # Missing closing parenthesis
226
+ Traceback (most recent call last):
227
+ ...
228
+ MDSyntaxError: unexpected EOF while parsing
229
+ """
230
+
231
+
232
+ class MDTypeError(MDException):
233
+ """Raised when an operation is applied to an inappropriate type.
234
+
235
+ This exception is raised when an operation or function is applied to
236
+ an object of inappropriate type. It can occur during parsing when
237
+ type validation fails.
238
+
239
+ Example:
240
+ >>> "string" + 5
241
+ Traceback (most recent call last):
242
+ ...
243
+ MDTypeError: can only concatenate str (not "int") to str
244
+
245
+ >>> len(42)
246
+ Traceback (most recent call last):
247
+ ...
248
+ MDTypeError: object of type 'int' has no len()
249
+ """
250
+
251
+ def __init__(self, message: str | ErrorTemplate, line: int = 0, column: int = 0, **kwargs: Any) -> None:
252
+ """Initialize type error.
253
+
254
+ Args:
255
+ message: Error message string or ErrorTemplate
256
+ line: Line number where error occurred
257
+ column: Column position where error occurred
258
+ **kwargs: Additional template parameters if message is ErrorTemplate
259
+ """
260
+ if isinstance(message, str):
261
+ # Create a simple ErrorTemplate from the string
262
+ from machine_dialect.errors.messages import ErrorTemplate
263
+
264
+ template = ErrorTemplate(message)
265
+ super().__init__(template, line, column, **kwargs)
266
+ else:
267
+ super().__init__(message, line, column, **kwargs)
268
+
269
+
270
+ class MDValueError(MDException):
271
+ """Raised when a value is inappropriate for the operation.
272
+
273
+ This exception is raised when an operation or function receives an
274
+ argument that has the right type but an inappropriate value. It can
275
+ occur during parsing when value validation fails.
276
+
277
+ Example:
278
+ >>> int("not a number")
279
+ Traceback (most recent call last):
280
+ ...
281
+ MDValueError: invalid literal for int() with base 10: 'not a number'
282
+
283
+ >>> list.remove([1, 2, 3], 4)
284
+ Traceback (most recent call last):
285
+ ...
286
+ MDValueError: list.remove(x): x not in list
287
+ """
288
+
289
+
290
+ class MDUninitializedError(MDException):
291
+ """Raised when a variable is used before being initialized.
292
+
293
+ This exception is raised during semantic analysis when a variable
294
+ that has been defined but not yet assigned a value is used in an
295
+ expression or assignment.
296
+
297
+ Example:
298
+ >>> Define `x` as Whole Number.
299
+ >>> Set `y` to `x`.
300
+ Traceback (most recent call last):
301
+ ...
302
+ MDUninitializedError: Variable 'x' is used before being initialized
303
+ """
304
+
305
+ def __init__(self, message: str | ErrorTemplate, line: int = 0, position: int = 0, **kwargs: Any) -> None:
306
+ """Initialize uninitialized variable error.
307
+
308
+ Args:
309
+ message: Error message string or ErrorTemplate
310
+ line: Line number where error occurred
311
+ position: Column position where error occurred
312
+ **kwargs: Additional template parameters if message is ErrorTemplate
313
+ """
314
+ if isinstance(message, str):
315
+ # Create a simple ErrorTemplate from the string
316
+ from machine_dialect.errors.messages import ErrorTemplate
317
+
318
+ template = ErrorTemplate(message)
319
+ super().__init__(template, line, position, **kwargs)
320
+ else:
321
+ super().__init__(message, line, position, **kwargs)
322
+
323
+
324
+ class MDRuntimeError(Exception):
325
+ """Machine Dialectâ„¢ Runtime Error.
326
+
327
+ Raised during runtime execution with optional source location.
328
+ This is used for errors that occur during MIR interpretation or VM execution.
329
+
330
+ Note: This inherits from Python's Exception (not MDException) because
331
+ it represents runtime errors that need to be caught by Python's exception
332
+ handling mechanism.
333
+ """
334
+
335
+ def __init__(
336
+ self,
337
+ message: str,
338
+ line: int | None = None,
339
+ column: int | None = None,
340
+ filename: str | None = None,
341
+ ) -> None:
342
+ """Initialize runtime error.
343
+
344
+ Args:
345
+ message: Error message string.
346
+ line: Line number where error occurred (None if unknown).
347
+ column: Column position where error occurred (None if unknown).
348
+ filename: Source file name (None if unknown).
349
+ """
350
+ self.message = message
351
+ self.line = line
352
+ self.column = column
353
+ self.filename = filename or "<standard-input>"
354
+ super().__init__(str(self))
355
+
356
+ def __str__(self) -> str:
357
+ """Return formatted error message with location."""
358
+ parts = []
359
+ if self.filename != "<standard-input>":
360
+ parts.append(f'File "{self.filename}"')
361
+ if self.line is not None and self.line > 0:
362
+ parts.append(f"line {self.line}")
363
+ if self.column is not None and self.column > 0:
364
+ parts.append(f"column {self.column}")
365
+
366
+ location = ", ".join(parts)
367
+ if location:
368
+ return f"{location}: {self.message}"
369
+ return self.message
@@ -0,0 +1,82 @@
1
+ from string import Template
2
+ from typing import Any
3
+
4
+
5
+ class ErrorTemplate(Template):
6
+ """Custom template class that prevents direct string usage in error messages.
7
+
8
+ DO NOT USE THIS CLASS DIRECTLY, USE THE CONSTANTS DEFINED BELOW"""
9
+
10
+ def format(self, **kwargs: Any) -> str:
11
+ """Format the template with keyword arguments.
12
+
13
+ This is a more Pythonic alternative to substitute().
14
+ """
15
+ return self.substitute(**kwargs)
16
+
17
+
18
+ # NameError
19
+ NAME_UNDEFINED = ErrorTemplate("Name '$name' is not defined")
20
+ VARIABLE_NOT_DEFINED = ErrorTemplate(
21
+ "Variable '$name' is not defined. Use 'Define `$name` as <type>.' to define it first"
22
+ )
23
+ VARIABLE_ALREADY_DEFINED = ErrorTemplate(
24
+ "Variable '$name' is already defined at line $original_line. Cannot redefine variables in the same scope"
25
+ )
26
+ ASSIGNMENT_TYPE_MISMATCH = ErrorTemplate(
27
+ "Cannot assign $actual_type value to variable '$variable' of type $expected_type"
28
+ )
29
+ UNEXPECTED_TOKEN = ErrorTemplate(
30
+ "Unexpected '$token_literal'. Expected a '$expected_token_type', but a got a '$received_token_type'"
31
+ )
32
+ INVALID_INTEGER_LITERAL = ErrorTemplate("Invalid integer literal: '$literal'")
33
+ INVALID_FLOAT_LITERAL = ErrorTemplate("Invalid float literal: '$literal'")
34
+ NO_PARSE_FUNCTION = ErrorTemplate("No suitable parse function was found to handle '$literal'")
35
+ EXPECTED_EXPRESSION_AFTER_OPERATOR = ErrorTemplate("expected expression after operator '$operator', got $got")
36
+ UNEXPECTED_TOKEN_AT_START = ErrorTemplate("unexpected token '$token' at start of expression")
37
+ EXPECTED_EXPRESSION = ErrorTemplate("expected expression, got $got")
38
+
39
+ # Block and control flow errors
40
+ EMPTY_IF_CONSEQUENCE = ErrorTemplate("If statement must have a non-empty consequence block")
41
+ EMPTY_ELSE_BLOCK = ErrorTemplate("Else/otherwise block must not be empty. If no alternative is needed, omit it.")
42
+ EMPTY_WHILE_BODY = ErrorTemplate("While loop must have a non-empty body block")
43
+ EMPTY_FOR_EACH_BODY = ErrorTemplate("For-each loop must have a non-empty body block")
44
+ EXPECTED_DETAILS_CLOSE = ErrorTemplate("Expected </details> tag after action body, got $token_type")
45
+ EXPECTED_BLOCK_MARKER = ErrorTemplate("Expected block marker '>', got $token_type")
46
+ EXPECTED_PREFIX_OPERATOR = ErrorTemplate("Expected prefix operator, got $token_type")
47
+ MISSING_DEPTH_TRANSITION = ErrorTemplate(
48
+ "After nested blocks ($nested_depth), add a blank line with just '$parent_depth' "
49
+ "before continuing at the parent depth. Found '$token_type' at line $line"
50
+ )
51
+ UNEXPECTED_BLOCK_DEPTH = ErrorTemplate("Unexpected block depth: expected $expected '>' but got $actual")
52
+
53
+ # Collection and list errors
54
+ INVALID_NAMED_LIST_KEY = ErrorTemplate("Named list keys must be string literals. Got $literal")
55
+
56
+ # Use statement errors
57
+ EXPECTED_FUNCTION_NAME = ErrorTemplate("Expected identifier for function name, got $token_type")
58
+ EXPECTED_IDENTIFIER_FOR_NAMED_ARG = ErrorTemplate("Expected identifier for named argument, got $type_name")
59
+ POSITIONAL_AFTER_NAMED = ErrorTemplate("Positional arguments cannot appear after named arguments")
60
+ INVALID_ARGUMENT_VALUE = ErrorTemplate("Invalid argument value: '$literal'")
61
+ MISSING_COMMA_BETWEEN_ARGS = ErrorTemplate("Expected comma between arguments")
62
+
63
+ # Generic parser errors
64
+ EXPECTED_TOKEN_AFTER = ErrorTemplate("Expected $expected after $after")
65
+ EXPECTED_IDENTIFIER_AFTER = ErrorTemplate("Expected $what identifier after $after")
66
+ EXPECTED_TOKEN = ErrorTemplate("Expected $token, got $got_token_type")
67
+ ILLEGAL_CHARACTER = ErrorTemplate("Expected $expected but found illegal character '$character'")
68
+ ILLEGAL_TOKEN = ErrorTemplate("Illegal token: '$token'")
69
+ UNEXPECTED_STATEMENT = ErrorTemplate("Unexpected statement type: $type")
70
+ UNHANDLED_OPERATION = ErrorTemplate("Unhandled $what operation: $operation")
71
+ INVALID_TYPE_NAME = ErrorTemplate("'$name' is not a valid type name. Expected one of: $valid_types")
72
+
73
+ # Interpreter errors
74
+ UNKNOWN_PREFIX_OPERATOR = ErrorTemplate("Unknown prefix operator: $operator")
75
+ UNKNOWN_INFIX_OPERATOR = ErrorTemplate("Unknown infix operator: $operator")
76
+ TYPE_MISMATCH = ErrorTemplate(
77
+ "Type mismatch: cannot apply operator '$operator' to operands of type '$left_type' and '$right_type'"
78
+ )
79
+ UNSUPPORTED_OPERATION = ErrorTemplate("Unsupported operation: '$operation' on type '$type'")
80
+ DIVISION_BY_ZERO = ErrorTemplate("Division by zero")
81
+ UNSUPPORTED_OPERAND_TYPE = ErrorTemplate("Unsupported operand type(s) for $operator: '$left_type' and '$right_type'")
82
+ UNSUPPORTED_UNARY_OPERAND = ErrorTemplate("Unsupported operand type for unary $operator: '$type'")
File without changes