koatl 0.1.11__tar.gz → 0.1.12__tar.gz
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.
- {koatl-0.1.11 → koatl-0.1.12}/Cargo.lock +2 -1
- {koatl-0.1.11 → koatl-0.1.12}/PKG-INFO +1 -2
- {koatl-0.1.11 → koatl-0.1.12}/koatl/Cargo.toml +3 -2
- koatl-0.1.12/koatl/python/koatl/__init__.py +15 -0
- {koatl-0.1.11 → koatl-0.1.12}/koatl/python/koatl/__main__.py +45 -18
- koatl-0.1.12/koatl/python/koatl/prelude/functional/async.tl +38 -0
- koatl-0.1.12/koatl/python/koatl/prelude/functional/async_util.py +15 -0
- {koatl-0.1.11 → koatl-0.1.12}/koatl/python/koatl/prelude/functional/ok.tl +1 -1
- {koatl-0.1.11 → koatl-0.1.12}/koatl/python/koatl/prelude/iterable.tl +2 -2
- koatl-0.1.12/koatl/python/koatl/runtime/__init__.py +42 -0
- koatl-0.1.11/koatl/python/koatl/runtime/__init__.py → koatl-0.1.12/koatl/python/koatl/runtime/helpers.py +15 -35
- koatl-0.1.12/koatl/python/koatl/runtime/record.py +88 -0
- koatl-0.1.12/koatl/python/koatl/runtime/virtual.py +111 -0
- koatl-0.1.12/koatl/src/lib.rs +184 -0
- koatl-0.1.12/koatl/tests/e2e/base/iterables.tl +21 -0
- {koatl-0.1.11 → koatl-0.1.12}/koatl/tests/e2e/base/match.tl +7 -7
- {koatl-0.1.11 → koatl-0.1.12}/koatl/tests/e2e/prelude/async.tl +2 -2
- koatl-0.1.12/koatl/tests/e2e/prelude/virtual.tl +14 -0
- {koatl-0.1.11 → koatl-0.1.12}/koatl/tests/test_e2e.py +1 -1
- {koatl-0.1.11 → koatl-0.1.12}/koatl-core/parser/src/ast.rs +1 -1
- {koatl-0.1.11 → koatl-0.1.12}/koatl-core/parser/src/parser.rs +33 -11
- {koatl-0.1.11 → koatl-0.1.12}/koatl-core/parser/src/util.rs +4 -1
- {koatl-0.1.11 → koatl-0.1.12}/koatl-core/src/lib.rs +1 -1
- {koatl-0.1.11 → koatl-0.1.12}/koatl-core/src/main.rs +2 -2
- {koatl-0.1.11 → koatl-0.1.12}/koatl-core/src/transform.rs +28 -12
- {koatl-0.1.11 → koatl-0.1.12}/pyproject.toml +4 -3
- koatl-0.1.12/python/koatl/__init__.py +15 -0
- {koatl-0.1.11 → koatl-0.1.12}/python/koatl/__main__.py +45 -18
- koatl-0.1.12/python/koatl/prelude/functional/async.tl +38 -0
- koatl-0.1.12/python/koatl/prelude/functional/async_util.py +15 -0
- {koatl-0.1.11 → koatl-0.1.12}/python/koatl/prelude/functional/ok.tl +1 -1
- {koatl-0.1.11 → koatl-0.1.12}/python/koatl/prelude/iterable.tl +2 -2
- koatl-0.1.12/python/koatl/runtime/__init__.py +42 -0
- koatl-0.1.11/python/koatl/runtime/__init__.py → koatl-0.1.12/python/koatl/runtime/helpers.py +15 -35
- koatl-0.1.12/python/koatl/runtime/record.py +88 -0
- koatl-0.1.12/python/koatl/runtime/virtual.py +111 -0
- koatl-0.1.11/koatl/python/koatl/__init__.py +0 -7
- koatl-0.1.11/koatl/python/koatl/prelude/functional/async.tl +0 -18
- koatl-0.1.11/koatl/python/koatl/prelude/functional/async_util.py +0 -27
- koatl-0.1.11/koatl/python/koatl/runtime/traits.py +0 -66
- koatl-0.1.11/koatl/src/lib.rs +0 -310
- koatl-0.1.11/koatl/tests/e2e/base/iterables.tl +0 -21
- koatl-0.1.11/koatl/tests/e2e/prelude/virtual.tl +0 -14
- koatl-0.1.11/python/koatl/__init__.py +0 -7
- koatl-0.1.11/python/koatl/prelude/functional/async.tl +0 -18
- koatl-0.1.11/python/koatl/prelude/functional/async_util.py +0 -27
- koatl-0.1.11/python/koatl/runtime/traits.py +0 -66
- {koatl-0.1.11 → koatl-0.1.12}/Cargo.toml +0 -0
- {koatl-0.1.11 → koatl-0.1.12}/README.md +0 -0
- {koatl-0.1.11 → koatl-0.1.12}/koatl/.github/workflows/CI.yml +0 -0
- {koatl-0.1.11 → koatl-0.1.12}/koatl/.gitignore +0 -0
- {koatl-0.1.11 → koatl-0.1.12}/koatl/LICENSE +0 -0
- {koatl-0.1.11 → koatl-0.1.12}/koatl/README.md +0 -0
- {koatl-0.1.11 → koatl-0.1.12}/koatl/python/koatl/cli.py +0 -0
- {koatl-0.1.11 → koatl-0.1.12}/koatl/python/koatl/notebook/__init__.py +0 -0
- {koatl-0.1.11 → koatl-0.1.12}/koatl/python/koatl/notebook/magic.py +0 -0
- {koatl-0.1.11 → koatl-0.1.12}/koatl/python/koatl/prelude/__init__.tl +0 -0
- {koatl-0.1.11 → koatl-0.1.12}/koatl/python/koatl/prelude/functional/__init__.tl +0 -0
- {koatl-0.1.11 → koatl-0.1.12}/koatl/python/koatl/prelude/functional/reader.tl +0 -0
- {koatl-0.1.11 → koatl-0.1.12}/koatl/python/koatl/runtime/meta_finder.py +0 -0
- {koatl-0.1.11 → koatl-0.1.12}/koatl/requirements.txt +0 -0
- {koatl-0.1.11 → koatl-0.1.12}/koatl/src/emit_py.rs +0 -0
- {koatl-0.1.11 → koatl-0.1.12}/koatl/tests/e2e/base/coal.tl +0 -0
- {koatl-0.1.11 → koatl-0.1.12}/koatl/tests/e2e/base/containers.tl +0 -0
- {koatl-0.1.11 → koatl-0.1.12}/koatl/tests/e2e/base/decorators.tl +0 -0
- {koatl-0.1.11 → koatl-0.1.12}/koatl/tests/e2e/base/destructure-for-and-fn.tl +0 -0
- {koatl-0.1.11 → koatl-0.1.12}/koatl/tests/e2e/base/destructure.tl +0 -0
- {koatl-0.1.11 → koatl-0.1.12}/koatl/tests/e2e/base/escape_ident.tl +0 -0
- {koatl-0.1.11 → koatl-0.1.12}/koatl/tests/e2e/base/fstr.tl +0 -0
- {koatl-0.1.11 → koatl-0.1.12}/koatl/tests/e2e/base/functions.tl +0 -0
- {koatl-0.1.11 → koatl-0.1.12}/koatl/tests/e2e/base/generator.tl +0 -0
- {koatl-0.1.11 → koatl-0.1.12}/koatl/tests/e2e/base/if_expr.tl +0 -0
- {koatl-0.1.11 → koatl-0.1.12}/koatl/tests/e2e/base/imports.tl +0 -0
- {koatl-0.1.11 → koatl-0.1.12}/koatl/tests/e2e/base/loops.tl +0 -0
- {koatl-0.1.11 → koatl-0.1.12}/koatl/tests/e2e/base/nary-list.tl +0 -0
- {koatl-0.1.11 → koatl-0.1.12}/koatl/tests/e2e/base/placeholder.tl +0 -0
- {koatl-0.1.11 → koatl-0.1.12}/koatl/tests/e2e/base/precedence.tl +0 -0
- {koatl-0.1.11 → koatl-0.1.12}/koatl/tests/e2e/base/semantic_whitespace.tl +0 -0
- {koatl-0.1.11 → koatl-0.1.12}/koatl/tests/e2e/base/slice.tl +0 -0
- {koatl-0.1.11 → koatl-0.1.12}/koatl/tests/e2e/base/try.tl +0 -0
- {koatl-0.1.11 → koatl-0.1.12}/koatl/tests/e2e/destructure.tl +0 -0
- {koatl-0.1.11 → koatl-0.1.12}/koatl/tests/e2e/prelude/ok.tl +0 -0
- {koatl-0.1.11 → koatl-0.1.12}/koatl/tests/e2e/prelude/reader.tl +0 -0
- {koatl-0.1.11 → koatl-0.1.12}/koatl/tests/e2e/util/__init__.py +0 -0
- {koatl-0.1.11 → koatl-0.1.12}/koatl/tests/e2e/util/module0.tl +0 -0
- {koatl-0.1.11 → koatl-0.1.12}/koatl/tests/e2e/util/module1.tl +0 -0
- {koatl-0.1.11 → koatl-0.1.12}/koatl/tests/e2e/util/module2.tl +0 -0
- {koatl-0.1.11 → koatl-0.1.12}/koatl/tests/parse/arith.tl +0 -0
- {koatl-0.1.11 → koatl-0.1.12}/koatl/tests/parse/assign.tl +0 -0
- {koatl-0.1.11 → koatl-0.1.12}/koatl/tests/parse/deco.tl +0 -0
- {koatl-0.1.11 → koatl-0.1.12}/koatl/tests/parse/func.tl +0 -0
- {koatl-0.1.11 → koatl-0.1.12}/koatl/tests/parse/matches.tl +0 -0
- {koatl-0.1.11 → koatl-0.1.12}/koatl/tests/test_parse.py +0 -0
- {koatl-0.1.11 → koatl-0.1.12}/koatl-core/Cargo.toml +0 -0
- {koatl-0.1.11 → koatl-0.1.12}/koatl-core/parser/Cargo.toml +0 -0
- {koatl-0.1.11 → koatl-0.1.12}/koatl-core/parser/src/lexer.rs +0 -0
- {koatl-0.1.11 → koatl-0.1.12}/koatl-core/parser/src/lib.rs +0 -0
- {koatl-0.1.11 → koatl-0.1.12}/koatl-core/parser/tests/lexer.rs +0 -0
- {koatl-0.1.11 → koatl-0.1.12}/koatl-core/src/linecol.rs +0 -0
- {koatl-0.1.11 → koatl-0.1.12}/koatl-core/src/parser.rs +0 -0
- {koatl-0.1.11 → koatl-0.1.12}/koatl-core/src/py/ast.rs +0 -0
- {koatl-0.1.11 → koatl-0.1.12}/koatl-core/src/py/emit.rs +0 -0
- {koatl-0.1.11 → koatl-0.1.12}/koatl-core/src/py/mod.rs +0 -0
- {koatl-0.1.11 → koatl-0.1.12}/koatl-core/src/py/util.rs +0 -0
- {koatl-0.1.11 → koatl-0.1.12}/python/koatl/cli.py +0 -0
- {koatl-0.1.11 → koatl-0.1.12}/python/koatl/notebook/__init__.py +0 -0
- {koatl-0.1.11 → koatl-0.1.12}/python/koatl/notebook/magic.py +0 -0
- {koatl-0.1.11 → koatl-0.1.12}/python/koatl/prelude/__init__.tl +0 -0
- {koatl-0.1.11 → koatl-0.1.12}/python/koatl/prelude/functional/__init__.tl +0 -0
- {koatl-0.1.11 → koatl-0.1.12}/python/koatl/prelude/functional/reader.tl +0 -0
- {koatl-0.1.11 → koatl-0.1.12}/python/koatl/runtime/meta_finder.py +0 -0
|
@@ -99,10 +99,11 @@ checksum = "f4c7245a08504955605670dbf141fceab975f15ca21570696aebe9d2e71576bd"
|
|
|
99
99
|
|
|
100
100
|
[[package]]
|
|
101
101
|
name = "koatl"
|
|
102
|
-
version = "0.1.
|
|
102
|
+
version = "0.1.12"
|
|
103
103
|
dependencies = [
|
|
104
104
|
"ariadne",
|
|
105
105
|
"koatl-core",
|
|
106
|
+
"once_cell",
|
|
106
107
|
"pyo3",
|
|
107
108
|
]
|
|
108
109
|
|
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: koatl
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.12
|
|
4
4
|
Classifier: Programming Language :: Rust
|
|
5
5
|
Classifier: Programming Language :: Python :: Implementation :: CPython
|
|
6
6
|
Classifier: Programming Language :: Python :: Implementation :: PyPy
|
|
7
|
-
Requires-Dist: forbiddenfruit
|
|
8
7
|
License-File: LICENSE
|
|
9
8
|
Requires-Python: >=3.8
|
|
10
9
|
Description-Content-Type: text/markdown; charset=UTF-8; variant=GFM
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[package]
|
|
2
2
|
name = "koatl"
|
|
3
|
-
version = "0.1.
|
|
3
|
+
version = "0.1.12"
|
|
4
4
|
edition = "2021"
|
|
5
5
|
|
|
6
6
|
[lib]
|
|
@@ -8,6 +8,7 @@ name = "koatl"
|
|
|
8
8
|
crate-type = ["cdylib"]
|
|
9
9
|
|
|
10
10
|
[dependencies]
|
|
11
|
+
koatl-core = { path = "../koatl-core" }
|
|
11
12
|
pyo3 = "0.25.0"
|
|
12
13
|
ariadne = "0.5.1"
|
|
13
|
-
|
|
14
|
+
once_cell = "1.19.0"
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
from . import _rs
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
def transpile(*args, **kwargs):
|
|
5
|
+
try:
|
|
6
|
+
return _rs.transpile(*args, **kwargs)
|
|
7
|
+
except SyntaxError as e:
|
|
8
|
+
raise SyntaxError(e.args[0].decode("utf8")) from None
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def transpile_raw(*args, **kwargs):
|
|
12
|
+
try:
|
|
13
|
+
return _rs.transpile_raw(*args, **kwargs)
|
|
14
|
+
except SyntaxError as e:
|
|
15
|
+
raise SyntaxError(e.args[0].decode("utf8")) from None
|
|
@@ -3,13 +3,16 @@ import subprocess
|
|
|
3
3
|
import os
|
|
4
4
|
import time
|
|
5
5
|
|
|
6
|
+
|
|
6
7
|
def main():
|
|
7
8
|
mode = "script"
|
|
8
9
|
transpile_only = False
|
|
9
10
|
|
|
10
11
|
while True and len(sys.argv) > 1:
|
|
11
12
|
if sys.argv[1] == "--help":
|
|
12
|
-
print(
|
|
13
|
+
print(
|
|
14
|
+
f"Usage: python -m koatl [--trans] [--mode script|module|interactive] <filename.(py|tl)>"
|
|
15
|
+
)
|
|
13
16
|
sys.exit(1)
|
|
14
17
|
|
|
15
18
|
if sys.argv[1] == "--mode":
|
|
@@ -31,37 +34,54 @@ def main():
|
|
|
31
34
|
km = None
|
|
32
35
|
|
|
33
36
|
try:
|
|
34
|
-
km = KernelManager(kernel_name=
|
|
37
|
+
km = KernelManager(kernel_name="koatl")
|
|
35
38
|
km.start_kernel()
|
|
36
39
|
|
|
37
40
|
# Give the kernel a moment to fully initialize
|
|
38
41
|
# time.sleep(1)
|
|
39
|
-
|
|
40
|
-
jupyter_command = [
|
|
42
|
+
|
|
43
|
+
jupyter_command = [
|
|
44
|
+
sys.executable,
|
|
45
|
+
"-m",
|
|
46
|
+
"jupyter_console",
|
|
47
|
+
"--existing",
|
|
48
|
+
km.connection_file,
|
|
49
|
+
]
|
|
41
50
|
subprocess.call(jupyter_command)
|
|
42
51
|
except FileNotFoundError:
|
|
43
52
|
print("\nError: 'jupyter' command not found.", file=sys.stderr)
|
|
44
|
-
print(
|
|
45
|
-
|
|
53
|
+
print(
|
|
54
|
+
"Please ensure 'jupyter_console' is installed (pip install jupyter_console) and in your PATH.",
|
|
55
|
+
file=sys.stderr,
|
|
56
|
+
)
|
|
57
|
+
print(
|
|
58
|
+
"Also, ensure 'koatl' kernel is installed for Jupyter.", file=sys.stderr
|
|
59
|
+
)
|
|
46
60
|
sys.exit(1)
|
|
47
61
|
except Exception as e:
|
|
48
62
|
print(f"\nAn unexpected error occurred: {e}", file=sys.stderr)
|
|
49
|
-
print(
|
|
63
|
+
print(
|
|
64
|
+
"Please ensure the 'koatl' kernel is correctly installed and registered with Jupyter.",
|
|
65
|
+
file=sys.stderr,
|
|
66
|
+
)
|
|
50
67
|
sys.exit(1)
|
|
51
68
|
finally:
|
|
52
69
|
# 4. Clean up: Shutdown the kernel and remove its connection file
|
|
53
70
|
if km and km.is_alive():
|
|
54
71
|
print("Shutting down the kernel...")
|
|
55
|
-
km.shutdown_kernel(now=True)
|
|
72
|
+
km.shutdown_kernel(now=True) # Forceful shutdown
|
|
56
73
|
print("Kernel shut down.")
|
|
57
|
-
|
|
74
|
+
|
|
58
75
|
# Clean up the connection file if it still exists
|
|
59
76
|
if km and km.connection_file and os.path.exists(km.connection_file):
|
|
60
77
|
try:
|
|
61
78
|
os.remove(km.connection_file)
|
|
62
79
|
print(f"Removed connection file: {km.connection_file}")
|
|
63
80
|
except OSError as e:
|
|
64
|
-
print(
|
|
81
|
+
print(
|
|
82
|
+
f"Error removing connection file {km.connection_file}: {e}",
|
|
83
|
+
file=sys.stderr,
|
|
84
|
+
)
|
|
65
85
|
else:
|
|
66
86
|
script_path = sys.argv[1]
|
|
67
87
|
sys.argv = sys.argv[1:]
|
|
@@ -73,27 +93,34 @@ def main():
|
|
|
73
93
|
print(f"Error: File not found at '{script_path}'")
|
|
74
94
|
sys.exit(1)
|
|
75
95
|
|
|
76
|
-
if script_path.endswith(
|
|
96
|
+
if script_path.endswith(".tl"):
|
|
77
97
|
import koatl.cli
|
|
98
|
+
|
|
78
99
|
if transpile_only:
|
|
79
|
-
print(
|
|
100
|
+
print(
|
|
101
|
+
koatl.cli.transpile_from_source(
|
|
102
|
+
original_script_code, mode=mode, script_path=script_path
|
|
103
|
+
)
|
|
104
|
+
)
|
|
80
105
|
else:
|
|
81
|
-
koatl.cli.run_from_source(
|
|
106
|
+
koatl.cli.run_from_source(
|
|
107
|
+
original_script_code, mode=mode, script_path=script_path
|
|
108
|
+
)
|
|
82
109
|
else:
|
|
83
|
-
injected_code =
|
|
84
|
-
"""
|
|
110
|
+
injected_code = """
|
|
85
111
|
# -- injected code --
|
|
86
112
|
from koatl.runtime import *
|
|
87
113
|
"""
|
|
88
114
|
|
|
89
115
|
full_code = injected_code + original_script_code
|
|
90
|
-
code_obj = compile(full_code, script_path,
|
|
116
|
+
code_obj = compile(full_code, script_path, "exec")
|
|
91
117
|
|
|
92
118
|
script_globals = {
|
|
93
|
-
|
|
119
|
+
"__name__": "__main__",
|
|
94
120
|
}
|
|
95
121
|
|
|
96
122
|
exec(code_obj, script_globals)
|
|
97
123
|
|
|
124
|
+
|
|
98
125
|
if __name__ == "__main__":
|
|
99
|
-
main()
|
|
126
|
+
main()
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import functools.wraps
|
|
2
|
+
import asyncio
|
|
3
|
+
import .async_util
|
|
4
|
+
|
|
5
|
+
export Async = class:
|
|
6
|
+
__init__ = (self, awaitable) => self.generator = awaitable.__await__()
|
|
7
|
+
|
|
8
|
+
__await__ = self => self.generator
|
|
9
|
+
|
|
10
|
+
__repr__ = self => "Async(...)"
|
|
11
|
+
|
|
12
|
+
from_generator_fn = &[staticmethod] (generator_fn, *args, **kwargs) =>
|
|
13
|
+
m = object.__new__(Async)
|
|
14
|
+
m.generator = generator_fn(*args, **kwargs)
|
|
15
|
+
return m
|
|
16
|
+
|
|
17
|
+
run = self => asyncio.run(async_util.to_coro(self))
|
|
18
|
+
|
|
19
|
+
bind_once = (self, f) => Async.from_generator_fn(
|
|
20
|
+
() =>
|
|
21
|
+
result = f(yield from self.__await__())
|
|
22
|
+
|
|
23
|
+
if hasattr(result, "__await__"):
|
|
24
|
+
return yield from result.__await__()
|
|
25
|
+
|
|
26
|
+
return result
|
|
27
|
+
)
|
|
28
|
+
|
|
29
|
+
pure = &[staticmethod] x => Async.from_generator_fn(
|
|
30
|
+
() =>
|
|
31
|
+
return x
|
|
32
|
+
yield None
|
|
33
|
+
)
|
|
34
|
+
|
|
35
|
+
sleep = &[staticmethod] x => Async(asyncio.sleep(x))
|
|
36
|
+
|
|
37
|
+
#- TODO: Why is asyncio.gather eager? -#
|
|
38
|
+
gather = &[staticmethod] (*args) => Async.from_generator_fn(() => yield from asyncio.gather(*args))
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
"""
|
|
2
|
+
At the time of writing, I haven't implemented async def
|
|
3
|
+
in Koatl, so this is a workaround.
|
|
4
|
+
|
|
5
|
+
This function converts a generic awaitable (perhaps a
|
|
6
|
+
vanilla generator) into a coroutine that can be used
|
|
7
|
+
by asyncio.run, which expects strictly a coroutine.
|
|
8
|
+
|
|
9
|
+
(In practice, async def shouldn't be needed anyways,
|
|
10
|
+
since we have the Async monad.)
|
|
11
|
+
"""
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
async def to_coro(awaitable):
|
|
15
|
+
return await awaitable
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
"""
|
|
2
|
+
This module initializes the environment for koatl.
|
|
3
|
+
It sets up the meta-finder hook to enable importing .tl files,
|
|
4
|
+
and also declares functions that are required for certain tl features to work,
|
|
5
|
+
such as coalescing and module exports.
|
|
6
|
+
|
|
7
|
+
koatl.runtime should be written in Python only since otherwise
|
|
8
|
+
it would create a circular dependency.
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
import functools
|
|
12
|
+
from types import SimpleNamespace
|
|
13
|
+
|
|
14
|
+
from . import meta_finder
|
|
15
|
+
|
|
16
|
+
meta_finder.install_hook()
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
from .virtual import *
|
|
20
|
+
from .record import *
|
|
21
|
+
from .helpers import *
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
__tl__ = SimpleNamespace(
|
|
25
|
+
unpack_record=helpers.unpack_record,
|
|
26
|
+
set_exports=helpers.set_exports,
|
|
27
|
+
do=helpers.do,
|
|
28
|
+
vget=helpers.vget,
|
|
29
|
+
ok=helpers.ok,
|
|
30
|
+
partial=functools.partial,
|
|
31
|
+
**{name: helpers.__dict__[name] for name in helpers.__all__},
|
|
32
|
+
**{name: record.__dict__[name] for name in record.__all__},
|
|
33
|
+
**{name: virtual.__dict__[name] for name in virtual.__all__}
|
|
34
|
+
)
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
__all__ = [
|
|
38
|
+
"__tl__",
|
|
39
|
+
*helpers.__all__,
|
|
40
|
+
*record.__all__,
|
|
41
|
+
*virtual.__all__,
|
|
42
|
+
]
|
|
@@ -1,17 +1,9 @@
|
|
|
1
|
-
"""
|
|
2
|
-
This module initializes the environment for koatl.
|
|
3
|
-
It sets up the meta-finder hook to enable importing .tl files,
|
|
4
|
-
and also declares functions that are required for certain tl features to work,
|
|
5
|
-
such as coalescing and module exports.
|
|
6
|
-
"""
|
|
7
|
-
|
|
8
1
|
from functools import wraps
|
|
9
|
-
from
|
|
2
|
+
from .virtual import vget
|
|
3
|
+
from .record import Record
|
|
10
4
|
|
|
11
|
-
from . import meta_finder
|
|
12
|
-
from .._rs import Record, vget, ok
|
|
13
5
|
|
|
14
|
-
|
|
6
|
+
__all__ = ["MatchError"]
|
|
15
7
|
|
|
16
8
|
|
|
17
9
|
class MatchError(Exception):
|
|
@@ -37,7 +29,10 @@ def set_exports(package_name, globals_dict, exports, module_star_exports):
|
|
|
37
29
|
|
|
38
30
|
exports.add(name)
|
|
39
31
|
|
|
40
|
-
|
|
32
|
+
if "__all__" not in globals_dict:
|
|
33
|
+
globals_dict["__all__"] = ()
|
|
34
|
+
|
|
35
|
+
globals_dict["__all__"] = tuple(set(globals_dict["__all__"]) | exports)
|
|
41
36
|
|
|
42
37
|
|
|
43
38
|
def unpack_record(obj):
|
|
@@ -50,6 +45,14 @@ def unpack_record(obj):
|
|
|
50
45
|
return Record(obj.__dict__)
|
|
51
46
|
|
|
52
47
|
|
|
48
|
+
def ok(obj):
|
|
49
|
+
if obj is None:
|
|
50
|
+
return False
|
|
51
|
+
if isinstance(obj, BaseException):
|
|
52
|
+
return False
|
|
53
|
+
return True
|
|
54
|
+
|
|
55
|
+
|
|
53
56
|
def do(f):
|
|
54
57
|
@wraps(f)
|
|
55
58
|
def impl(*args, **kwargs):
|
|
@@ -74,26 +77,3 @@ def do(f):
|
|
|
74
77
|
return vget(m, "bind_once")(recurse)
|
|
75
78
|
|
|
76
79
|
return impl
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
from .traits import *
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
__tl__ = SimpleNamespace(
|
|
83
|
-
Record=Record,
|
|
84
|
-
MatchError=MatchError,
|
|
85
|
-
unpack_record=unpack_record,
|
|
86
|
-
set_exports=set_exports,
|
|
87
|
-
vget=vget,
|
|
88
|
-
ok=ok,
|
|
89
|
-
do=do,
|
|
90
|
-
**{name: traits.__dict__[name] for name in traits.__all__}
|
|
91
|
-
)
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
__all__ = [
|
|
95
|
-
"__tl__",
|
|
96
|
-
"Record",
|
|
97
|
-
"MatchError",
|
|
98
|
-
*traits.__all__,
|
|
99
|
-
]
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import re
|
|
2
|
+
|
|
3
|
+
__all__ = ["Record"]
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class Record(dict):
|
|
7
|
+
def __repr__(self):
|
|
8
|
+
return self._repr_with_visited(set())
|
|
9
|
+
|
|
10
|
+
def __getattr__(self, name):
|
|
11
|
+
try:
|
|
12
|
+
return self[name]
|
|
13
|
+
except KeyError:
|
|
14
|
+
raise AttributeError(
|
|
15
|
+
f"'{type(self).__name__}' object has no attribute '{name}'"
|
|
16
|
+
) from None
|
|
17
|
+
|
|
18
|
+
def _repr_with_visited(self, visited):
|
|
19
|
+
# Handle cycles by checking if this object is already being processed
|
|
20
|
+
obj_id = id(self)
|
|
21
|
+
if obj_id in visited:
|
|
22
|
+
return "{...}"
|
|
23
|
+
|
|
24
|
+
visited.add(obj_id)
|
|
25
|
+
try:
|
|
26
|
+
if not self:
|
|
27
|
+
return "{}"
|
|
28
|
+
|
|
29
|
+
items = []
|
|
30
|
+
for key, value in self.items():
|
|
31
|
+
key_str = self._format_key(key)
|
|
32
|
+
|
|
33
|
+
# Handle value representation with cycle detection
|
|
34
|
+
if isinstance(value, Record):
|
|
35
|
+
value_str = value._repr_with_visited(visited.copy())
|
|
36
|
+
elif hasattr(value, "__dict__") and hasattr(value, "__class__"):
|
|
37
|
+
# For other objects that might contain cycles, use a simple repr
|
|
38
|
+
value_str = repr(value)
|
|
39
|
+
else:
|
|
40
|
+
value_str = repr(value)
|
|
41
|
+
|
|
42
|
+
items.append(f"{key_str}: {value_str}")
|
|
43
|
+
|
|
44
|
+
return "{" + ", ".join(items) + "}"
|
|
45
|
+
finally:
|
|
46
|
+
visited.remove(obj_id)
|
|
47
|
+
|
|
48
|
+
def _format_key(self, key):
|
|
49
|
+
if isinstance(key, str) and self._is_identifier(key):
|
|
50
|
+
# If key is an identifier, drop the quotes
|
|
51
|
+
return key
|
|
52
|
+
|
|
53
|
+
elif isinstance(key, (int, float, bool, type(None))):
|
|
54
|
+
# If key is a literal like 0, 1, True, False, None, use repr
|
|
55
|
+
return repr(key)
|
|
56
|
+
|
|
57
|
+
else:
|
|
58
|
+
# Otherwise, use f"({repr(key)})"
|
|
59
|
+
return f"({repr(key)})"
|
|
60
|
+
|
|
61
|
+
def _is_identifier(self, s):
|
|
62
|
+
return (
|
|
63
|
+
isinstance(s, str)
|
|
64
|
+
and re.match(r"^[a-zA-Z_][a-zA-Z0-9_]*$", s)
|
|
65
|
+
and s not in koatl_keywords
|
|
66
|
+
)
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
koatl_keywords = {
|
|
70
|
+
"if",
|
|
71
|
+
"else",
|
|
72
|
+
"while",
|
|
73
|
+
"for",
|
|
74
|
+
"def",
|
|
75
|
+
"class",
|
|
76
|
+
"return",
|
|
77
|
+
"import",
|
|
78
|
+
"from",
|
|
79
|
+
"as",
|
|
80
|
+
"with",
|
|
81
|
+
"try",
|
|
82
|
+
"except",
|
|
83
|
+
"finally",
|
|
84
|
+
"raise",
|
|
85
|
+
"assert",
|
|
86
|
+
"async",
|
|
87
|
+
"await",
|
|
88
|
+
}
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
from functools import partial
|
|
2
|
+
from itertools import count
|
|
3
|
+
from types import new_class
|
|
4
|
+
from .._rs import fast_vget, fast_vset, fast_vset_trait
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
def ExtensionProperty(f):
|
|
8
|
+
f.ext_prop = True
|
|
9
|
+
return f
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def vget(obj, name):
|
|
13
|
+
try:
|
|
14
|
+
return getattr(obj, name)
|
|
15
|
+
except:
|
|
16
|
+
# special case for iter - this could be implemented using types and trait vtbls
|
|
17
|
+
# but this is simpler and probably faster
|
|
18
|
+
if name == "iter":
|
|
19
|
+
if isinstance(obj, slice):
|
|
20
|
+
start = obj.start if obj.start is not None else 0
|
|
21
|
+
step = obj.step if obj.step is not None else 1
|
|
22
|
+
if obj.stop is None:
|
|
23
|
+
return count(start, step)
|
|
24
|
+
else:
|
|
25
|
+
return range(start, obj.stop, step)
|
|
26
|
+
|
|
27
|
+
try:
|
|
28
|
+
return obj.items()
|
|
29
|
+
except AttributeError:
|
|
30
|
+
pass
|
|
31
|
+
|
|
32
|
+
try:
|
|
33
|
+
return iter(obj)
|
|
34
|
+
except TypeError:
|
|
35
|
+
pass
|
|
36
|
+
|
|
37
|
+
v = fast_vget(obj, name)
|
|
38
|
+
if v is not None:
|
|
39
|
+
if hasattr(v, "ext_prop"):
|
|
40
|
+
return v(obj)
|
|
41
|
+
|
|
42
|
+
return partial(v, obj)
|
|
43
|
+
|
|
44
|
+
raise AttributeError(
|
|
45
|
+
f"'{type(obj).__name__}' object has no v-attribute '{name}'"
|
|
46
|
+
) from None
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
def Trait(module, name, methods, *, requires=[]):
|
|
50
|
+
def fix_methods(type_name, methods):
|
|
51
|
+
import inspect
|
|
52
|
+
|
|
53
|
+
for method_name, method in methods.items():
|
|
54
|
+
method.__name__ = method_name
|
|
55
|
+
method.__qualname__ = f"{type_name}.{method_name}"
|
|
56
|
+
|
|
57
|
+
if not isinstance(method, (staticmethod, classmethod)):
|
|
58
|
+
sig = inspect.signature(method)
|
|
59
|
+
params = list(sig.parameters.values())
|
|
60
|
+
params[0].replace(name="self")
|
|
61
|
+
sig = sig.replace(parameters=params)
|
|
62
|
+
method.__signature__ = sig
|
|
63
|
+
|
|
64
|
+
fix_methods(name, methods)
|
|
65
|
+
|
|
66
|
+
def instancecheck(cls, instance):
|
|
67
|
+
if cls != typ:
|
|
68
|
+
# if not checking for the trait itself, use the default behavior
|
|
69
|
+
return type.__instancecheck__(cls, instance)
|
|
70
|
+
|
|
71
|
+
for req in requires:
|
|
72
|
+
try:
|
|
73
|
+
vget(instance, req)
|
|
74
|
+
except AttributeError:
|
|
75
|
+
return False
|
|
76
|
+
|
|
77
|
+
return True
|
|
78
|
+
|
|
79
|
+
meta = type(
|
|
80
|
+
f"{name}Meta",
|
|
81
|
+
(type,),
|
|
82
|
+
{"__instancecheck__": instancecheck, "__module__": "types"},
|
|
83
|
+
)
|
|
84
|
+
|
|
85
|
+
def populate(ns):
|
|
86
|
+
for method_name, method in methods.items():
|
|
87
|
+
ns[method_name] = method
|
|
88
|
+
ns["__module__"] = module
|
|
89
|
+
ns["_methods"] = methods
|
|
90
|
+
ns["_requires"] = requires
|
|
91
|
+
|
|
92
|
+
typ = new_class(name, (), {"metaclass": meta}, populate)
|
|
93
|
+
|
|
94
|
+
return typ
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
def register_global_attr(type, name, value):
|
|
98
|
+
fast_vset(type, name, value)
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
def register_global_trait(type):
|
|
102
|
+
for name, method in type._methods.items():
|
|
103
|
+
fast_vset_trait(type.__name__, type._requires, name, method)
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
__all__ = [
|
|
107
|
+
"Trait",
|
|
108
|
+
"ExtensionProperty",
|
|
109
|
+
"register_global_attr",
|
|
110
|
+
"register_global_trait",
|
|
111
|
+
]
|