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,360 @@
1
+ """AI Agent for iterative Machine Dialect™ code generation and execution."""
2
+
3
+ import tempfile
4
+ import time
5
+ from dataclasses import dataclass
6
+ from pathlib import Path
7
+ from typing import Any
8
+
9
+ from machine_dialect.cfg.openai_generation import generate_with_openai
10
+ from machine_dialect.compiler import Compiler, CompilerConfig
11
+ from machine_dialect.compiler.config import OptimizationLevel
12
+
13
+
14
+ @dataclass
15
+ class AgentResult:
16
+ """Result from agent execution.
17
+
18
+ Attributes:
19
+ success: Whether the task was successfully completed.
20
+ iterations: Number of iterations taken.
21
+ code: Final code (if successful).
22
+ output: Program output (if any).
23
+ history: Full iteration history.
24
+ """
25
+
26
+ success: bool
27
+ iterations: int
28
+ code: str | None = None
29
+ output: str | None = None
30
+ history: list[dict[str, Any]] | None = None
31
+
32
+
33
+ class Agent:
34
+ """Iterative AI agent for Machine Dialect™ code generation."""
35
+
36
+ def __init__(self, client: Any, model: str = "gpt-5", verbose: bool = True):
37
+ """Initialize the agent.
38
+
39
+ Args:
40
+ client: OpenAI client instance.
41
+ model: Model to use for generation.
42
+ verbose: Whether to print progress.
43
+ """
44
+ self.client = client
45
+ self.model = model
46
+ self.verbose = verbose
47
+ self.iterations: list[dict[str, Any]] = []
48
+ self.total_tokens_used = 0
49
+
50
+ def solve(self, task: str, max_iterations: int = 5) -> AgentResult:
51
+ """Solve a task through iterative code generation.
52
+
53
+ Args:
54
+ task: The task description.
55
+ max_iterations: Maximum iterations to attempt.
56
+
57
+ Returns:
58
+ AgentResult with solution details.
59
+ """
60
+ # Track overall time
61
+ start_time = time.time()
62
+
63
+ if self.verbose:
64
+ print(f"🤖 Agent starting: {task}")
65
+ print(f" Model: {self.model}")
66
+ print(f" Max iterations: {max_iterations}")
67
+
68
+ self.iterations = []
69
+ current_task = task
70
+ successful_code = None
71
+ final_output = None
72
+
73
+ for i in range(max_iterations):
74
+ iteration_num = i + 1
75
+
76
+ if self.verbose:
77
+ print(f"\n📍 Iteration {iteration_num}/{max_iterations}")
78
+
79
+ # Generate code
80
+ try:
81
+ if self.verbose:
82
+ print(" Generating code...")
83
+
84
+ # Time the generation
85
+ gen_start = time.time()
86
+ code, token_info = self._generate(current_task)
87
+ gen_time = time.time() - gen_start
88
+
89
+ # Track token usage
90
+ if token_info:
91
+ total = token_info.get("total_tokens", 0)
92
+ prompt = token_info.get("prompt_tokens")
93
+ completion = token_info.get("completion_tokens")
94
+
95
+ if total:
96
+ self.total_tokens_used += total
97
+
98
+ if self.verbose:
99
+ print(f" ✓ Code generated (CFG-constrained) in {gen_time:.2f}s")
100
+
101
+ # Display token info based on what's available
102
+ if prompt is not None and completion is not None:
103
+ print(f" 📊 Tokens: {prompt} prompt + {completion} completion = {total} total")
104
+ elif total:
105
+ print(f" 📊 Tokens: {total} total")
106
+
107
+ if self.total_tokens_used > 0:
108
+ print(f" 📈 Cumulative: {self.total_tokens_used:,} tokens")
109
+
110
+ # Debug: show what was generated
111
+ print(f" Debug: Generated code: {code!r}")
112
+ else:
113
+ if self.verbose:
114
+ print(" ✓ Code generated (CFG-constrained)")
115
+ print(f" Debug: Generated code: {code!r}")
116
+
117
+ except Exception as e:
118
+ if self.verbose:
119
+ print(f" ✗ Generation failed: {e}")
120
+
121
+ self.iterations.append(
122
+ {"iteration": iteration_num, "code": None, "error": str(e), "phase": "generation"}
123
+ )
124
+ continue
125
+
126
+ # Compile and execute
127
+ result = self._execute(code)
128
+
129
+ # Record iteration
130
+ self.iterations.append({"iteration": iteration_num, "code": code, "result": result})
131
+
132
+ # Check result
133
+ if result["success"]:
134
+ if self.verbose:
135
+ output_msg = result.get("output", "No output")
136
+ if result.get("instructions"):
137
+ print(f" ✅ Success! Output: {output_msg}")
138
+ print(f" 📊 Executed {result['instructions']} instructions")
139
+ else:
140
+ print(f" ✅ Success! Output: {output_msg}")
141
+
142
+ successful_code = code
143
+ final_output = result.get("output")
144
+
145
+ # Optional: Try to optimize if we have iterations left
146
+ if iteration_num < max_iterations and self.verbose:
147
+ if not self._should_optimize(task, code, result):
148
+ break
149
+ current_task = f"Optimize this working solution for: {task}\n\nCurrent code:\n{code}"
150
+ else:
151
+ break
152
+
153
+ else:
154
+ # Failed - prepare for next iteration
155
+ error = result.get("error", "Unknown error")
156
+ phase = result.get("phase", "execution")
157
+
158
+ if self.verbose:
159
+ print(f" ❌ {phase.capitalize()} error: {error}")
160
+
161
+ # Build feedback for next iteration
162
+ current_task = self._build_error_feedback(task, code, error, phase)
163
+
164
+ # Calculate total time
165
+ total_time = time.time() - start_time
166
+
167
+ # Print final summary
168
+ if self.verbose:
169
+ if self.total_tokens_used > 0:
170
+ print(f"\n💰 Total: {self.total_tokens_used:,} tokens in {total_time:.2f}s")
171
+ else:
172
+ print(f"\n⏱️ Total time: {total_time:.2f}s")
173
+
174
+ # Return final result
175
+ return AgentResult(
176
+ success=successful_code is not None,
177
+ iterations=len(self.iterations),
178
+ code=successful_code,
179
+ output=final_output,
180
+ history=self.iterations,
181
+ )
182
+
183
+ def _generate(self, task: str) -> tuple[str, dict[str, int]]:
184
+ """Generate code using CFG constraints.
185
+
186
+ Args:
187
+ task: Task description with any feedback.
188
+
189
+ Returns:
190
+ Tuple of (code, token_info) where token_info contains usage stats.
191
+ """
192
+ # Simplify the task description if it's too complex
193
+ simplified_task = self._simplify_task(task)
194
+
195
+ # Use the existing CFG generation
196
+ return generate_with_openai(
197
+ self.client,
198
+ self.model,
199
+ simplified_task,
200
+ max_tokens=800,
201
+ temperature=0.7, # Will be ignored for GPT-5
202
+ )
203
+
204
+ def _simplify_task(self, task: str) -> str:
205
+ """Simplify complex task descriptions for better generation.
206
+
207
+ Args:
208
+ task: Original task description.
209
+
210
+ Returns:
211
+ Simplified task description.
212
+ """
213
+ # Remove overly complex instructions and focus on core functionality
214
+ simplified = task
215
+
216
+ # If task is very long, try to extract the essential parts
217
+ if len(task) > 500:
218
+ # Look for key phrases that indicate the main task
219
+ lines = task.split("\n")
220
+ essential_lines = []
221
+
222
+ for line in lines:
223
+ # Keep lines that describe the main task or errors
224
+ if any(
225
+ keyword in line.lower()
226
+ for keyword in [
227
+ "generate",
228
+ "create",
229
+ "calculate",
230
+ "implement",
231
+ "write",
232
+ "error:",
233
+ "failed:",
234
+ "fix",
235
+ "please",
236
+ ]
237
+ ):
238
+ essential_lines.append(line)
239
+
240
+ if essential_lines:
241
+ simplified = "\n".join(essential_lines[:10]) # Limit to 10 most relevant lines
242
+
243
+ # Add clarification about Machine Dialect™ syntax
244
+ if "error" not in simplified.lower():
245
+ simplified += (
246
+ "\nNote: Use Machine Dialect™ syntax with backticks for variables and underscores for literals."
247
+ )
248
+
249
+ return simplified
250
+
251
+ def _execute(self, code: str) -> dict[str, Any]:
252
+ """Compile and execute Machine Dialect™ code.
253
+
254
+ Args:
255
+ code: The code to execute.
256
+
257
+ Returns:
258
+ Execution result dictionary.
259
+ """
260
+ temp_path = None
261
+
262
+ try:
263
+ # Compile without optimizations
264
+ config = CompilerConfig(optimization_level=OptimizationLevel.NONE, verbose=False)
265
+ compiler = Compiler(config)
266
+
267
+ if self.verbose:
268
+ print(" Compiling...")
269
+
270
+ context = compiler.compile_string(code, module_name="agent_task")
271
+
272
+ # Check compilation errors
273
+ if context.has_errors():
274
+ error_msg = "Compilation failed"
275
+ if context.errors:
276
+ error = context.errors[0]
277
+ # Convert error object to string
278
+ error_msg = str(error)
279
+ return {"success": False, "phase": "compilation", "error": error_msg}
280
+
281
+ if self.verbose and context.bytecode_module:
282
+ bytecode_size = len(context.bytecode_module.serialize())
283
+ print(f" ✓ Compiled successfully ({bytecode_size} bytes)")
284
+
285
+ # Save bytecode to temporary file
286
+ if context.bytecode_module:
287
+ with tempfile.NamedTemporaryFile(suffix=".mdbc", delete=False) as f:
288
+ bytecode = context.bytecode_module.serialize()
289
+ f.write(bytecode)
290
+ temp_path = f.name
291
+ else:
292
+ raise ValueError("Compilation succeeded but no bytecode generated")
293
+
294
+ # Execute with Rust VM
295
+ if self.verbose:
296
+ print(" Executing bytecode...")
297
+
298
+ import machine_dialect_vm
299
+
300
+ vm = machine_dialect_vm.RustVM()
301
+ vm.load_bytecode(temp_path)
302
+ output = vm.execute()
303
+
304
+ # Get instruction count
305
+ instructions = vm.instruction_count()
306
+
307
+ return {
308
+ "success": True,
309
+ "phase": "runtime",
310
+ "output": str(output) if output is not None else "",
311
+ "instructions": instructions,
312
+ "bytecode_size": len(bytecode),
313
+ }
314
+
315
+ except ImportError:
316
+ return {"success": False, "phase": "runtime", "error": "Rust VM not available. Run ./build_vm.sh first."}
317
+ except Exception as e:
318
+ return {"success": False, "phase": "runtime", "error": str(e)}
319
+ finally:
320
+ # Clean up temp file
321
+ if temp_path:
322
+ Path(temp_path).unlink(missing_ok=True)
323
+
324
+ def _build_error_feedback(self, original_task: str, code: str, error: str, phase: str) -> str:
325
+ """Build task description with error feedback.
326
+
327
+ Args:
328
+ original_task: Original task description.
329
+ code: Code that failed.
330
+ error: Error message.
331
+ phase: Phase where error occurred.
332
+
333
+ Returns:
334
+ Enhanced task description for retry.
335
+ """
336
+ feedback = f"{original_task}\n\n"
337
+ feedback += f"Previous attempt failed during {phase}:\n"
338
+ feedback += f"Code:\n```\n{code}\n```\n\n"
339
+ feedback += f"Error: {error}\n\n"
340
+ feedback += "Please fix this error and provide a working solution."
341
+
342
+ return feedback
343
+
344
+ def _should_optimize(self, task: str, code: str, result: dict[str, Any]) -> bool:
345
+ """Decide if we should try to optimize working code.
346
+
347
+ Args:
348
+ task: Original task.
349
+ code: Working code.
350
+ result: Execution result.
351
+
352
+ Returns:
353
+ Whether to attempt optimization.
354
+ """
355
+ # Simple heuristic: don't optimize if it's already very small
356
+ if result.get("instructions", 0) < 50:
357
+ return False
358
+
359
+ # Could add more sophisticated logic here
360
+ return False # For now, stop on first success
@@ -0,0 +1,95 @@
1
+ # isort: skip_file
2
+ from .ast_node import ASTNode
3
+ from .expressions import (
4
+ Arguments,
5
+ CollectionAccessExpression,
6
+ ConditionalExpression,
7
+ ErrorExpression,
8
+ Expression,
9
+ Identifier,
10
+ InfixExpression,
11
+ PrefixExpression,
12
+ )
13
+ from .dict_extraction import DictExtraction
14
+ from .statements import (
15
+ ActionStatement,
16
+ BlockStatement,
17
+ CallStatement,
18
+ CollectionMutationStatement,
19
+ DefineStatement,
20
+ ErrorStatement,
21
+ ExpressionStatement,
22
+ ForEachStatement,
23
+ FunctionStatement,
24
+ FunctionVisibility,
25
+ IfStatement,
26
+ InteractionStatement,
27
+ Output,
28
+ Parameter,
29
+ ReturnStatement,
30
+ SayStatement,
31
+ SetStatement,
32
+ Statement,
33
+ UtilityStatement,
34
+ WhileStatement,
35
+ )
36
+ from .program import Program
37
+ from .literals import (
38
+ WholeNumberLiteral,
39
+ FloatLiteral,
40
+ StringLiteral,
41
+ YesNoLiteral,
42
+ EmptyLiteral,
43
+ URLLiteral,
44
+ UnorderedListLiteral,
45
+ OrderedListLiteral,
46
+ NamedListLiteral,
47
+ BlankLiteral,
48
+ )
49
+ from .call_expression import CallExpression
50
+
51
+
52
+ __all__ = [
53
+ "ASTNode",
54
+ "ActionStatement",
55
+ "Arguments",
56
+ "BlankLiteral",
57
+ "BlockStatement",
58
+ "CallExpression",
59
+ "CallStatement",
60
+ "CollectionAccessExpression",
61
+ "CollectionMutationStatement",
62
+ "ConditionalExpression",
63
+ "DefineStatement",
64
+ "DictExtraction",
65
+ "EmptyLiteral",
66
+ "ErrorExpression",
67
+ "ErrorStatement",
68
+ "Expression",
69
+ "ExpressionStatement",
70
+ "FloatLiteral",
71
+ "ForEachStatement",
72
+ "FunctionStatement",
73
+ "FunctionVisibility",
74
+ "Identifier",
75
+ "IfStatement",
76
+ "InfixExpression",
77
+ "InteractionStatement",
78
+ "NamedListLiteral",
79
+ "OrderedListLiteral",
80
+ "Output",
81
+ "Parameter",
82
+ "PrefixExpression",
83
+ "Program",
84
+ "ReturnStatement",
85
+ "SayStatement",
86
+ "SetStatement",
87
+ "Statement",
88
+ "StringLiteral",
89
+ "URLLiteral",
90
+ "UnorderedListLiteral",
91
+ "UtilityStatement",
92
+ "WhileStatement",
93
+ "WholeNumberLiteral",
94
+ "YesNoLiteral",
95
+ ]
@@ -0,0 +1,35 @@
1
+ from abc import ABC, abstractmethod
2
+ from typing import TYPE_CHECKING
3
+
4
+ if TYPE_CHECKING:
5
+ from machine_dialect.lexer.tokens import Token
6
+
7
+
8
+ class ASTNode(ABC):
9
+ @abstractmethod
10
+ def __str__(self) -> str:
11
+ pass
12
+
13
+ def desugar(self) -> "ASTNode":
14
+ """Simplify AST node for IR generation and optimization.
15
+
16
+ This method transforms the AST to remove syntactic sugar and normalize
17
+ semantically equivalent constructs. The default implementation returns
18
+ the node unchanged.
19
+
20
+ Returns:
21
+ A simplified version of this node or self if no simplification needed.
22
+ """
23
+ return self
24
+
25
+ def get_source_location(self) -> tuple[int, int] | None:
26
+ """Get the source location (line, column) of this AST node.
27
+
28
+ Returns:
29
+ A tuple of (line, column) if location info is available, None otherwise.
30
+ """
31
+ # Default implementation - subclasses with tokens can override
32
+ if hasattr(self, "token"):
33
+ token: Token = self.token
34
+ return (token.line, token.position)
35
+ return None
@@ -0,0 +1,82 @@
1
+ """CallExpression AST node for function calls that return values."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from typing import TYPE_CHECKING
6
+
7
+ from machine_dialect.ast.expressions import Expression
8
+
9
+ if TYPE_CHECKING:
10
+ from machine_dialect.lexer import Token
11
+
12
+
13
+ class CallExpression(Expression):
14
+ """A function call expression that returns a value.
15
+
16
+ CallExpression represents a function invocation that produces a value,
17
+ used in contexts where an expression is expected (e.g., in assignments
18
+ with 'using', or as part of larger expressions).
19
+
20
+ This is distinct from CallStatement, which represents standalone function
21
+ calls that don't necessarily return values.
22
+
23
+ Attributes:
24
+ function_name: The identifier or expression that names the function.
25
+ arguments: Optional Arguments node containing the function arguments.
26
+ """
27
+
28
+ def __init__(
29
+ self, token: Token, function_name: Expression | None = None, arguments: Expression | None = None
30
+ ) -> None:
31
+ """Initialize a CallExpression node.
32
+
33
+ Args:
34
+ token: The token that begins the call (typically the function name).
35
+ function_name: The expression identifying the function to call.
36
+ arguments: Optional Arguments node containing the function arguments.
37
+ """
38
+ super().__init__(token)
39
+ self.function_name = function_name
40
+ self.arguments = arguments
41
+
42
+ def token_literal(self) -> str:
43
+ """Return the literal value of the call token.
44
+
45
+ Returns:
46
+ The literal value of the token.
47
+ """
48
+ return self.token.literal
49
+
50
+ def __str__(self) -> str:
51
+ """Return string representation of the call expression.
52
+
53
+ Returns:
54
+ A string showing the function call with its arguments.
55
+ """
56
+ parts = []
57
+
58
+ if self.function_name:
59
+ parts.append(str(self.function_name))
60
+
61
+ if self.arguments:
62
+ parts.append(f"({self.arguments})")
63
+ else:
64
+ parts.append("()")
65
+
66
+ return "".join(parts)
67
+
68
+ def desugar(self) -> CallExpression:
69
+ """Desugar the call expression.
70
+
71
+ Returns:
72
+ A new CallExpression with desugared components.
73
+ """
74
+ desugared = CallExpression(self.token)
75
+
76
+ if self.function_name:
77
+ desugared.function_name = self.function_name.desugar()
78
+
79
+ if self.arguments:
80
+ desugared.arguments = self.arguments.desugar()
81
+
82
+ return desugared
@@ -0,0 +1,60 @@
1
+ """Dictionary extraction expressions for Machine Dialect™."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from typing import TYPE_CHECKING
6
+
7
+ from machine_dialect.ast.expressions import Expression
8
+
9
+ if TYPE_CHECKING:
10
+ from machine_dialect.lexer.tokens import Token
11
+
12
+
13
+ class DictExtraction(Expression):
14
+ """Extract keys or values from a dictionary.
15
+
16
+ Represents expressions like:
17
+ - the names of `person` (extracts keys)
18
+ - the contents of `person` (extracts values)
19
+
20
+ Attributes:
21
+ dictionary: The dictionary expression to extract from.
22
+ extract_type: What to extract ('names' for keys, 'contents' for values).
23
+ token: The token that begins this expression.
24
+ """
25
+
26
+ def __init__(self, token: Token, dictionary: Expression, extract_type: str) -> None:
27
+ """Initialize dictionary extraction expression.
28
+
29
+ Args:
30
+ token: The token that begins this expression.
31
+ dictionary: The dictionary to extract from.
32
+ extract_type: 'names' or 'contents'.
33
+ """
34
+ super().__init__(token)
35
+ self.token = token
36
+ self.dictionary = dictionary
37
+ self.extract_type = extract_type
38
+
39
+ def __str__(self) -> str:
40
+ """Return string representation."""
41
+ if self.extract_type == "names":
42
+ return f"the names of {self.dictionary}"
43
+ else:
44
+ return f"the contents of {self.dictionary}"
45
+
46
+ def desugar(self) -> DictExtraction:
47
+ """Desugar by recursively desugaring the dictionary."""
48
+ return DictExtraction(
49
+ self.token,
50
+ self.dictionary.desugar() if hasattr(self.dictionary, "desugar") else self.dictionary,
51
+ self.extract_type,
52
+ )
53
+
54
+ def to_hir(self) -> DictExtraction:
55
+ """Convert to HIR representation."""
56
+ return DictExtraction(
57
+ self.token,
58
+ self.dictionary.to_hir() if hasattr(self.dictionary, "to_hir") else self.dictionary,
59
+ self.extract_type,
60
+ )