koatl 0.3.13__tar.gz → 0.3.15__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.13 → koatl-0.3.15}/Cargo.lock +2 -2
- {koatl-0.3.13 → koatl-0.3.15}/PKG-INFO +2 -1
- {koatl-0.3.13 → koatl-0.3.15}/koatl/Cargo.toml +2 -1
- {koatl-0.3.13 → koatl-0.3.15}/koatl/python/koatl/prelude/__init__.tl +10 -0
- {koatl-0.3.13 → koatl-0.3.15}/koatl/python/koatl/runtime/record.py +44 -5
- koatl-0.3.15/koatl/python/koatl/runtime/vattr.py +66 -0
- {koatl-0.3.13 → koatl-0.3.15}/koatl/python/koatl/std/iter.tl +6 -4
- {koatl-0.3.13 → koatl-0.3.15}/koatl/src/emit_py.rs +6 -0
- koatl-0.3.15/koatl/tests/conftest.py +62 -0
- {koatl-0.3.13/koatl/tests/e2e/prelude → koatl-0.3.15/koatl/tests/e2e/base}/imports.tl +3 -3
- koatl-0.3.15/koatl/tests/e2e/base/imports2.tl +15 -0
- koatl-0.3.15/koatl/tests/fail-parse/unmatched_closing_delimiter.tl +1 -0
- koatl-0.3.15/koatl/tests/parse/operators.tl +1 -0
- {koatl-0.3.13 → koatl-0.3.15}/koatl/tests/test_e2e.py +1 -1
- koatl-0.3.15/koatl/tests/test_iterable.tl +176 -0
- koatl-0.3.15/koatl/tests/util/__init__.py +5 -0
- {koatl-0.3.13 → koatl-0.3.15}/koatl-core/src/py/ast.rs +1 -1
- {koatl-0.3.13 → koatl-0.3.15}/koatl-core/src/transform.rs +10 -15
- {koatl-0.3.13 → koatl-0.3.15}/koatl-parser/src/lexer.rs +16 -7
- {koatl-0.3.13 → koatl-0.3.15}/koatl-parser/src/parser.rs +24 -2
- {koatl-0.3.13 → koatl-0.3.15}/python/koatl/prelude/__init__.tl +10 -0
- {koatl-0.3.13 → koatl-0.3.15}/python/koatl/runtime/record.py +44 -5
- koatl-0.3.15/python/koatl/runtime/vattr.py +66 -0
- {koatl-0.3.13 → koatl-0.3.15}/python/koatl/std/iter.tl +6 -4
- koatl-0.3.13/koatl/python/koatl/runtime/vattr.py +0 -67
- koatl-0.3.13/koatl/tests/e2e/util/__init__.py +0 -2
- koatl-0.3.13/python/koatl/runtime/vattr.py +0 -67
- {koatl-0.3.13 → koatl-0.3.15}/Cargo.toml +0 -0
- {koatl-0.3.13 → koatl-0.3.15}/README.md +0 -0
- {koatl-0.3.13 → koatl-0.3.15}/koatl/.github/workflows/CI.yml +0 -0
- {koatl-0.3.13 → koatl-0.3.15}/koatl/.gitignore +0 -0
- {koatl-0.3.13 → koatl-0.3.15}/koatl/LICENSE +0 -0
- {koatl-0.3.13 → koatl-0.3.15}/koatl/README.md +0 -0
- {koatl-0.3.13 → koatl-0.3.15}/koatl/python/koatl/__init__.py +0 -0
- {koatl-0.3.13 → koatl-0.3.15}/koatl/python/koatl/__main__.py +0 -0
- {koatl-0.3.13 → koatl-0.3.15}/koatl/python/koatl/cli.py +0 -0
- {koatl-0.3.13 → koatl-0.3.15}/koatl/python/koatl/notebook/__init__.py +0 -0
- {koatl-0.3.13 → koatl-0.3.15}/koatl/python/koatl/notebook/magic.py +0 -0
- {koatl-0.3.13 → koatl-0.3.15}/koatl/python/koatl/runtime/__init__.py +0 -0
- {koatl-0.3.13 → koatl-0.3.15}/koatl/python/koatl/runtime/meta_finder.py +0 -0
- {koatl-0.3.13 → koatl-0.3.15}/koatl/python/koatl/std/__init__.tl +0 -0
- {koatl-0.3.13 → koatl-0.3.15}/koatl/python/koatl/std/control/__init__.tl +0 -0
- {koatl-0.3.13 → koatl-0.3.15}/koatl/python/koatl/std/control/async.tl +0 -0
- {koatl-0.3.13 → koatl-0.3.15}/koatl/python/koatl/std/control/base.tl +0 -0
- {koatl-0.3.13 → koatl-0.3.15}/koatl/python/koatl/std/control/do.tl +0 -0
- {koatl-0.3.13 → koatl-0.3.15}/koatl/python/koatl/std/control/env.tl +0 -0
- {koatl-0.3.13 → koatl-0.3.15}/koatl/python/koatl/std/control/memo.tl +0 -0
- {koatl-0.3.13 → koatl-0.3.15}/koatl/python/koatl/std/control/result.tl +0 -0
- {koatl-0.3.13 → koatl-0.3.15}/koatl/python/koatl/std/data/__init__.tl +0 -0
- {koatl-0.3.13 → koatl-0.3.15}/koatl/python/koatl/std/data/list.tl +0 -0
- {koatl-0.3.13 → koatl-0.3.15}/koatl/python/koatl/std/data/record.tl +0 -0
- {koatl-0.3.13 → koatl-0.3.15}/koatl/python/koatl/std/ext.tl +0 -0
- {koatl-0.3.13 → koatl-0.3.15}/koatl/python/koatl/std/io.tl +0 -0
- {koatl-0.3.13 → koatl-0.3.15}/koatl/python/koatl/std/json.tl +0 -0
- {koatl-0.3.13 → koatl-0.3.15}/koatl/python/koatl/std/lazy_module.tl +0 -0
- {koatl-0.3.13 → koatl-0.3.15}/koatl/python/koatl/std/pickle.tl +0 -0
- {koatl-0.3.13 → koatl-0.3.15}/koatl/python/koatl/std/re.tl +0 -0
- {koatl-0.3.13 → koatl-0.3.15}/koatl/python/koatl/std/trait.py +0 -0
- {koatl-0.3.13 → koatl-0.3.15}/koatl/requirements.txt +0 -0
- {koatl-0.3.13 → koatl-0.3.15}/koatl/src/lib.rs +0 -0
- {koatl-0.3.13 → koatl-0.3.15}/koatl/tests/e2e/base/arguments.tl +0 -0
- {koatl-0.3.13 → koatl-0.3.15}/koatl/tests/e2e/base/containers.tl +0 -0
- {koatl-0.3.13 → koatl-0.3.15}/koatl/tests/e2e/base/data.txt +0 -0
- {koatl-0.3.13 → koatl-0.3.15}/koatl/tests/e2e/base/decorators.tl +0 -0
- {koatl-0.3.13 → koatl-0.3.15}/koatl/tests/e2e/base/destructure-for-and-fn.tl +0 -0
- {koatl-0.3.13 → koatl-0.3.15}/koatl/tests/e2e/base/destructure.tl +0 -0
- {koatl-0.3.13 → koatl-0.3.15}/koatl/tests/e2e/base/escape_ident.tl +0 -0
- {koatl-0.3.13 → koatl-0.3.15}/koatl/tests/e2e/base/fstr.tl +0 -0
- {koatl-0.3.13 → koatl-0.3.15}/koatl/tests/e2e/base/functions.tl +0 -0
- {koatl-0.3.13 → koatl-0.3.15}/koatl/tests/e2e/base/generator.tl +0 -0
- {koatl-0.3.13 → koatl-0.3.15}/koatl/tests/e2e/base/if_expr.tl +0 -0
- {koatl-0.3.13 → koatl-0.3.15}/koatl/tests/e2e/base/loops.tl +0 -0
- {koatl-0.3.13 → koatl-0.3.15}/koatl/tests/e2e/base/match.tl +0 -0
- {koatl-0.3.13 → koatl-0.3.15}/koatl/tests/e2e/base/nary-list.tl +0 -0
- {koatl-0.3.13 → koatl-0.3.15}/koatl/tests/e2e/base/placeholder.tl +0 -0
- {koatl-0.3.13 → koatl-0.3.15}/koatl/tests/e2e/base/precedence.tl +0 -0
- {koatl-0.3.13 → koatl-0.3.15}/koatl/tests/e2e/base/scopes.tl +0 -0
- {koatl-0.3.13 → koatl-0.3.15}/koatl/tests/e2e/base/semantic_whitespace.tl +0 -0
- {koatl-0.3.13 → koatl-0.3.15}/koatl/tests/e2e/base/short_circuit.tl +0 -0
- {koatl-0.3.13 → koatl-0.3.15}/koatl/tests/e2e/base/with.tl +0 -0
- {koatl-0.3.13 → koatl-0.3.15}/koatl/tests/e2e/prelude/async.tl +0 -0
- {koatl-0.3.13 → koatl-0.3.15}/koatl/tests/e2e/prelude/aug_assign.tl +0 -0
- {koatl-0.3.13 → koatl-0.3.15}/koatl/tests/e2e/prelude/coal.tl +0 -0
- {koatl-0.3.13 → koatl-0.3.15}/koatl/tests/e2e/prelude/env.tl +0 -0
- {koatl-0.3.13 → koatl-0.3.15}/koatl/tests/e2e/prelude/iterables.tl +0 -0
- {koatl-0.3.13 → koatl-0.3.15}/koatl/tests/e2e/prelude/list.tl +0 -0
- {koatl-0.3.13 → koatl-0.3.15}/koatl/tests/e2e/prelude/memo.tl +0 -0
- {koatl-0.3.13 → koatl-0.3.15}/koatl/tests/e2e/prelude/record.tl +0 -0
- {koatl-0.3.13 → koatl-0.3.15}/koatl/tests/e2e/prelude/result.tl +0 -0
- {koatl-0.3.13 → koatl-0.3.15}/koatl/tests/e2e/prelude/slice.tl +0 -0
- {koatl-0.3.13 → koatl-0.3.15}/koatl/tests/e2e/prelude/try.tl +0 -0
- {koatl-0.3.13 → koatl-0.3.15}/koatl/tests/e2e/prelude/virtual.tl +0 -0
- {koatl-0.3.13/koatl/tests/e2e/util → koatl-0.3.15/koatl/tests/e2e/test_modules}/module0.tl +0 -0
- {koatl-0.3.13/koatl/tests/e2e/util → koatl-0.3.15/koatl/tests/e2e/test_modules}/module1.tl +0 -0
- {koatl-0.3.13/koatl/tests/e2e/util → koatl-0.3.15/koatl/tests/e2e/test_modules}/module2.tl +0 -0
- {koatl-0.3.13 → koatl-0.3.15}/koatl/tests/fail-parse/arguments_mixed_defaults.tl +0 -0
- {koatl-0.3.13 → koatl-0.3.15}/koatl/tests/fail-parse/arguments_multiple_kwargs.tl +0 -0
- {koatl-0.3.13 → koatl-0.3.15}/koatl/tests/fail-parse/arguments_multiple_kwonly_markers.tl +0 -0
- {koatl-0.3.13 → koatl-0.3.15}/koatl/tests/fail-parse/arguments_multiple_posonly_markers.tl +0 -0
- {koatl-0.3.13 → koatl-0.3.15}/koatl/tests/fail-parse/arguments_multiple_varargs.tl +0 -0
- {koatl-0.3.13 → koatl-0.3.15}/koatl/tests/fail-parse/arguments_posonly_after_kwonly.tl +0 -0
- {koatl-0.3.13 → koatl-0.3.15}/koatl/tests/fail-parse/arguments_vararg_and_kwonly_marker.tl +0 -0
- {koatl-0.3.13 → koatl-0.3.15}/koatl/tests/parse/arith.tl +0 -0
- {koatl-0.3.13 → koatl-0.3.15}/koatl/tests/parse/assign.tl +0 -0
- {koatl-0.3.13 → koatl-0.3.15}/koatl/tests/parse/block-comments.tl +0 -0
- {koatl-0.3.13 → koatl-0.3.15}/koatl/tests/parse/deco.tl +0 -0
- {koatl-0.3.13 → koatl-0.3.15}/koatl/tests/parse/func.tl +0 -0
- {koatl-0.3.13 → koatl-0.3.15}/koatl/tests/parse/matches.tl +0 -0
- {koatl-0.3.13 → koatl-0.3.15}/koatl/tests/parse/mutual-recursion.tl +0 -0
- {koatl-0.3.13 → koatl-0.3.15}/koatl/tests/parse/numbers.tl +0 -0
- {koatl-0.3.13 → koatl-0.3.15}/koatl/tests/test_parse.py +0 -0
- {koatl-0.3.13 → koatl-0.3.15}/koatl/tests/test_parse_fail.py +0 -0
- {koatl-0.3.13 → koatl-0.3.15}/koatl-core/Cargo.toml +0 -0
- {koatl-0.3.13 → koatl-0.3.15}/koatl-core/src/ast.rs +0 -0
- {koatl-0.3.13 → koatl-0.3.15}/koatl-core/src/ast_builder.rs +0 -0
- {koatl-0.3.13 → koatl-0.3.15}/koatl-core/src/inference.rs +0 -0
- {koatl-0.3.13 → koatl-0.3.15}/koatl-core/src/lib.rs +0 -0
- {koatl-0.3.13 → koatl-0.3.15}/koatl-core/src/lift_cst.rs +0 -0
- {koatl-0.3.13 → koatl-0.3.15}/koatl-core/src/main.rs +0 -0
- {koatl-0.3.13 → koatl-0.3.15}/koatl-core/src/py/ast_builder.rs +0 -0
- {koatl-0.3.13 → koatl-0.3.15}/koatl-core/src/py/emit.rs +0 -0
- {koatl-0.3.13 → koatl-0.3.15}/koatl-core/src/py/mod.rs +0 -0
- {koatl-0.3.13 → koatl-0.3.15}/koatl-core/src/resolve_scopes.rs +0 -0
- {koatl-0.3.13 → koatl-0.3.15}/koatl-core/src/types.rs +0 -0
- {koatl-0.3.13 → koatl-0.3.15}/koatl-core/src/util.rs +0 -0
- {koatl-0.3.13 → koatl-0.3.15}/koatl-parser/Cargo.toml +0 -0
- {koatl-0.3.13 → koatl-0.3.15}/koatl-parser/src/cst.rs +0 -0
- {koatl-0.3.13 → koatl-0.3.15}/koatl-parser/src/lib.rs +0 -0
- {koatl-0.3.13 → koatl-0.3.15}/koatl-parser/src/simple_fmt.rs +0 -0
- {koatl-0.3.13 → koatl-0.3.15}/pyproject.toml +0 -0
- {koatl-0.3.13 → koatl-0.3.15}/python/koatl/__init__.py +0 -0
- {koatl-0.3.13 → koatl-0.3.15}/python/koatl/__main__.py +0 -0
- {koatl-0.3.13 → koatl-0.3.15}/python/koatl/cli.py +0 -0
- {koatl-0.3.13 → koatl-0.3.15}/python/koatl/notebook/__init__.py +0 -0
- {koatl-0.3.13 → koatl-0.3.15}/python/koatl/notebook/magic.py +0 -0
- {koatl-0.3.13 → koatl-0.3.15}/python/koatl/runtime/__init__.py +0 -0
- {koatl-0.3.13 → koatl-0.3.15}/python/koatl/runtime/meta_finder.py +0 -0
- {koatl-0.3.13 → koatl-0.3.15}/python/koatl/std/__init__.tl +0 -0
- {koatl-0.3.13 → koatl-0.3.15}/python/koatl/std/control/__init__.tl +0 -0
- {koatl-0.3.13 → koatl-0.3.15}/python/koatl/std/control/async.tl +0 -0
- {koatl-0.3.13 → koatl-0.3.15}/python/koatl/std/control/base.tl +0 -0
- {koatl-0.3.13 → koatl-0.3.15}/python/koatl/std/control/do.tl +0 -0
- {koatl-0.3.13 → koatl-0.3.15}/python/koatl/std/control/env.tl +0 -0
- {koatl-0.3.13 → koatl-0.3.15}/python/koatl/std/control/memo.tl +0 -0
- {koatl-0.3.13 → koatl-0.3.15}/python/koatl/std/control/result.tl +0 -0
- {koatl-0.3.13 → koatl-0.3.15}/python/koatl/std/data/__init__.tl +0 -0
- {koatl-0.3.13 → koatl-0.3.15}/python/koatl/std/data/list.tl +0 -0
- {koatl-0.3.13 → koatl-0.3.15}/python/koatl/std/data/record.tl +0 -0
- {koatl-0.3.13 → koatl-0.3.15}/python/koatl/std/ext.tl +0 -0
- {koatl-0.3.13 → koatl-0.3.15}/python/koatl/std/io.tl +0 -0
- {koatl-0.3.13 → koatl-0.3.15}/python/koatl/std/json.tl +0 -0
- {koatl-0.3.13 → koatl-0.3.15}/python/koatl/std/lazy_module.tl +0 -0
- {koatl-0.3.13 → koatl-0.3.15}/python/koatl/std/pickle.tl +0 -0
- {koatl-0.3.13 → koatl-0.3.15}/python/koatl/std/re.tl +0 -0
- {koatl-0.3.13 → koatl-0.3.15}/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.15"
|
|
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.15
|
|
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
|
|
|
@@ -23,6 +23,16 @@ Extension.property(object, "result")! self => Result(self)
|
|
|
23
23
|
Extension.method(str, "match")! (regex, str) => Pattern(regex).match(str)
|
|
24
24
|
Extension.method(str, "matches")! (str, regex) => Pattern(regex).match(str)
|
|
25
25
|
|
|
26
|
+
Extension.method(list, "map")! (self, f) => self.iter.map(f).list()
|
|
27
|
+
Extension.method(list, "filter")! (self, f) => self.iter.filter(f).list()
|
|
28
|
+
|
|
29
|
+
Extension.method(dict, "map")! (self, f) => self.iter.map(f).dict()
|
|
30
|
+
Extension.method(dict, "map_values")! (self, f) => self.iter.map([k, v] => [k, f(v)]).dict()
|
|
31
|
+
Extension.method(dict, "map_keys")! (self, f) => self.iter.map([k, v] => [f(k), v]).dict()
|
|
32
|
+
Extension.method(dict, "filter")! (self, f) => self.iter.filter(f).dict()
|
|
33
|
+
Extension.method(dict, "filter_keys")! (self, f) => self.iter.filter([k, v] => f(k)).dict()
|
|
34
|
+
Extension.method(dict, "filter_values")! (self, f) => self.iter.filter([k, v] => f(v)).dict()
|
|
35
|
+
|
|
26
36
|
__tl__.do = koatl.std.control.do.do
|
|
27
37
|
|
|
28
38
|
__tl__.op_map = koatl.std.control.result.op_map
|
|
@@ -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
|
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
from functools import partial
|
|
2
|
+
from itertools import count
|
|
3
|
+
from koatl._rs import fast_vget
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
def vget(obj, name, ignore_traits=False):
|
|
7
|
+
try:
|
|
8
|
+
return getattr(obj, name)
|
|
9
|
+
except AttributeError as e:
|
|
10
|
+
# special case for iter - this could be implemented using types and trait vtbls
|
|
11
|
+
# but this is simpler and probably faster
|
|
12
|
+
if name == "iter":
|
|
13
|
+
if isinstance(obj, slice):
|
|
14
|
+
start = obj.start if obj.start is not None else 0
|
|
15
|
+
step = obj.step if obj.step is not None else 1
|
|
16
|
+
if obj.stop is None:
|
|
17
|
+
return iter(count(start, step))
|
|
18
|
+
else:
|
|
19
|
+
return iter(range(start, obj.stop, step))
|
|
20
|
+
|
|
21
|
+
try:
|
|
22
|
+
return iter(obj.items())
|
|
23
|
+
except AttributeError:
|
|
24
|
+
pass
|
|
25
|
+
|
|
26
|
+
try:
|
|
27
|
+
return iter(obj)
|
|
28
|
+
except TypeError:
|
|
29
|
+
pass
|
|
30
|
+
|
|
31
|
+
v = fast_vget(obj, name, ignore_traits)
|
|
32
|
+
if v is not None:
|
|
33
|
+
if hasattr(v, "_property"):
|
|
34
|
+
return v(obj)
|
|
35
|
+
|
|
36
|
+
return partial(v, obj)
|
|
37
|
+
|
|
38
|
+
e.__traceback__ = None
|
|
39
|
+
raise
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
def vhas(obj, name, ignore_traits=False):
|
|
43
|
+
if hasattr(obj, name):
|
|
44
|
+
return True
|
|
45
|
+
|
|
46
|
+
if name == "iter":
|
|
47
|
+
if isinstance(obj, slice):
|
|
48
|
+
return True
|
|
49
|
+
|
|
50
|
+
try:
|
|
51
|
+
obj.items()
|
|
52
|
+
return True
|
|
53
|
+
except AttributeError:
|
|
54
|
+
pass
|
|
55
|
+
|
|
56
|
+
try:
|
|
57
|
+
iter(obj)
|
|
58
|
+
return True
|
|
59
|
+
except TypeError:
|
|
60
|
+
pass
|
|
61
|
+
|
|
62
|
+
v = fast_vget(obj, name, ignore_traits)
|
|
63
|
+
if v is not None:
|
|
64
|
+
return True
|
|
65
|
+
|
|
66
|
+
return False
|
|
@@ -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 =>
|
|
@@ -631,6 +631,12 @@ impl<'src> PyExprExt<'src> for SPyExpr<'src> {
|
|
|
631
631
|
PyBinaryOp::FloorDiv => Some("FloorDiv"),
|
|
632
632
|
PyBinaryOp::Mod => Some("Mod"),
|
|
633
633
|
PyBinaryOp::Pow => Some("Pow"),
|
|
634
|
+
PyBinaryOp::BitAnd => Some("BitAnd"),
|
|
635
|
+
PyBinaryOp::BitOr => Some("BitOr"),
|
|
636
|
+
PyBinaryOp::BitXor => Some("BitXor"),
|
|
637
|
+
PyBinaryOp::MatMult => Some("MatMult"),
|
|
638
|
+
PyBinaryOp::LShift => Some("LShift"),
|
|
639
|
+
PyBinaryOp::RShift => Some("RShift"),
|
|
634
640
|
_ => None,
|
|
635
641
|
};
|
|
636
642
|
|
|
@@ -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 @@
|
|
|
1
|
+
1 >> 2 << 3 ^^ 4 // 5 && 6 ** (1 || 2 @@ -3)
|
|
@@ -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})
|
|
@@ -1829,26 +1829,21 @@ impl<'src> SStmtExt<'src> for SStmt<'src> {
|
|
|
1829
1829
|
tree.leaf.span,
|
|
1830
1830
|
))
|
|
1831
1831
|
} else {
|
|
1832
|
-
let
|
|
1832
|
+
let full_module = trunk_accum
|
|
1833
1833
|
.iter()
|
|
1834
1834
|
.map(|ident| ident.value.0.as_ref())
|
|
1835
1835
|
.collect::<Vec<_>>()
|
|
1836
1836
|
.join(".");
|
|
1837
1837
|
|
|
1838
|
-
let
|
|
1839
|
-
|
|
1840
|
-
|
|
1841
|
-
|
|
1842
|
-
|
|
1843
|
-
|
|
1844
|
-
|
|
1845
|
-
|
|
1846
|
-
|
|
1847
|
-
Some(base_module.into()),
|
|
1848
|
-
aliases,
|
|
1849
|
-
level,
|
|
1850
|
-
)]))
|
|
1851
|
-
}
|
|
1838
|
+
let last_name = trunk_accum.last().unwrap().value.escape();
|
|
1839
|
+
let asname = alias
|
|
1840
|
+
.as_ref()
|
|
1841
|
+
.map(|a| a.value.escape())
|
|
1842
|
+
.unwrap_or(last_name);
|
|
1843
|
+
|
|
1844
|
+
let aliases = vec![a.import_alias(full_module, Some(asname))];
|
|
1845
|
+
|
|
1846
|
+
Ok(PyBlock(vec![a.import(aliases)]))
|
|
1852
1847
|
}
|
|
1853
1848
|
}
|
|
1854
1849
|
ImportLeaf::Single(name, alias) => {
|
|
@@ -424,7 +424,7 @@ impl<'src> TokenizeCtx<'src> {
|
|
|
424
424
|
fn parse_symbol(&mut self) -> TResult<'src, (Token<'src>, Span)> {
|
|
425
425
|
const POLYGRAMS: &[&str] = &[
|
|
426
426
|
"+=", "-=", "*=", "/=", "|=", "??=", "===", "<=>", "=>", "..", "==", "<>", "<=", ">=",
|
|
427
|
-
"//", "%%", "@@", "**", "??", ".=", "::", "||", "&&", "^^", ">>", "<<",
|
|
427
|
+
"!=", "!==", "//", "%%", "@@", "**", "??", ".=", "::", "||", "&&", "^^", ">>", "<<",
|
|
428
428
|
];
|
|
429
429
|
const MONOGRAMS: &str = "[](){}<>.,;:!?@$%^&*+-=|\\/`~";
|
|
430
430
|
|
|
@@ -1574,7 +1574,16 @@ impl<'src> TokenizeCtx<'src> {
|
|
|
1574
1574
|
|
|
1575
1575
|
let mut tokens = TokenList(vec![]);
|
|
1576
1576
|
|
|
1577
|
-
let (block_tokens,
|
|
1577
|
+
let (block_tokens, end_type, _) = self.parse_block(0, ParseBlockMode::BeginInput)?;
|
|
1578
|
+
|
|
1579
|
+
// Check if we ended due to an unmatched closing delimiter at the top level
|
|
1580
|
+
if end_type == ParseBlockEndType::Delimiter {
|
|
1581
|
+
return Err(LexError::custom(
|
|
1582
|
+
self.span_since(&self.cursor()),
|
|
1583
|
+
"unmatched closing delimiter",
|
|
1584
|
+
));
|
|
1585
|
+
}
|
|
1586
|
+
|
|
1578
1587
|
tokens.0.extend(block_tokens.0);
|
|
1579
1588
|
|
|
1580
1589
|
Ok(tokens)
|
|
@@ -1652,7 +1661,7 @@ mod tests {
|
|
|
1652
1661
|
);
|
|
1653
1662
|
}
|
|
1654
1663
|
|
|
1655
|
-
fn simple_tokenize(source: &str) -> TokenList {
|
|
1664
|
+
fn simple_tokenize(source: &str) -> TokenList<'_> {
|
|
1656
1665
|
let (tokens, errors) = tokenize(source, true);
|
|
1657
1666
|
if !errors.is_empty() {
|
|
1658
1667
|
assert!(false, "Errors during tokenization: {:?}", errors);
|
|
@@ -1662,7 +1671,7 @@ mod tests {
|
|
|
1662
1671
|
tokens.unwrap()
|
|
1663
1672
|
}
|
|
1664
1673
|
|
|
1665
|
-
fn simple_trivium(typ: TrivialTokenType, value: &str) -> TrivialToken {
|
|
1674
|
+
fn simple_trivium(typ: TrivialTokenType, value: &'_ str) -> TrivialToken<'_> {
|
|
1666
1675
|
TrivialToken {
|
|
1667
1676
|
span: Span { start: 0, end: 0 },
|
|
1668
1677
|
typ,
|
|
@@ -1674,15 +1683,15 @@ mod tests {
|
|
|
1674
1683
|
simple_trivium(TrivialTokenType::Newline, "\n")
|
|
1675
1684
|
}
|
|
1676
1685
|
|
|
1677
|
-
fn whitespace_trivium(value: &str) -> TrivialToken {
|
|
1686
|
+
fn whitespace_trivium(value: &str) -> TrivialToken<'_> {
|
|
1678
1687
|
simple_trivium(TrivialTokenType::Whitespace, value)
|
|
1679
1688
|
}
|
|
1680
1689
|
|
|
1681
|
-
fn comment_trivium(value: &str) -> TrivialToken {
|
|
1690
|
+
fn comment_trivium(value: &str) -> TrivialToken<'_> {
|
|
1682
1691
|
simple_trivium(TrivialTokenType::LineComment, value)
|
|
1683
1692
|
}
|
|
1684
1693
|
|
|
1685
|
-
fn block_comment_trivium(value: &str) -> TrivialToken {
|
|
1694
|
+
fn block_comment_trivium(value: &'_ str) -> TrivialToken<'_> {
|
|
1686
1695
|
simple_trivium(TrivialTokenType::BlockComment, value)
|
|
1687
1696
|
}
|
|
1688
1697
|
|