koatl 0.1.38__tar.gz → 0.1.40__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.38 → koatl-0.1.40}/Cargo.lock +1 -1
- {koatl-0.1.38 → koatl-0.1.40}/PKG-INFO +1 -1
- {koatl-0.1.38 → koatl-0.1.40}/koatl/Cargo.toml +1 -1
- koatl-0.1.40/koatl/python/koatl/prelude/__init__.tl +40 -0
- koatl-0.1.40/koatl/python/koatl/runtime/__init__.py +47 -0
- koatl-0.1.40/koatl/python/koatl/runtime/record.py +249 -0
- koatl-0.1.38/koatl/python/koatl/runtime/virtual.py → koatl-0.1.40/koatl/python/koatl/runtime/vattr.py +1 -37
- koatl-0.1.40/koatl/python/koatl/std/alg/do.tl +34 -0
- {koatl-0.1.38 → koatl-0.1.40/koatl}/python/koatl/std/alg/result.tl +17 -1
- koatl-0.1.40/koatl/python/koatl/std/data/__init__.tl +2 -0
- koatl-0.1.40/koatl/python/koatl/std/data/record.tl +5 -0
- koatl-0.1.40/koatl/python/koatl/std/ext.tl +24 -0
- {koatl-0.1.38 → koatl-0.1.40}/koatl/python/koatl/std/lazy_module.tl +23 -5
- {koatl-0.1.38 → koatl-0.1.40/koatl}/python/koatl/std/trait.py +2 -2
- {koatl-0.1.38 → koatl-0.1.40}/koatl/src/lib.rs +20 -10
- {koatl-0.1.38 → koatl-0.1.40}/koatl/tests/e2e/base/containers.tl +4 -1
- {koatl-0.1.38 → koatl-0.1.40}/koatl-core/parser/src/lexer.rs +4 -28
- {koatl-0.1.38 → koatl-0.1.40}/koatl-core/parser/src/parser.rs +0 -1
- {koatl-0.1.38 → koatl-0.1.40}/koatl-core/src/py/emit.rs +3 -1
- {koatl-0.1.38 → koatl-0.1.40}/koatl-core/src/resolve_scopes.rs +5 -3
- {koatl-0.1.38 → koatl-0.1.40}/koatl-core/src/transform.rs +9 -2
- koatl-0.1.40/python/koatl/prelude/__init__.tl +40 -0
- koatl-0.1.40/python/koatl/runtime/__init__.py +47 -0
- koatl-0.1.40/python/koatl/runtime/record.py +249 -0
- koatl-0.1.38/python/koatl/runtime/virtual.py → koatl-0.1.40/python/koatl/runtime/vattr.py +1 -37
- koatl-0.1.40/python/koatl/std/alg/do.tl +34 -0
- {koatl-0.1.38/koatl → koatl-0.1.40}/python/koatl/std/alg/result.tl +17 -1
- koatl-0.1.40/python/koatl/std/data/__init__.tl +2 -0
- koatl-0.1.40/python/koatl/std/data/record.tl +5 -0
- koatl-0.1.40/python/koatl/std/ext.tl +24 -0
- {koatl-0.1.38 → koatl-0.1.40}/python/koatl/std/lazy_module.tl +23 -5
- {koatl-0.1.38/koatl → koatl-0.1.40}/python/koatl/std/trait.py +2 -2
- koatl-0.1.38/koatl/python/koatl/prelude/__init__.tl +0 -61
- koatl-0.1.38/koatl/python/koatl/runtime/__init__.py +0 -62
- koatl-0.1.38/koatl/python/koatl/runtime/helpers.py +0 -71
- koatl-0.1.38/koatl/python/koatl/runtime/record.py +0 -116
- koatl-0.1.38/koatl/python/koatl/std/data/__init__.tl +0 -1
- koatl-0.1.38/python/koatl/prelude/__init__.tl +0 -61
- koatl-0.1.38/python/koatl/runtime/__init__.py +0 -62
- koatl-0.1.38/python/koatl/runtime/helpers.py +0 -71
- koatl-0.1.38/python/koatl/runtime/record.py +0 -116
- koatl-0.1.38/python/koatl/std/data/__init__.tl +0 -1
- {koatl-0.1.38 → koatl-0.1.40}/Cargo.toml +0 -0
- {koatl-0.1.38 → koatl-0.1.40}/README.md +0 -0
- {koatl-0.1.38 → koatl-0.1.40}/koatl/.github/workflows/CI.yml +0 -0
- {koatl-0.1.38 → koatl-0.1.40}/koatl/.gitignore +0 -0
- {koatl-0.1.38 → koatl-0.1.40}/koatl/LICENSE +0 -0
- {koatl-0.1.38 → koatl-0.1.40}/koatl/README.md +0 -0
- {koatl-0.1.38 → koatl-0.1.40}/koatl/python/koatl/__init__.py +0 -0
- {koatl-0.1.38 → koatl-0.1.40}/koatl/python/koatl/__main__.py +0 -0
- {koatl-0.1.38 → koatl-0.1.40}/koatl/python/koatl/cli.py +0 -0
- {koatl-0.1.38 → koatl-0.1.40}/koatl/python/koatl/notebook/__init__.py +0 -0
- {koatl-0.1.38 → koatl-0.1.40}/koatl/python/koatl/notebook/magic.py +0 -0
- {koatl-0.1.38 → koatl-0.1.40}/koatl/python/koatl/runtime/meta_finder.py +0 -0
- {koatl-0.1.38 → koatl-0.1.40}/koatl/python/koatl/std/alg/__init__.tl +0 -0
- {koatl-0.1.38 → koatl-0.1.40}/koatl/python/koatl/std/alg/async.tl +0 -0
- {koatl-0.1.38 → koatl-0.1.40}/koatl/python/koatl/std/alg/base.tl +0 -0
- {koatl-0.1.38 → koatl-0.1.40}/koatl/python/koatl/std/alg/env.tl +0 -0
- {koatl-0.1.38 → koatl-0.1.40}/koatl/python/koatl/std/alg/memo.tl +0 -0
- {koatl-0.1.38 → koatl-0.1.40}/koatl/python/koatl/std/data/list.tl +0 -0
- {koatl-0.1.38 → koatl-0.1.40}/koatl/python/koatl/std/io.tl +0 -0
- {koatl-0.1.38 → koatl-0.1.40}/koatl/python/koatl/std/iter.tl +0 -0
- {koatl-0.1.38 → koatl-0.1.40}/koatl/python/koatl/std/re.tl +0 -0
- {koatl-0.1.38 → koatl-0.1.40}/koatl/requirements.txt +0 -0
- {koatl-0.1.38 → koatl-0.1.40}/koatl/src/emit_py.rs +0 -0
- {koatl-0.1.38 → koatl-0.1.40}/koatl/tests/e2e/base/data.txt +0 -0
- {koatl-0.1.38 → koatl-0.1.40}/koatl/tests/e2e/base/decorators.tl +0 -0
- {koatl-0.1.38 → koatl-0.1.40}/koatl/tests/e2e/base/destructure-for-and-fn.tl +0 -0
- {koatl-0.1.38 → koatl-0.1.40}/koatl/tests/e2e/base/destructure.tl +0 -0
- {koatl-0.1.38 → koatl-0.1.40}/koatl/tests/e2e/base/escape_ident.tl +0 -0
- {koatl-0.1.38 → koatl-0.1.40}/koatl/tests/e2e/base/fstr.tl +0 -0
- {koatl-0.1.38 → koatl-0.1.40}/koatl/tests/e2e/base/functions.tl +0 -0
- {koatl-0.1.38 → koatl-0.1.40}/koatl/tests/e2e/base/generator.tl +0 -0
- {koatl-0.1.38 → koatl-0.1.40}/koatl/tests/e2e/base/if_expr.tl +0 -0
- {koatl-0.1.38 → koatl-0.1.40}/koatl/tests/e2e/base/loops.tl +0 -0
- {koatl-0.1.38 → koatl-0.1.40}/koatl/tests/e2e/base/match.tl +0 -0
- {koatl-0.1.38 → koatl-0.1.40}/koatl/tests/e2e/base/nary-list.tl +0 -0
- {koatl-0.1.38 → koatl-0.1.40}/koatl/tests/e2e/base/placeholder.tl +0 -0
- {koatl-0.1.38 → koatl-0.1.40}/koatl/tests/e2e/base/precedence.tl +0 -0
- {koatl-0.1.38 → koatl-0.1.40}/koatl/tests/e2e/base/scopes.tl +0 -0
- {koatl-0.1.38 → koatl-0.1.40}/koatl/tests/e2e/base/semantic_whitespace.tl +0 -0
- {koatl-0.1.38 → koatl-0.1.40}/koatl/tests/e2e/base/short_circuit.tl +0 -0
- {koatl-0.1.38 → koatl-0.1.40}/koatl/tests/e2e/base/with.tl +0 -0
- {koatl-0.1.38 → koatl-0.1.40}/koatl/tests/e2e/prelude/async.tl +0 -0
- {koatl-0.1.38 → koatl-0.1.40}/koatl/tests/e2e/prelude/aug_assign.tl +0 -0
- {koatl-0.1.38 → koatl-0.1.40}/koatl/tests/e2e/prelude/coal.tl +0 -0
- {koatl-0.1.38 → koatl-0.1.40}/koatl/tests/e2e/prelude/env.tl +0 -0
- {koatl-0.1.38 → koatl-0.1.40}/koatl/tests/e2e/prelude/imports.tl +0 -0
- {koatl-0.1.38 → koatl-0.1.40}/koatl/tests/e2e/prelude/iterables.tl +0 -0
- {koatl-0.1.38 → koatl-0.1.40}/koatl/tests/e2e/prelude/list.tl +0 -0
- {koatl-0.1.38 → koatl-0.1.40}/koatl/tests/e2e/prelude/memo.tl +0 -0
- {koatl-0.1.38/koatl/tests/e2e/base → koatl-0.1.40/koatl/tests/e2e/prelude}/record.tl +0 -0
- {koatl-0.1.38 → koatl-0.1.40}/koatl/tests/e2e/prelude/result.tl +0 -0
- {koatl-0.1.38 → koatl-0.1.40}/koatl/tests/e2e/prelude/slice.tl +0 -0
- {koatl-0.1.38 → koatl-0.1.40}/koatl/tests/e2e/prelude/try.tl +0 -0
- {koatl-0.1.38 → koatl-0.1.40}/koatl/tests/e2e/prelude/virtual.tl +0 -0
- {koatl-0.1.38 → koatl-0.1.40}/koatl/tests/e2e/util/__init__.py +0 -0
- {koatl-0.1.38 → koatl-0.1.40}/koatl/tests/e2e/util/module0.tl +0 -0
- {koatl-0.1.38 → koatl-0.1.40}/koatl/tests/e2e/util/module1.tl +0 -0
- {koatl-0.1.38 → koatl-0.1.40}/koatl/tests/e2e/util/module2.tl +0 -0
- {koatl-0.1.38 → koatl-0.1.40}/koatl/tests/parse/arith.tl +0 -0
- {koatl-0.1.38 → koatl-0.1.40}/koatl/tests/parse/assign.tl +0 -0
- {koatl-0.1.38 → koatl-0.1.40}/koatl/tests/parse/block-comments.tl +0 -0
- {koatl-0.1.38 → koatl-0.1.40}/koatl/tests/parse/deco.tl +0 -0
- {koatl-0.1.38 → koatl-0.1.40}/koatl/tests/parse/func.tl +0 -0
- {koatl-0.1.38 → koatl-0.1.40}/koatl/tests/parse/matches.tl +0 -0
- {koatl-0.1.38 → koatl-0.1.40}/koatl/tests/test_e2e.py +0 -0
- {koatl-0.1.38 → koatl-0.1.40}/koatl/tests/test_parse.py +0 -0
- {koatl-0.1.38 → koatl-0.1.40}/koatl-core/Cargo.toml +0 -0
- {koatl-0.1.38 → koatl-0.1.40}/koatl-core/parser/Cargo.toml +0 -0
- {koatl-0.1.38 → koatl-0.1.40}/koatl-core/parser/src/ast.rs +0 -0
- {koatl-0.1.38 → koatl-0.1.40}/koatl-core/parser/src/lib.rs +0 -0
- {koatl-0.1.38 → koatl-0.1.40}/koatl-core/parser/src/util.rs +0 -0
- {koatl-0.1.38 → koatl-0.1.40}/koatl-core/src/inference.rs +0 -0
- {koatl-0.1.38 → koatl-0.1.40}/koatl-core/src/lib.rs +0 -0
- {koatl-0.1.38 → koatl-0.1.40}/koatl-core/src/main.rs +0 -0
- {koatl-0.1.38 → koatl-0.1.40}/koatl-core/src/parse_timer.rs +0 -0
- {koatl-0.1.38 → koatl-0.1.40}/koatl-core/src/parser.rs +0 -0
- {koatl-0.1.38 → koatl-0.1.40}/koatl-core/src/py/ast.rs +0 -0
- {koatl-0.1.38 → koatl-0.1.40}/koatl-core/src/py/mod.rs +0 -0
- {koatl-0.1.38 → koatl-0.1.40}/koatl-core/src/py/util.rs +0 -0
- {koatl-0.1.38 → koatl-0.1.40}/koatl-core/src/types.rs +0 -0
- {koatl-0.1.38 → koatl-0.1.40}/koatl-core/src/util.rs +0 -0
- {koatl-0.1.38 → koatl-0.1.40}/pyproject.toml +0 -0
- {koatl-0.1.38 → koatl-0.1.40}/python/koatl/__init__.py +0 -0
- {koatl-0.1.38 → koatl-0.1.40}/python/koatl/__main__.py +0 -0
- {koatl-0.1.38 → koatl-0.1.40}/python/koatl/cli.py +0 -0
- {koatl-0.1.38 → koatl-0.1.40}/python/koatl/notebook/__init__.py +0 -0
- {koatl-0.1.38 → koatl-0.1.40}/python/koatl/notebook/magic.py +0 -0
- {koatl-0.1.38 → koatl-0.1.40}/python/koatl/runtime/meta_finder.py +0 -0
- {koatl-0.1.38 → koatl-0.1.40}/python/koatl/std/alg/__init__.tl +0 -0
- {koatl-0.1.38 → koatl-0.1.40}/python/koatl/std/alg/async.tl +0 -0
- {koatl-0.1.38 → koatl-0.1.40}/python/koatl/std/alg/base.tl +0 -0
- {koatl-0.1.38 → koatl-0.1.40}/python/koatl/std/alg/env.tl +0 -0
- {koatl-0.1.38 → koatl-0.1.40}/python/koatl/std/alg/memo.tl +0 -0
- {koatl-0.1.38 → koatl-0.1.40}/python/koatl/std/data/list.tl +0 -0
- {koatl-0.1.38 → koatl-0.1.40}/python/koatl/std/io.tl +0 -0
- {koatl-0.1.38 → koatl-0.1.40}/python/koatl/std/iter.tl +0 -0
- {koatl-0.1.38 → koatl-0.1.40}/python/koatl/std/re.tl +0 -0
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
export import koatl.std.(
|
|
2
|
+
trait.*
|
|
3
|
+
ext.*
|
|
4
|
+
data.*
|
|
5
|
+
iter.*
|
|
6
|
+
alg.(Result, Ok, Err, Env, Memo, Async, AsyncMemo)
|
|
7
|
+
alg.do
|
|
8
|
+
)
|
|
9
|
+
|
|
10
|
+
import koatl.std.(
|
|
11
|
+
re.Pattern
|
|
12
|
+
lazy_module.(LazyModule, RootModulesProxy)
|
|
13
|
+
)
|
|
14
|
+
|
|
15
|
+
export std = LazyModule("koatl.std")
|
|
16
|
+
export mod = RootModulesProxy()
|
|
17
|
+
|
|
18
|
+
Extension.trait(Iterable)
|
|
19
|
+
|
|
20
|
+
Extension.property(list, "len")& List.len.fget
|
|
21
|
+
|
|
22
|
+
Extension.property(object, "result")& self => Result(self)
|
|
23
|
+
|
|
24
|
+
Extension.method(str, "match")& (regex, str) => Pattern(regex).match(str)
|
|
25
|
+
|
|
26
|
+
# Note: the below methods have arguments in reverse order to Python's re module.
|
|
27
|
+
Extension.method(str, "matches")& (str, regex) => Pattern(regex).match(str)
|
|
28
|
+
Extension.method(str, "search")& (str, regex) => Pattern(regex).search(str)
|
|
29
|
+
|
|
30
|
+
__tl__.do = koatl.std.alg.do.do
|
|
31
|
+
|
|
32
|
+
__tl__.op_map = koatl.std.alg.result.op_map
|
|
33
|
+
__tl__.op_coal = koatl.std.alg.result.op_coal
|
|
34
|
+
|
|
35
|
+
__tl__.Ok = koatl.std.alg.result.Ok
|
|
36
|
+
__tl__.Err = koatl.std.alg.result.Err
|
|
37
|
+
__tl__.Result = koatl.std.alg.result.Result
|
|
38
|
+
|
|
39
|
+
__tl__.memo_value = koatl.std.alg.memo.Memo.value
|
|
40
|
+
__tl__.async_memo_value = koatl.std.alg.memo.AsyncMemo.value
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import functools
|
|
2
|
+
import importlib
|
|
3
|
+
from types import SimpleNamespace
|
|
4
|
+
|
|
5
|
+
from koatl.runtime.record import Record
|
|
6
|
+
from . import meta_finder, vattr
|
|
7
|
+
|
|
8
|
+
meta_finder.install_hook()
|
|
9
|
+
|
|
10
|
+
__all__ = ["__tl__"]
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def set_exports(package_name, globals_dict, exports, module_star_exports):
|
|
14
|
+
exports = set(exports)
|
|
15
|
+
|
|
16
|
+
for module in module_star_exports:
|
|
17
|
+
mod = importlib.import_module(module, package_name)
|
|
18
|
+
|
|
19
|
+
if hasattr(mod, "__all__"):
|
|
20
|
+
for name in mod.__all__:
|
|
21
|
+
exports.add(name)
|
|
22
|
+
else:
|
|
23
|
+
for name in dir(mod):
|
|
24
|
+
if name.startswith("_"):
|
|
25
|
+
continue
|
|
26
|
+
|
|
27
|
+
exports.add(name)
|
|
28
|
+
|
|
29
|
+
if "__all__" not in globals_dict:
|
|
30
|
+
globals_dict["__all__"] = ()
|
|
31
|
+
|
|
32
|
+
globals_dict["__all__"] = tuple(set(globals_dict["__all__"]) | exports)
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
__tl__ = SimpleNamespace(
|
|
36
|
+
Exception=Exception,
|
|
37
|
+
slice=slice,
|
|
38
|
+
type=type,
|
|
39
|
+
partial=functools.partial,
|
|
40
|
+
#
|
|
41
|
+
record_literal=Record.from_dict_ref,
|
|
42
|
+
#
|
|
43
|
+
set_exports=set_exports,
|
|
44
|
+
#
|
|
45
|
+
vget=vattr.vget,
|
|
46
|
+
vhas=vattr.vhas,
|
|
47
|
+
)
|
|
@@ -0,0 +1,249 @@
|
|
|
1
|
+
import collections
|
|
2
|
+
from collections.abc import MutableMapping
|
|
3
|
+
import functools
|
|
4
|
+
import inspect
|
|
5
|
+
import re
|
|
6
|
+
|
|
7
|
+
_property = property
|
|
8
|
+
|
|
9
|
+
__all__ = ["Record"]
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
@collections.abc.MutableMapping.register
|
|
13
|
+
class Record:
|
|
14
|
+
def __init__(self, data=None, /, **kwargs):
|
|
15
|
+
if data is None:
|
|
16
|
+
self.__dict__ = kwargs
|
|
17
|
+
else:
|
|
18
|
+
self.__dict__ = dict(data, **kwargs)
|
|
19
|
+
|
|
20
|
+
@classmethod
|
|
21
|
+
def from_dict_ref(cls, dict_obj):
|
|
22
|
+
self = cls.__new__(cls)
|
|
23
|
+
self.__dict__ = dict_obj
|
|
24
|
+
return self
|
|
25
|
+
|
|
26
|
+
@staticmethod
|
|
27
|
+
def method(fn):
|
|
28
|
+
fn._method = True
|
|
29
|
+
return fn
|
|
30
|
+
|
|
31
|
+
@staticmethod
|
|
32
|
+
def property(fn):
|
|
33
|
+
fn._property = True
|
|
34
|
+
return fn
|
|
35
|
+
|
|
36
|
+
def __getattribute__(self, name):
|
|
37
|
+
dict = object.__getattribute__(self, "__dict__")
|
|
38
|
+
|
|
39
|
+
try:
|
|
40
|
+
attr = dict[name]
|
|
41
|
+
|
|
42
|
+
if hasattr(attr, "_property"):
|
|
43
|
+
return attr(self)
|
|
44
|
+
elif hasattr(attr, "_method"):
|
|
45
|
+
return functools.partial(attr, self)
|
|
46
|
+
except KeyError:
|
|
47
|
+
pass
|
|
48
|
+
|
|
49
|
+
return object.__getattribute__(self, name)
|
|
50
|
+
|
|
51
|
+
@_property
|
|
52
|
+
def iter(self):
|
|
53
|
+
return self.items()
|
|
54
|
+
|
|
55
|
+
# MutableMapping
|
|
56
|
+
def __len__(self):
|
|
57
|
+
return len(self.__dict__)
|
|
58
|
+
|
|
59
|
+
def __getitem__(self, key):
|
|
60
|
+
try:
|
|
61
|
+
return self.__dict__[key]
|
|
62
|
+
except KeyError as e:
|
|
63
|
+
raise e
|
|
64
|
+
|
|
65
|
+
def __setitem__(self, key, item):
|
|
66
|
+
self.__dict__[key] = item
|
|
67
|
+
|
|
68
|
+
def __delitem__(self, key):
|
|
69
|
+
del self.__dict__[key]
|
|
70
|
+
|
|
71
|
+
def __iter__(self):
|
|
72
|
+
return iter(self.__dict__)
|
|
73
|
+
|
|
74
|
+
def __contains__(self, key):
|
|
75
|
+
return key in self.__dict__
|
|
76
|
+
|
|
77
|
+
def get(self, key, default=None):
|
|
78
|
+
return self.__dict__.get(key, default)
|
|
79
|
+
|
|
80
|
+
def items(self):
|
|
81
|
+
return self.__dict__.items()
|
|
82
|
+
|
|
83
|
+
def keys(self):
|
|
84
|
+
return self.__dict__.keys()
|
|
85
|
+
|
|
86
|
+
def values(self):
|
|
87
|
+
return self.__dict__.values()
|
|
88
|
+
|
|
89
|
+
# dict
|
|
90
|
+
def __repr__(self):
|
|
91
|
+
return repr(self.__dict__)
|
|
92
|
+
|
|
93
|
+
def __or__(self, other):
|
|
94
|
+
if isinstance(other, Record):
|
|
95
|
+
return self.__class__(self.__dict__ | other.__dict__)
|
|
96
|
+
if isinstance(other, dict):
|
|
97
|
+
return self.__class__(self.__dict__ | other)
|
|
98
|
+
return NotImplemented
|
|
99
|
+
|
|
100
|
+
def __ror__(self, other):
|
|
101
|
+
if isinstance(other, Record):
|
|
102
|
+
return self.__class__(other.__dict__ | self.__dict__)
|
|
103
|
+
if isinstance(other, dict):
|
|
104
|
+
return self.__class__(other | self.__dict__)
|
|
105
|
+
return NotImplemented
|
|
106
|
+
|
|
107
|
+
def __ior__(self, other):
|
|
108
|
+
if isinstance(other, Record):
|
|
109
|
+
self.__dict__ |= other.__dict__
|
|
110
|
+
else:
|
|
111
|
+
self.__dict__ |= other
|
|
112
|
+
return self
|
|
113
|
+
|
|
114
|
+
def __copy__(self):
|
|
115
|
+
inst = self.__class__.__new__(self.__class__)
|
|
116
|
+
inst.__dict__ = self.__dict__.copy()
|
|
117
|
+
return inst
|
|
118
|
+
|
|
119
|
+
def copy(self):
|
|
120
|
+
if self.__class__ is Record:
|
|
121
|
+
return Record(self.__dict__.copy())
|
|
122
|
+
import copy
|
|
123
|
+
|
|
124
|
+
data = self.__dict__
|
|
125
|
+
try:
|
|
126
|
+
self.__dict__ = {}
|
|
127
|
+
c = copy.copy(self)
|
|
128
|
+
finally:
|
|
129
|
+
self.__dict__ = data
|
|
130
|
+
c.update(self)
|
|
131
|
+
return c
|
|
132
|
+
|
|
133
|
+
@_property
|
|
134
|
+
def len(self):
|
|
135
|
+
return len(self)
|
|
136
|
+
|
|
137
|
+
# Other
|
|
138
|
+
|
|
139
|
+
def __repr__(self):
|
|
140
|
+
return self._repr_with_visited(set())
|
|
141
|
+
|
|
142
|
+
def __hash__(self):
|
|
143
|
+
return hash(tuple(sorted(self.items())))
|
|
144
|
+
|
|
145
|
+
def __eq__(self, other):
|
|
146
|
+
if isinstance(other, Record):
|
|
147
|
+
return self.__dict__ == other.__dict__
|
|
148
|
+
|
|
149
|
+
if isinstance(other, dict):
|
|
150
|
+
return self.__dict__ == other
|
|
151
|
+
|
|
152
|
+
return NotImplemented
|
|
153
|
+
|
|
154
|
+
def _repr_with_visited(self, visited):
|
|
155
|
+
# Handle cycles by checking if this object is already being processed
|
|
156
|
+
obj_id = id(self)
|
|
157
|
+
if obj_id in visited:
|
|
158
|
+
return "{...}"
|
|
159
|
+
|
|
160
|
+
visited.add(obj_id)
|
|
161
|
+
try:
|
|
162
|
+
if not self:
|
|
163
|
+
return "{}"
|
|
164
|
+
|
|
165
|
+
items = []
|
|
166
|
+
for key, value in self.items():
|
|
167
|
+
key_str = self._format_key(key)
|
|
168
|
+
|
|
169
|
+
# Handle value representation with cycle detection
|
|
170
|
+
if isinstance(value, Record):
|
|
171
|
+
value_str = value._repr_with_visited(visited.copy())
|
|
172
|
+
elif hasattr(value, "__dict__") and hasattr(value, "__class__"):
|
|
173
|
+
# For other objects that might contain cycles, use a simple repr
|
|
174
|
+
value_str = repr(value)
|
|
175
|
+
else:
|
|
176
|
+
value_str = repr(value)
|
|
177
|
+
|
|
178
|
+
items.append(f"{key_str}: {value_str}")
|
|
179
|
+
|
|
180
|
+
return "{" + ", ".join(items) + "}"
|
|
181
|
+
finally:
|
|
182
|
+
visited.remove(obj_id)
|
|
183
|
+
|
|
184
|
+
def _format_key(self, key):
|
|
185
|
+
if isinstance(key, str):
|
|
186
|
+
if self._is_identifier(key):
|
|
187
|
+
# If key is an identifier, drop the quotes
|
|
188
|
+
return key
|
|
189
|
+
return f'"{key}"'
|
|
190
|
+
|
|
191
|
+
elif isinstance(key, (int, float, bool, type(None))):
|
|
192
|
+
# If key is a literal like 0, 1, True, False, None, use repr
|
|
193
|
+
return repr(key)
|
|
194
|
+
|
|
195
|
+
else:
|
|
196
|
+
# Otherwise, use f"({repr(key)})"
|
|
197
|
+
return f"({repr(key)})"
|
|
198
|
+
|
|
199
|
+
def _is_identifier(self, s):
|
|
200
|
+
return (
|
|
201
|
+
isinstance(s, str)
|
|
202
|
+
and re.match(r"^[a-zA-Z_][a-zA-Z0-9_]*$", s)
|
|
203
|
+
and s not in koatl_keywords
|
|
204
|
+
)
|
|
205
|
+
|
|
206
|
+
|
|
207
|
+
for key, value in MutableMapping.__dict__.items():
|
|
208
|
+
# copy over mixin methods from MutableMapping
|
|
209
|
+
if key.startswith("__"):
|
|
210
|
+
continue
|
|
211
|
+
|
|
212
|
+
if not inspect.isfunction(value):
|
|
213
|
+
continue
|
|
214
|
+
|
|
215
|
+
if hasattr(value, "__isabstractmethod__") and value.__isabstractmethod__:
|
|
216
|
+
continue
|
|
217
|
+
|
|
218
|
+
if key not in Record.__dict__:
|
|
219
|
+
setattr(Record, key, value)
|
|
220
|
+
|
|
221
|
+
koatl_keywords = {
|
|
222
|
+
"if",
|
|
223
|
+
"then",
|
|
224
|
+
"else",
|
|
225
|
+
"import",
|
|
226
|
+
"export",
|
|
227
|
+
"as",
|
|
228
|
+
"class",
|
|
229
|
+
"while",
|
|
230
|
+
"for",
|
|
231
|
+
"in",
|
|
232
|
+
"break",
|
|
233
|
+
"continue",
|
|
234
|
+
"with",
|
|
235
|
+
"yield",
|
|
236
|
+
"global",
|
|
237
|
+
"return",
|
|
238
|
+
"raise",
|
|
239
|
+
"try",
|
|
240
|
+
"except",
|
|
241
|
+
"finally",
|
|
242
|
+
"and",
|
|
243
|
+
"or",
|
|
244
|
+
"not",
|
|
245
|
+
"await",
|
|
246
|
+
"let",
|
|
247
|
+
"const",
|
|
248
|
+
"with",
|
|
249
|
+
}
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
from functools import partial
|
|
2
2
|
from itertools import count
|
|
3
|
-
from
|
|
4
|
-
from koatl._rs import fast_vget, fast_vset, fast_vset_trait
|
|
3
|
+
from koatl._rs import fast_vget
|
|
5
4
|
|
|
6
5
|
|
|
7
6
|
def vget(obj, name, ignore_traits=False):
|
|
@@ -66,38 +65,3 @@ def vhas(obj, name, ignore_traits=False):
|
|
|
66
65
|
return True
|
|
67
66
|
|
|
68
67
|
return False
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
def ext_prop(type, name):
|
|
72
|
-
def impl(value):
|
|
73
|
-
value._property = True
|
|
74
|
-
fast_vset(type, name, value)
|
|
75
|
-
return value
|
|
76
|
-
|
|
77
|
-
return impl
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
def ext_method(type, name):
|
|
81
|
-
def impl(value):
|
|
82
|
-
fast_vset(type, name, value)
|
|
83
|
-
return value
|
|
84
|
-
|
|
85
|
-
return impl
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
def ext_trait(type):
|
|
89
|
-
for name, value in type._own_methods.items():
|
|
90
|
-
fast_vset_trait(type.__name__, type._trait_reqs, name, value)
|
|
91
|
-
return type
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
Extension = SimpleNamespace(
|
|
95
|
-
property=ext_prop,
|
|
96
|
-
method=ext_method,
|
|
97
|
-
trait=ext_trait,
|
|
98
|
-
)
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
__all__ = [
|
|
102
|
-
"Extension",
|
|
103
|
-
]
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import functools.wraps
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
export do = f => wraps(f)& (*args, **kwargs) =>
|
|
5
|
+
let gen = f(*args, **kwargs)
|
|
6
|
+
|
|
7
|
+
let m
|
|
8
|
+
try:
|
|
9
|
+
m = gen.send(None)
|
|
10
|
+
except StopIteration() as e:
|
|
11
|
+
raise ValueError(
|
|
12
|
+
"Returning before `@` is not allowed. "
|
|
13
|
+
"Use `return @MonadType.pure(value)` instead."
|
|
14
|
+
)
|
|
15
|
+
|
|
16
|
+
try:
|
|
17
|
+
# TODO: this is a workaround to avoid recursion.
|
|
18
|
+
# is it possible to derive bind_gen directly from bind_once?
|
|
19
|
+
|
|
20
|
+
return m.bind_gen(gen)
|
|
21
|
+
except AttributeError():
|
|
22
|
+
None
|
|
23
|
+
|
|
24
|
+
let recurse = v =>
|
|
25
|
+
try:
|
|
26
|
+
m = gen.send(v)
|
|
27
|
+
return m.bind_once(recurse)
|
|
28
|
+
except StopIteration() as e:
|
|
29
|
+
return m.pure(e.value)
|
|
30
|
+
|
|
31
|
+
try:
|
|
32
|
+
return m.bind_once(recurse)
|
|
33
|
+
except AttributeError():
|
|
34
|
+
raise ValueError("@ can only be used with an object that has `bind_once`.")
|
|
@@ -7,6 +7,22 @@ infer_ok = x =>
|
|
|
7
7
|
BaseException() => False
|
|
8
8
|
default True
|
|
9
9
|
|
|
10
|
+
op_coal = (x, f) =>
|
|
11
|
+
if x matches Result():
|
|
12
|
+
return x.coalesce(f)
|
|
13
|
+
|
|
14
|
+
if not infer_ok(x):
|
|
15
|
+
return f()
|
|
16
|
+
return x
|
|
17
|
+
|
|
18
|
+
op_map = (x, f) =>
|
|
19
|
+
if x matches Result():
|
|
20
|
+
return x.map(f)
|
|
21
|
+
|
|
22
|
+
if infer_ok(x):
|
|
23
|
+
return f(x)
|
|
24
|
+
return x
|
|
25
|
+
|
|
10
26
|
export Result = class(MonadOnce):
|
|
11
27
|
__slots__ = ()
|
|
12
28
|
__match_args__ = ("value",)
|
|
@@ -158,4 +174,4 @@ export Err = class(Result):
|
|
|
158
174
|
if self.value matches BaseException():
|
|
159
175
|
raise self.value
|
|
160
176
|
raise ValueError(f"Expected Ok, got {repr(self)}")
|
|
161
|
-
coalesce = (self, f) => f()
|
|
177
|
+
coalesce = (self, f) => f()
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import koatl._rs.(fast_vset, fast_vset_trait)
|
|
2
|
+
|
|
3
|
+
ext_prop = (type, name) => value =>
|
|
4
|
+
value::_property = True
|
|
5
|
+
fast_vset(type, name, value)
|
|
6
|
+
value
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
ext_method = (type, name) => value =>
|
|
10
|
+
fast_vset(type, name, value)
|
|
11
|
+
value
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
ext_trait = type =>
|
|
15
|
+
for name, value in type::_own_methods:
|
|
16
|
+
fast_vset_trait(type::__name__, type::_trait_reqs, name, value)
|
|
17
|
+
type
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
export Extension = {
|
|
21
|
+
property: ext_prop,
|
|
22
|
+
method: ext_method,
|
|
23
|
+
trait: ext_trait,
|
|
24
|
+
}
|
|
@@ -3,14 +3,14 @@ import collections
|
|
|
3
3
|
|
|
4
4
|
export LazyModule = class:
|
|
5
5
|
__init__ = (self, name) =>
|
|
6
|
-
self._name = name
|
|
7
|
-
self._module = None
|
|
8
|
-
self._submodules = {}
|
|
6
|
+
self.__dict__["_name"] = name
|
|
7
|
+
self.__dict__["_module"] = None
|
|
8
|
+
self.__dict__["_submodules"] = {}
|
|
9
9
|
|
|
10
10
|
__getattr__ = (self, attr) =>
|
|
11
11
|
try:
|
|
12
12
|
if self._module === None:
|
|
13
|
-
self._module = importlib.import_module(self._name)
|
|
13
|
+
self.__dict__["_module"] = importlib.import_module(self._name)
|
|
14
14
|
|
|
15
15
|
if hasattr(self._module, "__path__"):
|
|
16
16
|
if attr not in self._submodules:
|
|
@@ -30,4 +30,22 @@ export LazyModule = class:
|
|
|
30
30
|
|
|
31
31
|
raise AttributeError(f"Module '{self._name}' has no attribute '{attr}'")
|
|
32
32
|
|
|
33
|
-
|
|
33
|
+
__setattr__ = (self, attr, value) =>
|
|
34
|
+
if self._module === None:
|
|
35
|
+
self.__dict__["_module"] = importlib.import_module(self._name)
|
|
36
|
+
|
|
37
|
+
setattr(self._module, attr, value)
|
|
38
|
+
|
|
39
|
+
__repr__ = self => f"LazyModule({self._name})"
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
export RootModulesProxy = class:
|
|
43
|
+
__init__ = (self) =>
|
|
44
|
+
self._modules = {}
|
|
45
|
+
|
|
46
|
+
__getattr__ = (self, attr) =>
|
|
47
|
+
if attr not in self._modules:
|
|
48
|
+
self._modules[attr] = LazyModule(attr)
|
|
49
|
+
return self._modules[attr]
|
|
50
|
+
|
|
51
|
+
__repr__ = self => f"RootModulesProxy({self._modules})"
|
|
@@ -2,7 +2,7 @@ import abc
|
|
|
2
2
|
import collections
|
|
3
3
|
import inspect
|
|
4
4
|
|
|
5
|
-
from koatl.
|
|
5
|
+
from koatl.prelude import __tl__
|
|
6
6
|
|
|
7
7
|
|
|
8
8
|
@collections.abc.Mapping.register
|
|
@@ -90,7 +90,7 @@ class TraitMeta(MappingMeta):
|
|
|
90
90
|
# Check if the exact class has _trait_reqs, in which case it's a trait.
|
|
91
91
|
if "_trait_reqs" in cls.__dict__:
|
|
92
92
|
for req in cls._trait_reqs:
|
|
93
|
-
if not vhas(instance, req):
|
|
93
|
+
if not __tl__.vhas(instance, req):
|
|
94
94
|
return False
|
|
95
95
|
|
|
96
96
|
return True
|
|
@@ -118,8 +118,9 @@ fn fast_vget<'py, 'ptr>(
|
|
|
118
118
|
let vtbl2 = VTBL2.lock().unwrap();
|
|
119
119
|
|
|
120
120
|
if let Some(traits) = vtbl2.get(&name) {
|
|
121
|
-
let
|
|
122
|
-
let
|
|
121
|
+
let runtime = py.import("koatl.runtime")?;
|
|
122
|
+
let tl = runtime.getattr("__tl__")?;
|
|
123
|
+
let vget = tl.getattr("vget")?;
|
|
123
124
|
|
|
124
125
|
for t in traits {
|
|
125
126
|
let mut ok = true;
|
|
@@ -179,14 +180,23 @@ fn fast_vset_trait<'py, 'ptr>(
|
|
|
179
180
|
}
|
|
180
181
|
|
|
181
182
|
// TODO: what about conflicting traits?
|
|
182
|
-
vtbl.get_mut(&name).unwrap()
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
183
|
+
let vtbl_entry = vtbl.get_mut(&name).unwrap();
|
|
184
|
+
if let Some(existing) = vtbl_entry
|
|
185
|
+
.iter_mut()
|
|
186
|
+
.find(|e| e.name == trait_name.to_string())
|
|
187
|
+
{
|
|
188
|
+
existing.requirements = reqs;
|
|
189
|
+
existing.value = value.clone().unbind();
|
|
190
|
+
} else {
|
|
191
|
+
vtbl_entry.insert(
|
|
192
|
+
0,
|
|
193
|
+
TraitAttr {
|
|
194
|
+
name: trait_name.to_string(),
|
|
195
|
+
requirements: reqs,
|
|
196
|
+
value: value.clone().unbind(),
|
|
197
|
+
},
|
|
198
|
+
);
|
|
199
|
+
}
|
|
190
200
|
|
|
191
201
|
Ok(())
|
|
192
202
|
}
|
|
@@ -2,7 +2,10 @@ import util.assert_eq
|
|
|
2
2
|
|
|
3
3
|
assert_eq(type([1, 2, 3]), list)
|
|
4
4
|
assert_eq(type((1, 2, 3)), tuple)
|
|
5
|
-
|
|
5
|
+
|
|
6
|
+
# Record type is not directly made available by the runtime.
|
|
7
|
+
assert_eq(type({1: 2}).__name__, "Record")
|
|
8
|
+
|
|
6
9
|
assert_eq(type(()), tuple)
|
|
7
10
|
assert_eq(type((1,)), tuple)
|
|
8
11
|
assert_eq(type(1), int)
|
|
@@ -132,7 +132,6 @@ pub fn py_escape_str(s: &str) -> String {
|
|
|
132
132
|
}
|
|
133
133
|
|
|
134
134
|
pub fn py_escape_fstr(s: &str) -> String {
|
|
135
|
-
// TODO
|
|
136
135
|
py_escape_str(s)
|
|
137
136
|
.chars()
|
|
138
137
|
.map(|c| match c {
|
|
@@ -143,30 +142,6 @@ pub fn py_escape_fstr(s: &str) -> String {
|
|
|
143
142
|
.collect()
|
|
144
143
|
}
|
|
145
144
|
|
|
146
|
-
pub fn escape_str(s: &str) -> String {
|
|
147
|
-
// TODO
|
|
148
|
-
s.chars()
|
|
149
|
-
.map(|c| match c {
|
|
150
|
-
'\n' => "\\n".to_string(),
|
|
151
|
-
'"' => "\\\"".to_string(),
|
|
152
|
-
_ => c.to_string(),
|
|
153
|
-
})
|
|
154
|
-
.collect()
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
pub fn escape_fstr(s: &str) -> String {
|
|
158
|
-
// TODO
|
|
159
|
-
s.chars()
|
|
160
|
-
.map(|c| match c {
|
|
161
|
-
'{' => "{{".to_string(),
|
|
162
|
-
'}' => "}}".to_string(),
|
|
163
|
-
'\n' => "\\n".to_string(),
|
|
164
|
-
'"' => "\\\"".to_string(),
|
|
165
|
-
_ => c.to_string(),
|
|
166
|
-
})
|
|
167
|
-
.collect()
|
|
168
|
-
}
|
|
169
|
-
|
|
170
145
|
// TODO don't duplicate this with parser below
|
|
171
146
|
pub fn is_valid_ident(s: &str) -> bool {
|
|
172
147
|
if s.is_empty() {
|
|
@@ -661,9 +636,11 @@ where
|
|
|
661
636
|
current_str = String::new();
|
|
662
637
|
|
|
663
638
|
self.parse_nonsemantic()?;
|
|
664
|
-
|
|
639
|
+
while self.try_parse(TokenizeCtx::parse_empty_line).is_ok() {}
|
|
640
|
+
|
|
665
641
|
let sexpr = self.try_parse(|x| x.parse_block(0, NewBlockType::BeginInput))?;
|
|
666
|
-
|
|
642
|
+
|
|
643
|
+
while self.try_parse(TokenizeCtx::parse_empty_line).is_ok() {}
|
|
667
644
|
|
|
668
645
|
self.parse_indentation()?;
|
|
669
646
|
|
|
@@ -851,7 +828,6 @@ where
|
|
|
851
828
|
) -> TResult<'src, Spanned<TokenList<'src>>> {
|
|
852
829
|
let mut tokens = vec![];
|
|
853
830
|
|
|
854
|
-
// TODO should parse_empty_line be part of parse_indentation?
|
|
855
831
|
while self.try_parse(TokenizeCtx::parse_empty_line).is_ok() {}
|
|
856
832
|
|
|
857
833
|
let indent_level = self.try_parse(|x| x.parse_indentation()).map_err(|_| {
|