koatl 0.3.18__tar.gz → 0.3.20__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (154) hide show
  1. {koatl-0.3.18 → koatl-0.3.20}/Cargo.lock +1 -1
  2. {koatl-0.3.18 → koatl-0.3.20}/PKG-INFO +1 -1
  3. {koatl-0.3.18 → koatl-0.3.20}/koatl/Cargo.toml +1 -1
  4. {koatl-0.3.18 → koatl-0.3.20}/koatl/python/koatl/std/iter.tl +9 -5
  5. {koatl-0.3.18 → koatl-0.3.20}/koatl/src/emit_py.rs +8 -2
  6. koatl-0.3.20/koatl/tests/e2e/base/fstr.tl +51 -0
  7. {koatl-0.3.18 → koatl-0.3.20}/koatl/tests/test_iterable.tl +16 -14
  8. {koatl-0.3.18 → koatl-0.3.20}/koatl-parser/src/lexer.rs +4 -2
  9. {koatl-0.3.18 → koatl-0.3.20}/python/koatl/std/iter.tl +9 -5
  10. koatl-0.3.18/koatl/tests/e2e/base/fstr.tl +0 -27
  11. {koatl-0.3.18 → koatl-0.3.20}/Cargo.toml +0 -0
  12. {koatl-0.3.18 → koatl-0.3.20}/README.md +0 -0
  13. {koatl-0.3.18 → koatl-0.3.20}/koatl/.github/workflows/CI.yml +0 -0
  14. {koatl-0.3.18 → koatl-0.3.20}/koatl/.gitignore +0 -0
  15. {koatl-0.3.18 → koatl-0.3.20}/koatl/LICENSE +0 -0
  16. {koatl-0.3.18 → koatl-0.3.20}/koatl/README.md +0 -0
  17. {koatl-0.3.18 → koatl-0.3.20}/koatl/python/koatl/__init__.py +0 -0
  18. {koatl-0.3.18 → koatl-0.3.20}/koatl/python/koatl/__main__.py +0 -0
  19. {koatl-0.3.18 → koatl-0.3.20}/koatl/python/koatl/cli.py +0 -0
  20. {koatl-0.3.18 → koatl-0.3.20}/koatl/python/koatl/notebook/__init__.py +0 -0
  21. {koatl-0.3.18 → koatl-0.3.20}/koatl/python/koatl/notebook/magic.py +0 -0
  22. {koatl-0.3.18 → koatl-0.3.20}/koatl/python/koatl/prelude/__init__.tl +0 -0
  23. {koatl-0.3.18 → koatl-0.3.20}/koatl/python/koatl/runtime/__init__.py +0 -0
  24. {koatl-0.3.18 → koatl-0.3.20}/koatl/python/koatl/runtime/meta_finder.py +0 -0
  25. {koatl-0.3.18 → koatl-0.3.20}/koatl/python/koatl/runtime/record.py +0 -0
  26. {koatl-0.3.18 → koatl-0.3.20}/koatl/python/koatl/runtime/vattr.py +0 -0
  27. {koatl-0.3.18 → koatl-0.3.20}/koatl/python/koatl/std/__init__.tl +0 -0
  28. {koatl-0.3.18 → koatl-0.3.20}/koatl/python/koatl/std/control/__init__.tl +0 -0
  29. {koatl-0.3.18 → koatl-0.3.20}/koatl/python/koatl/std/control/async.tl +0 -0
  30. {koatl-0.3.18 → koatl-0.3.20}/koatl/python/koatl/std/control/base.tl +0 -0
  31. {koatl-0.3.18 → koatl-0.3.20}/koatl/python/koatl/std/control/do.tl +0 -0
  32. {koatl-0.3.18 → koatl-0.3.20}/koatl/python/koatl/std/control/env.tl +0 -0
  33. {koatl-0.3.18 → koatl-0.3.20}/koatl/python/koatl/std/control/memo.tl +0 -0
  34. {koatl-0.3.18 → koatl-0.3.20}/koatl/python/koatl/std/control/result.tl +0 -0
  35. {koatl-0.3.18 → koatl-0.3.20}/koatl/python/koatl/std/data/__init__.tl +0 -0
  36. {koatl-0.3.18 → koatl-0.3.20}/koatl/python/koatl/std/data/list.tl +0 -0
  37. {koatl-0.3.18 → koatl-0.3.20}/koatl/python/koatl/std/data/record.tl +0 -0
  38. {koatl-0.3.18 → koatl-0.3.20}/koatl/python/koatl/std/ext.tl +0 -0
  39. {koatl-0.3.18 → koatl-0.3.20}/koatl/python/koatl/std/io.tl +0 -0
  40. {koatl-0.3.18 → koatl-0.3.20}/koatl/python/koatl/std/json.tl +0 -0
  41. {koatl-0.3.18 → koatl-0.3.20}/koatl/python/koatl/std/lazy_module.tl +0 -0
  42. {koatl-0.3.18 → koatl-0.3.20}/koatl/python/koatl/std/pickle.tl +0 -0
  43. {koatl-0.3.18 → koatl-0.3.20}/koatl/python/koatl/std/re.tl +0 -0
  44. {koatl-0.3.18 → koatl-0.3.20}/koatl/python/koatl/std/trait.py +0 -0
  45. {koatl-0.3.18 → koatl-0.3.20}/koatl/requirements.txt +0 -0
  46. {koatl-0.3.18 → koatl-0.3.20}/koatl/src/lib.rs +0 -0
  47. {koatl-0.3.18 → koatl-0.3.20}/koatl/tests/conftest.py +0 -0
  48. {koatl-0.3.18 → koatl-0.3.20}/koatl/tests/e2e/base/arguments.tl +0 -0
  49. {koatl-0.3.18 → koatl-0.3.20}/koatl/tests/e2e/base/containers.tl +0 -0
  50. {koatl-0.3.18 → koatl-0.3.20}/koatl/tests/e2e/base/data.txt +0 -0
  51. {koatl-0.3.18 → koatl-0.3.20}/koatl/tests/e2e/base/decorators.tl +0 -0
  52. {koatl-0.3.18 → koatl-0.3.20}/koatl/tests/e2e/base/destructure-for-and-fn.tl +0 -0
  53. {koatl-0.3.18 → koatl-0.3.20}/koatl/tests/e2e/base/destructure.tl +0 -0
  54. {koatl-0.3.18 → koatl-0.3.20}/koatl/tests/e2e/base/escape_ident.tl +0 -0
  55. {koatl-0.3.18 → koatl-0.3.20}/koatl/tests/e2e/base/functions.tl +0 -0
  56. {koatl-0.3.18 → koatl-0.3.20}/koatl/tests/e2e/base/generator.tl +0 -0
  57. {koatl-0.3.18 → koatl-0.3.20}/koatl/tests/e2e/base/if_expr.tl +0 -0
  58. {koatl-0.3.18 → koatl-0.3.20}/koatl/tests/e2e/base/imports.tl +0 -0
  59. {koatl-0.3.18 → koatl-0.3.20}/koatl/tests/e2e/base/imports2.tl +0 -0
  60. {koatl-0.3.18 → koatl-0.3.20}/koatl/tests/e2e/base/loops.tl +0 -0
  61. {koatl-0.3.18 → koatl-0.3.20}/koatl/tests/e2e/base/match.tl +0 -0
  62. {koatl-0.3.18 → koatl-0.3.20}/koatl/tests/e2e/base/nary-list.tl +0 -0
  63. {koatl-0.3.18 → koatl-0.3.20}/koatl/tests/e2e/base/placeholder.tl +0 -0
  64. {koatl-0.3.18 → koatl-0.3.20}/koatl/tests/e2e/base/precedence.tl +0 -0
  65. {koatl-0.3.18 → koatl-0.3.20}/koatl/tests/e2e/base/scopes.tl +0 -0
  66. {koatl-0.3.18 → koatl-0.3.20}/koatl/tests/e2e/base/semantic_whitespace.tl +0 -0
  67. {koatl-0.3.18 → koatl-0.3.20}/koatl/tests/e2e/base/short_circuit.tl +0 -0
  68. {koatl-0.3.18 → koatl-0.3.20}/koatl/tests/e2e/base/with.tl +0 -0
  69. {koatl-0.3.18 → koatl-0.3.20}/koatl/tests/e2e/prelude/async.tl +0 -0
  70. {koatl-0.3.18 → koatl-0.3.20}/koatl/tests/e2e/prelude/aug_assign.tl +0 -0
  71. {koatl-0.3.18 → koatl-0.3.20}/koatl/tests/e2e/prelude/coal.tl +0 -0
  72. {koatl-0.3.18 → koatl-0.3.20}/koatl/tests/e2e/prelude/env.tl +0 -0
  73. {koatl-0.3.18 → koatl-0.3.20}/koatl/tests/e2e/prelude/iterables.tl +0 -0
  74. {koatl-0.3.18 → koatl-0.3.20}/koatl/tests/e2e/prelude/list.tl +0 -0
  75. {koatl-0.3.18 → koatl-0.3.20}/koatl/tests/e2e/prelude/memo.tl +0 -0
  76. {koatl-0.3.18 → koatl-0.3.20}/koatl/tests/e2e/prelude/record.tl +0 -0
  77. {koatl-0.3.18 → koatl-0.3.20}/koatl/tests/e2e/prelude/result.tl +0 -0
  78. {koatl-0.3.18 → koatl-0.3.20}/koatl/tests/e2e/prelude/slice.tl +0 -0
  79. {koatl-0.3.18 → koatl-0.3.20}/koatl/tests/e2e/prelude/try.tl +0 -0
  80. {koatl-0.3.18 → koatl-0.3.20}/koatl/tests/e2e/prelude/virtual.tl +0 -0
  81. {koatl-0.3.18 → koatl-0.3.20}/koatl/tests/e2e/test_modules/module0.tl +0 -0
  82. {koatl-0.3.18 → koatl-0.3.20}/koatl/tests/e2e/test_modules/module1.tl +0 -0
  83. {koatl-0.3.18 → koatl-0.3.20}/koatl/tests/e2e/test_modules/module2.tl +0 -0
  84. {koatl-0.3.18 → koatl-0.3.20}/koatl/tests/fail-parse/arguments_mixed_defaults.tl +0 -0
  85. {koatl-0.3.18 → koatl-0.3.20}/koatl/tests/fail-parse/arguments_multiple_kwargs.tl +0 -0
  86. {koatl-0.3.18 → koatl-0.3.20}/koatl/tests/fail-parse/arguments_multiple_kwonly_markers.tl +0 -0
  87. {koatl-0.3.18 → koatl-0.3.20}/koatl/tests/fail-parse/arguments_multiple_posonly_markers.tl +0 -0
  88. {koatl-0.3.18 → koatl-0.3.20}/koatl/tests/fail-parse/arguments_multiple_varargs.tl +0 -0
  89. {koatl-0.3.18 → koatl-0.3.20}/koatl/tests/fail-parse/arguments_posonly_after_kwonly.tl +0 -0
  90. {koatl-0.3.18 → koatl-0.3.20}/koatl/tests/fail-parse/arguments_vararg_and_kwonly_marker.tl +0 -0
  91. {koatl-0.3.18 → koatl-0.3.20}/koatl/tests/fail-parse/unmatched_closing_delimiter.tl +0 -0
  92. {koatl-0.3.18 → koatl-0.3.20}/koatl/tests/parse/arith.tl +0 -0
  93. {koatl-0.3.18 → koatl-0.3.20}/koatl/tests/parse/assign.tl +0 -0
  94. {koatl-0.3.18 → koatl-0.3.20}/koatl/tests/parse/block-comments.tl +0 -0
  95. {koatl-0.3.18 → koatl-0.3.20}/koatl/tests/parse/deco.tl +0 -0
  96. {koatl-0.3.18 → koatl-0.3.20}/koatl/tests/parse/func.tl +0 -0
  97. {koatl-0.3.18 → koatl-0.3.20}/koatl/tests/parse/matches.tl +0 -0
  98. {koatl-0.3.18 → koatl-0.3.20}/koatl/tests/parse/mutual-recursion.tl +0 -0
  99. {koatl-0.3.18 → koatl-0.3.20}/koatl/tests/parse/numbers.tl +0 -0
  100. {koatl-0.3.18 → koatl-0.3.20}/koatl/tests/parse/operators.tl +0 -0
  101. {koatl-0.3.18 → koatl-0.3.20}/koatl/tests/test_e2e.py +0 -0
  102. {koatl-0.3.18 → koatl-0.3.20}/koatl/tests/test_parse.py +0 -0
  103. {koatl-0.3.18 → koatl-0.3.20}/koatl/tests/test_parse_fail.py +0 -0
  104. {koatl-0.3.18 → koatl-0.3.20}/koatl/tests/test_re.tl +0 -0
  105. {koatl-0.3.18 → koatl-0.3.20}/koatl/tests/util/__init__.py +0 -0
  106. {koatl-0.3.18 → koatl-0.3.20}/koatl-core/Cargo.toml +0 -0
  107. {koatl-0.3.18 → koatl-0.3.20}/koatl-core/src/ast.rs +0 -0
  108. {koatl-0.3.18 → koatl-0.3.20}/koatl-core/src/ast_builder.rs +0 -0
  109. {koatl-0.3.18 → koatl-0.3.20}/koatl-core/src/inference.rs +0 -0
  110. {koatl-0.3.18 → koatl-0.3.20}/koatl-core/src/lib.rs +0 -0
  111. {koatl-0.3.18 → koatl-0.3.20}/koatl-core/src/lift_cst.rs +0 -0
  112. {koatl-0.3.18 → koatl-0.3.20}/koatl-core/src/main.rs +0 -0
  113. {koatl-0.3.18 → koatl-0.3.20}/koatl-core/src/py/ast.rs +0 -0
  114. {koatl-0.3.18 → koatl-0.3.20}/koatl-core/src/py/ast_builder.rs +0 -0
  115. {koatl-0.3.18 → koatl-0.3.20}/koatl-core/src/py/emit.rs +0 -0
  116. {koatl-0.3.18 → koatl-0.3.20}/koatl-core/src/py/mod.rs +0 -0
  117. {koatl-0.3.18 → koatl-0.3.20}/koatl-core/src/resolve_scopes.rs +0 -0
  118. {koatl-0.3.18 → koatl-0.3.20}/koatl-core/src/transform.rs +0 -0
  119. {koatl-0.3.18 → koatl-0.3.20}/koatl-core/src/types.rs +0 -0
  120. {koatl-0.3.18 → koatl-0.3.20}/koatl-core/src/util.rs +0 -0
  121. {koatl-0.3.18 → koatl-0.3.20}/koatl-parser/Cargo.toml +0 -0
  122. {koatl-0.3.18 → koatl-0.3.20}/koatl-parser/src/cst.rs +0 -0
  123. {koatl-0.3.18 → koatl-0.3.20}/koatl-parser/src/lib.rs +0 -0
  124. {koatl-0.3.18 → koatl-0.3.20}/koatl-parser/src/parser.rs +0 -0
  125. {koatl-0.3.18 → koatl-0.3.20}/koatl-parser/src/simple_fmt.rs +0 -0
  126. {koatl-0.3.18 → koatl-0.3.20}/pyproject.toml +0 -0
  127. {koatl-0.3.18 → koatl-0.3.20}/python/koatl/__init__.py +0 -0
  128. {koatl-0.3.18 → koatl-0.3.20}/python/koatl/__main__.py +0 -0
  129. {koatl-0.3.18 → koatl-0.3.20}/python/koatl/cli.py +0 -0
  130. {koatl-0.3.18 → koatl-0.3.20}/python/koatl/notebook/__init__.py +0 -0
  131. {koatl-0.3.18 → koatl-0.3.20}/python/koatl/notebook/magic.py +0 -0
  132. {koatl-0.3.18 → koatl-0.3.20}/python/koatl/prelude/__init__.tl +0 -0
  133. {koatl-0.3.18 → koatl-0.3.20}/python/koatl/runtime/__init__.py +0 -0
  134. {koatl-0.3.18 → koatl-0.3.20}/python/koatl/runtime/meta_finder.py +0 -0
  135. {koatl-0.3.18 → koatl-0.3.20}/python/koatl/runtime/record.py +0 -0
  136. {koatl-0.3.18 → koatl-0.3.20}/python/koatl/runtime/vattr.py +0 -0
  137. {koatl-0.3.18 → koatl-0.3.20}/python/koatl/std/__init__.tl +0 -0
  138. {koatl-0.3.18 → koatl-0.3.20}/python/koatl/std/control/__init__.tl +0 -0
  139. {koatl-0.3.18 → koatl-0.3.20}/python/koatl/std/control/async.tl +0 -0
  140. {koatl-0.3.18 → koatl-0.3.20}/python/koatl/std/control/base.tl +0 -0
  141. {koatl-0.3.18 → koatl-0.3.20}/python/koatl/std/control/do.tl +0 -0
  142. {koatl-0.3.18 → koatl-0.3.20}/python/koatl/std/control/env.tl +0 -0
  143. {koatl-0.3.18 → koatl-0.3.20}/python/koatl/std/control/memo.tl +0 -0
  144. {koatl-0.3.18 → koatl-0.3.20}/python/koatl/std/control/result.tl +0 -0
  145. {koatl-0.3.18 → koatl-0.3.20}/python/koatl/std/data/__init__.tl +0 -0
  146. {koatl-0.3.18 → koatl-0.3.20}/python/koatl/std/data/list.tl +0 -0
  147. {koatl-0.3.18 → koatl-0.3.20}/python/koatl/std/data/record.tl +0 -0
  148. {koatl-0.3.18 → koatl-0.3.20}/python/koatl/std/ext.tl +0 -0
  149. {koatl-0.3.18 → koatl-0.3.20}/python/koatl/std/io.tl +0 -0
  150. {koatl-0.3.18 → koatl-0.3.20}/python/koatl/std/json.tl +0 -0
  151. {koatl-0.3.18 → koatl-0.3.20}/python/koatl/std/lazy_module.tl +0 -0
  152. {koatl-0.3.18 → koatl-0.3.20}/python/koatl/std/pickle.tl +0 -0
  153. {koatl-0.3.18 → koatl-0.3.20}/python/koatl/std/re.tl +0 -0
  154. {koatl-0.3.18 → koatl-0.3.20}/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.18"
193
+ version = "0.3.20"
194
194
  dependencies = [
195
195
  "ariadne",
196
196
  "koatl-core",
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: koatl
3
- Version: 0.3.18
3
+ Version: 0.3.20
4
4
  Classifier: Programming Language :: Rust
5
5
  Classifier: Programming Language :: Python :: Implementation :: CPython
6
6
  Classifier: Programming Language :: Python :: Implementation :: PyPy
@@ -1,6 +1,6 @@
1
1
  [package]
2
2
  name = "koatl"
3
- version = "0.3.18"
3
+ version = "0.3.20"
4
4
  edition = "2021"
5
5
  homepage = "https://koatl.org"
6
6
 
@@ -84,16 +84,20 @@ export Iterable = class(Traversable, Trait):
84
84
 
85
85
  impl()
86
86
 
87
- flat_map = (self, f) => itertools.chain.from_iterable(self.map(f))
87
+ flat_map = (self, f=None) =>
88
+ if f === None:
89
+ itertools.chain.from_iterable(self.iter)
90
+ else:
91
+ itertools.chain.from_iterable(self.iter.map(f))
88
92
 
89
- reverse = self => reversed(list(self.iter))
93
+ reversed = self => reversed(list(self.iter))
90
94
 
91
- sort = (self, key=None, reverse=False) =>
95
+ sorted = (self, key=None, reverse=False) =>
92
96
  sorted(self.iter, key=key, reverse=reverse)
93
97
 
94
98
  copy = self => itertools.tee(self.iter)
95
99
 
96
- count = (self, f=None) =>
100
+ tally = (self, f=None) =>
97
101
  let acc = 0
98
102
  if f === None:
99
103
  for _ in self:
@@ -187,7 +191,7 @@ export Iterable = class(Traversable, Trait):
187
191
  impl()
188
192
 
189
193
  join = (self, sep="") =>
190
- sep.join(self.map(str))
194
+ sep.join(self.iter.map(str))
191
195
 
192
196
  sum = self =>
193
197
  let acc = 0
@@ -708,11 +708,17 @@ impl<'src> PyExprExt<'src> for SPyExpr<'src> {
708
708
  PyFstrPart::Str(s) => {
709
709
  values.push(ctx.ast_node("Constant", (s.as_ref(),), &self.tl_span)?);
710
710
  }
711
- PyFstrPart::Expr(expr, _format_spec) => {
711
+ PyFstrPart::Expr(expr, format_spec) => {
712
712
  let expr_ast = expr.emit_py(ctx)?;
713
+ let format_spec_ast = if let Some(spec) = format_spec {
714
+ spec.emit_py(ctx)?
715
+ } else {
716
+ ctx.py.None()
717
+ };
718
+
713
719
  values.push(ctx.ast_node(
714
720
  "FormattedValue",
715
- (expr_ast, -1, ctx.py.None()),
721
+ (expr_ast, -1, format_spec_ast),
716
722
  &self.tl_span,
717
723
  )?);
718
724
  }
@@ -0,0 +1,51 @@
1
+ import util.assert_eq
2
+
3
+ assert_eq(f"{1}", "1")
4
+
5
+ x = 1
6
+
7
+ fstr = f"x = {x + 1}"
8
+ assert_eq(fstr, "x = 2")
9
+
10
+ fstr = f"x = {(y => y)(x)}"
11
+ assert_eq(fstr, "x = 1")
12
+
13
+ fstr = f"={(
14
+ let a = 1
15
+ let b = 2
16
+ let c = 3
17
+ a * b * c
18
+ )}="
19
+ assert_eq(fstr, "=6=")
20
+
21
+ assert_eq(f"{{}}", "{}")
22
+ assert_eq(f"{{{1}}}", "{1}")
23
+
24
+ assert_eq(f"""
25
+
26
+ {{1}}
27
+ {2 * 5}""", "\n\n{1}\n10")
28
+
29
+ # Test format specifiers
30
+ num = 42
31
+ assert_eq(f"{num%d}", "42")
32
+ assert_eq(f"{num%05d}", "00042")
33
+ assert_eq(f"{num%>5d}", " 42")
34
+ assert_eq(f"{num%<5d}", "42 ")
35
+ assert_eq(f"{num%^5d}", " 42 ")
36
+
37
+ pi = 3.14159
38
+ assert_eq(f"{pi%.2f}", "3.14")
39
+ assert_eq(f"{pi%.4f}", "3.1416")
40
+
41
+ hex_num = 255
42
+ assert_eq(f"{hex_num%x}", "ff")
43
+ assert_eq(f"{hex_num%X}", "FF")
44
+ assert_eq(f"{hex_num%#x}", "0xff")
45
+
46
+ # Test multiple format specs in one string
47
+ assert_eq(f"{num%05d} and {pi%.2f}", "00042 and 3.14")
48
+
49
+ # Test format spec with expressions
50
+ assert_eq(f"{1 + 1%d}", "2")
51
+ assert_eq(f"{(10 * 5)%03d}", "050")
@@ -57,11 +57,14 @@ test_all = () =>
57
57
  assert_eq([].all(x => x > 0), True)
58
58
  assert_eq([True, True, True].all(x => x), True)
59
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)
60
+ test_tally = () =>
61
+ # tally() works on Iterable trait via .iter
62
+ assert_eq([1, 2, 3, 4, 5].iter.tally(), 5)
63
+ assert_eq([].iter.tally(), 0)
64
+ assert_eq((..10).tally(), 10)
65
+ assert_eq([1, 2, 3, 4, 5].iter.tally(x => x > 2), 3)
66
+ assert_eq([1, 2, 3, 4, 5].iter.tally(x => x %% 2 == 0), 2)
67
+ assert_eq([1, 2, 3].iter.tally(x => x > 10), 0)
65
68
 
66
69
  test_take = () =>
67
70
  assert_eq([1, 2, 3, 4, 5].take(3).list(), [1, 2, 3])
@@ -104,16 +107,15 @@ test_cycle = () =>
104
107
  assert_eq([1, 2, 3].cycle().take(7).list(), [1, 2, 3, 1, 2, 3, 1])
105
108
  assert_eq([5].cycle().take(3).list(), [5, 5, 5])
106
109
 
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()), [])
110
+ test_reversed = () =>
111
+ assert_eq(list([1, 2, 3, 4, 5].reversed()), [5, 4, 3, 2, 1])
112
+ assert_eq(list([1].reversed()), [1])
113
+ assert_eq(list([].reversed()), [])
112
114
 
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(), [])
115
+ test_sorted = () =>
116
+ assert_eq([3, 1, 4, 1, 5].iter.sorted().list(), [1, 1, 3, 4, 5])
117
+ assert_eq(["c", "a", "b"].iter.sorted().list(), ["a", "b", "c"])
118
+ assert_eq([].iter.sorted().list(), [])
117
119
 
118
120
  test_join = () =>
119
121
  assert_eq(["a", "b", "c"].join(", "), "a, b, c")
@@ -970,9 +970,11 @@ impl<'src> TokenizeCtx<'src> {
970
970
  seen_quotes += 1;
971
971
 
972
972
  if seen_quotes == ending_char_count {
973
- let span = self.span_since(&marker);
973
+ // Use ending_marker for the span/slice end position, not current cursor,
974
+ // because we may have consumed some ending quotes already
975
+ let span = Span::new(marker..ending_marker);
974
976
  tokens.push(SToken::new(
975
- Token::FstrInner(self.slice_since(&marker), current_str),
977
+ Token::FstrInner(&self.input[marker..ending_marker], current_str),
976
978
  span,
977
979
  Vec::new(),
978
980
  ));
@@ -84,16 +84,20 @@ export Iterable = class(Traversable, Trait):
84
84
 
85
85
  impl()
86
86
 
87
- flat_map = (self, f) => itertools.chain.from_iterable(self.map(f))
87
+ flat_map = (self, f=None) =>
88
+ if f === None:
89
+ itertools.chain.from_iterable(self.iter)
90
+ else:
91
+ itertools.chain.from_iterable(self.iter.map(f))
88
92
 
89
- reverse = self => reversed(list(self.iter))
93
+ reversed = self => reversed(list(self.iter))
90
94
 
91
- sort = (self, key=None, reverse=False) =>
95
+ sorted = (self, key=None, reverse=False) =>
92
96
  sorted(self.iter, key=key, reverse=reverse)
93
97
 
94
98
  copy = self => itertools.tee(self.iter)
95
99
 
96
- count = (self, f=None) =>
100
+ tally = (self, f=None) =>
97
101
  let acc = 0
98
102
  if f === None:
99
103
  for _ in self:
@@ -187,7 +191,7 @@ export Iterable = class(Traversable, Trait):
187
191
  impl()
188
192
 
189
193
  join = (self, sep="") =>
190
- sep.join(self.map(str))
194
+ sep.join(self.iter.map(str))
191
195
 
192
196
  sum = self =>
193
197
  let acc = 0
@@ -1,27 +0,0 @@
1
- import util.assert_eq
2
-
3
- assert_eq(f"{1}", "1")
4
-
5
- x = 1
6
-
7
- fstr = f"x = {x+1}"
8
- assert_eq(fstr, "x = 2")
9
-
10
- fstr = f"x = {(y => y)(x)}"
11
- assert_eq(fstr, "x = 1")
12
-
13
- fstr = f"={(
14
- let a = 1
15
- let b = 2
16
- let c = 3
17
- a * b * c
18
- )}="
19
- assert_eq(fstr, "=6=")
20
-
21
- assert_eq(f"{{}}", "{}")
22
- assert_eq(f"{{{1}}}", "{1}")
23
-
24
- assert_eq(f"""
25
-
26
- {{1}}
27
- {2 * 5}""", "\n\n{1}\n10")
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes