koatl 0.1.27__tar.gz → 0.1.28__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.27 → koatl-0.1.28}/Cargo.lock +1 -1
- {koatl-0.1.27 → koatl-0.1.28}/PKG-INFO +1 -1
- {koatl-0.1.27 → koatl-0.1.28}/koatl/Cargo.toml +1 -1
- {koatl-0.1.27 → koatl-0.1.28/koatl}/python/koatl/prelude/functional/algebra.tl +5 -10
- {koatl-0.1.27 → koatl-0.1.28/koatl}/python/koatl/prelude/functional/list.tl +2 -3
- {koatl-0.1.27 → koatl-0.1.28/koatl}/python/koatl/prelude/functional/result.tl +5 -6
- {koatl-0.1.27 → koatl-0.1.28/koatl}/python/koatl/prelude/iterable.tl +22 -26
- {koatl-0.1.27 → koatl-0.1.28}/koatl/python/koatl/runtime/__init__.py +4 -1
- koatl-0.1.28/koatl/python/koatl/runtime/classes.py +92 -0
- {koatl-0.1.27 → koatl-0.1.28}/koatl/python/koatl/runtime/helpers.py +0 -10
- koatl-0.1.28/koatl/python/koatl/runtime/virtual.py +103 -0
- {koatl-0.1.27 → koatl-0.1.28}/koatl/src/lib.rs +9 -5
- {koatl-0.1.27 → koatl-0.1.28}/koatl/tests/e2e/base/coal.tl +9 -0
- koatl-0.1.28/koatl/tests/e2e/prelude/aug_assign.tl +23 -0
- {koatl-0.1.27 → koatl-0.1.28}/koatl-core/src/transform.rs +38 -60
- {koatl-0.1.27/koatl → koatl-0.1.28}/python/koatl/prelude/functional/algebra.tl +5 -10
- {koatl-0.1.27/koatl → koatl-0.1.28}/python/koatl/prelude/functional/list.tl +2 -3
- {koatl-0.1.27/koatl → koatl-0.1.28}/python/koatl/prelude/functional/result.tl +5 -6
- {koatl-0.1.27/koatl → koatl-0.1.28}/python/koatl/prelude/iterable.tl +22 -26
- {koatl-0.1.27 → koatl-0.1.28}/python/koatl/runtime/__init__.py +4 -1
- koatl-0.1.28/python/koatl/runtime/classes.py +92 -0
- {koatl-0.1.27 → koatl-0.1.28}/python/koatl/runtime/helpers.py +0 -10
- koatl-0.1.28/python/koatl/runtime/virtual.py +103 -0
- koatl-0.1.27/koatl/python/koatl/runtime/virtual.py +0 -139
- koatl-0.1.27/koatl/tests/e2e/prelude/aug_assign.tl +0 -13
- koatl-0.1.27/python/koatl/runtime/virtual.py +0 -139
- {koatl-0.1.27 → koatl-0.1.28}/Cargo.toml +0 -0
- {koatl-0.1.27 → koatl-0.1.28}/README.md +0 -0
- {koatl-0.1.27 → koatl-0.1.28}/koatl/.github/workflows/CI.yml +0 -0
- {koatl-0.1.27 → koatl-0.1.28}/koatl/.gitignore +0 -0
- {koatl-0.1.27 → koatl-0.1.28}/koatl/LICENSE +0 -0
- {koatl-0.1.27 → koatl-0.1.28}/koatl/README.md +0 -0
- {koatl-0.1.27 → koatl-0.1.28}/koatl/python/koatl/__init__.py +0 -0
- {koatl-0.1.27 → koatl-0.1.28}/koatl/python/koatl/__main__.py +0 -0
- {koatl-0.1.27 → koatl-0.1.28}/koatl/python/koatl/cli.py +0 -0
- {koatl-0.1.27 → koatl-0.1.28}/koatl/python/koatl/notebook/__init__.py +0 -0
- {koatl-0.1.27 → koatl-0.1.28}/koatl/python/koatl/notebook/magic.py +0 -0
- {koatl-0.1.27 → koatl-0.1.28}/koatl/python/koatl/prelude/__init__.tl +0 -0
- {koatl-0.1.27 → koatl-0.1.28}/koatl/python/koatl/prelude/functional/__init__.tl +0 -0
- {koatl-0.1.27 → koatl-0.1.28}/koatl/python/koatl/prelude/functional/async.tl +0 -0
- {koatl-0.1.27 → koatl-0.1.28}/koatl/python/koatl/prelude/functional/async_util.py +0 -0
- {koatl-0.1.27 → koatl-0.1.28}/koatl/python/koatl/prelude/functional/memo.tl +0 -0
- {koatl-0.1.27 → koatl-0.1.28}/koatl/python/koatl/prelude/functional/reader.tl +0 -0
- {koatl-0.1.27 → koatl-0.1.28}/koatl/python/koatl/runtime/meta_finder.py +0 -0
- {koatl-0.1.27 → koatl-0.1.28}/koatl/python/koatl/runtime/record.py +0 -0
- {koatl-0.1.27 → koatl-0.1.28}/koatl/requirements.txt +0 -0
- {koatl-0.1.27 → koatl-0.1.28}/koatl/src/emit_py.rs +0 -0
- {koatl-0.1.27 → koatl-0.1.28}/koatl/tests/e2e/base/containers.tl +0 -0
- {koatl-0.1.27 → koatl-0.1.28}/koatl/tests/e2e/base/decorators.tl +0 -0
- {koatl-0.1.27 → koatl-0.1.28}/koatl/tests/e2e/base/destructure-for-and-fn.tl +0 -0
- {koatl-0.1.27 → koatl-0.1.28}/koatl/tests/e2e/base/destructure.tl +0 -0
- {koatl-0.1.27 → koatl-0.1.28}/koatl/tests/e2e/base/escape_ident.tl +0 -0
- {koatl-0.1.27 → koatl-0.1.28}/koatl/tests/e2e/base/fstr.tl +0 -0
- {koatl-0.1.27 → koatl-0.1.28}/koatl/tests/e2e/base/functions.tl +0 -0
- {koatl-0.1.27 → koatl-0.1.28}/koatl/tests/e2e/base/generator.tl +0 -0
- {koatl-0.1.27 → koatl-0.1.28}/koatl/tests/e2e/base/if_expr.tl +0 -0
- {koatl-0.1.27 → koatl-0.1.28}/koatl/tests/e2e/base/imports.tl +0 -0
- {koatl-0.1.27 → koatl-0.1.28}/koatl/tests/e2e/base/loops.tl +0 -0
- {koatl-0.1.27 → koatl-0.1.28}/koatl/tests/e2e/base/match.tl +0 -0
- {koatl-0.1.27 → koatl-0.1.28}/koatl/tests/e2e/base/nary-list.tl +0 -0
- {koatl-0.1.27 → koatl-0.1.28}/koatl/tests/e2e/base/placeholder.tl +0 -0
- {koatl-0.1.27 → koatl-0.1.28}/koatl/tests/e2e/base/precedence.tl +0 -0
- {koatl-0.1.27 → koatl-0.1.28}/koatl/tests/e2e/base/record.tl +0 -0
- {koatl-0.1.27 → koatl-0.1.28}/koatl/tests/e2e/base/scopes.tl +0 -0
- {koatl-0.1.27 → koatl-0.1.28}/koatl/tests/e2e/base/semantic_whitespace.tl +0 -0
- {koatl-0.1.27 → koatl-0.1.28}/koatl/tests/e2e/base/short_circuit.tl +0 -0
- {koatl-0.1.27 → koatl-0.1.28}/koatl/tests/e2e/destructure.tl +0 -0
- {koatl-0.1.27 → koatl-0.1.28}/koatl/tests/e2e/prelude/async.tl +0 -0
- {koatl-0.1.27 → koatl-0.1.28}/koatl/tests/e2e/prelude/iterables.tl +0 -0
- {koatl-0.1.27 → koatl-0.1.28}/koatl/tests/e2e/prelude/list.tl +0 -0
- {koatl-0.1.27 → koatl-0.1.28}/koatl/tests/e2e/prelude/memo.tl +0 -0
- {koatl-0.1.27 → koatl-0.1.28}/koatl/tests/e2e/prelude/reader.tl +0 -0
- {koatl-0.1.27 → koatl-0.1.28}/koatl/tests/e2e/prelude/result.tl +0 -0
- {koatl-0.1.27 → koatl-0.1.28}/koatl/tests/e2e/prelude/slice.tl +0 -0
- {koatl-0.1.27 → koatl-0.1.28}/koatl/tests/e2e/prelude/try.tl +0 -0
- {koatl-0.1.27 → koatl-0.1.28}/koatl/tests/e2e/prelude/virtual.tl +0 -0
- {koatl-0.1.27 → koatl-0.1.28}/koatl/tests/e2e/util/__init__.py +0 -0
- {koatl-0.1.27 → koatl-0.1.28}/koatl/tests/e2e/util/module0.tl +0 -0
- {koatl-0.1.27 → koatl-0.1.28}/koatl/tests/e2e/util/module1.tl +0 -0
- {koatl-0.1.27 → koatl-0.1.28}/koatl/tests/e2e/util/module2.tl +0 -0
- {koatl-0.1.27 → koatl-0.1.28}/koatl/tests/parse/arith.tl +0 -0
- {koatl-0.1.27 → koatl-0.1.28}/koatl/tests/parse/assign.tl +0 -0
- {koatl-0.1.27 → koatl-0.1.28}/koatl/tests/parse/block-comments.tl +0 -0
- {koatl-0.1.27 → koatl-0.1.28}/koatl/tests/parse/deco.tl +0 -0
- {koatl-0.1.27 → koatl-0.1.28}/koatl/tests/parse/func.tl +0 -0
- {koatl-0.1.27 → koatl-0.1.28}/koatl/tests/parse/matches.tl +0 -0
- {koatl-0.1.27 → koatl-0.1.28}/koatl/tests/test_e2e.py +0 -0
- {koatl-0.1.27 → koatl-0.1.28}/koatl/tests/test_parse.py +0 -0
- {koatl-0.1.27 → koatl-0.1.28}/koatl-core/Cargo.toml +0 -0
- {koatl-0.1.27 → koatl-0.1.28}/koatl-core/parser/Cargo.toml +0 -0
- {koatl-0.1.27 → koatl-0.1.28}/koatl-core/parser/src/ast.rs +0 -0
- {koatl-0.1.27 → koatl-0.1.28}/koatl-core/parser/src/lexer.rs +0 -0
- {koatl-0.1.27 → koatl-0.1.28}/koatl-core/parser/src/lib.rs +0 -0
- {koatl-0.1.27 → koatl-0.1.28}/koatl-core/parser/src/parser.rs +0 -0
- {koatl-0.1.27 → koatl-0.1.28}/koatl-core/parser/src/util.rs +0 -0
- {koatl-0.1.27 → koatl-0.1.28}/koatl-core/parser/tests/lexer.rs +0 -0
- {koatl-0.1.27 → koatl-0.1.28}/koatl-core/src/inference.rs +0 -0
- {koatl-0.1.27 → koatl-0.1.28}/koatl-core/src/lib.rs +0 -0
- {koatl-0.1.27 → koatl-0.1.28}/koatl-core/src/main.rs +0 -0
- {koatl-0.1.27 → koatl-0.1.28}/koatl-core/src/parse_timer.rs +0 -0
- {koatl-0.1.27 → koatl-0.1.28}/koatl-core/src/parser.rs +0 -0
- {koatl-0.1.27 → koatl-0.1.28}/koatl-core/src/py/ast.rs +0 -0
- {koatl-0.1.27 → koatl-0.1.28}/koatl-core/src/py/emit.rs +0 -0
- {koatl-0.1.27 → koatl-0.1.28}/koatl-core/src/py/mod.rs +0 -0
- {koatl-0.1.27 → koatl-0.1.28}/koatl-core/src/py/util.rs +0 -0
- {koatl-0.1.27 → koatl-0.1.28}/koatl-core/src/resolve_scopes.rs +0 -0
- {koatl-0.1.27 → koatl-0.1.28}/koatl-core/src/types.rs +0 -0
- {koatl-0.1.27 → koatl-0.1.28}/koatl-core/src/util.rs +0 -0
- {koatl-0.1.27 → koatl-0.1.28}/pyproject.toml +0 -0
- {koatl-0.1.27 → koatl-0.1.28}/python/koatl/__init__.py +0 -0
- {koatl-0.1.27 → koatl-0.1.28}/python/koatl/__main__.py +0 -0
- {koatl-0.1.27 → koatl-0.1.28}/python/koatl/cli.py +0 -0
- {koatl-0.1.27 → koatl-0.1.28}/python/koatl/notebook/__init__.py +0 -0
- {koatl-0.1.27 → koatl-0.1.28}/python/koatl/notebook/magic.py +0 -0
- {koatl-0.1.27 → koatl-0.1.28}/python/koatl/prelude/__init__.tl +0 -0
- {koatl-0.1.27 → koatl-0.1.28}/python/koatl/prelude/functional/__init__.tl +0 -0
- {koatl-0.1.27 → koatl-0.1.28}/python/koatl/prelude/functional/async.tl +0 -0
- {koatl-0.1.27 → koatl-0.1.28}/python/koatl/prelude/functional/async_util.py +0 -0
- {koatl-0.1.27 → koatl-0.1.28}/python/koatl/prelude/functional/memo.tl +0 -0
- {koatl-0.1.27 → koatl-0.1.28}/python/koatl/prelude/functional/reader.tl +0 -0
- {koatl-0.1.27 → koatl-0.1.28}/python/koatl/runtime/meta_finder.py +0 -0
- {koatl-0.1.27 → koatl-0.1.28}/python/koatl/runtime/record.py +0 -0
|
@@ -1,6 +1,4 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
export Monad = class(abc.ABC):
|
|
1
|
+
export Monad = class(Trait):
|
|
4
2
|
"""
|
|
5
3
|
Abstract base class for monads.
|
|
6
4
|
|
|
@@ -9,17 +7,16 @@ export Monad = class(abc.ABC):
|
|
|
9
7
|
"""
|
|
10
8
|
__slots__ = ()
|
|
11
9
|
|
|
12
|
-
bind =
|
|
10
|
+
bind = Abstract& (self, f) => None
|
|
13
11
|
|
|
14
|
-
pure = staticmethod&
|
|
12
|
+
pure = staticmethod& Abstract& value => None
|
|
15
13
|
|
|
16
14
|
# Automatically generated implementations.
|
|
17
15
|
map = (self, f) => self.bind(x => self.pure(f(x)))
|
|
18
16
|
apply = (self, f) => self.bind(x => f.map(fn => fn(x)))
|
|
19
17
|
|
|
20
18
|
|
|
21
|
-
|
|
22
|
-
export MonadOnce = class(abc.ABC):
|
|
19
|
+
export MonadOnce = class(Monad, Trait):
|
|
23
20
|
"""
|
|
24
21
|
Abstract base class for single-use monads.
|
|
25
22
|
|
|
@@ -32,9 +29,7 @@ export MonadOnce = class(abc.ABC):
|
|
|
32
29
|
__slots__ = ()
|
|
33
30
|
|
|
34
31
|
# The default implementation required for `@` syntax that should be overridden by subclasses.
|
|
35
|
-
bind_once =
|
|
36
|
-
|
|
37
|
-
pure = staticmethod& abc.abstractmethod& value => None
|
|
32
|
+
bind_once = Abstract& (self, f) => None
|
|
38
33
|
|
|
39
34
|
# An optional, optimized implementation of `bind` that skips deep recursion.
|
|
40
35
|
# TODO: can this be automatically generated from bind_once?
|
|
@@ -1,10 +1,9 @@
|
|
|
1
|
-
import collections.UserList
|
|
2
1
|
import itertools
|
|
3
2
|
|
|
4
3
|
import .Monad
|
|
5
4
|
import ..iterable.Iterable
|
|
6
5
|
|
|
7
|
-
export List = class(
|
|
6
|
+
export List = class(Monad):
|
|
8
7
|
bind_once = (self, f) =>
|
|
9
8
|
raise NotImplementedError(
|
|
10
9
|
"Binding List in a do-block doesn't work in Koatl " +
|
|
@@ -23,4 +22,4 @@ for name, method in List.__dict__:
|
|
|
23
22
|
if name.startswith("_"):
|
|
24
23
|
continue
|
|
25
24
|
|
|
26
|
-
|
|
25
|
+
ExtensionMethod(list, name)& method
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import functools.wraps
|
|
2
|
-
import koatl.runtime.virtual.register_global_attr
|
|
3
2
|
import .algebra.MonadOnce
|
|
4
3
|
|
|
5
4
|
export Result = class(MonadOnce):
|
|
@@ -118,14 +117,14 @@ export Err = class(Result):
|
|
|
118
117
|
coalesce = (self, f) => f()
|
|
119
118
|
|
|
120
119
|
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
120
|
+
ExtensionProperty(type(None), "ok")& _ => False
|
|
121
|
+
ExtensionProperty(BaseException, "ok")& _ => False
|
|
122
|
+
ExtensionProperty(object, "ok")& _ => True
|
|
124
123
|
|
|
125
|
-
|
|
124
|
+
ExtensionProperty(object, "result")& Result
|
|
126
125
|
|
|
127
126
|
# Enables @ operator for bare objects.
|
|
128
|
-
|
|
127
|
+
ExtensionMethod(object, "bind_gen")& Result.bind_gen
|
|
129
128
|
|
|
130
129
|
__tl__.Ok = Ok
|
|
131
130
|
__tl__.Err = Err
|
|
@@ -1,15 +1,17 @@
|
|
|
1
1
|
import itertools
|
|
2
2
|
import builtins
|
|
3
3
|
|
|
4
|
-
|
|
5
|
-
|
|
4
|
+
export Iterable = ExtensionTrait& class(Trait):
|
|
5
|
+
iter = Abstract
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
map = (self, f) => builtins.map(f, self.iter)
|
|
8
8
|
|
|
9
|
-
|
|
9
|
+
filter = (self, f) => builtins.filter(f, self.iter)
|
|
10
10
|
|
|
11
|
-
|
|
12
|
-
|
|
11
|
+
flat_map = (self, f) => itertools.chain.from_iterable(self.map(f))
|
|
12
|
+
|
|
13
|
+
traverse = (self, f) =>
|
|
14
|
+
let it = self.iter
|
|
13
15
|
let v
|
|
14
16
|
try:
|
|
15
17
|
v = next(it)
|
|
@@ -39,45 +41,39 @@ methods = {
|
|
|
39
41
|
acc = acc.apply(m.map(x => acc => [*acc, x]))
|
|
40
42
|
acc
|
|
41
43
|
|
|
42
|
-
fold
|
|
44
|
+
fold = (self, init, f) =>
|
|
43
45
|
let acc = init
|
|
44
|
-
for i in
|
|
46
|
+
for i in self:
|
|
45
47
|
acc = f(acc, i)
|
|
46
48
|
acc
|
|
47
49
|
|
|
48
|
-
first
|
|
49
|
-
for i in
|
|
50
|
+
first = (self, f) =>
|
|
51
|
+
for i in self:
|
|
50
52
|
if f(i):
|
|
51
53
|
return i
|
|
52
54
|
return None
|
|
53
55
|
|
|
54
|
-
last
|
|
56
|
+
last = (self, f) =>
|
|
55
57
|
let result = None
|
|
56
|
-
for i in
|
|
58
|
+
for i in self:
|
|
57
59
|
if f(i):
|
|
58
60
|
result = i
|
|
59
61
|
return result
|
|
60
62
|
|
|
61
|
-
at
|
|
62
|
-
for i in
|
|
63
|
+
at = (self, index) =>
|
|
64
|
+
for i in self:
|
|
63
65
|
if i == index:
|
|
64
66
|
return i
|
|
65
67
|
raise IndexError("Index out of range")
|
|
66
68
|
|
|
67
|
-
sum
|
|
69
|
+
sum = self =>
|
|
68
70
|
let acc = 0
|
|
69
|
-
for i in
|
|
71
|
+
for i in self:
|
|
70
72
|
acc = acc + i
|
|
71
73
|
acc
|
|
72
74
|
|
|
73
|
-
list
|
|
74
|
-
list(
|
|
75
|
-
|
|
76
|
-
record: x =>
|
|
77
|
-
Record(x.iter)
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
# TODO merge this with typing.Iterable?
|
|
75
|
+
list = self =>
|
|
76
|
+
list(self.iter)
|
|
81
77
|
|
|
82
|
-
|
|
83
|
-
|
|
78
|
+
record = self =>
|
|
79
|
+
Record(self.iter)
|
|
@@ -19,6 +19,7 @@ meta_finder.install_hook()
|
|
|
19
19
|
from .virtual import *
|
|
20
20
|
from .record import *
|
|
21
21
|
from .helpers import *
|
|
22
|
+
from .classes import *
|
|
22
23
|
|
|
23
24
|
|
|
24
25
|
def dummy(name):
|
|
@@ -33,9 +34,9 @@ def dummy(name):
|
|
|
33
34
|
__tl__ = SimpleNamespace(
|
|
34
35
|
Exception=Exception,
|
|
35
36
|
slice=slice,
|
|
37
|
+
type=type,
|
|
36
38
|
vget=virtual.vget,
|
|
37
39
|
vhas=virtual.vhas,
|
|
38
|
-
unpack_record=helpers.unpack_record,
|
|
39
40
|
set_exports=helpers.set_exports,
|
|
40
41
|
do=helpers.do,
|
|
41
42
|
partial=functools.partial,
|
|
@@ -50,6 +51,7 @@ __tl__ = SimpleNamespace(
|
|
|
50
51
|
**{name: helpers.__dict__[name] for name in helpers.__all__},
|
|
51
52
|
**{name: record.__dict__[name] for name in record.__all__},
|
|
52
53
|
**{name: virtual.__dict__[name] for name in virtual.__all__},
|
|
54
|
+
**{name: classes.__dict__[name] for name in classes.__all__},
|
|
53
55
|
)
|
|
54
56
|
|
|
55
57
|
|
|
@@ -58,4 +60,5 @@ __all__ = [
|
|
|
58
60
|
*helpers.__all__,
|
|
59
61
|
*record.__all__,
|
|
60
62
|
*virtual.__all__,
|
|
63
|
+
*classes.__all__,
|
|
61
64
|
]
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import abc
|
|
2
|
+
import collections
|
|
3
|
+
import inspect
|
|
4
|
+
|
|
5
|
+
from koatl.runtime.virtual import vhas
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
@collections.abc.Mapping.register
|
|
9
|
+
class MappingMeta(type):
|
|
10
|
+
def __getitem__(self, key):
|
|
11
|
+
return getattr(self, key)
|
|
12
|
+
|
|
13
|
+
def __iter__(self):
|
|
14
|
+
return self.keys().__iter__()
|
|
15
|
+
|
|
16
|
+
def __len__(self):
|
|
17
|
+
return len(self.items())
|
|
18
|
+
|
|
19
|
+
def __contains__(self, key):
|
|
20
|
+
return hasattr(self, key)
|
|
21
|
+
|
|
22
|
+
def get(self, key, default=None):
|
|
23
|
+
if hasattr(self, key):
|
|
24
|
+
return getattr(self, key)
|
|
25
|
+
else:
|
|
26
|
+
return default
|
|
27
|
+
|
|
28
|
+
def keys(self):
|
|
29
|
+
return [k for k, _ in self.items()]
|
|
30
|
+
|
|
31
|
+
def values(self):
|
|
32
|
+
return [v for _, v in self.items()]
|
|
33
|
+
|
|
34
|
+
def items(self):
|
|
35
|
+
return [(k, v) for k, v in inspect.getmembers(self) if not k.startswith("_")]
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
class Class(metaclass=MappingMeta):
|
|
39
|
+
pass
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
# temporary value, since TraitMeta needs to reference Trait.
|
|
43
|
+
Trait = None
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
class TraitMeta(MappingMeta):
|
|
47
|
+
def __init__(cls, name, bases, namespace):
|
|
48
|
+
super().__init__(name, bases, namespace)
|
|
49
|
+
|
|
50
|
+
if Trait in bases:
|
|
51
|
+
cls._trait_reqs = []
|
|
52
|
+
cls._own_methods = []
|
|
53
|
+
|
|
54
|
+
for key, value in inspect.getmembers(cls):
|
|
55
|
+
if (
|
|
56
|
+
hasattr(value, "__isabstractmethod__")
|
|
57
|
+
and value.__isabstractmethod__
|
|
58
|
+
):
|
|
59
|
+
cls._trait_reqs.append(key)
|
|
60
|
+
|
|
61
|
+
for key, value in namespace.items():
|
|
62
|
+
if (
|
|
63
|
+
hasattr(value, "__isabstractmethod__")
|
|
64
|
+
and value.__isabstractmethod__
|
|
65
|
+
):
|
|
66
|
+
# Abstract methods are not considered "own methods".
|
|
67
|
+
continue
|
|
68
|
+
|
|
69
|
+
if callable(value) and not key.startswith("_"):
|
|
70
|
+
cls._own_methods.append(key)
|
|
71
|
+
|
|
72
|
+
def __instancecheck__(cls, instance):
|
|
73
|
+
# Check if the exact class has _trait_reqs, in which case it's a trait.
|
|
74
|
+
if "_trait_reqs" in cls.__dict__:
|
|
75
|
+
for req in cls._trait_reqs:
|
|
76
|
+
if not vhas(instance, req):
|
|
77
|
+
return False
|
|
78
|
+
|
|
79
|
+
return True
|
|
80
|
+
else:
|
|
81
|
+
return type.__instancecheck__(cls, instance)
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
class Trait(metaclass=TraitMeta):
|
|
85
|
+
pass
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
Abstract = lambda value: abc.abstractmethod(value)
|
|
89
|
+
Abstract.__isabstractmethod__ = True
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
__all__ = ["Class", "Trait", "Abstract"]
|
|
@@ -35,16 +35,6 @@ def set_exports(package_name, globals_dict, exports, module_star_exports):
|
|
|
35
35
|
globals_dict["__all__"] = tuple(set(globals_dict["__all__"]) | exports)
|
|
36
36
|
|
|
37
37
|
|
|
38
|
-
def unpack_record(obj):
|
|
39
|
-
"""
|
|
40
|
-
used in record unpacking
|
|
41
|
-
"""
|
|
42
|
-
if hasattr(obj, "items"):
|
|
43
|
-
return Record(obj.items())
|
|
44
|
-
else:
|
|
45
|
-
return Record(obj.__dict__)
|
|
46
|
-
|
|
47
|
-
|
|
48
38
|
def ok(obj):
|
|
49
39
|
try:
|
|
50
40
|
return obj.ok
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
from functools import partial
|
|
2
|
+
from itertools import count
|
|
3
|
+
from .._rs import fast_vget, fast_vset, fast_vset_trait
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
def vget(obj, name, ignore_traits=False):
|
|
7
|
+
try:
|
|
8
|
+
return getattr(obj, name)
|
|
9
|
+
except:
|
|
10
|
+
# special case for iter - this could be implemented using types and trait vtbls
|
|
11
|
+
# but this is simpler and probably faster
|
|
12
|
+
if name == "iter":
|
|
13
|
+
if isinstance(obj, slice):
|
|
14
|
+
start = obj.start if obj.start is not None else 0
|
|
15
|
+
step = obj.step if obj.step is not None else 1
|
|
16
|
+
if obj.stop is None:
|
|
17
|
+
return count(start, step)
|
|
18
|
+
else:
|
|
19
|
+
return range(start, obj.stop, step)
|
|
20
|
+
|
|
21
|
+
try:
|
|
22
|
+
return obj.items()
|
|
23
|
+
except AttributeError:
|
|
24
|
+
pass
|
|
25
|
+
|
|
26
|
+
try:
|
|
27
|
+
return iter(obj)
|
|
28
|
+
except TypeError:
|
|
29
|
+
pass
|
|
30
|
+
|
|
31
|
+
v = fast_vget(obj, name, ignore_traits)
|
|
32
|
+
if v is not None:
|
|
33
|
+
if hasattr(v, "_ext_prop"):
|
|
34
|
+
return v(obj)
|
|
35
|
+
|
|
36
|
+
return partial(v, obj)
|
|
37
|
+
|
|
38
|
+
raise AttributeError(
|
|
39
|
+
f"'{type(obj).__name__}' object has no v-attribute '{name}'"
|
|
40
|
+
) from None
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
def vhas(obj, name, ignore_traits=False):
|
|
44
|
+
if hasattr(obj, name):
|
|
45
|
+
return True
|
|
46
|
+
|
|
47
|
+
if name == "iter":
|
|
48
|
+
if isinstance(obj, slice):
|
|
49
|
+
return True
|
|
50
|
+
|
|
51
|
+
try:
|
|
52
|
+
obj.items()
|
|
53
|
+
return True
|
|
54
|
+
except AttributeError:
|
|
55
|
+
pass
|
|
56
|
+
|
|
57
|
+
try:
|
|
58
|
+
iter(obj)
|
|
59
|
+
return True
|
|
60
|
+
except TypeError:
|
|
61
|
+
pass
|
|
62
|
+
|
|
63
|
+
v = fast_vget(obj, name, ignore_traits)
|
|
64
|
+
if v is not None:
|
|
65
|
+
return True
|
|
66
|
+
|
|
67
|
+
return False
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
def ExtensionProperty(type, name):
|
|
71
|
+
def impl(value):
|
|
72
|
+
value._ext_prop = True
|
|
73
|
+
fast_vset(type, name, value)
|
|
74
|
+
return value
|
|
75
|
+
|
|
76
|
+
return impl
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
def ExtensionMethod(type, name):
|
|
80
|
+
def impl(value):
|
|
81
|
+
fast_vset(type, name, value)
|
|
82
|
+
return value
|
|
83
|
+
|
|
84
|
+
return impl
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
def ExtensionTrait(type):
|
|
88
|
+
for name in type._own_methods:
|
|
89
|
+
fast_vset_trait(type.__name__, type._trait_reqs, name, type.__dict__[name])
|
|
90
|
+
return type
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
def TraitProperty(value):
|
|
94
|
+
value._ext_prop = True
|
|
95
|
+
return value
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
__all__ = [
|
|
99
|
+
"ExtensionProperty",
|
|
100
|
+
"ExtensionMethod",
|
|
101
|
+
"ExtensionTrait",
|
|
102
|
+
"TraitProperty",
|
|
103
|
+
]
|
|
@@ -178,11 +178,15 @@ fn fast_vset_trait<'py, 'ptr>(
|
|
|
178
178
|
vtbl.insert(name.clone(), Vec::new());
|
|
179
179
|
}
|
|
180
180
|
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
181
|
+
// TODO: what about conflicting traits?
|
|
182
|
+
vtbl.get_mut(&name).unwrap().insert(
|
|
183
|
+
0,
|
|
184
|
+
TraitAttr {
|
|
185
|
+
name: trait_name.to_string(),
|
|
186
|
+
requirements: reqs,
|
|
187
|
+
value: value.clone().unbind(),
|
|
188
|
+
},
|
|
189
|
+
);
|
|
186
190
|
|
|
187
191
|
Ok(())
|
|
188
192
|
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import util.assert_eq
|
|
2
|
+
|
|
3
|
+
x = 1
|
|
4
|
+
x += 2
|
|
5
|
+
assert_eq(x, 3)
|
|
6
|
+
|
|
7
|
+
x = None
|
|
8
|
+
x ??= 2
|
|
9
|
+
assert_eq(x, 2)
|
|
10
|
+
|
|
11
|
+
x = 4
|
|
12
|
+
x |= $ + 2
|
|
13
|
+
assert_eq(x, 6)
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
counts = 0
|
|
17
|
+
f = () =>
|
|
18
|
+
counts += 1
|
|
19
|
+
{x: None}
|
|
20
|
+
f().x ??= 2
|
|
21
|
+
|
|
22
|
+
# should only call once
|
|
23
|
+
assert_eq(counts, 1)
|
|
@@ -230,6 +230,29 @@ fn simple_err(msg: impl Into<String>, span: Span) -> TlErrs {
|
|
|
230
230
|
TlErrBuilder::new().message(msg.into()).span(span).build()
|
|
231
231
|
}
|
|
232
232
|
|
|
233
|
+
fn deduplicate<'src, 'ast>(
|
|
234
|
+
ctx: &mut TlCtx<'src, 'ast>,
|
|
235
|
+
expr: SPyExpr<'src>,
|
|
236
|
+
span: Span,
|
|
237
|
+
) -> TlResult<SPyExprWithPre<'src>> {
|
|
238
|
+
let var_name = ctx.create_aux_var("lhs", span.start);
|
|
239
|
+
let a = PyAstBuilder::new(span);
|
|
240
|
+
let mut pre = PyBlock::new();
|
|
241
|
+
|
|
242
|
+
let expr = match expr.value {
|
|
243
|
+
PyExpr::Ident(id, _) => a.load_ident(id),
|
|
244
|
+
x => {
|
|
245
|
+
pre.push(a.assign(
|
|
246
|
+
a.ident(var_name.clone(), PyAccessCtx::Store),
|
|
247
|
+
(x, expr.tl_span).into(),
|
|
248
|
+
));
|
|
249
|
+
a.load_ident(var_name.clone())
|
|
250
|
+
}
|
|
251
|
+
};
|
|
252
|
+
|
|
253
|
+
Ok(SPyExprWithPre { value: expr, pre })
|
|
254
|
+
}
|
|
255
|
+
|
|
233
256
|
impl<'src> BlockExt<'src> for [Indirect<SStmt<'src>>] {
|
|
234
257
|
fn transform<'ast>(
|
|
235
258
|
&'ast self,
|
|
@@ -715,10 +738,16 @@ fn create_throwing_matcher<'src, 'ast>(
|
|
|
715
738
|
let fail = PyBlock(vec![a.raise(Some(a.call(
|
|
716
739
|
a.load_ident("MatchError"),
|
|
717
740
|
vec![a.call_arg(a.fstr(vec![
|
|
718
|
-
a.fstr_str("failed to match value "),
|
|
719
|
-
a.fstr_expr(
|
|
741
|
+
a.fstr_str("failed to match value of type "),
|
|
742
|
+
a.fstr_expr(
|
|
743
|
+
a.call(
|
|
744
|
+
a.tl_builtin("type"),
|
|
745
|
+
vec![a.call_arg(a.load_ident(cursor.clone()))],
|
|
746
|
+
),
|
|
747
|
+
None,
|
|
748
|
+
),
|
|
720
749
|
a.fstr_str(format!(
|
|
721
|
-
" to pattern {}",
|
|
750
|
+
" to pattern \"{}\"",
|
|
722
751
|
&ctx.source[pattern.span.start..pattern.span.end]
|
|
723
752
|
)),
|
|
724
753
|
]))],
|
|
@@ -1528,29 +1557,6 @@ impl<'src> SStmtExt<'src> for SStmt<'src> {
|
|
|
1528
1557
|
if let Some(BinaryOp::Coalesce | BinaryOp::Pipe) = op {
|
|
1529
1558
|
let lhs = pre.bind(lhs.transform_store(ctx)?);
|
|
1530
1559
|
|
|
1531
|
-
fn deduplicate<'src, 'ast>(
|
|
1532
|
-
ctx: &mut TlCtx<'src, 'ast>,
|
|
1533
|
-
expr: SPyExpr<'src>,
|
|
1534
|
-
span: Span,
|
|
1535
|
-
) -> TlResult<SPyExprWithPre<'src>> {
|
|
1536
|
-
let var_name = ctx.create_aux_var("lhs", span.start);
|
|
1537
|
-
let a = PyAstBuilder::new(span);
|
|
1538
|
-
let mut pre = PyBlock::new();
|
|
1539
|
-
|
|
1540
|
-
let expr = match expr.value {
|
|
1541
|
-
PyExpr::Ident(id, _) => a.load_ident(id),
|
|
1542
|
-
x => {
|
|
1543
|
-
pre.push(a.assign(
|
|
1544
|
-
a.ident(var_name.clone(), PyAccessCtx::Store),
|
|
1545
|
-
(x, expr.tl_span).into(),
|
|
1546
|
-
));
|
|
1547
|
-
a.load_ident(var_name.clone())
|
|
1548
|
-
}
|
|
1549
|
-
};
|
|
1550
|
-
|
|
1551
|
-
Ok(SPyExprWithPre { value: expr, pre })
|
|
1552
|
-
}
|
|
1553
|
-
|
|
1554
1560
|
// TODO this is a bit hacky. We need to get separate the root node
|
|
1555
1561
|
// from the rest of the expression to avoid double evaluation
|
|
1556
1562
|
let (safe_lhs_store, safe_lhs_load) = match lhs.value {
|
|
@@ -1568,11 +1574,11 @@ impl<'src> SStmtExt<'src> for SStmt<'src> {
|
|
|
1568
1574
|
}
|
|
1569
1575
|
PyExpr::Subscript(left, right, _) => {
|
|
1570
1576
|
let left_span = left.tl_span;
|
|
1571
|
-
// TODO, critical: this leads to double evaluation of subscript indices
|
|
1572
1577
|
let dedup = pre.bind(deduplicate(ctx, *left, left_span)?);
|
|
1578
|
+
let dedup_right = pre.bind(deduplicate(ctx, *right, left_span)?);
|
|
1573
1579
|
(
|
|
1574
|
-
a.subscript(dedup.clone(),
|
|
1575
|
-
a.subscript(dedup,
|
|
1580
|
+
a.subscript(dedup.clone(), dedup_right.clone(), PyAccessCtx::Store),
|
|
1581
|
+
a.subscript(dedup, dedup_right, PyAccessCtx::Load),
|
|
1576
1582
|
)
|
|
1577
1583
|
}
|
|
1578
1584
|
_ => panic!(),
|
|
@@ -1717,17 +1723,6 @@ impl<'src> SStmtExt<'src> for SStmt<'src> {
|
|
|
1717
1723
|
trait SExprExt<'src, 'ast> {
|
|
1718
1724
|
fn transform(&'ast self, ctx: &mut TlCtx<'src, 'ast>) -> TlResult<SPyExprWithPre<'src>>;
|
|
1719
1725
|
|
|
1720
|
-
/**
|
|
1721
|
-
* Transforms
|
|
1722
|
-
* expr
|
|
1723
|
-
* to
|
|
1724
|
-
* x = expr
|
|
1725
|
-
* x
|
|
1726
|
-
*
|
|
1727
|
-
* to avoid evaluating expr multiple times
|
|
1728
|
-
*/
|
|
1729
|
-
fn transform_lifted(&'ast self, ctx: &mut TlCtx<'src, 'ast>) -> TlResult<SPyExprWithPre<'src>>;
|
|
1730
|
-
|
|
1731
1726
|
fn transform_store(&'ast self, ctx: &mut TlCtx<'src, 'ast>) -> TlResult<SPyExprWithPre<'src>>;
|
|
1732
1727
|
|
|
1733
1728
|
fn transform_full(
|
|
@@ -1742,25 +1737,6 @@ impl<'src, 'ast> SExprExt<'src, 'ast> for SExpr<'src> {
|
|
|
1742
1737
|
self.transform_full(ctx, PyAccessCtx::Load)
|
|
1743
1738
|
}
|
|
1744
1739
|
|
|
1745
|
-
fn transform_lifted(&'ast self, ctx: &mut TlCtx<'src, 'ast>) -> TlResult<SPyExprWithPre<'src>> {
|
|
1746
|
-
let mut pre = PyBlock::new();
|
|
1747
|
-
let value = pre.bind(self.transform(ctx)?);
|
|
1748
|
-
let a = PyAstBuilder::new(self.span);
|
|
1749
|
-
|
|
1750
|
-
let expr = match self.value {
|
|
1751
|
-
Expr::Ident(..) | Expr::Literal(..) => value,
|
|
1752
|
-
_ => {
|
|
1753
|
-
let temp_var = ctx.create_aux_var("tmp", self.span.start);
|
|
1754
|
-
|
|
1755
|
-
pre.push(a.assign(a.ident(temp_var.clone(), PyAccessCtx::Store), value));
|
|
1756
|
-
|
|
1757
|
-
a.ident(temp_var, PyAccessCtx::Load)
|
|
1758
|
-
}
|
|
1759
|
-
};
|
|
1760
|
-
|
|
1761
|
-
Ok(SPyExprWithPre { value: expr, pre })
|
|
1762
|
-
}
|
|
1763
|
-
|
|
1764
1740
|
fn transform_store(&'ast self, ctx: &mut TlCtx<'src, 'ast>) -> TlResult<SPyExprWithPre<'src>> {
|
|
1765
1741
|
self.transform_full(ctx, PyAccessCtx::Store)
|
|
1766
1742
|
}
|
|
@@ -1939,10 +1915,12 @@ impl<'src, 'ast> SExprExt<'src, 'ast> for SExpr<'src> {
|
|
|
1939
1915
|
}
|
|
1940
1916
|
Expr::Binary(op, lhs, rhs) => 'block: {
|
|
1941
1917
|
if let BinaryOp::Coalesce = op {
|
|
1942
|
-
let py_lhs = pre.bind(lhs.
|
|
1918
|
+
let py_lhs = pre.bind(lhs.transform(ctx)?);
|
|
1943
1919
|
let call = pre.bind(create_coalesce(ctx, py_lhs, rhs, span)?);
|
|
1944
1920
|
break 'block call;
|
|
1945
1921
|
} else if let BinaryOp::And | BinaryOp::Or = op {
|
|
1922
|
+
// handle short-circuiting manually
|
|
1923
|
+
|
|
1946
1924
|
let is_and = *op == BinaryOp::And;
|
|
1947
1925
|
|
|
1948
1926
|
let py_lhs = pre.bind(lhs.transform(ctx)?);
|