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,148 @@
|
|
|
1
|
+
"""Regex module for Zexus standard library."""
|
|
2
|
+
|
|
3
|
+
import re
|
|
4
|
+
from typing import List, Dict, Any, Optional
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class RegexModule:
|
|
8
|
+
"""Provides regular expression operations."""
|
|
9
|
+
|
|
10
|
+
@staticmethod
|
|
11
|
+
def match(pattern: str, text: str, flags: int = 0) -> Optional[Dict[str, Any]]:
|
|
12
|
+
"""Match pattern at start of text."""
|
|
13
|
+
m = re.match(pattern, text, flags)
|
|
14
|
+
if m:
|
|
15
|
+
return {
|
|
16
|
+
'matched': True,
|
|
17
|
+
'groups': list(m.groups()),
|
|
18
|
+
'group_dict': m.groupdict(),
|
|
19
|
+
'span': m.span(),
|
|
20
|
+
'start': m.start(),
|
|
21
|
+
'end': m.end()
|
|
22
|
+
}
|
|
23
|
+
return None
|
|
24
|
+
|
|
25
|
+
@staticmethod
|
|
26
|
+
def search(pattern: str, text: str, flags: int = 0) -> Optional[Dict[str, Any]]:
|
|
27
|
+
"""Search for pattern in text."""
|
|
28
|
+
m = re.search(pattern, text, flags)
|
|
29
|
+
if m:
|
|
30
|
+
return {
|
|
31
|
+
'matched': True,
|
|
32
|
+
'groups': list(m.groups()),
|
|
33
|
+
'group_dict': m.groupdict(),
|
|
34
|
+
'span': m.span(),
|
|
35
|
+
'start': m.start(),
|
|
36
|
+
'end': m.end()
|
|
37
|
+
}
|
|
38
|
+
return None
|
|
39
|
+
|
|
40
|
+
@staticmethod
|
|
41
|
+
def findall(pattern: str, text: str, flags: int = 0) -> List[str]:
|
|
42
|
+
"""Find all occurrences of pattern."""
|
|
43
|
+
return re.findall(pattern, text, flags)
|
|
44
|
+
|
|
45
|
+
@staticmethod
|
|
46
|
+
def finditer(pattern: str, text: str, flags: int = 0) -> List[Dict[str, Any]]:
|
|
47
|
+
"""Find all matches as iterator."""
|
|
48
|
+
matches = []
|
|
49
|
+
for m in re.finditer(pattern, text, flags):
|
|
50
|
+
matches.append({
|
|
51
|
+
'matched': True,
|
|
52
|
+
'groups': list(m.groups()),
|
|
53
|
+
'group_dict': m.groupdict(),
|
|
54
|
+
'span': m.span(),
|
|
55
|
+
'start': m.start(),
|
|
56
|
+
'end': m.end()
|
|
57
|
+
})
|
|
58
|
+
return matches
|
|
59
|
+
|
|
60
|
+
@staticmethod
|
|
61
|
+
def sub(pattern: str, replacement: str, text: str, count: int = 0, flags: int = 0) -> str:
|
|
62
|
+
"""Replace pattern with replacement."""
|
|
63
|
+
return re.sub(pattern, replacement, text, count, flags)
|
|
64
|
+
|
|
65
|
+
@staticmethod
|
|
66
|
+
def subn(pattern: str, replacement: str, text: str, count: int = 0, flags: int = 0) -> tuple:
|
|
67
|
+
"""Replace pattern and return (new_string, number_of_subs)."""
|
|
68
|
+
return re.subn(pattern, replacement, text, count, flags)
|
|
69
|
+
|
|
70
|
+
@staticmethod
|
|
71
|
+
def split(pattern: str, text: str, maxsplit: int = 0, flags: int = 0) -> List[str]:
|
|
72
|
+
"""Split text by pattern."""
|
|
73
|
+
return re.split(pattern, text, maxsplit, flags)
|
|
74
|
+
|
|
75
|
+
@staticmethod
|
|
76
|
+
def escape(pattern: str) -> str:
|
|
77
|
+
"""Escape special characters in pattern."""
|
|
78
|
+
return re.escape(pattern)
|
|
79
|
+
|
|
80
|
+
@staticmethod
|
|
81
|
+
def compile(pattern: str, flags: int = 0) -> str:
|
|
82
|
+
"""Compile regex pattern (returns pattern string for Zexus)."""
|
|
83
|
+
# In Zexus, we can't return compiled pattern objects
|
|
84
|
+
# Just validate and return the pattern
|
|
85
|
+
re.compile(pattern, flags) # Validate
|
|
86
|
+
return pattern
|
|
87
|
+
|
|
88
|
+
@staticmethod
|
|
89
|
+
def is_match(pattern: str, text: str, flags: int = 0) -> bool:
|
|
90
|
+
"""Check if pattern matches text."""
|
|
91
|
+
return re.match(pattern, text, flags) is not None
|
|
92
|
+
|
|
93
|
+
@staticmethod
|
|
94
|
+
def is_search(pattern: str, text: str, flags: int = 0) -> bool:
|
|
95
|
+
"""Check if pattern exists in text."""
|
|
96
|
+
return re.search(pattern, text, flags) is not None
|
|
97
|
+
|
|
98
|
+
@staticmethod
|
|
99
|
+
def count_matches(pattern: str, text: str, flags: int = 0) -> int:
|
|
100
|
+
"""Count number of matches."""
|
|
101
|
+
return len(re.findall(pattern, text, flags))
|
|
102
|
+
|
|
103
|
+
@staticmethod
|
|
104
|
+
def extract_groups(pattern: str, text: str, flags: int = 0) -> List[str]:
|
|
105
|
+
"""Extract all groups from first match."""
|
|
106
|
+
m = re.search(pattern, text, flags)
|
|
107
|
+
if m:
|
|
108
|
+
return list(m.groups())
|
|
109
|
+
return []
|
|
110
|
+
|
|
111
|
+
@staticmethod
|
|
112
|
+
def extract_all_groups(pattern: str, text: str, flags: int = 0) -> List[List[str]]:
|
|
113
|
+
"""Extract groups from all matches."""
|
|
114
|
+
matches = []
|
|
115
|
+
for m in re.finditer(pattern, text, flags):
|
|
116
|
+
matches.append(list(m.groups()))
|
|
117
|
+
return matches
|
|
118
|
+
|
|
119
|
+
# Flag constants
|
|
120
|
+
IGNORECASE = re.IGNORECASE
|
|
121
|
+
MULTILINE = re.MULTILINE
|
|
122
|
+
DOTALL = re.DOTALL
|
|
123
|
+
VERBOSE = re.VERBOSE
|
|
124
|
+
ASCII = re.ASCII
|
|
125
|
+
UNICODE = re.UNICODE
|
|
126
|
+
|
|
127
|
+
|
|
128
|
+
# Export functions for easy access
|
|
129
|
+
match = RegexModule.match
|
|
130
|
+
search = RegexModule.search
|
|
131
|
+
findall = RegexModule.findall
|
|
132
|
+
finditer = RegexModule.finditer
|
|
133
|
+
sub = RegexModule.sub
|
|
134
|
+
subn = RegexModule.subn
|
|
135
|
+
split = RegexModule.split
|
|
136
|
+
escape = RegexModule.escape
|
|
137
|
+
compile = RegexModule.compile
|
|
138
|
+
is_match = RegexModule.is_match
|
|
139
|
+
is_search = RegexModule.is_search
|
|
140
|
+
count_matches = RegexModule.count_matches
|
|
141
|
+
extract_groups = RegexModule.extract_groups
|
|
142
|
+
extract_all_groups = RegexModule.extract_all_groups
|
|
143
|
+
IGNORECASE = RegexModule.IGNORECASE
|
|
144
|
+
MULTILINE = RegexModule.MULTILINE
|
|
145
|
+
DOTALL = RegexModule.DOTALL
|
|
146
|
+
VERBOSE = RegexModule.VERBOSE
|
|
147
|
+
ASCII = RegexModule.ASCII
|
|
148
|
+
UNICODE = RegexModule.UNICODE
|
|
@@ -0,0 +1,253 @@
|
|
|
1
|
+
"""Socket/TCP primitives module for Zexus standard library."""
|
|
2
|
+
|
|
3
|
+
import socket
|
|
4
|
+
import threading
|
|
5
|
+
import time
|
|
6
|
+
from typing import Callable, Optional, Dict, Any
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class SocketModule:
|
|
10
|
+
"""Provides socket and TCP operations."""
|
|
11
|
+
|
|
12
|
+
@staticmethod
|
|
13
|
+
def create_server(host: str, port: int, handler: Callable, backlog: int = 5) -> 'TCPServer':
|
|
14
|
+
"""Create a TCP server that listens for connections.
|
|
15
|
+
|
|
16
|
+
Args:
|
|
17
|
+
host: Host address to bind to (e.g., '0.0.0.0', 'localhost')
|
|
18
|
+
port: Port number to listen on
|
|
19
|
+
handler: Callback function called for each connection
|
|
20
|
+
backlog: Maximum number of queued connections
|
|
21
|
+
|
|
22
|
+
Returns:
|
|
23
|
+
TCPServer instance
|
|
24
|
+
"""
|
|
25
|
+
return TCPServer(host, port, handler, backlog)
|
|
26
|
+
|
|
27
|
+
@staticmethod
|
|
28
|
+
def create_connection(host: str, port: int, timeout: float = 5.0) -> 'TCPConnection':
|
|
29
|
+
"""Create a TCP client connection.
|
|
30
|
+
|
|
31
|
+
Args:
|
|
32
|
+
host: Remote host to connect to
|
|
33
|
+
port: Remote port to connect to
|
|
34
|
+
timeout: Connection timeout in seconds
|
|
35
|
+
|
|
36
|
+
Returns:
|
|
37
|
+
TCPConnection instance
|
|
38
|
+
"""
|
|
39
|
+
return TCPConnection(host, port, timeout)
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
class TCPServer:
|
|
43
|
+
"""TCP server that accepts connections and handles them with a callback."""
|
|
44
|
+
|
|
45
|
+
def __init__(self, host: str, port: int, handler: Callable, backlog: int = 5):
|
|
46
|
+
self.host = host
|
|
47
|
+
self.port = port
|
|
48
|
+
self.handler = handler
|
|
49
|
+
self.backlog = backlog
|
|
50
|
+
self.socket: Optional[socket.socket] = None
|
|
51
|
+
self.running = False
|
|
52
|
+
self.thread: Optional[threading.Thread] = None
|
|
53
|
+
|
|
54
|
+
def start(self) -> None:
|
|
55
|
+
"""Start the server in a background thread."""
|
|
56
|
+
if self.running:
|
|
57
|
+
raise RuntimeError("Server is already running")
|
|
58
|
+
|
|
59
|
+
self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
|
60
|
+
self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
|
|
61
|
+
self.socket.bind((self.host, self.port))
|
|
62
|
+
self.socket.listen(self.backlog)
|
|
63
|
+
self.running = True
|
|
64
|
+
|
|
65
|
+
# Start accept loop in background thread
|
|
66
|
+
self.thread = threading.Thread(target=self._accept_loop, daemon=True)
|
|
67
|
+
self.thread.start()
|
|
68
|
+
|
|
69
|
+
def _accept_loop(self):
|
|
70
|
+
"""Accept connections and spawn handler threads."""
|
|
71
|
+
while self.running:
|
|
72
|
+
try:
|
|
73
|
+
self.socket.settimeout(1.0) # Allow checking self.running
|
|
74
|
+
client_socket, address = self.socket.accept()
|
|
75
|
+
|
|
76
|
+
# Spawn handler in new thread
|
|
77
|
+
handler_thread = threading.Thread(
|
|
78
|
+
target=self._handle_connection,
|
|
79
|
+
args=(client_socket, address),
|
|
80
|
+
daemon=True
|
|
81
|
+
)
|
|
82
|
+
handler_thread.start()
|
|
83
|
+
|
|
84
|
+
except socket.timeout:
|
|
85
|
+
continue
|
|
86
|
+
except Exception as e:
|
|
87
|
+
if self.running: # Only log if we're not shutting down
|
|
88
|
+
print(f"Server accept error: {e}")
|
|
89
|
+
break
|
|
90
|
+
|
|
91
|
+
def _handle_connection(self, client_socket: socket.socket, address: tuple):
|
|
92
|
+
"""Handle a single client connection."""
|
|
93
|
+
try:
|
|
94
|
+
connection = TCPConnection.from_socket(client_socket, address)
|
|
95
|
+
self.handler(connection)
|
|
96
|
+
except Exception as e:
|
|
97
|
+
print(f"Connection handler error: {e}")
|
|
98
|
+
finally:
|
|
99
|
+
try:
|
|
100
|
+
client_socket.close()
|
|
101
|
+
except:
|
|
102
|
+
pass
|
|
103
|
+
|
|
104
|
+
def stop(self) -> None:
|
|
105
|
+
"""Stop the server."""
|
|
106
|
+
self.running = False
|
|
107
|
+
if self.socket:
|
|
108
|
+
try:
|
|
109
|
+
self.socket.close()
|
|
110
|
+
except:
|
|
111
|
+
pass
|
|
112
|
+
if self.thread:
|
|
113
|
+
self.thread.join(timeout=2.0)
|
|
114
|
+
|
|
115
|
+
def is_running(self) -> bool:
|
|
116
|
+
"""Check if server is running."""
|
|
117
|
+
return self.running
|
|
118
|
+
|
|
119
|
+
def get_address(self) -> Dict[str, Any]:
|
|
120
|
+
"""Get server address info."""
|
|
121
|
+
return {
|
|
122
|
+
'host': self.host,
|
|
123
|
+
'port': self.port,
|
|
124
|
+
'running': self.running
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
|
|
128
|
+
class TCPConnection:
|
|
129
|
+
"""Represents a TCP connection (client or server-side)."""
|
|
130
|
+
|
|
131
|
+
def __init__(self, host: str, port: int, timeout: float = 5.0):
|
|
132
|
+
"""Create a new client connection."""
|
|
133
|
+
self.host = host
|
|
134
|
+
self.port = port
|
|
135
|
+
self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
|
136
|
+
self.socket.settimeout(timeout)
|
|
137
|
+
self.socket.connect((host, port))
|
|
138
|
+
self.connected = True
|
|
139
|
+
|
|
140
|
+
@classmethod
|
|
141
|
+
def from_socket(cls, sock: socket.socket, address: tuple):
|
|
142
|
+
"""Create TCPConnection from existing socket (for server-side)."""
|
|
143
|
+
conn = cls.__new__(cls)
|
|
144
|
+
conn.socket = sock
|
|
145
|
+
conn.host = address[0]
|
|
146
|
+
conn.port = address[1]
|
|
147
|
+
conn.connected = True
|
|
148
|
+
return conn
|
|
149
|
+
|
|
150
|
+
def send(self, data: bytes) -> int:
|
|
151
|
+
"""Send data over the connection.
|
|
152
|
+
|
|
153
|
+
Args:
|
|
154
|
+
data: Bytes to send
|
|
155
|
+
|
|
156
|
+
Returns:
|
|
157
|
+
Number of bytes sent
|
|
158
|
+
"""
|
|
159
|
+
if not self.connected:
|
|
160
|
+
raise RuntimeError("Connection is closed")
|
|
161
|
+
return self.socket.sendall(data) or len(data)
|
|
162
|
+
|
|
163
|
+
def send_string(self, text: str, encoding: str = 'utf-8') -> int:
|
|
164
|
+
"""Send string over the connection.
|
|
165
|
+
|
|
166
|
+
Args:
|
|
167
|
+
text: String to send
|
|
168
|
+
encoding: Text encoding
|
|
169
|
+
|
|
170
|
+
Returns:
|
|
171
|
+
Number of bytes sent
|
|
172
|
+
"""
|
|
173
|
+
return self.send(text.encode(encoding))
|
|
174
|
+
|
|
175
|
+
def receive(self, buffer_size: int = 4096) -> bytes:
|
|
176
|
+
"""Receive data from the connection.
|
|
177
|
+
|
|
178
|
+
Args:
|
|
179
|
+
buffer_size: Maximum bytes to receive
|
|
180
|
+
|
|
181
|
+
Returns:
|
|
182
|
+
Received bytes (empty if connection closed)
|
|
183
|
+
"""
|
|
184
|
+
if not self.connected:
|
|
185
|
+
raise RuntimeError("Connection is closed")
|
|
186
|
+
|
|
187
|
+
try:
|
|
188
|
+
data = self.socket.recv(buffer_size)
|
|
189
|
+
if not data:
|
|
190
|
+
self.connected = False
|
|
191
|
+
return data
|
|
192
|
+
except socket.timeout:
|
|
193
|
+
return b''
|
|
194
|
+
|
|
195
|
+
def receive_string(self, buffer_size: int = 4096, encoding: str = 'utf-8') -> str:
|
|
196
|
+
"""Receive string from the connection.
|
|
197
|
+
|
|
198
|
+
Args:
|
|
199
|
+
buffer_size: Maximum bytes to receive
|
|
200
|
+
encoding: Text encoding
|
|
201
|
+
|
|
202
|
+
Returns:
|
|
203
|
+
Received string
|
|
204
|
+
"""
|
|
205
|
+
data = self.receive(buffer_size)
|
|
206
|
+
return data.decode(encoding) if data else ''
|
|
207
|
+
|
|
208
|
+
def receive_all(self, timeout: float = 5.0) -> bytes:
|
|
209
|
+
"""Receive all available data until connection closes or timeout.
|
|
210
|
+
|
|
211
|
+
Args:
|
|
212
|
+
timeout: Maximum time to wait
|
|
213
|
+
|
|
214
|
+
Returns:
|
|
215
|
+
All received bytes
|
|
216
|
+
"""
|
|
217
|
+
chunks = []
|
|
218
|
+
start_time = time.time()
|
|
219
|
+
self.socket.settimeout(0.1) # Small timeout for checking
|
|
220
|
+
|
|
221
|
+
while time.time() - start_time < timeout:
|
|
222
|
+
try:
|
|
223
|
+
chunk = self.socket.recv(4096)
|
|
224
|
+
if not chunk:
|
|
225
|
+
break
|
|
226
|
+
chunks.append(chunk)
|
|
227
|
+
except socket.timeout:
|
|
228
|
+
if chunks: # If we got some data, we're done
|
|
229
|
+
break
|
|
230
|
+
continue
|
|
231
|
+
|
|
232
|
+
return b''.join(chunks)
|
|
233
|
+
|
|
234
|
+
def close(self) -> None:
|
|
235
|
+
"""Close the connection."""
|
|
236
|
+
if self.connected:
|
|
237
|
+
try:
|
|
238
|
+
self.socket.close()
|
|
239
|
+
except:
|
|
240
|
+
pass
|
|
241
|
+
self.connected = False
|
|
242
|
+
|
|
243
|
+
def is_connected(self) -> bool:
|
|
244
|
+
"""Check if connection is still open."""
|
|
245
|
+
return self.connected
|
|
246
|
+
|
|
247
|
+
def get_address(self) -> Dict[str, Any]:
|
|
248
|
+
"""Get connection address info."""
|
|
249
|
+
return {
|
|
250
|
+
'host': self.host,
|
|
251
|
+
'port': self.port,
|
|
252
|
+
'connected': self.connected
|
|
253
|
+
}
|
|
@@ -0,0 +1,208 @@
|
|
|
1
|
+
#!/usr/bin/env zexus
|
|
2
|
+
# Zexus Testing Framework
|
|
3
|
+
# Provides assertion functions and test utilities
|
|
4
|
+
|
|
5
|
+
# Global test state - using individual variables instead of map
|
|
6
|
+
let _total = 0
|
|
7
|
+
let _passed = 0
|
|
8
|
+
let _failed = 0
|
|
9
|
+
let _current_suite = ""
|
|
10
|
+
let _failures = []
|
|
11
|
+
|
|
12
|
+
# Reset test statistics
|
|
13
|
+
action reset_test_stats() {
|
|
14
|
+
_total = 0
|
|
15
|
+
_passed = 0
|
|
16
|
+
_failed = 0
|
|
17
|
+
_current_suite = ""
|
|
18
|
+
_failures = []
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
# Start a test suite
|
|
22
|
+
action describe(suite_name) {
|
|
23
|
+
_current_suite = suite_name
|
|
24
|
+
print("\n" + suite_name)
|
|
25
|
+
print("=" + string_repeat("=", len(suite_name)))
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
# Helper to repeat string
|
|
29
|
+
action string_repeat(str, count) {
|
|
30
|
+
let result = ""
|
|
31
|
+
let i = 0
|
|
32
|
+
while i < count {
|
|
33
|
+
result = result + str
|
|
34
|
+
i = i + 1
|
|
35
|
+
}
|
|
36
|
+
return result
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
# Individual test case
|
|
40
|
+
action it(description, test_func) {
|
|
41
|
+
_total = _total + 1
|
|
42
|
+
|
|
43
|
+
try {
|
|
44
|
+
test_func()
|
|
45
|
+
_passed = _passed + 1
|
|
46
|
+
print(" ✓ " + description)
|
|
47
|
+
return true
|
|
48
|
+
} catch (e) {
|
|
49
|
+
_failed = _failed + 1
|
|
50
|
+
let failure = {
|
|
51
|
+
"suite": _current_suite,
|
|
52
|
+
"test": description,
|
|
53
|
+
"error": string(e)
|
|
54
|
+
}
|
|
55
|
+
_failures = push(_failures, failure)
|
|
56
|
+
print(" ✗ " + description)
|
|
57
|
+
print(" Error: " + string(e))
|
|
58
|
+
return false
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
# Assertion: equality
|
|
63
|
+
action assert_eq(actual, expected, message) {
|
|
64
|
+
if actual != expected {
|
|
65
|
+
let error_msg = "Assertion failed: " + message
|
|
66
|
+
error_msg = error_msg + "\n Expected: " + string(expected)
|
|
67
|
+
error_msg = error_msg + "\n Got: " + string(actual)
|
|
68
|
+
throw error_msg
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
# Assertion: not equal
|
|
73
|
+
action assert_ne(actual, expected, message) {
|
|
74
|
+
if actual == expected {
|
|
75
|
+
let error_msg = "Assertion failed: " + message
|
|
76
|
+
error_msg = error_msg + "\n Expected NOT to equal: " + string(expected)
|
|
77
|
+
error_msg = error_msg + "\n But got: " + string(actual)
|
|
78
|
+
throw error_msg
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
# Assertion: true
|
|
83
|
+
action assert_true(value, message) {
|
|
84
|
+
if !value {
|
|
85
|
+
throw "Assertion failed: " + message + " (expected true, got false)"
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
# Assertion: false
|
|
90
|
+
action assert_false(value, message) {
|
|
91
|
+
if value {
|
|
92
|
+
throw "Assertion failed: " + message + " (expected false, got true)"
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
# Assertion: null
|
|
97
|
+
action assert_null(value, message) {
|
|
98
|
+
if value != null {
|
|
99
|
+
throw "Assertion failed: " + message + " (expected null, got " + string(value) + ")"
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
# Assertion: not null
|
|
104
|
+
action assert_not_null(value, message) {
|
|
105
|
+
if value == null {
|
|
106
|
+
throw "Assertion failed: " + message + " (expected non-null value)"
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
# Assertion: type check
|
|
111
|
+
action assert_type(value, expected_type, message) {
|
|
112
|
+
let actual_type = type(value)
|
|
113
|
+
if actual_type != expected_type {
|
|
114
|
+
let error_msg = "Assertion failed: " + message
|
|
115
|
+
error_msg = error_msg + "\n Expected type: " + expected_type
|
|
116
|
+
error_msg = error_msg + "\n Got type: " + actual_type
|
|
117
|
+
throw error_msg
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
# Assertion: throws error
|
|
122
|
+
action assert_throws(func, expected_error, message) {
|
|
123
|
+
let did_throw = false
|
|
124
|
+
let error_msg = ""
|
|
125
|
+
|
|
126
|
+
try {
|
|
127
|
+
func()
|
|
128
|
+
} catch (e) {
|
|
129
|
+
did_throw = true
|
|
130
|
+
error_msg = string(e)
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
if !did_throw {
|
|
134
|
+
throw "Assertion failed: " + message + " (expected function to throw)"
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
# Assertion: greater than
|
|
139
|
+
action assert_gt(actual, expected, message) {
|
|
140
|
+
if actual <= expected {
|
|
141
|
+
let error_msg = "Assertion failed: " + message
|
|
142
|
+
error_msg = error_msg + "\n Expected > " + string(expected)
|
|
143
|
+
error_msg = error_msg + "\n Got: " + string(actual)
|
|
144
|
+
throw error_msg
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
# Assertion: greater than or equal
|
|
149
|
+
action assert_gte(actual, expected, message) {
|
|
150
|
+
if actual < expected {
|
|
151
|
+
let error_msg = "Assertion failed: " + message
|
|
152
|
+
error_msg = error_msg + "\n Expected >= " + string(expected)
|
|
153
|
+
error_msg = error_msg + "\n Got: " + string(actual)
|
|
154
|
+
throw error_msg
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
# Assertion: less than
|
|
159
|
+
action assert_lt(actual, expected, message) {
|
|
160
|
+
if actual >= expected {
|
|
161
|
+
let error_msg = "Assertion failed: " + message
|
|
162
|
+
error_msg = error_msg + "\n Expected < " + string(expected)
|
|
163
|
+
error_msg = error_msg + "\n Got: " + string(actual)
|
|
164
|
+
throw error_msg
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
# Assertion: less than or equal
|
|
169
|
+
action assert_lte(actual, expected, message) {
|
|
170
|
+
if actual > expected {
|
|
171
|
+
let error_msg = "Assertion failed: " + message
|
|
172
|
+
error_msg = error_msg + "\n Expected <= " + string(expected)
|
|
173
|
+
error_msg = error_msg + "\n Got: " + string(actual)
|
|
174
|
+
throw error_msg
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
# Print test summary
|
|
179
|
+
action print_test_summary() {
|
|
180
|
+
print("\n" + string_repeat("=", 50))
|
|
181
|
+
print("TEST SUMMARY")
|
|
182
|
+
print(string_repeat("=", 50))
|
|
183
|
+
print("Total tests: " + string(_total))
|
|
184
|
+
print("Passed: " + string(_passed) + " ✓")
|
|
185
|
+
print("Failed: " + string(_failed) + " ✗")
|
|
186
|
+
|
|
187
|
+
if _failed > 0 {
|
|
188
|
+
print("\nFailed Tests:")
|
|
189
|
+
let i = 0
|
|
190
|
+
while i < len(_failures) {
|
|
191
|
+
let failure = _failures[i]
|
|
192
|
+
print(" " + string(i + 1) + ". " + failure["suite"] + " > " + failure["test"])
|
|
193
|
+
print(" " + failure["error"])
|
|
194
|
+
i = i + 1
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
print(string_repeat("=", 50))
|
|
199
|
+
|
|
200
|
+
if _failed == 0 {
|
|
201
|
+
print("🎉 ALL TESTS PASSED!")
|
|
202
|
+
return 0
|
|
203
|
+
} else {
|
|
204
|
+
print("❌ SOME TESTS FAILED")
|
|
205
|
+
return 1
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
|