koatl 0.1.18__tar.gz → 0.1.20__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.18 → koatl-0.1.20}/Cargo.lock +1 -1
- {koatl-0.1.18 → koatl-0.1.20}/PKG-INFO +1 -1
- {koatl-0.1.18 → koatl-0.1.20}/koatl/Cargo.toml +1 -1
- {koatl-0.1.18 → koatl-0.1.20/koatl}/python/koatl/prelude/functional/__init__.tl +1 -0
- koatl-0.1.20/koatl/python/koatl/prelude/functional/memo.tl +63 -0
- {koatl-0.1.18 → koatl-0.1.20/koatl}/python/koatl/runtime/__init__.py +7 -0
- {koatl-0.1.18 → koatl-0.1.20}/koatl/src/lib.rs +2 -2
- koatl-0.1.20/koatl/tests/e2e/prelude/memo.tl +31 -0
- {koatl-0.1.18 → koatl-0.1.20}/koatl-core/parser/src/ast.rs +1 -0
- {koatl-0.1.18 → koatl-0.1.20}/koatl-core/parser/src/parser.rs +9 -0
- {koatl-0.1.18 → koatl-0.1.20}/koatl-core/src/inference.rs +1 -9
- {koatl-0.1.18 → koatl-0.1.20}/koatl-core/src/lib.rs +8 -3
- {koatl-0.1.18 → koatl-0.1.20}/koatl-core/src/main.rs +1 -1
- {koatl-0.1.18 → koatl-0.1.20}/koatl-core/src/py/util.rs +2 -2
- {koatl-0.1.18 → koatl-0.1.20}/koatl-core/src/resolve_scopes.rs +59 -11
- {koatl-0.1.18 → koatl-0.1.20}/koatl-core/src/transform.rs +103 -16
- {koatl-0.1.18/koatl → koatl-0.1.20}/python/koatl/prelude/functional/__init__.tl +1 -0
- koatl-0.1.20/python/koatl/prelude/functional/memo.tl +63 -0
- {koatl-0.1.18/koatl → koatl-0.1.20}/python/koatl/runtime/__init__.py +7 -0
- {koatl-0.1.18 → koatl-0.1.20}/Cargo.toml +0 -0
- {koatl-0.1.18 → koatl-0.1.20}/README.md +0 -0
- {koatl-0.1.18 → koatl-0.1.20}/koatl/.github/workflows/CI.yml +0 -0
- {koatl-0.1.18 → koatl-0.1.20}/koatl/.gitignore +0 -0
- {koatl-0.1.18 → koatl-0.1.20}/koatl/LICENSE +0 -0
- {koatl-0.1.18 → koatl-0.1.20}/koatl/README.md +0 -0
- {koatl-0.1.18 → koatl-0.1.20}/koatl/python/koatl/__init__.py +0 -0
- {koatl-0.1.18 → koatl-0.1.20}/koatl/python/koatl/__main__.py +0 -0
- {koatl-0.1.18 → koatl-0.1.20}/koatl/python/koatl/cli.py +0 -0
- {koatl-0.1.18 → koatl-0.1.20}/koatl/python/koatl/notebook/__init__.py +0 -0
- {koatl-0.1.18 → koatl-0.1.20}/koatl/python/koatl/notebook/magic.py +0 -0
- {koatl-0.1.18 → koatl-0.1.20}/koatl/python/koatl/prelude/__init__.tl +0 -0
- {koatl-0.1.18 → koatl-0.1.20}/koatl/python/koatl/prelude/functional/async.tl +0 -0
- {koatl-0.1.18 → koatl-0.1.20}/koatl/python/koatl/prelude/functional/async_util.py +0 -0
- {koatl-0.1.18 → koatl-0.1.20}/koatl/python/koatl/prelude/functional/monad.tl +0 -0
- {koatl-0.1.18 → koatl-0.1.20}/koatl/python/koatl/prelude/functional/reader.tl +0 -0
- {koatl-0.1.18 → koatl-0.1.20}/koatl/python/koatl/prelude/functional/result.tl +0 -0
- {koatl-0.1.18 → koatl-0.1.20}/koatl/python/koatl/prelude/iterable.tl +0 -0
- {koatl-0.1.18 → koatl-0.1.20}/koatl/python/koatl/runtime/helpers.py +0 -0
- {koatl-0.1.18 → koatl-0.1.20}/koatl/python/koatl/runtime/meta_finder.py +0 -0
- {koatl-0.1.18 → koatl-0.1.20}/koatl/python/koatl/runtime/record.py +0 -0
- {koatl-0.1.18 → koatl-0.1.20}/koatl/python/koatl/runtime/virtual.py +0 -0
- {koatl-0.1.18 → koatl-0.1.20}/koatl/requirements.txt +0 -0
- {koatl-0.1.18 → koatl-0.1.20}/koatl/src/emit_py.rs +0 -0
- {koatl-0.1.18 → koatl-0.1.20}/koatl/tests/e2e/base/coal.tl +0 -0
- {koatl-0.1.18 → koatl-0.1.20}/koatl/tests/e2e/base/containers.tl +0 -0
- {koatl-0.1.18 → koatl-0.1.20}/koatl/tests/e2e/base/decorators.tl +0 -0
- {koatl-0.1.18 → koatl-0.1.20}/koatl/tests/e2e/base/destructure-for-and-fn.tl +0 -0
- {koatl-0.1.18 → koatl-0.1.20}/koatl/tests/e2e/base/destructure.tl +0 -0
- {koatl-0.1.18 → koatl-0.1.20}/koatl/tests/e2e/base/escape_ident.tl +0 -0
- {koatl-0.1.18 → koatl-0.1.20}/koatl/tests/e2e/base/fstr.tl +0 -0
- {koatl-0.1.18 → koatl-0.1.20}/koatl/tests/e2e/base/functions.tl +0 -0
- {koatl-0.1.18 → koatl-0.1.20}/koatl/tests/e2e/base/generator.tl +0 -0
- {koatl-0.1.18 → koatl-0.1.20}/koatl/tests/e2e/base/if_expr.tl +0 -0
- {koatl-0.1.18 → koatl-0.1.20}/koatl/tests/e2e/base/imports.tl +0 -0
- {koatl-0.1.18 → koatl-0.1.20}/koatl/tests/e2e/base/loops.tl +0 -0
- {koatl-0.1.18 → koatl-0.1.20}/koatl/tests/e2e/base/match.tl +0 -0
- {koatl-0.1.18 → koatl-0.1.20}/koatl/tests/e2e/base/nary-list.tl +0 -0
- {koatl-0.1.18 → koatl-0.1.20}/koatl/tests/e2e/base/placeholder.tl +0 -0
- {koatl-0.1.18 → koatl-0.1.20}/koatl/tests/e2e/base/precedence.tl +0 -0
- {koatl-0.1.18 → koatl-0.1.20}/koatl/tests/e2e/base/scopes.tl +0 -0
- {koatl-0.1.18 → koatl-0.1.20}/koatl/tests/e2e/base/semantic_whitespace.tl +0 -0
- {koatl-0.1.18 → koatl-0.1.20}/koatl/tests/e2e/base/slice.tl +0 -0
- {koatl-0.1.18 → koatl-0.1.20}/koatl/tests/e2e/base/try.tl +0 -0
- {koatl-0.1.18 → koatl-0.1.20}/koatl/tests/e2e/destructure.tl +0 -0
- {koatl-0.1.18 → koatl-0.1.20}/koatl/tests/e2e/prelude/async.tl +0 -0
- {koatl-0.1.18 → koatl-0.1.20}/koatl/tests/e2e/prelude/iterables.tl +0 -0
- {koatl-0.1.18 → koatl-0.1.20}/koatl/tests/e2e/prelude/reader.tl +0 -0
- {koatl-0.1.18 → koatl-0.1.20}/koatl/tests/e2e/prelude/result.tl +0 -0
- {koatl-0.1.18 → koatl-0.1.20}/koatl/tests/e2e/prelude/virtual.tl +0 -0
- {koatl-0.1.18 → koatl-0.1.20}/koatl/tests/e2e/util/__init__.py +0 -0
- {koatl-0.1.18 → koatl-0.1.20}/koatl/tests/e2e/util/module0.tl +0 -0
- {koatl-0.1.18 → koatl-0.1.20}/koatl/tests/e2e/util/module1.tl +0 -0
- {koatl-0.1.18 → koatl-0.1.20}/koatl/tests/e2e/util/module2.tl +0 -0
- {koatl-0.1.18 → koatl-0.1.20}/koatl/tests/parse/arith.tl +0 -0
- {koatl-0.1.18 → koatl-0.1.20}/koatl/tests/parse/assign.tl +0 -0
- {koatl-0.1.18 → koatl-0.1.20}/koatl/tests/parse/block-comments.tl +0 -0
- {koatl-0.1.18 → koatl-0.1.20}/koatl/tests/parse/deco.tl +0 -0
- {koatl-0.1.18 → koatl-0.1.20}/koatl/tests/parse/func.tl +0 -0
- {koatl-0.1.18 → koatl-0.1.20}/koatl/tests/parse/matches.tl +0 -0
- {koatl-0.1.18 → koatl-0.1.20}/koatl/tests/test_e2e.py +0 -0
- {koatl-0.1.18 → koatl-0.1.20}/koatl/tests/test_parse.py +0 -0
- {koatl-0.1.18 → koatl-0.1.20}/koatl-core/Cargo.toml +0 -0
- {koatl-0.1.18 → koatl-0.1.20}/koatl-core/parser/Cargo.toml +0 -0
- {koatl-0.1.18 → koatl-0.1.20}/koatl-core/parser/src/lexer.rs +0 -0
- {koatl-0.1.18 → koatl-0.1.20}/koatl-core/parser/src/lib.rs +0 -0
- {koatl-0.1.18 → koatl-0.1.20}/koatl-core/parser/src/util.rs +0 -0
- {koatl-0.1.18 → koatl-0.1.20}/koatl-core/parser/tests/lexer.rs +0 -0
- {koatl-0.1.18 → koatl-0.1.20}/koatl-core/src/parser.rs +0 -0
- {koatl-0.1.18 → koatl-0.1.20}/koatl-core/src/py/ast.rs +0 -0
- {koatl-0.1.18 → koatl-0.1.20}/koatl-core/src/py/emit.rs +0 -0
- {koatl-0.1.18 → koatl-0.1.20}/koatl-core/src/py/mod.rs +0 -0
- {koatl-0.1.18 → koatl-0.1.20}/koatl-core/src/types.rs +0 -0
- {koatl-0.1.18 → koatl-0.1.20}/koatl-core/src/util.rs +0 -0
- {koatl-0.1.18 → koatl-0.1.20}/pyproject.toml +0 -0
- {koatl-0.1.18 → koatl-0.1.20}/python/koatl/__init__.py +0 -0
- {koatl-0.1.18 → koatl-0.1.20}/python/koatl/__main__.py +0 -0
- {koatl-0.1.18 → koatl-0.1.20}/python/koatl/cli.py +0 -0
- {koatl-0.1.18 → koatl-0.1.20}/python/koatl/notebook/__init__.py +0 -0
- {koatl-0.1.18 → koatl-0.1.20}/python/koatl/notebook/magic.py +0 -0
- {koatl-0.1.18 → koatl-0.1.20}/python/koatl/prelude/__init__.tl +0 -0
- {koatl-0.1.18 → koatl-0.1.20}/python/koatl/prelude/functional/async.tl +0 -0
- {koatl-0.1.18 → koatl-0.1.20}/python/koatl/prelude/functional/async_util.py +0 -0
- {koatl-0.1.18 → koatl-0.1.20}/python/koatl/prelude/functional/monad.tl +0 -0
- {koatl-0.1.18 → koatl-0.1.20}/python/koatl/prelude/functional/reader.tl +0 -0
- {koatl-0.1.18 → koatl-0.1.20}/python/koatl/prelude/functional/result.tl +0 -0
- {koatl-0.1.18 → koatl-0.1.20}/python/koatl/prelude/iterable.tl +0 -0
- {koatl-0.1.18 → koatl-0.1.20}/python/koatl/runtime/helpers.py +0 -0
- {koatl-0.1.18 → koatl-0.1.20}/python/koatl/runtime/meta_finder.py +0 -0
- {koatl-0.1.18 → koatl-0.1.20}/python/koatl/runtime/record.py +0 -0
- {koatl-0.1.18 → koatl-0.1.20}/python/koatl/runtime/virtual.py +0 -0
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import collections.defaultdict
|
|
2
|
+
import functools.wraps
|
|
3
|
+
import .result.Ok
|
|
4
|
+
import .Monad
|
|
5
|
+
|
|
6
|
+
export Memo = class(Monad):
|
|
7
|
+
Cache = class:
|
|
8
|
+
__init__ = self =>
|
|
9
|
+
self.cache = defaultdict(dict)
|
|
10
|
+
|
|
11
|
+
get_or_compute = (self, name, deps, f) =>
|
|
12
|
+
if try self.cache[name][deps] except KeyError() matches (Ok() as v):
|
|
13
|
+
return v
|
|
14
|
+
|
|
15
|
+
let value = f()
|
|
16
|
+
self.cache[name][deps] = value
|
|
17
|
+
value
|
|
18
|
+
|
|
19
|
+
__repr__ = self => f"Memo.Cache({self.cache})"
|
|
20
|
+
|
|
21
|
+
__init__ = (self, f) => self.f = f
|
|
22
|
+
|
|
23
|
+
__repr__ = self => f"Memo(...)"
|
|
24
|
+
|
|
25
|
+
value = staticmethod& (id, deps, f) =>
|
|
26
|
+
Memo(ctx => ctx.get_or_compute(id, tuple(deps), f))
|
|
27
|
+
|
|
28
|
+
fn = staticmethod& f => wraps(f)& (*args, **kwargs) =>
|
|
29
|
+
let id = f"{f.__module__}.{f.__qualname__}"
|
|
30
|
+
let deps = (tuple(args), tuple(kwargs.items()))
|
|
31
|
+
|
|
32
|
+
Memo(ctx =>
|
|
33
|
+
ctx.get_or_compute(id, deps, () =>
|
|
34
|
+
let v = f(*args, **kwargs)
|
|
35
|
+
if v matches Memo():
|
|
36
|
+
v = v.run(ctx)
|
|
37
|
+
v
|
|
38
|
+
)
|
|
39
|
+
)
|
|
40
|
+
|
|
41
|
+
run = (self, ctx=Cache()) => self.f(ctx)
|
|
42
|
+
|
|
43
|
+
pure = staticmethod& value => Memo(ctx => value)
|
|
44
|
+
|
|
45
|
+
bind_once = (self, f) => Memo(ctx =>
|
|
46
|
+
let value = f(self.run(ctx))
|
|
47
|
+
if value matches Memo():
|
|
48
|
+
value = value.run(ctx)
|
|
49
|
+
value
|
|
50
|
+
)
|
|
51
|
+
|
|
52
|
+
bind_gen = (self, gen) => Memo(ctx =>
|
|
53
|
+
self = self.run(ctx)
|
|
54
|
+
try:
|
|
55
|
+
while True:
|
|
56
|
+
self = gen.send(self)
|
|
57
|
+
if self matches Memo():
|
|
58
|
+
self = self.run(ctx)
|
|
59
|
+
except StopIteration(value=value):
|
|
60
|
+
return value
|
|
61
|
+
)
|
|
62
|
+
|
|
63
|
+
__tl__.memo = Memo.value
|
|
@@ -21,11 +21,18 @@ from .record import *
|
|
|
21
21
|
from .helpers import *
|
|
22
22
|
|
|
23
23
|
|
|
24
|
+
def dummy_memo(*args, **kwargs):
|
|
25
|
+
raise RuntimeError(
|
|
26
|
+
"memo is not available without the prelude. Please import koatl.prelude."
|
|
27
|
+
)
|
|
28
|
+
|
|
29
|
+
|
|
24
30
|
__tl__ = SimpleNamespace(
|
|
25
31
|
Exception=Exception,
|
|
26
32
|
slice=slice,
|
|
27
33
|
vget=virtual.vget,
|
|
28
34
|
vhas=virtual.vhas,
|
|
35
|
+
memo=dummy_memo,
|
|
29
36
|
unpack_record=helpers.unpack_record,
|
|
30
37
|
set_exports=helpers.set_exports,
|
|
31
38
|
do=helpers.do,
|
|
@@ -29,7 +29,7 @@ fn get_option(mode: &str) -> PyResult<TranspileOptions> {
|
|
|
29
29
|
fn transpile(src: &str, mode: &str, filename: &str) -> PyResult<PyObject> {
|
|
30
30
|
let options = get_option(mode)?;
|
|
31
31
|
|
|
32
|
-
let py_ast = transpile_to_py_ast(src, options).map_err(|e| {
|
|
32
|
+
let py_ast = transpile_to_py_ast(src, filename, options).map_err(|e| {
|
|
33
33
|
PyErr::new::<pyo3::exceptions::PySyntaxError, _>(format_errs(&e, filename, src))
|
|
34
34
|
})?;
|
|
35
35
|
|
|
@@ -43,7 +43,7 @@ fn transpile(src: &str, mode: &str, filename: &str) -> PyResult<PyObject> {
|
|
|
43
43
|
fn transpile_raw(src: &str, mode: &str, filename: &str) -> PyResult<PyObject> {
|
|
44
44
|
let options = get_option(mode)?;
|
|
45
45
|
|
|
46
|
-
let ctx = transpile_to_source(src, options).map_err(|e| {
|
|
46
|
+
let ctx = transpile_to_source(src, filename, options).map_err(|e| {
|
|
47
47
|
PyErr::new::<pyo3::exceptions::PySyntaxError, _>(format_errs(&e, filename, src))
|
|
48
48
|
})?;
|
|
49
49
|
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import util.assert_eq
|
|
2
|
+
|
|
3
|
+
counts = 0
|
|
4
|
+
|
|
5
|
+
fib = Memo.fn& x =>
|
|
6
|
+
if x < 2:
|
|
7
|
+
return 1
|
|
8
|
+
|
|
9
|
+
counts = counts + 1
|
|
10
|
+
|
|
11
|
+
let a = @fib(x - 1)
|
|
12
|
+
let b = @fib(x - 2)
|
|
13
|
+
|
|
14
|
+
a + b
|
|
15
|
+
|
|
16
|
+
assert_eq(fib(10).run(), 89)
|
|
17
|
+
assert_eq(counts < 20, True)
|
|
18
|
+
|
|
19
|
+
counts = 0
|
|
20
|
+
|
|
21
|
+
f = x =>
|
|
22
|
+
memo:
|
|
23
|
+
counts = counts + 1
|
|
24
|
+
x * 2
|
|
25
|
+
|
|
26
|
+
ctx = Memo.Cache()
|
|
27
|
+
assert_eq(f(10).run(ctx), 20)
|
|
28
|
+
assert_eq(f(10).run(ctx), 20)
|
|
29
|
+
assert_eq(f(5).run(ctx), 10)
|
|
30
|
+
assert_eq(f(5).run(ctx), 10)
|
|
31
|
+
assert_eq(counts, 2)
|
|
@@ -781,8 +781,17 @@ where
|
|
|
781
781
|
})
|
|
782
782
|
.labelled("control-expression");
|
|
783
783
|
|
|
784
|
+
let memo_expr = just(Token::Ident("memo"))
|
|
785
|
+
.then(just(START_BLOCK).or_not())
|
|
786
|
+
.ignore_then(expr_or_inline_stmt_or_block.clone())
|
|
787
|
+
.map(|x| Expr::Memo(x.indirect()))
|
|
788
|
+
.spanned_expr()
|
|
789
|
+
.labelled("memo-expression")
|
|
790
|
+
.boxed();
|
|
791
|
+
|
|
784
792
|
atom.define(
|
|
785
793
|
choice((
|
|
794
|
+
memo_expr,
|
|
786
795
|
ident_expr.clone(),
|
|
787
796
|
classic_if,
|
|
788
797
|
classic_match,
|
|
@@ -152,15 +152,7 @@ impl<'src, 'ast> SExprExt<'src, 'ast> for Indirect<SExpr<'src>> {
|
|
|
152
152
|
b.traverse(ctx);
|
|
153
153
|
Type::Any
|
|
154
154
|
}
|
|
155
|
-
Expr::Await(expr) => {
|
|
156
|
-
expr.traverse(ctx);
|
|
157
|
-
Type::Any
|
|
158
|
-
}
|
|
159
|
-
Expr::Yield(expr) => {
|
|
160
|
-
expr.traverse(ctx);
|
|
161
|
-
Type::Any
|
|
162
|
-
}
|
|
163
|
-
Expr::YieldFrom(expr) => {
|
|
155
|
+
Expr::Await(expr) | Expr::Yield(expr) | Expr::Memo(expr) | Expr::YieldFrom(expr) => {
|
|
164
156
|
expr.traverse(ctx);
|
|
165
157
|
Type::Any
|
|
166
158
|
}
|
|
@@ -60,6 +60,7 @@ impl TranspileOptions {
|
|
|
60
60
|
|
|
61
61
|
pub fn transpile_to_py_ast<'src>(
|
|
62
62
|
src: &'src str,
|
|
63
|
+
filename: &'src str,
|
|
63
64
|
options: TranspileOptions,
|
|
64
65
|
) -> TlResult<PyBlock<'src>> {
|
|
65
66
|
let tl_ast = parse_tl(src)?;
|
|
@@ -79,7 +80,7 @@ pub fn transpile_to_py_ast<'src>(
|
|
|
79
80
|
}
|
|
80
81
|
};
|
|
81
82
|
|
|
82
|
-
let output = match transform_ast(&src, &tl_ast, &resolve_state, &inference) {
|
|
83
|
+
let output = match transform_ast(&src, &filename, &tl_ast, &resolve_state, &inference) {
|
|
83
84
|
Ok(output) => Some(output),
|
|
84
85
|
Err(e) => {
|
|
85
86
|
errs.extend(e);
|
|
@@ -173,8 +174,12 @@ pub fn transpile_to_py_ast<'src>(
|
|
|
173
174
|
Ok(py_ast)
|
|
174
175
|
}
|
|
175
176
|
|
|
176
|
-
pub fn transpile_to_source(
|
|
177
|
-
|
|
177
|
+
pub fn transpile_to_source(
|
|
178
|
+
src: &str,
|
|
179
|
+
filename: &str,
|
|
180
|
+
options: TranspileOptions,
|
|
181
|
+
) -> TlResult<EmitCtx> {
|
|
182
|
+
let mut py_ast = transpile_to_py_ast(src, filename, options)?;
|
|
178
183
|
|
|
179
184
|
let mut ctx = EmitCtx::new();
|
|
180
185
|
py_ast.emit_to(&mut ctx, 0).map_err(|e| {
|
|
@@ -13,7 +13,7 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
|
|
|
13
13
|
let filename = std::env::args().nth(2).ok_or("Missing filename argument")?;
|
|
14
14
|
let src = std::fs::read_to_string(&filename).unwrap();
|
|
15
15
|
|
|
16
|
-
match transpile_to_source(&src, TranspileOptions::module()) {
|
|
16
|
+
match transpile_to_source(&src, &filename, TranspileOptions::module()) {
|
|
17
17
|
Ok(ctx) => match cmd.as_str() {
|
|
18
18
|
"trans" => {
|
|
19
19
|
println!("{}", ctx.source);
|
|
@@ -334,11 +334,11 @@ impl PyAstBuilder {
|
|
|
334
334
|
}
|
|
335
335
|
|
|
336
336
|
// Utility builders for tuple items
|
|
337
|
-
pub fn
|
|
337
|
+
pub fn list_item<'src>(&self, expr: SPyExpr<'src>) -> PyListItem<'src> {
|
|
338
338
|
PyListItem::Item(expr)
|
|
339
339
|
}
|
|
340
340
|
|
|
341
|
-
pub fn
|
|
341
|
+
pub fn list_spread<'src>(&self, expr: SPyExpr<'src>) -> PyListItem<'src> {
|
|
342
342
|
PyListItem::Spread(expr)
|
|
343
343
|
}
|
|
344
344
|
|
|
@@ -37,6 +37,7 @@ pub struct ResolveState<'src> {
|
|
|
37
37
|
pub resolutions: HashMap<RefHash, DeclarationKey>,
|
|
38
38
|
pub functions: HashMap<RefHash, FnInfo>,
|
|
39
39
|
pub patterns: HashMap<RefHash, PatternInfo>,
|
|
40
|
+
pub memo_captures: HashMap<RefHash, FnInfo>,
|
|
40
41
|
|
|
41
42
|
pub declarations: SlotMap<DeclarationKey, Declaration<'src>>,
|
|
42
43
|
pub scopes: SlotMap<ScopeKey, Scope>,
|
|
@@ -86,6 +87,7 @@ impl<'src> ResolveState<'src> {
|
|
|
86
87
|
resolutions: HashMap::new(),
|
|
87
88
|
functions: HashMap::new(),
|
|
88
89
|
patterns: HashMap::new(),
|
|
90
|
+
memo_captures: HashMap::new(),
|
|
89
91
|
|
|
90
92
|
declarations: SlotMap::with_key(),
|
|
91
93
|
scopes,
|
|
@@ -116,6 +118,7 @@ impl<'src> ResolveState<'src> {
|
|
|
116
118
|
}
|
|
117
119
|
|
|
118
120
|
let Some(fn_ctx) = self.fn_stack.last_mut() else {
|
|
121
|
+
// This should never happen since if not fn_local, there must be at least one function context
|
|
119
122
|
return Err(simple_err("Internal error: no function context", ident.span).into());
|
|
120
123
|
};
|
|
121
124
|
|
|
@@ -374,12 +377,19 @@ impl PlaceholderGuard {
|
|
|
374
377
|
}
|
|
375
378
|
}
|
|
376
379
|
|
|
380
|
+
// This is a bit of a misuse, since during traversal,
|
|
381
|
+
// FnInfo represents a "capture context" rather than a function
|
|
382
|
+
// (i.e., it logs captures and monadic constructs like Async)
|
|
383
|
+
|
|
384
|
+
// ...but it becomes a real function context once it gets added
|
|
385
|
+
// to the hashmap.
|
|
377
386
|
#[derive(Debug, Clone)]
|
|
378
387
|
pub struct FnInfo {
|
|
379
388
|
pub is_do: bool,
|
|
380
389
|
pub is_async: bool,
|
|
381
390
|
pub is_generator: bool,
|
|
382
391
|
pub is_placeholder: bool,
|
|
392
|
+
pub is_memo: bool,
|
|
383
393
|
|
|
384
394
|
pub arg_names: Vec<DeclarationKey>,
|
|
385
395
|
pub captures: HashSet<DeclarationKey>,
|
|
@@ -392,6 +402,7 @@ impl FnInfo {
|
|
|
392
402
|
is_async: false,
|
|
393
403
|
is_generator: false,
|
|
394
404
|
is_placeholder: false,
|
|
405
|
+
is_memo: false,
|
|
395
406
|
arg_names: Vec::new(),
|
|
396
407
|
captures: HashSet::new(),
|
|
397
408
|
}
|
|
@@ -1131,17 +1142,18 @@ impl<'src> SExprExt<'src> for Indirect<SExpr<'src>> {
|
|
|
1131
1142
|
|
|
1132
1143
|
let mut fn_info = FnInfo::new();
|
|
1133
1144
|
for (i, decl) in decls.iter().enumerate() {
|
|
1134
|
-
if
|
|
1135
|
-
.iter()
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
+
if state.declarations[*decl].name.0 != "_" {
|
|
1146
|
+
if let Some(found) = decls[..i].iter().find(|x| {
|
|
1147
|
+
state.declarations[**x].name == state.declarations[*decl].name
|
|
1148
|
+
}) {
|
|
1149
|
+
state.errors.extend(
|
|
1150
|
+
TlErrBuilder::new()
|
|
1151
|
+
.message("Duplicate declaration in function arguments")
|
|
1152
|
+
.context("First declared here", state.declarations[*found].loc)
|
|
1153
|
+
.span(state.declarations[*decl].loc)
|
|
1154
|
+
.build(),
|
|
1155
|
+
);
|
|
1156
|
+
}
|
|
1145
1157
|
}
|
|
1146
1158
|
|
|
1147
1159
|
fn_info.arg_names.push(*decl);
|
|
@@ -1286,6 +1298,42 @@ impl<'src> SExprExt<'src> for Indirect<SExpr<'src>> {
|
|
|
1286
1298
|
|
|
1287
1299
|
Expr::Unary(unary_op, expr.traverse(state))
|
|
1288
1300
|
}
|
|
1301
|
+
Expr::Memo(inner) => {
|
|
1302
|
+
state.set_do(span);
|
|
1303
|
+
|
|
1304
|
+
let mut fn_ctx = FnInfo::new();
|
|
1305
|
+
fn_ctx.is_memo = true;
|
|
1306
|
+
|
|
1307
|
+
let mut scope = Scope::new();
|
|
1308
|
+
scope.is_fn = true;
|
|
1309
|
+
|
|
1310
|
+
// TODO it's confusing that we need to
|
|
1311
|
+
// set scope.is_fn = true all the time in order
|
|
1312
|
+
// for captures to be found properly.
|
|
1313
|
+
// is there any better way?
|
|
1314
|
+
|
|
1315
|
+
let scope = state.scopes.insert(scope);
|
|
1316
|
+
state.fn_stack.push(fn_ctx);
|
|
1317
|
+
|
|
1318
|
+
let scoped = state.scoped(scope, |state| {
|
|
1319
|
+
state.placeholder_guarded(span, |state| inner.traverse_expecting_scope(state))
|
|
1320
|
+
});
|
|
1321
|
+
|
|
1322
|
+
let inner = scoped.value;
|
|
1323
|
+
|
|
1324
|
+
let fn_ctx = state.fn_stack.pop().unwrap();
|
|
1325
|
+
|
|
1326
|
+
if fn_ctx.is_async || fn_ctx.is_generator || fn_ctx.is_do {
|
|
1327
|
+
state.errors.extend(simple_err(
|
|
1328
|
+
"Memo expressions cannot be async, generator, or do",
|
|
1329
|
+
span,
|
|
1330
|
+
));
|
|
1331
|
+
}
|
|
1332
|
+
|
|
1333
|
+
state.memo_captures.insert(inner.as_ref().into(), fn_ctx);
|
|
1334
|
+
|
|
1335
|
+
Expr::Memo(inner)
|
|
1336
|
+
}
|
|
1289
1337
|
Expr::Await(x) => {
|
|
1290
1338
|
state.set_async(span);
|
|
1291
1339
|
Expr::Await(x.traverse(state))
|
|
@@ -51,8 +51,9 @@ struct PyDecl<'src> {
|
|
|
51
51
|
#[allow(dead_code)]
|
|
52
52
|
struct TlCtx<'src, 'ast> {
|
|
53
53
|
source: &'src str,
|
|
54
|
-
|
|
54
|
+
filename: &'src str,
|
|
55
55
|
line_cache: LineColCache,
|
|
56
|
+
export_stars: Vec<PyIdent<'src>>,
|
|
56
57
|
|
|
57
58
|
ident_counts: HashMap<Ident<'src>, usize>,
|
|
58
59
|
py_decls: HashMap<DeclarationKey, PyDecl<'src>>,
|
|
@@ -60,6 +61,7 @@ struct TlCtx<'src, 'ast> {
|
|
|
60
61
|
functions: &'ast HashMap<RefHash, FnInfo>,
|
|
61
62
|
patterns: &'ast HashMap<RefHash, PatternInfo>,
|
|
62
63
|
resolutions: &'ast HashMap<RefHash, DeclarationKey>,
|
|
64
|
+
memo_captures: &'ast HashMap<RefHash, FnInfo>,
|
|
63
65
|
|
|
64
66
|
scopes: &'ast SlotMap<ScopeKey, Scope>,
|
|
65
67
|
declarations: &'ast SlotMap<DeclarationKey, Declaration<'src>>,
|
|
@@ -70,11 +72,13 @@ struct TlCtx<'src, 'ast> {
|
|
|
70
72
|
impl<'src, 'ast> TlCtx<'src, 'ast> {
|
|
71
73
|
fn new(
|
|
72
74
|
source: &'src str,
|
|
75
|
+
filename: &'src str,
|
|
73
76
|
resolve_state: &'ast ResolveState<'src>,
|
|
74
77
|
inference: &'ast InferenceCtx<'src, 'ast>,
|
|
75
78
|
) -> TlResult<Self> {
|
|
76
79
|
Ok(TlCtx {
|
|
77
80
|
source,
|
|
81
|
+
filename,
|
|
78
82
|
export_stars: Vec::new(),
|
|
79
83
|
line_cache: LineColCache::new(source),
|
|
80
84
|
|
|
@@ -84,6 +88,7 @@ impl<'src, 'ast> TlCtx<'src, 'ast> {
|
|
|
84
88
|
functions: &resolve_state.functions,
|
|
85
89
|
patterns: &resolve_state.patterns,
|
|
86
90
|
resolutions: &resolve_state.resolutions,
|
|
91
|
+
memo_captures: &resolve_state.memo_captures,
|
|
87
92
|
|
|
88
93
|
scopes: &resolve_state.scopes,
|
|
89
94
|
declarations: &resolve_state.declarations,
|
|
@@ -1021,7 +1026,7 @@ fn create_throwing_matcher<'src, 'ast>(
|
|
|
1021
1026
|
pattern: &'ast SPattern<'src>,
|
|
1022
1027
|
pattern_meta: &'ast PatternInfo,
|
|
1023
1028
|
) -> TlResult<(PyBlock<'src>, PyIdent<'src>)> {
|
|
1024
|
-
if let Pattern::Capture(Some(
|
|
1029
|
+
if let Pattern::Capture(Some(ident)) = &pattern.value {
|
|
1025
1030
|
if pattern_meta.decls.len() != 1 {
|
|
1026
1031
|
return Err(simple_err(
|
|
1027
1032
|
"Internal: expected exactly one decl",
|
|
@@ -1029,8 +1034,10 @@ fn create_throwing_matcher<'src, 'ast>(
|
|
|
1029
1034
|
));
|
|
1030
1035
|
}
|
|
1031
1036
|
|
|
1032
|
-
|
|
1033
|
-
|
|
1037
|
+
if ident.value.0 != "_" {
|
|
1038
|
+
let decl = pattern_meta.decls.iter().next().unwrap();
|
|
1039
|
+
return Ok((PyBlock::new(), ctx.decl_py_ident(*decl)?));
|
|
1040
|
+
}
|
|
1034
1041
|
}
|
|
1035
1042
|
|
|
1036
1043
|
let cursor = ctx.create_aux_var("matcher", pattern.span.start);
|
|
@@ -1285,7 +1292,15 @@ fn make_arglist<'src, 'ast>(
|
|
|
1285
1292
|
.iter()
|
|
1286
1293
|
.find(|key| ctx.declarations[**key].name == name.value)
|
|
1287
1294
|
.ok_or_else(|| simple_err("Internal: missing arg name", name.span))?;
|
|
1288
|
-
|
|
1295
|
+
|
|
1296
|
+
let decl_value = &ctx.declarations[*decl];
|
|
1297
|
+
|
|
1298
|
+
if decl_value.name.0 == "_" {
|
|
1299
|
+
// need to create a unique name to prevent python complaining
|
|
1300
|
+
PyArgDefItem::ArgSpread(ctx.create_aux_var("_", name.span.start))
|
|
1301
|
+
} else {
|
|
1302
|
+
PyArgDefItem::ArgSpread(ctx.decl_py_ident(*decl)?)
|
|
1303
|
+
}
|
|
1289
1304
|
}
|
|
1290
1305
|
ArgDefItem::KwargSpread(name) => {
|
|
1291
1306
|
let decl = info
|
|
@@ -1293,7 +1308,14 @@ fn make_arglist<'src, 'ast>(
|
|
|
1293
1308
|
.iter()
|
|
1294
1309
|
.find(|key| ctx.declarations[**key].name == name.value)
|
|
1295
1310
|
.ok_or_else(|| simple_err("Internal: missing arg name", name.span))?;
|
|
1296
|
-
|
|
1311
|
+
|
|
1312
|
+
let decl_value = &ctx.declarations[*decl];
|
|
1313
|
+
|
|
1314
|
+
if decl_value.name.0 == "_" {
|
|
1315
|
+
PyArgDefItem::KwargSpread(ctx.create_aux_var("_", name.span.start))
|
|
1316
|
+
} else {
|
|
1317
|
+
PyArgDefItem::KwargSpread(ctx.decl_py_ident(*decl)?)
|
|
1318
|
+
}
|
|
1297
1319
|
}
|
|
1298
1320
|
};
|
|
1299
1321
|
args_vec.push(arg);
|
|
@@ -1314,7 +1336,9 @@ struct PartialPyFnDef<'a> {
|
|
|
1314
1336
|
}
|
|
1315
1337
|
|
|
1316
1338
|
enum FnDef<'src, 'ast> {
|
|
1317
|
-
|
|
1339
|
+
/**
|
|
1340
|
+
* Args, body, is_do, is_async
|
|
1341
|
+
*/
|
|
1318
1342
|
PyFnDef(Vec<PyArgDefItem<'src>>, PyBlock<'src>, bool, bool),
|
|
1319
1343
|
|
|
1320
1344
|
// Expr::Fn, args, body
|
|
@@ -1383,7 +1407,8 @@ fn prepare_py_fn<'src, 'ast>(
|
|
|
1383
1407
|
let mut globals = vec![];
|
|
1384
1408
|
|
|
1385
1409
|
for capture in fn_info.captures.iter() {
|
|
1386
|
-
|
|
1410
|
+
let scope = &ctx.scopes[ctx.declarations[*capture].scope];
|
|
1411
|
+
if scope.is_global || scope.is_class {
|
|
1387
1412
|
globals.push(ctx.decl_py_ident(*capture)?);
|
|
1388
1413
|
} else {
|
|
1389
1414
|
nonlocals.push(ctx.decl_py_ident(*capture)?);
|
|
@@ -1600,7 +1625,7 @@ fn transform_postfix_expr<'src, 'ast>(
|
|
|
1600
1625
|
expr: &'ast SExpr<'src>,
|
|
1601
1626
|
access_ctx: PyAccessCtx,
|
|
1602
1627
|
) -> TlResult<SPyExprWithPre<'src>> {
|
|
1603
|
-
let (
|
|
1628
|
+
let (mapped, lhs_node) = match &expr.value {
|
|
1604
1629
|
Expr::RawAttribute(obj, _) => (false, obj),
|
|
1605
1630
|
Expr::Subscript(obj, _) => (false, obj),
|
|
1606
1631
|
Expr::Call(obj, _) => (false, obj),
|
|
@@ -1619,20 +1644,17 @@ fn transform_postfix_expr<'src, 'ast>(
|
|
|
1619
1644
|
}
|
|
1620
1645
|
};
|
|
1621
1646
|
|
|
1622
|
-
if let Expr::Attribute(..) | Expr::RawAttribute(..) = &expr.value {
|
|
1647
|
+
if let Expr::Attribute(..) | Expr::RawAttribute(..) | Expr::Subscript(..) = &expr.value {
|
|
1623
1648
|
} else {
|
|
1624
1649
|
if access_ctx != PyAccessCtx::Load {
|
|
1625
|
-
return Err(simple_err(
|
|
1626
|
-
"Internal error: Cannot use null-coalescing in a non-Load context",
|
|
1627
|
-
expr.span,
|
|
1628
|
-
));
|
|
1650
|
+
return Err(simple_err("Illegal assignment target", expr.span));
|
|
1629
1651
|
}
|
|
1630
1652
|
}
|
|
1631
1653
|
|
|
1632
1654
|
let mut pre = PyBlock::new();
|
|
1633
1655
|
let a = PyAstBuilder::new(expr.span);
|
|
1634
1656
|
|
|
1635
|
-
let lhs = if
|
|
1657
|
+
let lhs = if mapped {
|
|
1636
1658
|
pre.bind(lhs_node.transform_lifted(ctx)?)
|
|
1637
1659
|
} else {
|
|
1638
1660
|
pre.bind(lhs_node.transform(ctx)?)
|
|
@@ -2226,6 +2248,70 @@ impl<'src, 'ast> SExprExt<'src, 'ast> for SExpr<'src> {
|
|
|
2226
2248
|
|
|
2227
2249
|
a.binary(py_op, lhs, rhs)
|
|
2228
2250
|
}
|
|
2251
|
+
Expr::Memo(expr) => {
|
|
2252
|
+
let memo_captures =
|
|
2253
|
+
ctx.memo_captures
|
|
2254
|
+
.get(&expr.as_ref().into())
|
|
2255
|
+
.ok_or_else(|| {
|
|
2256
|
+
simple_err(
|
|
2257
|
+
"Internal error: Memo expression not found in memo captures",
|
|
2258
|
+
expr.span,
|
|
2259
|
+
)
|
|
2260
|
+
})?;
|
|
2261
|
+
|
|
2262
|
+
let py_expr = expr.transform(ctx)?;
|
|
2263
|
+
let mut py_body = PyBlock::new();
|
|
2264
|
+
|
|
2265
|
+
let mut nonlocals = vec![];
|
|
2266
|
+
let mut globals = vec![];
|
|
2267
|
+
|
|
2268
|
+
for capture in memo_captures.captures.iter() {
|
|
2269
|
+
if ctx.scopes[ctx.declarations[*capture].scope].is_global {
|
|
2270
|
+
globals.push(ctx.decl_py_ident(*capture)?);
|
|
2271
|
+
} else {
|
|
2272
|
+
nonlocals.push(ctx.decl_py_ident(*capture)?);
|
|
2273
|
+
}
|
|
2274
|
+
}
|
|
2275
|
+
|
|
2276
|
+
if !nonlocals.is_empty() {
|
|
2277
|
+
py_body.push(a.nonlocal(nonlocals.iter().map(|x| x.clone()).collect()));
|
|
2278
|
+
}
|
|
2279
|
+
if !globals.is_empty() {
|
|
2280
|
+
py_body.push(a.global(globals.iter().map(|x| x.clone()).collect()));
|
|
2281
|
+
}
|
|
2282
|
+
|
|
2283
|
+
py_body.extend(py_expr.pre);
|
|
2284
|
+
py_body.push(a.return_(py_expr.value));
|
|
2285
|
+
|
|
2286
|
+
let callback = pre.bind(make_fn_exp(
|
|
2287
|
+
ctx,
|
|
2288
|
+
FnDef::PyFnDef(vec![], py_body, false, false),
|
|
2289
|
+
&span,
|
|
2290
|
+
)?);
|
|
2291
|
+
|
|
2292
|
+
let linecol = ctx.line_cache.linecol(span.start);
|
|
2293
|
+
|
|
2294
|
+
a.yield_(a.call(
|
|
2295
|
+
a.tl_builtin("memo"),
|
|
2296
|
+
vec![
|
|
2297
|
+
PyCallItem::Arg(
|
|
2298
|
+
a.str(
|
|
2299
|
+
format!("{}:{}:{}", ctx.filename, linecol.0, linecol.1)
|
|
2300
|
+
)
|
|
2301
|
+
),
|
|
2302
|
+
PyCallItem::Arg(
|
|
2303
|
+
a.tuple(
|
|
2304
|
+
nonlocals
|
|
2305
|
+
.iter()
|
|
2306
|
+
.map(|x| a.list_item(a.load_ident(x.clone())))
|
|
2307
|
+
.collect(),
|
|
2308
|
+
PyAccessCtx::Load,
|
|
2309
|
+
),
|
|
2310
|
+
),
|
|
2311
|
+
PyCallItem::Arg(callback),
|
|
2312
|
+
],
|
|
2313
|
+
))
|
|
2314
|
+
}
|
|
2229
2315
|
Expr::Await(expr) => a.await_(pre.bind(expr.transform(ctx)?)),
|
|
2230
2316
|
Expr::Yield(expr) => a.yield_(pre.bind(expr.transform(ctx)?)),
|
|
2231
2317
|
Expr::YieldFrom(expr) => a.yield_from(a.call(
|
|
@@ -2344,11 +2430,12 @@ pub struct TransformOutput<'src> {
|
|
|
2344
2430
|
|
|
2345
2431
|
pub fn transform_ast<'src, 'ast>(
|
|
2346
2432
|
source: &'src str,
|
|
2433
|
+
filename: &'src str,
|
|
2347
2434
|
block: &'ast SExpr<'src>,
|
|
2348
2435
|
resolve_state: &'ast ResolveState<'src>,
|
|
2349
2436
|
inference: &'ast InferenceCtx<'src, 'ast>,
|
|
2350
2437
|
) -> TlResult<TransformOutput<'src>> {
|
|
2351
|
-
let mut ctx = TlCtx::new(source, resolve_state, inference)?;
|
|
2438
|
+
let mut ctx = TlCtx::new(source, filename, resolve_state, inference)?;
|
|
2352
2439
|
|
|
2353
2440
|
let mut py_block = PyBlock::new();
|
|
2354
2441
|
let expr = py_block.bind(block.transform(&mut ctx)?);
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import collections.defaultdict
|
|
2
|
+
import functools.wraps
|
|
3
|
+
import .result.Ok
|
|
4
|
+
import .Monad
|
|
5
|
+
|
|
6
|
+
export Memo = class(Monad):
|
|
7
|
+
Cache = class:
|
|
8
|
+
__init__ = self =>
|
|
9
|
+
self.cache = defaultdict(dict)
|
|
10
|
+
|
|
11
|
+
get_or_compute = (self, name, deps, f) =>
|
|
12
|
+
if try self.cache[name][deps] except KeyError() matches (Ok() as v):
|
|
13
|
+
return v
|
|
14
|
+
|
|
15
|
+
let value = f()
|
|
16
|
+
self.cache[name][deps] = value
|
|
17
|
+
value
|
|
18
|
+
|
|
19
|
+
__repr__ = self => f"Memo.Cache({self.cache})"
|
|
20
|
+
|
|
21
|
+
__init__ = (self, f) => self.f = f
|
|
22
|
+
|
|
23
|
+
__repr__ = self => f"Memo(...)"
|
|
24
|
+
|
|
25
|
+
value = staticmethod& (id, deps, f) =>
|
|
26
|
+
Memo(ctx => ctx.get_or_compute(id, tuple(deps), f))
|
|
27
|
+
|
|
28
|
+
fn = staticmethod& f => wraps(f)& (*args, **kwargs) =>
|
|
29
|
+
let id = f"{f.__module__}.{f.__qualname__}"
|
|
30
|
+
let deps = (tuple(args), tuple(kwargs.items()))
|
|
31
|
+
|
|
32
|
+
Memo(ctx =>
|
|
33
|
+
ctx.get_or_compute(id, deps, () =>
|
|
34
|
+
let v = f(*args, **kwargs)
|
|
35
|
+
if v matches Memo():
|
|
36
|
+
v = v.run(ctx)
|
|
37
|
+
v
|
|
38
|
+
)
|
|
39
|
+
)
|
|
40
|
+
|
|
41
|
+
run = (self, ctx=Cache()) => self.f(ctx)
|
|
42
|
+
|
|
43
|
+
pure = staticmethod& value => Memo(ctx => value)
|
|
44
|
+
|
|
45
|
+
bind_once = (self, f) => Memo(ctx =>
|
|
46
|
+
let value = f(self.run(ctx))
|
|
47
|
+
if value matches Memo():
|
|
48
|
+
value = value.run(ctx)
|
|
49
|
+
value
|
|
50
|
+
)
|
|
51
|
+
|
|
52
|
+
bind_gen = (self, gen) => Memo(ctx =>
|
|
53
|
+
self = self.run(ctx)
|
|
54
|
+
try:
|
|
55
|
+
while True:
|
|
56
|
+
self = gen.send(self)
|
|
57
|
+
if self matches Memo():
|
|
58
|
+
self = self.run(ctx)
|
|
59
|
+
except StopIteration(value=value):
|
|
60
|
+
return value
|
|
61
|
+
)
|
|
62
|
+
|
|
63
|
+
__tl__.memo = Memo.value
|
|
@@ -21,11 +21,18 @@ from .record import *
|
|
|
21
21
|
from .helpers import *
|
|
22
22
|
|
|
23
23
|
|
|
24
|
+
def dummy_memo(*args, **kwargs):
|
|
25
|
+
raise RuntimeError(
|
|
26
|
+
"memo is not available without the prelude. Please import koatl.prelude."
|
|
27
|
+
)
|
|
28
|
+
|
|
29
|
+
|
|
24
30
|
__tl__ = SimpleNamespace(
|
|
25
31
|
Exception=Exception,
|
|
26
32
|
slice=slice,
|
|
27
33
|
vget=virtual.vget,
|
|
28
34
|
vhas=virtual.vhas,
|
|
35
|
+
memo=dummy_memo,
|
|
29
36
|
unpack_record=helpers.unpack_record,
|
|
30
37
|
set_exports=helpers.set_exports,
|
|
31
38
|
do=helpers.do,
|
|
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
|