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,418 @@
1
+ """Tests for symbol table management."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import pytest
6
+
7
+ from machine_dialect.codegen.symtab import Scope, Symbol, SymbolTable, SymbolType
8
+
9
+
10
+ class TestSymbolType:
11
+ """Test SymbolType enum."""
12
+
13
+ def test_symbol_types(self) -> None:
14
+ """Test all symbol type values."""
15
+ assert SymbolType.LOCAL.value == "local"
16
+ assert SymbolType.GLOBAL.value == "global"
17
+ assert SymbolType.PARAMETER.value == "parameter"
18
+
19
+
20
+ class TestSymbol:
21
+ """Test Symbol dataclass."""
22
+
23
+ def test_create_symbol(self) -> None:
24
+ """Test creating a symbol."""
25
+ symbol = Symbol("x", SymbolType.LOCAL, 0)
26
+ assert symbol.name == "x"
27
+ assert symbol.symbol_type == SymbolType.LOCAL
28
+ assert symbol.slot == 0
29
+
30
+ def test_create_global_symbol(self) -> None:
31
+ """Test creating a global symbol."""
32
+ symbol = Symbol("global_var", SymbolType.GLOBAL, -1)
33
+ assert symbol.name == "global_var"
34
+ assert symbol.symbol_type == SymbolType.GLOBAL
35
+ assert symbol.slot == -1
36
+
37
+ def test_create_parameter_symbol(self) -> None:
38
+ """Test creating a parameter symbol."""
39
+ symbol = Symbol("param", SymbolType.PARAMETER, 1)
40
+ assert symbol.name == "param"
41
+ assert symbol.symbol_type == SymbolType.PARAMETER
42
+ assert symbol.slot == 1
43
+
44
+
45
+ class TestScope:
46
+ """Test Scope class."""
47
+
48
+ def test_create_global_scope(self) -> None:
49
+ """Test creating a global scope."""
50
+ scope = Scope()
51
+ assert scope.parent is None
52
+ assert scope.name == "global"
53
+ assert scope.is_global is True
54
+ assert len(scope.symbols) == 0
55
+ assert scope.next_slot == 0
56
+
57
+ def test_create_nested_scope(self) -> None:
58
+ """Test creating a nested scope."""
59
+ parent = Scope()
60
+ child = Scope(parent, "function")
61
+ assert child.parent is parent
62
+ assert child.name == "function"
63
+ assert child.is_global is False
64
+ assert len(child.symbols) == 0
65
+ assert child.next_slot == 0
66
+
67
+ def test_define_local_variable(self) -> None:
68
+ """Test defining a local variable."""
69
+ scope = Scope(Scope(), "function")
70
+ symbol = scope.define_local("x")
71
+
72
+ assert symbol.name == "x"
73
+ assert symbol.symbol_type == SymbolType.LOCAL
74
+ assert symbol.slot == 0
75
+ assert scope.next_slot == 1
76
+ assert "x" in scope.symbols
77
+
78
+ def test_define_local_variable_already_exists(self) -> None:
79
+ """Test defining a local variable that already exists."""
80
+ scope = Scope(Scope(), "function")
81
+ symbol1 = scope.define_local("x")
82
+ symbol2 = scope.define_local("x")
83
+
84
+ # Should return the same symbol
85
+ assert symbol1 is symbol2
86
+ assert scope.next_slot == 1 # Should not increment
87
+
88
+ def test_define_multiple_local_variables(self) -> None:
89
+ """Test defining multiple local variables."""
90
+ scope = Scope(Scope(), "function")
91
+ x = scope.define_local("x")
92
+ y = scope.define_local("y")
93
+ z = scope.define_local("z")
94
+
95
+ assert x.slot == 0
96
+ assert y.slot == 1
97
+ assert z.slot == 2
98
+ assert scope.next_slot == 3
99
+
100
+ def test_define_parameter(self) -> None:
101
+ """Test defining a parameter."""
102
+ scope = Scope(Scope(), "function")
103
+ symbol = scope.define_parameter("param")
104
+
105
+ assert symbol.name == "param"
106
+ assert symbol.symbol_type == SymbolType.PARAMETER
107
+ assert symbol.slot == 0
108
+ assert scope.next_slot == 1
109
+ assert "param" in scope.symbols
110
+
111
+ def test_define_multiple_parameters(self) -> None:
112
+ """Test defining multiple parameters."""
113
+ scope = Scope(Scope(), "function")
114
+ a = scope.define_parameter("a")
115
+ b = scope.define_parameter("b")
116
+
117
+ assert a.slot == 0
118
+ assert b.slot == 1
119
+ assert scope.next_slot == 2
120
+
121
+ def test_define_global_variable(self) -> None:
122
+ """Test defining a global variable."""
123
+ scope = Scope()
124
+ symbol = scope.define_global("global_var")
125
+
126
+ assert symbol.name == "global_var"
127
+ assert symbol.symbol_type == SymbolType.GLOBAL
128
+ assert symbol.slot == -1
129
+ assert scope.next_slot == 0 # Globals don't use slots
130
+ assert "global_var" in scope.symbols
131
+
132
+ def test_resolve_in_current_scope(self) -> None:
133
+ """Test resolving a variable in the current scope."""
134
+ scope = Scope(Scope(), "function")
135
+ defined_symbol = scope.define_local("x")
136
+ resolved_symbol = scope.resolve("x")
137
+
138
+ assert resolved_symbol is defined_symbol
139
+
140
+ def test_resolve_in_parent_scope(self) -> None:
141
+ """Test resolving a variable in parent scope."""
142
+ parent = Scope()
143
+ parent_symbol = parent.define_global("global_var")
144
+ child = Scope(parent, "function")
145
+
146
+ resolved_symbol = child.resolve("global_var")
147
+ assert resolved_symbol is parent_symbol
148
+
149
+ def test_resolve_nested_scopes(self) -> None:
150
+ """Test resolving through multiple nested scopes."""
151
+ grandparent = Scope()
152
+ grandparent_symbol = grandparent.define_global("x")
153
+
154
+ parent = Scope(grandparent, "outer")
155
+ child = Scope(parent, "inner")
156
+
157
+ resolved_symbol = child.resolve("x")
158
+ assert resolved_symbol is grandparent_symbol
159
+
160
+ def test_resolve_not_found(self) -> None:
161
+ """Test resolving a non-existent variable."""
162
+ scope = Scope()
163
+ resolved_symbol = scope.resolve("nonexistent")
164
+ assert resolved_symbol is None
165
+
166
+ def test_resolve_shadowing(self) -> None:
167
+ """Test variable shadowing."""
168
+ parent = Scope()
169
+ parent.define_global("x")
170
+
171
+ child = Scope(parent, "function")
172
+ child_symbol = child.define_local("x")
173
+
174
+ # Should resolve to child's x, not parent's
175
+ resolved_symbol = child.resolve("x")
176
+ assert resolved_symbol is child_symbol
177
+ assert resolved_symbol.symbol_type == SymbolType.LOCAL
178
+
179
+ def test_num_locals(self) -> None:
180
+ """Test getting number of locals."""
181
+ scope = Scope(Scope(), "function")
182
+ assert scope.num_locals() == 0
183
+
184
+ scope.define_local("x")
185
+ assert scope.num_locals() == 1
186
+
187
+ scope.define_local("y")
188
+ assert scope.num_locals() == 2
189
+
190
+ # Parameters also count as locals for slot allocation
191
+ scope.define_parameter("param")
192
+ assert scope.num_locals() == 3
193
+
194
+ def test_num_locals_globals_dont_count(self) -> None:
195
+ """Test that globals don't count toward num_locals."""
196
+ scope = Scope()
197
+ scope.define_global("global1")
198
+ scope.define_global("global2")
199
+ assert scope.num_locals() == 0
200
+
201
+
202
+ class TestSymbolTable:
203
+ """Test SymbolTable class."""
204
+
205
+ def test_create_symbol_table(self) -> None:
206
+ """Test creating a symbol table."""
207
+ symtab = SymbolTable()
208
+ assert symtab.current_scope is symtab.global_scope
209
+ assert symtab.current_scope.name == "global"
210
+ assert symtab.is_global_scope() is True
211
+
212
+ def test_enter_scope(self) -> None:
213
+ """Test entering a new scope."""
214
+ symtab = SymbolTable()
215
+ symtab.enter_scope("function")
216
+
217
+ assert symtab.current_scope.name == "function"
218
+ assert symtab.current_scope.parent is symtab.global_scope
219
+ assert symtab.is_global_scope() is False
220
+
221
+ def test_exit_scope(self) -> None:
222
+ """Test exiting a scope."""
223
+ symtab = SymbolTable()
224
+ symtab.enter_scope("function")
225
+ symtab.exit_scope()
226
+
227
+ assert symtab.current_scope is symtab.global_scope
228
+ assert symtab.is_global_scope() is True
229
+
230
+ def test_exit_global_scope_raises_error(self) -> None:
231
+ """Test that exiting global scope raises an error."""
232
+ symtab = SymbolTable()
233
+ with pytest.raises(RuntimeError, match="Cannot exit global scope"):
234
+ symtab.exit_scope()
235
+
236
+ def test_nested_scopes(self) -> None:
237
+ """Test nested scope management."""
238
+ symtab = SymbolTable()
239
+
240
+ # Enter function scope
241
+ symtab.enter_scope("function")
242
+ function_scope = symtab.current_scope
243
+
244
+ # Enter block scope
245
+ symtab.enter_scope("block")
246
+ block_scope = symtab.current_scope
247
+
248
+ assert block_scope.parent is function_scope
249
+ assert function_scope.parent is symtab.global_scope
250
+
251
+ # Exit back to function
252
+ symtab.exit_scope()
253
+ assert symtab.current_scope is function_scope
254
+
255
+ # Exit back to global
256
+ symtab.exit_scope()
257
+ assert symtab.current_scope is symtab.global_scope
258
+
259
+ def test_define_in_global_scope(self) -> None:
260
+ """Test defining variables in global scope."""
261
+ symtab = SymbolTable()
262
+ symbol = symtab.define("global_var")
263
+
264
+ assert symbol.symbol_type == SymbolType.GLOBAL
265
+ assert symbol.slot == -1
266
+ assert symbol.name == "global_var"
267
+
268
+ def test_define_in_local_scope(self) -> None:
269
+ """Test defining variables in local scope."""
270
+ symtab = SymbolTable()
271
+ symtab.enter_scope("function")
272
+
273
+ symbol = symtab.define("local_var")
274
+ assert symbol.symbol_type == SymbolType.LOCAL
275
+ assert symbol.slot == 0
276
+ assert symbol.name == "local_var"
277
+
278
+ def test_define_parameter(self) -> None:
279
+ """Test defining parameters."""
280
+ symtab = SymbolTable()
281
+ symtab.enter_scope("function")
282
+
283
+ symbol = symtab.define("param", is_parameter=True)
284
+ assert symbol.symbol_type == SymbolType.PARAMETER
285
+ assert symbol.slot == 0
286
+ assert symbol.name == "param"
287
+
288
+ def test_define_parameter_in_global_scope(self) -> None:
289
+ """Test that parameters in global scope become globals."""
290
+ symtab = SymbolTable()
291
+ symbol = symtab.define("param", is_parameter=True)
292
+
293
+ # In global scope, parameters become globals
294
+ assert symbol.symbol_type == SymbolType.GLOBAL
295
+ assert symbol.slot == -1
296
+
297
+ def test_resolve_local_variable(self) -> None:
298
+ """Test resolving a local variable."""
299
+ symtab = SymbolTable()
300
+ symtab.enter_scope("function")
301
+
302
+ defined_symbol = symtab.define("x")
303
+ resolved_symbol = symtab.resolve("x")
304
+
305
+ assert resolved_symbol is defined_symbol
306
+
307
+ def test_resolve_global_variable(self) -> None:
308
+ """Test resolving a global variable."""
309
+ symtab = SymbolTable()
310
+ global_symbol = symtab.define("global_var")
311
+
312
+ symtab.enter_scope("function")
313
+ resolved_symbol = symtab.resolve("global_var")
314
+
315
+ assert resolved_symbol is global_symbol
316
+
317
+ def test_resolve_creates_implicit_global(self) -> None:
318
+ """Test that resolving undefined variable creates implicit global."""
319
+ symtab = SymbolTable()
320
+ symtab.enter_scope("function")
321
+
322
+ resolved_symbol = symtab.resolve("undefined_var")
323
+
324
+ assert resolved_symbol is not None
325
+ assert resolved_symbol.name == "undefined_var"
326
+ assert resolved_symbol.symbol_type == SymbolType.GLOBAL
327
+ assert resolved_symbol.slot == -1
328
+
329
+ def test_resolve_in_global_scope_returns_none(self) -> None:
330
+ """Test that resolving undefined var in global scope returns None."""
331
+ symtab = SymbolTable()
332
+ resolved_symbol = symtab.resolve("undefined_var")
333
+ assert resolved_symbol is None
334
+
335
+ def test_num_locals(self) -> None:
336
+ """Test getting number of locals in current scope."""
337
+ symtab = SymbolTable()
338
+ assert symtab.num_locals() == 0
339
+
340
+ symtab.enter_scope("function")
341
+ assert symtab.num_locals() == 0
342
+
343
+ symtab.define("x")
344
+ assert symtab.num_locals() == 1
345
+
346
+ symtab.define("y")
347
+ assert symtab.num_locals() == 2
348
+
349
+ def test_current_scope_name(self) -> None:
350
+ """Test getting current scope name."""
351
+ symtab = SymbolTable()
352
+ assert symtab.current_scope_name() == "global"
353
+
354
+ symtab.enter_scope("function")
355
+ assert symtab.current_scope_name() == "function"
356
+
357
+ symtab.enter_scope("block")
358
+ assert symtab.current_scope_name() == "block"
359
+
360
+ def test_complex_scoping_scenario(self) -> None:
361
+ """Test a complex scenario with multiple scopes and variables."""
362
+ symtab = SymbolTable()
363
+
364
+ # Define global variable
365
+ global_var = symtab.define("global_var")
366
+
367
+ # Enter function scope
368
+ symtab.enter_scope("function")
369
+ param1 = symtab.define("param1", is_parameter=True)
370
+ param2 = symtab.define("param2", is_parameter=True)
371
+ local1 = symtab.define("local1")
372
+
373
+ # Enter block scope
374
+ symtab.enter_scope("block")
375
+ local2 = symtab.define("local2")
376
+
377
+ # Test resolution from deepest scope
378
+ assert symtab.resolve("local2") is local2
379
+ assert symtab.resolve("local1") is local1
380
+ assert symtab.resolve("param1") is param1
381
+ assert symtab.resolve("global_var") is global_var
382
+
383
+ # Test slot allocation
384
+ assert param1.slot == 0
385
+ assert param2.slot == 1
386
+ assert local1.slot == 2
387
+ assert local2.slot == 0 # New scope, new slot numbering
388
+
389
+ # Test scope info
390
+ assert symtab.current_scope_name() == "block"
391
+ assert symtab.num_locals() == 1 # Only local2 in current scope
392
+
393
+ symtab.exit_scope()
394
+ assert symtab.num_locals() == 3 # param1, param2, local1
395
+
396
+ def test_variable_shadowing_through_symbol_table(self) -> None:
397
+ """Test variable shadowing through symbol table interface."""
398
+ symtab = SymbolTable()
399
+
400
+ # Define global x
401
+ global_x = symtab.define("x")
402
+
403
+ # Enter function and define local x
404
+ symtab.enter_scope("function")
405
+ local_x = symtab.define("x")
406
+
407
+ # Should resolve to local x
408
+ resolved_x = symtab.resolve("x")
409
+ assert resolved_x is local_x
410
+ assert resolved_x.symbol_type == SymbolType.LOCAL
411
+
412
+ # Exit function scope
413
+ symtab.exit_scope()
414
+
415
+ # Should now resolve to global x
416
+ resolved_x = symtab.resolve("x")
417
+ assert resolved_x is global_x
418
+ assert resolved_x.symbol_type == SymbolType.GLOBAL