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,426 @@
1
+ #!/usr/bin/env python3
2
+ """Machine Dialect™ REPL (Read-Eval-Print Loop).
3
+
4
+ This module provides an interactive REPL for the Machine Dialect™ language.
5
+ It can operate in multiple modes:
6
+ - Default: Execute code using the Rust VM
7
+ - Debug tokens (--debug-tokens): Tokenizes input and displays tokens
8
+ - AST mode (--ast): Show HIR/AST without executing
9
+ """
10
+
11
+ import argparse
12
+ import sys
13
+ from typing import Any
14
+
15
+ # readline provides command history and line editing, but is not available on Windows
16
+ if sys.platform != "win32":
17
+ import readline # noqa: F401
18
+
19
+ from machine_dialect.compiler.config import CompilerConfig
20
+ from machine_dialect.compiler.context import CompilationContext
21
+ from machine_dialect.compiler.phases.hir_generation import HIRGenerationPhase
22
+ from machine_dialect.lexer.lexer import Lexer
23
+ from machine_dialect.lexer.tokens import Token
24
+ from machine_dialect.parser.parser import Parser
25
+
26
+
27
+ class REPL:
28
+ """Interactive REPL for Machine Dialect™.
29
+
30
+ Provides an interactive environment for testing Machine Dialect™ syntax
31
+ by parsing input and displaying the AST or tokens.
32
+
33
+ Attributes:
34
+ prompt: The prompt string displayed to the user.
35
+ running: Flag indicating whether the REPL is running.
36
+ debug_tokens: Whether to show tokens instead of AST.
37
+ show_ast: Whether to show AST instead of evaluating.
38
+ accumulated_source: Accumulated source code for parsing.
39
+ multiline_buffer: Buffer for collecting multi-line input.
40
+ in_multiline_mode: Whether currently collecting multi-line input.
41
+ hir_phase: HIR generation phase for desugaring AST nodes.
42
+ vm_runner: Optional VM runner for code execution.
43
+ """
44
+
45
+ def __init__(self, debug_tokens: bool = False, show_ast: bool = False) -> None:
46
+ """Initialize the REPL with default settings.
47
+
48
+ Args:
49
+ debug_tokens: Whether to show tokens instead of evaluating.
50
+ show_ast: Whether to show AST instead of evaluating.
51
+ """
52
+ self.prompt = "md> "
53
+ self.running = True
54
+ self.debug_tokens = debug_tokens
55
+ self.show_ast = show_ast
56
+ self.accumulated_source = ""
57
+ self.multiline_buffer = ""
58
+ self.in_multiline_mode = False
59
+ self.hir_phase = HIRGenerationPhase() # HIR generation phase for desugaring
60
+ self.vm_runner: Any = None
61
+ self._init_vm_runner()
62
+
63
+ def _init_vm_runner(self) -> None:
64
+ """Initialize the VM runner if not in token/AST debug modes."""
65
+ if not self.debug_tokens and not self.show_ast:
66
+ try:
67
+ from machine_dialect.compiler.vm_runner import VMRunner
68
+
69
+ self.vm_runner = VMRunner(debug=False, optimize=True)
70
+ except (ImportError, RuntimeError) as e:
71
+ print(f"Warning: Rust VM not available: {e}")
72
+ print("Falling back to AST display mode.")
73
+ self.show_ast = True
74
+
75
+ def print_welcome(self) -> None:
76
+ """Print the welcome message when REPL starts."""
77
+ print("Machine Dialect™ REPL v0.1.0")
78
+ if self.debug_tokens:
79
+ mode = "Token Debug Mode"
80
+ elif self.show_ast:
81
+ mode = "HIR/AST Display Mode"
82
+ elif self.vm_runner:
83
+ mode = "Rust VM Execution Mode"
84
+ else:
85
+ mode = "HIR Mode (desugared AST)"
86
+ print(f"Mode: {mode}")
87
+ print("Type 'exit' to exit, 'help' for help")
88
+ print("-" * 50)
89
+
90
+ def print_help(self) -> None:
91
+ """Print help information about available commands."""
92
+ print("\nAvailable commands:")
93
+ print(" exit - Exit the REPL")
94
+ print(" help - Show this help message")
95
+ print(" clear - Clear the screen")
96
+ if not self.debug_tokens:
97
+ print(" reset - Clear accumulated source")
98
+
99
+ if self.debug_tokens:
100
+ print("\nEnter any text to see its tokens.")
101
+ elif self.show_ast:
102
+ print("\nEnter Machine Dialect™ code to see its HIR (desugared AST).")
103
+ print("Source is accumulated across lines until an error occurs.")
104
+ elif self.vm_runner:
105
+ print("\nEnter Machine Dialect™ code to execute it on the Rust VM.")
106
+ print("Source is accumulated across lines until an error occurs.")
107
+ else:
108
+ print("\nEnter Machine Dialect™ code to see its HIR (desugared AST).")
109
+ print("Source is accumulated across lines until an error occurs.")
110
+
111
+ print("\nMulti-line input:")
112
+ print(" Lines ending with ':' enter multi-line mode")
113
+ print(" Lines starting with '>' continue multi-line input")
114
+ print(" Empty line or line not matching above completes input")
115
+ print(" Ctrl+C cancels multi-line input")
116
+
117
+ print("\nExample: Set `x` to _10_.")
118
+ print("\nMulti-line example:")
119
+ print(" md> If _5_ > _3_ then:")
120
+ print(" ... > _42_.")
121
+ print(" ... ")
122
+ print()
123
+
124
+ def clear_screen(self) -> None:
125
+ """Clear the terminal screen."""
126
+ import os
127
+
128
+ os.system("cls" if os.name == "nt" else "clear")
129
+
130
+ def format_token(self, token: Token) -> str:
131
+ """Format a token for display.
132
+
133
+ Args:
134
+ token: The token to format.
135
+
136
+ Returns:
137
+ A formatted string representation of the token.
138
+ """
139
+ return f" {token.type.name:<20} | {token.literal!r}"
140
+
141
+ def should_continue_multiline(self, line: str) -> bool:
142
+ """Check if we should continue collecting multi-line input.
143
+
144
+ Args:
145
+ line: The current input line.
146
+
147
+ Returns:
148
+ True if we should continue collecting input, False otherwise.
149
+ """
150
+ stripped = line.strip()
151
+ # Continue if line ends with colon or starts with '>'
152
+ return stripped.endswith(":") or stripped.startswith(">")
153
+
154
+ def get_multiline_prompt(self) -> str:
155
+ """Get the appropriate prompt for multi-line input.
156
+
157
+ Returns:
158
+ The prompt string to use.
159
+ """
160
+ # Count the depth of '>' markers in the buffer
161
+ depth = 0
162
+ for line in self.multiline_buffer.split("\n"):
163
+ stripped = line.strip()
164
+ if stripped.startswith(">"):
165
+ # Count consecutive '>' at the start
166
+ for char in stripped:
167
+ if char == ">":
168
+ depth += 1
169
+ else:
170
+ break
171
+ break
172
+
173
+ if depth > 0:
174
+ return "... "
175
+ else:
176
+ return "... "
177
+
178
+ def tokenize_and_print(self, input_text: str) -> None:
179
+ """Tokenize the input and print the results.
180
+
181
+ Args:
182
+ input_text: The Machine Dialect™ code to tokenize.
183
+
184
+ Note:
185
+ This method handles both successful tokenization and error cases,
186
+ displaying any lexical errors before showing the tokens.
187
+ """
188
+ try:
189
+ from machine_dialect.lexer.tokens import TokenType
190
+
191
+ lexer = Lexer(input_text)
192
+
193
+ # Stream tokens
194
+ tokens = []
195
+ while True:
196
+ token = lexer.next_token()
197
+ tokens.append(token)
198
+ if token.type == TokenType.MISC_EOF:
199
+ break
200
+
201
+ print(f"\nTokens ({len(tokens)}):")
202
+ print("-" * 50)
203
+ print(f" {'Type':<20} | Literal")
204
+ print("-" * 50)
205
+
206
+ for token in tokens:
207
+ print(self.format_token(token))
208
+
209
+ print("-" * 50)
210
+ print()
211
+
212
+ except Exception as e:
213
+ print(f"Error: {e}")
214
+ print()
215
+
216
+ def parse_and_print(self, input_text: str) -> None:
217
+ """Parse the input and print the AST or evaluation result.
218
+
219
+ Args:
220
+ input_text: The Machine Dialect™ code to parse.
221
+
222
+ Note:
223
+ This method accumulates source code and attempts to parse it.
224
+ If parsing fails, it shows the error and removes the problematic line.
225
+ """
226
+ # Add new input to accumulated source
227
+ if self.accumulated_source:
228
+ # Add a newline separator if we have existing content
229
+ test_source = self.accumulated_source + "\n" + input_text
230
+ else:
231
+ test_source = input_text
232
+
233
+ # Create parser and parse
234
+ parser = Parser()
235
+ ast = parser.parse(test_source)
236
+
237
+ # Check for errors
238
+ if parser.has_errors():
239
+ # Show parser errors but don't update accumulated source
240
+ print("\nErrors found:")
241
+ print("-" * 50)
242
+ for error in parser.errors:
243
+ print(f" {error}")
244
+ print("-" * 50)
245
+ print("(Input not added to accumulated source)")
246
+ print()
247
+ else:
248
+ # If successful, update accumulated source
249
+ self.accumulated_source = test_source
250
+
251
+ # Generate HIR by desugaring the AST
252
+ # Create a minimal compilation context for HIR generation
253
+ from pathlib import Path
254
+
255
+ from machine_dialect.ast.program import Program
256
+
257
+ config = CompilerConfig(verbose=False)
258
+ context = CompilationContext(source_path=Path("<repl>"), source_content=test_source, config=config)
259
+ hir = self.hir_phase.run(context, ast)
260
+
261
+ # Execute or show AST based on mode
262
+ if self.vm_runner:
263
+ # Execute using Rust VM
264
+ try:
265
+ result = self.vm_runner.execute(self.accumulated_source)
266
+ print("\nExecution Result:")
267
+ print("-" * 50)
268
+ if result is not None:
269
+ print(f" {result}")
270
+ else:
271
+ print(" (no return value)")
272
+ print("-" * 50)
273
+ print()
274
+ except Exception as e:
275
+ print(f"\nExecution Error: {e}")
276
+ print()
277
+ else:
278
+ # Show HIR/AST
279
+ print("\nHIR (desugared AST):")
280
+ print("-" * 50)
281
+ if isinstance(hir, Program) and hir.statements:
282
+ for node in hir.statements:
283
+ print(f" {node}")
284
+ else:
285
+ print(" (empty)")
286
+ print("-" * 50)
287
+ print()
288
+
289
+ def run(self) -> int:
290
+ """Run the main REPL loop.
291
+
292
+ Handles user input, command processing, and multi-line input collection.
293
+ Continues until the user exits or an unhandled error occurs.
294
+
295
+ Returns:
296
+ Exit code (0 for normal exit, 1 for error exit).
297
+ """
298
+ self.print_welcome()
299
+
300
+ while self.running:
301
+ try:
302
+ # Determine prompt based on multiline mode
303
+ if self.in_multiline_mode:
304
+ prompt = self.get_multiline_prompt()
305
+ else:
306
+ prompt = self.prompt
307
+
308
+ # Get input
309
+ user_input = input(prompt)
310
+
311
+ # In multiline mode, handle special cases
312
+ if self.in_multiline_mode:
313
+ # Check if we should continue multiline
314
+ if self.should_continue_multiline(user_input):
315
+ # Add to buffer with newline
316
+ if self.multiline_buffer:
317
+ self.multiline_buffer += "\n" + user_input
318
+ else:
319
+ self.multiline_buffer = user_input
320
+ continue
321
+ else:
322
+ # End multiline mode - process the complete buffer
323
+ if self.multiline_buffer:
324
+ complete_input = self.multiline_buffer + "\n" + user_input
325
+ else:
326
+ complete_input = user_input
327
+
328
+ # Reset multiline mode
329
+ self.multiline_buffer = ""
330
+ self.in_multiline_mode = False
331
+
332
+ # Process the complete input
333
+ user_input = complete_input
334
+ else:
335
+ # Check for commands (only in normal mode)
336
+ if user_input.strip().lower() == "exit":
337
+ print("Goodbye!")
338
+ self.running = False
339
+ return 0 # Normal exit
340
+ elif user_input.strip().lower() == "help":
341
+ self.print_help()
342
+ continue
343
+ elif user_input.strip().lower() == "clear":
344
+ self.clear_screen()
345
+ self.print_welcome()
346
+ # Also clear accumulated source
347
+ if not self.debug_tokens:
348
+ self.accumulated_source = ""
349
+ continue
350
+ elif user_input.strip().lower() == "reset" and not self.debug_tokens:
351
+ # Reset accumulated source in AST mode
352
+ self.accumulated_source = ""
353
+ print("Accumulated source cleared.")
354
+ continue
355
+
356
+ # Check if we should enter multiline mode
357
+ if not self.debug_tokens and self.should_continue_multiline(user_input):
358
+ self.in_multiline_mode = True
359
+ self.multiline_buffer = user_input
360
+ continue
361
+
362
+ # Process non-empty input
363
+ if user_input.strip():
364
+ # Auto-append period if missing (for non-token mode)
365
+ if not self.debug_tokens and not user_input.strip().endswith("."):
366
+ user_input = user_input + "."
367
+
368
+ # Process input based on mode
369
+ if self.debug_tokens:
370
+ self.tokenize_and_print(user_input)
371
+ else:
372
+ self.parse_and_print(user_input)
373
+
374
+ except (KeyboardInterrupt, EOFError):
375
+ # Handle Ctrl+C and Ctrl+D
376
+ if self.in_multiline_mode:
377
+ # Cancel multiline mode
378
+ print("\nMultiline input cancelled.")
379
+ self.multiline_buffer = ""
380
+ self.in_multiline_mode = False
381
+ else:
382
+ print("\nGoodbye!")
383
+ self.running = False
384
+ return 0 # Normal exit via Ctrl+D
385
+ except Exception as e:
386
+ print(f"Unexpected error: {e}")
387
+ # Reset multiline mode on error
388
+ if self.in_multiline_mode:
389
+ self.multiline_buffer = ""
390
+ self.in_multiline_mode = False
391
+ return 1 # Error exit
392
+
393
+ return 0 # Default normal exit
394
+
395
+
396
+ def main() -> None:
397
+ """Entry point for the Machine Dialect™ REPL.
398
+
399
+ Parses command line arguments and starts the appropriate REPL mode.
400
+ Supports token debug mode and AST display mode via command line flags.
401
+ """
402
+ parser = argparse.ArgumentParser(description="Machine Dialect™ REPL")
403
+ parser.add_argument(
404
+ "--debug-tokens",
405
+ action="store_true",
406
+ help="Run in token debug mode (show tokens)",
407
+ )
408
+ parser.add_argument(
409
+ "--ast",
410
+ action="store_true",
411
+ help="Run in AST mode (show AST instead of evaluating)",
412
+ )
413
+ args = parser.parse_args()
414
+
415
+ # Check for incompatible flags
416
+ if args.debug_tokens and args.ast:
417
+ print("Error: --debug-tokens and --ast flags are not compatible")
418
+ sys.exit(1)
419
+
420
+ repl = REPL(debug_tokens=args.debug_tokens, show_ast=args.ast)
421
+ exit_code = repl.run()
422
+ sys.exit(exit_code)
423
+
424
+
425
+ if __name__ == "__main__":
426
+ main()
File without changes