koatl 0.3.14__tar.gz → 0.3.16__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.3.14 → koatl-0.3.16}/Cargo.lock +2 -2
- {koatl-0.3.14 → koatl-0.3.16}/PKG-INFO +2 -1
- {koatl-0.3.14 → koatl-0.3.16}/koatl/Cargo.toml +2 -1
- {koatl-0.3.14 → koatl-0.3.16}/koatl/python/koatl/prelude/__init__.tl +14 -3
- {koatl-0.3.14 → koatl-0.3.16}/koatl/python/koatl/runtime/record.py +44 -5
- {koatl-0.3.14 → koatl-0.3.16}/koatl/python/koatl/std/iter.tl +6 -4
- {koatl-0.3.14 → koatl-0.3.16}/koatl/python/koatl/std/re.tl +1 -1
- koatl-0.3.16/koatl/tests/conftest.py +62 -0
- {koatl-0.3.14/koatl/tests/e2e/prelude → koatl-0.3.16/koatl/tests/e2e/base}/imports.tl +3 -3
- koatl-0.3.16/koatl/tests/e2e/base/imports2.tl +15 -0
- koatl-0.3.16/koatl/tests/fail-parse/unmatched_closing_delimiter.tl +1 -0
- {koatl-0.3.14 → koatl-0.3.16}/koatl/tests/test_e2e.py +1 -1
- koatl-0.3.16/koatl/tests/test_iterable.tl +176 -0
- koatl-0.3.16/koatl/tests/test_re.tl +204 -0
- koatl-0.3.16/koatl/tests/util/__init__.py +11 -0
- {koatl-0.3.14 → koatl-0.3.16}/koatl-core/src/py/ast.rs +1 -1
- {koatl-0.3.14 → koatl-0.3.16}/koatl-core/src/transform.rs +10 -15
- {koatl-0.3.14 → koatl-0.3.16}/koatl-parser/src/lexer.rs +16 -7
- {koatl-0.3.14 → koatl-0.3.16}/koatl-parser/src/parser.rs +24 -2
- {koatl-0.3.14 → koatl-0.3.16}/python/koatl/prelude/__init__.tl +14 -3
- {koatl-0.3.14 → koatl-0.3.16}/python/koatl/runtime/record.py +44 -5
- {koatl-0.3.14 → koatl-0.3.16}/python/koatl/std/iter.tl +6 -4
- {koatl-0.3.14 → koatl-0.3.16}/python/koatl/std/re.tl +1 -1
- koatl-0.3.14/koatl/tests/e2e/util/__init__.py +0 -2
- {koatl-0.3.14 → koatl-0.3.16}/Cargo.toml +0 -0
- {koatl-0.3.14 → koatl-0.3.16}/README.md +0 -0
- {koatl-0.3.14 → koatl-0.3.16}/koatl/.github/workflows/CI.yml +0 -0
- {koatl-0.3.14 → koatl-0.3.16}/koatl/.gitignore +0 -0
- {koatl-0.3.14 → koatl-0.3.16}/koatl/LICENSE +0 -0
- {koatl-0.3.14 → koatl-0.3.16}/koatl/README.md +0 -0
- {koatl-0.3.14 → koatl-0.3.16}/koatl/python/koatl/__init__.py +0 -0
- {koatl-0.3.14 → koatl-0.3.16}/koatl/python/koatl/__main__.py +0 -0
- {koatl-0.3.14 → koatl-0.3.16}/koatl/python/koatl/cli.py +0 -0
- {koatl-0.3.14 → koatl-0.3.16}/koatl/python/koatl/notebook/__init__.py +0 -0
- {koatl-0.3.14 → koatl-0.3.16}/koatl/python/koatl/notebook/magic.py +0 -0
- {koatl-0.3.14 → koatl-0.3.16}/koatl/python/koatl/runtime/__init__.py +0 -0
- {koatl-0.3.14 → koatl-0.3.16}/koatl/python/koatl/runtime/meta_finder.py +0 -0
- {koatl-0.3.14 → koatl-0.3.16}/koatl/python/koatl/runtime/vattr.py +0 -0
- {koatl-0.3.14 → koatl-0.3.16}/koatl/python/koatl/std/__init__.tl +0 -0
- {koatl-0.3.14 → koatl-0.3.16}/koatl/python/koatl/std/control/__init__.tl +0 -0
- {koatl-0.3.14 → koatl-0.3.16}/koatl/python/koatl/std/control/async.tl +0 -0
- {koatl-0.3.14 → koatl-0.3.16}/koatl/python/koatl/std/control/base.tl +0 -0
- {koatl-0.3.14 → koatl-0.3.16}/koatl/python/koatl/std/control/do.tl +0 -0
- {koatl-0.3.14 → koatl-0.3.16}/koatl/python/koatl/std/control/env.tl +0 -0
- {koatl-0.3.14 → koatl-0.3.16}/koatl/python/koatl/std/control/memo.tl +0 -0
- {koatl-0.3.14 → koatl-0.3.16}/koatl/python/koatl/std/control/result.tl +0 -0
- {koatl-0.3.14 → koatl-0.3.16}/koatl/python/koatl/std/data/__init__.tl +0 -0
- {koatl-0.3.14 → koatl-0.3.16}/koatl/python/koatl/std/data/list.tl +0 -0
- {koatl-0.3.14 → koatl-0.3.16}/koatl/python/koatl/std/data/record.tl +0 -0
- {koatl-0.3.14 → koatl-0.3.16}/koatl/python/koatl/std/ext.tl +0 -0
- {koatl-0.3.14 → koatl-0.3.16}/koatl/python/koatl/std/io.tl +0 -0
- {koatl-0.3.14 → koatl-0.3.16}/koatl/python/koatl/std/json.tl +0 -0
- {koatl-0.3.14 → koatl-0.3.16}/koatl/python/koatl/std/lazy_module.tl +0 -0
- {koatl-0.3.14 → koatl-0.3.16}/koatl/python/koatl/std/pickle.tl +0 -0
- {koatl-0.3.14 → koatl-0.3.16}/koatl/python/koatl/std/trait.py +0 -0
- {koatl-0.3.14 → koatl-0.3.16}/koatl/requirements.txt +0 -0
- {koatl-0.3.14 → koatl-0.3.16}/koatl/src/emit_py.rs +0 -0
- {koatl-0.3.14 → koatl-0.3.16}/koatl/src/lib.rs +0 -0
- {koatl-0.3.14 → koatl-0.3.16}/koatl/tests/e2e/base/arguments.tl +0 -0
- {koatl-0.3.14 → koatl-0.3.16}/koatl/tests/e2e/base/containers.tl +0 -0
- {koatl-0.3.14 → koatl-0.3.16}/koatl/tests/e2e/base/data.txt +0 -0
- {koatl-0.3.14 → koatl-0.3.16}/koatl/tests/e2e/base/decorators.tl +0 -0
- {koatl-0.3.14 → koatl-0.3.16}/koatl/tests/e2e/base/destructure-for-and-fn.tl +0 -0
- {koatl-0.3.14 → koatl-0.3.16}/koatl/tests/e2e/base/destructure.tl +0 -0
- {koatl-0.3.14 → koatl-0.3.16}/koatl/tests/e2e/base/escape_ident.tl +0 -0
- {koatl-0.3.14 → koatl-0.3.16}/koatl/tests/e2e/base/fstr.tl +0 -0
- {koatl-0.3.14 → koatl-0.3.16}/koatl/tests/e2e/base/functions.tl +0 -0
- {koatl-0.3.14 → koatl-0.3.16}/koatl/tests/e2e/base/generator.tl +0 -0
- {koatl-0.3.14 → koatl-0.3.16}/koatl/tests/e2e/base/if_expr.tl +0 -0
- {koatl-0.3.14 → koatl-0.3.16}/koatl/tests/e2e/base/loops.tl +0 -0
- {koatl-0.3.14 → koatl-0.3.16}/koatl/tests/e2e/base/match.tl +0 -0
- {koatl-0.3.14 → koatl-0.3.16}/koatl/tests/e2e/base/nary-list.tl +0 -0
- {koatl-0.3.14 → koatl-0.3.16}/koatl/tests/e2e/base/placeholder.tl +0 -0
- {koatl-0.3.14 → koatl-0.3.16}/koatl/tests/e2e/base/precedence.tl +0 -0
- {koatl-0.3.14 → koatl-0.3.16}/koatl/tests/e2e/base/scopes.tl +0 -0
- {koatl-0.3.14 → koatl-0.3.16}/koatl/tests/e2e/base/semantic_whitespace.tl +0 -0
- {koatl-0.3.14 → koatl-0.3.16}/koatl/tests/e2e/base/short_circuit.tl +0 -0
- {koatl-0.3.14 → koatl-0.3.16}/koatl/tests/e2e/base/with.tl +0 -0
- {koatl-0.3.14 → koatl-0.3.16}/koatl/tests/e2e/prelude/async.tl +0 -0
- {koatl-0.3.14 → koatl-0.3.16}/koatl/tests/e2e/prelude/aug_assign.tl +0 -0
- {koatl-0.3.14 → koatl-0.3.16}/koatl/tests/e2e/prelude/coal.tl +0 -0
- {koatl-0.3.14 → koatl-0.3.16}/koatl/tests/e2e/prelude/env.tl +0 -0
- {koatl-0.3.14 → koatl-0.3.16}/koatl/tests/e2e/prelude/iterables.tl +0 -0
- {koatl-0.3.14 → koatl-0.3.16}/koatl/tests/e2e/prelude/list.tl +0 -0
- {koatl-0.3.14 → koatl-0.3.16}/koatl/tests/e2e/prelude/memo.tl +0 -0
- {koatl-0.3.14 → koatl-0.3.16}/koatl/tests/e2e/prelude/record.tl +0 -0
- {koatl-0.3.14 → koatl-0.3.16}/koatl/tests/e2e/prelude/result.tl +0 -0
- {koatl-0.3.14 → koatl-0.3.16}/koatl/tests/e2e/prelude/slice.tl +0 -0
- {koatl-0.3.14 → koatl-0.3.16}/koatl/tests/e2e/prelude/try.tl +0 -0
- {koatl-0.3.14 → koatl-0.3.16}/koatl/tests/e2e/prelude/virtual.tl +0 -0
- {koatl-0.3.14/koatl/tests/e2e/util → koatl-0.3.16/koatl/tests/e2e/test_modules}/module0.tl +0 -0
- {koatl-0.3.14/koatl/tests/e2e/util → koatl-0.3.16/koatl/tests/e2e/test_modules}/module1.tl +0 -0
- {koatl-0.3.14/koatl/tests/e2e/util → koatl-0.3.16/koatl/tests/e2e/test_modules}/module2.tl +0 -0
- {koatl-0.3.14 → koatl-0.3.16}/koatl/tests/fail-parse/arguments_mixed_defaults.tl +0 -0
- {koatl-0.3.14 → koatl-0.3.16}/koatl/tests/fail-parse/arguments_multiple_kwargs.tl +0 -0
- {koatl-0.3.14 → koatl-0.3.16}/koatl/tests/fail-parse/arguments_multiple_kwonly_markers.tl +0 -0
- {koatl-0.3.14 → koatl-0.3.16}/koatl/tests/fail-parse/arguments_multiple_posonly_markers.tl +0 -0
- {koatl-0.3.14 → koatl-0.3.16}/koatl/tests/fail-parse/arguments_multiple_varargs.tl +0 -0
- {koatl-0.3.14 → koatl-0.3.16}/koatl/tests/fail-parse/arguments_posonly_after_kwonly.tl +0 -0
- {koatl-0.3.14 → koatl-0.3.16}/koatl/tests/fail-parse/arguments_vararg_and_kwonly_marker.tl +0 -0
- {koatl-0.3.14 → koatl-0.3.16}/koatl/tests/parse/arith.tl +0 -0
- {koatl-0.3.14 → koatl-0.3.16}/koatl/tests/parse/assign.tl +0 -0
- {koatl-0.3.14 → koatl-0.3.16}/koatl/tests/parse/block-comments.tl +0 -0
- {koatl-0.3.14 → koatl-0.3.16}/koatl/tests/parse/deco.tl +0 -0
- {koatl-0.3.14 → koatl-0.3.16}/koatl/tests/parse/func.tl +0 -0
- {koatl-0.3.14 → koatl-0.3.16}/koatl/tests/parse/matches.tl +0 -0
- {koatl-0.3.14 → koatl-0.3.16}/koatl/tests/parse/mutual-recursion.tl +0 -0
- {koatl-0.3.14 → koatl-0.3.16}/koatl/tests/parse/numbers.tl +0 -0
- {koatl-0.3.14 → koatl-0.3.16}/koatl/tests/parse/operators.tl +0 -0
- {koatl-0.3.14 → koatl-0.3.16}/koatl/tests/test_parse.py +0 -0
- {koatl-0.3.14 → koatl-0.3.16}/koatl/tests/test_parse_fail.py +0 -0
- {koatl-0.3.14 → koatl-0.3.16}/koatl-core/Cargo.toml +0 -0
- {koatl-0.3.14 → koatl-0.3.16}/koatl-core/src/ast.rs +0 -0
- {koatl-0.3.14 → koatl-0.3.16}/koatl-core/src/ast_builder.rs +0 -0
- {koatl-0.3.14 → koatl-0.3.16}/koatl-core/src/inference.rs +0 -0
- {koatl-0.3.14 → koatl-0.3.16}/koatl-core/src/lib.rs +0 -0
- {koatl-0.3.14 → koatl-0.3.16}/koatl-core/src/lift_cst.rs +0 -0
- {koatl-0.3.14 → koatl-0.3.16}/koatl-core/src/main.rs +0 -0
- {koatl-0.3.14 → koatl-0.3.16}/koatl-core/src/py/ast_builder.rs +0 -0
- {koatl-0.3.14 → koatl-0.3.16}/koatl-core/src/py/emit.rs +0 -0
- {koatl-0.3.14 → koatl-0.3.16}/koatl-core/src/py/mod.rs +0 -0
- {koatl-0.3.14 → koatl-0.3.16}/koatl-core/src/resolve_scopes.rs +0 -0
- {koatl-0.3.14 → koatl-0.3.16}/koatl-core/src/types.rs +0 -0
- {koatl-0.3.14 → koatl-0.3.16}/koatl-core/src/util.rs +0 -0
- {koatl-0.3.14 → koatl-0.3.16}/koatl-parser/Cargo.toml +0 -0
- {koatl-0.3.14 → koatl-0.3.16}/koatl-parser/src/cst.rs +0 -0
- {koatl-0.3.14 → koatl-0.3.16}/koatl-parser/src/lib.rs +0 -0
- {koatl-0.3.14 → koatl-0.3.16}/koatl-parser/src/simple_fmt.rs +0 -0
- {koatl-0.3.14 → koatl-0.3.16}/pyproject.toml +0 -0
- {koatl-0.3.14 → koatl-0.3.16}/python/koatl/__init__.py +0 -0
- {koatl-0.3.14 → koatl-0.3.16}/python/koatl/__main__.py +0 -0
- {koatl-0.3.14 → koatl-0.3.16}/python/koatl/cli.py +0 -0
- {koatl-0.3.14 → koatl-0.3.16}/python/koatl/notebook/__init__.py +0 -0
- {koatl-0.3.14 → koatl-0.3.16}/python/koatl/notebook/magic.py +0 -0
- {koatl-0.3.14 → koatl-0.3.16}/python/koatl/runtime/__init__.py +0 -0
- {koatl-0.3.14 → koatl-0.3.16}/python/koatl/runtime/meta_finder.py +0 -0
- {koatl-0.3.14 → koatl-0.3.16}/python/koatl/runtime/vattr.py +0 -0
- {koatl-0.3.14 → koatl-0.3.16}/python/koatl/std/__init__.tl +0 -0
- {koatl-0.3.14 → koatl-0.3.16}/python/koatl/std/control/__init__.tl +0 -0
- {koatl-0.3.14 → koatl-0.3.16}/python/koatl/std/control/async.tl +0 -0
- {koatl-0.3.14 → koatl-0.3.16}/python/koatl/std/control/base.tl +0 -0
- {koatl-0.3.14 → koatl-0.3.16}/python/koatl/std/control/do.tl +0 -0
- {koatl-0.3.14 → koatl-0.3.16}/python/koatl/std/control/env.tl +0 -0
- {koatl-0.3.14 → koatl-0.3.16}/python/koatl/std/control/memo.tl +0 -0
- {koatl-0.3.14 → koatl-0.3.16}/python/koatl/std/control/result.tl +0 -0
- {koatl-0.3.14 → koatl-0.3.16}/python/koatl/std/data/__init__.tl +0 -0
- {koatl-0.3.14 → koatl-0.3.16}/python/koatl/std/data/list.tl +0 -0
- {koatl-0.3.14 → koatl-0.3.16}/python/koatl/std/data/record.tl +0 -0
- {koatl-0.3.14 → koatl-0.3.16}/python/koatl/std/ext.tl +0 -0
- {koatl-0.3.14 → koatl-0.3.16}/python/koatl/std/io.tl +0 -0
- {koatl-0.3.14 → koatl-0.3.16}/python/koatl/std/json.tl +0 -0
- {koatl-0.3.14 → koatl-0.3.16}/python/koatl/std/lazy_module.tl +0 -0
- {koatl-0.3.14 → koatl-0.3.16}/python/koatl/std/pickle.tl +0 -0
- {koatl-0.3.14 → koatl-0.3.16}/python/koatl/std/trait.py +0 -0
|
@@ -190,7 +190,7 @@ checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c"
|
|
|
190
190
|
|
|
191
191
|
[[package]]
|
|
192
192
|
name = "koatl"
|
|
193
|
-
version = "0.3.
|
|
193
|
+
version = "0.3.16"
|
|
194
194
|
dependencies = [
|
|
195
195
|
"ariadne",
|
|
196
196
|
"koatl-core",
|
|
@@ -248,7 +248,7 @@ dependencies = [
|
|
|
248
248
|
|
|
249
249
|
[[package]]
|
|
250
250
|
name = "ohtli"
|
|
251
|
-
version = "0.1.
|
|
251
|
+
version = "0.1.2"
|
|
252
252
|
dependencies = [
|
|
253
253
|
"anyhow",
|
|
254
254
|
"clap",
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: koatl
|
|
3
|
-
Version: 0.3.
|
|
3
|
+
Version: 0.3.16
|
|
4
4
|
Classifier: Programming Language :: Rust
|
|
5
5
|
Classifier: Programming Language :: Python :: Implementation :: CPython
|
|
6
6
|
Classifier: Programming Language :: Python :: Implementation :: PyPy
|
|
7
7
|
License-File: LICENSE
|
|
8
|
+
Home-Page: https://koatl.org
|
|
8
9
|
Requires-Python: >=3.8
|
|
9
10
|
Description-Content-Type: text/markdown; charset=UTF-8; variant=GFM
|
|
10
11
|
|
|
@@ -14,14 +14,25 @@ import koatl.std.(
|
|
|
14
14
|
export std = LazyModule("koatl.std")
|
|
15
15
|
export mod = RootModulesProxy()
|
|
16
16
|
|
|
17
|
+
# Extensions
|
|
18
|
+
|
|
17
19
|
Extension.trait(Iterable)
|
|
18
20
|
|
|
21
|
+
Extension.method(str, "match")! (regex, str) => Pattern(regex).match(str)
|
|
22
|
+
Extension.method(str, "matches")! (str, regex) => Pattern(regex).match(str)
|
|
23
|
+
|
|
19
24
|
Extension.property(list, "len")! List.len.fget
|
|
25
|
+
Extension.method(list, "map")! (self, f) => self.iter.map(f).list()
|
|
26
|
+
Extension.method(list, "filter")! (self, f) => self.iter.filter(f).list()
|
|
20
27
|
|
|
21
|
-
Extension.
|
|
28
|
+
Extension.method(dict, "map")! (self, f) => self.iter.map(f).dict()
|
|
29
|
+
Extension.method(dict, "map_values")! (self, f) => self.iter.map([k, v] => [k, f(v)]).dict()
|
|
30
|
+
Extension.method(dict, "map_keys")! (self, f) => self.iter.map([k, v] => [f(k), v]).dict()
|
|
31
|
+
Extension.method(dict, "filter")! (self, f) => self.iter.filter(f).dict()
|
|
32
|
+
Extension.method(dict, "filter_keys")! (self, f) => self.iter.filter([k, v] => f(k)).dict()
|
|
33
|
+
Extension.method(dict, "filter_values")! (self, f) => self.iter.filter([k, v] => f(v)).dict()
|
|
22
34
|
|
|
23
|
-
|
|
24
|
-
Extension.method(str, "matches")! (str, regex) => Pattern(regex).match(str)
|
|
35
|
+
# Implementations for language features
|
|
25
36
|
|
|
26
37
|
__tl__.do = koatl.std.control.do.do
|
|
27
38
|
|
|
@@ -4,8 +4,6 @@ import functools
|
|
|
4
4
|
import inspect
|
|
5
5
|
import re
|
|
6
6
|
|
|
7
|
-
_property = property
|
|
8
|
-
|
|
9
7
|
__all__ = ["Record"]
|
|
10
8
|
|
|
11
9
|
|
|
@@ -48,9 +46,50 @@ class Record:
|
|
|
48
46
|
|
|
49
47
|
return object.__getattribute__(self, name)
|
|
50
48
|
|
|
51
|
-
|
|
49
|
+
def map(self, f):
|
|
50
|
+
newrec = Record()
|
|
51
|
+
for k, v in self.items():
|
|
52
|
+
nk, nv = f((k, v))
|
|
53
|
+
newrec[nk] = nv
|
|
54
|
+
return newrec
|
|
55
|
+
|
|
56
|
+
def map_values(self, f):
|
|
57
|
+
newrec = Record()
|
|
58
|
+
for k, v in self.items():
|
|
59
|
+
newrec[k] = f(v)
|
|
60
|
+
return newrec
|
|
61
|
+
|
|
62
|
+
def map_keys(self, f):
|
|
63
|
+
newrec = Record()
|
|
64
|
+
for k, v in self.items():
|
|
65
|
+
nk = f(k)
|
|
66
|
+
newrec[nk] = v
|
|
67
|
+
return newrec
|
|
68
|
+
|
|
69
|
+
def filter(self, f):
|
|
70
|
+
newrec = Record()
|
|
71
|
+
for k, v in self.items():
|
|
72
|
+
if f((k, v)):
|
|
73
|
+
newrec[k] = v
|
|
74
|
+
return newrec
|
|
75
|
+
|
|
76
|
+
def filter_values(self, f):
|
|
77
|
+
newrec = Record()
|
|
78
|
+
for k, v in self.items():
|
|
79
|
+
if f(v):
|
|
80
|
+
newrec[k] = v
|
|
81
|
+
return newrec
|
|
82
|
+
|
|
83
|
+
def filter_keys(self, f):
|
|
84
|
+
newrec = Record()
|
|
85
|
+
for k, v in self.items():
|
|
86
|
+
if f(k):
|
|
87
|
+
newrec[k] = v
|
|
88
|
+
return newrec
|
|
89
|
+
|
|
90
|
+
@__builtins__["property"]
|
|
52
91
|
def iter(self):
|
|
53
|
-
return self.items()
|
|
92
|
+
return iter(self.items())
|
|
54
93
|
|
|
55
94
|
# MutableMapping
|
|
56
95
|
def __len__(self):
|
|
@@ -130,7 +169,7 @@ class Record:
|
|
|
130
169
|
c.update(self)
|
|
131
170
|
return c
|
|
132
171
|
|
|
133
|
-
@
|
|
172
|
+
@__builtins__["property"]
|
|
134
173
|
def len(self):
|
|
135
174
|
return len(self)
|
|
136
175
|
|
|
@@ -10,7 +10,7 @@ export Iterable = class(Traversable, Trait):
|
|
|
10
10
|
|
|
11
11
|
skip = (self, n) =>
|
|
12
12
|
let it = self.iter
|
|
13
|
-
for _ in..n:
|
|
13
|
+
for _ in ..n:
|
|
14
14
|
next(it, None)
|
|
15
15
|
it
|
|
16
16
|
|
|
@@ -27,7 +27,7 @@ export Iterable = class(Traversable, Trait):
|
|
|
27
27
|
take = (self, n) =>
|
|
28
28
|
let impl = () =>
|
|
29
29
|
let it = self.iter
|
|
30
|
-
for _ in..n:
|
|
30
|
+
for _ in ..n:
|
|
31
31
|
try:
|
|
32
32
|
yield next(it)
|
|
33
33
|
except StopIteration(value=value) =>
|
|
@@ -56,6 +56,8 @@ export Iterable = class(Traversable, Trait):
|
|
|
56
56
|
product = (self, *others) =>
|
|
57
57
|
itertools.product(self.iter, *others.map($.iter))
|
|
58
58
|
|
|
59
|
+
cycle = self => itertools.cycle(self.iter)
|
|
60
|
+
|
|
59
61
|
zip = (self, *others) =>
|
|
60
62
|
zip(self.iter, *others.map($.iter))
|
|
61
63
|
|
|
@@ -86,7 +88,7 @@ export Iterable = class(Traversable, Trait):
|
|
|
86
88
|
|
|
87
89
|
reverse = self => reversed(list(self.iter))
|
|
88
90
|
|
|
89
|
-
|
|
91
|
+
sort = (self, key=None, reverse=False) =>
|
|
90
92
|
sorted(self.iter, key=key, reverse=reverse)
|
|
91
93
|
|
|
92
94
|
copy = self => itertools.tee(self.iter)
|
|
@@ -184,7 +186,7 @@ export Iterable = class(Traversable, Trait):
|
|
|
184
186
|
|
|
185
187
|
impl()
|
|
186
188
|
|
|
187
|
-
|
|
189
|
+
join = (self, sep="") =>
|
|
188
190
|
sep.join(self.map(str))
|
|
189
191
|
|
|
190
192
|
sum = self =>
|
|
@@ -20,7 +20,7 @@ export Pattern = class:
|
|
|
20
20
|
if not isinstance(string, str):
|
|
21
21
|
raise TypeError(f"Expected a string, but got {type(string).__name__}")
|
|
22
22
|
|
|
23
|
-
self.pattern.match(string, flags).
|
|
23
|
+
self.pattern.match(string, flags).(Result).map(Match)
|
|
24
24
|
|
|
25
25
|
export Match = collections.abc.Sequence.register! class:
|
|
26
26
|
__slots__ = ("_match",)
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Pytest configuration for Koatl tests.
|
|
3
|
+
This allows pytest to discover and execute .tl files as test modules.
|
|
4
|
+
"""
|
|
5
|
+
import pytest
|
|
6
|
+
import koatl
|
|
7
|
+
import sys
|
|
8
|
+
from pathlib import Path
|
|
9
|
+
|
|
10
|
+
# Add e2e directory to Python path so util module can be imported
|
|
11
|
+
sys.path.insert(0, str(Path(__file__).parent / "e2e"))
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def pytest_collect_file(parent, file_path):
|
|
15
|
+
"""
|
|
16
|
+
Custom collector to discover .tl files as test modules.
|
|
17
|
+
"""
|
|
18
|
+
if file_path.suffix == ".tl" and file_path.name.startswith("test_"):
|
|
19
|
+
return TlModule.from_parent(parent, path=file_path)
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
class TlModule(pytest.Module):
|
|
23
|
+
"""
|
|
24
|
+
Custom pytest Module for .tl files.
|
|
25
|
+
Transpiles the .tl file and collects test functions from it.
|
|
26
|
+
"""
|
|
27
|
+
|
|
28
|
+
def collect(self):
|
|
29
|
+
"""
|
|
30
|
+
Transpile the .tl file and collect test functions.
|
|
31
|
+
"""
|
|
32
|
+
with open(self.path, "r") as f:
|
|
33
|
+
source = f.read()
|
|
34
|
+
|
|
35
|
+
try:
|
|
36
|
+
# Transpile to Python AST in module mode
|
|
37
|
+
py_ast = koatl.transpile(source, mode="module")
|
|
38
|
+
|
|
39
|
+
# Create a namespace for the module
|
|
40
|
+
module_name = self.path.stem
|
|
41
|
+
module_namespace = {
|
|
42
|
+
"__name__": module_name,
|
|
43
|
+
"__file__": str(self.path),
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
# Compile and execute the Python AST in the namespace
|
|
47
|
+
# This defines all test_* functions
|
|
48
|
+
code_obj = compile(py_ast, str(self.path), "exec")
|
|
49
|
+
exec(code_obj, module_namespace)
|
|
50
|
+
|
|
51
|
+
# Collect test functions from the namespace
|
|
52
|
+
for name, obj in module_namespace.items():
|
|
53
|
+
if name.startswith("test_") and callable(obj):
|
|
54
|
+
func = pytest.Function.from_parent(
|
|
55
|
+
self,
|
|
56
|
+
name=name
|
|
57
|
+
)
|
|
58
|
+
func.obj = obj
|
|
59
|
+
yield func
|
|
60
|
+
except Exception as e:
|
|
61
|
+
# If transpilation fails, create an error item
|
|
62
|
+
raise self.CollectError(f"Error transpiling {self.path}: {e}") from e
|
|
@@ -11,18 +11,18 @@ import os.*
|
|
|
11
11
|
|
|
12
12
|
assert_eq(getcwd, os.getcwd)
|
|
13
13
|
|
|
14
|
-
import
|
|
14
|
+
import e2e.test_modules.module0
|
|
15
15
|
|
|
16
16
|
assert_eq(set(module0.__all__), set(["z"]))
|
|
17
17
|
assert_eq(module0.z, 3)
|
|
18
18
|
|
|
19
|
-
import
|
|
19
|
+
import e2e.test_modules.module1
|
|
20
20
|
|
|
21
21
|
assert_eq(set(module1.__all__), set(["a", "z"]))
|
|
22
22
|
assert_eq(module1.a, 1)
|
|
23
23
|
assert_eq(module1.z, 3)
|
|
24
24
|
|
|
25
|
-
import
|
|
25
|
+
import e2e.test_modules.module2
|
|
26
26
|
|
|
27
27
|
assert_eq(set(module2.__all__), set(["b"]))
|
|
28
28
|
assert_eq(module2.b, 3)
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import ast
|
|
2
|
+
import koatl
|
|
3
|
+
import util.assert_contains
|
|
4
|
+
|
|
5
|
+
# Test: import a.b should emit "from a import b"
|
|
6
|
+
parsed = koatl.transpile("import a.b", mode="no_prelude")
|
|
7
|
+
assert_contains(ast.unparse(parsed), "from a import b")
|
|
8
|
+
|
|
9
|
+
# Test: import a.b.(.) should emit "import a.b as b"
|
|
10
|
+
parsed = koatl.transpile("import a.b.(.)", mode="no_prelude")
|
|
11
|
+
assert_contains(ast.unparse(parsed), "import a.b as b")
|
|
12
|
+
|
|
13
|
+
# Test: import a.b.c should emit "from a.b import c"
|
|
14
|
+
parsed = koatl.transpile("import a.b.c", mode="no_prelude")
|
|
15
|
+
assert_contains(ast.unparse(parsed), "from a.b import c")
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
a)
|
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
import util.assert_eq
|
|
2
|
+
|
|
3
|
+
test_sum = () =>
|
|
4
|
+
assert_eq((..10).sum(), 45)
|
|
5
|
+
assert_eq([1, 2, 3, 4, 5].sum(), 15)
|
|
6
|
+
assert_eq([].sum(), 0)
|
|
7
|
+
assert_eq([1.5, 2.5, 3.0].sum(), 7.0)
|
|
8
|
+
|
|
9
|
+
test_product = () =>
|
|
10
|
+
let prod_iter = [1, 2, 3].product([4, 5])
|
|
11
|
+
assert_eq(list(prod_iter), [(1, 4), (1, 5), (2, 4), (2, 5), (3, 4), (3, 5)])
|
|
12
|
+
|
|
13
|
+
test_min = () =>
|
|
14
|
+
assert_eq([3, 1, 4, 1, 5].min(), 1)
|
|
15
|
+
assert_eq([10, 5, 8].min(), 5)
|
|
16
|
+
assert_eq([42].min(), 42)
|
|
17
|
+
|
|
18
|
+
test_max = () =>
|
|
19
|
+
assert_eq([3, 1, 4, 1, 5].max(), 5)
|
|
20
|
+
assert_eq([10, 5, 8].max(), 10)
|
|
21
|
+
assert_eq([42].max(), 42)
|
|
22
|
+
|
|
23
|
+
test_map = () =>
|
|
24
|
+
# List.map returns a list directly (not an iterator)
|
|
25
|
+
assert_eq([1, 2, 3].map($ * 2), [2, 4, 6])
|
|
26
|
+
assert_eq([1, 2, 3].map($ + 10), [11, 12, 13])
|
|
27
|
+
assert_eq([].map($ * 2), [])
|
|
28
|
+
# Range/iterator map still returns an iterator
|
|
29
|
+
assert_eq((..5).map($ * 2).list(), [0, 2, 4, 6, 8])
|
|
30
|
+
|
|
31
|
+
test_filter = () =>
|
|
32
|
+
assert_eq([1, 2, 3, 4, 5].filter($ > 3).list(), [4, 5])
|
|
33
|
+
assert_eq([1, 2, 3, 4, 5].filter($ %% 2 == 0).list(), [2, 4])
|
|
34
|
+
assert_eq((..10).filter($ > 5).list(), [6, 7, 8, 9])
|
|
35
|
+
assert_eq([1, 2, 3].filter($ > 10).list(), [])
|
|
36
|
+
|
|
37
|
+
test_flat_map = () =>
|
|
38
|
+
assert_eq([1, 2, 3].flat_map(x => [x, x * 2]).list(), [1, 2, 2, 4, 3, 6])
|
|
39
|
+
assert_eq([[1, 2], [3, 4]].flat_map(x => x).list(), [1, 2, 3, 4])
|
|
40
|
+
assert_eq([].flat_map(x => [x, x]).list(), [])
|
|
41
|
+
|
|
42
|
+
test_find = () =>
|
|
43
|
+
# find() returns Ok(value) or Err()
|
|
44
|
+
assert_eq([1, 2, 3, 4, 5].find($ > 3).ok, True)
|
|
45
|
+
let result = [1, 2, 3, 4, 5].find($ > 10)
|
|
46
|
+
assert_eq(result.ok, False)
|
|
47
|
+
|
|
48
|
+
test_any = () =>
|
|
49
|
+
assert_eq([1, 2, 3].any(x => x > 2), True)
|
|
50
|
+
assert_eq([1, 2, 3].any(x => x > 10), False)
|
|
51
|
+
assert_eq([].any(x => x > 0), False)
|
|
52
|
+
assert_eq([False, False, True].any(x => x), True)
|
|
53
|
+
|
|
54
|
+
test_all = () =>
|
|
55
|
+
assert_eq([1, 2, 3].all(x => x > 0), True)
|
|
56
|
+
assert_eq([1, 2, 3].all(x => x > 2), False)
|
|
57
|
+
assert_eq([].all(x => x > 0), True)
|
|
58
|
+
assert_eq([True, True, True].all(x => x), True)
|
|
59
|
+
|
|
60
|
+
test_count = () =>
|
|
61
|
+
# count() works on Iterable trait via .iter
|
|
62
|
+
assert_eq([1, 2, 3, 4, 5].iter.count(x => x > 2), 3)
|
|
63
|
+
assert_eq([1, 2, 3, 4, 5].iter.count(x => x %% 2 == 0), 2)
|
|
64
|
+
assert_eq([1, 2, 3].iter.count(x => x > 10), 0)
|
|
65
|
+
|
|
66
|
+
test_take = () =>
|
|
67
|
+
assert_eq([1, 2, 3, 4, 5].take(3).list(), [1, 2, 3])
|
|
68
|
+
assert_eq((..100).take(5).list(), [0, 1, 2, 3, 4])
|
|
69
|
+
assert_eq([1, 2].take(10).list(), [1, 2])
|
|
70
|
+
assert_eq([].take(5).list(), [])
|
|
71
|
+
|
|
72
|
+
test_skip = () =>
|
|
73
|
+
assert_eq([1, 2, 3, 4, 5].skip(2).list(), [3, 4, 5])
|
|
74
|
+
assert_eq((..10).skip(5).list(), [5, 6, 7, 8, 9])
|
|
75
|
+
assert_eq([1, 2].skip(10).list(), [])
|
|
76
|
+
assert_eq([].skip(5).list(), [])
|
|
77
|
+
|
|
78
|
+
test_take_while = () =>
|
|
79
|
+
assert_eq([1, 2, 3, 4, 5].take_while($ < 4).list(), [1, 2, 3])
|
|
80
|
+
assert_eq([2, 4, 6, 7, 8].take_while($ %% 2 == 0).list(), [2, 4, 6])
|
|
81
|
+
assert_eq([1, 2, 3].take_while($ > 10).list(), [])
|
|
82
|
+
|
|
83
|
+
test_skip_while = () =>
|
|
84
|
+
# Uses skip_while() method
|
|
85
|
+
assert_eq([1, 2, 3, 4, 5].skip_while($ < 4).list(), [4, 5])
|
|
86
|
+
assert_eq([2, 4, 6, 7, 8].skip_while($ %% 2 == 0).list(), [7, 8])
|
|
87
|
+
assert_eq([1, 2, 3].skip_while($ > 10).list(), [1, 2, 3])
|
|
88
|
+
|
|
89
|
+
test_enumerate = () =>
|
|
90
|
+
assert_eq((..3).enumerate().list(), [(0, 0), (1, 1), (2, 2)])
|
|
91
|
+
assert_eq(["a", "b", "c"].enumerate().list(), [(0, "a"), (1, "b"), (2, "c")])
|
|
92
|
+
|
|
93
|
+
test_zip = () =>
|
|
94
|
+
assert_eq([1, 2, 3].zip([4, 5, 6]).list(), [(1, 4), (2, 5), (3, 6)])
|
|
95
|
+
assert_eq([1, 2].zip(["a", "b", "c"]).list(), [(1, "a"), (2, "b")])
|
|
96
|
+
assert_eq([].zip([1, 2, 3]).list(), [])
|
|
97
|
+
|
|
98
|
+
test_chain = () =>
|
|
99
|
+
assert_eq([1, 2].chain([3, 4]).list(), [1, 2, 3, 4])
|
|
100
|
+
assert_eq([1].chain([]).chain([2, 3]).list(), [1, 2, 3])
|
|
101
|
+
assert_eq([].chain([]).list(), [])
|
|
102
|
+
|
|
103
|
+
test_cycle = () =>
|
|
104
|
+
assert_eq([1, 2, 3].cycle().take(7).list(), [1, 2, 3, 1, 2, 3, 1])
|
|
105
|
+
assert_eq([5].cycle().take(3).list(), [5, 5, 5])
|
|
106
|
+
|
|
107
|
+
test_reverse = () =>
|
|
108
|
+
# reverse() is a method on Iterable trait, accessed via .iter
|
|
109
|
+
assert_eq(list([1, 2, 3, 4, 5].iter.reverse()), [5, 4, 3, 2, 1])
|
|
110
|
+
assert_eq(list([1].iter.reverse()), [1])
|
|
111
|
+
assert_eq(list([].iter.reverse()), [])
|
|
112
|
+
|
|
113
|
+
test_sort = () =>
|
|
114
|
+
assert_eq([3, 1, 4, 1, 5].iter.sort().list(), [1, 1, 3, 4, 5])
|
|
115
|
+
assert_eq(["c", "a", "b"].iter.sort().list(), ["a", "b", "c"])
|
|
116
|
+
assert_eq([].iter.sort().list(), [])
|
|
117
|
+
|
|
118
|
+
test_join = () =>
|
|
119
|
+
assert_eq(["a", "b", "c"].join(", "), "a, b, c")
|
|
120
|
+
assert_eq([1, 2, 3].map(str).join("-"), "1-2-3")
|
|
121
|
+
assert_eq(["hello"].join(", "), "hello")
|
|
122
|
+
assert_eq([].join(", "), "")
|
|
123
|
+
|
|
124
|
+
test_associate = () =>
|
|
125
|
+
assert_eq((..3).associate($ * 2), {0: 0, 1: 2, 2: 4})
|
|
126
|
+
assert_eq(["a", "bb", "ccc"].associate(len), {"a": 1, "bb": 2, "ccc": 3})
|
|
127
|
+
assert_eq([].associate($ + 1), {})
|
|
128
|
+
|
|
129
|
+
test_group_by = () =>
|
|
130
|
+
assert_eq([1, 2, 3, 4, 5].group_by($ %% 2), {0: [2, 4], 1: [1, 3, 5]})
|
|
131
|
+
assert_eq(["a", "bb", "ccc", "dd"].group_by(len), {1: ["a"], 2: ["bb", "dd"], 3: ["ccc"]})
|
|
132
|
+
assert_eq([].group_by($ > 0), {})
|
|
133
|
+
|
|
134
|
+
test_list_conversion = () =>
|
|
135
|
+
assert_eq((..5).list(), [0, 1, 2, 3, 4])
|
|
136
|
+
assert_eq([1, 2, 3].map($ * 2).list(), [2, 4, 6])
|
|
137
|
+
|
|
138
|
+
test_record_conversion = () =>
|
|
139
|
+
# Dict.map returns a dict directly (not an iterator)
|
|
140
|
+
assert_eq({1: 2, 3: 4}.map([k, v] => [k * 2, v * 3]), {2: 6, 6: 12})
|
|
141
|
+
assert_eq([[1, "a"], [2, "b"]].record(), {1: "a", 2: "b"})
|
|
142
|
+
|
|
143
|
+
test_record_take = () =>
|
|
144
|
+
assert_eq({0: 2}.take(1).list(), [(0, 2)])
|
|
145
|
+
|
|
146
|
+
test_for_each = () =>
|
|
147
|
+
let test_list = []
|
|
148
|
+
[1, 2, 3].for_each(test_list.append)
|
|
149
|
+
assert_eq(test_list, [1, 2, 3])
|
|
150
|
+
|
|
151
|
+
test_fold = () =>
|
|
152
|
+
assert_eq([1, 2, 3, 4].fold(0, (acc, x) => acc + x), 10)
|
|
153
|
+
assert_eq([1, 2, 3].fold(1, (acc, x) => acc * x), 6)
|
|
154
|
+
assert_eq([5, 3, 8, 1].fold(0, (acc, x) => max(acc, x)), 8)
|
|
155
|
+
|
|
156
|
+
# Record/dict methods - defined in both prelude/__init__.tl (Extension.method for dict)
|
|
157
|
+
# and runtime/record.py (Record class methods)
|
|
158
|
+
test_record_map = () =>
|
|
159
|
+
# map transforms both keys and values
|
|
160
|
+
assert_eq({1: 10, 2: 20}.map([k, v] => [k + 1, v + 5]), {2: 15, 3: 25})
|
|
161
|
+
assert_eq({"a": 1, "b": 2}.map([k, v] => [k.upper(), v * 10]), {"A": 10, "B": 20})
|
|
162
|
+
|
|
163
|
+
test_record_filter = () =>
|
|
164
|
+
# filter based on key-value pairs (defined in prelude/__init__.tl for dict)
|
|
165
|
+
assert_eq({1: 10, 2: 20, 3: 30}.filter([k, v] => v > 15), {2: 20, 3: 30})
|
|
166
|
+
assert_eq({1: 10, 2: 20, 3: 30}.filter([k, v] => k %% 2 == 1), {1: 10, 3: 30})
|
|
167
|
+
|
|
168
|
+
test_record_filter_keys = () =>
|
|
169
|
+
# filter_keys - defined in prelude/__init__.tl for dict and record.py for Record
|
|
170
|
+
assert_eq({1: 10, 2: 20, 3: 30}.filter_keys($ > 1), {2: 20, 3: 30})
|
|
171
|
+
assert_eq({"a": 1, "b": 2, "c": 3}.filter_keys($ <> "b"), {"a": 1, "c": 3})
|
|
172
|
+
|
|
173
|
+
test_record_filter_values = () =>
|
|
174
|
+
# filter_values - defined in prelude/__init__.tl for dict and record.py for Record
|
|
175
|
+
assert_eq({1: 10, 2: 20, 3: 30}.filter_values($ >= 20), {2: 20, 3: 30})
|
|
176
|
+
assert_eq({"a": 5, "b": 10, "c": 25}.filter_values($ %% 10 == 5), {"a": 5, "c": 25})
|