koatl 0.1.33__tar.gz → 0.1.34__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.33 → koatl-0.1.34}/Cargo.lock +1 -1
- {koatl-0.1.33 → koatl-0.1.34}/PKG-INFO +1 -1
- {koatl-0.1.33 → koatl-0.1.34}/koatl/Cargo.toml +1 -1
- {koatl-0.1.33 → koatl-0.1.34/koatl}/python/koatl/prelude/functional/result.tl +1 -1
- {koatl-0.1.33 → koatl-0.1.34/koatl}/python/koatl/prelude/iterable.tl +63 -13
- {koatl-0.1.33 → koatl-0.1.34/koatl}/python/koatl/runtime/record.py +10 -0
- {koatl-0.1.33 → koatl-0.1.34}/koatl/python/koatl/runtime/virtual.py +1 -1
- {koatl-0.1.33 → koatl-0.1.34}/koatl/src/emit_py.rs +3 -0
- {koatl-0.1.33 → koatl-0.1.34}/koatl/tests/e2e/base/coal.tl +1 -1
- {koatl-0.1.33 → koatl-0.1.34}/koatl/tests/e2e/prelude/try.tl +2 -2
- {koatl-0.1.33 → koatl-0.1.34}/koatl-core/parser/src/ast.rs +9 -5
- {koatl-0.1.33 → koatl-0.1.34}/koatl-core/parser/src/lexer.rs +40 -18
- {koatl-0.1.33 → koatl-0.1.34}/koatl-core/parser/src/parser.rs +37 -23
- {koatl-0.1.33 → koatl-0.1.34}/koatl-core/src/py/ast.rs +4 -1
- {koatl-0.1.33 → koatl-0.1.34}/koatl-core/src/py/emit.rs +43 -18
- {koatl-0.1.33 → koatl-0.1.34}/koatl-core/src/py/util.rs +1 -1
- {koatl-0.1.33 → koatl-0.1.34}/koatl-core/src/resolve_scopes.rs +1 -1
- {koatl-0.1.33 → koatl-0.1.34}/koatl-core/src/transform.rs +10 -6
- {koatl-0.1.33/koatl → koatl-0.1.34}/python/koatl/prelude/functional/result.tl +1 -1
- {koatl-0.1.33/koatl → koatl-0.1.34}/python/koatl/prelude/iterable.tl +63 -13
- {koatl-0.1.33/koatl → koatl-0.1.34}/python/koatl/runtime/record.py +10 -0
- {koatl-0.1.33 → koatl-0.1.34}/python/koatl/runtime/virtual.py +1 -1
- {koatl-0.1.33 → koatl-0.1.34}/Cargo.toml +0 -0
- {koatl-0.1.33 → koatl-0.1.34}/README.md +0 -0
- {koatl-0.1.33 → koatl-0.1.34}/koatl/.github/workflows/CI.yml +0 -0
- {koatl-0.1.33 → koatl-0.1.34}/koatl/.gitignore +0 -0
- {koatl-0.1.33 → koatl-0.1.34}/koatl/LICENSE +0 -0
- {koatl-0.1.33 → koatl-0.1.34}/koatl/README.md +0 -0
- {koatl-0.1.33 → koatl-0.1.34}/koatl/python/koatl/__init__.py +0 -0
- {koatl-0.1.33 → koatl-0.1.34}/koatl/python/koatl/__main__.py +0 -0
- {koatl-0.1.33 → koatl-0.1.34}/koatl/python/koatl/cli.py +0 -0
- {koatl-0.1.33 → koatl-0.1.34}/koatl/python/koatl/notebook/__init__.py +0 -0
- {koatl-0.1.33 → koatl-0.1.34}/koatl/python/koatl/notebook/magic.py +0 -0
- {koatl-0.1.33 → koatl-0.1.34}/koatl/python/koatl/prelude/__init__.tl +0 -0
- {koatl-0.1.33 → koatl-0.1.34}/koatl/python/koatl/prelude/functional/__init__.tl +0 -0
- {koatl-0.1.33 → koatl-0.1.34}/koatl/python/koatl/prelude/functional/algebra.tl +0 -0
- {koatl-0.1.33 → koatl-0.1.34}/koatl/python/koatl/prelude/functional/async.tl +0 -0
- {koatl-0.1.33 → koatl-0.1.34}/koatl/python/koatl/prelude/functional/env.tl +0 -0
- {koatl-0.1.33 → koatl-0.1.34}/koatl/python/koatl/prelude/functional/list.tl +0 -0
- {koatl-0.1.33 → koatl-0.1.34}/koatl/python/koatl/prelude/functional/memo.tl +0 -0
- {koatl-0.1.33 → koatl-0.1.34}/koatl/python/koatl/prelude/io.tl +0 -0
- {koatl-0.1.33 → koatl-0.1.34}/koatl/python/koatl/prelude/regex.tl +0 -0
- {koatl-0.1.33 → koatl-0.1.34}/koatl/python/koatl/runtime/__init__.py +0 -0
- {koatl-0.1.33 → koatl-0.1.34}/koatl/python/koatl/runtime/classes.py +0 -0
- {koatl-0.1.33 → koatl-0.1.34}/koatl/python/koatl/runtime/helpers.py +0 -0
- {koatl-0.1.33 → koatl-0.1.34}/koatl/python/koatl/runtime/meta_finder.py +0 -0
- {koatl-0.1.33 → koatl-0.1.34}/koatl/requirements.txt +0 -0
- {koatl-0.1.33 → koatl-0.1.34}/koatl/src/lib.rs +0 -0
- {koatl-0.1.33 → koatl-0.1.34}/koatl/tests/e2e/base/containers.tl +0 -0
- {koatl-0.1.33 → koatl-0.1.34}/koatl/tests/e2e/base/data.txt +0 -0
- {koatl-0.1.33 → koatl-0.1.34}/koatl/tests/e2e/base/decorators.tl +0 -0
- {koatl-0.1.33 → koatl-0.1.34}/koatl/tests/e2e/base/destructure-for-and-fn.tl +0 -0
- {koatl-0.1.33 → koatl-0.1.34}/koatl/tests/e2e/base/destructure.tl +0 -0
- {koatl-0.1.33 → koatl-0.1.34}/koatl/tests/e2e/base/escape_ident.tl +0 -0
- {koatl-0.1.33 → koatl-0.1.34}/koatl/tests/e2e/base/fstr.tl +0 -0
- {koatl-0.1.33 → koatl-0.1.34}/koatl/tests/e2e/base/functions.tl +0 -0
- {koatl-0.1.33 → koatl-0.1.34}/koatl/tests/e2e/base/generator.tl +0 -0
- {koatl-0.1.33 → koatl-0.1.34}/koatl/tests/e2e/base/if_expr.tl +0 -0
- {koatl-0.1.33 → koatl-0.1.34}/koatl/tests/e2e/base/imports.tl +0 -0
- {koatl-0.1.33 → koatl-0.1.34}/koatl/tests/e2e/base/loops.tl +0 -0
- {koatl-0.1.33 → koatl-0.1.34}/koatl/tests/e2e/base/match.tl +0 -0
- {koatl-0.1.33 → koatl-0.1.34}/koatl/tests/e2e/base/nary-list.tl +0 -0
- {koatl-0.1.33 → koatl-0.1.34}/koatl/tests/e2e/base/placeholder.tl +0 -0
- {koatl-0.1.33 → koatl-0.1.34}/koatl/tests/e2e/base/precedence.tl +0 -0
- {koatl-0.1.33 → koatl-0.1.34}/koatl/tests/e2e/base/record.tl +0 -0
- {koatl-0.1.33 → koatl-0.1.34}/koatl/tests/e2e/base/scopes.tl +0 -0
- {koatl-0.1.33 → koatl-0.1.34}/koatl/tests/e2e/base/semantic_whitespace.tl +0 -0
- {koatl-0.1.33 → koatl-0.1.34}/koatl/tests/e2e/base/short_circuit.tl +0 -0
- {koatl-0.1.33 → koatl-0.1.34}/koatl/tests/e2e/base/with.tl +0 -0
- {koatl-0.1.33 → koatl-0.1.34}/koatl/tests/e2e/prelude/async.tl +0 -0
- {koatl-0.1.33 → koatl-0.1.34}/koatl/tests/e2e/prelude/aug_assign.tl +0 -0
- {koatl-0.1.33 → koatl-0.1.34}/koatl/tests/e2e/prelude/env.tl +0 -0
- {koatl-0.1.33 → koatl-0.1.34}/koatl/tests/e2e/prelude/iterables.tl +0 -0
- {koatl-0.1.33 → koatl-0.1.34}/koatl/tests/e2e/prelude/list.tl +0 -0
- {koatl-0.1.33 → koatl-0.1.34}/koatl/tests/e2e/prelude/memo.tl +0 -0
- {koatl-0.1.33 → koatl-0.1.34}/koatl/tests/e2e/prelude/result.tl +0 -0
- {koatl-0.1.33 → koatl-0.1.34}/koatl/tests/e2e/prelude/slice.tl +0 -0
- {koatl-0.1.33 → koatl-0.1.34}/koatl/tests/e2e/prelude/virtual.tl +0 -0
- {koatl-0.1.33 → koatl-0.1.34}/koatl/tests/e2e/util/__init__.py +0 -0
- {koatl-0.1.33 → koatl-0.1.34}/koatl/tests/e2e/util/module0.tl +0 -0
- {koatl-0.1.33 → koatl-0.1.34}/koatl/tests/e2e/util/module1.tl +0 -0
- {koatl-0.1.33 → koatl-0.1.34}/koatl/tests/e2e/util/module2.tl +0 -0
- {koatl-0.1.33 → koatl-0.1.34}/koatl/tests/parse/arith.tl +0 -0
- {koatl-0.1.33 → koatl-0.1.34}/koatl/tests/parse/assign.tl +0 -0
- {koatl-0.1.33 → koatl-0.1.34}/koatl/tests/parse/block-comments.tl +0 -0
- {koatl-0.1.33 → koatl-0.1.34}/koatl/tests/parse/deco.tl +0 -0
- {koatl-0.1.33 → koatl-0.1.34}/koatl/tests/parse/func.tl +0 -0
- {koatl-0.1.33 → koatl-0.1.34}/koatl/tests/parse/matches.tl +0 -0
- {koatl-0.1.33 → koatl-0.1.34}/koatl/tests/test_e2e.py +0 -0
- {koatl-0.1.33 → koatl-0.1.34}/koatl/tests/test_parse.py +0 -0
- {koatl-0.1.33 → koatl-0.1.34}/koatl-core/Cargo.toml +0 -0
- {koatl-0.1.33 → koatl-0.1.34}/koatl-core/parser/Cargo.toml +0 -0
- {koatl-0.1.33 → koatl-0.1.34}/koatl-core/parser/src/lib.rs +0 -0
- {koatl-0.1.33 → koatl-0.1.34}/koatl-core/parser/src/util.rs +0 -0
- {koatl-0.1.33 → koatl-0.1.34}/koatl-core/src/inference.rs +0 -0
- {koatl-0.1.33 → koatl-0.1.34}/koatl-core/src/lib.rs +0 -0
- {koatl-0.1.33 → koatl-0.1.34}/koatl-core/src/main.rs +0 -0
- {koatl-0.1.33 → koatl-0.1.34}/koatl-core/src/parse_timer.rs +0 -0
- {koatl-0.1.33 → koatl-0.1.34}/koatl-core/src/parser.rs +0 -0
- {koatl-0.1.33 → koatl-0.1.34}/koatl-core/src/py/mod.rs +0 -0
- {koatl-0.1.33 → koatl-0.1.34}/koatl-core/src/types.rs +0 -0
- {koatl-0.1.33 → koatl-0.1.34}/koatl-core/src/util.rs +0 -0
- {koatl-0.1.33 → koatl-0.1.34}/pyproject.toml +0 -0
- {koatl-0.1.33 → koatl-0.1.34}/python/koatl/__init__.py +0 -0
- {koatl-0.1.33 → koatl-0.1.34}/python/koatl/__main__.py +0 -0
- {koatl-0.1.33 → koatl-0.1.34}/python/koatl/cli.py +0 -0
- {koatl-0.1.33 → koatl-0.1.34}/python/koatl/notebook/__init__.py +0 -0
- {koatl-0.1.33 → koatl-0.1.34}/python/koatl/notebook/magic.py +0 -0
- {koatl-0.1.33 → koatl-0.1.34}/python/koatl/prelude/__init__.tl +0 -0
- {koatl-0.1.33 → koatl-0.1.34}/python/koatl/prelude/functional/__init__.tl +0 -0
- {koatl-0.1.33 → koatl-0.1.34}/python/koatl/prelude/functional/algebra.tl +0 -0
- {koatl-0.1.33 → koatl-0.1.34}/python/koatl/prelude/functional/async.tl +0 -0
- {koatl-0.1.33 → koatl-0.1.34}/python/koatl/prelude/functional/env.tl +0 -0
- {koatl-0.1.33 → koatl-0.1.34}/python/koatl/prelude/functional/list.tl +0 -0
- {koatl-0.1.33 → koatl-0.1.34}/python/koatl/prelude/functional/memo.tl +0 -0
- {koatl-0.1.33 → koatl-0.1.34}/python/koatl/prelude/io.tl +0 -0
- {koatl-0.1.33 → koatl-0.1.34}/python/koatl/prelude/regex.tl +0 -0
- {koatl-0.1.33 → koatl-0.1.34}/python/koatl/runtime/__init__.py +0 -0
- {koatl-0.1.33 → koatl-0.1.34}/python/koatl/runtime/classes.py +0 -0
- {koatl-0.1.33 → koatl-0.1.34}/python/koatl/runtime/helpers.py +0 -0
- {koatl-0.1.33 → koatl-0.1.34}/python/koatl/runtime/meta_finder.py +0 -0
|
@@ -160,7 +160,7 @@ export Err = class(Result):
|
|
|
160
160
|
raise ValueError(f"Expected Ok, got {repr(self)}")
|
|
161
161
|
coalesce = (self, f) => f()
|
|
162
162
|
|
|
163
|
-
Extension.property(object, "result")& Result
|
|
163
|
+
Extension.property(object, "result")& self => Result
|
|
164
164
|
|
|
165
165
|
__tl__.Ok = Ok
|
|
166
166
|
__tl__.Err = Err
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import itertools
|
|
2
2
|
import builtins
|
|
3
|
-
import .functional.(Traversable, Ok, Err, Memo, Async, AsyncMemo)
|
|
3
|
+
import .functional.(Traversable, Ok, Err, Memo, Async, AsyncMemo, Result)
|
|
4
4
|
|
|
5
5
|
export Iterable = Extension.trait& class(Traversable, Trait):
|
|
6
6
|
iter = Abstract
|
|
@@ -50,6 +50,22 @@ export Iterable = Extension.trait& class(Traversable, Trait):
|
|
|
50
50
|
|
|
51
51
|
filter = (self, f) => builtins.filter(f, self.iter)
|
|
52
52
|
|
|
53
|
+
filter_map = (self, f=None) =>
|
|
54
|
+
let impl = () =>
|
|
55
|
+
if f === None:
|
|
56
|
+
for i in self.iter:
|
|
57
|
+
if Result(i) matches Ok(value):
|
|
58
|
+
yield value
|
|
59
|
+
else:
|
|
60
|
+
for i in self.iter:
|
|
61
|
+
if Result(f(i)) matches Ok(value):
|
|
62
|
+
yield value
|
|
63
|
+
|
|
64
|
+
impl.__name__ = f"filter_map"
|
|
65
|
+
impl.__qualname__ = f"Iterable.filter_map"
|
|
66
|
+
|
|
67
|
+
impl()
|
|
68
|
+
|
|
53
69
|
flat_map = (self, f) => itertools.chain.from_iterable(self.map(f))
|
|
54
70
|
|
|
55
71
|
reverse = self => reversed(list(self.iter))
|
|
@@ -59,8 +75,16 @@ export Iterable = Extension.trait& class(Traversable, Trait):
|
|
|
59
75
|
|
|
60
76
|
copy = self => itertools.tee(self.iter)
|
|
61
77
|
|
|
62
|
-
|
|
63
|
-
|
|
78
|
+
count = (self, f=None) =>
|
|
79
|
+
let acc = 0
|
|
80
|
+
if f === None:
|
|
81
|
+
for _ in self:
|
|
82
|
+
acc += 1
|
|
83
|
+
else:
|
|
84
|
+
for i in self:
|
|
85
|
+
if f(i):
|
|
86
|
+
acc += 1
|
|
87
|
+
acc
|
|
64
88
|
|
|
65
89
|
fold = (self, init, f) =>
|
|
66
90
|
let acc = init
|
|
@@ -163,30 +187,56 @@ export Iterable = Extension.trait& class(Traversable, Trait):
|
|
|
163
187
|
raise ValueError("mean of empty iterable")
|
|
164
188
|
acc / count
|
|
165
189
|
|
|
166
|
-
max = self =>
|
|
190
|
+
max = (self, key=None) =>
|
|
167
191
|
let it = self.iter
|
|
168
|
-
let v
|
|
192
|
+
let v, m
|
|
169
193
|
try:
|
|
170
194
|
v = next(it)
|
|
195
|
+
if key === None:
|
|
196
|
+
m = v
|
|
197
|
+
else:
|
|
198
|
+
m = key(v)
|
|
171
199
|
except StopIteration(value=value):
|
|
172
200
|
raise ValueError("max of empty iterable")
|
|
173
201
|
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
202
|
+
|
|
203
|
+
if key === None:
|
|
204
|
+
for i in it:
|
|
205
|
+
if i > m:
|
|
206
|
+
v = i
|
|
207
|
+
m = i
|
|
208
|
+
else:
|
|
209
|
+
for i in it:
|
|
210
|
+
let ki = key(i)
|
|
211
|
+
if ki > m:
|
|
212
|
+
v = i
|
|
213
|
+
m = ki
|
|
214
|
+
|
|
177
215
|
v
|
|
178
216
|
|
|
179
|
-
min = self =>
|
|
217
|
+
min = (self, key=None) =>
|
|
180
218
|
let it = self.iter
|
|
181
|
-
let v
|
|
219
|
+
let v, m
|
|
182
220
|
try:
|
|
183
221
|
v = next(it)
|
|
222
|
+
if key === None:
|
|
223
|
+
m = v
|
|
224
|
+
else:
|
|
225
|
+
m = key(v)
|
|
184
226
|
except StopIteration(value=value):
|
|
185
227
|
raise ValueError("min of empty iterable")
|
|
186
228
|
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
229
|
+
if key === None:
|
|
230
|
+
for i in it:
|
|
231
|
+
if i < m:
|
|
232
|
+
v = i
|
|
233
|
+
m = i
|
|
234
|
+
else:
|
|
235
|
+
for i in it:
|
|
236
|
+
let ki = key(i)
|
|
237
|
+
if ki < m:
|
|
238
|
+
v = i
|
|
239
|
+
m = ki
|
|
190
240
|
v
|
|
191
241
|
|
|
192
242
|
list = self =>
|
|
@@ -21,6 +21,16 @@ class Record(dict):
|
|
|
21
21
|
|
|
22
22
|
return attr
|
|
23
23
|
|
|
24
|
+
def __hash__(self):
|
|
25
|
+
return hash(tuple(sorted(self.items())))
|
|
26
|
+
|
|
27
|
+
def __eq__(self, other):
|
|
28
|
+
return super().__eq__(other)
|
|
29
|
+
|
|
30
|
+
@property
|
|
31
|
+
def len(self):
|
|
32
|
+
return len(self)
|
|
33
|
+
|
|
24
34
|
@staticmethod
|
|
25
35
|
def method(fn):
|
|
26
36
|
fn._method = True
|
|
@@ -7,7 +7,7 @@ from .._rs import fast_vget, fast_vset, fast_vset_trait
|
|
|
7
7
|
def vget(obj, name, ignore_traits=False):
|
|
8
8
|
try:
|
|
9
9
|
return getattr(obj, name)
|
|
10
|
-
except:
|
|
10
|
+
except AttributeError:
|
|
11
11
|
pass
|
|
12
12
|
|
|
13
13
|
# special case for iter - this could be implemented using types and trait vtbls
|
|
@@ -553,6 +553,7 @@ impl<'src> PyExprExt<'src> for SPyExpr<'src> {
|
|
|
553
553
|
PyBinaryOp::Sub => Some("Sub"),
|
|
554
554
|
PyBinaryOp::Mult => Some("Mult"),
|
|
555
555
|
PyBinaryOp::Div => Some("Div"),
|
|
556
|
+
PyBinaryOp::FloorDiv => Some("FloorDiv"),
|
|
556
557
|
PyBinaryOp::Mod => Some("Mod"),
|
|
557
558
|
PyBinaryOp::Pow => Some("Pow"),
|
|
558
559
|
_ => None,
|
|
@@ -596,6 +597,8 @@ impl<'src> PyExprExt<'src> for SPyExpr<'src> {
|
|
|
596
597
|
PyBinaryOp::Neq => Some("NotEq"),
|
|
597
598
|
PyBinaryOp::Is => Some("Is"),
|
|
598
599
|
PyBinaryOp::Nis => Some("IsNot"),
|
|
600
|
+
PyBinaryOp::In => Some("In"),
|
|
601
|
+
PyBinaryOp::Nin => Some("NotIn"),
|
|
599
602
|
_ => None,
|
|
600
603
|
};
|
|
601
604
|
|
|
@@ -35,11 +35,15 @@ pub enum BinaryOp {
|
|
|
35
35
|
Add,
|
|
36
36
|
Sub,
|
|
37
37
|
Mul,
|
|
38
|
-
Mod,
|
|
39
38
|
MatMul,
|
|
40
39
|
Div,
|
|
41
40
|
Exp,
|
|
42
41
|
|
|
42
|
+
FloorDiv,
|
|
43
|
+
Mod,
|
|
44
|
+
|
|
45
|
+
In,
|
|
46
|
+
Nin,
|
|
43
47
|
Lt,
|
|
44
48
|
Leq,
|
|
45
49
|
Gt,
|
|
@@ -138,9 +142,9 @@ pub enum Stmt<'a, TTree: Tree> {
|
|
|
138
142
|
}
|
|
139
143
|
|
|
140
144
|
#[derive(Debug, Clone)]
|
|
141
|
-
pub struct FmtExpr<
|
|
145
|
+
pub struct FmtExpr<TTree: Tree> {
|
|
142
146
|
pub expr: TTree::Expr,
|
|
143
|
-
pub fmt: Option<
|
|
147
|
+
pub fmt: Option<TTree::Expr>,
|
|
144
148
|
}
|
|
145
149
|
|
|
146
150
|
#[derive(Debug, Clone)]
|
|
@@ -229,7 +233,7 @@ pub enum Expr<'a, TTree: Tree> {
|
|
|
229
233
|
Block(Vec<TTree::Stmt>),
|
|
230
234
|
|
|
231
235
|
Fn(Vec<ArgDefItem<'a, TTree>>, TTree::Expr),
|
|
232
|
-
Fstr(Spanned<String>, Vec<(FmtExpr<
|
|
236
|
+
Fstr(Spanned<String>, Vec<(FmtExpr<TTree>, Spanned<String>)>),
|
|
233
237
|
|
|
234
238
|
// these are removed during desugaring
|
|
235
239
|
Decorated(TTree::Expr, TTree::Expr),
|
|
@@ -347,4 +351,4 @@ pub type SMappingItem<'a> = MappingItem<STree<'a>>;
|
|
|
347
351
|
pub type SMatchCase<'a> = MatchCase<STree<'a>>;
|
|
348
352
|
pub type SCallItem<'a> = CallItem<'a, STree<'a>>;
|
|
349
353
|
pub type SArgDefItem<'a> = ArgDefItem<'a, STree<'a>>;
|
|
350
|
-
pub type SFmtExpr<'a> = FmtExpr<
|
|
354
|
+
pub type SFmtExpr<'a> = FmtExpr<STree<'a>>;
|
|
@@ -5,7 +5,10 @@ use chumsky::{
|
|
|
5
5
|
label::LabelError,
|
|
6
6
|
prelude::*,
|
|
7
7
|
};
|
|
8
|
-
use std::{
|
|
8
|
+
use std::{
|
|
9
|
+
collections::HashSet,
|
|
10
|
+
fmt::{self},
|
|
11
|
+
};
|
|
9
12
|
|
|
10
13
|
use crate::ast::{Span, Spannable, Spanned};
|
|
11
14
|
|
|
@@ -321,7 +324,7 @@ where
|
|
|
321
324
|
fn parse_symbol(&mut self) -> TResult<'src, Spanned<Token<'src>>> {
|
|
322
325
|
const POLYGRAMS: &[&str] = &[
|
|
323
326
|
"+=", "-=", "*=", "/=", "|=", "??=", "===", "<=>", "=>", "..", "==", "<>", "<=", ">=",
|
|
324
|
-
"//", "**", "??", ".=",
|
|
327
|
+
"//", "**", "??", ".=", "::",
|
|
325
328
|
];
|
|
326
329
|
const MONOGRAMS: &str = "[](){}<>.,;:!?@$%^&*+-=|\\/`~";
|
|
327
330
|
|
|
@@ -612,23 +615,13 @@ where
|
|
|
612
615
|
}
|
|
613
616
|
}
|
|
614
617
|
|
|
615
|
-
fn
|
|
618
|
+
fn parse_fstr_inner(&mut self, ending: &str, verbatim: bool) -> TResult<'src, TokenList<'src>> {
|
|
616
619
|
let mut marker = self.cursor();
|
|
617
|
-
|
|
618
|
-
if verbatim {
|
|
619
|
-
self.parse_seq("f\"\"\"")?;
|
|
620
|
-
} else {
|
|
621
|
-
self.parse_seq("f\"")?;
|
|
622
|
-
}
|
|
623
|
-
|
|
624
620
|
let mut tokens = vec![];
|
|
625
621
|
let mut current_str = String::new();
|
|
626
622
|
|
|
627
623
|
loop {
|
|
628
|
-
if self
|
|
629
|
-
.try_parse(|x| x.parse_seq(if verbatim { "\"\"\"" } else { "\"" }))
|
|
630
|
-
.is_ok()
|
|
631
|
-
{
|
|
624
|
+
if self.look_ahead(|x| x.parse_seq(ending)).is_ok() {
|
|
632
625
|
if tokens.len() == 0 {
|
|
633
626
|
tokens.push(Token::FstrBegin(current_str).spanned(self.span_since(&marker)));
|
|
634
627
|
} else {
|
|
@@ -667,12 +660,19 @@ where
|
|
|
667
660
|
|
|
668
661
|
self.parse_nonsemantic()?;
|
|
669
662
|
let _ = self.try_parse(|x| x.parse_newline());
|
|
670
|
-
|
|
671
663
|
let sexpr = self.try_parse(|x| x.parse_block(0, NewBlockType::BeginInput))?;
|
|
672
|
-
|
|
673
664
|
let _ = self.try_parse(|x| x.parse_newline());
|
|
674
|
-
|
|
675
|
-
self.
|
|
665
|
+
|
|
666
|
+
self.parse_indentation()?;
|
|
667
|
+
|
|
668
|
+
marker = self.cursor();
|
|
669
|
+
let mut format_tokens = vec![];
|
|
670
|
+
if self.try_parse(|x| x.parse_seq("!")).is_ok() {
|
|
671
|
+
format_tokens.push(Token::Symbol("!").spanned(self.span_since(&marker)));
|
|
672
|
+
format_tokens.extend(self.parse_fstr_inner("}", verbatim)?);
|
|
673
|
+
}
|
|
674
|
+
|
|
675
|
+
self.parse_seq("}")?;
|
|
676
676
|
|
|
677
677
|
tokens.push(Token::Indent.spanned(Span::new(
|
|
678
678
|
sexpr.span.context,
|
|
@@ -687,6 +687,7 @@ where
|
|
|
687
687
|
sexpr.span.context,
|
|
688
688
|
sexpr.span.end..sexpr.span.end,
|
|
689
689
|
)));
|
|
690
|
+
tokens.extend(format_tokens);
|
|
690
691
|
|
|
691
692
|
marker = self.cursor();
|
|
692
693
|
|
|
@@ -703,6 +704,20 @@ where
|
|
|
703
704
|
}
|
|
704
705
|
}
|
|
705
706
|
|
|
707
|
+
fn parse_fstr(&mut self, verbatim: bool) -> TResult<'src, TokenList<'src>> {
|
|
708
|
+
if verbatim {
|
|
709
|
+
self.parse_seq("f\"\"\"")?;
|
|
710
|
+
let inner = self.parse_fstr_inner("\"\"\"", true)?;
|
|
711
|
+
self.parse_seq("\"\"\"")?;
|
|
712
|
+
return Ok(inner);
|
|
713
|
+
} else {
|
|
714
|
+
self.parse_seq("f\"")?;
|
|
715
|
+
let inner = self.parse_fstr_inner("\"", false)?;
|
|
716
|
+
self.parse_seq("\"")?;
|
|
717
|
+
return Ok(inner);
|
|
718
|
+
}
|
|
719
|
+
}
|
|
720
|
+
|
|
706
721
|
fn parse_str_start(&mut self) -> TResult<'src, ()> {
|
|
707
722
|
let start = self.cursor();
|
|
708
723
|
|
|
@@ -818,6 +833,13 @@ where
|
|
|
818
833
|
break;
|
|
819
834
|
}
|
|
820
835
|
|
|
836
|
+
if let Token::Symbol("!") = &tok.value {
|
|
837
|
+
// Format specifier delimiter; end block.
|
|
838
|
+
self.input.rewind(saved);
|
|
839
|
+
end_block = true;
|
|
840
|
+
break;
|
|
841
|
+
}
|
|
842
|
+
|
|
821
843
|
if let Token::Symbol(s) = &tok.value {
|
|
822
844
|
let char = s.chars().next().unwrap_or('\0');
|
|
823
845
|
if OPEN_DELIMS.contains(&char) {
|
|
@@ -525,6 +525,8 @@ where
|
|
|
525
525
|
symbol("-=").to(BinaryOp::Sub),
|
|
526
526
|
symbol("*=").to(BinaryOp::Mul),
|
|
527
527
|
symbol("/=").to(BinaryOp::Div),
|
|
528
|
+
symbol("//=").to(BinaryOp::FloorDiv),
|
|
529
|
+
symbol("%=").to(BinaryOp::Mod),
|
|
528
530
|
symbol("|=").to(BinaryOp::Pipe),
|
|
529
531
|
symbol("??=").to(BinaryOp::Coalesce),
|
|
530
532
|
))
|
|
@@ -543,6 +545,7 @@ where
|
|
|
543
545
|
SStmtInner::Expr(lhs.indirect())
|
|
544
546
|
}
|
|
545
547
|
})
|
|
548
|
+
.labelled("assignment")
|
|
546
549
|
.boxed();
|
|
547
550
|
|
|
548
551
|
let inline_assign_stmt = group((expr.clone(), assign_op.clone().then(expr.clone()).or_not()))
|
|
@@ -553,6 +556,7 @@ where
|
|
|
553
556
|
SStmtInner::Expr(lhs.indirect())
|
|
554
557
|
}
|
|
555
558
|
})
|
|
559
|
+
.labelled("assignment")
|
|
556
560
|
.boxed();
|
|
557
561
|
|
|
558
562
|
let while_stmt = just(Token::Kw("while"))
|
|
@@ -955,27 +959,32 @@ where
|
|
|
955
959
|
}
|
|
956
960
|
.map_with(|x, e| x.spanned(e.span()));
|
|
957
961
|
|
|
958
|
-
let fstr =
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
(
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
962
|
+
let mut fstr = Recursive::<chumsky::recursive::Indirect<TInput, SExpr, TExtra>>::declare();
|
|
963
|
+
|
|
964
|
+
fstr.define(
|
|
965
|
+
fstr_begin
|
|
966
|
+
.then(
|
|
967
|
+
expr_or_block
|
|
968
|
+
.clone()
|
|
969
|
+
.then(symbol("!").ignore_then(fstr.clone()).or_not())
|
|
970
|
+
.then(fstr_continue)
|
|
971
|
+
.map(|((block, fmt), cont)| {
|
|
972
|
+
(
|
|
973
|
+
FmtExpr {
|
|
974
|
+
expr: block.indirect(),
|
|
975
|
+
fmt: fmt.map(|x| x.indirect()),
|
|
976
|
+
},
|
|
977
|
+
cont,
|
|
978
|
+
)
|
|
979
|
+
})
|
|
980
|
+
.repeated()
|
|
981
|
+
.collect::<Vec<_>>(),
|
|
982
|
+
)
|
|
983
|
+
.map(|(begin, parts)| SExprInner::Fstr(begin, parts))
|
|
984
|
+
.spanned_expr()
|
|
985
|
+
.labelled("f-string")
|
|
986
|
+
.boxed(),
|
|
987
|
+
);
|
|
979
988
|
|
|
980
989
|
let class_ = just(Token::Kw("class"))
|
|
981
990
|
.ignore_then(
|
|
@@ -1183,7 +1192,7 @@ where
|
|
|
1183
1192
|
.labelled("then-attribute")
|
|
1184
1193
|
.boxed();
|
|
1185
1194
|
|
|
1186
|
-
let raw_attr = symbol("
|
|
1195
|
+
let raw_attr = symbol("::")
|
|
1187
1196
|
.ignore_then(ident.clone())
|
|
1188
1197
|
.map(Postfix::RawAttribute)
|
|
1189
1198
|
.labelled("raw-attribute")
|
|
@@ -1307,6 +1316,7 @@ where
|
|
|
1307
1316
|
select! {
|
|
1308
1317
|
Token::Symbol("*") => BinaryOp::Mul,
|
|
1309
1318
|
Token::Symbol("/") => BinaryOp::Div,
|
|
1319
|
+
Token::Symbol("//") => BinaryOp::FloorDiv,
|
|
1310
1320
|
Token::Symbol("%") => BinaryOp::Mod,
|
|
1311
1321
|
Token::Symbol("@") => BinaryOp::MatMul,
|
|
1312
1322
|
},
|
|
@@ -1325,6 +1335,7 @@ where
|
|
|
1325
1335
|
let binary3 = make_binary_op(
|
|
1326
1336
|
binary2.clone(),
|
|
1327
1337
|
select! {
|
|
1338
|
+
Token::Kw("in") => BinaryOp::In,
|
|
1328
1339
|
Token::Symbol("<") => BinaryOp::Lt,
|
|
1329
1340
|
Token::Symbol("<=") => BinaryOp::Leq,
|
|
1330
1341
|
Token::Symbol(">") => BinaryOp::Gt,
|
|
@@ -1333,7 +1344,10 @@ where
|
|
|
1333
1344
|
Token::Symbol("<>") => BinaryOp::Neq,
|
|
1334
1345
|
Token::Symbol("===") => BinaryOp::Is,
|
|
1335
1346
|
Token::Symbol("<=>") => BinaryOp::Nis,
|
|
1336
|
-
}
|
|
1347
|
+
}
|
|
1348
|
+
.or(just(Token::Kw("not"))
|
|
1349
|
+
.then(just(Token::Kw("in")))
|
|
1350
|
+
.to(BinaryOp::Nin)),
|
|
1337
1351
|
false,
|
|
1338
1352
|
);
|
|
1339
1353
|
|
|
@@ -146,6 +146,7 @@ pub enum PyBinaryOp {
|
|
|
146
146
|
Mult,
|
|
147
147
|
Div,
|
|
148
148
|
Mod,
|
|
149
|
+
FloorDiv,
|
|
149
150
|
Pow,
|
|
150
151
|
MatMult,
|
|
151
152
|
|
|
@@ -160,6 +161,8 @@ pub enum PyBinaryOp {
|
|
|
160
161
|
Geq,
|
|
161
162
|
Is,
|
|
162
163
|
Nis,
|
|
164
|
+
In,
|
|
165
|
+
Nin,
|
|
163
166
|
}
|
|
164
167
|
|
|
165
168
|
#[derive(Debug, Clone)]
|
|
@@ -200,7 +203,7 @@ pub enum PyDictItem<'a> {
|
|
|
200
203
|
#[derive(Debug, Clone)]
|
|
201
204
|
pub enum PyFstrPart<'a> {
|
|
202
205
|
Str(PyIdent<'a>),
|
|
203
|
-
Expr(SPyExpr<'a>, Option<
|
|
206
|
+
Expr(SPyExpr<'a>, Option<SPyExpr<'a>>),
|
|
204
207
|
}
|
|
205
208
|
|
|
206
209
|
#[derive(Debug, Clone)]
|
|
@@ -5,7 +5,10 @@ use parser::{
|
|
|
5
5
|
lexer::{py_escape_fstr, py_escape_str},
|
|
6
6
|
};
|
|
7
7
|
|
|
8
|
-
use crate::{
|
|
8
|
+
use crate::{
|
|
9
|
+
py::ast::*,
|
|
10
|
+
util::{TlErrBuilder, TlResult},
|
|
11
|
+
};
|
|
9
12
|
|
|
10
13
|
const LOW_PREC: f32 = -100.0;
|
|
11
14
|
const HIGH_PREC: f32 = 100.0;
|
|
@@ -258,10 +261,16 @@ impl PyBinaryOp {
|
|
|
258
261
|
| PyBinaryOp::Geq
|
|
259
262
|
| PyBinaryOp::Is
|
|
260
263
|
| PyBinaryOp::Nis
|
|
264
|
+
| PyBinaryOp::In
|
|
265
|
+
| PyBinaryOp::Nin
|
|
261
266
|
| PyBinaryOp::And
|
|
262
267
|
| PyBinaryOp::Or => 0.0,
|
|
263
268
|
PyBinaryOp::Add | PyBinaryOp::Sub => 1.0,
|
|
264
|
-
PyBinaryOp::Mult
|
|
269
|
+
PyBinaryOp::Mult
|
|
270
|
+
| PyBinaryOp::Div
|
|
271
|
+
| PyBinaryOp::Mod
|
|
272
|
+
| PyBinaryOp::MatMult
|
|
273
|
+
| PyBinaryOp::FloorDiv => 2.0,
|
|
265
274
|
PyBinaryOp::Pow => 3.0,
|
|
266
275
|
}
|
|
267
276
|
}
|
|
@@ -272,6 +281,7 @@ impl PyBinaryOp {
|
|
|
272
281
|
PyBinaryOp::Sub => "-",
|
|
273
282
|
PyBinaryOp::Mult => "*",
|
|
274
283
|
PyBinaryOp::Div => "/",
|
|
284
|
+
PyBinaryOp::FloorDiv => "//",
|
|
275
285
|
PyBinaryOp::Mod => "%",
|
|
276
286
|
PyBinaryOp::Pow => "**",
|
|
277
287
|
PyBinaryOp::MatMult => "@",
|
|
@@ -283,6 +293,8 @@ impl PyBinaryOp {
|
|
|
283
293
|
PyBinaryOp::Geq => ">=",
|
|
284
294
|
PyBinaryOp::Is => "is",
|
|
285
295
|
PyBinaryOp::Nis => "is not",
|
|
296
|
+
PyBinaryOp::In => "in",
|
|
297
|
+
PyBinaryOp::Nin => "not in",
|
|
286
298
|
PyBinaryOp::And => "and",
|
|
287
299
|
PyBinaryOp::Or => "or",
|
|
288
300
|
});
|
|
@@ -476,22 +488,7 @@ impl SPyExpr<'_> {
|
|
|
476
488
|
PyExpr::Literal(literal) => literal.emit_to(ctx, parent_precendence)?,
|
|
477
489
|
PyExpr::Fstr(fstr_parts) => {
|
|
478
490
|
ctx.emit("f\"");
|
|
479
|
-
|
|
480
|
-
match part {
|
|
481
|
-
PyFstrPart::Str(s) => {
|
|
482
|
-
ctx.emit_escaped_fstr(s);
|
|
483
|
-
}
|
|
484
|
-
PyFstrPart::Expr(expr, fmt) => {
|
|
485
|
-
ctx.emit("{");
|
|
486
|
-
expr.emit_sided_to(ctx, HIGH_PREC, true)?;
|
|
487
|
-
if let Some(fmt) = fmt {
|
|
488
|
-
ctx.emit(":");
|
|
489
|
-
ctx.emit(fmt);
|
|
490
|
-
}
|
|
491
|
-
ctx.emit("}");
|
|
492
|
-
}
|
|
493
|
-
}
|
|
494
|
-
}
|
|
491
|
+
emit_fstr_inner(ctx, fstr_parts)?;
|
|
495
492
|
ctx.emit("\"");
|
|
496
493
|
}
|
|
497
494
|
PyExpr::Slice(start, stop, step) => {
|
|
@@ -547,6 +544,34 @@ impl SPyExpr<'_> {
|
|
|
547
544
|
}
|
|
548
545
|
}
|
|
549
546
|
|
|
547
|
+
fn emit_fstr_inner(ctx: &mut EmitCtx, fstr_parts: &mut [PyFstrPart<'_>]) -> TlResult<()> {
|
|
548
|
+
for part in fstr_parts.iter_mut() {
|
|
549
|
+
match part {
|
|
550
|
+
PyFstrPart::Str(s) => {
|
|
551
|
+
ctx.emit_escaped_fstr(s);
|
|
552
|
+
}
|
|
553
|
+
PyFstrPart::Expr(expr, fmt) => {
|
|
554
|
+
ctx.emit("{");
|
|
555
|
+
expr.emit_sided_to(ctx, HIGH_PREC, true)?;
|
|
556
|
+
|
|
557
|
+
if let Some(fmt) = fmt {
|
|
558
|
+
ctx.emit(":");
|
|
559
|
+
let PyExpr::Fstr(fmt_parts) = &mut fmt.value else {
|
|
560
|
+
return Err(TlErrBuilder::new()
|
|
561
|
+
.message("Format specifier must be an fstr")
|
|
562
|
+
.span(fmt.tl_span)
|
|
563
|
+
.build());
|
|
564
|
+
};
|
|
565
|
+
emit_fstr_inner(ctx, fmt_parts)?;
|
|
566
|
+
}
|
|
567
|
+
ctx.emit("}");
|
|
568
|
+
}
|
|
569
|
+
}
|
|
570
|
+
}
|
|
571
|
+
|
|
572
|
+
Ok(())
|
|
573
|
+
}
|
|
574
|
+
|
|
550
575
|
impl PyBlock<'_> {
|
|
551
576
|
pub fn emit_to(&mut self, ctx: &mut EmitCtx, delta_indentation: i32) -> TlResult<()> {
|
|
552
577
|
let old_indentation = ctx.indentation;
|
|
@@ -376,7 +376,7 @@ impl PyAstBuilder {
|
|
|
376
376
|
pub fn fstr_expr<'src>(
|
|
377
377
|
&self,
|
|
378
378
|
expr: SPyExpr<'src>,
|
|
379
|
-
format_spec: impl Into<Option<
|
|
379
|
+
format_spec: impl Into<Option<SPyExpr<'src>>>,
|
|
380
380
|
) -> PyFstrPart<'src> {
|
|
381
381
|
PyFstrPart::Expr(expr, format_spec.into())
|
|
382
382
|
}
|
|
@@ -1348,10 +1348,7 @@ fn transform_postfix_expr<'src, 'ast>(
|
|
|
1348
1348
|
}
|
|
1349
1349
|
Expr::ScopedAttribute(_, rhs) | Expr::MappedScopedAttribute(_, rhs) => {
|
|
1350
1350
|
let t = inner_pre.bind(rhs.transform(ctx)?);
|
|
1351
|
-
a.call(
|
|
1352
|
-
a.tl_builtin("partial"),
|
|
1353
|
-
vec![PyCallItem::Arg(t), PyCallItem::Arg(lhs)],
|
|
1354
|
-
)
|
|
1351
|
+
a.call(t, vec![PyCallItem::Arg(lhs)])
|
|
1355
1352
|
}
|
|
1356
1353
|
Expr::RawAttribute(_, attr) | Expr::MappedRawAttribute(_, attr) => {
|
|
1357
1354
|
a.attribute(lhs, attr.value.escape(), access_ctx)
|
|
@@ -2168,10 +2165,14 @@ impl<'src, 'ast> SExprExt<'src, 'ast> for SExpr<'src> {
|
|
|
2168
2165
|
nodes.push(PyFstrPart::Str(begin.value.clone().into()));
|
|
2169
2166
|
|
|
2170
2167
|
for (fmt_expr, str_part) in parts {
|
|
2171
|
-
// TODO format specifiers?
|
|
2172
2168
|
let expr = pre.bind(fmt_expr.expr.transform(ctx)?);
|
|
2169
|
+
let fmt = fmt_expr
|
|
2170
|
+
.fmt
|
|
2171
|
+
.as_ref()
|
|
2172
|
+
.map(|x| -> TlResult<_> { Ok(pre.bind(x.transform(ctx)?)) })
|
|
2173
|
+
.transpose()?;
|
|
2173
2174
|
|
|
2174
|
-
nodes.push(PyFstrPart::Expr(expr,
|
|
2175
|
+
nodes.push(PyFstrPart::Expr(expr, fmt));
|
|
2175
2176
|
nodes.push(PyFstrPart::Str(str_part.value.clone().into()));
|
|
2176
2177
|
}
|
|
2177
2178
|
|
|
@@ -2225,6 +2226,7 @@ fn map_py_binary_op(op: BinaryOp, span: Span) -> TlResult<PyBinaryOp> {
|
|
|
2225
2226
|
BinaryOp::Sub => PyBinaryOp::Sub,
|
|
2226
2227
|
BinaryOp::Mul => PyBinaryOp::Mult,
|
|
2227
2228
|
BinaryOp::Div => PyBinaryOp::Div,
|
|
2229
|
+
BinaryOp::FloorDiv => PyBinaryOp::FloorDiv,
|
|
2228
2230
|
BinaryOp::Mod => PyBinaryOp::Mod,
|
|
2229
2231
|
BinaryOp::Exp => PyBinaryOp::Pow,
|
|
2230
2232
|
BinaryOp::MatMul => PyBinaryOp::MatMult,
|
|
@@ -2237,6 +2239,8 @@ fn map_py_binary_op(op: BinaryOp, span: Span) -> TlResult<PyBinaryOp> {
|
|
|
2237
2239
|
BinaryOp::Neq => PyBinaryOp::Neq,
|
|
2238
2240
|
BinaryOp::Is => PyBinaryOp::Is,
|
|
2239
2241
|
BinaryOp::Nis => PyBinaryOp::Nis,
|
|
2242
|
+
BinaryOp::In => PyBinaryOp::In,
|
|
2243
|
+
BinaryOp::Nin => PyBinaryOp::Nin,
|
|
2240
2244
|
|
|
2241
2245
|
_ => return Err(simple_err("Internal error: Unsupported binary op", span)),
|
|
2242
2246
|
})
|
|
@@ -160,7 +160,7 @@ export Err = class(Result):
|
|
|
160
160
|
raise ValueError(f"Expected Ok, got {repr(self)}")
|
|
161
161
|
coalesce = (self, f) => f()
|
|
162
162
|
|
|
163
|
-
Extension.property(object, "result")& Result
|
|
163
|
+
Extension.property(object, "result")& self => Result
|
|
164
164
|
|
|
165
165
|
__tl__.Ok = Ok
|
|
166
166
|
__tl__.Err = Err
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import itertools
|
|
2
2
|
import builtins
|
|
3
|
-
import .functional.(Traversable, Ok, Err, Memo, Async, AsyncMemo)
|
|
3
|
+
import .functional.(Traversable, Ok, Err, Memo, Async, AsyncMemo, Result)
|
|
4
4
|
|
|
5
5
|
export Iterable = Extension.trait& class(Traversable, Trait):
|
|
6
6
|
iter = Abstract
|
|
@@ -50,6 +50,22 @@ export Iterable = Extension.trait& class(Traversable, Trait):
|
|
|
50
50
|
|
|
51
51
|
filter = (self, f) => builtins.filter(f, self.iter)
|
|
52
52
|
|
|
53
|
+
filter_map = (self, f=None) =>
|
|
54
|
+
let impl = () =>
|
|
55
|
+
if f === None:
|
|
56
|
+
for i in self.iter:
|
|
57
|
+
if Result(i) matches Ok(value):
|
|
58
|
+
yield value
|
|
59
|
+
else:
|
|
60
|
+
for i in self.iter:
|
|
61
|
+
if Result(f(i)) matches Ok(value):
|
|
62
|
+
yield value
|
|
63
|
+
|
|
64
|
+
impl.__name__ = f"filter_map"
|
|
65
|
+
impl.__qualname__ = f"Iterable.filter_map"
|
|
66
|
+
|
|
67
|
+
impl()
|
|
68
|
+
|
|
53
69
|
flat_map = (self, f) => itertools.chain.from_iterable(self.map(f))
|
|
54
70
|
|
|
55
71
|
reverse = self => reversed(list(self.iter))
|
|
@@ -59,8 +75,16 @@ export Iterable = Extension.trait& class(Traversable, Trait):
|
|
|
59
75
|
|
|
60
76
|
copy = self => itertools.tee(self.iter)
|
|
61
77
|
|
|
62
|
-
|
|
63
|
-
|
|
78
|
+
count = (self, f=None) =>
|
|
79
|
+
let acc = 0
|
|
80
|
+
if f === None:
|
|
81
|
+
for _ in self:
|
|
82
|
+
acc += 1
|
|
83
|
+
else:
|
|
84
|
+
for i in self:
|
|
85
|
+
if f(i):
|
|
86
|
+
acc += 1
|
|
87
|
+
acc
|
|
64
88
|
|
|
65
89
|
fold = (self, init, f) =>
|
|
66
90
|
let acc = init
|
|
@@ -163,30 +187,56 @@ export Iterable = Extension.trait& class(Traversable, Trait):
|
|
|
163
187
|
raise ValueError("mean of empty iterable")
|
|
164
188
|
acc / count
|
|
165
189
|
|
|
166
|
-
max = self =>
|
|
190
|
+
max = (self, key=None) =>
|
|
167
191
|
let it = self.iter
|
|
168
|
-
let v
|
|
192
|
+
let v, m
|
|
169
193
|
try:
|
|
170
194
|
v = next(it)
|
|
195
|
+
if key === None:
|
|
196
|
+
m = v
|
|
197
|
+
else:
|
|
198
|
+
m = key(v)
|
|
171
199
|
except StopIteration(value=value):
|
|
172
200
|
raise ValueError("max of empty iterable")
|
|
173
201
|
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
202
|
+
|
|
203
|
+
if key === None:
|
|
204
|
+
for i in it:
|
|
205
|
+
if i > m:
|
|
206
|
+
v = i
|
|
207
|
+
m = i
|
|
208
|
+
else:
|
|
209
|
+
for i in it:
|
|
210
|
+
let ki = key(i)
|
|
211
|
+
if ki > m:
|
|
212
|
+
v = i
|
|
213
|
+
m = ki
|
|
214
|
+
|
|
177
215
|
v
|
|
178
216
|
|
|
179
|
-
min = self =>
|
|
217
|
+
min = (self, key=None) =>
|
|
180
218
|
let it = self.iter
|
|
181
|
-
let v
|
|
219
|
+
let v, m
|
|
182
220
|
try:
|
|
183
221
|
v = next(it)
|
|
222
|
+
if key === None:
|
|
223
|
+
m = v
|
|
224
|
+
else:
|
|
225
|
+
m = key(v)
|
|
184
226
|
except StopIteration(value=value):
|
|
185
227
|
raise ValueError("min of empty iterable")
|
|
186
228
|
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
229
|
+
if key === None:
|
|
230
|
+
for i in it:
|
|
231
|
+
if i < m:
|
|
232
|
+
v = i
|
|
233
|
+
m = i
|
|
234
|
+
else:
|
|
235
|
+
for i in it:
|
|
236
|
+
let ki = key(i)
|
|
237
|
+
if ki < m:
|
|
238
|
+
v = i
|
|
239
|
+
m = ki
|
|
190
240
|
v
|
|
191
241
|
|
|
192
242
|
list = self =>
|
|
@@ -21,6 +21,16 @@ class Record(dict):
|
|
|
21
21
|
|
|
22
22
|
return attr
|
|
23
23
|
|
|
24
|
+
def __hash__(self):
|
|
25
|
+
return hash(tuple(sorted(self.items())))
|
|
26
|
+
|
|
27
|
+
def __eq__(self, other):
|
|
28
|
+
return super().__eq__(other)
|
|
29
|
+
|
|
30
|
+
@property
|
|
31
|
+
def len(self):
|
|
32
|
+
return len(self)
|
|
33
|
+
|
|
24
34
|
@staticmethod
|
|
25
35
|
def method(fn):
|
|
26
36
|
fn._method = True
|
|
@@ -7,7 +7,7 @@ from .._rs import fast_vget, fast_vset, fast_vset_trait
|
|
|
7
7
|
def vget(obj, name, ignore_traits=False):
|
|
8
8
|
try:
|
|
9
9
|
return getattr(obj, name)
|
|
10
|
-
except:
|
|
10
|
+
except AttributeError:
|
|
11
11
|
pass
|
|
12
12
|
|
|
13
13
|
# special case for iter - this could be implemented using types and trait vtbls
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|