koatl 0.1.24__tar.gz → 0.1.26__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.24 → koatl-0.1.26}/Cargo.lock +1 -1
- {koatl-0.1.24 → koatl-0.1.26}/PKG-INFO +1 -1
- {koatl-0.1.24 → koatl-0.1.26}/koatl/Cargo.toml +1 -1
- {koatl-0.1.24 → koatl-0.1.26}/koatl/python/koatl/prelude/functional/__init__.tl +1 -1
- koatl-0.1.26/koatl/python/koatl/prelude/functional/algebra.tl +46 -0
- {koatl-0.1.24 → koatl-0.1.26}/koatl/python/koatl/prelude/functional/async.tl +3 -3
- {koatl-0.1.24 → koatl-0.1.26/koatl}/python/koatl/prelude/functional/list.tl +1 -1
- {koatl-0.1.24 → koatl-0.1.26}/koatl/python/koatl/prelude/functional/memo.tl +21 -11
- {koatl-0.1.24 → koatl-0.1.26/koatl}/python/koatl/prelude/functional/reader.tl +2 -2
- {koatl-0.1.24 → koatl-0.1.26/koatl}/python/koatl/prelude/functional/result.tl +45 -29
- {koatl-0.1.24 → koatl-0.1.26/koatl}/python/koatl/prelude/iterable.tl +2 -2
- {koatl-0.1.24 → koatl-0.1.26/koatl}/python/koatl/runtime/__init__.py +16 -7
- {koatl-0.1.24 → koatl-0.1.26}/koatl/python/koatl/runtime/helpers.py +9 -6
- {koatl-0.1.24 → koatl-0.1.26}/koatl/python/koatl/runtime/virtual.py +2 -1
- {koatl-0.1.24 → koatl-0.1.26}/koatl/tests/e2e/base/coal.tl +0 -12
- koatl-0.1.26/koatl/tests/e2e/base/loops.tl +25 -0
- {koatl-0.1.24 → koatl-0.1.26}/koatl/tests/e2e/base/match.tl +0 -2
- koatl-0.1.26/koatl/tests/e2e/base/short_circuit.tl +42 -0
- {koatl-0.1.24 → koatl-0.1.26}/koatl/tests/e2e/prelude/memo.tl +1 -1
- {koatl-0.1.24/koatl/tests/e2e/base → koatl-0.1.26/koatl/tests/e2e/prelude}/try.tl +11 -4
- {koatl-0.1.24 → koatl-0.1.26}/koatl-core/parser/src/ast.rs +1 -1
- {koatl-0.1.24 → koatl-0.1.26}/koatl-core/parser/src/parser.rs +0 -1
- {koatl-0.1.24 → koatl-0.1.26}/koatl-core/src/py/emit.rs +2 -6
- {koatl-0.1.24 → koatl-0.1.26}/koatl-core/src/resolve_scopes.rs +138 -44
- {koatl-0.1.24 → koatl-0.1.26}/koatl-core/src/transform.rs +207 -145
- {koatl-0.1.24 → koatl-0.1.26}/python/koatl/prelude/functional/__init__.tl +1 -1
- koatl-0.1.26/python/koatl/prelude/functional/algebra.tl +46 -0
- {koatl-0.1.24 → koatl-0.1.26}/python/koatl/prelude/functional/async.tl +3 -3
- {koatl-0.1.24/koatl → koatl-0.1.26}/python/koatl/prelude/functional/list.tl +1 -1
- {koatl-0.1.24 → koatl-0.1.26}/python/koatl/prelude/functional/memo.tl +21 -11
- {koatl-0.1.24/koatl → koatl-0.1.26}/python/koatl/prelude/functional/reader.tl +2 -2
- {koatl-0.1.24/koatl → koatl-0.1.26}/python/koatl/prelude/functional/result.tl +45 -29
- {koatl-0.1.24/koatl → koatl-0.1.26}/python/koatl/prelude/iterable.tl +2 -2
- {koatl-0.1.24/koatl → koatl-0.1.26}/python/koatl/runtime/__init__.py +16 -7
- {koatl-0.1.24 → koatl-0.1.26}/python/koatl/runtime/helpers.py +9 -6
- {koatl-0.1.24 → koatl-0.1.26}/python/koatl/runtime/virtual.py +2 -1
- koatl-0.1.24/koatl/python/koatl/prelude/functional/monad.tl +0 -20
- koatl-0.1.24/koatl/tests/e2e/base/loops.tl +0 -14
- koatl-0.1.24/python/koatl/prelude/functional/monad.tl +0 -20
- {koatl-0.1.24 → koatl-0.1.26}/Cargo.toml +0 -0
- {koatl-0.1.24 → koatl-0.1.26}/README.md +0 -0
- {koatl-0.1.24 → koatl-0.1.26}/koatl/.github/workflows/CI.yml +0 -0
- {koatl-0.1.24 → koatl-0.1.26}/koatl/.gitignore +0 -0
- {koatl-0.1.24 → koatl-0.1.26}/koatl/LICENSE +0 -0
- {koatl-0.1.24 → koatl-0.1.26}/koatl/README.md +0 -0
- {koatl-0.1.24 → koatl-0.1.26}/koatl/python/koatl/__init__.py +0 -0
- {koatl-0.1.24 → koatl-0.1.26}/koatl/python/koatl/__main__.py +0 -0
- {koatl-0.1.24 → koatl-0.1.26}/koatl/python/koatl/cli.py +0 -0
- {koatl-0.1.24 → koatl-0.1.26}/koatl/python/koatl/notebook/__init__.py +0 -0
- {koatl-0.1.24 → koatl-0.1.26}/koatl/python/koatl/notebook/magic.py +0 -0
- {koatl-0.1.24 → koatl-0.1.26}/koatl/python/koatl/prelude/__init__.tl +0 -0
- {koatl-0.1.24 → koatl-0.1.26}/koatl/python/koatl/prelude/functional/async_util.py +0 -0
- {koatl-0.1.24 → koatl-0.1.26}/koatl/python/koatl/runtime/meta_finder.py +0 -0
- {koatl-0.1.24 → koatl-0.1.26}/koatl/python/koatl/runtime/record.py +0 -0
- {koatl-0.1.24 → koatl-0.1.26}/koatl/requirements.txt +0 -0
- {koatl-0.1.24 → koatl-0.1.26}/koatl/src/emit_py.rs +0 -0
- {koatl-0.1.24 → koatl-0.1.26}/koatl/src/lib.rs +0 -0
- {koatl-0.1.24 → koatl-0.1.26}/koatl/tests/e2e/base/containers.tl +0 -0
- {koatl-0.1.24 → koatl-0.1.26}/koatl/tests/e2e/base/decorators.tl +0 -0
- {koatl-0.1.24 → koatl-0.1.26}/koatl/tests/e2e/base/destructure-for-and-fn.tl +0 -0
- {koatl-0.1.24 → koatl-0.1.26}/koatl/tests/e2e/base/destructure.tl +0 -0
- {koatl-0.1.24 → koatl-0.1.26}/koatl/tests/e2e/base/escape_ident.tl +0 -0
- {koatl-0.1.24 → koatl-0.1.26}/koatl/tests/e2e/base/fstr.tl +0 -0
- {koatl-0.1.24 → koatl-0.1.26}/koatl/tests/e2e/base/functions.tl +0 -0
- {koatl-0.1.24 → koatl-0.1.26}/koatl/tests/e2e/base/generator.tl +0 -0
- {koatl-0.1.24 → koatl-0.1.26}/koatl/tests/e2e/base/if_expr.tl +0 -0
- {koatl-0.1.24 → koatl-0.1.26}/koatl/tests/e2e/base/imports.tl +0 -0
- {koatl-0.1.24 → koatl-0.1.26}/koatl/tests/e2e/base/nary-list.tl +0 -0
- {koatl-0.1.24 → koatl-0.1.26}/koatl/tests/e2e/base/placeholder.tl +0 -0
- {koatl-0.1.24 → koatl-0.1.26}/koatl/tests/e2e/base/precedence.tl +0 -0
- {koatl-0.1.24 → koatl-0.1.26}/koatl/tests/e2e/base/scopes.tl +0 -0
- {koatl-0.1.24 → koatl-0.1.26}/koatl/tests/e2e/base/semantic_whitespace.tl +0 -0
- {koatl-0.1.24 → koatl-0.1.26}/koatl/tests/e2e/destructure.tl +0 -0
- {koatl-0.1.24 → koatl-0.1.26}/koatl/tests/e2e/prelude/async.tl +0 -0
- {koatl-0.1.24 → koatl-0.1.26}/koatl/tests/e2e/prelude/iterables.tl +0 -0
- {koatl-0.1.24 → koatl-0.1.26}/koatl/tests/e2e/prelude/list.tl +0 -0
- {koatl-0.1.24 → koatl-0.1.26}/koatl/tests/e2e/prelude/reader.tl +0 -0
- {koatl-0.1.24 → koatl-0.1.26}/koatl/tests/e2e/prelude/result.tl +0 -0
- {koatl-0.1.24/koatl/tests/e2e/base → koatl-0.1.26/koatl/tests/e2e/prelude}/slice.tl +0 -0
- {koatl-0.1.24 → koatl-0.1.26}/koatl/tests/e2e/prelude/virtual.tl +0 -0
- {koatl-0.1.24 → koatl-0.1.26}/koatl/tests/e2e/util/__init__.py +0 -0
- {koatl-0.1.24 → koatl-0.1.26}/koatl/tests/e2e/util/module0.tl +0 -0
- {koatl-0.1.24 → koatl-0.1.26}/koatl/tests/e2e/util/module1.tl +0 -0
- {koatl-0.1.24 → koatl-0.1.26}/koatl/tests/e2e/util/module2.tl +0 -0
- {koatl-0.1.24 → koatl-0.1.26}/koatl/tests/parse/arith.tl +0 -0
- {koatl-0.1.24 → koatl-0.1.26}/koatl/tests/parse/assign.tl +0 -0
- {koatl-0.1.24 → koatl-0.1.26}/koatl/tests/parse/block-comments.tl +0 -0
- {koatl-0.1.24 → koatl-0.1.26}/koatl/tests/parse/deco.tl +0 -0
- {koatl-0.1.24 → koatl-0.1.26}/koatl/tests/parse/func.tl +0 -0
- {koatl-0.1.24 → koatl-0.1.26}/koatl/tests/parse/matches.tl +0 -0
- {koatl-0.1.24 → koatl-0.1.26}/koatl/tests/test_e2e.py +0 -0
- {koatl-0.1.24 → koatl-0.1.26}/koatl/tests/test_parse.py +0 -0
- {koatl-0.1.24 → koatl-0.1.26}/koatl-core/Cargo.toml +0 -0
- {koatl-0.1.24 → koatl-0.1.26}/koatl-core/parser/Cargo.toml +0 -0
- {koatl-0.1.24 → koatl-0.1.26}/koatl-core/parser/src/lexer.rs +0 -0
- {koatl-0.1.24 → koatl-0.1.26}/koatl-core/parser/src/lib.rs +0 -0
- {koatl-0.1.24 → koatl-0.1.26}/koatl-core/parser/src/util.rs +0 -0
- {koatl-0.1.24 → koatl-0.1.26}/koatl-core/parser/tests/lexer.rs +0 -0
- {koatl-0.1.24 → koatl-0.1.26}/koatl-core/src/inference.rs +0 -0
- {koatl-0.1.24 → koatl-0.1.26}/koatl-core/src/lib.rs +0 -0
- {koatl-0.1.24 → koatl-0.1.26}/koatl-core/src/main.rs +0 -0
- {koatl-0.1.24 → koatl-0.1.26}/koatl-core/src/parse_timer.rs +0 -0
- {koatl-0.1.24 → koatl-0.1.26}/koatl-core/src/parser.rs +0 -0
- {koatl-0.1.24 → koatl-0.1.26}/koatl-core/src/py/ast.rs +0 -0
- {koatl-0.1.24 → koatl-0.1.26}/koatl-core/src/py/mod.rs +0 -0
- {koatl-0.1.24 → koatl-0.1.26}/koatl-core/src/py/util.rs +0 -0
- {koatl-0.1.24 → koatl-0.1.26}/koatl-core/src/types.rs +0 -0
- {koatl-0.1.24 → koatl-0.1.26}/koatl-core/src/util.rs +0 -0
- {koatl-0.1.24 → koatl-0.1.26}/pyproject.toml +0 -0
- {koatl-0.1.24 → koatl-0.1.26}/python/koatl/__init__.py +0 -0
- {koatl-0.1.24 → koatl-0.1.26}/python/koatl/__main__.py +0 -0
- {koatl-0.1.24 → koatl-0.1.26}/python/koatl/cli.py +0 -0
- {koatl-0.1.24 → koatl-0.1.26}/python/koatl/notebook/__init__.py +0 -0
- {koatl-0.1.24 → koatl-0.1.26}/python/koatl/notebook/magic.py +0 -0
- {koatl-0.1.24 → koatl-0.1.26}/python/koatl/prelude/__init__.tl +0 -0
- {koatl-0.1.24 → koatl-0.1.26}/python/koatl/prelude/functional/async_util.py +0 -0
- {koatl-0.1.24 → koatl-0.1.26}/python/koatl/runtime/meta_finder.py +0 -0
- {koatl-0.1.24 → koatl-0.1.26}/python/koatl/runtime/record.py +0 -0
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import abc
|
|
2
|
+
|
|
3
|
+
export Monad = class(abc.ABC):
|
|
4
|
+
"""
|
|
5
|
+
Abstract base class for monads.
|
|
6
|
+
|
|
7
|
+
Subclasses must implement `bind` and `pure`.
|
|
8
|
+
Automatically provides standard monadic operations: bind_once, map, and apply.
|
|
9
|
+
"""
|
|
10
|
+
__slots__ = ()
|
|
11
|
+
|
|
12
|
+
bind = abc.abstractmethod& (self, f) => None
|
|
13
|
+
|
|
14
|
+
pure = staticmethod& abc.abstractmethod& value => None
|
|
15
|
+
|
|
16
|
+
# Automatically generated implementations.
|
|
17
|
+
map = (self, f) => self.bind(x => self.pure(f(x)))
|
|
18
|
+
apply = (self, f) => self.bind(x => f.map(fn => fn(x)))
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
# TODO: should this inherit from Monad?
|
|
22
|
+
export MonadOnce = class(abc.ABC):
|
|
23
|
+
"""
|
|
24
|
+
Abstract base class for single-use monads.
|
|
25
|
+
|
|
26
|
+
A MonadOnce can only be bound once, which is suitable for
|
|
27
|
+
use with Python generators that cannot be cloned or reused.
|
|
28
|
+
|
|
29
|
+
Subclasses must implement `bind_once` and `pure`.
|
|
30
|
+
Automatically provides (likely suboptimal) standard monadic operations: bind, map, and apply.
|
|
31
|
+
"""
|
|
32
|
+
__slots__ = ()
|
|
33
|
+
|
|
34
|
+
# The default implementation required for `@` syntax that should be overridden by subclasses.
|
|
35
|
+
bind_once = abc.abstractmethod& (self, f) => None
|
|
36
|
+
|
|
37
|
+
pure = staticmethod& abc.abstractmethod& value => None
|
|
38
|
+
|
|
39
|
+
# An optional, optimized implementation of `bind` that skips deep recursion.
|
|
40
|
+
# TODO: can this be automatically generated from bind_once?
|
|
41
|
+
# bind_gen = (self, gen) => ...
|
|
42
|
+
|
|
43
|
+
# Automatically generated implementations.
|
|
44
|
+
bind = (self, f) => self.bind_once(f)
|
|
45
|
+
map = (self, f) => self.bind(x => self.pure(f(x)))
|
|
46
|
+
apply = (self, f) => self.bind(x => f.map(fn => fn(x)))
|
|
@@ -2,9 +2,9 @@ import functools.wraps
|
|
|
2
2
|
import asyncio
|
|
3
3
|
|
|
4
4
|
import .async_util
|
|
5
|
-
import .
|
|
5
|
+
import .MonadOnce
|
|
6
6
|
|
|
7
|
-
export Async = class(
|
|
7
|
+
export Async = class(MonadOnce):
|
|
8
8
|
__init__ = (self, awaitable) => self.generator = awaitable.__await__()
|
|
9
9
|
|
|
10
10
|
__await__ = self => self.generator
|
|
@@ -39,5 +39,5 @@ export Async = class(Monad):
|
|
|
39
39
|
|
|
40
40
|
sleep = staticmethod& x => Async(asyncio.sleep(x))
|
|
41
41
|
|
|
42
|
-
|
|
42
|
+
# TODO: Why is asyncio.gather eager?
|
|
43
43
|
gather = staticmethod& (*args) => Async.from_generator_fn& () => yield from asyncio.gather(*args)
|
|
@@ -1,18 +1,16 @@
|
|
|
1
1
|
import collections.defaultdict
|
|
2
2
|
import functools.wraps
|
|
3
3
|
import .result.(Result, Ok)
|
|
4
|
-
import .
|
|
4
|
+
import .MonadOnce
|
|
5
5
|
|
|
6
|
-
export Memo = class(
|
|
6
|
+
export Memo = class(MonadOnce):
|
|
7
7
|
Cache = class:
|
|
8
8
|
__init__ = self =>
|
|
9
9
|
self.cache = defaultdict(dict)
|
|
10
10
|
|
|
11
11
|
__repr__ = self => f"Memo.Cache({self.cache})"
|
|
12
12
|
|
|
13
|
-
try_get = (self, name, deps) =>
|
|
14
|
-
# TODO should try operator return a Result directly?
|
|
15
|
-
Result(try self.cache[name][deps] except KeyError())
|
|
13
|
+
try_get = (self, name, deps) => try self.cache[name][deps] except KeyError()
|
|
16
14
|
|
|
17
15
|
update = (self, name, deps, value) =>
|
|
18
16
|
self.cache[name][deps] = value
|
|
@@ -22,6 +20,17 @@ export Memo = class(Monad):
|
|
|
22
20
|
|
|
23
21
|
__repr__ = self => f"Memo(...)"
|
|
24
22
|
|
|
23
|
+
# This needs to be special cased because if we try to use Memo.value
|
|
24
|
+
# directly, the *generator* itself gets memoized. We want to memoize
|
|
25
|
+
# the thing that that comes out of the generator.
|
|
26
|
+
bind_value = staticmethod& (id, deps, f) =>
|
|
27
|
+
Memo(ctx =>
|
|
28
|
+
if ctx.try_get(id, tuple(deps)) matches Ok(value):
|
|
29
|
+
return value
|
|
30
|
+
|
|
31
|
+
ctx.update(id, tuple(deps), f().f(ctx))
|
|
32
|
+
)
|
|
33
|
+
|
|
25
34
|
value = staticmethod& (id, deps, f) =>
|
|
26
35
|
Memo(ctx =>
|
|
27
36
|
if ctx.try_get(id, tuple(deps)) matches Ok(value):
|
|
@@ -40,7 +49,7 @@ export Memo = class(Monad):
|
|
|
40
49
|
|
|
41
50
|
let v = f(*args, **kwargs)
|
|
42
51
|
if v matches Memo():
|
|
43
|
-
v = v.
|
|
52
|
+
v = v.f(ctx)
|
|
44
53
|
|
|
45
54
|
ctx.update(id, deps, v)
|
|
46
55
|
)
|
|
@@ -53,21 +62,22 @@ export Memo = class(Monad):
|
|
|
53
62
|
pure = staticmethod& value => Memo(ctx => value)
|
|
54
63
|
|
|
55
64
|
bind_once = (self, f) => Memo(ctx =>
|
|
56
|
-
let value = f(self.
|
|
65
|
+
let value = f(self.f(ctx))
|
|
57
66
|
if value matches Memo():
|
|
58
|
-
value = value.
|
|
67
|
+
value = value.f(ctx)
|
|
59
68
|
value
|
|
60
69
|
)
|
|
61
70
|
|
|
62
71
|
bind_gen = (self, gen) => Memo(ctx =>
|
|
63
|
-
self = self.
|
|
72
|
+
self = self.f(ctx)
|
|
64
73
|
try:
|
|
65
74
|
while True:
|
|
66
75
|
self = gen.send(self)
|
|
67
76
|
if self matches Memo():
|
|
68
|
-
self = self.
|
|
77
|
+
self = self.f(ctx)
|
|
69
78
|
except StopIteration(value=value):
|
|
70
79
|
return value
|
|
71
80
|
)
|
|
72
81
|
|
|
73
|
-
__tl__.
|
|
82
|
+
__tl__.memo_value = Memo.value
|
|
83
|
+
__tl__.bind_memo_value = Memo.bind_value
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import functools.wraps
|
|
2
|
-
import .monad.Monad
|
|
3
2
|
import koatl.runtime.virtual.register_global_attr
|
|
3
|
+
import .algebra.MonadOnce
|
|
4
4
|
|
|
5
|
-
export Result = class:
|
|
5
|
+
export Result = class(MonadOnce):
|
|
6
6
|
__slots__ = ()
|
|
7
7
|
__match_args__ = ("value",)
|
|
8
8
|
|
|
@@ -14,24 +14,15 @@ export Result = class:
|
|
|
14
14
|
__init__ = (self, *args, **kwargs) =>
|
|
15
15
|
raise ValueError("Result should not be instantiated directly, use Ok or Err")
|
|
16
16
|
|
|
17
|
-
|
|
17
|
+
checked = staticmethod& f =>
|
|
18
18
|
"""
|
|
19
|
-
|
|
20
|
-
|
|
19
|
+
Runs the function in a try block and returns a Result.
|
|
20
|
+
If the function raises an exception, it will be wrapped in an Err.
|
|
21
21
|
"""
|
|
22
|
-
|
|
23
|
-
return
|
|
24
|
-
|
|
25
|
-
|
|
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
|
|
22
|
+
try:
|
|
23
|
+
return Ok(f())
|
|
24
|
+
except BaseException() as e:
|
|
25
|
+
return Err(e)
|
|
35
26
|
|
|
36
27
|
bind_once = (self, f) =>
|
|
37
28
|
self = Result(self)
|
|
@@ -96,8 +87,14 @@ export Ok = class(Result):
|
|
|
96
87
|
return None
|
|
97
88
|
self.value = value
|
|
98
89
|
|
|
90
|
+
__eq__ = (self, other) =>
|
|
91
|
+
if not isinstance(other, Ok):
|
|
92
|
+
return False
|
|
93
|
+
return self.value == other.value
|
|
94
|
+
|
|
99
95
|
__repr__ = self => f"Ok({repr(self.value)})"
|
|
100
96
|
unwrap = self => self.value
|
|
97
|
+
coalesce = (self, f) => self.value
|
|
101
98
|
|
|
102
99
|
export Err = class(Result):
|
|
103
100
|
__slots__ = ("value",)
|
|
@@ -108,24 +105,43 @@ export Err = class(Result):
|
|
|
108
105
|
return None
|
|
109
106
|
self.value = value
|
|
110
107
|
|
|
108
|
+
__eq__ = (self, other) =>
|
|
109
|
+
if not isinstance(other, Err):
|
|
110
|
+
return False
|
|
111
|
+
return self.value == other.value
|
|
112
|
+
|
|
111
113
|
__repr__ = self => f"Err({repr(self.value)})"
|
|
112
114
|
unwrap = self =>
|
|
113
115
|
if self.value matches BaseException():
|
|
114
116
|
raise self.value
|
|
115
117
|
raise ValueError(f"Expected Ok, got {repr(self.value)}")
|
|
118
|
+
coalesce = (self, f) => f()
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
register_global_attr(type(None), "ok", ExtensionProperty(_ => False))
|
|
122
|
+
register_global_attr(BaseException, "ok", ExtensionProperty(_ => False))
|
|
123
|
+
register_global_attr(object, "ok", ExtensionProperty(_ => True))
|
|
124
|
+
|
|
125
|
+
register_global_attr(object, "result", ExtensionProperty(Result))
|
|
126
|
+
|
|
127
|
+
# Enables @ operator for bare objects.
|
|
128
|
+
register_global_attr(object, "bind_gen", Result.bind_gen)
|
|
116
129
|
|
|
130
|
+
__tl__.Ok = Ok
|
|
131
|
+
__tl__.Err = Err
|
|
117
132
|
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
for name, method in Result.__dict__:
|
|
122
|
-
if name.startswith("_"):
|
|
123
|
-
continue
|
|
124
|
-
if name == "map":
|
|
125
|
-
continue
|
|
133
|
+
__tl__.op_coal = (x, f) =>
|
|
134
|
+
if x matches Result():
|
|
135
|
+
return x.coalesce(f)
|
|
126
136
|
|
|
127
|
-
|
|
137
|
+
if not x.ok:
|
|
138
|
+
return f()
|
|
139
|
+
return x
|
|
128
140
|
|
|
129
|
-
|
|
141
|
+
__tl__.op_map = (x, f) =>
|
|
142
|
+
if x matches Result():
|
|
143
|
+
return x.map(f)
|
|
130
144
|
|
|
131
|
-
|
|
145
|
+
if x.ok:
|
|
146
|
+
return f(x)
|
|
147
|
+
return x
|
|
@@ -21,13 +21,13 @@ methods = {
|
|
|
21
21
|
if not hasattr(m, "apply"):
|
|
22
22
|
# special case for bare types - slightly more efficient
|
|
23
23
|
# ...also required since bare types don't have .map
|
|
24
|
-
if not
|
|
24
|
+
if not m.ok:
|
|
25
25
|
return m
|
|
26
26
|
|
|
27
27
|
let acc = [m]
|
|
28
28
|
for v in it:
|
|
29
29
|
let fv = f(v)
|
|
30
|
-
if not
|
|
30
|
+
if not fv.ok:
|
|
31
31
|
return fv
|
|
32
32
|
acc.append(fv)
|
|
33
33
|
return acc
|
|
@@ -21,10 +21,13 @@ from .record import *
|
|
|
21
21
|
from .helpers import *
|
|
22
22
|
|
|
23
23
|
|
|
24
|
-
def
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
24
|
+
def dummy(name):
|
|
25
|
+
def wrapper(*args, **kwargs):
|
|
26
|
+
raise RuntimeError(
|
|
27
|
+
f"{name} is not available without the prelude. Please import koatl.prelude."
|
|
28
|
+
)
|
|
29
|
+
|
|
30
|
+
return wrapper
|
|
28
31
|
|
|
29
32
|
|
|
30
33
|
__tl__ = SimpleNamespace(
|
|
@@ -32,15 +35,21 @@ __tl__ = SimpleNamespace(
|
|
|
32
35
|
slice=slice,
|
|
33
36
|
vget=virtual.vget,
|
|
34
37
|
vhas=virtual.vhas,
|
|
35
|
-
memo=dummy_memo,
|
|
36
38
|
unpack_record=helpers.unpack_record,
|
|
37
39
|
set_exports=helpers.set_exports,
|
|
38
40
|
do=helpers.do,
|
|
39
|
-
ok=helpers.ok,
|
|
40
41
|
partial=functools.partial,
|
|
42
|
+
# These require more complex logic and require the prelude.
|
|
43
|
+
# The runtime provides dummy implementations that raise if used without the prelude.
|
|
44
|
+
memo_value=dummy("memo"),
|
|
45
|
+
bind_memo_value=dummy("memo"),
|
|
46
|
+
op_map=dummy("?"),
|
|
47
|
+
op_coal=("??"),
|
|
48
|
+
Ok=dummy("try-expr"),
|
|
49
|
+
Err=dummy("try-expr"),
|
|
41
50
|
**{name: helpers.__dict__[name] for name in helpers.__all__},
|
|
42
51
|
**{name: record.__dict__[name] for name in record.__all__},
|
|
43
|
-
**{name: virtual.__dict__[name] for name in virtual.__all__}
|
|
52
|
+
**{name: virtual.__dict__[name] for name in virtual.__all__},
|
|
44
53
|
)
|
|
45
54
|
|
|
46
55
|
|
|
@@ -66,6 +66,10 @@ def do(f):
|
|
|
66
66
|
try:
|
|
67
67
|
m = gen.send(None)
|
|
68
68
|
except StopIteration as e:
|
|
69
|
+
if not hasattr(e.value, "bind_once"):
|
|
70
|
+
raise ValueError(
|
|
71
|
+
"This do-block returned a bare value before it could infer the monadic type. Wrap the value in pure()."
|
|
72
|
+
) from None
|
|
69
73
|
return e.value
|
|
70
74
|
|
|
71
75
|
def recurse(v):
|
|
@@ -74,17 +78,16 @@ def do(f):
|
|
|
74
78
|
m = gen.send(v)
|
|
75
79
|
return vget(m, "bind_once")(recurse)
|
|
76
80
|
except StopIteration as e:
|
|
77
|
-
|
|
78
|
-
return vget(m, "pure")(e.value)
|
|
79
|
-
except AttributeError:
|
|
80
|
-
return e.value
|
|
81
|
+
return vget(m, "pure")(e.value)
|
|
81
82
|
|
|
82
83
|
try:
|
|
83
84
|
# TODO: this is a workaround to avoid recursion.
|
|
84
85
|
# is it possible to derive bind_gen directly from bind_once?
|
|
85
86
|
|
|
86
|
-
|
|
87
|
-
except
|
|
87
|
+
bind_gen = vget(m, "bind_gen")
|
|
88
|
+
except AttributeError:
|
|
88
89
|
return vget(m, "bind_once")(recurse)
|
|
89
90
|
|
|
91
|
+
return bind_gen(gen)
|
|
92
|
+
|
|
90
93
|
return impl
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import abc
|
|
1
2
|
from functools import partial
|
|
2
3
|
from itertools import count
|
|
3
4
|
from types import new_class
|
|
@@ -105,7 +106,7 @@ def Trait(module, name, methods, *, requires=[]):
|
|
|
105
106
|
|
|
106
107
|
meta = type(
|
|
107
108
|
f"{name}Meta",
|
|
108
|
-
(
|
|
109
|
+
(abc.ABCMeta,),
|
|
109
110
|
{"__instancecheck__": instancecheck, "__module__": "types"},
|
|
110
111
|
)
|
|
111
112
|
|
|
@@ -17,15 +17,3 @@ assert_eq(1?.($ + 1)(), 2)
|
|
|
17
17
|
|
|
18
18
|
assert_eq(None ?? 1, 1)
|
|
19
19
|
assert_eq(int(5) ?? 1, 5)
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
# try exprs
|
|
23
|
-
|
|
24
|
-
assert_eq(type(try x), NameError)
|
|
25
|
-
assert_eq(type(try int(1)[1]), TypeError)
|
|
26
|
-
assert_eq(type(try [0][5]), IndexError)
|
|
27
|
-
assert_eq(try 5, 5)
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
assert_eq((try 5)?.($+1)?(), 6)
|
|
31
|
-
assert_eq(type((try x)?.($+1)?()), NameError)
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import util.assert_eq
|
|
2
|
+
|
|
3
|
+
x = []
|
|
4
|
+
for i in [1, 2, 3]:
|
|
5
|
+
x = [*x, i]
|
|
6
|
+
|
|
7
|
+
assert_eq(x, [1, 2, 3])
|
|
8
|
+
|
|
9
|
+
i = True
|
|
10
|
+
while (x => x)(i):
|
|
11
|
+
if i === False:
|
|
12
|
+
assert False
|
|
13
|
+
|
|
14
|
+
i = False
|
|
15
|
+
|
|
16
|
+
counts = []
|
|
17
|
+
counter = 0
|
|
18
|
+
while (
|
|
19
|
+
counter = counter + 1
|
|
20
|
+
counter < 5
|
|
21
|
+
):
|
|
22
|
+
counts.append(counter)
|
|
23
|
+
|
|
24
|
+
assert_eq(counter, 5)
|
|
25
|
+
assert_eq(counts, [1, 2, 3, 4])
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import util.assert_eq
|
|
2
|
+
|
|
3
|
+
assert_eq(
|
|
4
|
+
True and False
|
|
5
|
+
False
|
|
6
|
+
)
|
|
7
|
+
|
|
8
|
+
# No short-circuiting here.
|
|
9
|
+
|
|
10
|
+
flag = 0
|
|
11
|
+
assert_eq(
|
|
12
|
+
True and (
|
|
13
|
+
flag = 1
|
|
14
|
+
True
|
|
15
|
+
)
|
|
16
|
+
True
|
|
17
|
+
)
|
|
18
|
+
assert_eq(flag, 1)
|
|
19
|
+
|
|
20
|
+
# This needs to short-circuit.
|
|
21
|
+
|
|
22
|
+
flag = 0
|
|
23
|
+
assert_eq(
|
|
24
|
+
False and (
|
|
25
|
+
flag = 1
|
|
26
|
+
True
|
|
27
|
+
)
|
|
28
|
+
False
|
|
29
|
+
)
|
|
30
|
+
assert_eq(flag, 0)
|
|
31
|
+
|
|
32
|
+
# Same with or
|
|
33
|
+
|
|
34
|
+
flag = 0
|
|
35
|
+
assert_eq(
|
|
36
|
+
True or (
|
|
37
|
+
flag = 1
|
|
38
|
+
True
|
|
39
|
+
)
|
|
40
|
+
True
|
|
41
|
+
)
|
|
42
|
+
assert_eq(flag, 0)
|
|
@@ -3,12 +3,14 @@ import util.assert_eq
|
|
|
3
3
|
# precedence
|
|
4
4
|
assert_eq(try 1 ?? 2, 1)
|
|
5
5
|
assert_eq(try z ?? 2, 2)
|
|
6
|
-
assert_eq(
|
|
6
|
+
assert_eq(try z matches Err(), True)
|
|
7
|
+
assert_eq((try z).value matches NameError(), True)
|
|
7
8
|
assert_eq(try z ?? try 1 ?? 2, 1)
|
|
8
|
-
assert_eq(try z ?? try None ?? 2,
|
|
9
|
+
assert_eq(try z ?? try None ?? 2, None)
|
|
10
|
+
assert_eq(try z ?? Err(None) ?? 2, 2)
|
|
9
11
|
|
|
10
12
|
err_type = NameError
|
|
11
|
-
assert_eq(
|
|
13
|
+
assert_eq(try a except err_type() matches Err(), True)
|
|
12
14
|
|
|
13
15
|
# handlers
|
|
14
16
|
assert_eq(try 1 except ValueError() ?? 2, 1)
|
|
@@ -19,4 +21,9 @@ try:
|
|
|
19
21
|
try a except (ValueError() | StopIteration())
|
|
20
22
|
assert False
|
|
21
23
|
except:
|
|
22
|
-
None
|
|
24
|
+
None
|
|
25
|
+
|
|
26
|
+
assert_eq(try 1 matches Ok(1), True)
|
|
27
|
+
|
|
28
|
+
assert_eq((try 5)?.($+1)?(), Ok(6))
|
|
29
|
+
assert_eq((try x)?.($+1)?() matches Err(), True)
|
|
@@ -210,7 +210,6 @@ where
|
|
|
210
210
|
if items.len() == 1 && last_comma.is_none() {
|
|
211
211
|
let item = items.into_iter().next().unwrap();
|
|
212
212
|
if let PatternSequenceItem::Item(inner) = item {
|
|
213
|
-
// TODO ???
|
|
214
213
|
inner.extract()
|
|
215
214
|
} else {
|
|
216
215
|
Pattern::Sequence(vec![item]).spanned(e.span())
|
|
@@ -456,21 +456,18 @@ impl SPyExpr<'_> {
|
|
|
456
456
|
ctx.emit("]");
|
|
457
457
|
}
|
|
458
458
|
PyExpr::Yield(expr) => {
|
|
459
|
-
set_prec(-0.5);
|
|
460
459
|
ctx.emit("(");
|
|
461
460
|
ctx.emit("yield ");
|
|
462
461
|
expr.emit_to(ctx, LOW_PREC)?;
|
|
463
462
|
ctx.emit(")");
|
|
464
463
|
}
|
|
465
464
|
PyExpr::Await(expr) => {
|
|
466
|
-
|
|
467
|
-
ctx.emit_indent();
|
|
465
|
+
ctx.emit("(");
|
|
468
466
|
ctx.emit("await ");
|
|
469
467
|
expr.emit_to(ctx, LOW_PREC)?;
|
|
470
|
-
ctx.
|
|
468
|
+
ctx.emit(")");
|
|
471
469
|
}
|
|
472
470
|
PyExpr::YieldFrom(expr) => {
|
|
473
|
-
set_prec(-0.5); // TODO is this precedence correct?
|
|
474
471
|
ctx.emit("(");
|
|
475
472
|
ctx.emit("yield from ");
|
|
476
473
|
expr.emit_to(ctx, LOW_PREC)?;
|
|
@@ -511,7 +508,6 @@ impl SPyExpr<'_> {
|
|
|
511
508
|
}
|
|
512
509
|
}
|
|
513
510
|
PyExpr::IfExpr(cond, if_, else_) => {
|
|
514
|
-
// TODO precedence here?
|
|
515
511
|
ctx.emit("(");
|
|
516
512
|
if_.emit_to(ctx, LOW_PREC)?;
|
|
517
513
|
ctx.emit(" if ");
|