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.
Files changed (154) hide show
  1. {koatl-0.3.14 → koatl-0.3.16}/Cargo.lock +2 -2
  2. {koatl-0.3.14 → koatl-0.3.16}/PKG-INFO +2 -1
  3. {koatl-0.3.14 → koatl-0.3.16}/koatl/Cargo.toml +2 -1
  4. {koatl-0.3.14 → koatl-0.3.16}/koatl/python/koatl/prelude/__init__.tl +14 -3
  5. {koatl-0.3.14 → koatl-0.3.16}/koatl/python/koatl/runtime/record.py +44 -5
  6. {koatl-0.3.14 → koatl-0.3.16}/koatl/python/koatl/std/iter.tl +6 -4
  7. {koatl-0.3.14 → koatl-0.3.16}/koatl/python/koatl/std/re.tl +1 -1
  8. koatl-0.3.16/koatl/tests/conftest.py +62 -0
  9. {koatl-0.3.14/koatl/tests/e2e/prelude → koatl-0.3.16/koatl/tests/e2e/base}/imports.tl +3 -3
  10. koatl-0.3.16/koatl/tests/e2e/base/imports2.tl +15 -0
  11. koatl-0.3.16/koatl/tests/fail-parse/unmatched_closing_delimiter.tl +1 -0
  12. {koatl-0.3.14 → koatl-0.3.16}/koatl/tests/test_e2e.py +1 -1
  13. koatl-0.3.16/koatl/tests/test_iterable.tl +176 -0
  14. koatl-0.3.16/koatl/tests/test_re.tl +204 -0
  15. koatl-0.3.16/koatl/tests/util/__init__.py +11 -0
  16. {koatl-0.3.14 → koatl-0.3.16}/koatl-core/src/py/ast.rs +1 -1
  17. {koatl-0.3.14 → koatl-0.3.16}/koatl-core/src/transform.rs +10 -15
  18. {koatl-0.3.14 → koatl-0.3.16}/koatl-parser/src/lexer.rs +16 -7
  19. {koatl-0.3.14 → koatl-0.3.16}/koatl-parser/src/parser.rs +24 -2
  20. {koatl-0.3.14 → koatl-0.3.16}/python/koatl/prelude/__init__.tl +14 -3
  21. {koatl-0.3.14 → koatl-0.3.16}/python/koatl/runtime/record.py +44 -5
  22. {koatl-0.3.14 → koatl-0.3.16}/python/koatl/std/iter.tl +6 -4
  23. {koatl-0.3.14 → koatl-0.3.16}/python/koatl/std/re.tl +1 -1
  24. koatl-0.3.14/koatl/tests/e2e/util/__init__.py +0 -2
  25. {koatl-0.3.14 → koatl-0.3.16}/Cargo.toml +0 -0
  26. {koatl-0.3.14 → koatl-0.3.16}/README.md +0 -0
  27. {koatl-0.3.14 → koatl-0.3.16}/koatl/.github/workflows/CI.yml +0 -0
  28. {koatl-0.3.14 → koatl-0.3.16}/koatl/.gitignore +0 -0
  29. {koatl-0.3.14 → koatl-0.3.16}/koatl/LICENSE +0 -0
  30. {koatl-0.3.14 → koatl-0.3.16}/koatl/README.md +0 -0
  31. {koatl-0.3.14 → koatl-0.3.16}/koatl/python/koatl/__init__.py +0 -0
  32. {koatl-0.3.14 → koatl-0.3.16}/koatl/python/koatl/__main__.py +0 -0
  33. {koatl-0.3.14 → koatl-0.3.16}/koatl/python/koatl/cli.py +0 -0
  34. {koatl-0.3.14 → koatl-0.3.16}/koatl/python/koatl/notebook/__init__.py +0 -0
  35. {koatl-0.3.14 → koatl-0.3.16}/koatl/python/koatl/notebook/magic.py +0 -0
  36. {koatl-0.3.14 → koatl-0.3.16}/koatl/python/koatl/runtime/__init__.py +0 -0
  37. {koatl-0.3.14 → koatl-0.3.16}/koatl/python/koatl/runtime/meta_finder.py +0 -0
  38. {koatl-0.3.14 → koatl-0.3.16}/koatl/python/koatl/runtime/vattr.py +0 -0
  39. {koatl-0.3.14 → koatl-0.3.16}/koatl/python/koatl/std/__init__.tl +0 -0
  40. {koatl-0.3.14 → koatl-0.3.16}/koatl/python/koatl/std/control/__init__.tl +0 -0
  41. {koatl-0.3.14 → koatl-0.3.16}/koatl/python/koatl/std/control/async.tl +0 -0
  42. {koatl-0.3.14 → koatl-0.3.16}/koatl/python/koatl/std/control/base.tl +0 -0
  43. {koatl-0.3.14 → koatl-0.3.16}/koatl/python/koatl/std/control/do.tl +0 -0
  44. {koatl-0.3.14 → koatl-0.3.16}/koatl/python/koatl/std/control/env.tl +0 -0
  45. {koatl-0.3.14 → koatl-0.3.16}/koatl/python/koatl/std/control/memo.tl +0 -0
  46. {koatl-0.3.14 → koatl-0.3.16}/koatl/python/koatl/std/control/result.tl +0 -0
  47. {koatl-0.3.14 → koatl-0.3.16}/koatl/python/koatl/std/data/__init__.tl +0 -0
  48. {koatl-0.3.14 → koatl-0.3.16}/koatl/python/koatl/std/data/list.tl +0 -0
  49. {koatl-0.3.14 → koatl-0.3.16}/koatl/python/koatl/std/data/record.tl +0 -0
  50. {koatl-0.3.14 → koatl-0.3.16}/koatl/python/koatl/std/ext.tl +0 -0
  51. {koatl-0.3.14 → koatl-0.3.16}/koatl/python/koatl/std/io.tl +0 -0
  52. {koatl-0.3.14 → koatl-0.3.16}/koatl/python/koatl/std/json.tl +0 -0
  53. {koatl-0.3.14 → koatl-0.3.16}/koatl/python/koatl/std/lazy_module.tl +0 -0
  54. {koatl-0.3.14 → koatl-0.3.16}/koatl/python/koatl/std/pickle.tl +0 -0
  55. {koatl-0.3.14 → koatl-0.3.16}/koatl/python/koatl/std/trait.py +0 -0
  56. {koatl-0.3.14 → koatl-0.3.16}/koatl/requirements.txt +0 -0
  57. {koatl-0.3.14 → koatl-0.3.16}/koatl/src/emit_py.rs +0 -0
  58. {koatl-0.3.14 → koatl-0.3.16}/koatl/src/lib.rs +0 -0
  59. {koatl-0.3.14 → koatl-0.3.16}/koatl/tests/e2e/base/arguments.tl +0 -0
  60. {koatl-0.3.14 → koatl-0.3.16}/koatl/tests/e2e/base/containers.tl +0 -0
  61. {koatl-0.3.14 → koatl-0.3.16}/koatl/tests/e2e/base/data.txt +0 -0
  62. {koatl-0.3.14 → koatl-0.3.16}/koatl/tests/e2e/base/decorators.tl +0 -0
  63. {koatl-0.3.14 → koatl-0.3.16}/koatl/tests/e2e/base/destructure-for-and-fn.tl +0 -0
  64. {koatl-0.3.14 → koatl-0.3.16}/koatl/tests/e2e/base/destructure.tl +0 -0
  65. {koatl-0.3.14 → koatl-0.3.16}/koatl/tests/e2e/base/escape_ident.tl +0 -0
  66. {koatl-0.3.14 → koatl-0.3.16}/koatl/tests/e2e/base/fstr.tl +0 -0
  67. {koatl-0.3.14 → koatl-0.3.16}/koatl/tests/e2e/base/functions.tl +0 -0
  68. {koatl-0.3.14 → koatl-0.3.16}/koatl/tests/e2e/base/generator.tl +0 -0
  69. {koatl-0.3.14 → koatl-0.3.16}/koatl/tests/e2e/base/if_expr.tl +0 -0
  70. {koatl-0.3.14 → koatl-0.3.16}/koatl/tests/e2e/base/loops.tl +0 -0
  71. {koatl-0.3.14 → koatl-0.3.16}/koatl/tests/e2e/base/match.tl +0 -0
  72. {koatl-0.3.14 → koatl-0.3.16}/koatl/tests/e2e/base/nary-list.tl +0 -0
  73. {koatl-0.3.14 → koatl-0.3.16}/koatl/tests/e2e/base/placeholder.tl +0 -0
  74. {koatl-0.3.14 → koatl-0.3.16}/koatl/tests/e2e/base/precedence.tl +0 -0
  75. {koatl-0.3.14 → koatl-0.3.16}/koatl/tests/e2e/base/scopes.tl +0 -0
  76. {koatl-0.3.14 → koatl-0.3.16}/koatl/tests/e2e/base/semantic_whitespace.tl +0 -0
  77. {koatl-0.3.14 → koatl-0.3.16}/koatl/tests/e2e/base/short_circuit.tl +0 -0
  78. {koatl-0.3.14 → koatl-0.3.16}/koatl/tests/e2e/base/with.tl +0 -0
  79. {koatl-0.3.14 → koatl-0.3.16}/koatl/tests/e2e/prelude/async.tl +0 -0
  80. {koatl-0.3.14 → koatl-0.3.16}/koatl/tests/e2e/prelude/aug_assign.tl +0 -0
  81. {koatl-0.3.14 → koatl-0.3.16}/koatl/tests/e2e/prelude/coal.tl +0 -0
  82. {koatl-0.3.14 → koatl-0.3.16}/koatl/tests/e2e/prelude/env.tl +0 -0
  83. {koatl-0.3.14 → koatl-0.3.16}/koatl/tests/e2e/prelude/iterables.tl +0 -0
  84. {koatl-0.3.14 → koatl-0.3.16}/koatl/tests/e2e/prelude/list.tl +0 -0
  85. {koatl-0.3.14 → koatl-0.3.16}/koatl/tests/e2e/prelude/memo.tl +0 -0
  86. {koatl-0.3.14 → koatl-0.3.16}/koatl/tests/e2e/prelude/record.tl +0 -0
  87. {koatl-0.3.14 → koatl-0.3.16}/koatl/tests/e2e/prelude/result.tl +0 -0
  88. {koatl-0.3.14 → koatl-0.3.16}/koatl/tests/e2e/prelude/slice.tl +0 -0
  89. {koatl-0.3.14 → koatl-0.3.16}/koatl/tests/e2e/prelude/try.tl +0 -0
  90. {koatl-0.3.14 → koatl-0.3.16}/koatl/tests/e2e/prelude/virtual.tl +0 -0
  91. {koatl-0.3.14/koatl/tests/e2e/util → koatl-0.3.16/koatl/tests/e2e/test_modules}/module0.tl +0 -0
  92. {koatl-0.3.14/koatl/tests/e2e/util → koatl-0.3.16/koatl/tests/e2e/test_modules}/module1.tl +0 -0
  93. {koatl-0.3.14/koatl/tests/e2e/util → koatl-0.3.16/koatl/tests/e2e/test_modules}/module2.tl +0 -0
  94. {koatl-0.3.14 → koatl-0.3.16}/koatl/tests/fail-parse/arguments_mixed_defaults.tl +0 -0
  95. {koatl-0.3.14 → koatl-0.3.16}/koatl/tests/fail-parse/arguments_multiple_kwargs.tl +0 -0
  96. {koatl-0.3.14 → koatl-0.3.16}/koatl/tests/fail-parse/arguments_multiple_kwonly_markers.tl +0 -0
  97. {koatl-0.3.14 → koatl-0.3.16}/koatl/tests/fail-parse/arguments_multiple_posonly_markers.tl +0 -0
  98. {koatl-0.3.14 → koatl-0.3.16}/koatl/tests/fail-parse/arguments_multiple_varargs.tl +0 -0
  99. {koatl-0.3.14 → koatl-0.3.16}/koatl/tests/fail-parse/arguments_posonly_after_kwonly.tl +0 -0
  100. {koatl-0.3.14 → koatl-0.3.16}/koatl/tests/fail-parse/arguments_vararg_and_kwonly_marker.tl +0 -0
  101. {koatl-0.3.14 → koatl-0.3.16}/koatl/tests/parse/arith.tl +0 -0
  102. {koatl-0.3.14 → koatl-0.3.16}/koatl/tests/parse/assign.tl +0 -0
  103. {koatl-0.3.14 → koatl-0.3.16}/koatl/tests/parse/block-comments.tl +0 -0
  104. {koatl-0.3.14 → koatl-0.3.16}/koatl/tests/parse/deco.tl +0 -0
  105. {koatl-0.3.14 → koatl-0.3.16}/koatl/tests/parse/func.tl +0 -0
  106. {koatl-0.3.14 → koatl-0.3.16}/koatl/tests/parse/matches.tl +0 -0
  107. {koatl-0.3.14 → koatl-0.3.16}/koatl/tests/parse/mutual-recursion.tl +0 -0
  108. {koatl-0.3.14 → koatl-0.3.16}/koatl/tests/parse/numbers.tl +0 -0
  109. {koatl-0.3.14 → koatl-0.3.16}/koatl/tests/parse/operators.tl +0 -0
  110. {koatl-0.3.14 → koatl-0.3.16}/koatl/tests/test_parse.py +0 -0
  111. {koatl-0.3.14 → koatl-0.3.16}/koatl/tests/test_parse_fail.py +0 -0
  112. {koatl-0.3.14 → koatl-0.3.16}/koatl-core/Cargo.toml +0 -0
  113. {koatl-0.3.14 → koatl-0.3.16}/koatl-core/src/ast.rs +0 -0
  114. {koatl-0.3.14 → koatl-0.3.16}/koatl-core/src/ast_builder.rs +0 -0
  115. {koatl-0.3.14 → koatl-0.3.16}/koatl-core/src/inference.rs +0 -0
  116. {koatl-0.3.14 → koatl-0.3.16}/koatl-core/src/lib.rs +0 -0
  117. {koatl-0.3.14 → koatl-0.3.16}/koatl-core/src/lift_cst.rs +0 -0
  118. {koatl-0.3.14 → koatl-0.3.16}/koatl-core/src/main.rs +0 -0
  119. {koatl-0.3.14 → koatl-0.3.16}/koatl-core/src/py/ast_builder.rs +0 -0
  120. {koatl-0.3.14 → koatl-0.3.16}/koatl-core/src/py/emit.rs +0 -0
  121. {koatl-0.3.14 → koatl-0.3.16}/koatl-core/src/py/mod.rs +0 -0
  122. {koatl-0.3.14 → koatl-0.3.16}/koatl-core/src/resolve_scopes.rs +0 -0
  123. {koatl-0.3.14 → koatl-0.3.16}/koatl-core/src/types.rs +0 -0
  124. {koatl-0.3.14 → koatl-0.3.16}/koatl-core/src/util.rs +0 -0
  125. {koatl-0.3.14 → koatl-0.3.16}/koatl-parser/Cargo.toml +0 -0
  126. {koatl-0.3.14 → koatl-0.3.16}/koatl-parser/src/cst.rs +0 -0
  127. {koatl-0.3.14 → koatl-0.3.16}/koatl-parser/src/lib.rs +0 -0
  128. {koatl-0.3.14 → koatl-0.3.16}/koatl-parser/src/simple_fmt.rs +0 -0
  129. {koatl-0.3.14 → koatl-0.3.16}/pyproject.toml +0 -0
  130. {koatl-0.3.14 → koatl-0.3.16}/python/koatl/__init__.py +0 -0
  131. {koatl-0.3.14 → koatl-0.3.16}/python/koatl/__main__.py +0 -0
  132. {koatl-0.3.14 → koatl-0.3.16}/python/koatl/cli.py +0 -0
  133. {koatl-0.3.14 → koatl-0.3.16}/python/koatl/notebook/__init__.py +0 -0
  134. {koatl-0.3.14 → koatl-0.3.16}/python/koatl/notebook/magic.py +0 -0
  135. {koatl-0.3.14 → koatl-0.3.16}/python/koatl/runtime/__init__.py +0 -0
  136. {koatl-0.3.14 → koatl-0.3.16}/python/koatl/runtime/meta_finder.py +0 -0
  137. {koatl-0.3.14 → koatl-0.3.16}/python/koatl/runtime/vattr.py +0 -0
  138. {koatl-0.3.14 → koatl-0.3.16}/python/koatl/std/__init__.tl +0 -0
  139. {koatl-0.3.14 → koatl-0.3.16}/python/koatl/std/control/__init__.tl +0 -0
  140. {koatl-0.3.14 → koatl-0.3.16}/python/koatl/std/control/async.tl +0 -0
  141. {koatl-0.3.14 → koatl-0.3.16}/python/koatl/std/control/base.tl +0 -0
  142. {koatl-0.3.14 → koatl-0.3.16}/python/koatl/std/control/do.tl +0 -0
  143. {koatl-0.3.14 → koatl-0.3.16}/python/koatl/std/control/env.tl +0 -0
  144. {koatl-0.3.14 → koatl-0.3.16}/python/koatl/std/control/memo.tl +0 -0
  145. {koatl-0.3.14 → koatl-0.3.16}/python/koatl/std/control/result.tl +0 -0
  146. {koatl-0.3.14 → koatl-0.3.16}/python/koatl/std/data/__init__.tl +0 -0
  147. {koatl-0.3.14 → koatl-0.3.16}/python/koatl/std/data/list.tl +0 -0
  148. {koatl-0.3.14 → koatl-0.3.16}/python/koatl/std/data/record.tl +0 -0
  149. {koatl-0.3.14 → koatl-0.3.16}/python/koatl/std/ext.tl +0 -0
  150. {koatl-0.3.14 → koatl-0.3.16}/python/koatl/std/io.tl +0 -0
  151. {koatl-0.3.14 → koatl-0.3.16}/python/koatl/std/json.tl +0 -0
  152. {koatl-0.3.14 → koatl-0.3.16}/python/koatl/std/lazy_module.tl +0 -0
  153. {koatl-0.3.14 → koatl-0.3.16}/python/koatl/std/pickle.tl +0 -0
  154. {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.14"
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.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.14
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
 
@@ -1,7 +1,8 @@
1
1
  [package]
2
2
  name = "koatl"
3
- version = "0.3.14"
3
+ version = "0.3.16"
4
4
  edition = "2021"
5
+ homepage = "https://koatl.org"
5
6
 
6
7
  [lib]
7
8
  name = "koatl"
@@ -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.property(object, "result")! self => Result(self)
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
- Extension.method(str, "match")! (regex, str) => Pattern(regex).match(str)
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
- @_property
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
- @_property
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
- sorted = (self, key=None, reverse=False) =>
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
- join_str = (self, sep="") =>
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).result.map(Match)
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 util.module0
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 util.module1
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 util.module2
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")
@@ -4,7 +4,7 @@ import os
4
4
  import koatl.cli
5
5
  from pathlib import Path
6
6
 
7
- sys.path.append(str(Path(__file__).parent / "e2e"))
7
+ sys.path.append(str(Path(__file__).parent))
8
8
  os.chdir(Path(__file__).parent / "e2e")
9
9
 
10
10
 
@@ -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})