koatl 0.1.22__tar.gz → 0.1.24__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.22 → koatl-0.1.24}/Cargo.lock +1 -1
- {koatl-0.1.22 → koatl-0.1.24}/PKG-INFO +1 -1
- {koatl-0.1.22 → koatl-0.1.24}/koatl/Cargo.toml +1 -1
- {koatl-0.1.22 → koatl-0.1.24}/koatl/python/koatl/prelude/functional/__init__.tl +16 -3
- koatl-0.1.24/koatl/python/koatl/prelude/functional/list.tl +26 -0
- {koatl-0.1.22 → koatl-0.1.24/koatl}/python/koatl/prelude/functional/memo.tl +5 -4
- {koatl-0.1.22 → koatl-0.1.24/koatl}/python/koatl/prelude/functional/monad.tl +12 -4
- koatl-0.1.24/koatl/python/koatl/prelude/functional/result.tl +131 -0
- koatl-0.1.24/koatl/python/koatl/prelude/iterable.tl +83 -0
- {koatl-0.1.22 → koatl-0.1.24}/koatl/python/koatl/runtime/helpers.py +5 -0
- {koatl-0.1.22 → koatl-0.1.24}/koatl/python/koatl/runtime/virtual.py +2 -2
- {koatl-0.1.22 → koatl-0.1.24}/koatl/src/emit_py.rs +20 -3
- {koatl-0.1.22 → koatl-0.1.24}/koatl/src/lib.rs +23 -8
- koatl-0.1.24/koatl/tests/e2e/prelude/list.tl +18 -0
- {koatl-0.1.22 → koatl-0.1.24}/koatl-core/parser/src/parser.rs +11 -1
- {koatl-0.1.22 → koatl-0.1.24}/koatl-core/src/resolve_scopes.rs +25 -13
- {koatl-0.1.22 → koatl-0.1.24}/koatl-core/src/transform.rs +46 -36
- {koatl-0.1.22 → koatl-0.1.24}/python/koatl/prelude/functional/__init__.tl +16 -3
- koatl-0.1.24/python/koatl/prelude/functional/list.tl +26 -0
- {koatl-0.1.22/koatl → koatl-0.1.24}/python/koatl/prelude/functional/memo.tl +5 -4
- {koatl-0.1.22/koatl → koatl-0.1.24}/python/koatl/prelude/functional/monad.tl +12 -4
- koatl-0.1.24/python/koatl/prelude/functional/result.tl +131 -0
- koatl-0.1.24/python/koatl/prelude/iterable.tl +83 -0
- {koatl-0.1.22 → koatl-0.1.24}/python/koatl/runtime/helpers.py +5 -0
- {koatl-0.1.22 → koatl-0.1.24}/python/koatl/runtime/virtual.py +2 -2
- koatl-0.1.22/koatl/python/koatl/prelude/functional/result.tl +0 -93
- koatl-0.1.22/koatl/python/koatl/prelude/iterable.tl +0 -56
- koatl-0.1.22/python/koatl/prelude/functional/result.tl +0 -93
- koatl-0.1.22/python/koatl/prelude/iterable.tl +0 -56
- {koatl-0.1.22 → koatl-0.1.24}/Cargo.toml +0 -0
- {koatl-0.1.22 → koatl-0.1.24}/README.md +0 -0
- {koatl-0.1.22 → koatl-0.1.24}/koatl/.github/workflows/CI.yml +0 -0
- {koatl-0.1.22 → koatl-0.1.24}/koatl/.gitignore +0 -0
- {koatl-0.1.22 → koatl-0.1.24}/koatl/LICENSE +0 -0
- {koatl-0.1.22 → koatl-0.1.24}/koatl/README.md +0 -0
- {koatl-0.1.22 → koatl-0.1.24}/koatl/python/koatl/__init__.py +0 -0
- {koatl-0.1.22 → koatl-0.1.24}/koatl/python/koatl/__main__.py +0 -0
- {koatl-0.1.22 → koatl-0.1.24}/koatl/python/koatl/cli.py +0 -0
- {koatl-0.1.22 → koatl-0.1.24}/koatl/python/koatl/notebook/__init__.py +0 -0
- {koatl-0.1.22 → koatl-0.1.24}/koatl/python/koatl/notebook/magic.py +0 -0
- {koatl-0.1.22 → koatl-0.1.24}/koatl/python/koatl/prelude/__init__.tl +0 -0
- {koatl-0.1.22 → koatl-0.1.24}/koatl/python/koatl/prelude/functional/async.tl +0 -0
- {koatl-0.1.22 → koatl-0.1.24}/koatl/python/koatl/prelude/functional/async_util.py +0 -0
- {koatl-0.1.22 → koatl-0.1.24}/koatl/python/koatl/prelude/functional/reader.tl +0 -0
- {koatl-0.1.22 → koatl-0.1.24}/koatl/python/koatl/runtime/__init__.py +0 -0
- {koatl-0.1.22 → koatl-0.1.24}/koatl/python/koatl/runtime/meta_finder.py +0 -0
- {koatl-0.1.22 → koatl-0.1.24}/koatl/python/koatl/runtime/record.py +0 -0
- {koatl-0.1.22 → koatl-0.1.24}/koatl/requirements.txt +0 -0
- {koatl-0.1.22 → koatl-0.1.24}/koatl/tests/e2e/base/coal.tl +0 -0
- {koatl-0.1.22 → koatl-0.1.24}/koatl/tests/e2e/base/containers.tl +0 -0
- {koatl-0.1.22 → koatl-0.1.24}/koatl/tests/e2e/base/decorators.tl +0 -0
- {koatl-0.1.22 → koatl-0.1.24}/koatl/tests/e2e/base/destructure-for-and-fn.tl +0 -0
- {koatl-0.1.22 → koatl-0.1.24}/koatl/tests/e2e/base/destructure.tl +0 -0
- {koatl-0.1.22 → koatl-0.1.24}/koatl/tests/e2e/base/escape_ident.tl +0 -0
- {koatl-0.1.22 → koatl-0.1.24}/koatl/tests/e2e/base/fstr.tl +0 -0
- {koatl-0.1.22 → koatl-0.1.24}/koatl/tests/e2e/base/functions.tl +0 -0
- {koatl-0.1.22 → koatl-0.1.24}/koatl/tests/e2e/base/generator.tl +0 -0
- {koatl-0.1.22 → koatl-0.1.24}/koatl/tests/e2e/base/if_expr.tl +0 -0
- {koatl-0.1.22 → koatl-0.1.24}/koatl/tests/e2e/base/imports.tl +0 -0
- {koatl-0.1.22 → koatl-0.1.24}/koatl/tests/e2e/base/loops.tl +0 -0
- {koatl-0.1.22 → koatl-0.1.24}/koatl/tests/e2e/base/match.tl +0 -0
- {koatl-0.1.22 → koatl-0.1.24}/koatl/tests/e2e/base/nary-list.tl +0 -0
- {koatl-0.1.22 → koatl-0.1.24}/koatl/tests/e2e/base/placeholder.tl +0 -0
- {koatl-0.1.22 → koatl-0.1.24}/koatl/tests/e2e/base/precedence.tl +0 -0
- {koatl-0.1.22 → koatl-0.1.24}/koatl/tests/e2e/base/scopes.tl +0 -0
- {koatl-0.1.22 → koatl-0.1.24}/koatl/tests/e2e/base/semantic_whitespace.tl +0 -0
- {koatl-0.1.22 → koatl-0.1.24}/koatl/tests/e2e/base/slice.tl +0 -0
- {koatl-0.1.22 → koatl-0.1.24}/koatl/tests/e2e/base/try.tl +0 -0
- {koatl-0.1.22 → koatl-0.1.24}/koatl/tests/e2e/destructure.tl +0 -0
- {koatl-0.1.22 → koatl-0.1.24}/koatl/tests/e2e/prelude/async.tl +0 -0
- {koatl-0.1.22 → koatl-0.1.24}/koatl/tests/e2e/prelude/iterables.tl +0 -0
- {koatl-0.1.22 → koatl-0.1.24}/koatl/tests/e2e/prelude/memo.tl +0 -0
- {koatl-0.1.22 → koatl-0.1.24}/koatl/tests/e2e/prelude/reader.tl +0 -0
- {koatl-0.1.22 → koatl-0.1.24}/koatl/tests/e2e/prelude/result.tl +0 -0
- {koatl-0.1.22 → koatl-0.1.24}/koatl/tests/e2e/prelude/virtual.tl +0 -0
- {koatl-0.1.22 → koatl-0.1.24}/koatl/tests/e2e/util/__init__.py +0 -0
- {koatl-0.1.22 → koatl-0.1.24}/koatl/tests/e2e/util/module0.tl +0 -0
- {koatl-0.1.22 → koatl-0.1.24}/koatl/tests/e2e/util/module1.tl +0 -0
- {koatl-0.1.22 → koatl-0.1.24}/koatl/tests/e2e/util/module2.tl +0 -0
- {koatl-0.1.22 → koatl-0.1.24}/koatl/tests/parse/arith.tl +0 -0
- {koatl-0.1.22 → koatl-0.1.24}/koatl/tests/parse/assign.tl +0 -0
- {koatl-0.1.22 → koatl-0.1.24}/koatl/tests/parse/block-comments.tl +0 -0
- {koatl-0.1.22 → koatl-0.1.24}/koatl/tests/parse/deco.tl +0 -0
- {koatl-0.1.22 → koatl-0.1.24}/koatl/tests/parse/func.tl +0 -0
- {koatl-0.1.22 → koatl-0.1.24}/koatl/tests/parse/matches.tl +0 -0
- {koatl-0.1.22 → koatl-0.1.24}/koatl/tests/test_e2e.py +0 -0
- {koatl-0.1.22 → koatl-0.1.24}/koatl/tests/test_parse.py +0 -0
- {koatl-0.1.22 → koatl-0.1.24}/koatl-core/Cargo.toml +0 -0
- {koatl-0.1.22 → koatl-0.1.24}/koatl-core/parser/Cargo.toml +0 -0
- {koatl-0.1.22 → koatl-0.1.24}/koatl-core/parser/src/ast.rs +0 -0
- {koatl-0.1.22 → koatl-0.1.24}/koatl-core/parser/src/lexer.rs +0 -0
- {koatl-0.1.22 → koatl-0.1.24}/koatl-core/parser/src/lib.rs +0 -0
- {koatl-0.1.22 → koatl-0.1.24}/koatl-core/parser/src/util.rs +0 -0
- {koatl-0.1.22 → koatl-0.1.24}/koatl-core/parser/tests/lexer.rs +0 -0
- {koatl-0.1.22 → koatl-0.1.24}/koatl-core/src/inference.rs +0 -0
- {koatl-0.1.22 → koatl-0.1.24}/koatl-core/src/lib.rs +0 -0
- {koatl-0.1.22 → koatl-0.1.24}/koatl-core/src/main.rs +0 -0
- {koatl-0.1.22 → koatl-0.1.24}/koatl-core/src/parse_timer.rs +0 -0
- {koatl-0.1.22 → koatl-0.1.24}/koatl-core/src/parser.rs +0 -0
- {koatl-0.1.22 → koatl-0.1.24}/koatl-core/src/py/ast.rs +0 -0
- {koatl-0.1.22 → koatl-0.1.24}/koatl-core/src/py/emit.rs +0 -0
- {koatl-0.1.22 → koatl-0.1.24}/koatl-core/src/py/mod.rs +0 -0
- {koatl-0.1.22 → koatl-0.1.24}/koatl-core/src/py/util.rs +0 -0
- {koatl-0.1.22 → koatl-0.1.24}/koatl-core/src/types.rs +0 -0
- {koatl-0.1.22 → koatl-0.1.24}/koatl-core/src/util.rs +0 -0
- {koatl-0.1.22 → koatl-0.1.24}/pyproject.toml +0 -0
- {koatl-0.1.22 → koatl-0.1.24}/python/koatl/__init__.py +0 -0
- {koatl-0.1.22 → koatl-0.1.24}/python/koatl/__main__.py +0 -0
- {koatl-0.1.22 → koatl-0.1.24}/python/koatl/cli.py +0 -0
- {koatl-0.1.22 → koatl-0.1.24}/python/koatl/notebook/__init__.py +0 -0
- {koatl-0.1.22 → koatl-0.1.24}/python/koatl/notebook/magic.py +0 -0
- {koatl-0.1.22 → koatl-0.1.24}/python/koatl/prelude/__init__.tl +0 -0
- {koatl-0.1.22 → koatl-0.1.24}/python/koatl/prelude/functional/async.tl +0 -0
- {koatl-0.1.22 → koatl-0.1.24}/python/koatl/prelude/functional/async_util.py +0 -0
- {koatl-0.1.22 → koatl-0.1.24}/python/koatl/prelude/functional/reader.tl +0 -0
- {koatl-0.1.22 → koatl-0.1.24}/python/koatl/runtime/__init__.py +0 -0
- {koatl-0.1.22 → koatl-0.1.24}/python/koatl/runtime/meta_finder.py +0 -0
- {koatl-0.1.22 → koatl-0.1.24}/python/koatl/runtime/record.py +0 -0
|
@@ -3,9 +3,17 @@ export import .result.*
|
|
|
3
3
|
export import .async.*
|
|
4
4
|
export import .reader.*
|
|
5
5
|
export import .memo.*
|
|
6
|
+
export import .list.*
|
|
6
7
|
|
|
7
|
-
|
|
8
|
-
|
|
8
|
+
named = name => fn =>
|
|
9
|
+
fn.__name__ = name
|
|
10
|
+
fn.__qualname__ = name
|
|
11
|
+
fn
|
|
12
|
+
|
|
13
|
+
methods = {
|
|
14
|
+
id: named("id")& x => x
|
|
15
|
+
|
|
16
|
+
compose: named("compose")& (*args) =>
|
|
9
17
|
args match:
|
|
10
18
|
[] => raise ValueError("At least one function is required for composition")
|
|
11
19
|
[f] => f
|
|
@@ -21,4 +29,9 @@ export Fn = class:
|
|
|
21
29
|
composed.signature = fs[-1].signature
|
|
22
30
|
|
|
23
31
|
composed
|
|
24
|
-
default raise ValueError("Invalid arguments for Fn.compose()")
|
|
32
|
+
default raise ValueError("Invalid arguments for Fn.compose()")
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
globals().update(methods)
|
|
36
|
+
|
|
37
|
+
__all__ = methods.keys() | tuple
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import collections.UserList
|
|
2
|
+
import itertools
|
|
3
|
+
|
|
4
|
+
import .monad.Monad
|
|
5
|
+
import ..iterable.Iterable
|
|
6
|
+
|
|
7
|
+
export List = class(UserList, Monad):
|
|
8
|
+
bind_once = (self, f) =>
|
|
9
|
+
raise NotImplementedError(
|
|
10
|
+
"Binding List in a do-block doesn't work in Koatl " +
|
|
11
|
+
"due to generator limitations. " +
|
|
12
|
+
"Wrap in Ok to use the regular Result monad."
|
|
13
|
+
)
|
|
14
|
+
|
|
15
|
+
bind = (self, f) => List(self.flat_map(f))
|
|
16
|
+
|
|
17
|
+
pure = staticmethod& x => [x]
|
|
18
|
+
|
|
19
|
+
traverse = Iterable.traverse
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
for name, method in List.__dict__:
|
|
23
|
+
if name.startswith("_"):
|
|
24
|
+
continue
|
|
25
|
+
|
|
26
|
+
register_global_attr(list, name, method)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import collections.defaultdict
|
|
2
2
|
import functools.wraps
|
|
3
|
-
import .result.Ok
|
|
3
|
+
import .result.(Result, Ok)
|
|
4
4
|
import .Monad
|
|
5
5
|
|
|
6
6
|
export Memo = class(Monad):
|
|
@@ -11,7 +11,8 @@ export Memo = class(Monad):
|
|
|
11
11
|
__repr__ = self => f"Memo.Cache({self.cache})"
|
|
12
12
|
|
|
13
13
|
try_get = (self, name, deps) =>
|
|
14
|
-
try
|
|
14
|
+
# TODO should try operator return a Result directly?
|
|
15
|
+
Result(try self.cache[name][deps] except KeyError())
|
|
15
16
|
|
|
16
17
|
update = (self, name, deps, value) =>
|
|
17
18
|
self.cache[name][deps] = value
|
|
@@ -23,7 +24,7 @@ export Memo = class(Monad):
|
|
|
23
24
|
|
|
24
25
|
value = staticmethod& (id, deps, f) =>
|
|
25
26
|
Memo(ctx =>
|
|
26
|
-
if ctx.try_get(id, tuple(deps)) matches Ok()
|
|
27
|
+
if ctx.try_get(id, tuple(deps)) matches Ok(value):
|
|
27
28
|
return value
|
|
28
29
|
|
|
29
30
|
ctx.update(id, tuple(deps), f())
|
|
@@ -34,7 +35,7 @@ export Memo = class(Monad):
|
|
|
34
35
|
let deps = (tuple(args), tuple(kwargs.items()))
|
|
35
36
|
|
|
36
37
|
Memo(ctx =>
|
|
37
|
-
if ctx.try_get(id, deps) matches Ok()
|
|
38
|
+
if ctx.try_get(id, deps) matches Ok(value):
|
|
38
39
|
return value
|
|
39
40
|
|
|
40
41
|
let v = f(*args, **kwargs)
|
|
@@ -1,12 +1,20 @@
|
|
|
1
1
|
import abc
|
|
2
2
|
|
|
3
3
|
export Monad = class(abc.ABC):
|
|
4
|
+
__slots__ = ()
|
|
5
|
+
|
|
6
|
+
# The default implementation required for `@` syntax that should be overridden by subclasses.
|
|
7
|
+
bind_once = abc.abstractmethod& (self, f) => None
|
|
8
|
+
|
|
9
|
+
pure = staticmethod& abc.abstractmethod& value => None
|
|
10
|
+
|
|
11
|
+
# Automatically given by bind_once.
|
|
4
12
|
bind = (self, f) => self.bind_once(f)
|
|
5
13
|
|
|
6
14
|
# An optional, optimized implementation of `bind` that skips deep recursion.
|
|
15
|
+
# TODO: can this be automatically generated?
|
|
7
16
|
bind_gen = (self, gen) => raise NotImplementedError()
|
|
8
17
|
|
|
9
|
-
#
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
pure = staticmethod& abc.abstractmethod& value => None
|
|
18
|
+
# Automatically generated implementations.
|
|
19
|
+
map = (self, f) => self.bind(x => self.pure(f(x)))
|
|
20
|
+
apply = (self, f) => self.bind(x => f.map(fn => fn(x)))
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
import functools.wraps
|
|
2
|
+
import .monad.Monad
|
|
3
|
+
import koatl.runtime.virtual.register_global_attr
|
|
4
|
+
|
|
5
|
+
export Result = class:
|
|
6
|
+
__slots__ = ()
|
|
7
|
+
__match_args__ = ("value",)
|
|
8
|
+
|
|
9
|
+
__new__ = (cls, value) =>
|
|
10
|
+
if isinstance(value, Result):
|
|
11
|
+
return value
|
|
12
|
+
value.ok then Ok(value) else Err(value)
|
|
13
|
+
|
|
14
|
+
__init__ = (self, *args, **kwargs) =>
|
|
15
|
+
raise ValueError("Result should not be instantiated directly, use Ok or Err")
|
|
16
|
+
|
|
17
|
+
raw = self =>
|
|
18
|
+
"""
|
|
19
|
+
Unwraps the value from a Result, making it look like
|
|
20
|
+
a non-monadic Python value.
|
|
21
|
+
"""
|
|
22
|
+
if self matches not Result():
|
|
23
|
+
return self
|
|
24
|
+
|
|
25
|
+
if self.ok:
|
|
26
|
+
if self.value.ok:
|
|
27
|
+
return self.value
|
|
28
|
+
else:
|
|
29
|
+
return self
|
|
30
|
+
else:
|
|
31
|
+
if self.value.ok:
|
|
32
|
+
return self
|
|
33
|
+
else:
|
|
34
|
+
return self.value
|
|
35
|
+
|
|
36
|
+
bind_once = (self, f) =>
|
|
37
|
+
self = Result(self)
|
|
38
|
+
if not self.ok:
|
|
39
|
+
return self
|
|
40
|
+
|
|
41
|
+
let v = Result(f(self.value))
|
|
42
|
+
|
|
43
|
+
bind = bind_once
|
|
44
|
+
|
|
45
|
+
bind_gen = (self, gen) =>
|
|
46
|
+
self = Result(self)
|
|
47
|
+
try:
|
|
48
|
+
while True:
|
|
49
|
+
if not self.ok:
|
|
50
|
+
return self
|
|
51
|
+
|
|
52
|
+
self = Result(gen.send(self.value))
|
|
53
|
+
except StopIteration(value=value):
|
|
54
|
+
return Result.pure(value)
|
|
55
|
+
|
|
56
|
+
pure = staticmethod& x => Ok(x)
|
|
57
|
+
|
|
58
|
+
apply = (self, f) =>
|
|
59
|
+
self = Result(self)
|
|
60
|
+
f = Result(f)
|
|
61
|
+
|
|
62
|
+
if not self.ok:
|
|
63
|
+
return self
|
|
64
|
+
if not f.ok:
|
|
65
|
+
return f
|
|
66
|
+
|
|
67
|
+
Ok(f(self))
|
|
68
|
+
|
|
69
|
+
map = (self, f) =>
|
|
70
|
+
self = Result(self)
|
|
71
|
+
if self.ok:
|
|
72
|
+
return Ok(f(self.value))
|
|
73
|
+
return self
|
|
74
|
+
|
|
75
|
+
map_err = (self, f) =>
|
|
76
|
+
self = Result(self)
|
|
77
|
+
if not self.ok:
|
|
78
|
+
return Err(f(self.value))
|
|
79
|
+
return self
|
|
80
|
+
|
|
81
|
+
map_none = (self, f) =>
|
|
82
|
+
self = Result(self)
|
|
83
|
+
if not self.ok and self.value === None:
|
|
84
|
+
return Err(f())
|
|
85
|
+
return self
|
|
86
|
+
|
|
87
|
+
export Ok = class(Result):
|
|
88
|
+
__slots__ = ("value",)
|
|
89
|
+
ok = True
|
|
90
|
+
__new__ = (cls, value) => object.__new__(cls)
|
|
91
|
+
__init__ = (self, value) =>
|
|
92
|
+
if hasattr(self, "value"):
|
|
93
|
+
# This is necessary to prevent overwriting the value
|
|
94
|
+
# since Python's Result.__new__ will call Ok.__init__ again
|
|
95
|
+
# if the object is already created.
|
|
96
|
+
return None
|
|
97
|
+
self.value = value
|
|
98
|
+
|
|
99
|
+
__repr__ = self => f"Ok({repr(self.value)})"
|
|
100
|
+
unwrap = self => self.value
|
|
101
|
+
|
|
102
|
+
export Err = class(Result):
|
|
103
|
+
__slots__ = ("value",)
|
|
104
|
+
ok = False
|
|
105
|
+
__new__ = (cls, value) => object.__new__(cls)
|
|
106
|
+
__init__ = (self, value) =>
|
|
107
|
+
if hasattr(self, "value"):
|
|
108
|
+
return None
|
|
109
|
+
self.value = value
|
|
110
|
+
|
|
111
|
+
__repr__ = self => f"Err({repr(self.value)})"
|
|
112
|
+
unwrap = self =>
|
|
113
|
+
if self.value matches BaseException():
|
|
114
|
+
raise self.value
|
|
115
|
+
raise ValueError(f"Expected Ok, got {repr(self.value)}")
|
|
116
|
+
|
|
117
|
+
|
|
118
|
+
# Provide a default implementation for *most* Result methods
|
|
119
|
+
# ...we shouldn't provide a default for `map` since that
|
|
120
|
+
# would prevent virtual trait lookup. TODO: fix this?
|
|
121
|
+
for name, method in Result.__dict__:
|
|
122
|
+
if name.startswith("_"):
|
|
123
|
+
continue
|
|
124
|
+
if name == "map":
|
|
125
|
+
continue
|
|
126
|
+
|
|
127
|
+
let make_closure = method => (self, *args, **kwargs) => Result.raw(method(self, *args, **kwargs))
|
|
128
|
+
|
|
129
|
+
register_global_attr(object, name, make_closure(method))
|
|
130
|
+
|
|
131
|
+
register_global_attr(object, "ok", ExtensionProperty(__tl__.ok))
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import itertools
|
|
2
|
+
import builtins
|
|
3
|
+
|
|
4
|
+
methods = {
|
|
5
|
+
map: (x, f) => builtins.map(f, x.iter)
|
|
6
|
+
|
|
7
|
+
filter: (x, f) => builtins.filter(f, x.iter)
|
|
8
|
+
|
|
9
|
+
flat_map: (x, f) => itertools.chain.from_iterable(x.map(f))
|
|
10
|
+
|
|
11
|
+
traverse: (x, f) =>
|
|
12
|
+
let it = x.iter
|
|
13
|
+
let v
|
|
14
|
+
try:
|
|
15
|
+
v = next(it)
|
|
16
|
+
except StopIteration():
|
|
17
|
+
return []
|
|
18
|
+
|
|
19
|
+
let m = f(v)
|
|
20
|
+
|
|
21
|
+
if not hasattr(m, "apply"):
|
|
22
|
+
# special case for bare types - slightly more efficient
|
|
23
|
+
# ...also required since bare types don't have .map
|
|
24
|
+
if not __tl__.ok(m):
|
|
25
|
+
return m
|
|
26
|
+
|
|
27
|
+
let acc = [m]
|
|
28
|
+
for v in it:
|
|
29
|
+
let fv = f(v)
|
|
30
|
+
if not __tl__.ok(fv):
|
|
31
|
+
return fv
|
|
32
|
+
acc.append(fv)
|
|
33
|
+
return acc
|
|
34
|
+
|
|
35
|
+
let acc = m.map([$])
|
|
36
|
+
for v in it:
|
|
37
|
+
m = f(v)
|
|
38
|
+
# acc = liftA2((list, value) => [*list, value])(acc, f(v))
|
|
39
|
+
acc = acc.apply(m.map(x => acc => [*acc, x]))
|
|
40
|
+
acc
|
|
41
|
+
|
|
42
|
+
fold: (x, init, f) =>
|
|
43
|
+
let acc = init
|
|
44
|
+
for i in x:
|
|
45
|
+
acc = f(acc, i)
|
|
46
|
+
acc
|
|
47
|
+
|
|
48
|
+
first: (x, f) =>
|
|
49
|
+
for i in x:
|
|
50
|
+
if f(i):
|
|
51
|
+
return i
|
|
52
|
+
return None
|
|
53
|
+
|
|
54
|
+
last: (x, f) =>
|
|
55
|
+
let result = None
|
|
56
|
+
for i in x:
|
|
57
|
+
if f(i):
|
|
58
|
+
result = i
|
|
59
|
+
return result
|
|
60
|
+
|
|
61
|
+
at: (x, index) =>
|
|
62
|
+
for i in x:
|
|
63
|
+
if i == index:
|
|
64
|
+
return i
|
|
65
|
+
raise IndexError("Index out of range")
|
|
66
|
+
|
|
67
|
+
sum: x =>
|
|
68
|
+
let acc = 0
|
|
69
|
+
for i in x:
|
|
70
|
+
acc = acc + i
|
|
71
|
+
acc
|
|
72
|
+
|
|
73
|
+
list: x =>
|
|
74
|
+
list(x.iter)
|
|
75
|
+
|
|
76
|
+
record: x =>
|
|
77
|
+
Record(x.iter)
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
# TODO merge this with typing.Iterable?
|
|
81
|
+
|
|
82
|
+
export Iterable = Trait(__name__, "Iterable", methods, requires=["iter"])
|
|
83
|
+
register_global_trait(Iterable)
|
|
@@ -9,7 +9,7 @@ def ExtensionProperty(f):
|
|
|
9
9
|
return f
|
|
10
10
|
|
|
11
11
|
|
|
12
|
-
def vget(obj, name):
|
|
12
|
+
def vget(obj, name, ignore_traits=False):
|
|
13
13
|
try:
|
|
14
14
|
return getattr(obj, name)
|
|
15
15
|
except:
|
|
@@ -34,7 +34,7 @@ def vget(obj, name):
|
|
|
34
34
|
except TypeError:
|
|
35
35
|
pass
|
|
36
36
|
|
|
37
|
-
v = fast_vget(obj, name)
|
|
37
|
+
v = fast_vget(obj, name, ignore_traits)
|
|
38
38
|
if v is not None:
|
|
39
39
|
if hasattr(v, "ext_prop"):
|
|
40
40
|
return v(obj)
|
|
@@ -502,7 +502,7 @@ impl<'src> PyExprExt<'src> for SPyExpr<'src> {
|
|
|
502
502
|
ctx.ast_node("Name", (ident, c.emit_py(ctx)?), &self.tl_span)?
|
|
503
503
|
}
|
|
504
504
|
PyExpr::Binary(op, left, right) => {
|
|
505
|
-
let
|
|
505
|
+
let py_bin_op = match op {
|
|
506
506
|
PyBinaryOp::Add => Some("Add"),
|
|
507
507
|
PyBinaryOp::Sub => Some("Sub"),
|
|
508
508
|
PyBinaryOp::Mult => Some("Mult"),
|
|
@@ -512,18 +512,35 @@ impl<'src> PyExprExt<'src> for SPyExpr<'src> {
|
|
|
512
512
|
_ => None,
|
|
513
513
|
};
|
|
514
514
|
|
|
515
|
-
if let Some(
|
|
515
|
+
if let Some(py_bin_op) = py_bin_op {
|
|
516
516
|
return ctx.ast_node(
|
|
517
517
|
"BinOp",
|
|
518
518
|
(
|
|
519
519
|
left.emit_py(ctx)?,
|
|
520
|
-
ctx.ast_cls(
|
|
520
|
+
ctx.ast_cls(py_bin_op, ())?,
|
|
521
521
|
right.emit_py(ctx)?,
|
|
522
522
|
),
|
|
523
523
|
&self.tl_span,
|
|
524
524
|
);
|
|
525
525
|
}
|
|
526
526
|
|
|
527
|
+
let py_bool_op = match op {
|
|
528
|
+
PyBinaryOp::And => Some("And"),
|
|
529
|
+
PyBinaryOp::Or => Some("Or"),
|
|
530
|
+
_ => None,
|
|
531
|
+
};
|
|
532
|
+
|
|
533
|
+
if let Some(py_bool_op) = py_bool_op {
|
|
534
|
+
return ctx.ast_node(
|
|
535
|
+
"BoolOp",
|
|
536
|
+
(
|
|
537
|
+
ctx.ast_cls(py_bool_op, ())?,
|
|
538
|
+
[left.emit_py(ctx)?, right.emit_py(ctx)?],
|
|
539
|
+
),
|
|
540
|
+
&self.tl_span,
|
|
541
|
+
);
|
|
542
|
+
}
|
|
543
|
+
|
|
527
544
|
let py_cmp_op = match op {
|
|
528
545
|
PyBinaryOp::Lt => Some("Lt"),
|
|
529
546
|
PyBinaryOp::Gt => Some("Gt"),
|
|
@@ -79,27 +79,42 @@ struct TraitAttr {
|
|
|
79
79
|
static VTBL2: Lazy<Mutex<HashMap<String, Vec<TraitAttr>>>> =
|
|
80
80
|
Lazy::new(|| Mutex::new(HashMap::new()));
|
|
81
81
|
|
|
82
|
-
#[pyfunction(signature=(obj, name))]
|
|
82
|
+
#[pyfunction(signature=(obj, name, ignore_traits))]
|
|
83
83
|
fn fast_vget<'py, 'ptr>(
|
|
84
84
|
obj: &'ptr Bound<'py, PyAny>,
|
|
85
85
|
name: &'ptr Bound<'py, PyString>,
|
|
86
|
+
ignore_traits: bool,
|
|
86
87
|
) -> PyResult<PyObject> {
|
|
87
88
|
let name = name.to_string();
|
|
88
89
|
|
|
89
90
|
let py = obj.py();
|
|
90
91
|
|
|
91
|
-
|
|
92
|
+
{
|
|
93
|
+
// This block is necessary to ensure the lock is released
|
|
94
|
+
// before we possibly re-enter fast_vget through __tl__.vget below.
|
|
92
95
|
|
|
93
|
-
|
|
94
|
-
let mro = obj.get_type().mro();
|
|
96
|
+
let vtbl = VTBL.lock().unwrap();
|
|
95
97
|
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
98
|
+
if let Some(types) = vtbl.get(&name) {
|
|
99
|
+
let mro = obj.get_type().mro();
|
|
100
|
+
|
|
101
|
+
for typ in mro {
|
|
102
|
+
if let Some(attr) = types.get(&(typ.as_ptr() as usize)) {
|
|
103
|
+
return Ok((*attr).clone_ref(py));
|
|
104
|
+
}
|
|
99
105
|
}
|
|
100
106
|
}
|
|
101
107
|
}
|
|
102
108
|
|
|
109
|
+
if ignore_traits {
|
|
110
|
+
// This prevents a deadlock from fast_vget being called
|
|
111
|
+
// *again* from inside __tl_.vget while vtbl2 is locked.
|
|
112
|
+
|
|
113
|
+
// Also, prevents a trait from being dependent on other traits,
|
|
114
|
+
// which might cause an infinite loop sometimes.
|
|
115
|
+
return Ok(py.None().into_any());
|
|
116
|
+
}
|
|
117
|
+
|
|
103
118
|
let vtbl2 = VTBL2.lock().unwrap();
|
|
104
119
|
|
|
105
120
|
if let Some(traits) = vtbl2.get(&name) {
|
|
@@ -109,7 +124,7 @@ fn fast_vget<'py, 'ptr>(
|
|
|
109
124
|
for t in traits {
|
|
110
125
|
let mut ok = true;
|
|
111
126
|
for r in t.requirements.iter() {
|
|
112
|
-
if vget.call1((obj, r)).is_err() {
|
|
127
|
+
if vget.call1((obj, r, true)).is_err() {
|
|
113
128
|
ok = false;
|
|
114
129
|
break;
|
|
115
130
|
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import util.assert_eq
|
|
2
|
+
|
|
3
|
+
# Traverse makes sure that apply and map implementations are correct.
|
|
4
|
+
|
|
5
|
+
assert_eq(
|
|
6
|
+
[1, 2, 3].traverse(x => @Async.pure(x)).run() # run in a new event loop
|
|
7
|
+
[1, 2, 3]
|
|
8
|
+
)
|
|
9
|
+
|
|
10
|
+
assert_eq(
|
|
11
|
+
[1, 2, 3].traverse(x => x + 1)
|
|
12
|
+
[2, 3, 4]
|
|
13
|
+
)
|
|
14
|
+
|
|
15
|
+
assert_eq(
|
|
16
|
+
[1, 2, 3].traverse(x => None)
|
|
17
|
+
None
|
|
18
|
+
)
|
|
@@ -640,7 +640,17 @@ where
|
|
|
640
640
|
.or_not()
|
|
641
641
|
.then_ignore(just(Token::Kw("import")))
|
|
642
642
|
.then(group((
|
|
643
|
-
|
|
643
|
+
// TODO this looks extremely cursed
|
|
644
|
+
symbol("..")
|
|
645
|
+
.to(2)
|
|
646
|
+
.repeated()
|
|
647
|
+
.foldr(
|
|
648
|
+
symbol(".")
|
|
649
|
+
.or_not()
|
|
650
|
+
.map(|x| if x.is_some() { 1 } else { 0 }),
|
|
651
|
+
|acc, sum| acc + sum,
|
|
652
|
+
)
|
|
653
|
+
.boxed(),
|
|
644
654
|
ident
|
|
645
655
|
.clone()
|
|
646
656
|
.then_ignore(symbol("."))
|
|
@@ -2,6 +2,7 @@ use std::collections::HashMap;
|
|
|
2
2
|
use std::collections::HashSet;
|
|
3
3
|
use std::fmt::Display;
|
|
4
4
|
|
|
5
|
+
use slotmap::Key;
|
|
5
6
|
use slotmap::SlotMap;
|
|
6
7
|
use slotmap::new_key_type;
|
|
7
8
|
|
|
@@ -70,10 +71,10 @@ fn top_scope_and_key<'src, 'state>(
|
|
|
70
71
|
#[allow(dead_code)]
|
|
71
72
|
impl<'src> ResolveState<'src> {
|
|
72
73
|
fn new(source: &'src str) -> Self {
|
|
73
|
-
let mut root_scope = Scope::new();
|
|
74
|
+
let mut root_scope = Scope::new(ScopeKey::null());
|
|
74
75
|
root_scope.is_global = true;
|
|
75
76
|
|
|
76
|
-
let err_scope = Scope::new();
|
|
77
|
+
let err_scope = Scope::new(ScopeKey::null());
|
|
77
78
|
|
|
78
79
|
let mut scopes = SlotMap::with_key();
|
|
79
80
|
let root_scope_key = scopes.insert(root_scope);
|
|
@@ -107,6 +108,10 @@ impl<'src> ResolveState<'src> {
|
|
|
107
108
|
top_scope(&self.scope_stack, &mut self.scopes)
|
|
108
109
|
}
|
|
109
110
|
|
|
111
|
+
fn top_scope_key(&mut self) -> ScopeKey {
|
|
112
|
+
*self.scope_stack.last_mut().unwrap()
|
|
113
|
+
}
|
|
114
|
+
|
|
110
115
|
fn top_scope_and_key(&mut self) -> (&mut Scope, ScopeKey) {
|
|
111
116
|
top_scope_and_key(&self.scope_stack, &mut self.scopes)
|
|
112
117
|
}
|
|
@@ -185,10 +190,10 @@ impl<'src> ResolveState<'src> {
|
|
|
185
190
|
where
|
|
186
191
|
F: FnOnce(&mut ResolveState<'src>) -> Indirect<SExpr<'src>>,
|
|
187
192
|
{
|
|
188
|
-
let mut
|
|
189
|
-
|
|
193
|
+
let mut dummy_scope = Scope::new(ScopeKey::null());
|
|
194
|
+
dummy_scope.is_fn = true;
|
|
190
195
|
|
|
191
|
-
let temp_scope_key = self.scopes.insert(
|
|
196
|
+
let temp_scope_key = self.scopes.insert(dummy_scope);
|
|
192
197
|
|
|
193
198
|
let ph_decl = self.declarations.insert_declaration(
|
|
194
199
|
Ident("x".into()).spanned(span),
|
|
@@ -460,6 +465,9 @@ impl Display for Declaration<'_> {
|
|
|
460
465
|
|
|
461
466
|
#[derive(Debug)]
|
|
462
467
|
pub struct Scope {
|
|
468
|
+
// TODO make this option
|
|
469
|
+
pub parent: ScopeKey,
|
|
470
|
+
|
|
463
471
|
pub locals: Vec<DeclarationKey>,
|
|
464
472
|
|
|
465
473
|
pub is_class: bool,
|
|
@@ -488,8 +496,9 @@ impl Display for Scope {
|
|
|
488
496
|
}
|
|
489
497
|
|
|
490
498
|
impl Scope {
|
|
491
|
-
fn new() -> Scope {
|
|
499
|
+
fn new(parent: ScopeKey) -> Scope {
|
|
492
500
|
Self {
|
|
501
|
+
parent,
|
|
493
502
|
locals: Vec::new(),
|
|
494
503
|
lifted_decls: Vec::new(),
|
|
495
504
|
|
|
@@ -797,7 +806,7 @@ fn pattern_scoped<'src>(
|
|
|
797
806
|
state: &mut ResolveState<'src>,
|
|
798
807
|
pattern: Indirect<SPattern<'src>>,
|
|
799
808
|
) -> (Indirect<SPattern<'src>>, ScopeKey, PatternMeta<'src>) {
|
|
800
|
-
let scope = Scope::new();
|
|
809
|
+
let scope = Scope::new(state.top_scope_key());
|
|
801
810
|
let scope_key = state.scopes.insert(scope);
|
|
802
811
|
|
|
803
812
|
let (pattern, meta) = pattern.traverse(state);
|
|
@@ -946,7 +955,8 @@ impl<'src> SExprExt<'src> for Indirect<SExpr<'src>> {
|
|
|
946
955
|
}
|
|
947
956
|
new_stmts
|
|
948
957
|
} else {
|
|
949
|
-
let
|
|
958
|
+
let parent = state.top_scope_key();
|
|
959
|
+
let scope = state.scopes.insert(Scope::new(parent));
|
|
950
960
|
state
|
|
951
961
|
.scoped(scope, |state| {
|
|
952
962
|
let mut new_stmts = Vec::new();
|
|
@@ -1040,7 +1050,8 @@ impl<'src> SExprExt<'src> for Indirect<SExpr<'src>> {
|
|
|
1040
1050
|
let (pattern, scope, _meta) = pattern_scoped(state, pattern);
|
|
1041
1051
|
(Some(pattern), scope)
|
|
1042
1052
|
} else {
|
|
1043
|
-
|
|
1053
|
+
let parent = state.top_scope_key();
|
|
1054
|
+
(None, state.scopes.insert(Scope::new(parent)))
|
|
1044
1055
|
};
|
|
1045
1056
|
|
|
1046
1057
|
SMatchCase {
|
|
@@ -1058,7 +1069,7 @@ impl<'src> SExprExt<'src> for Indirect<SExpr<'src>> {
|
|
|
1058
1069
|
Expr::Class(bases, body) => {
|
|
1059
1070
|
let bases = traverse_call_items(state, bases);
|
|
1060
1071
|
|
|
1061
|
-
let mut scope = Scope::new();
|
|
1072
|
+
let mut scope = Scope::new(state.top_scope_key());
|
|
1062
1073
|
scope.is_class = true;
|
|
1063
1074
|
let scope = state.scopes.insert(scope);
|
|
1064
1075
|
|
|
@@ -1071,7 +1082,7 @@ impl<'src> SExprExt<'src> for Indirect<SExpr<'src>> {
|
|
|
1071
1082
|
Expr::Fn(arg_def_items, body) => {
|
|
1072
1083
|
let mut decls = vec![];
|
|
1073
1084
|
|
|
1074
|
-
let mut scope = Scope::new();
|
|
1085
|
+
let mut scope = Scope::new(state.top_scope_key());
|
|
1075
1086
|
scope.is_fn = true;
|
|
1076
1087
|
let scope = state.scopes.insert(scope);
|
|
1077
1088
|
|
|
@@ -1297,7 +1308,7 @@ impl<'src> SExprExt<'src> for Indirect<SExpr<'src>> {
|
|
|
1297
1308
|
let mut fn_ctx = FnInfo::new();
|
|
1298
1309
|
fn_ctx.is_memo = true;
|
|
1299
1310
|
|
|
1300
|
-
let mut scope = Scope::new();
|
|
1311
|
+
let mut scope = Scope::new(state.top_scope_key());
|
|
1301
1312
|
scope.is_fn = true;
|
|
1302
1313
|
|
|
1303
1314
|
// TODO it's confusing that we need to
|
|
@@ -1467,7 +1478,8 @@ impl<'src> SStmtExt<'src> for Indirect<SStmt<'src>> {
|
|
|
1467
1478
|
let (pattern, scope, _meta) = pattern_scoped(state, pattern);
|
|
1468
1479
|
(Some(pattern), scope)
|
|
1469
1480
|
} else {
|
|
1470
|
-
|
|
1481
|
+
let parent = state.top_scope_key();
|
|
1482
|
+
(None, state.scopes.insert(Scope::new(parent)))
|
|
1471
1483
|
};
|
|
1472
1484
|
|
|
1473
1485
|
let body = state
|