koatl 0.1.23__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.23 → koatl-0.1.24}/Cargo.lock +1 -1
- {koatl-0.1.23 → koatl-0.1.24}/PKG-INFO +1 -1
- {koatl-0.1.23 → koatl-0.1.24}/koatl/Cargo.toml +1 -1
- {koatl-0.1.23 → koatl-0.1.24/koatl}/python/koatl/prelude/functional/memo.tl +5 -4
- {koatl-0.1.23 → koatl-0.1.24/koatl}/python/koatl/prelude/functional/monad.tl +2 -0
- koatl-0.1.24/koatl/python/koatl/prelude/functional/result.tl +131 -0
- {koatl-0.1.23 → koatl-0.1.24}/koatl/python/koatl/runtime/helpers.py +5 -0
- {koatl-0.1.23 → koatl-0.1.24}/koatl/src/emit_py.rs +20 -3
- {koatl-0.1.23 → koatl-0.1.24}/koatl-core/src/resolve_scopes.rs +25 -13
- {koatl-0.1.23 → koatl-0.1.24}/koatl-core/src/transform.rs +46 -36
- {koatl-0.1.23/koatl → koatl-0.1.24}/python/koatl/prelude/functional/memo.tl +5 -4
- {koatl-0.1.23/koatl → koatl-0.1.24}/python/koatl/prelude/functional/monad.tl +2 -0
- koatl-0.1.24/python/koatl/prelude/functional/result.tl +131 -0
- {koatl-0.1.23 → koatl-0.1.24}/python/koatl/runtime/helpers.py +5 -0
- koatl-0.1.23/koatl/python/koatl/prelude/functional/result.tl +0 -90
- koatl-0.1.23/python/koatl/prelude/functional/result.tl +0 -90
- {koatl-0.1.23 → koatl-0.1.24}/Cargo.toml +0 -0
- {koatl-0.1.23 → koatl-0.1.24}/README.md +0 -0
- {koatl-0.1.23 → koatl-0.1.24}/koatl/.github/workflows/CI.yml +0 -0
- {koatl-0.1.23 → koatl-0.1.24}/koatl/.gitignore +0 -0
- {koatl-0.1.23 → koatl-0.1.24}/koatl/LICENSE +0 -0
- {koatl-0.1.23 → koatl-0.1.24}/koatl/README.md +0 -0
- {koatl-0.1.23 → koatl-0.1.24}/koatl/python/koatl/__init__.py +0 -0
- {koatl-0.1.23 → koatl-0.1.24}/koatl/python/koatl/__main__.py +0 -0
- {koatl-0.1.23 → koatl-0.1.24}/koatl/python/koatl/cli.py +0 -0
- {koatl-0.1.23 → koatl-0.1.24}/koatl/python/koatl/notebook/__init__.py +0 -0
- {koatl-0.1.23 → koatl-0.1.24}/koatl/python/koatl/notebook/magic.py +0 -0
- {koatl-0.1.23 → koatl-0.1.24}/koatl/python/koatl/prelude/__init__.tl +0 -0
- {koatl-0.1.23 → koatl-0.1.24}/koatl/python/koatl/prelude/functional/__init__.tl +0 -0
- {koatl-0.1.23 → koatl-0.1.24}/koatl/python/koatl/prelude/functional/async.tl +0 -0
- {koatl-0.1.23 → koatl-0.1.24}/koatl/python/koatl/prelude/functional/async_util.py +0 -0
- {koatl-0.1.23 → koatl-0.1.24}/koatl/python/koatl/prelude/functional/list.tl +0 -0
- {koatl-0.1.23 → koatl-0.1.24}/koatl/python/koatl/prelude/functional/reader.tl +0 -0
- {koatl-0.1.23 → koatl-0.1.24}/koatl/python/koatl/prelude/iterable.tl +0 -0
- {koatl-0.1.23 → koatl-0.1.24}/koatl/python/koatl/runtime/__init__.py +0 -0
- {koatl-0.1.23 → koatl-0.1.24}/koatl/python/koatl/runtime/meta_finder.py +0 -0
- {koatl-0.1.23 → koatl-0.1.24}/koatl/python/koatl/runtime/record.py +0 -0
- {koatl-0.1.23 → koatl-0.1.24}/koatl/python/koatl/runtime/virtual.py +0 -0
- {koatl-0.1.23 → koatl-0.1.24}/koatl/requirements.txt +0 -0
- {koatl-0.1.23 → koatl-0.1.24}/koatl/src/lib.rs +0 -0
- {koatl-0.1.23 → koatl-0.1.24}/koatl/tests/e2e/base/coal.tl +0 -0
- {koatl-0.1.23 → koatl-0.1.24}/koatl/tests/e2e/base/containers.tl +0 -0
- {koatl-0.1.23 → koatl-0.1.24}/koatl/tests/e2e/base/decorators.tl +0 -0
- {koatl-0.1.23 → koatl-0.1.24}/koatl/tests/e2e/base/destructure-for-and-fn.tl +0 -0
- {koatl-0.1.23 → koatl-0.1.24}/koatl/tests/e2e/base/destructure.tl +0 -0
- {koatl-0.1.23 → koatl-0.1.24}/koatl/tests/e2e/base/escape_ident.tl +0 -0
- {koatl-0.1.23 → koatl-0.1.24}/koatl/tests/e2e/base/fstr.tl +0 -0
- {koatl-0.1.23 → koatl-0.1.24}/koatl/tests/e2e/base/functions.tl +0 -0
- {koatl-0.1.23 → koatl-0.1.24}/koatl/tests/e2e/base/generator.tl +0 -0
- {koatl-0.1.23 → koatl-0.1.24}/koatl/tests/e2e/base/if_expr.tl +0 -0
- {koatl-0.1.23 → koatl-0.1.24}/koatl/tests/e2e/base/imports.tl +0 -0
- {koatl-0.1.23 → koatl-0.1.24}/koatl/tests/e2e/base/loops.tl +0 -0
- {koatl-0.1.23 → koatl-0.1.24}/koatl/tests/e2e/base/match.tl +0 -0
- {koatl-0.1.23 → koatl-0.1.24}/koatl/tests/e2e/base/nary-list.tl +0 -0
- {koatl-0.1.23 → koatl-0.1.24}/koatl/tests/e2e/base/placeholder.tl +0 -0
- {koatl-0.1.23 → koatl-0.1.24}/koatl/tests/e2e/base/precedence.tl +0 -0
- {koatl-0.1.23 → koatl-0.1.24}/koatl/tests/e2e/base/scopes.tl +0 -0
- {koatl-0.1.23 → koatl-0.1.24}/koatl/tests/e2e/base/semantic_whitespace.tl +0 -0
- {koatl-0.1.23 → koatl-0.1.24}/koatl/tests/e2e/base/slice.tl +0 -0
- {koatl-0.1.23 → koatl-0.1.24}/koatl/tests/e2e/base/try.tl +0 -0
- {koatl-0.1.23 → koatl-0.1.24}/koatl/tests/e2e/destructure.tl +0 -0
- {koatl-0.1.23 → koatl-0.1.24}/koatl/tests/e2e/prelude/async.tl +0 -0
- {koatl-0.1.23 → koatl-0.1.24}/koatl/tests/e2e/prelude/iterables.tl +0 -0
- {koatl-0.1.23 → koatl-0.1.24}/koatl/tests/e2e/prelude/list.tl +0 -0
- {koatl-0.1.23 → koatl-0.1.24}/koatl/tests/e2e/prelude/memo.tl +0 -0
- {koatl-0.1.23 → koatl-0.1.24}/koatl/tests/e2e/prelude/reader.tl +0 -0
- {koatl-0.1.23 → koatl-0.1.24}/koatl/tests/e2e/prelude/result.tl +0 -0
- {koatl-0.1.23 → koatl-0.1.24}/koatl/tests/e2e/prelude/virtual.tl +0 -0
- {koatl-0.1.23 → koatl-0.1.24}/koatl/tests/e2e/util/__init__.py +0 -0
- {koatl-0.1.23 → koatl-0.1.24}/koatl/tests/e2e/util/module0.tl +0 -0
- {koatl-0.1.23 → koatl-0.1.24}/koatl/tests/e2e/util/module1.tl +0 -0
- {koatl-0.1.23 → koatl-0.1.24}/koatl/tests/e2e/util/module2.tl +0 -0
- {koatl-0.1.23 → koatl-0.1.24}/koatl/tests/parse/arith.tl +0 -0
- {koatl-0.1.23 → koatl-0.1.24}/koatl/tests/parse/assign.tl +0 -0
- {koatl-0.1.23 → koatl-0.1.24}/koatl/tests/parse/block-comments.tl +0 -0
- {koatl-0.1.23 → koatl-0.1.24}/koatl/tests/parse/deco.tl +0 -0
- {koatl-0.1.23 → koatl-0.1.24}/koatl/tests/parse/func.tl +0 -0
- {koatl-0.1.23 → koatl-0.1.24}/koatl/tests/parse/matches.tl +0 -0
- {koatl-0.1.23 → koatl-0.1.24}/koatl/tests/test_e2e.py +0 -0
- {koatl-0.1.23 → koatl-0.1.24}/koatl/tests/test_parse.py +0 -0
- {koatl-0.1.23 → koatl-0.1.24}/koatl-core/Cargo.toml +0 -0
- {koatl-0.1.23 → koatl-0.1.24}/koatl-core/parser/Cargo.toml +0 -0
- {koatl-0.1.23 → koatl-0.1.24}/koatl-core/parser/src/ast.rs +0 -0
- {koatl-0.1.23 → koatl-0.1.24}/koatl-core/parser/src/lexer.rs +0 -0
- {koatl-0.1.23 → koatl-0.1.24}/koatl-core/parser/src/lib.rs +0 -0
- {koatl-0.1.23 → koatl-0.1.24}/koatl-core/parser/src/parser.rs +0 -0
- {koatl-0.1.23 → koatl-0.1.24}/koatl-core/parser/src/util.rs +0 -0
- {koatl-0.1.23 → koatl-0.1.24}/koatl-core/parser/tests/lexer.rs +0 -0
- {koatl-0.1.23 → koatl-0.1.24}/koatl-core/src/inference.rs +0 -0
- {koatl-0.1.23 → koatl-0.1.24}/koatl-core/src/lib.rs +0 -0
- {koatl-0.1.23 → koatl-0.1.24}/koatl-core/src/main.rs +0 -0
- {koatl-0.1.23 → koatl-0.1.24}/koatl-core/src/parse_timer.rs +0 -0
- {koatl-0.1.23 → koatl-0.1.24}/koatl-core/src/parser.rs +0 -0
- {koatl-0.1.23 → koatl-0.1.24}/koatl-core/src/py/ast.rs +0 -0
- {koatl-0.1.23 → koatl-0.1.24}/koatl-core/src/py/emit.rs +0 -0
- {koatl-0.1.23 → koatl-0.1.24}/koatl-core/src/py/mod.rs +0 -0
- {koatl-0.1.23 → koatl-0.1.24}/koatl-core/src/py/util.rs +0 -0
- {koatl-0.1.23 → koatl-0.1.24}/koatl-core/src/types.rs +0 -0
- {koatl-0.1.23 → koatl-0.1.24}/koatl-core/src/util.rs +0 -0
- {koatl-0.1.23 → koatl-0.1.24}/pyproject.toml +0 -0
- {koatl-0.1.23 → koatl-0.1.24}/python/koatl/__init__.py +0 -0
- {koatl-0.1.23 → koatl-0.1.24}/python/koatl/__main__.py +0 -0
- {koatl-0.1.23 → koatl-0.1.24}/python/koatl/cli.py +0 -0
- {koatl-0.1.23 → koatl-0.1.24}/python/koatl/notebook/__init__.py +0 -0
- {koatl-0.1.23 → koatl-0.1.24}/python/koatl/notebook/magic.py +0 -0
- {koatl-0.1.23 → koatl-0.1.24}/python/koatl/prelude/__init__.tl +0 -0
- {koatl-0.1.23 → koatl-0.1.24}/python/koatl/prelude/functional/__init__.tl +0 -0
- {koatl-0.1.23 → koatl-0.1.24}/python/koatl/prelude/functional/async.tl +0 -0
- {koatl-0.1.23 → koatl-0.1.24}/python/koatl/prelude/functional/async_util.py +0 -0
- {koatl-0.1.23 → koatl-0.1.24}/python/koatl/prelude/functional/list.tl +0 -0
- {koatl-0.1.23 → koatl-0.1.24}/python/koatl/prelude/functional/reader.tl +0 -0
- {koatl-0.1.23 → koatl-0.1.24}/python/koatl/prelude/iterable.tl +0 -0
- {koatl-0.1.23 → koatl-0.1.24}/python/koatl/runtime/__init__.py +0 -0
- {koatl-0.1.23 → koatl-0.1.24}/python/koatl/runtime/meta_finder.py +0 -0
- {koatl-0.1.23 → koatl-0.1.24}/python/koatl/runtime/record.py +0 -0
- {koatl-0.1.23 → koatl-0.1.24}/python/koatl/runtime/virtual.py +0 -0
|
@@ -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)
|
|
@@ -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))
|
|
@@ -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"),
|
|
@@ -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
|
|
@@ -14,7 +14,7 @@ use crate::{
|
|
|
14
14
|
};
|
|
15
15
|
use once_cell::sync::Lazy;
|
|
16
16
|
use parser::ast::*;
|
|
17
|
-
use slotmap::SlotMap;
|
|
17
|
+
use slotmap::{Key, SlotMap};
|
|
18
18
|
use std::hash::{Hash, Hasher};
|
|
19
19
|
|
|
20
20
|
static PY_KWS: &[&str] = &[
|
|
@@ -1404,25 +1404,9 @@ fn prepare_py_fn<'src, 'ast>(
|
|
|
1404
1404
|
decorators.push(a.tl_builtin("do"));
|
|
1405
1405
|
}
|
|
1406
1406
|
|
|
1407
|
-
let
|
|
1408
|
-
let mut globals = vec![];
|
|
1409
|
-
|
|
1410
|
-
for capture in fn_info.captures.iter() {
|
|
1411
|
-
let scope = &ctx.scopes[ctx.declarations[*capture].scope];
|
|
1412
|
-
if scope.is_global || scope.is_class {
|
|
1413
|
-
globals.push(ctx.decl_py_ident(*capture)?);
|
|
1414
|
-
} else {
|
|
1415
|
-
nonlocals.push(ctx.decl_py_ident(*capture)?);
|
|
1416
|
-
}
|
|
1417
|
-
}
|
|
1418
|
-
|
|
1419
|
-
if !nonlocals.is_empty() {
|
|
1420
|
-
py_body.push(a.nonlocal(nonlocals.iter().map(|x| x.clone()).collect()));
|
|
1421
|
-
}
|
|
1422
|
-
if !globals.is_empty() {
|
|
1423
|
-
py_body.push(a.global(globals.iter().map(|x| x.clone()).collect()));
|
|
1424
|
-
}
|
|
1407
|
+
let (py_bindings, _, _) = py_fn_bindings(ctx, fn_info, *span)?;
|
|
1425
1408
|
|
|
1409
|
+
py_body.extend(py_bindings);
|
|
1426
1410
|
py_body.extend(body.pre);
|
|
1427
1411
|
py_body.push(a.return_(body.value));
|
|
1428
1412
|
}
|
|
@@ -2257,24 +2241,9 @@ impl<'src, 'ast> SExprExt<'src, 'ast> for SExpr<'src> {
|
|
|
2257
2241
|
let py_expr = expr.transform(ctx)?;
|
|
2258
2242
|
let mut py_body = PyBlock::new();
|
|
2259
2243
|
|
|
2260
|
-
let
|
|
2261
|
-
let mut globals = vec![];
|
|
2262
|
-
|
|
2263
|
-
for capture in memo_captures.captures.iter() {
|
|
2264
|
-
if ctx.scopes[ctx.declarations[*capture].scope].is_global {
|
|
2265
|
-
globals.push(ctx.decl_py_ident(*capture)?);
|
|
2266
|
-
} else {
|
|
2267
|
-
nonlocals.push(ctx.decl_py_ident(*capture)?);
|
|
2268
|
-
}
|
|
2269
|
-
}
|
|
2270
|
-
|
|
2271
|
-
if !nonlocals.is_empty() {
|
|
2272
|
-
py_body.push(a.nonlocal(nonlocals.iter().map(|x| x.clone()).collect()));
|
|
2273
|
-
}
|
|
2274
|
-
if !globals.is_empty() {
|
|
2275
|
-
py_body.push(a.global(globals.iter().map(|x| x.clone()).collect()));
|
|
2276
|
-
}
|
|
2244
|
+
let (py_bindings, nonlocals, _globals) = py_fn_bindings(ctx, memo_captures, span)?;
|
|
2277
2245
|
|
|
2246
|
+
py_body.extend(py_bindings);
|
|
2278
2247
|
py_body.extend(py_expr.pre);
|
|
2279
2248
|
py_body.push(a.return_(py_expr.value));
|
|
2280
2249
|
|
|
@@ -2430,6 +2399,47 @@ impl<'src, 'ast> SExprExt<'src, 'ast> for SExpr<'src> {
|
|
|
2430
2399
|
}
|
|
2431
2400
|
}
|
|
2432
2401
|
|
|
2402
|
+
fn py_fn_bindings<'src, 'ast>(
|
|
2403
|
+
ctx: &mut TlCtx<'src, 'ast>,
|
|
2404
|
+
memo_captures: &FnInfo,
|
|
2405
|
+
span: Span,
|
|
2406
|
+
) -> TlResult<(PyBlock<'src>, Vec<PyIdent<'src>>, Vec<PyIdent<'src>>)> {
|
|
2407
|
+
let a = PyAstBuilder::new(span);
|
|
2408
|
+
|
|
2409
|
+
let mut nonlocals = vec![];
|
|
2410
|
+
let mut globals = vec![];
|
|
2411
|
+
let mut py_body = PyBlock::new();
|
|
2412
|
+
|
|
2413
|
+
for capture in memo_captures.captures.iter() {
|
|
2414
|
+
let mut scope = &ctx.scopes[ctx.declarations[*capture].scope];
|
|
2415
|
+
loop {
|
|
2416
|
+
if scope.parent.is_null() {
|
|
2417
|
+
break;
|
|
2418
|
+
}
|
|
2419
|
+
|
|
2420
|
+
if scope.is_fn || scope.is_class || scope.is_global {
|
|
2421
|
+
break;
|
|
2422
|
+
}
|
|
2423
|
+
scope = &ctx.scopes[scope.parent];
|
|
2424
|
+
}
|
|
2425
|
+
|
|
2426
|
+
if scope.is_global || scope.is_class {
|
|
2427
|
+
globals.push(ctx.decl_py_ident(*capture)?);
|
|
2428
|
+
} else {
|
|
2429
|
+
nonlocals.push(ctx.decl_py_ident(*capture)?);
|
|
2430
|
+
}
|
|
2431
|
+
}
|
|
2432
|
+
|
|
2433
|
+
if !nonlocals.is_empty() {
|
|
2434
|
+
py_body.push(a.nonlocal(nonlocals.iter().map(|x| x.clone()).collect()));
|
|
2435
|
+
}
|
|
2436
|
+
if !globals.is_empty() {
|
|
2437
|
+
py_body.push(a.global(globals.iter().map(|x| x.clone()).collect()));
|
|
2438
|
+
}
|
|
2439
|
+
|
|
2440
|
+
Ok((py_body, nonlocals, globals))
|
|
2441
|
+
}
|
|
2442
|
+
|
|
2433
2443
|
pub struct TransformOutput<'src> {
|
|
2434
2444
|
pub py_block: PyBlock<'src>,
|
|
2435
2445
|
pub exports: Vec<PyIdent<'src>>,
|
|
@@ -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)
|
|
@@ -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))
|
|
@@ -1,90 +0,0 @@
|
|
|
1
|
-
import functools.wraps
|
|
2
|
-
import .monad.Monad
|
|
3
|
-
import koatl.runtime.virtual.register_global_attr
|
|
4
|
-
|
|
5
|
-
export Result = class(Monad):
|
|
6
|
-
bind_once = (self, f) => self match:
|
|
7
|
-
Ok(value) => f(value)
|
|
8
|
-
Ok() => f(self)
|
|
9
|
-
default => self
|
|
10
|
-
|
|
11
|
-
bind = bind_once
|
|
12
|
-
|
|
13
|
-
bind_gen = (self, gen) =>
|
|
14
|
-
try:
|
|
15
|
-
while True:
|
|
16
|
-
if not __tl__.ok(self):
|
|
17
|
-
return self
|
|
18
|
-
|
|
19
|
-
if self matches Ok(value):
|
|
20
|
-
self = value
|
|
21
|
-
|
|
22
|
-
self = gen.send(self)
|
|
23
|
-
except StopIteration(value=value):
|
|
24
|
-
if value === None:
|
|
25
|
-
return Ok(None)
|
|
26
|
-
return value
|
|
27
|
-
|
|
28
|
-
pure = staticmethod& x => Ok(x)
|
|
29
|
-
|
|
30
|
-
apply = (self, f) =>
|
|
31
|
-
if not __tl__.ok(self):
|
|
32
|
-
return self
|
|
33
|
-
if not __tl__.ok(f):
|
|
34
|
-
return f
|
|
35
|
-
|
|
36
|
-
# unwrap the Oks - this is a bit weird
|
|
37
|
-
# but it allows bare types to be Results
|
|
38
|
-
if self matches Ok(value):
|
|
39
|
-
self = self.value
|
|
40
|
-
if f matches Ok(value):
|
|
41
|
-
f = f.value
|
|
42
|
-
|
|
43
|
-
f(self)
|
|
44
|
-
|
|
45
|
-
# Map must not be defined since it will override any special map
|
|
46
|
-
# implementation for traits, specifically for Iterable -
|
|
47
|
-
# is there a better way around this (in the vtable implementation)?
|
|
48
|
-
# map = ...
|
|
49
|
-
|
|
50
|
-
map_err = (self, f) =>
|
|
51
|
-
if self matches Err():
|
|
52
|
-
return f(self)
|
|
53
|
-
else:
|
|
54
|
-
return self
|
|
55
|
-
|
|
56
|
-
map_none = (self, f) =>
|
|
57
|
-
if self matches None:
|
|
58
|
-
return f()
|
|
59
|
-
else:
|
|
60
|
-
return self
|
|
61
|
-
|
|
62
|
-
OkMeta = class(type):
|
|
63
|
-
__instancecheck__ = (cls, instance) => __tl__.ok(instance)
|
|
64
|
-
|
|
65
|
-
export Ok = class(metaclass=OkMeta):
|
|
66
|
-
__match_args__ = ("value",)
|
|
67
|
-
|
|
68
|
-
__init__ = (self, value) =>
|
|
69
|
-
self.value = value
|
|
70
|
-
|
|
71
|
-
assert = staticmethod& value =>
|
|
72
|
-
value match:
|
|
73
|
-
BaseException() as e => raise e
|
|
74
|
-
None => raise ValueError("Expected a value, got None")
|
|
75
|
-
default value
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
# Since we are using a custom metaclass, we can't derive from Result
|
|
79
|
-
# so need to copy the methods over manually from Result
|
|
80
|
-
|
|
81
|
-
# We could just use the object fallback methods, but this avoids
|
|
82
|
-
# the vget so is slightly faster
|
|
83
|
-
for name, method in Result.__dict__:
|
|
84
|
-
if name.startswith("_"):
|
|
85
|
-
continue
|
|
86
|
-
|
|
87
|
-
setattr(Ok, name, method)
|
|
88
|
-
register_global_attr(object, name, method)
|
|
89
|
-
|
|
90
|
-
export Err = BaseException
|
|
@@ -1,90 +0,0 @@
|
|
|
1
|
-
import functools.wraps
|
|
2
|
-
import .monad.Monad
|
|
3
|
-
import koatl.runtime.virtual.register_global_attr
|
|
4
|
-
|
|
5
|
-
export Result = class(Monad):
|
|
6
|
-
bind_once = (self, f) => self match:
|
|
7
|
-
Ok(value) => f(value)
|
|
8
|
-
Ok() => f(self)
|
|
9
|
-
default => self
|
|
10
|
-
|
|
11
|
-
bind = bind_once
|
|
12
|
-
|
|
13
|
-
bind_gen = (self, gen) =>
|
|
14
|
-
try:
|
|
15
|
-
while True:
|
|
16
|
-
if not __tl__.ok(self):
|
|
17
|
-
return self
|
|
18
|
-
|
|
19
|
-
if self matches Ok(value):
|
|
20
|
-
self = value
|
|
21
|
-
|
|
22
|
-
self = gen.send(self)
|
|
23
|
-
except StopIteration(value=value):
|
|
24
|
-
if value === None:
|
|
25
|
-
return Ok(None)
|
|
26
|
-
return value
|
|
27
|
-
|
|
28
|
-
pure = staticmethod& x => Ok(x)
|
|
29
|
-
|
|
30
|
-
apply = (self, f) =>
|
|
31
|
-
if not __tl__.ok(self):
|
|
32
|
-
return self
|
|
33
|
-
if not __tl__.ok(f):
|
|
34
|
-
return f
|
|
35
|
-
|
|
36
|
-
# unwrap the Oks - this is a bit weird
|
|
37
|
-
# but it allows bare types to be Results
|
|
38
|
-
if self matches Ok(value):
|
|
39
|
-
self = self.value
|
|
40
|
-
if f matches Ok(value):
|
|
41
|
-
f = f.value
|
|
42
|
-
|
|
43
|
-
f(self)
|
|
44
|
-
|
|
45
|
-
# Map must not be defined since it will override any special map
|
|
46
|
-
# implementation for traits, specifically for Iterable -
|
|
47
|
-
# is there a better way around this (in the vtable implementation)?
|
|
48
|
-
# map = ...
|
|
49
|
-
|
|
50
|
-
map_err = (self, f) =>
|
|
51
|
-
if self matches Err():
|
|
52
|
-
return f(self)
|
|
53
|
-
else:
|
|
54
|
-
return self
|
|
55
|
-
|
|
56
|
-
map_none = (self, f) =>
|
|
57
|
-
if self matches None:
|
|
58
|
-
return f()
|
|
59
|
-
else:
|
|
60
|
-
return self
|
|
61
|
-
|
|
62
|
-
OkMeta = class(type):
|
|
63
|
-
__instancecheck__ = (cls, instance) => __tl__.ok(instance)
|
|
64
|
-
|
|
65
|
-
export Ok = class(metaclass=OkMeta):
|
|
66
|
-
__match_args__ = ("value",)
|
|
67
|
-
|
|
68
|
-
__init__ = (self, value) =>
|
|
69
|
-
self.value = value
|
|
70
|
-
|
|
71
|
-
assert = staticmethod& value =>
|
|
72
|
-
value match:
|
|
73
|
-
BaseException() as e => raise e
|
|
74
|
-
None => raise ValueError("Expected a value, got None")
|
|
75
|
-
default value
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
# Since we are using a custom metaclass, we can't derive from Result
|
|
79
|
-
# so need to copy the methods over manually from Result
|
|
80
|
-
|
|
81
|
-
# We could just use the object fallback methods, but this avoids
|
|
82
|
-
# the vget so is slightly faster
|
|
83
|
-
for name, method in Result.__dict__:
|
|
84
|
-
if name.startswith("_"):
|
|
85
|
-
continue
|
|
86
|
-
|
|
87
|
-
setattr(Ok, name, method)
|
|
88
|
-
register_global_attr(object, name, method)
|
|
89
|
-
|
|
90
|
-
export Err = BaseException
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|