zexus 1.6.2

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 (227) hide show
  1. package/LICENSE +0 -0
  2. package/README.md +2513 -0
  3. package/bin/zexus +2 -0
  4. package/bin/zpics +2 -0
  5. package/bin/zpm +2 -0
  6. package/bin/zx +2 -0
  7. package/bin/zx-deploy +2 -0
  8. package/bin/zx-dev +2 -0
  9. package/bin/zx-run +2 -0
  10. package/package.json +66 -0
  11. package/scripts/README.md +24 -0
  12. package/scripts/postinstall.js +44 -0
  13. package/shared_config.json +24 -0
  14. package/src/README.md +1525 -0
  15. package/src/tests/run_zexus_tests.py +117 -0
  16. package/src/tests/test_all_phases.zx +346 -0
  17. package/src/tests/test_blockchain_features.zx +306 -0
  18. package/src/tests/test_complexity_features.zx +321 -0
  19. package/src/tests/test_core_integration.py +185 -0
  20. package/src/tests/test_phase10_ecosystem.zx +177 -0
  21. package/src/tests/test_phase1_modifiers.zx +87 -0
  22. package/src/tests/test_phase2_plugins.zx +80 -0
  23. package/src/tests/test_phase3_security.zx +97 -0
  24. package/src/tests/test_phase4_vfs.zx +116 -0
  25. package/src/tests/test_phase5_types.zx +117 -0
  26. package/src/tests/test_phase6_metaprogramming.zx +125 -0
  27. package/src/tests/test_phase7_optimization.zx +132 -0
  28. package/src/tests/test_phase9_advanced_types.zx +157 -0
  29. package/src/tests/test_security_features.py +419 -0
  30. package/src/tests/test_security_features.zx +276 -0
  31. package/src/tests/test_simple_zx.zx +1 -0
  32. package/src/tests/test_verification_simple.zx +69 -0
  33. package/src/zexus/__init__.py +28 -0
  34. package/src/zexus/__main__.py +5 -0
  35. package/src/zexus/__pycache__/__init__.cpython-312.pyc +0 -0
  36. package/src/zexus/__pycache__/advanced_types.cpython-312.pyc +0 -0
  37. package/src/zexus/__pycache__/builtin_modules.cpython-312.pyc +0 -0
  38. package/src/zexus/__pycache__/capability_system.cpython-312.pyc +0 -0
  39. package/src/zexus/__pycache__/complexity_system.cpython-312.pyc +0 -0
  40. package/src/zexus/__pycache__/concurrency_system.cpython-312.pyc +0 -0
  41. package/src/zexus/__pycache__/config.cpython-312.pyc +0 -0
  42. package/src/zexus/__pycache__/dependency_injection.cpython-312.pyc +0 -0
  43. package/src/zexus/__pycache__/ecosystem.cpython-312.pyc +0 -0
  44. package/src/zexus/__pycache__/environment.cpython-312.pyc +0 -0
  45. package/src/zexus/__pycache__/error_reporter.cpython-312.pyc +0 -0
  46. package/src/zexus/__pycache__/hybrid_orchestrator.cpython-312.pyc +0 -0
  47. package/src/zexus/__pycache__/lexer.cpython-312.pyc +0 -0
  48. package/src/zexus/__pycache__/metaprogramming.cpython-312.pyc +0 -0
  49. package/src/zexus/__pycache__/module_cache.cpython-312.pyc +0 -0
  50. package/src/zexus/__pycache__/object.cpython-312.pyc +0 -0
  51. package/src/zexus/__pycache__/optimization.cpython-312.pyc +0 -0
  52. package/src/zexus/__pycache__/plugin_system.cpython-312.pyc +0 -0
  53. package/src/zexus/__pycache__/policy_engine.cpython-312.pyc +0 -0
  54. package/src/zexus/__pycache__/security.cpython-312.pyc +0 -0
  55. package/src/zexus/__pycache__/stdlib_integration.cpython-312.pyc +0 -0
  56. package/src/zexus/__pycache__/strategy_recovery.cpython-312.pyc +0 -0
  57. package/src/zexus/__pycache__/syntax_validator.cpython-312.pyc +0 -0
  58. package/src/zexus/__pycache__/type_system.cpython-312.pyc +0 -0
  59. package/src/zexus/__pycache__/virtual_filesystem.cpython-312.pyc +0 -0
  60. package/src/zexus/__pycache__/zexus_ast.cpython-312.pyc +0 -0
  61. package/src/zexus/__pycache__/zexus_token.cpython-312.pyc +0 -0
  62. package/src/zexus/advanced_types.py +401 -0
  63. package/src/zexus/blockchain/__init__.py +40 -0
  64. package/src/zexus/blockchain/__pycache__/__init__.cpython-312.pyc +0 -0
  65. package/src/zexus/blockchain/__pycache__/crypto.cpython-312.pyc +0 -0
  66. package/src/zexus/blockchain/__pycache__/ledger.cpython-312.pyc +0 -0
  67. package/src/zexus/blockchain/__pycache__/transaction.cpython-312.pyc +0 -0
  68. package/src/zexus/blockchain/crypto.py +463 -0
  69. package/src/zexus/blockchain/ledger.py +255 -0
  70. package/src/zexus/blockchain/transaction.py +267 -0
  71. package/src/zexus/builtin_modules.py +284 -0
  72. package/src/zexus/builtin_plugins.py +317 -0
  73. package/src/zexus/capability_system.py +372 -0
  74. package/src/zexus/cli/__init__.py +2 -0
  75. package/src/zexus/cli/__pycache__/__init__.cpython-312.pyc +0 -0
  76. package/src/zexus/cli/__pycache__/main.cpython-312.pyc +0 -0
  77. package/src/zexus/cli/main.py +707 -0
  78. package/src/zexus/cli/zpm.py +203 -0
  79. package/src/zexus/compare_interpreter_compiler.py +146 -0
  80. package/src/zexus/compiler/__init__.py +169 -0
  81. package/src/zexus/compiler/__pycache__/__init__.cpython-312.pyc +0 -0
  82. package/src/zexus/compiler/__pycache__/lexer.cpython-312.pyc +0 -0
  83. package/src/zexus/compiler/__pycache__/parser.cpython-312.pyc +0 -0
  84. package/src/zexus/compiler/__pycache__/zexus_ast.cpython-312.pyc +0 -0
  85. package/src/zexus/compiler/bytecode.py +266 -0
  86. package/src/zexus/compiler/compat_runtime.py +277 -0
  87. package/src/zexus/compiler/lexer.py +257 -0
  88. package/src/zexus/compiler/parser.py +779 -0
  89. package/src/zexus/compiler/semantic.py +118 -0
  90. package/src/zexus/compiler/zexus_ast.py +454 -0
  91. package/src/zexus/complexity_system.py +575 -0
  92. package/src/zexus/concurrency_system.py +493 -0
  93. package/src/zexus/config.py +201 -0
  94. package/src/zexus/crypto_bridge.py +19 -0
  95. package/src/zexus/dependency_injection.py +423 -0
  96. package/src/zexus/ecosystem.py +434 -0
  97. package/src/zexus/environment.py +101 -0
  98. package/src/zexus/environment_manager.py +119 -0
  99. package/src/zexus/error_reporter.py +314 -0
  100. package/src/zexus/evaluator/__init__.py +12 -0
  101. package/src/zexus/evaluator/__pycache__/__init__.cpython-312.pyc +0 -0
  102. package/src/zexus/evaluator/__pycache__/bytecode_compiler.cpython-312.pyc +0 -0
  103. package/src/zexus/evaluator/__pycache__/core.cpython-312.pyc +0 -0
  104. package/src/zexus/evaluator/__pycache__/expressions.cpython-312.pyc +0 -0
  105. package/src/zexus/evaluator/__pycache__/functions.cpython-312.pyc +0 -0
  106. package/src/zexus/evaluator/__pycache__/integration.cpython-312.pyc +0 -0
  107. package/src/zexus/evaluator/__pycache__/statements.cpython-312.pyc +0 -0
  108. package/src/zexus/evaluator/__pycache__/utils.cpython-312.pyc +0 -0
  109. package/src/zexus/evaluator/bytecode_compiler.py +700 -0
  110. package/src/zexus/evaluator/core.py +891 -0
  111. package/src/zexus/evaluator/expressions.py +827 -0
  112. package/src/zexus/evaluator/functions.py +3989 -0
  113. package/src/zexus/evaluator/integration.py +396 -0
  114. package/src/zexus/evaluator/statements.py +4303 -0
  115. package/src/zexus/evaluator/utils.py +126 -0
  116. package/src/zexus/evaluator_original.py +2041 -0
  117. package/src/zexus/external_bridge.py +16 -0
  118. package/src/zexus/find_affected_imports.sh +155 -0
  119. package/src/zexus/hybrid_orchestrator.py +152 -0
  120. package/src/zexus/input_validation.py +259 -0
  121. package/src/zexus/lexer.py +571 -0
  122. package/src/zexus/logging.py +89 -0
  123. package/src/zexus/lsp/__init__.py +9 -0
  124. package/src/zexus/lsp/completion_provider.py +207 -0
  125. package/src/zexus/lsp/definition_provider.py +22 -0
  126. package/src/zexus/lsp/hover_provider.py +71 -0
  127. package/src/zexus/lsp/server.py +269 -0
  128. package/src/zexus/lsp/symbol_provider.py +31 -0
  129. package/src/zexus/metaprogramming.py +321 -0
  130. package/src/zexus/module_cache.py +89 -0
  131. package/src/zexus/module_manager.py +107 -0
  132. package/src/zexus/object.py +973 -0
  133. package/src/zexus/optimization.py +424 -0
  134. package/src/zexus/parser/__init__.py +31 -0
  135. package/src/zexus/parser/__pycache__/__init__.cpython-312.pyc +0 -0
  136. package/src/zexus/parser/__pycache__/parser.cpython-312.pyc +0 -0
  137. package/src/zexus/parser/__pycache__/strategy_context.cpython-312.pyc +0 -0
  138. package/src/zexus/parser/__pycache__/strategy_structural.cpython-312.pyc +0 -0
  139. package/src/zexus/parser/integration.py +86 -0
  140. package/src/zexus/parser/parser.py +3977 -0
  141. package/src/zexus/parser/strategy_context.py +7254 -0
  142. package/src/zexus/parser/strategy_structural.py +1033 -0
  143. package/src/zexus/persistence.py +391 -0
  144. package/src/zexus/plugin_system.py +290 -0
  145. package/src/zexus/policy_engine.py +365 -0
  146. package/src/zexus/profiler/__init__.py +5 -0
  147. package/src/zexus/profiler/profiler.py +233 -0
  148. package/src/zexus/purity_system.py +398 -0
  149. package/src/zexus/runtime/__init__.py +20 -0
  150. package/src/zexus/runtime/async_runtime.py +324 -0
  151. package/src/zexus/search_old_imports.sh +65 -0
  152. package/src/zexus/security.py +1407 -0
  153. package/src/zexus/stack_trace.py +233 -0
  154. package/src/zexus/stdlib/__init__.py +27 -0
  155. package/src/zexus/stdlib/blockchain.py +341 -0
  156. package/src/zexus/stdlib/compression.py +167 -0
  157. package/src/zexus/stdlib/crypto.py +124 -0
  158. package/src/zexus/stdlib/datetime.py +163 -0
  159. package/src/zexus/stdlib/db_mongo.py +199 -0
  160. package/src/zexus/stdlib/db_mysql.py +162 -0
  161. package/src/zexus/stdlib/db_postgres.py +163 -0
  162. package/src/zexus/stdlib/db_sqlite.py +133 -0
  163. package/src/zexus/stdlib/encoding.py +230 -0
  164. package/src/zexus/stdlib/fs.py +195 -0
  165. package/src/zexus/stdlib/http.py +219 -0
  166. package/src/zexus/stdlib/http_server.py +248 -0
  167. package/src/zexus/stdlib/json_module.py +61 -0
  168. package/src/zexus/stdlib/math.py +360 -0
  169. package/src/zexus/stdlib/os_module.py +265 -0
  170. package/src/zexus/stdlib/regex.py +148 -0
  171. package/src/zexus/stdlib/sockets.py +253 -0
  172. package/src/zexus/stdlib/test_framework.zx +208 -0
  173. package/src/zexus/stdlib/test_runner.zx +119 -0
  174. package/src/zexus/stdlib_integration.py +341 -0
  175. package/src/zexus/strategy_recovery.py +256 -0
  176. package/src/zexus/syntax_validator.py +356 -0
  177. package/src/zexus/testing/zpics.py +407 -0
  178. package/src/zexus/testing/zpics_runtime.py +369 -0
  179. package/src/zexus/type_system.py +374 -0
  180. package/src/zexus/validation_system.py +569 -0
  181. package/src/zexus/virtual_filesystem.py +355 -0
  182. package/src/zexus/vm/__init__.py +8 -0
  183. package/src/zexus/vm/__pycache__/__init__.cpython-312.pyc +0 -0
  184. package/src/zexus/vm/__pycache__/async_optimizer.cpython-312.pyc +0 -0
  185. package/src/zexus/vm/__pycache__/bytecode.cpython-312.pyc +0 -0
  186. package/src/zexus/vm/__pycache__/cache.cpython-312.pyc +0 -0
  187. package/src/zexus/vm/__pycache__/jit.cpython-312.pyc +0 -0
  188. package/src/zexus/vm/__pycache__/memory_manager.cpython-312.pyc +0 -0
  189. package/src/zexus/vm/__pycache__/memory_pool.cpython-312.pyc +0 -0
  190. package/src/zexus/vm/__pycache__/optimizer.cpython-312.pyc +0 -0
  191. package/src/zexus/vm/__pycache__/parallel_vm.cpython-312.pyc +0 -0
  192. package/src/zexus/vm/__pycache__/peephole_optimizer.cpython-312.pyc +0 -0
  193. package/src/zexus/vm/__pycache__/profiler.cpython-312.pyc +0 -0
  194. package/src/zexus/vm/__pycache__/register_allocator.cpython-312.pyc +0 -0
  195. package/src/zexus/vm/__pycache__/register_vm.cpython-312.pyc +0 -0
  196. package/src/zexus/vm/__pycache__/ssa_converter.cpython-312.pyc +0 -0
  197. package/src/zexus/vm/__pycache__/vm.cpython-312.pyc +0 -0
  198. package/src/zexus/vm/async_optimizer.py +420 -0
  199. package/src/zexus/vm/bytecode.py +428 -0
  200. package/src/zexus/vm/bytecode_converter.py +297 -0
  201. package/src/zexus/vm/cache.py +532 -0
  202. package/src/zexus/vm/jit.py +720 -0
  203. package/src/zexus/vm/memory_manager.py +520 -0
  204. package/src/zexus/vm/memory_pool.py +511 -0
  205. package/src/zexus/vm/optimizer.py +478 -0
  206. package/src/zexus/vm/parallel_vm.py +899 -0
  207. package/src/zexus/vm/peephole_optimizer.py +452 -0
  208. package/src/zexus/vm/profiler.py +527 -0
  209. package/src/zexus/vm/register_allocator.py +462 -0
  210. package/src/zexus/vm/register_vm.py +520 -0
  211. package/src/zexus/vm/ssa_converter.py +757 -0
  212. package/src/zexus/vm/vm.py +1392 -0
  213. package/src/zexus/zexus_ast.py +1782 -0
  214. package/src/zexus/zexus_token.py +253 -0
  215. package/src/zexus/zpm/__init__.py +15 -0
  216. package/src/zexus/zpm/installer.py +116 -0
  217. package/src/zexus/zpm/package_manager.py +208 -0
  218. package/src/zexus/zpm/publisher.py +98 -0
  219. package/src/zexus/zpm/registry.py +110 -0
  220. package/src/zexus.egg-info/PKG-INFO +2235 -0
  221. package/src/zexus.egg-info/SOURCES.txt +876 -0
  222. package/src/zexus.egg-info/dependency_links.txt +1 -0
  223. package/src/zexus.egg-info/entry_points.txt +3 -0
  224. package/src/zexus.egg-info/not-zip-safe +1 -0
  225. package/src/zexus.egg-info/requires.txt +14 -0
  226. package/src/zexus.egg-info/top_level.txt +2 -0
  227. package/zexus.json +14 -0
@@ -0,0 +1,779 @@
1
+ # parser.py (TOLERANT MULTI-STRATEGY PARSER)
2
+ """
3
+ Clean Production Parser for Zexus - Fixes Object Literal Issue
4
+ """
5
+
6
+ from ..zexus_token import *
7
+ from .lexer import Lexer
8
+ from .zexus_ast import *
9
+
10
+ # Precedence constants
11
+ LOWEST, ASSIGN_PREC, EQUALS, LESSGREATER, SUM, PRODUCT, PREFIX, CALL, LOGICAL = 1, 2, 3, 4, 5, 6, 7, 8, 9
12
+
13
+ precedences = {
14
+ EQ: EQUALS, NOT_EQ: EQUALS,
15
+ LT: LESSGREATER, GT: LESSGREATER, LTE: LESSGREATER, GTE: LESSGREATER,
16
+ PLUS: SUM, MINUS: SUM,
17
+ SLASH: PRODUCT, STAR: PRODUCT, MOD: PRODUCT,
18
+ AND: LOGICAL, OR: LOGICAL,
19
+ LPAREN: CALL,
20
+ DOT: CALL,
21
+ ASSIGN: ASSIGN_PREC,
22
+ }
23
+
24
+ class ProductionParser:
25
+ def __init__(self, lexer):
26
+ self.lexer = lexer
27
+ self.errors = []
28
+ self.cur_token = None
29
+ self.peek_token = None
30
+
31
+ # Parser function maps
32
+ self.prefix_parse_fns = {
33
+ IDENT: self.parse_identifier,
34
+ INT: self.parse_integer_literal,
35
+ FLOAT: self.parse_float_literal,
36
+ STRING: self.parse_string_literal,
37
+ BANG: self.parse_prefix_expression,
38
+ MINUS: self.parse_prefix_expression,
39
+ TRUE: self.parse_boolean,
40
+ FALSE: self.parse_boolean,
41
+ LPAREN: self.parse_grouped_expression,
42
+ IF: self.parse_if_expression,
43
+ LBRACKET: self.parse_list_literal,
44
+ LBRACE: self.parse_map_literal, # FIXED: Map literal parsing
45
+ ACTION: self.parse_action_literal,
46
+ EMBEDDED: self.parse_embedded_literal,
47
+ LAMBDA: self.parse_lambda_expression,
48
+ AWAIT: self.parse_await_expression, # NEW: Await expression
49
+ }
50
+
51
+ self.infix_parse_fns = {
52
+ PLUS: self.parse_infix_expression,
53
+ MINUS: self.parse_infix_expression,
54
+ SLASH: self.parse_infix_expression,
55
+ STAR: self.parse_infix_expression,
56
+ MOD: self.parse_infix_expression,
57
+ EQ: self.parse_infix_expression,
58
+ NOT_EQ: self.parse_infix_expression,
59
+ LT: self.parse_infix_expression,
60
+ GT: self.parse_infix_expression,
61
+ LTE: self.parse_infix_expression,
62
+ GTE: self.parse_infix_expression,
63
+ AND: self.parse_infix_expression,
64
+ OR: self.parse_infix_expression,
65
+ ASSIGN: self.parse_assignment_expression,
66
+ LPAREN: self.parse_call_expression,
67
+ DOT: self.parse_method_call_expression,
68
+ LAMBDA: self.parse_lambda_infix, # support arrow-style lambdas: params => body
69
+ }
70
+
71
+ self.next_token()
72
+ self.next_token()
73
+
74
+ def parse_program(self):
75
+ """Clean, efficient program parsing"""
76
+ program = Program()
77
+ while not self.cur_token_is(EOF):
78
+ # Tolerant: skip stray semicolons between statements
79
+ if self.cur_token_is(SEMICOLON):
80
+ self.next_token()
81
+ continue
82
+
83
+ stmt = self.parse_statement()
84
+ if stmt:
85
+ program.statements.append(stmt)
86
+
87
+ self.next_token()
88
+ return program
89
+
90
+ def parse_statement(self):
91
+ """Parse statements with clear error reporting"""
92
+ try:
93
+ if self.cur_token_is(LET):
94
+ return self.parse_let_statement()
95
+ elif self.cur_token_is(RETURN):
96
+ return self.parse_return_statement()
97
+ elif self.cur_token_is(PRINT):
98
+ return self.parse_print_statement()
99
+ elif self.cur_token_is(FOR):
100
+ return self.parse_for_each_statement()
101
+ elif self.cur_token_is(ACTION):
102
+ return self.parse_action_statement()
103
+ elif self.cur_token_is(ASYNC):
104
+ # support "async action name ..." or "action async name ..."
105
+ # If "async action ..." then consume ASYNC and expect ACTION next
106
+ self.next_token()
107
+ if self.cur_token_is(ACTION):
108
+ return self.parse_action_statement(async_flag=True)
109
+ # otherwise error
110
+ self.errors.append(f"Line {self.cur_token.line}: Expected 'action' after 'async'")
111
+ return None
112
+ elif self.cur_token_is(EVENT):
113
+ return self.parse_event_declaration()
114
+ elif self.cur_token_is(EMIT):
115
+ return self.parse_emit_statement()
116
+ elif self.cur_token_is(ENUM):
117
+ return self.parse_enum_declaration()
118
+ elif self.cur_token_is(PROTOCOL):
119
+ return self.parse_protocol_declaration()
120
+ elif self.cur_token_is(IMPORT):
121
+ return self.parse_import_statement()
122
+ else:
123
+ return self.parse_expression_statement()
124
+ except Exception as e:
125
+ self.errors.append(f"Line {self.cur_token.line}: Parse error - {str(e)}")
126
+ return None
127
+
128
+ def parse_let_statement(self):
129
+ """Fixed: Properly handles object literals"""
130
+ if not self.expect_peek(IDENT):
131
+ self.errors.append(f"Line {self.cur_token.line}: Expected variable name after 'let'")
132
+ return None
133
+
134
+ name = Identifier(self.cur_token.literal)
135
+
136
+ if not self.expect_peek(ASSIGN):
137
+ return None
138
+
139
+ self.next_token()
140
+ value = self.parse_expression(LOWEST)
141
+
142
+ return LetStatement(name=name, value=value)
143
+
144
+ def parse_map_literal(self):
145
+ """FIXED: Proper map literal parsing - this was the core issue!"""
146
+ pairs = []
147
+
148
+ # Must be called when current token is LBRACE
149
+ if not self.cur_token_is(LBRACE):
150
+ self.errors.append(f"Line {getattr(self.cur_token, 'line', 'unknown')}: parse_map_literal called on non-brace token")
151
+ return None
152
+
153
+ # Move inside the braces
154
+ self.next_token() # advance to token after '{'
155
+
156
+ # Handle empty object case: {}
157
+ if self.cur_token_is(RBRACE):
158
+ return MapLiteral(pairs)
159
+
160
+ # Parse key-value pairs
161
+ while not self.cur_token_is(RBRACE) and not self.cur_token_is(EOF):
162
+ # Parse key (can be string or identifier)
163
+ if self.cur_token_is(STRING):
164
+ key = StringLiteral(self.cur_token.literal)
165
+ elif self.cur_token_is(IDENT):
166
+ key = Identifier(self.cur_token.literal)
167
+ else:
168
+ self.errors.append(f"Line {getattr(self.cur_token, 'line', 'unknown')}: Object key must be string or identifier")
169
+ return None
170
+
171
+ # Expect colon (current peek should be COLON)
172
+ if not self.expect_peek(COLON):
173
+ return None
174
+
175
+ # Move to value token and parse it
176
+ self.next_token()
177
+ value = self.parse_expression(LOWEST)
178
+ if value is None:
179
+ return None
180
+
181
+ pairs.append((key, value))
182
+
183
+ # Accept comma OR semicolon as separators; tolerate trailing separators
184
+ if self.peek_token_is(COMMA) or self.peek_token_is(SEMICOLON):
185
+ self.next_token() # move to separator
186
+ # advance to next token after separator (or closing brace)
187
+ if self.peek_token_is(RBRACE):
188
+ self.next_token() # move to RBRACE and break next loop iteration
189
+ break
190
+ self.next_token()
191
+ continue
192
+
193
+ # If closing brace is the next token, consume it and finish
194
+ if self.peek_token_is(RBRACE):
195
+ self.next_token() # advance to RBRACE
196
+ break
197
+
198
+ # Otherwise, try to advance; tolerant parsing
199
+ self.next_token()
200
+
201
+ # Final check: should be at a RBRACE token
202
+ if not self.cur_token_is(RBRACE):
203
+ self.errors.append(f"Line {getattr(self.cur_token, 'line', 'unknown')}: Expected '}}' to close object literal")
204
+ return None
205
+
206
+ # Note: we keep the closing brace consumed (caller behavior consistent)
207
+ return MapLiteral(pairs)
208
+
209
+ # Rest of parser methods (simplified for production)
210
+ def parse_expression(self, precedence):
211
+ if self.cur_token.type not in self.prefix_parse_fns:
212
+ self.errors.append(f"Line {self.cur_token.line}: Unexpected token '{self.cur_token.literal}'")
213
+ return None
214
+
215
+ prefix = self.prefix_parse_fns[self.cur_token.type]
216
+ left_exp = prefix()
217
+
218
+ if left_exp is None:
219
+ return None
220
+
221
+ while (not self.peek_token_is(SEMICOLON) and
222
+ not self.peek_token_is(EOF) and
223
+ precedence <= self.peek_precedence()):
224
+
225
+ if self.peek_token.type not in self.infix_parse_fns:
226
+ return left_exp
227
+
228
+ infix = self.infix_parse_fns[self.peek_token.type]
229
+ self.next_token()
230
+ left_exp = infix(left_exp)
231
+
232
+ if left_exp is None:
233
+ return None
234
+
235
+ return left_exp
236
+
237
+ def parse_identifier(self):
238
+ return Identifier(value=self.cur_token.literal)
239
+
240
+ def parse_integer_literal(self):
241
+ try:
242
+ return IntegerLiteral(value=int(self.cur_token.literal))
243
+ except ValueError:
244
+ self.errors.append(f"Line {self.cur_token.line}: Could not parse {self.cur_token.literal} as integer")
245
+ return None
246
+
247
+ def parse_float_literal(self):
248
+ try:
249
+ return FloatLiteral(value=float(self.cur_token.literal))
250
+ except ValueError:
251
+ self.errors.append(f"Line {self.cur_token.line}: Could not parse {self.cur_token.literal} as float")
252
+ return None
253
+
254
+ def parse_string_literal(self):
255
+ return StringLiteral(value=self.cur_token.literal)
256
+
257
+ def parse_boolean(self):
258
+ return Boolean(value=self.cur_token_is(TRUE))
259
+
260
+ def parse_list_literal(self):
261
+ elements = self.parse_expression_list(RBRACKET)
262
+ return ListLiteral(elements=elements)
263
+
264
+ def parse_grouped_expression(self):
265
+ self.next_token()
266
+ exp = self.parse_expression(LOWEST)
267
+ if not self.expect_peek(RPAREN):
268
+ return None
269
+ return exp
270
+
271
+ def parse_prefix_expression(self):
272
+ expression = PrefixExpression(operator=self.cur_token.literal, right=None)
273
+ self.next_token()
274
+ expression.right = self.parse_expression(PREFIX)
275
+ return expression
276
+
277
+ def parse_infix_expression(self, left):
278
+ expression = InfixExpression(left=left, operator=self.cur_token.literal, right=None)
279
+ precedence = self.cur_precedence()
280
+ self.next_token()
281
+ expression.right = self.parse_expression(precedence)
282
+ return expression
283
+
284
+ def parse_call_expression(self, function):
285
+ arguments = self.parse_expression_list(RPAREN)
286
+ return CallExpression(function=function, arguments=arguments)
287
+
288
+ def parse_assignment_expression(self, left):
289
+ if not isinstance(left, Identifier):
290
+ self.errors.append(f"Line {self.cur_token.line}: Cannot assign to {type(left).__name__}")
291
+ return None
292
+
293
+ expression = AssignmentExpression(name=left, value=None)
294
+ self.next_token()
295
+ expression.value = self.parse_expression(LOWEST)
296
+ return expression
297
+
298
+ def parse_method_call_expression(self, left):
299
+ if not self.expect_peek(IDENT):
300
+ return None
301
+
302
+ method = Identifier(self.cur_token.literal)
303
+
304
+ if self.peek_token_is(LPAREN):
305
+ self.next_token()
306
+ arguments = self.parse_expression_list(RPAREN)
307
+ return MethodCallExpression(object=left, method=method, arguments=arguments)
308
+ else:
309
+ return PropertyAccessExpression(object=left, property=method)
310
+
311
+ def parse_expression_list(self, end):
312
+ elements = []
313
+ if self.peek_token_is(end):
314
+ self.next_token()
315
+ return elements
316
+
317
+ self.next_token()
318
+ elements.append(self.parse_expression(LOWEST))
319
+
320
+ while self.peek_token_is(COMMA):
321
+ self.next_token()
322
+ self.next_token()
323
+ elements.append(self.parse_expression(LOWEST))
324
+
325
+ if not self.expect_peek(end):
326
+ return elements
327
+
328
+ return elements
329
+
330
+ # Statement parsing methods
331
+ def parse_expression_statement(self):
332
+ """Parse expression as a statement"""
333
+ stmt = ExpressionStatement(expression=self.parse_expression(LOWEST))
334
+ if self.peek_token_is(SEMICOLON):
335
+ self.next_token()
336
+ return stmt
337
+
338
+ def parse_return_statement(self):
339
+ stmt = ReturnStatement(return_value=None)
340
+ self.next_token()
341
+ stmt.return_value = self.parse_expression(LOWEST)
342
+ return stmt
343
+
344
+ def parse_print_statement(self):
345
+ stmt = PrintStatement(value=None)
346
+ self.next_token()
347
+ stmt.value = self.parse_expression(LOWEST)
348
+ return stmt
349
+
350
+ def parse_if_statement(self):
351
+ self.next_token() # Skip IF
352
+
353
+ # Parse condition (with or without parentheses)
354
+ if self.cur_token_is(LPAREN):
355
+ self.next_token()
356
+ condition = self.parse_expression(LOWEST)
357
+ if self.cur_token_is(RPAREN):
358
+ self.next_token()
359
+ else:
360
+ condition = self.parse_expression(LOWEST)
361
+
362
+ if not condition:
363
+ return None
364
+
365
+ # Parse consequence
366
+ consequence = self.parse_block()
367
+ if not consequence:
368
+ return None
369
+
370
+ alternative = None
371
+ if self.cur_token_is(ELSE):
372
+ self.next_token()
373
+ alternative = self.parse_block()
374
+
375
+ return IfStatement(condition=condition, consequence=consequence, alternative=alternative)
376
+
377
+ def parse_block(self):
378
+ block = BlockStatement()
379
+
380
+ # Handle different block styles
381
+ if self.cur_token_is(LBRACE):
382
+ self.next_token() # Skip {
383
+
384
+ while not self.cur_token_is(RBRACE) and not self.cur_token_is(EOF):
385
+ # Skip stray semicolons between statements inside a block
386
+ if self.cur_token_is(SEMICOLON):
387
+ self.next_token()
388
+ continue
389
+
390
+ stmt = self.parse_statement()
391
+ if stmt:
392
+ block.statements.append(stmt)
393
+
394
+ # After parsing a statement, consume any trailing semicolons so they don't become unexpected tokens
395
+ while self.peek_token_is(SEMICOLON):
396
+ self.next_token() # move to semicolon
397
+ self.next_token() # move past semicolon
398
+
399
+ # Advance to next token if parser hasn't advanced to EOF or closing brace
400
+ if not self.cur_token_is(RBRACE) and not self.cur_token_is(EOF):
401
+ self.next_token()
402
+
403
+ if self.cur_token_is(EOF):
404
+ self.errors.append("Unclosed block (reached EOF)")
405
+ else:
406
+ # Single statement block
407
+ # Tolerant: allow a trailing semicolon after single statement
408
+ stmt = self.parse_statement()
409
+ if stmt:
410
+ block.statements.append(stmt)
411
+ if self.peek_token_is(SEMICOLON):
412
+ self.next_token() # consume semicolon
413
+
414
+ return block
415
+
416
+ def parse_for_each_statement(self):
417
+ if not self.expect_peek(EACH):
418
+ return None
419
+
420
+ if not self.expect_peek(IDENT):
421
+ return None
422
+
423
+ item = Identifier(self.cur_token.literal)
424
+
425
+ if not self.expect_peek(IN):
426
+ return None
427
+
428
+ self.next_token()
429
+ iterable = self.parse_expression(LOWEST)
430
+
431
+ body = self.parse_block()
432
+
433
+ return ForEachStatement(item=item, iterable=iterable, body=body)
434
+
435
+ def parse_action_statement(self, async_flag=False):
436
+ """Parse action declaration; supports optional async modifier (action async name(...) { ... } or async action ...)"""
437
+ # current token is ACTION (or we arrived here after consuming ASYNC)
438
+ is_async = async_flag
439
+
440
+ # Handle optional 'async' immediately after 'action': action async name ...
441
+ if self.peek_token_is(IDENT) and self.peek_token.literal == "async":
442
+ # unusual: peek is IDENT with literal "async" — but lexer maps "async" to ASYNC token;
443
+ pass
444
+
445
+ # If next token is ASYNC (action async name ...)
446
+ if self.peek_token_is(ASYNC):
447
+ self.next_token()
448
+ is_async = True
449
+
450
+ # Continue normal action parse
451
+ if not self.expect_peek(IDENT):
452
+ return None
453
+ name = Identifier(self.cur_token.literal)
454
+
455
+ parameters = []
456
+ if self.peek_token_is(LPAREN):
457
+ # Advance into the parameter list: consume '(' then move to first inner token
458
+ self.next_token() # move to LPAREN
459
+ self.next_token() # move to token after '('
460
+ parameters = self.parse_parameter_list()
461
+ # If current token is ')' (empty params case), advance past it.
462
+ if self.cur_token_is(RPAREN):
463
+ self.next_token()
464
+ else:
465
+ # Otherwise expect a closing paren next and consume it
466
+ if not self.expect_peek(RPAREN):
467
+ return None
468
+ # consume the ')'
469
+ self.next_token()
470
+
471
+ body = self.parse_block()
472
+ # Create ActionStatement with is_async flag (add attribute)
473
+ stmt = ActionStatement(name=name, parameters=parameters, body=body)
474
+ # attach async flag if supported by AST
475
+ setattr(stmt, "is_async", is_async)
476
+ return stmt
477
+
478
+ def parse_action_literal(self):
479
+ if not self.expect_peek(LPAREN):
480
+ return None
481
+
482
+ parameters = self.parse_parameter_list()
483
+ if parameters is None:
484
+ return None
485
+
486
+ body = self.parse_expression(LOWEST)
487
+ # If action literal is used as an expression, callers may expect a function-like node.
488
+ # Mark the ActionLiteral node to indicate expression-level function (helps lowering).
489
+ action_lit = ActionLiteral(parameters=parameters, body=body)
490
+ setattr(action_lit, "is_expression", True)
491
+ return action_lit
492
+
493
+ def parse_await_expression(self):
494
+ # current token is AWAIT
495
+ self.next_token()
496
+ value = self.parse_expression(LOWEST)
497
+ return AwaitExpression(expression=value)
498
+
499
+ def parse_if_expression(self):
500
+ """Parse if expression: if (condition) { consequence } else { alternative }"""
501
+ expression = IfExpression(condition=None, consequence=None, alternative=None)
502
+
503
+ if not self.expect_peek(LPAREN):
504
+ return None
505
+
506
+ self.next_token()
507
+ expression.condition = self.parse_expression(LOWEST)
508
+
509
+ if not self.expect_peek(RPAREN):
510
+ return None
511
+
512
+ if not self.expect_peek(LBRACE):
513
+ return None
514
+
515
+ expression.consequence = self.parse_block()
516
+
517
+ if self.peek_token_is(ELSE):
518
+ self.next_token()
519
+ if not self.expect_peek(LBRACE):
520
+ return None
521
+ expression.alternative = self.parse_block()
522
+
523
+ return expression
524
+
525
+ def parse_embedded_literal(self):
526
+ """Parse embedded code block: @{ language ... code ... }"""
527
+ if not self.expect_peek(LBRACE):
528
+ return None
529
+
530
+ self.next_token()
531
+ code_lines = []
532
+
533
+ # Read until closing brace
534
+ while not self.cur_token_is(RBRACE) and not self.cur_token_is(EOF):
535
+ code_lines.append(self.cur_token.literal)
536
+ self.next_token()
537
+
538
+ if not self.cur_token_is(RBRACE):
539
+ self.errors.append("Expected } after embedded code block")
540
+ return None
541
+
542
+ self.next_token() # Skip closing brace
543
+
544
+ code_content = ' '.join(code_lines)
545
+ lines = code_content.strip().split('\n')
546
+
547
+ if not lines:
548
+ self.errors.append("Empty embedded code block")
549
+ return None
550
+
551
+ # First line is language, rest is code
552
+ language_line = lines[0].strip() if lines else "unknown"
553
+ language = language_line if language_line else "unknown"
554
+ code = '\n'.join(lines[1:]).strip() if len(lines) > 1 else ""
555
+
556
+ return EmbeddedLiteral(language=language, code=code)
557
+
558
+ def parse_lambda_expression(self):
559
+ """Parse lambda/arrow function: x => body or lambda(x): body"""
560
+ token = self.cur_token
561
+ parameters = []
562
+
563
+ self.next_token()
564
+
565
+ if self.cur_token_is(LPAREN):
566
+ self.next_token()
567
+ parameters = self.parse_parameter_list()
568
+ if not self.expect_peek(RPAREN):
569
+ return None
570
+ elif self.cur_token_is(IDENT):
571
+ # Single parameter without parens
572
+ parameters = [Identifier(self.cur_token.literal)]
573
+ self.next_token()
574
+
575
+ # Handle arrow or colon separator
576
+ if self.cur_token_is(COLON):
577
+ self.next_token()
578
+ elif self.cur_token_is(LAMBDA): # => token
579
+ self.next_token()
580
+ elif self.cur_token_is(MINUS) and self.peek_token_is(GT):
581
+ self.next_token() # Skip -
582
+ self.next_token() # Skip >
583
+
584
+ body = self.parse_expression(LOWEST)
585
+ return LambdaExpression(parameters=parameters, body=body)
586
+
587
+ def parse_lambda_infix(self, left):
588
+ """Parse arrow-style lambda when encountering leftside 'params' followed by =>
589
+
590
+ Examples:
591
+ x => x + 1
592
+ (a, b) => a + b
593
+ """
594
+ # Build parameter list from `left` expression
595
+ params = []
596
+ if isinstance(left, Identifier):
597
+ params = [left]
598
+ else:
599
+ try:
600
+ if hasattr(left, 'elements'):
601
+ for el in left.elements:
602
+ if isinstance(el, Identifier):
603
+ params.append(el)
604
+ except Exception:
605
+ pass
606
+
607
+ # Current token is LAMBDA; advance to body
608
+ self.next_token()
609
+
610
+ if self.cur_token_is(COLON):
611
+ self.next_token()
612
+
613
+ body = self.parse_expression(LOWEST)
614
+ return LambdaExpression(parameters=params, body=body)
615
+
616
+ def parse_action_literal(self):
617
+ """Parse action literal: action (params) { body } or action (params) => expr"""
618
+ if not self.expect_peek(LPAREN):
619
+ return None
620
+
621
+ parameters = self.parse_parameter_list()
622
+ if parameters is None:
623
+ return None
624
+
625
+ # Expect closing paren
626
+ if not self.expect_peek(RPAREN):
627
+ return None
628
+
629
+ self.next_token()
630
+
631
+ # Action body can be a block or expression
632
+ if self.cur_token_is(LBRACE):
633
+ body = self.parse_block()
634
+ else:
635
+ # Expression body (shorthand)
636
+ body = self.parse_expression(LOWEST)
637
+
638
+ action_lit = ActionLiteral(parameters=parameters, body=body)
639
+ return action_lit
640
+
641
+ def parse_parameter_list(self):
642
+ """Parse parameter list for functions"""
643
+ parameters = []
644
+
645
+ if self.cur_token_is(RPAREN):
646
+ return parameters
647
+
648
+ while not self.cur_token_is(RPAREN) and not self.cur_token_is(EOF):
649
+ if self.cur_token_is(IDENT):
650
+ parameters.append(Identifier(self.cur_token.literal))
651
+ self.next_token()
652
+ else:
653
+ break
654
+
655
+ # Handle comma separator
656
+ if self.cur_token_is(COMMA):
657
+ self.next_token()
658
+ elif self.cur_token_is(RPAREN):
659
+ break
660
+ else:
661
+ break
662
+
663
+ return parameters
664
+
665
+ def parse_event_declaration(self):
666
+ if not self.expect_peek(IDENT):
667
+ return None
668
+ name = Identifier(self.cur_token.literal)
669
+ body = self.parse_block()
670
+ return EventDeclaration(name=name, properties=body)
671
+
672
+ def parse_emit_statement(self):
673
+ if not self.expect_peek(IDENT):
674
+ return None
675
+ name = Identifier(self.cur_token.literal)
676
+ payload = None
677
+ if self.peek_token_is(LPAREN):
678
+ self.next_token()
679
+ self.next_token()
680
+ payload = self.parse_expression(LOWEST)
681
+ if not self.expect_peek(RPAREN):
682
+ return None
683
+ elif self.peek_token_is(LBRACE):
684
+ self.next_token()
685
+ payload = self.parse_block()
686
+ return EmitStatement(name=name, payload=payload)
687
+
688
+ def parse_enum_declaration(self):
689
+ if not self.expect_peek(IDENT):
690
+ return None
691
+ name = Identifier(self.cur_token.literal)
692
+ if not self.expect_peek(LBRACE):
693
+ return None
694
+ # parse simple comma-separated identifiers or key:value pairs
695
+ members = {}
696
+ self.next_token()
697
+ while not self.cur_token_is(RBRACE) and not self.cur_token_is(EOF):
698
+ if self.cur_token_is(IDENT) or self.cur_token_is(STRING):
699
+ key = self.cur_token.literal
700
+ # optional colon value
701
+ val = None
702
+ if self.peek_token_is(COLON):
703
+ self.next_token()
704
+ self.next_token()
705
+ if self.cur_token_is(INT):
706
+ val = int(self.cur_token.literal)
707
+ members[key] = val
708
+ if self.peek_token_is(COMMA):
709
+ self.next_token()
710
+ self.next_token()
711
+ continue
712
+ self.next_token()
713
+ if not self.cur_token_is(RBRACE):
714
+ self.errors.append("Unclosed enum declaration")
715
+ return None
716
+ return EnumDeclaration(name=name, members=members)
717
+
718
+ def parse_protocol_declaration(self):
719
+ if not self.expect_peek(IDENT):
720
+ return None
721
+ name = Identifier(self.cur_token.literal)
722
+ if not self.expect_peek(LBRACE):
723
+ return None
724
+ # parse simple list of method signatures (as identifiers)
725
+ spec = {"methods": []}
726
+ self.next_token()
727
+ while not self.cur_token_is(RBRACE) and not self.cur_token_is(EOF):
728
+ if self.cur_token_is(IDENT):
729
+ spec["methods"].append(self.cur_token.literal)
730
+ if self.peek_token_is(COMMA):
731
+ self.next_token()
732
+ self.next_token()
733
+ continue
734
+ self.next_token()
735
+ if not self.cur_token_is(RBRACE):
736
+ self.errors.append("Unclosed protocol declaration")
737
+ return None
738
+ return ProtocolDeclaration(name=name, spec=spec)
739
+
740
+ def parse_import_statement(self):
741
+ if not self.expect_peek(STRING):
742
+ return None
743
+ module_path = self.cur_token.literal
744
+ alias = None
745
+ if self.peek_token_is(IDENT) and self.peek_token.literal == "as":
746
+ self.next_token()
747
+ self.next_token()
748
+ if self.cur_token_is(IDENT):
749
+ alias = self.cur_token.literal
750
+ return ImportStatement(module_path=module_path, alias=alias)
751
+
752
+ # Token utilities
753
+ def next_token(self):
754
+ self.cur_token = self.peek_token
755
+ self.peek_token = self.lexer.next_token()
756
+
757
+ def cur_token_is(self, t):
758
+ return self.cur_token.type == t
759
+
760
+ def peek_token_is(self, t):
761
+ return self.peek_token.type == t
762
+
763
+ def expect_peek(self, t):
764
+ if self.peek_token_is(t):
765
+ self.next_token()
766
+ return True
767
+ self.errors.append(f"Line {self.cur_token.line}: Expected '{t}', got '{self.peek_token.type}'")
768
+ return False
769
+
770
+ def peek_precedence(self):
771
+ return precedences.get(self.peek_token.type, LOWEST)
772
+
773
+ def cur_precedence(self):
774
+ return precedences.get(self.cur_token.type, LOWEST)
775
+
776
+ # --- Compatibility alias ----------------------------------------------------
777
+ # Provide the common name `Parser` for code that imports the compiler parser
778
+ # using older/alternate names.
779
+ Parser = ProductionParser