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.
- package/LICENSE +0 -0
- package/README.md +2513 -0
- package/bin/zexus +2 -0
- package/bin/zpics +2 -0
- package/bin/zpm +2 -0
- package/bin/zx +2 -0
- package/bin/zx-deploy +2 -0
- package/bin/zx-dev +2 -0
- package/bin/zx-run +2 -0
- package/package.json +66 -0
- package/scripts/README.md +24 -0
- package/scripts/postinstall.js +44 -0
- package/shared_config.json +24 -0
- package/src/README.md +1525 -0
- package/src/tests/run_zexus_tests.py +117 -0
- package/src/tests/test_all_phases.zx +346 -0
- package/src/tests/test_blockchain_features.zx +306 -0
- package/src/tests/test_complexity_features.zx +321 -0
- package/src/tests/test_core_integration.py +185 -0
- package/src/tests/test_phase10_ecosystem.zx +177 -0
- package/src/tests/test_phase1_modifiers.zx +87 -0
- package/src/tests/test_phase2_plugins.zx +80 -0
- package/src/tests/test_phase3_security.zx +97 -0
- package/src/tests/test_phase4_vfs.zx +116 -0
- package/src/tests/test_phase5_types.zx +117 -0
- package/src/tests/test_phase6_metaprogramming.zx +125 -0
- package/src/tests/test_phase7_optimization.zx +132 -0
- package/src/tests/test_phase9_advanced_types.zx +157 -0
- package/src/tests/test_security_features.py +419 -0
- package/src/tests/test_security_features.zx +276 -0
- package/src/tests/test_simple_zx.zx +1 -0
- package/src/tests/test_verification_simple.zx +69 -0
- package/src/zexus/__init__.py +28 -0
- package/src/zexus/__main__.py +5 -0
- package/src/zexus/__pycache__/__init__.cpython-312.pyc +0 -0
- package/src/zexus/__pycache__/advanced_types.cpython-312.pyc +0 -0
- package/src/zexus/__pycache__/builtin_modules.cpython-312.pyc +0 -0
- package/src/zexus/__pycache__/capability_system.cpython-312.pyc +0 -0
- package/src/zexus/__pycache__/complexity_system.cpython-312.pyc +0 -0
- package/src/zexus/__pycache__/concurrency_system.cpython-312.pyc +0 -0
- package/src/zexus/__pycache__/config.cpython-312.pyc +0 -0
- package/src/zexus/__pycache__/dependency_injection.cpython-312.pyc +0 -0
- package/src/zexus/__pycache__/ecosystem.cpython-312.pyc +0 -0
- package/src/zexus/__pycache__/environment.cpython-312.pyc +0 -0
- package/src/zexus/__pycache__/error_reporter.cpython-312.pyc +0 -0
- package/src/zexus/__pycache__/hybrid_orchestrator.cpython-312.pyc +0 -0
- package/src/zexus/__pycache__/lexer.cpython-312.pyc +0 -0
- package/src/zexus/__pycache__/metaprogramming.cpython-312.pyc +0 -0
- package/src/zexus/__pycache__/module_cache.cpython-312.pyc +0 -0
- package/src/zexus/__pycache__/object.cpython-312.pyc +0 -0
- package/src/zexus/__pycache__/optimization.cpython-312.pyc +0 -0
- package/src/zexus/__pycache__/plugin_system.cpython-312.pyc +0 -0
- package/src/zexus/__pycache__/policy_engine.cpython-312.pyc +0 -0
- package/src/zexus/__pycache__/security.cpython-312.pyc +0 -0
- package/src/zexus/__pycache__/stdlib_integration.cpython-312.pyc +0 -0
- package/src/zexus/__pycache__/strategy_recovery.cpython-312.pyc +0 -0
- package/src/zexus/__pycache__/syntax_validator.cpython-312.pyc +0 -0
- package/src/zexus/__pycache__/type_system.cpython-312.pyc +0 -0
- package/src/zexus/__pycache__/virtual_filesystem.cpython-312.pyc +0 -0
- package/src/zexus/__pycache__/zexus_ast.cpython-312.pyc +0 -0
- package/src/zexus/__pycache__/zexus_token.cpython-312.pyc +0 -0
- package/src/zexus/advanced_types.py +401 -0
- package/src/zexus/blockchain/__init__.py +40 -0
- package/src/zexus/blockchain/__pycache__/__init__.cpython-312.pyc +0 -0
- package/src/zexus/blockchain/__pycache__/crypto.cpython-312.pyc +0 -0
- package/src/zexus/blockchain/__pycache__/ledger.cpython-312.pyc +0 -0
- package/src/zexus/blockchain/__pycache__/transaction.cpython-312.pyc +0 -0
- package/src/zexus/blockchain/crypto.py +463 -0
- package/src/zexus/blockchain/ledger.py +255 -0
- package/src/zexus/blockchain/transaction.py +267 -0
- package/src/zexus/builtin_modules.py +284 -0
- package/src/zexus/builtin_plugins.py +317 -0
- package/src/zexus/capability_system.py +372 -0
- package/src/zexus/cli/__init__.py +2 -0
- package/src/zexus/cli/__pycache__/__init__.cpython-312.pyc +0 -0
- package/src/zexus/cli/__pycache__/main.cpython-312.pyc +0 -0
- package/src/zexus/cli/main.py +707 -0
- package/src/zexus/cli/zpm.py +203 -0
- package/src/zexus/compare_interpreter_compiler.py +146 -0
- package/src/zexus/compiler/__init__.py +169 -0
- package/src/zexus/compiler/__pycache__/__init__.cpython-312.pyc +0 -0
- package/src/zexus/compiler/__pycache__/lexer.cpython-312.pyc +0 -0
- package/src/zexus/compiler/__pycache__/parser.cpython-312.pyc +0 -0
- package/src/zexus/compiler/__pycache__/zexus_ast.cpython-312.pyc +0 -0
- package/src/zexus/compiler/bytecode.py +266 -0
- package/src/zexus/compiler/compat_runtime.py +277 -0
- package/src/zexus/compiler/lexer.py +257 -0
- package/src/zexus/compiler/parser.py +779 -0
- package/src/zexus/compiler/semantic.py +118 -0
- package/src/zexus/compiler/zexus_ast.py +454 -0
- package/src/zexus/complexity_system.py +575 -0
- package/src/zexus/concurrency_system.py +493 -0
- package/src/zexus/config.py +201 -0
- package/src/zexus/crypto_bridge.py +19 -0
- package/src/zexus/dependency_injection.py +423 -0
- package/src/zexus/ecosystem.py +434 -0
- package/src/zexus/environment.py +101 -0
- package/src/zexus/environment_manager.py +119 -0
- package/src/zexus/error_reporter.py +314 -0
- package/src/zexus/evaluator/__init__.py +12 -0
- package/src/zexus/evaluator/__pycache__/__init__.cpython-312.pyc +0 -0
- package/src/zexus/evaluator/__pycache__/bytecode_compiler.cpython-312.pyc +0 -0
- package/src/zexus/evaluator/__pycache__/core.cpython-312.pyc +0 -0
- package/src/zexus/evaluator/__pycache__/expressions.cpython-312.pyc +0 -0
- package/src/zexus/evaluator/__pycache__/functions.cpython-312.pyc +0 -0
- package/src/zexus/evaluator/__pycache__/integration.cpython-312.pyc +0 -0
- package/src/zexus/evaluator/__pycache__/statements.cpython-312.pyc +0 -0
- package/src/zexus/evaluator/__pycache__/utils.cpython-312.pyc +0 -0
- package/src/zexus/evaluator/bytecode_compiler.py +700 -0
- package/src/zexus/evaluator/core.py +891 -0
- package/src/zexus/evaluator/expressions.py +827 -0
- package/src/zexus/evaluator/functions.py +3989 -0
- package/src/zexus/evaluator/integration.py +396 -0
- package/src/zexus/evaluator/statements.py +4303 -0
- package/src/zexus/evaluator/utils.py +126 -0
- package/src/zexus/evaluator_original.py +2041 -0
- package/src/zexus/external_bridge.py +16 -0
- package/src/zexus/find_affected_imports.sh +155 -0
- package/src/zexus/hybrid_orchestrator.py +152 -0
- package/src/zexus/input_validation.py +259 -0
- package/src/zexus/lexer.py +571 -0
- package/src/zexus/logging.py +89 -0
- package/src/zexus/lsp/__init__.py +9 -0
- package/src/zexus/lsp/completion_provider.py +207 -0
- package/src/zexus/lsp/definition_provider.py +22 -0
- package/src/zexus/lsp/hover_provider.py +71 -0
- package/src/zexus/lsp/server.py +269 -0
- package/src/zexus/lsp/symbol_provider.py +31 -0
- package/src/zexus/metaprogramming.py +321 -0
- package/src/zexus/module_cache.py +89 -0
- package/src/zexus/module_manager.py +107 -0
- package/src/zexus/object.py +973 -0
- package/src/zexus/optimization.py +424 -0
- package/src/zexus/parser/__init__.py +31 -0
- package/src/zexus/parser/__pycache__/__init__.cpython-312.pyc +0 -0
- package/src/zexus/parser/__pycache__/parser.cpython-312.pyc +0 -0
- package/src/zexus/parser/__pycache__/strategy_context.cpython-312.pyc +0 -0
- package/src/zexus/parser/__pycache__/strategy_structural.cpython-312.pyc +0 -0
- package/src/zexus/parser/integration.py +86 -0
- package/src/zexus/parser/parser.py +3977 -0
- package/src/zexus/parser/strategy_context.py +7254 -0
- package/src/zexus/parser/strategy_structural.py +1033 -0
- package/src/zexus/persistence.py +391 -0
- package/src/zexus/plugin_system.py +290 -0
- package/src/zexus/policy_engine.py +365 -0
- package/src/zexus/profiler/__init__.py +5 -0
- package/src/zexus/profiler/profiler.py +233 -0
- package/src/zexus/purity_system.py +398 -0
- package/src/zexus/runtime/__init__.py +20 -0
- package/src/zexus/runtime/async_runtime.py +324 -0
- package/src/zexus/search_old_imports.sh +65 -0
- package/src/zexus/security.py +1407 -0
- package/src/zexus/stack_trace.py +233 -0
- package/src/zexus/stdlib/__init__.py +27 -0
- package/src/zexus/stdlib/blockchain.py +341 -0
- package/src/zexus/stdlib/compression.py +167 -0
- package/src/zexus/stdlib/crypto.py +124 -0
- package/src/zexus/stdlib/datetime.py +163 -0
- package/src/zexus/stdlib/db_mongo.py +199 -0
- package/src/zexus/stdlib/db_mysql.py +162 -0
- package/src/zexus/stdlib/db_postgres.py +163 -0
- package/src/zexus/stdlib/db_sqlite.py +133 -0
- package/src/zexus/stdlib/encoding.py +230 -0
- package/src/zexus/stdlib/fs.py +195 -0
- package/src/zexus/stdlib/http.py +219 -0
- package/src/zexus/stdlib/http_server.py +248 -0
- package/src/zexus/stdlib/json_module.py +61 -0
- package/src/zexus/stdlib/math.py +360 -0
- package/src/zexus/stdlib/os_module.py +265 -0
- package/src/zexus/stdlib/regex.py +148 -0
- package/src/zexus/stdlib/sockets.py +253 -0
- package/src/zexus/stdlib/test_framework.zx +208 -0
- package/src/zexus/stdlib/test_runner.zx +119 -0
- package/src/zexus/stdlib_integration.py +341 -0
- package/src/zexus/strategy_recovery.py +256 -0
- package/src/zexus/syntax_validator.py +356 -0
- package/src/zexus/testing/zpics.py +407 -0
- package/src/zexus/testing/zpics_runtime.py +369 -0
- package/src/zexus/type_system.py +374 -0
- package/src/zexus/validation_system.py +569 -0
- package/src/zexus/virtual_filesystem.py +355 -0
- package/src/zexus/vm/__init__.py +8 -0
- package/src/zexus/vm/__pycache__/__init__.cpython-312.pyc +0 -0
- package/src/zexus/vm/__pycache__/async_optimizer.cpython-312.pyc +0 -0
- package/src/zexus/vm/__pycache__/bytecode.cpython-312.pyc +0 -0
- package/src/zexus/vm/__pycache__/cache.cpython-312.pyc +0 -0
- package/src/zexus/vm/__pycache__/jit.cpython-312.pyc +0 -0
- package/src/zexus/vm/__pycache__/memory_manager.cpython-312.pyc +0 -0
- package/src/zexus/vm/__pycache__/memory_pool.cpython-312.pyc +0 -0
- package/src/zexus/vm/__pycache__/optimizer.cpython-312.pyc +0 -0
- package/src/zexus/vm/__pycache__/parallel_vm.cpython-312.pyc +0 -0
- package/src/zexus/vm/__pycache__/peephole_optimizer.cpython-312.pyc +0 -0
- package/src/zexus/vm/__pycache__/profiler.cpython-312.pyc +0 -0
- package/src/zexus/vm/__pycache__/register_allocator.cpython-312.pyc +0 -0
- package/src/zexus/vm/__pycache__/register_vm.cpython-312.pyc +0 -0
- package/src/zexus/vm/__pycache__/ssa_converter.cpython-312.pyc +0 -0
- package/src/zexus/vm/__pycache__/vm.cpython-312.pyc +0 -0
- package/src/zexus/vm/async_optimizer.py +420 -0
- package/src/zexus/vm/bytecode.py +428 -0
- package/src/zexus/vm/bytecode_converter.py +297 -0
- package/src/zexus/vm/cache.py +532 -0
- package/src/zexus/vm/jit.py +720 -0
- package/src/zexus/vm/memory_manager.py +520 -0
- package/src/zexus/vm/memory_pool.py +511 -0
- package/src/zexus/vm/optimizer.py +478 -0
- package/src/zexus/vm/parallel_vm.py +899 -0
- package/src/zexus/vm/peephole_optimizer.py +452 -0
- package/src/zexus/vm/profiler.py +527 -0
- package/src/zexus/vm/register_allocator.py +462 -0
- package/src/zexus/vm/register_vm.py +520 -0
- package/src/zexus/vm/ssa_converter.py +757 -0
- package/src/zexus/vm/vm.py +1392 -0
- package/src/zexus/zexus_ast.py +1782 -0
- package/src/zexus/zexus_token.py +253 -0
- package/src/zexus/zpm/__init__.py +15 -0
- package/src/zexus/zpm/installer.py +116 -0
- package/src/zexus/zpm/package_manager.py +208 -0
- package/src/zexus/zpm/publisher.py +98 -0
- package/src/zexus/zpm/registry.py +110 -0
- package/src/zexus.egg-info/PKG-INFO +2235 -0
- package/src/zexus.egg-info/SOURCES.txt +876 -0
- package/src/zexus.egg-info/dependency_links.txt +1 -0
- package/src/zexus.egg-info/entry_points.txt +3 -0
- package/src/zexus.egg-info/not-zip-safe +1 -0
- package/src/zexus.egg-info/requires.txt +14 -0
- package/src/zexus.egg-info/top_level.txt +2 -0
- package/zexus.json +14 -0
|
@@ -0,0 +1,973 @@
|
|
|
1
|
+
# src/zexus/object.py
|
|
2
|
+
import time
|
|
3
|
+
import random
|
|
4
|
+
import json
|
|
5
|
+
import os
|
|
6
|
+
import sys
|
|
7
|
+
from threading import Lock
|
|
8
|
+
|
|
9
|
+
class Object:
|
|
10
|
+
def inspect(self):
|
|
11
|
+
raise NotImplementedError("Subclasses must implement this method")
|
|
12
|
+
|
|
13
|
+
# === EXISTING TYPES ===
|
|
14
|
+
class Integer(Object):
|
|
15
|
+
def __init__(self, value): self.value = value
|
|
16
|
+
def inspect(self): return str(self.value)
|
|
17
|
+
def type(self): return "INTEGER"
|
|
18
|
+
|
|
19
|
+
class Float(Object):
|
|
20
|
+
def __init__(self, value): self.value = value
|
|
21
|
+
def inspect(self): return str(self.value)
|
|
22
|
+
def type(self): return "FLOAT"
|
|
23
|
+
|
|
24
|
+
class Boolean(Object):
|
|
25
|
+
def __init__(self, value): self.value = value
|
|
26
|
+
def inspect(self): return "true" if self.value else "false"
|
|
27
|
+
def type(self): return "BOOLEAN"
|
|
28
|
+
|
|
29
|
+
class Null(Object):
|
|
30
|
+
def inspect(self): return "null"
|
|
31
|
+
def type(self): return "NULL"
|
|
32
|
+
|
|
33
|
+
class String(Object):
|
|
34
|
+
def __init__(self, value): self.value = value
|
|
35
|
+
def inspect(self): return self.value
|
|
36
|
+
def type(self): return "STRING"
|
|
37
|
+
def __str__(self): return self.value
|
|
38
|
+
def __eq__(self, other):
|
|
39
|
+
"""Enable String objects to be used as dict keys"""
|
|
40
|
+
if isinstance(other, String):
|
|
41
|
+
return self.value == other.value
|
|
42
|
+
return False
|
|
43
|
+
def __hash__(self):
|
|
44
|
+
"""Enable String objects to be used as dict keys"""
|
|
45
|
+
return hash(self.value)
|
|
46
|
+
|
|
47
|
+
class List(Object):
|
|
48
|
+
def __init__(self, elements): self.elements = elements
|
|
49
|
+
def inspect(self):
|
|
50
|
+
elements_str = ", ".join([el.inspect() for el in self.elements])
|
|
51
|
+
return f"[{elements_str}]"
|
|
52
|
+
def type(self): return "LIST"
|
|
53
|
+
|
|
54
|
+
def get(self, index):
|
|
55
|
+
"""Get element by index"""
|
|
56
|
+
try:
|
|
57
|
+
# Handle Integer object or raw int
|
|
58
|
+
idx = index.value if hasattr(index, 'value') else index
|
|
59
|
+
idx = int(idx)
|
|
60
|
+
if 0 <= idx < len(self.elements):
|
|
61
|
+
return self.elements[idx]
|
|
62
|
+
return NULL
|
|
63
|
+
except Exception:
|
|
64
|
+
return NULL
|
|
65
|
+
|
|
66
|
+
def append(self, item):
|
|
67
|
+
"""Append item to list in-place (mutating operation)"""
|
|
68
|
+
self.elements.append(item)
|
|
69
|
+
return self # Return self for method chaining
|
|
70
|
+
|
|
71
|
+
def extend(self, other_list):
|
|
72
|
+
"""Extend list with another list in-place"""
|
|
73
|
+
if isinstance(other_list, List):
|
|
74
|
+
self.elements.extend(other_list.elements)
|
|
75
|
+
return self
|
|
76
|
+
|
|
77
|
+
class Map(Object):
|
|
78
|
+
def __init__(self, pairs):
|
|
79
|
+
self.pairs = pairs
|
|
80
|
+
|
|
81
|
+
def type(self): return "MAP"
|
|
82
|
+
def inspect(self):
|
|
83
|
+
pairs = []
|
|
84
|
+
for key, value in self.pairs.items():
|
|
85
|
+
key_str = key.inspect() if hasattr(key, 'inspect') else str(key)
|
|
86
|
+
value_str = value.inspect() if hasattr(value, 'inspect') else str(value)
|
|
87
|
+
pairs.append(f"{key_str}: {value_str}")
|
|
88
|
+
return "{" + ", ".join(pairs) + "}"
|
|
89
|
+
|
|
90
|
+
def get(self, key):
|
|
91
|
+
"""Get value by key (compatible with string keys)"""
|
|
92
|
+
return self.pairs.get(key)
|
|
93
|
+
|
|
94
|
+
def set(self, key, value):
|
|
95
|
+
"""Set value for key, blocking modification if key is sealed."""
|
|
96
|
+
existing = self.pairs.get(key)
|
|
97
|
+
if existing is not None and existing.__class__.__name__ == 'SealedObject':
|
|
98
|
+
raise EvaluationError(f"Cannot modify sealed map key: {key}")
|
|
99
|
+
self.pairs[key] = value
|
|
100
|
+
|
|
101
|
+
class EmbeddedCode(Object):
|
|
102
|
+
def __init__(self, name, language, code):
|
|
103
|
+
self.name = name
|
|
104
|
+
self.language = language
|
|
105
|
+
self.code = code
|
|
106
|
+
def inspect(self): return f"<embedded {self.language} code: {self.name}>"
|
|
107
|
+
def type(self): return "EMBEDDED_CODE"
|
|
108
|
+
|
|
109
|
+
class ReturnValue(Object):
|
|
110
|
+
def __init__(self, value): self.value = value
|
|
111
|
+
def inspect(self): return self.value.inspect()
|
|
112
|
+
def type(self): return "RETURN_VALUE"
|
|
113
|
+
|
|
114
|
+
class Action(Object):
|
|
115
|
+
def __init__(self, parameters, body, env):
|
|
116
|
+
self.parameters, self.body, self.env = parameters, body, env
|
|
117
|
+
def inspect(self):
|
|
118
|
+
params = ", ".join([p.value for p in self.parameters])
|
|
119
|
+
return f"action({params}) {{\n ...\n}}"
|
|
120
|
+
def type(self): return "ACTION"
|
|
121
|
+
|
|
122
|
+
class LambdaFunction(Object):
|
|
123
|
+
def __init__(self, parameters, body, env):
|
|
124
|
+
self.parameters = parameters
|
|
125
|
+
self.body = body
|
|
126
|
+
self.env = env
|
|
127
|
+
def inspect(self):
|
|
128
|
+
params = ", ".join([p.value for p in self.parameters])
|
|
129
|
+
return f"lambda({params})"
|
|
130
|
+
def type(self): return "LAMBDA_FUNCTION"
|
|
131
|
+
class Modifier(Object):
|
|
132
|
+
"""Function modifier for access control and validation"""
|
|
133
|
+
def __init__(self, name, parameters, body, env):
|
|
134
|
+
self.name = name
|
|
135
|
+
self.parameters = parameters
|
|
136
|
+
self.body = body
|
|
137
|
+
self.env = env
|
|
138
|
+
def inspect(self):
|
|
139
|
+
params = ", ".join([p.value for p in self.parameters]) if self.parameters else ""
|
|
140
|
+
return f"modifier {self.name}({params})"
|
|
141
|
+
def type(self): return "MODIFIER"
|
|
142
|
+
|
|
143
|
+
|
|
144
|
+
class Builtin(Object):
|
|
145
|
+
def __init__(self, fn, name=""):
|
|
146
|
+
self.fn = fn
|
|
147
|
+
self.name = name
|
|
148
|
+
def inspect(self): return f"<built-in function: {self.name}>"
|
|
149
|
+
def type(self): return "BUILTIN"
|
|
150
|
+
|
|
151
|
+
# === ASYNC/AWAIT OBJECTS ===
|
|
152
|
+
|
|
153
|
+
class Promise(Object):
|
|
154
|
+
"""
|
|
155
|
+
Promise object representing an async operation
|
|
156
|
+
States: PENDING, FULFILLED, REJECTED
|
|
157
|
+
"""
|
|
158
|
+
PENDING = "PENDING"
|
|
159
|
+
FULFILLED = "FULFILLED"
|
|
160
|
+
REJECTED = "REJECTED"
|
|
161
|
+
|
|
162
|
+
def __init__(self, executor=None, env=None, stack_trace=None):
|
|
163
|
+
self.state = Promise.PENDING
|
|
164
|
+
self.value = None
|
|
165
|
+
self.error = None
|
|
166
|
+
self.then_callbacks = []
|
|
167
|
+
self.catch_callbacks = []
|
|
168
|
+
self.finally_callbacks = []
|
|
169
|
+
|
|
170
|
+
# Async context propagation
|
|
171
|
+
self.env = env # Environment at promise creation
|
|
172
|
+
self.stack_trace = stack_trace or [] # Stack trace context
|
|
173
|
+
|
|
174
|
+
# If executor provided, run it immediately
|
|
175
|
+
if executor:
|
|
176
|
+
try:
|
|
177
|
+
executor(self._resolve, self._reject)
|
|
178
|
+
except Exception as e:
|
|
179
|
+
self._reject(e)
|
|
180
|
+
|
|
181
|
+
def _resolve(self, value):
|
|
182
|
+
"""Resolve the promise with a value"""
|
|
183
|
+
if self.state != Promise.PENDING:
|
|
184
|
+
return
|
|
185
|
+
self.state = Promise.FULFILLED
|
|
186
|
+
self.value = value
|
|
187
|
+
|
|
188
|
+
# Execute then callbacks
|
|
189
|
+
for callback in self.then_callbacks:
|
|
190
|
+
try:
|
|
191
|
+
callback(value)
|
|
192
|
+
except Exception:
|
|
193
|
+
pass
|
|
194
|
+
|
|
195
|
+
# Execute finally callbacks
|
|
196
|
+
for callback in self.finally_callbacks:
|
|
197
|
+
try:
|
|
198
|
+
callback()
|
|
199
|
+
except Exception:
|
|
200
|
+
pass
|
|
201
|
+
|
|
202
|
+
def _reject(self, error):
|
|
203
|
+
"""Reject the promise with an error"""
|
|
204
|
+
if self.state != Promise.PENDING:
|
|
205
|
+
return
|
|
206
|
+
self.state = Promise.REJECTED
|
|
207
|
+
self.error = error
|
|
208
|
+
|
|
209
|
+
# Execute catch callbacks
|
|
210
|
+
for callback in self.catch_callbacks:
|
|
211
|
+
try:
|
|
212
|
+
callback(error)
|
|
213
|
+
except Exception:
|
|
214
|
+
pass
|
|
215
|
+
|
|
216
|
+
# Execute finally callbacks
|
|
217
|
+
for callback in self.finally_callbacks:
|
|
218
|
+
try:
|
|
219
|
+
callback()
|
|
220
|
+
except Exception:
|
|
221
|
+
pass
|
|
222
|
+
|
|
223
|
+
def then(self, callback):
|
|
224
|
+
"""Add a success callback"""
|
|
225
|
+
if self.state == Promise.FULFILLED:
|
|
226
|
+
callback(self.value)
|
|
227
|
+
elif self.state == Promise.PENDING:
|
|
228
|
+
self.then_callbacks.append(callback)
|
|
229
|
+
return self
|
|
230
|
+
|
|
231
|
+
def catch(self, callback):
|
|
232
|
+
"""Add an error callback"""
|
|
233
|
+
if self.state == Promise.REJECTED:
|
|
234
|
+
callback(self.error)
|
|
235
|
+
elif self.state == Promise.PENDING:
|
|
236
|
+
self.catch_callbacks.append(callback)
|
|
237
|
+
return self
|
|
238
|
+
|
|
239
|
+
def finally_callback(self, callback):
|
|
240
|
+
"""Add a finally callback (runs regardless of outcome)"""
|
|
241
|
+
if self.state != Promise.PENDING:
|
|
242
|
+
callback()
|
|
243
|
+
else:
|
|
244
|
+
self.finally_callbacks.append(callback)
|
|
245
|
+
return self
|
|
246
|
+
|
|
247
|
+
def is_resolved(self):
|
|
248
|
+
"""Check if promise is resolved (fulfilled or rejected)"""
|
|
249
|
+
return self.state != Promise.PENDING
|
|
250
|
+
|
|
251
|
+
def get_value(self):
|
|
252
|
+
"""Get the promise value (blocks if pending)"""
|
|
253
|
+
if self.state == Promise.FULFILLED:
|
|
254
|
+
return self.value
|
|
255
|
+
elif self.state == Promise.REJECTED:
|
|
256
|
+
raise Exception(f"Promise rejected: {self.error}")
|
|
257
|
+
else:
|
|
258
|
+
raise Exception("Promise is still pending")
|
|
259
|
+
|
|
260
|
+
def inspect(self):
|
|
261
|
+
if self.state == Promise.PENDING:
|
|
262
|
+
return "Promise { <pending> }"
|
|
263
|
+
elif self.state == Promise.FULFILLED:
|
|
264
|
+
value_str = self.value.inspect() if hasattr(self.value, 'inspect') else str(self.value)
|
|
265
|
+
return f"Promise {{ <fulfilled>: {value_str} }}"
|
|
266
|
+
else:
|
|
267
|
+
return f"Promise {{ <rejected>: {self.error} }}"
|
|
268
|
+
|
|
269
|
+
def type(self):
|
|
270
|
+
return "PROMISE"
|
|
271
|
+
|
|
272
|
+
|
|
273
|
+
class Coroutine(Object):
|
|
274
|
+
"""
|
|
275
|
+
Coroutine object representing an async function execution
|
|
276
|
+
Wraps a generator/iterator for suspension and resumption
|
|
277
|
+
"""
|
|
278
|
+
def __init__(self, generator, action):
|
|
279
|
+
self.generator = generator
|
|
280
|
+
self.action = action # The async action that created this coroutine
|
|
281
|
+
self.is_complete = False
|
|
282
|
+
self.result = None
|
|
283
|
+
self.error = None
|
|
284
|
+
|
|
285
|
+
def resume(self, value=None):
|
|
286
|
+
"""Resume coroutine execution, returns (is_done, value/error)"""
|
|
287
|
+
try:
|
|
288
|
+
if self.is_complete:
|
|
289
|
+
return (True, self.result)
|
|
290
|
+
|
|
291
|
+
# Send value to generator and get next yielded value
|
|
292
|
+
next_value = self.generator.send(value)
|
|
293
|
+
return (False, next_value)
|
|
294
|
+
except StopIteration as e:
|
|
295
|
+
self.is_complete = True
|
|
296
|
+
self.result = e.value if hasattr(e, 'value') else None
|
|
297
|
+
return (True, self.result)
|
|
298
|
+
except Exception as e:
|
|
299
|
+
self.is_complete = True
|
|
300
|
+
self.error = e
|
|
301
|
+
return (True, e)
|
|
302
|
+
|
|
303
|
+
def inspect(self):
|
|
304
|
+
if self.is_complete:
|
|
305
|
+
if self.result is not None:
|
|
306
|
+
result_str = self.result.inspect() if hasattr(self.result, 'inspect') else str(self.result)
|
|
307
|
+
return f"Coroutine {{ <complete>: {result_str} }}"
|
|
308
|
+
return "Coroutine { <complete>: null }"
|
|
309
|
+
return "Coroutine { <running> }"
|
|
310
|
+
|
|
311
|
+
def type(self):
|
|
312
|
+
return "COROUTINE"
|
|
313
|
+
|
|
314
|
+
# === ENTITY OBJECTS ===
|
|
315
|
+
|
|
316
|
+
class EntityDefinition(Object):
|
|
317
|
+
def __init__(self, name, properties, parent=None):
|
|
318
|
+
self.name = name
|
|
319
|
+
self.properties = properties # List of property definitions
|
|
320
|
+
self.parent = parent # Optional parent entity for inheritance
|
|
321
|
+
|
|
322
|
+
def type(self):
|
|
323
|
+
return "ENTITY_DEF"
|
|
324
|
+
|
|
325
|
+
def inspect(self):
|
|
326
|
+
# Handle both dict format {prop_name: {type: ..., default_value: ...}}
|
|
327
|
+
# and list format [{name: ..., type: ...}]
|
|
328
|
+
if isinstance(self.properties, dict):
|
|
329
|
+
props_str = ", ".join([f"{name}: {info['type']}" for name, info in self.properties.items()])
|
|
330
|
+
else:
|
|
331
|
+
props_str = ", ".join([f"{prop['name']}: {prop['type']}" for prop in self.properties])
|
|
332
|
+
return f"entity {self.name} {{ {props_str} }}"
|
|
333
|
+
|
|
334
|
+
def create_instance(self, initial_values=None):
|
|
335
|
+
"""Create an instance of this entity with optional initial values"""
|
|
336
|
+
return EntityInstance(self, initial_values or {})
|
|
337
|
+
|
|
338
|
+
class EntityInstance(Object):
|
|
339
|
+
def __init__(self, entity_def, values):
|
|
340
|
+
self.entity_def = entity_def
|
|
341
|
+
self.values = values
|
|
342
|
+
|
|
343
|
+
def type(self):
|
|
344
|
+
return "ENTITY_INSTANCE"
|
|
345
|
+
|
|
346
|
+
def inspect(self):
|
|
347
|
+
values_str = ", ".join([f"{k}: {v.inspect()}" for k, v in self.values.items()])
|
|
348
|
+
return f"{self.entity_def.name} {{ {values_str} }}"
|
|
349
|
+
|
|
350
|
+
def get(self, property_name):
|
|
351
|
+
return self.values.get(property_name, NULL)
|
|
352
|
+
|
|
353
|
+
def set(self, property_name, value):
|
|
354
|
+
# Check if property exists in entity definition
|
|
355
|
+
prop_def = next((prop for prop in self.entity_def.properties if prop['name'] == property_name), None)
|
|
356
|
+
if prop_def:
|
|
357
|
+
self.values[property_name] = value
|
|
358
|
+
return TRUE
|
|
359
|
+
return FALSE
|
|
360
|
+
|
|
361
|
+
# === UTILITY CLASSES ===
|
|
362
|
+
|
|
363
|
+
class DateTime(Object):
|
|
364
|
+
def __init__(self, timestamp=None):
|
|
365
|
+
self.timestamp = timestamp or time.time()
|
|
366
|
+
|
|
367
|
+
def inspect(self):
|
|
368
|
+
return f"<DateTime: {self.timestamp}>"
|
|
369
|
+
|
|
370
|
+
def type(self):
|
|
371
|
+
return "DATETIME"
|
|
372
|
+
|
|
373
|
+
@staticmethod
|
|
374
|
+
def now():
|
|
375
|
+
return DateTime(time.time())
|
|
376
|
+
|
|
377
|
+
def to_timestamp(self):
|
|
378
|
+
return Integer(int(self.timestamp))
|
|
379
|
+
|
|
380
|
+
def __str__(self):
|
|
381
|
+
return str(self.timestamp)
|
|
382
|
+
|
|
383
|
+
class Math(Object):
|
|
384
|
+
def type(self):
|
|
385
|
+
return "MATH_UTILITY"
|
|
386
|
+
|
|
387
|
+
def inspect(self):
|
|
388
|
+
return "<Math utilities>"
|
|
389
|
+
|
|
390
|
+
@staticmethod
|
|
391
|
+
def random_int(min_val, max_val):
|
|
392
|
+
return Integer(random.randint(min_val, max_val))
|
|
393
|
+
|
|
394
|
+
@staticmethod
|
|
395
|
+
def to_hex_string(number):
|
|
396
|
+
if isinstance(number, Integer):
|
|
397
|
+
return String(hex(number.value))
|
|
398
|
+
return String(hex(number))
|
|
399
|
+
|
|
400
|
+
@staticmethod
|
|
401
|
+
def hex_to_int(hex_string):
|
|
402
|
+
if isinstance(hex_string, String):
|
|
403
|
+
return Integer(int(hex_string.value, 16))
|
|
404
|
+
return Integer(int(hex_string, 16))
|
|
405
|
+
|
|
406
|
+
@staticmethod
|
|
407
|
+
def sqrt(number):
|
|
408
|
+
if isinstance(number, Integer):
|
|
409
|
+
return Float(number.value ** 0.5)
|
|
410
|
+
elif isinstance(number, Float):
|
|
411
|
+
return Float(number.value ** 0.5)
|
|
412
|
+
return Null()
|
|
413
|
+
|
|
414
|
+
class File(Object):
|
|
415
|
+
def type(self):
|
|
416
|
+
return "FILE_UTILITY"
|
|
417
|
+
|
|
418
|
+
def inspect(self):
|
|
419
|
+
return "<File I/O utilities>"
|
|
420
|
+
|
|
421
|
+
# === BASIC TIER ===
|
|
422
|
+
@staticmethod
|
|
423
|
+
def read_text(path):
|
|
424
|
+
try:
|
|
425
|
+
if isinstance(path, String):
|
|
426
|
+
path = path.value
|
|
427
|
+
with open(path, 'r', encoding='utf-8') as f:
|
|
428
|
+
return String(f.read())
|
|
429
|
+
except Exception as e:
|
|
430
|
+
return EvaluationError(f"File read error: {str(e)}")
|
|
431
|
+
|
|
432
|
+
@staticmethod
|
|
433
|
+
def write_text(path, content):
|
|
434
|
+
try:
|
|
435
|
+
if isinstance(path, String):
|
|
436
|
+
path = path.value
|
|
437
|
+
if isinstance(content, String):
|
|
438
|
+
content = content.value
|
|
439
|
+
with open(path, 'w', encoding='utf-8') as f:
|
|
440
|
+
f.write(content)
|
|
441
|
+
return Boolean(True)
|
|
442
|
+
except Exception as e:
|
|
443
|
+
return EvaluationError(f"File write error: {str(e)}")
|
|
444
|
+
|
|
445
|
+
@staticmethod
|
|
446
|
+
def exists(path):
|
|
447
|
+
if isinstance(path, String):
|
|
448
|
+
path = path.value
|
|
449
|
+
return Boolean(os.path.exists(path))
|
|
450
|
+
|
|
451
|
+
# === MEDIUM TIER ===
|
|
452
|
+
@staticmethod
|
|
453
|
+
def read_json(path):
|
|
454
|
+
try:
|
|
455
|
+
content = File.read_text(path)
|
|
456
|
+
if isinstance(content, EvaluationError):
|
|
457
|
+
return content
|
|
458
|
+
data = json.loads(content.value)
|
|
459
|
+
# Convert Python data to Zexus objects
|
|
460
|
+
return File._python_to_zexus(data)
|
|
461
|
+
except Exception as e:
|
|
462
|
+
return EvaluationError(f"JSON read error: {str(e)}")
|
|
463
|
+
|
|
464
|
+
@staticmethod
|
|
465
|
+
def write_json(path, data):
|
|
466
|
+
try:
|
|
467
|
+
# Always convert Zexus objects to Python objects
|
|
468
|
+
python_data = File._zexus_to_python(data)
|
|
469
|
+
json_str = json.dumps(python_data, indent=2)
|
|
470
|
+
return File.write_text(path, String(json_str))
|
|
471
|
+
except Exception as e:
|
|
472
|
+
return EvaluationError(f"JSON write error: {str(e)}")
|
|
473
|
+
|
|
474
|
+
@staticmethod
|
|
475
|
+
def append_text(path, content):
|
|
476
|
+
try:
|
|
477
|
+
if isinstance(path, String):
|
|
478
|
+
path = path.value
|
|
479
|
+
if isinstance(content, String):
|
|
480
|
+
content = content.value
|
|
481
|
+
with open(path, 'a', encoding='utf-8') as f:
|
|
482
|
+
f.write(content + '\n')
|
|
483
|
+
return Boolean(True)
|
|
484
|
+
except Exception as e:
|
|
485
|
+
return EvaluationError(f"File append error: {str(e)}")
|
|
486
|
+
|
|
487
|
+
@staticmethod
|
|
488
|
+
def list_directory(path):
|
|
489
|
+
try:
|
|
490
|
+
if isinstance(path, String):
|
|
491
|
+
path = path.value
|
|
492
|
+
files = os.listdir(path)
|
|
493
|
+
return List([String(f) for f in files])
|
|
494
|
+
except Exception as e:
|
|
495
|
+
return EvaluationError(f"Directory list error: {str(e)}")
|
|
496
|
+
|
|
497
|
+
# === ADVANCED TIER ===
|
|
498
|
+
@staticmethod
|
|
499
|
+
def read_chunk(path, offset, length):
|
|
500
|
+
try:
|
|
501
|
+
if isinstance(path, String):
|
|
502
|
+
path = path.value
|
|
503
|
+
if isinstance(offset, Integer):
|
|
504
|
+
offset = offset.value
|
|
505
|
+
if isinstance(length, Integer):
|
|
506
|
+
length = length.value
|
|
507
|
+
|
|
508
|
+
with open(path, 'rb') as f:
|
|
509
|
+
f.seek(offset)
|
|
510
|
+
data = f.read(length)
|
|
511
|
+
return String(data.hex()) # Return as hex string
|
|
512
|
+
except Exception as e:
|
|
513
|
+
return EvaluationError(f"File chunk read error: {str(e)}")
|
|
514
|
+
|
|
515
|
+
@staticmethod
|
|
516
|
+
def write_chunk(path, offset, data):
|
|
517
|
+
try:
|
|
518
|
+
if isinstance(path, String):
|
|
519
|
+
path = path.value
|
|
520
|
+
if isinstance(offset, Integer):
|
|
521
|
+
offset = offset.value
|
|
522
|
+
if isinstance(data, String):
|
|
523
|
+
data = bytes.fromhex(data.value)
|
|
524
|
+
|
|
525
|
+
with open(path, 'r+b') as f:
|
|
526
|
+
f.seek(offset)
|
|
527
|
+
f.write(data)
|
|
528
|
+
return Boolean(True)
|
|
529
|
+
except Exception as e:
|
|
530
|
+
return EvaluationError(f"File chunk write error: {str(e)}")
|
|
531
|
+
|
|
532
|
+
@staticmethod
|
|
533
|
+
def atomic_write(path, data):
|
|
534
|
+
"""Atomic write to prevent corruption"""
|
|
535
|
+
try:
|
|
536
|
+
if isinstance(path, String):
|
|
537
|
+
path = path.value
|
|
538
|
+
|
|
539
|
+
# Write to temporary file first
|
|
540
|
+
temp_path = path + '.tmp'
|
|
541
|
+
result = File.write_text(temp_path, data)
|
|
542
|
+
if result == Boolean(True):
|
|
543
|
+
# Atomic rename
|
|
544
|
+
os.replace(temp_path, path)
|
|
545
|
+
return Boolean(True)
|
|
546
|
+
return result
|
|
547
|
+
except Exception as e:
|
|
548
|
+
return EvaluationError(f"Atomic write error: {str(e)}")
|
|
549
|
+
|
|
550
|
+
# File locking for concurrent access
|
|
551
|
+
_file_locks = {}
|
|
552
|
+
_lock = Lock()
|
|
553
|
+
|
|
554
|
+
@staticmethod
|
|
555
|
+
def lock_file(path):
|
|
556
|
+
"""Lock file for exclusive access"""
|
|
557
|
+
try:
|
|
558
|
+
if isinstance(path, String):
|
|
559
|
+
path = path.value
|
|
560
|
+
|
|
561
|
+
with File._lock:
|
|
562
|
+
if path not in File._file_locks:
|
|
563
|
+
File._file_locks[path] = Lock()
|
|
564
|
+
|
|
565
|
+
File._file_locks[path].acquire()
|
|
566
|
+
return Boolean(True)
|
|
567
|
+
except Exception as e:
|
|
568
|
+
return EvaluationError(f"File lock error: {str(e)}")
|
|
569
|
+
|
|
570
|
+
@staticmethod
|
|
571
|
+
def unlock_file(path):
|
|
572
|
+
"""Unlock file"""
|
|
573
|
+
try:
|
|
574
|
+
if isinstance(path, String):
|
|
575
|
+
path = path.value
|
|
576
|
+
|
|
577
|
+
with File._lock:
|
|
578
|
+
if path in File._file_locks:
|
|
579
|
+
File._file_locks[path].release()
|
|
580
|
+
return Boolean(True)
|
|
581
|
+
return Boolean(False)
|
|
582
|
+
except Exception as e:
|
|
583
|
+
return EvaluationError(f"File unlock error: {str(e)}")
|
|
584
|
+
|
|
585
|
+
# Helper methods for data conversion
|
|
586
|
+
@staticmethod
|
|
587
|
+
def _python_to_zexus(value):
|
|
588
|
+
if isinstance(value, dict):
|
|
589
|
+
pairs = {}
|
|
590
|
+
for k, v in value.items():
|
|
591
|
+
pairs[k] = File._python_to_zexus(v)
|
|
592
|
+
return Map(pairs)
|
|
593
|
+
elif isinstance(value, list):
|
|
594
|
+
return List([File._python_to_zexus(item) for item in value])
|
|
595
|
+
elif isinstance(value, str):
|
|
596
|
+
return String(value)
|
|
597
|
+
elif isinstance(value, int):
|
|
598
|
+
return Integer(value)
|
|
599
|
+
elif isinstance(value, float):
|
|
600
|
+
return Float(value)
|
|
601
|
+
elif isinstance(value, bool):
|
|
602
|
+
return Boolean(value)
|
|
603
|
+
else:
|
|
604
|
+
return String(str(value))
|
|
605
|
+
|
|
606
|
+
@staticmethod
|
|
607
|
+
def _zexus_to_python(value):
|
|
608
|
+
if isinstance(value, Map):
|
|
609
|
+
# Handle both String keys and regular string keys
|
|
610
|
+
result = {}
|
|
611
|
+
for k, v in value.pairs.items():
|
|
612
|
+
key = k.value if isinstance(k, String) else str(k)
|
|
613
|
+
result[key] = File._zexus_to_python(v)
|
|
614
|
+
return result
|
|
615
|
+
elif isinstance(value, List):
|
|
616
|
+
return [File._zexus_to_python(item) for item in value.elements]
|
|
617
|
+
elif isinstance(value, String):
|
|
618
|
+
return value.value
|
|
619
|
+
elif isinstance(value, Integer):
|
|
620
|
+
return value.value
|
|
621
|
+
elif isinstance(value, Float):
|
|
622
|
+
return value.value
|
|
623
|
+
elif isinstance(value, Boolean):
|
|
624
|
+
return value.value
|
|
625
|
+
elif value == Null() or value is None:
|
|
626
|
+
return None
|
|
627
|
+
elif isinstance(value, dict):
|
|
628
|
+
# Handle plain Python dicts (fallback)
|
|
629
|
+
return {str(k): File._zexus_to_python(v) for k, v in value.items()}
|
|
630
|
+
elif isinstance(value, list):
|
|
631
|
+
# Handle plain Python lists (fallback)
|
|
632
|
+
return [File._zexus_to_python(item) for item in value]
|
|
633
|
+
else:
|
|
634
|
+
return str(value)
|
|
635
|
+
|
|
636
|
+
# Debug utility for enhanced error tracking
|
|
637
|
+
class Debug(Object):
|
|
638
|
+
def type(self):
|
|
639
|
+
return "DEBUG_UTILITY"
|
|
640
|
+
|
|
641
|
+
def inspect(self):
|
|
642
|
+
return "<Debug utilities>"
|
|
643
|
+
|
|
644
|
+
@staticmethod
|
|
645
|
+
def log(message, value=None):
|
|
646
|
+
"""Log debug information with optional value"""
|
|
647
|
+
if isinstance(message, String):
|
|
648
|
+
message = message.value
|
|
649
|
+
|
|
650
|
+
debug_msg = f"🔍 DEBUG: {message}"
|
|
651
|
+
if value is not None:
|
|
652
|
+
debug_msg += f" → {value.inspect() if hasattr(value, 'inspect') else value}"
|
|
653
|
+
|
|
654
|
+
print(debug_msg)
|
|
655
|
+
return value if value is not None else Boolean(True)
|
|
656
|
+
|
|
657
|
+
@staticmethod
|
|
658
|
+
def trace(message):
|
|
659
|
+
"""Add stack trace to debug output"""
|
|
660
|
+
import traceback
|
|
661
|
+
if isinstance(message, String):
|
|
662
|
+
message = message.value
|
|
663
|
+
|
|
664
|
+
print(f"🔍 TRACE: {message}")
|
|
665
|
+
print("Stack trace:")
|
|
666
|
+
for line in traceback.format_stack()[:-1]:
|
|
667
|
+
print(f" {line.strip()}")
|
|
668
|
+
return Boolean(True)
|
|
669
|
+
|
|
670
|
+
# Global dependency collector stack for WATCH feature
|
|
671
|
+
_dependency_collector_stack = []
|
|
672
|
+
|
|
673
|
+
def start_collecting_dependencies():
|
|
674
|
+
_dependency_collector_stack.append(set())
|
|
675
|
+
|
|
676
|
+
def stop_collecting_dependencies():
|
|
677
|
+
if _dependency_collector_stack:
|
|
678
|
+
return _dependency_collector_stack.pop()
|
|
679
|
+
return set()
|
|
680
|
+
|
|
681
|
+
def record_dependency(env, name):
|
|
682
|
+
if _dependency_collector_stack:
|
|
683
|
+
_dependency_collector_stack[-1].add((env, name))
|
|
684
|
+
|
|
685
|
+
class Environment:
|
|
686
|
+
def __init__(self, outer=None, persistence_scope=None):
|
|
687
|
+
self.store = {}
|
|
688
|
+
self.const_vars = set() # Track const variables
|
|
689
|
+
self.outer = outer
|
|
690
|
+
self.exports = {}
|
|
691
|
+
# Debug tracking
|
|
692
|
+
self.debug_mode = False
|
|
693
|
+
# Reactive watchers: name -> list of (callback_fn, context_env)
|
|
694
|
+
self.watchers = {}
|
|
695
|
+
# Persistence support
|
|
696
|
+
self.persistence_scope = persistence_scope
|
|
697
|
+
self._persistent_storage = None
|
|
698
|
+
self._memory_tracker = None
|
|
699
|
+
self._init_persistence()
|
|
700
|
+
|
|
701
|
+
def get(self, name):
|
|
702
|
+
val = self.store.get(name)
|
|
703
|
+
if val is not None:
|
|
704
|
+
record_dependency(self, name)
|
|
705
|
+
return val
|
|
706
|
+
|
|
707
|
+
if self.outer is not None:
|
|
708
|
+
return self.outer.get(name)
|
|
709
|
+
return None
|
|
710
|
+
|
|
711
|
+
def set(self, name, val):
|
|
712
|
+
# Check if trying to reassign a const variable
|
|
713
|
+
if name in self.const_vars:
|
|
714
|
+
from .object import EvaluationError
|
|
715
|
+
raise ValueError(f"Cannot reassign const variable '{name}'")
|
|
716
|
+
self.store[name] = val
|
|
717
|
+
self.notify_watchers(name, val)
|
|
718
|
+
return val
|
|
719
|
+
|
|
720
|
+
def assign(self, name, val):
|
|
721
|
+
"""Assign to an existing variable in the scope chain, or create in current if not found."""
|
|
722
|
+
# 1. Check current scope
|
|
723
|
+
if name in self.store:
|
|
724
|
+
if hasattr(self, 'const_vars') and name in self.const_vars:
|
|
725
|
+
raise ValueError(f"Cannot reassign const variable '{name}'")
|
|
726
|
+
self.store[name] = val
|
|
727
|
+
if hasattr(self, 'notify_watchers'):
|
|
728
|
+
self.notify_watchers(name, val)
|
|
729
|
+
return val
|
|
730
|
+
|
|
731
|
+
# 2. Check outer scope
|
|
732
|
+
if self.outer is not None:
|
|
733
|
+
# Let's try to find where it is defined first.
|
|
734
|
+
scope = self.outer
|
|
735
|
+
while scope is not None:
|
|
736
|
+
if name in scope.store:
|
|
737
|
+
# Check for const (defensive - some envs might not have const_vars)
|
|
738
|
+
if hasattr(scope, 'const_vars') and name in scope.const_vars:
|
|
739
|
+
raise ValueError(f"Cannot reassign const variable '{name}'")
|
|
740
|
+
scope.store[name] = val
|
|
741
|
+
if hasattr(scope, 'notify_watchers'):
|
|
742
|
+
scope.notify_watchers(name, val)
|
|
743
|
+
return val
|
|
744
|
+
scope = scope.outer
|
|
745
|
+
|
|
746
|
+
# Not found anywhere -> Create in CURRENT scope (local)
|
|
747
|
+
self.store[name] = val
|
|
748
|
+
if hasattr(self, 'notify_watchers'):
|
|
749
|
+
self.notify_watchers(name, val)
|
|
750
|
+
return val
|
|
751
|
+
|
|
752
|
+
# 3. No outer scope (Global) -> Create here
|
|
753
|
+
self.store[name] = val
|
|
754
|
+
if hasattr(self, 'notify_watchers'):
|
|
755
|
+
self.notify_watchers(name, val)
|
|
756
|
+
return val
|
|
757
|
+
|
|
758
|
+
def _has_variable(self, name):
|
|
759
|
+
"""Check if a variable name exists in this scope or any outer scope."""
|
|
760
|
+
if name in self.store:
|
|
761
|
+
return True
|
|
762
|
+
if self.outer and hasattr(self.outer, '_has_variable'):
|
|
763
|
+
return self.outer._has_variable(name)
|
|
764
|
+
return False
|
|
765
|
+
|
|
766
|
+
def set_const(self, name, val):
|
|
767
|
+
"""Set a constant (immutable) variable"""
|
|
768
|
+
# Only check CURRENT scope for const shadowing - allow shadowing in nested scopes
|
|
769
|
+
if name in self.store and name in self.const_vars:
|
|
770
|
+
from .object import EvaluationError
|
|
771
|
+
raise ValueError(f"Cannot reassign const variable '{name}'")
|
|
772
|
+
self.store[name] = val
|
|
773
|
+
self.const_vars.add(name)
|
|
774
|
+
return val
|
|
775
|
+
|
|
776
|
+
def export(self, name, value):
|
|
777
|
+
self.exports[name] = value
|
|
778
|
+
return value
|
|
779
|
+
|
|
780
|
+
def get_exports(self):
|
|
781
|
+
return self.exports
|
|
782
|
+
|
|
783
|
+
def enable_debug(self):
|
|
784
|
+
self.debug_mode = True
|
|
785
|
+
|
|
786
|
+
def disable_debug(self):
|
|
787
|
+
self.debug_mode = False
|
|
788
|
+
|
|
789
|
+
def add_watcher(self, name, callback):
|
|
790
|
+
if name not in self.watchers:
|
|
791
|
+
self.watchers[name] = []
|
|
792
|
+
self.watchers[name].append(callback)
|
|
793
|
+
|
|
794
|
+
def notify_watchers(self, name, new_val):
|
|
795
|
+
if name in self.watchers:
|
|
796
|
+
# Copy list to avoid modification during iteration issues
|
|
797
|
+
callbacks = self.watchers[name][:]
|
|
798
|
+
for cb in callbacks:
|
|
799
|
+
try:
|
|
800
|
+
cb(new_val)
|
|
801
|
+
except Exception as e:
|
|
802
|
+
print(f"Error in watcher for {name}: {e}")
|
|
803
|
+
|
|
804
|
+
# === PERSISTENCE METHODS ===
|
|
805
|
+
|
|
806
|
+
def _init_persistence(self):
|
|
807
|
+
"""Initialize persistence system if scope is provided"""
|
|
808
|
+
if self.persistence_scope:
|
|
809
|
+
try:
|
|
810
|
+
# Lazy import to avoid circular dependencies
|
|
811
|
+
import sys
|
|
812
|
+
if 'zexus.persistence' in sys.modules:
|
|
813
|
+
from .persistence import PersistentStorage, MemoryTracker
|
|
814
|
+
self._persistent_storage = PersistentStorage(self.persistence_scope)
|
|
815
|
+
self._memory_tracker = MemoryTracker()
|
|
816
|
+
self._memory_tracker.start_tracking()
|
|
817
|
+
except (ImportError, Exception):
|
|
818
|
+
# Persistence module not available or error - continue without it
|
|
819
|
+
pass
|
|
820
|
+
|
|
821
|
+
def set_persistent(self, name, val):
|
|
822
|
+
"""Set a persistent variable that survives program restarts"""
|
|
823
|
+
if self._persistent_storage:
|
|
824
|
+
self._persistent_storage.set(name, val)
|
|
825
|
+
# Also store in regular memory for access
|
|
826
|
+
self.store[name] = val
|
|
827
|
+
self.notify_watchers(name, val)
|
|
828
|
+
return val
|
|
829
|
+
|
|
830
|
+
def get_persistent(self, name, default=None):
|
|
831
|
+
"""Get a persistent variable"""
|
|
832
|
+
if self._persistent_storage:
|
|
833
|
+
val = self._persistent_storage.get(name)
|
|
834
|
+
if val is not None:
|
|
835
|
+
return val
|
|
836
|
+
# Fallback to regular store
|
|
837
|
+
return self.store.get(name, default)
|
|
838
|
+
|
|
839
|
+
def delete_persistent(self, name):
|
|
840
|
+
"""Delete a persistent variable"""
|
|
841
|
+
if self._persistent_storage:
|
|
842
|
+
self._persistent_storage.delete(name)
|
|
843
|
+
if name in self.store:
|
|
844
|
+
del self.store[name]
|
|
845
|
+
|
|
846
|
+
def get_memory_stats(self):
|
|
847
|
+
"""Get current memory tracking statistics"""
|
|
848
|
+
if self._memory_tracker:
|
|
849
|
+
return self._memory_tracker.get_stats()
|
|
850
|
+
return {"tracked_objects": 0, "message": "Memory tracking not enabled"}
|
|
851
|
+
|
|
852
|
+
def enable_memory_tracking(self):
|
|
853
|
+
"""Enable memory leak detection"""
|
|
854
|
+
if not self._memory_tracker:
|
|
855
|
+
try:
|
|
856
|
+
# Lazy import
|
|
857
|
+
import sys
|
|
858
|
+
if 'zexus.persistence' in sys.modules:
|
|
859
|
+
from .persistence import MemoryTracker
|
|
860
|
+
self._memory_tracker = MemoryTracker()
|
|
861
|
+
self._memory_tracker.start_tracking()
|
|
862
|
+
except (ImportError, Exception):
|
|
863
|
+
pass
|
|
864
|
+
|
|
865
|
+
def cleanup_persistence(self):
|
|
866
|
+
"""Clean up persistence resources"""
|
|
867
|
+
if self._memory_tracker:
|
|
868
|
+
self._memory_tracker.stop_tracking()
|
|
869
|
+
if self._persistent_storage:
|
|
870
|
+
self._persistent_storage.close()
|
|
871
|
+
|
|
872
|
+
# Global constants
|
|
873
|
+
NULL = Null()
|
|
874
|
+
TRUE = Boolean(True)
|
|
875
|
+
FALSE = Boolean(False)
|
|
876
|
+
|
|
877
|
+
# File object for RAII pattern (using statement)
|
|
878
|
+
class FileHandle(Object):
|
|
879
|
+
"""File object that supports cleanup via close() method"""
|
|
880
|
+
def __init__(self, path, mode='r'):
|
|
881
|
+
self.path = path
|
|
882
|
+
self.mode = mode
|
|
883
|
+
self.handle = None
|
|
884
|
+
self.closed = False
|
|
885
|
+
|
|
886
|
+
def open(self):
|
|
887
|
+
"""Open the file"""
|
|
888
|
+
if not self.handle:
|
|
889
|
+
try:
|
|
890
|
+
self.handle = open(self.path, self.mode)
|
|
891
|
+
except Exception as e:
|
|
892
|
+
raise Exception(f"Failed to open file {self.path}: {e}")
|
|
893
|
+
return self
|
|
894
|
+
|
|
895
|
+
def close(self):
|
|
896
|
+
"""Close the file (called by using statement cleanup)"""
|
|
897
|
+
if self.handle and not self.closed:
|
|
898
|
+
self.handle.close()
|
|
899
|
+
self.closed = True
|
|
900
|
+
|
|
901
|
+
def read(self):
|
|
902
|
+
"""Read file contents"""
|
|
903
|
+
if not self.handle:
|
|
904
|
+
self.open()
|
|
905
|
+
return String(self.handle.read())
|
|
906
|
+
|
|
907
|
+
def write(self, content):
|
|
908
|
+
"""Write content to file"""
|
|
909
|
+
if not self.handle:
|
|
910
|
+
self.open()
|
|
911
|
+
self.handle.write(content)
|
|
912
|
+
return NULL
|
|
913
|
+
|
|
914
|
+
def inspect(self):
|
|
915
|
+
status = "closed" if self.closed else "open"
|
|
916
|
+
return f"File({self.path}, {status})"
|
|
917
|
+
|
|
918
|
+
def type(self):
|
|
919
|
+
return "FILE"
|
|
920
|
+
|
|
921
|
+
# EvaluationError class for error handling
|
|
922
|
+
class EvaluationError(Object):
|
|
923
|
+
def __init__(self, message, line=None, column=None, stack_trace=None, filename=None, suggestion=None):
|
|
924
|
+
self.message = message
|
|
925
|
+
self.line = line
|
|
926
|
+
self.column = column
|
|
927
|
+
self.stack_trace = stack_trace or []
|
|
928
|
+
self.filename = filename
|
|
929
|
+
self.suggestion = suggestion
|
|
930
|
+
|
|
931
|
+
def inspect(self):
|
|
932
|
+
return f"❌ Error: {self.message}"
|
|
933
|
+
|
|
934
|
+
def type(self):
|
|
935
|
+
return "ERROR"
|
|
936
|
+
|
|
937
|
+
def __str__(self):
|
|
938
|
+
"""Format as a nice error message"""
|
|
939
|
+
# Try to use error reporter if available
|
|
940
|
+
try:
|
|
941
|
+
from .error_reporter import get_error_reporter, ZexusError, ErrorCategory
|
|
942
|
+
|
|
943
|
+
error_reporter = get_error_reporter()
|
|
944
|
+
|
|
945
|
+
# Create a formatted error
|
|
946
|
+
# We use a temporary ZexusError for formatting
|
|
947
|
+
temp_error = ZexusError(
|
|
948
|
+
message=self.message,
|
|
949
|
+
category=ErrorCategory.USER_CODE,
|
|
950
|
+
filename=self.filename or "<runtime>",
|
|
951
|
+
line=self.line,
|
|
952
|
+
column=self.column,
|
|
953
|
+
source_line=error_reporter.get_source_line(self.filename, self.line) if self.line else None,
|
|
954
|
+
suggestion=self.suggestion
|
|
955
|
+
)
|
|
956
|
+
|
|
957
|
+
# Add stack trace if available
|
|
958
|
+
if self.stack_trace:
|
|
959
|
+
trace = "\n".join(self.stack_trace[-5:])
|
|
960
|
+
temp_error.message += f"\n\nStack trace:\n{trace}"
|
|
961
|
+
|
|
962
|
+
return temp_error.format_error()
|
|
963
|
+
except Exception:
|
|
964
|
+
# Fallback to simple format if error reporter not available
|
|
965
|
+
location = f"Line {self.line}:{self.column}" if self.line and self.column else "Unknown location"
|
|
966
|
+
trace = "\n".join(self.stack_trace[-3:]) if self.stack_trace else ""
|
|
967
|
+
trace_section = f"\n Stack:\n{trace}" if trace else ""
|
|
968
|
+
suggestion_section = f"\n 💡 Suggestion: {self.suggestion}" if self.suggestion else ""
|
|
969
|
+
return f"❌ Runtime Error at {location}\n {self.message}{suggestion_section}{trace_section}"
|
|
970
|
+
|
|
971
|
+
def __len__(self):
|
|
972
|
+
"""Support len() on errors to prevent secondary failures"""
|
|
973
|
+
return len(self.message)
|