koatl 0.1.37__tar.gz → 0.1.39__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.
Files changed (139) hide show
  1. {koatl-0.1.37 → koatl-0.1.39}/Cargo.lock +1 -1
  2. {koatl-0.1.37 → koatl-0.1.39}/PKG-INFO +1 -1
  3. {koatl-0.1.37 → koatl-0.1.39}/koatl/Cargo.toml +1 -1
  4. koatl-0.1.39/koatl/python/koatl/prelude/__init__.tl +40 -0
  5. koatl-0.1.39/koatl/python/koatl/runtime/__init__.py +47 -0
  6. koatl-0.1.39/koatl/python/koatl/runtime/record.py +252 -0
  7. koatl-0.1.37/koatl/python/koatl/runtime/virtual.py → koatl-0.1.39/koatl/python/koatl/runtime/vattr.py +1 -37
  8. {koatl-0.1.37 → koatl-0.1.39/koatl}/python/koatl/std/alg/base.tl +2 -0
  9. koatl-0.1.39/koatl/python/koatl/std/alg/do.tl +34 -0
  10. {koatl-0.1.37 → koatl-0.1.39/koatl}/python/koatl/std/alg/result.tl +17 -1
  11. koatl-0.1.39/koatl/python/koatl/std/data/__init__.tl +2 -0
  12. koatl-0.1.39/koatl/python/koatl/std/data/record.tl +5 -0
  13. koatl-0.1.39/koatl/python/koatl/std/ext.tl +24 -0
  14. {koatl-0.1.37 → koatl-0.1.39/koatl}/python/koatl/std/iter.tl +2 -1
  15. {koatl-0.1.37 → koatl-0.1.39}/koatl/python/koatl/std/lazy_module.tl +13 -1
  16. koatl-0.1.37/koatl/python/koatl/runtime/classes.py → koatl-0.1.39/koatl/python/koatl/std/trait.py +3 -3
  17. {koatl-0.1.37 → koatl-0.1.39}/koatl/src/lib.rs +3 -2
  18. {koatl-0.1.37 → koatl-0.1.39}/koatl/tests/e2e/base/containers.tl +4 -1
  19. {koatl-0.1.37 → koatl-0.1.39}/koatl-core/parser/src/lexer.rs +180 -122
  20. {koatl-0.1.37 → koatl-0.1.39}/koatl-core/parser/src/parser.rs +0 -1
  21. {koatl-0.1.37 → koatl-0.1.39}/koatl-core/src/py/emit.rs +3 -1
  22. {koatl-0.1.37 → koatl-0.1.39}/koatl-core/src/resolve_scopes.rs +5 -3
  23. {koatl-0.1.37 → koatl-0.1.39}/koatl-core/src/transform.rs +9 -2
  24. koatl-0.1.39/python/koatl/prelude/__init__.tl +40 -0
  25. koatl-0.1.39/python/koatl/runtime/__init__.py +47 -0
  26. koatl-0.1.39/python/koatl/runtime/record.py +252 -0
  27. koatl-0.1.37/python/koatl/runtime/virtual.py → koatl-0.1.39/python/koatl/runtime/vattr.py +1 -37
  28. {koatl-0.1.37/koatl → koatl-0.1.39}/python/koatl/std/alg/base.tl +2 -0
  29. koatl-0.1.39/python/koatl/std/alg/do.tl +34 -0
  30. {koatl-0.1.37/koatl → koatl-0.1.39}/python/koatl/std/alg/result.tl +17 -1
  31. koatl-0.1.39/python/koatl/std/data/__init__.tl +2 -0
  32. koatl-0.1.39/python/koatl/std/data/record.tl +5 -0
  33. koatl-0.1.39/python/koatl/std/ext.tl +24 -0
  34. {koatl-0.1.37/koatl → koatl-0.1.39}/python/koatl/std/iter.tl +2 -1
  35. {koatl-0.1.37 → koatl-0.1.39}/python/koatl/std/lazy_module.tl +13 -1
  36. koatl-0.1.37/python/koatl/runtime/classes.py → koatl-0.1.39/python/koatl/std/trait.py +3 -3
  37. koatl-0.1.37/koatl/python/koatl/prelude/__init__.tl +0 -60
  38. koatl-0.1.37/koatl/python/koatl/runtime/__init__.py +0 -65
  39. koatl-0.1.37/koatl/python/koatl/runtime/helpers.py +0 -71
  40. koatl-0.1.37/koatl/python/koatl/runtime/record.py +0 -116
  41. koatl-0.1.37/koatl/python/koatl/std/data/__init__.tl +0 -1
  42. koatl-0.1.37/python/koatl/prelude/__init__.tl +0 -60
  43. koatl-0.1.37/python/koatl/runtime/__init__.py +0 -65
  44. koatl-0.1.37/python/koatl/runtime/helpers.py +0 -71
  45. koatl-0.1.37/python/koatl/runtime/record.py +0 -116
  46. koatl-0.1.37/python/koatl/std/data/__init__.tl +0 -1
  47. {koatl-0.1.37 → koatl-0.1.39}/Cargo.toml +0 -0
  48. {koatl-0.1.37 → koatl-0.1.39}/README.md +0 -0
  49. {koatl-0.1.37 → koatl-0.1.39}/koatl/.github/workflows/CI.yml +0 -0
  50. {koatl-0.1.37 → koatl-0.1.39}/koatl/.gitignore +0 -0
  51. {koatl-0.1.37 → koatl-0.1.39}/koatl/LICENSE +0 -0
  52. {koatl-0.1.37 → koatl-0.1.39}/koatl/README.md +0 -0
  53. {koatl-0.1.37 → koatl-0.1.39}/koatl/python/koatl/__init__.py +0 -0
  54. {koatl-0.1.37 → koatl-0.1.39}/koatl/python/koatl/__main__.py +0 -0
  55. {koatl-0.1.37 → koatl-0.1.39}/koatl/python/koatl/cli.py +0 -0
  56. {koatl-0.1.37 → koatl-0.1.39}/koatl/python/koatl/notebook/__init__.py +0 -0
  57. {koatl-0.1.37 → koatl-0.1.39}/koatl/python/koatl/notebook/magic.py +0 -0
  58. {koatl-0.1.37 → koatl-0.1.39}/koatl/python/koatl/runtime/meta_finder.py +0 -0
  59. {koatl-0.1.37 → koatl-0.1.39}/koatl/python/koatl/std/alg/__init__.tl +0 -0
  60. {koatl-0.1.37 → koatl-0.1.39}/koatl/python/koatl/std/alg/async.tl +0 -0
  61. {koatl-0.1.37 → koatl-0.1.39}/koatl/python/koatl/std/alg/env.tl +0 -0
  62. {koatl-0.1.37 → koatl-0.1.39}/koatl/python/koatl/std/alg/memo.tl +0 -0
  63. {koatl-0.1.37 → koatl-0.1.39}/koatl/python/koatl/std/data/list.tl +0 -0
  64. {koatl-0.1.37 → koatl-0.1.39}/koatl/python/koatl/std/io.tl +0 -0
  65. {koatl-0.1.37 → koatl-0.1.39}/koatl/python/koatl/std/re.tl +0 -0
  66. {koatl-0.1.37 → koatl-0.1.39}/koatl/requirements.txt +0 -0
  67. {koatl-0.1.37 → koatl-0.1.39}/koatl/src/emit_py.rs +0 -0
  68. {koatl-0.1.37 → koatl-0.1.39}/koatl/tests/e2e/base/data.txt +0 -0
  69. {koatl-0.1.37 → koatl-0.1.39}/koatl/tests/e2e/base/decorators.tl +0 -0
  70. {koatl-0.1.37 → koatl-0.1.39}/koatl/tests/e2e/base/destructure-for-and-fn.tl +0 -0
  71. {koatl-0.1.37 → koatl-0.1.39}/koatl/tests/e2e/base/destructure.tl +0 -0
  72. {koatl-0.1.37 → koatl-0.1.39}/koatl/tests/e2e/base/escape_ident.tl +0 -0
  73. {koatl-0.1.37 → koatl-0.1.39}/koatl/tests/e2e/base/fstr.tl +0 -0
  74. {koatl-0.1.37 → koatl-0.1.39}/koatl/tests/e2e/base/functions.tl +0 -0
  75. {koatl-0.1.37 → koatl-0.1.39}/koatl/tests/e2e/base/generator.tl +0 -0
  76. {koatl-0.1.37 → koatl-0.1.39}/koatl/tests/e2e/base/if_expr.tl +0 -0
  77. {koatl-0.1.37 → koatl-0.1.39}/koatl/tests/e2e/base/loops.tl +0 -0
  78. {koatl-0.1.37 → koatl-0.1.39}/koatl/tests/e2e/base/match.tl +0 -0
  79. {koatl-0.1.37 → koatl-0.1.39}/koatl/tests/e2e/base/nary-list.tl +0 -0
  80. {koatl-0.1.37 → koatl-0.1.39}/koatl/tests/e2e/base/placeholder.tl +0 -0
  81. {koatl-0.1.37 → koatl-0.1.39}/koatl/tests/e2e/base/precedence.tl +0 -0
  82. {koatl-0.1.37 → koatl-0.1.39}/koatl/tests/e2e/base/scopes.tl +0 -0
  83. {koatl-0.1.37 → koatl-0.1.39}/koatl/tests/e2e/base/semantic_whitespace.tl +0 -0
  84. {koatl-0.1.37 → koatl-0.1.39}/koatl/tests/e2e/base/short_circuit.tl +0 -0
  85. {koatl-0.1.37 → koatl-0.1.39}/koatl/tests/e2e/base/with.tl +0 -0
  86. {koatl-0.1.37 → koatl-0.1.39}/koatl/tests/e2e/prelude/async.tl +0 -0
  87. {koatl-0.1.37 → koatl-0.1.39}/koatl/tests/e2e/prelude/aug_assign.tl +0 -0
  88. {koatl-0.1.37/koatl/tests/e2e/base → koatl-0.1.39/koatl/tests/e2e/prelude}/coal.tl +0 -0
  89. {koatl-0.1.37 → koatl-0.1.39}/koatl/tests/e2e/prelude/env.tl +0 -0
  90. {koatl-0.1.37/koatl/tests/e2e/base → koatl-0.1.39/koatl/tests/e2e/prelude}/imports.tl +0 -0
  91. {koatl-0.1.37 → koatl-0.1.39}/koatl/tests/e2e/prelude/iterables.tl +0 -0
  92. {koatl-0.1.37 → koatl-0.1.39}/koatl/tests/e2e/prelude/list.tl +0 -0
  93. {koatl-0.1.37 → koatl-0.1.39}/koatl/tests/e2e/prelude/memo.tl +0 -0
  94. {koatl-0.1.37/koatl/tests/e2e/base → koatl-0.1.39/koatl/tests/e2e/prelude}/record.tl +0 -0
  95. {koatl-0.1.37 → koatl-0.1.39}/koatl/tests/e2e/prelude/result.tl +0 -0
  96. {koatl-0.1.37 → koatl-0.1.39}/koatl/tests/e2e/prelude/slice.tl +0 -0
  97. {koatl-0.1.37 → koatl-0.1.39}/koatl/tests/e2e/prelude/try.tl +0 -0
  98. {koatl-0.1.37 → koatl-0.1.39}/koatl/tests/e2e/prelude/virtual.tl +0 -0
  99. {koatl-0.1.37 → koatl-0.1.39}/koatl/tests/e2e/util/__init__.py +0 -0
  100. {koatl-0.1.37 → koatl-0.1.39}/koatl/tests/e2e/util/module0.tl +0 -0
  101. {koatl-0.1.37 → koatl-0.1.39}/koatl/tests/e2e/util/module1.tl +0 -0
  102. {koatl-0.1.37 → koatl-0.1.39}/koatl/tests/e2e/util/module2.tl +0 -0
  103. {koatl-0.1.37 → koatl-0.1.39}/koatl/tests/parse/arith.tl +0 -0
  104. {koatl-0.1.37 → koatl-0.1.39}/koatl/tests/parse/assign.tl +0 -0
  105. {koatl-0.1.37 → koatl-0.1.39}/koatl/tests/parse/block-comments.tl +0 -0
  106. {koatl-0.1.37 → koatl-0.1.39}/koatl/tests/parse/deco.tl +0 -0
  107. {koatl-0.1.37 → koatl-0.1.39}/koatl/tests/parse/func.tl +0 -0
  108. {koatl-0.1.37 → koatl-0.1.39}/koatl/tests/parse/matches.tl +0 -0
  109. {koatl-0.1.37 → koatl-0.1.39}/koatl/tests/test_e2e.py +0 -0
  110. {koatl-0.1.37 → koatl-0.1.39}/koatl/tests/test_parse.py +0 -0
  111. {koatl-0.1.37 → koatl-0.1.39}/koatl-core/Cargo.toml +0 -0
  112. {koatl-0.1.37 → koatl-0.1.39}/koatl-core/parser/Cargo.toml +0 -0
  113. {koatl-0.1.37 → koatl-0.1.39}/koatl-core/parser/src/ast.rs +0 -0
  114. {koatl-0.1.37 → koatl-0.1.39}/koatl-core/parser/src/lib.rs +0 -0
  115. {koatl-0.1.37 → koatl-0.1.39}/koatl-core/parser/src/util.rs +0 -0
  116. {koatl-0.1.37 → koatl-0.1.39}/koatl-core/src/inference.rs +0 -0
  117. {koatl-0.1.37 → koatl-0.1.39}/koatl-core/src/lib.rs +0 -0
  118. {koatl-0.1.37 → koatl-0.1.39}/koatl-core/src/main.rs +0 -0
  119. {koatl-0.1.37 → koatl-0.1.39}/koatl-core/src/parse_timer.rs +0 -0
  120. {koatl-0.1.37 → koatl-0.1.39}/koatl-core/src/parser.rs +0 -0
  121. {koatl-0.1.37 → koatl-0.1.39}/koatl-core/src/py/ast.rs +0 -0
  122. {koatl-0.1.37 → koatl-0.1.39}/koatl-core/src/py/mod.rs +0 -0
  123. {koatl-0.1.37 → koatl-0.1.39}/koatl-core/src/py/util.rs +0 -0
  124. {koatl-0.1.37 → koatl-0.1.39}/koatl-core/src/types.rs +0 -0
  125. {koatl-0.1.37 → koatl-0.1.39}/koatl-core/src/util.rs +0 -0
  126. {koatl-0.1.37 → koatl-0.1.39}/pyproject.toml +0 -0
  127. {koatl-0.1.37 → koatl-0.1.39}/python/koatl/__init__.py +0 -0
  128. {koatl-0.1.37 → koatl-0.1.39}/python/koatl/__main__.py +0 -0
  129. {koatl-0.1.37 → koatl-0.1.39}/python/koatl/cli.py +0 -0
  130. {koatl-0.1.37 → koatl-0.1.39}/python/koatl/notebook/__init__.py +0 -0
  131. {koatl-0.1.37 → koatl-0.1.39}/python/koatl/notebook/magic.py +0 -0
  132. {koatl-0.1.37 → koatl-0.1.39}/python/koatl/runtime/meta_finder.py +0 -0
  133. {koatl-0.1.37 → koatl-0.1.39}/python/koatl/std/alg/__init__.tl +0 -0
  134. {koatl-0.1.37 → koatl-0.1.39}/python/koatl/std/alg/async.tl +0 -0
  135. {koatl-0.1.37 → koatl-0.1.39}/python/koatl/std/alg/env.tl +0 -0
  136. {koatl-0.1.37 → koatl-0.1.39}/python/koatl/std/alg/memo.tl +0 -0
  137. {koatl-0.1.37 → koatl-0.1.39}/python/koatl/std/data/list.tl +0 -0
  138. {koatl-0.1.37 → koatl-0.1.39}/python/koatl/std/io.tl +0 -0
  139. {koatl-0.1.37 → koatl-0.1.39}/python/koatl/std/re.tl +0 -0
@@ -99,7 +99,7 @@ checksum = "f4c7245a08504955605670dbf141fceab975f15ca21570696aebe9d2e71576bd"
99
99
 
100
100
  [[package]]
101
101
  name = "koatl"
102
- version = "0.1.37"
102
+ version = "0.1.39"
103
103
  dependencies = [
104
104
  "ariadne",
105
105
  "koatl-core",
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: koatl
3
- Version: 0.1.37
3
+ Version: 0.1.39
4
4
  Classifier: Programming Language :: Rust
5
5
  Classifier: Programming Language :: Python :: Implementation :: CPython
6
6
  Classifier: Programming Language :: Python :: Implementation :: PyPy
@@ -1,6 +1,6 @@
1
1
  [package]
2
2
  name = "koatl"
3
- version = "0.1.37"
3
+ version = "0.1.39"
4
4
  edition = "2021"
5
5
 
6
6
  [lib]
@@ -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,252 @@
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
+ if not isinstance(dict_obj, dict):
23
+ raise TypeError("Expected a dictionary")
24
+
25
+ self = cls.__new__(cls)
26
+ self.__dict__ = dict_obj
27
+ return self
28
+
29
+ @staticmethod
30
+ def method(fn):
31
+ fn._method = True
32
+ return fn
33
+
34
+ @staticmethod
35
+ def property(fn):
36
+ fn._property = True
37
+ return fn
38
+
39
+ def __getattribute__(self, name):
40
+ dict = object.__getattribute__(self, "__dict__")
41
+
42
+ try:
43
+ attr = dict[name]
44
+
45
+ if hasattr(attr, "_property"):
46
+ return attr(self)
47
+ elif hasattr(attr, "_method"):
48
+ return functools.partial(attr, self)
49
+ except KeyError:
50
+ pass
51
+
52
+ return object.__getattribute__(self, name)
53
+
54
+ @_property
55
+ def iter(self):
56
+ return self.items()
57
+
58
+ # MutableMapping
59
+ def __len__(self):
60
+ return len(self.__dict__)
61
+
62
+ def __getitem__(self, key):
63
+ try:
64
+ return self.__dict__[key]
65
+ except KeyError as e:
66
+ raise e
67
+
68
+ def __setitem__(self, key, item):
69
+ self.__dict__[key] = item
70
+
71
+ def __delitem__(self, key):
72
+ del self.__dict__[key]
73
+
74
+ def __iter__(self):
75
+ return iter(self.__dict__)
76
+
77
+ def __contains__(self, key):
78
+ return key in self.__dict__
79
+
80
+ def get(self, key, default=None):
81
+ return self.__dict__.get(key, default)
82
+
83
+ def items(self):
84
+ return self.__dict__.items()
85
+
86
+ def keys(self):
87
+ return self.__dict__.keys()
88
+
89
+ def values(self):
90
+ return self.__dict__.values()
91
+
92
+ # dict
93
+ def __repr__(self):
94
+ return repr(self.__dict__)
95
+
96
+ def __or__(self, other):
97
+ if isinstance(other, Record):
98
+ return self.__class__(self.__dict__ | other.__dict__)
99
+ if isinstance(other, dict):
100
+ return self.__class__(self.__dict__ | other)
101
+ return NotImplemented
102
+
103
+ def __ror__(self, other):
104
+ if isinstance(other, Record):
105
+ return self.__class__(other.__dict__ | self.__dict__)
106
+ if isinstance(other, dict):
107
+ return self.__class__(other | self.__dict__)
108
+ return NotImplemented
109
+
110
+ def __ior__(self, other):
111
+ if isinstance(other, Record):
112
+ self.__dict__ |= other.__dict__
113
+ else:
114
+ self.__dict__ |= other
115
+ return self
116
+
117
+ def __copy__(self):
118
+ inst = self.__class__.__new__(self.__class__)
119
+ inst.__dict__ = self.__dict__.copy()
120
+ return inst
121
+
122
+ def copy(self):
123
+ if self.__class__ is Record:
124
+ return Record(self.__dict__.copy())
125
+ import copy
126
+
127
+ data = self.__dict__
128
+ try:
129
+ self.__dict__ = {}
130
+ c = copy.copy(self)
131
+ finally:
132
+ self.__dict__ = data
133
+ c.update(self)
134
+ return c
135
+
136
+ @_property
137
+ def len(self):
138
+ return len(self)
139
+
140
+ # Other
141
+
142
+ def __repr__(self):
143
+ return self._repr_with_visited(set())
144
+
145
+ def __hash__(self):
146
+ return hash(tuple(sorted(self.items())))
147
+
148
+ def __eq__(self, other):
149
+ if isinstance(other, Record):
150
+ return self.__dict__ == other.__dict__
151
+
152
+ if isinstance(other, dict):
153
+ return self.__dict__ == other
154
+
155
+ return NotImplemented
156
+
157
+ def _repr_with_visited(self, visited):
158
+ # Handle cycles by checking if this object is already being processed
159
+ obj_id = id(self)
160
+ if obj_id in visited:
161
+ return "{...}"
162
+
163
+ visited.add(obj_id)
164
+ try:
165
+ if not self:
166
+ return "{}"
167
+
168
+ items = []
169
+ for key, value in self.items():
170
+ key_str = self._format_key(key)
171
+
172
+ # Handle value representation with cycle detection
173
+ if isinstance(value, Record):
174
+ value_str = value._repr_with_visited(visited.copy())
175
+ elif hasattr(value, "__dict__") and hasattr(value, "__class__"):
176
+ # For other objects that might contain cycles, use a simple repr
177
+ value_str = repr(value)
178
+ else:
179
+ value_str = repr(value)
180
+
181
+ items.append(f"{key_str}: {value_str}")
182
+
183
+ return "{" + ", ".join(items) + "}"
184
+ finally:
185
+ visited.remove(obj_id)
186
+
187
+ def _format_key(self, key):
188
+ if isinstance(key, str):
189
+ if self._is_identifier(key):
190
+ # If key is an identifier, drop the quotes
191
+ return key
192
+ return f'"{key}"'
193
+
194
+ elif isinstance(key, (int, float, bool, type(None))):
195
+ # If key is a literal like 0, 1, True, False, None, use repr
196
+ return repr(key)
197
+
198
+ else:
199
+ # Otherwise, use f"({repr(key)})"
200
+ return f"({repr(key)})"
201
+
202
+ def _is_identifier(self, s):
203
+ return (
204
+ isinstance(s, str)
205
+ and re.match(r"^[a-zA-Z_][a-zA-Z0-9_]*$", s)
206
+ and s not in koatl_keywords
207
+ )
208
+
209
+
210
+ for key, value in MutableMapping.__dict__.items():
211
+ # copy over mixin methods from MutableMapping
212
+ if key.startswith("__"):
213
+ continue
214
+
215
+ if not inspect.isfunction(value):
216
+ continue
217
+
218
+ if hasattr(value, "__isabstractmethod__") and value.__isabstractmethod__:
219
+ continue
220
+
221
+ if key not in Record.__dict__:
222
+ setattr(Record, key, value)
223
+
224
+ koatl_keywords = {
225
+ "if",
226
+ "then",
227
+ "else",
228
+ "import",
229
+ "export",
230
+ "as",
231
+ "class",
232
+ "while",
233
+ "for",
234
+ "in",
235
+ "break",
236
+ "continue",
237
+ "with",
238
+ "yield",
239
+ "global",
240
+ "return",
241
+ "raise",
242
+ "try",
243
+ "except",
244
+ "finally",
245
+ "and",
246
+ "or",
247
+ "not",
248
+ "await",
249
+ "let",
250
+ "const",
251
+ "with",
252
+ }
@@ -1,7 +1,6 @@
1
1
  from functools import partial
2
2
  from itertools import count
3
- from types import SimpleNamespace
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
- ]
@@ -1,3 +1,5 @@
1
+ import koatl.std.trait.Trait
2
+
1
3
  export Monad = class(Trait):
2
4
  """
3
5
  Abstract base class for monads.
@@ -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,2 @@
1
+ export import .list.List
2
+ export import .record.Record
@@ -0,0 +1,5 @@
1
+ import koatl.runtime
2
+
3
+ # TODO: should we just move this to this module?
4
+
5
+ export Record = runtime.record.Record
@@ -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
+ }
@@ -1,7 +1,8 @@
1
1
  import itertools
2
2
  import builtins
3
- import .alg.(Traversable, Ok, Err, Memo, Async, AsyncMemo, Result)
4
3
 
4
+ import koatl.std.trait.Trait
5
+ import .alg.(Traversable, Ok, Err, Memo, Async, AsyncMemo, Result)
5
6
 
6
7
  export Iterable = class(Traversable, Trait):
7
8
  iter = Trait.abstract& self => None
@@ -30,4 +30,16 @@ export LazyModule = class:
30
30
 
31
31
  raise AttributeError(f"Module '{self._name}' has no attribute '{attr}'")
32
32
 
33
- __repr__ = self => f"LazyModule({self._name})"
33
+ __repr__ = self => f"LazyModule({self._name})"
34
+
35
+
36
+ export RootModulesProxy = class:
37
+ __init__ = (self) =>
38
+ self._modules = {}
39
+
40
+ __getattr__ = (self, attr) =>
41
+ if attr not in self._modules:
42
+ self._modules[attr] = LazyModule(attr)
43
+ return self._modules[attr]
44
+
45
+ __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.runtime.virtual import vhas
5
+ from koatl.prelude import __tl__
6
6
 
7
7
 
8
8
  @collections.abc.Mapping.register
@@ -40,7 +40,7 @@ class MappingMeta(type):
40
40
  return [(k, v) for k, v in inspect.getmembers(self) if not k.startswith("_")]
41
41
 
42
42
 
43
- # A utility base class to inherit from to enable __getitem__ method lookup on types and thus destructuring.
43
+ # A utility base class to inherit from that implements Mapping on the type and thus destructuring.
44
44
  class Class(metaclass=MappingMeta):
45
45
  pass
46
46
 
@@ -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 tlmod = py.import("koatl.runtime.virtual")?;
122
- let vget = tlmod.getattr("vget")?;
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;
@@ -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
- assert_eq(type({1: 2}), Record)
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)