koatl 0.1.12__tar.gz → 0.1.14__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 (110) hide show
  1. {koatl-0.1.12 → koatl-0.1.14}/Cargo.lock +1 -1
  2. {koatl-0.1.12 → koatl-0.1.14}/PKG-INFO +1 -1
  3. {koatl-0.1.12 → koatl-0.1.14}/koatl/Cargo.toml +1 -1
  4. {koatl-0.1.12 → koatl-0.1.14/koatl}/python/koatl/cli.py +2 -2
  5. {koatl-0.1.12 → koatl-0.1.14/koatl}/python/koatl/prelude/functional/__init__.tl +3 -2
  6. koatl-0.1.14/koatl/python/koatl/prelude/functional/async.tl +42 -0
  7. koatl-0.1.14/koatl/python/koatl/prelude/functional/monad.tl +12 -0
  8. koatl-0.1.14/koatl/python/koatl/prelude/functional/reader.tl +33 -0
  9. koatl-0.1.14/koatl/python/koatl/prelude/functional/result.tl +80 -0
  10. {koatl-0.1.12 → koatl-0.1.14/koatl}/python/koatl/runtime/__init__.py +2 -1
  11. {koatl-0.1.12 → koatl-0.1.14/koatl}/python/koatl/runtime/helpers.py +8 -4
  12. {koatl-0.1.12 → koatl-0.1.14}/koatl/python/koatl/runtime/meta_finder.py +6 -2
  13. {koatl-0.1.12 → koatl-0.1.14/koatl}/python/koatl/runtime/virtual.py +27 -0
  14. {koatl-0.1.12 → koatl-0.1.14}/koatl/tests/e2e/base/coal.tl +3 -3
  15. koatl-0.1.14/koatl/tests/e2e/base/placeholder.tl +37 -0
  16. koatl-0.1.12/koatl/tests/e2e/prelude/ok.tl → koatl-0.1.14/koatl/tests/e2e/prelude/result.tl +11 -1
  17. koatl-0.1.14/koatl/tests/parse/deco.tl +2 -0
  18. {koatl-0.1.12 → koatl-0.1.14}/koatl-core/parser/src/ast.rs +5 -5
  19. {koatl-0.1.12 → koatl-0.1.14}/koatl-core/parser/src/parser.rs +41 -38
  20. {koatl-0.1.12 → koatl-0.1.14}/koatl-core/parser/src/util.rs +2 -2
  21. {koatl-0.1.12 → koatl-0.1.14}/koatl-core/src/transform.rs +187 -199
  22. {koatl-0.1.12/koatl → koatl-0.1.14}/python/koatl/cli.py +2 -2
  23. {koatl-0.1.12/koatl → koatl-0.1.14}/python/koatl/prelude/functional/__init__.tl +3 -2
  24. koatl-0.1.14/python/koatl/prelude/functional/async.tl +42 -0
  25. koatl-0.1.14/python/koatl/prelude/functional/monad.tl +12 -0
  26. koatl-0.1.14/python/koatl/prelude/functional/reader.tl +33 -0
  27. koatl-0.1.14/python/koatl/prelude/functional/result.tl +80 -0
  28. {koatl-0.1.12/koatl → koatl-0.1.14}/python/koatl/runtime/__init__.py +2 -1
  29. {koatl-0.1.12/koatl → koatl-0.1.14}/python/koatl/runtime/helpers.py +8 -4
  30. {koatl-0.1.12 → koatl-0.1.14}/python/koatl/runtime/meta_finder.py +6 -2
  31. {koatl-0.1.12/koatl → koatl-0.1.14}/python/koatl/runtime/virtual.py +27 -0
  32. koatl-0.1.12/koatl/python/koatl/prelude/functional/async.tl +0 -38
  33. koatl-0.1.12/koatl/python/koatl/prelude/functional/ok.tl +0 -51
  34. koatl-0.1.12/koatl/python/koatl/prelude/functional/reader.tl +0 -24
  35. koatl-0.1.12/koatl/tests/e2e/base/placeholder.tl +0 -23
  36. koatl-0.1.12/koatl/tests/parse/deco.tl +0 -2
  37. koatl-0.1.12/python/koatl/prelude/functional/async.tl +0 -38
  38. koatl-0.1.12/python/koatl/prelude/functional/ok.tl +0 -51
  39. koatl-0.1.12/python/koatl/prelude/functional/reader.tl +0 -24
  40. {koatl-0.1.12 → koatl-0.1.14}/Cargo.toml +0 -0
  41. {koatl-0.1.12 → koatl-0.1.14}/README.md +0 -0
  42. {koatl-0.1.12 → koatl-0.1.14}/koatl/.github/workflows/CI.yml +0 -0
  43. {koatl-0.1.12 → koatl-0.1.14}/koatl/.gitignore +0 -0
  44. {koatl-0.1.12 → koatl-0.1.14}/koatl/LICENSE +0 -0
  45. {koatl-0.1.12 → koatl-0.1.14}/koatl/README.md +0 -0
  46. {koatl-0.1.12 → koatl-0.1.14}/koatl/python/koatl/__init__.py +0 -0
  47. {koatl-0.1.12 → koatl-0.1.14}/koatl/python/koatl/__main__.py +0 -0
  48. {koatl-0.1.12 → koatl-0.1.14}/koatl/python/koatl/notebook/__init__.py +0 -0
  49. {koatl-0.1.12 → koatl-0.1.14}/koatl/python/koatl/notebook/magic.py +0 -0
  50. {koatl-0.1.12 → koatl-0.1.14}/koatl/python/koatl/prelude/__init__.tl +0 -0
  51. {koatl-0.1.12 → koatl-0.1.14}/koatl/python/koatl/prelude/functional/async_util.py +0 -0
  52. {koatl-0.1.12 → koatl-0.1.14}/koatl/python/koatl/prelude/iterable.tl +0 -0
  53. {koatl-0.1.12 → koatl-0.1.14}/koatl/python/koatl/runtime/record.py +0 -0
  54. {koatl-0.1.12 → koatl-0.1.14}/koatl/requirements.txt +0 -0
  55. {koatl-0.1.12 → koatl-0.1.14}/koatl/src/emit_py.rs +0 -0
  56. {koatl-0.1.12 → koatl-0.1.14}/koatl/src/lib.rs +0 -0
  57. {koatl-0.1.12 → koatl-0.1.14}/koatl/tests/e2e/base/containers.tl +0 -0
  58. {koatl-0.1.12 → koatl-0.1.14}/koatl/tests/e2e/base/decorators.tl +0 -0
  59. {koatl-0.1.12 → koatl-0.1.14}/koatl/tests/e2e/base/destructure-for-and-fn.tl +0 -0
  60. {koatl-0.1.12 → koatl-0.1.14}/koatl/tests/e2e/base/destructure.tl +0 -0
  61. {koatl-0.1.12 → koatl-0.1.14}/koatl/tests/e2e/base/escape_ident.tl +0 -0
  62. {koatl-0.1.12 → koatl-0.1.14}/koatl/tests/e2e/base/fstr.tl +0 -0
  63. {koatl-0.1.12 → koatl-0.1.14}/koatl/tests/e2e/base/functions.tl +0 -0
  64. {koatl-0.1.12 → koatl-0.1.14}/koatl/tests/e2e/base/generator.tl +0 -0
  65. {koatl-0.1.12 → koatl-0.1.14}/koatl/tests/e2e/base/if_expr.tl +0 -0
  66. {koatl-0.1.12 → koatl-0.1.14}/koatl/tests/e2e/base/imports.tl +0 -0
  67. {koatl-0.1.12 → koatl-0.1.14}/koatl/tests/e2e/base/iterables.tl +0 -0
  68. {koatl-0.1.12 → koatl-0.1.14}/koatl/tests/e2e/base/loops.tl +0 -0
  69. {koatl-0.1.12 → koatl-0.1.14}/koatl/tests/e2e/base/match.tl +0 -0
  70. {koatl-0.1.12 → koatl-0.1.14}/koatl/tests/e2e/base/nary-list.tl +0 -0
  71. {koatl-0.1.12 → koatl-0.1.14}/koatl/tests/e2e/base/precedence.tl +0 -0
  72. {koatl-0.1.12 → koatl-0.1.14}/koatl/tests/e2e/base/semantic_whitespace.tl +0 -0
  73. {koatl-0.1.12 → koatl-0.1.14}/koatl/tests/e2e/base/slice.tl +0 -0
  74. {koatl-0.1.12 → koatl-0.1.14}/koatl/tests/e2e/base/try.tl +0 -0
  75. {koatl-0.1.12 → koatl-0.1.14}/koatl/tests/e2e/destructure.tl +0 -0
  76. {koatl-0.1.12 → koatl-0.1.14}/koatl/tests/e2e/prelude/async.tl +0 -0
  77. {koatl-0.1.12 → koatl-0.1.14}/koatl/tests/e2e/prelude/reader.tl +0 -0
  78. {koatl-0.1.12 → koatl-0.1.14}/koatl/tests/e2e/prelude/virtual.tl +0 -0
  79. {koatl-0.1.12 → koatl-0.1.14}/koatl/tests/e2e/util/__init__.py +0 -0
  80. {koatl-0.1.12 → koatl-0.1.14}/koatl/tests/e2e/util/module0.tl +0 -0
  81. {koatl-0.1.12 → koatl-0.1.14}/koatl/tests/e2e/util/module1.tl +0 -0
  82. {koatl-0.1.12 → koatl-0.1.14}/koatl/tests/e2e/util/module2.tl +0 -0
  83. {koatl-0.1.12 → koatl-0.1.14}/koatl/tests/parse/arith.tl +0 -0
  84. {koatl-0.1.12 → koatl-0.1.14}/koatl/tests/parse/assign.tl +0 -0
  85. {koatl-0.1.12 → koatl-0.1.14}/koatl/tests/parse/func.tl +0 -0
  86. {koatl-0.1.12 → koatl-0.1.14}/koatl/tests/parse/matches.tl +0 -0
  87. {koatl-0.1.12 → koatl-0.1.14}/koatl/tests/test_e2e.py +0 -0
  88. {koatl-0.1.12 → koatl-0.1.14}/koatl/tests/test_parse.py +0 -0
  89. {koatl-0.1.12 → koatl-0.1.14}/koatl-core/Cargo.toml +0 -0
  90. {koatl-0.1.12 → koatl-0.1.14}/koatl-core/parser/Cargo.toml +0 -0
  91. {koatl-0.1.12 → koatl-0.1.14}/koatl-core/parser/src/lexer.rs +0 -0
  92. {koatl-0.1.12 → koatl-0.1.14}/koatl-core/parser/src/lib.rs +0 -0
  93. {koatl-0.1.12 → koatl-0.1.14}/koatl-core/parser/tests/lexer.rs +0 -0
  94. {koatl-0.1.12 → koatl-0.1.14}/koatl-core/src/lib.rs +0 -0
  95. {koatl-0.1.12 → koatl-0.1.14}/koatl-core/src/linecol.rs +0 -0
  96. {koatl-0.1.12 → koatl-0.1.14}/koatl-core/src/main.rs +0 -0
  97. {koatl-0.1.12 → koatl-0.1.14}/koatl-core/src/parser.rs +0 -0
  98. {koatl-0.1.12 → koatl-0.1.14}/koatl-core/src/py/ast.rs +0 -0
  99. {koatl-0.1.12 → koatl-0.1.14}/koatl-core/src/py/emit.rs +0 -0
  100. {koatl-0.1.12 → koatl-0.1.14}/koatl-core/src/py/mod.rs +0 -0
  101. {koatl-0.1.12 → koatl-0.1.14}/koatl-core/src/py/util.rs +0 -0
  102. {koatl-0.1.12 → koatl-0.1.14}/pyproject.toml +0 -0
  103. {koatl-0.1.12 → koatl-0.1.14}/python/koatl/__init__.py +0 -0
  104. {koatl-0.1.12 → koatl-0.1.14}/python/koatl/__main__.py +0 -0
  105. {koatl-0.1.12 → koatl-0.1.14}/python/koatl/notebook/__init__.py +0 -0
  106. {koatl-0.1.12 → koatl-0.1.14}/python/koatl/notebook/magic.py +0 -0
  107. {koatl-0.1.12 → koatl-0.1.14}/python/koatl/prelude/__init__.tl +0 -0
  108. {koatl-0.1.12 → koatl-0.1.14}/python/koatl/prelude/functional/async_util.py +0 -0
  109. {koatl-0.1.12 → koatl-0.1.14}/python/koatl/prelude/iterable.tl +0 -0
  110. {koatl-0.1.12 → koatl-0.1.14}/python/koatl/runtime/record.py +0 -0
@@ -99,7 +99,7 @@ checksum = "f4c7245a08504955605670dbf141fceab975f15ca21570696aebe9d2e71576bd"
99
99
 
100
100
  [[package]]
101
101
  name = "koatl"
102
- version = "0.1.12"
102
+ version = "0.1.14"
103
103
  dependencies = [
104
104
  "ariadne",
105
105
  "koatl-core",
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: koatl
3
- Version: 0.1.12
3
+ Version: 0.1.14
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.1.12"
3
+ version = "0.1.14"
4
4
  edition = "2021"
5
5
 
6
6
  [lib]
@@ -2,7 +2,7 @@ def transpile_from_source(source, mode="script", script_path="<string>"):
2
2
  from koatl import transpile
3
3
  import ast
4
4
 
5
- transpiled_code = transpile(source, mode=mode)
5
+ transpiled_code = transpile(source, mode=mode, filename=str(script_path))
6
6
 
7
7
  return ast.unparse(transpiled_code)
8
8
 
@@ -10,7 +10,7 @@ def transpile_from_source(source, mode="script", script_path="<string>"):
10
10
  def run_from_source(source, mode="script", script_path="<string>"):
11
11
  from koatl import transpile
12
12
 
13
- transpiled_code = transpile(source, mode=mode)
13
+ transpiled_code = transpile(source, mode=mode, filename=str(script_path))
14
14
  code_obj = compile(transpiled_code, script_path, "exec")
15
15
 
16
16
  script_globals = {"__name__": "__main__"}
@@ -1,9 +1,10 @@
1
- export import .ok.*
1
+ export import .monad.*
2
+ export import .result.*
2
3
  export import .async.*
3
4
  export import .reader.*
4
5
 
5
6
  export Fn = class:
6
- compose = &[staticmethod] (*args) =>
7
+ compose = staticmethod& (*args) =>
7
8
  args match:
8
9
  [] => raise ValueError("At least one function is required for composition")
9
10
  [f] => f
@@ -0,0 +1,42 @@
1
+ import functools.wraps
2
+ import asyncio
3
+ import .async_util
4
+
5
+ export Async = class:
6
+ __init__ = (self, awaitable) => self.generator = awaitable.__await__()
7
+
8
+ __await__ = self => self.generator
9
+
10
+ __repr__ = self => "Async(...)"
11
+
12
+ from_generator_fn = staticmethod& (generator_fn, *args, **kwargs) =>
13
+ m = object.__new__(Async)
14
+ m.generator = generator_fn(*args, **kwargs)
15
+ return m
16
+
17
+ run = self => asyncio.run(async_util.to_coro(self))
18
+
19
+ bind_once = (self, f) => Async.from_generator_fn& () =>
20
+ result = f(yield from self.__await__())
21
+
22
+ if hasattr(result, "__await__"):
23
+ return yield from result.__await__()
24
+
25
+ return result
26
+
27
+ bind_gen = (self, gen) => Async.from_generator_fn& () =>
28
+ nonlocal self = self
29
+ try:
30
+ while True:
31
+ self = gen.send(yield from self.__await__())
32
+ except StopIteration(value=value):
33
+ return value
34
+
35
+ pure = staticmethod& x => Async.from_generator_fn& () =>
36
+ return x
37
+ yield None
38
+
39
+ sleep = staticmethod& x => Async(asyncio.sleep(x))
40
+
41
+ #- TODO: Why is asyncio.gather eager? -#
42
+ gather = staticmethod& (*args) => Async.from_generator_fn& () => yield from asyncio.gather(*args)
@@ -0,0 +1,12 @@
1
+ import abc
2
+
3
+ export Monad = class(abc.ABC):
4
+ bind = (self, f) => self.bind_once(f)
5
+
6
+ # An optional, optimized implementation of `bind` that skips deep recursion.
7
+ bind_gen = (self, gen) => raise NotImplementedError()
8
+
9
+ # The default implementation required for `@` syntax that should be overridden by subclasses.
10
+ bind_once = abc.abstractmethod& (self, f) => None
11
+
12
+ pure = staticmethod& abc.abstractmethod& value => None
@@ -0,0 +1,33 @@
1
+ import functools.wraps
2
+
3
+ export Reader = class:
4
+ __init__ = (self, fn) => self.fn = fn
5
+
6
+ __repr__ = self => "Reader(...)"
7
+
8
+ run = (self, ctx) => self.fn(ctx)
9
+
10
+ bind_once = (self, f) => Reader& ctx =>
11
+ v = f(self.fn(ctx))
12
+ if v matches Reader():
13
+ v.fn(ctx)
14
+ else:
15
+ v
16
+
17
+ # TODO: this is a workaround to avoid recursion.
18
+ # how to get bind_gen directly from bind_once?
19
+ bind_gen = (self, gen) => Reader& ctx =>
20
+ nonlocal self = self
21
+ try:
22
+ while True:
23
+ self = gen.send(self.fn(ctx))
24
+ except StopIteration(value=value):
25
+ return value
26
+
27
+ NoKey = object()
28
+
29
+ ask = staticmethod& (key=NoKey) => Reader(
30
+ key === Reader.NoKey then ctx => ctx else ctx => ctx[key]
31
+ )
32
+
33
+ pure = staticmethod& value => Reader(ctx => value)
@@ -0,0 +1,80 @@
1
+ import functools.wraps
2
+ import .monad.Monad
3
+ import koatl.runtime.virtual.register_global_attr
4
+
5
+ export Result = class(Monad):
6
+ bind_once = (self, f) => self match:
7
+ Ok(value) => f(value)
8
+ Ok() => f(self)
9
+ default => self
10
+
11
+ bind_gen = (self, gen) =>
12
+ try:
13
+ while True:
14
+ if not __tl__.ok(self):
15
+ return self
16
+
17
+ if self matches Ok(value):
18
+ self = value
19
+
20
+ self = gen.send(self)
21
+ except StopIteration(value=value):
22
+ if value === None:
23
+ return Ok(None)
24
+ return value
25
+
26
+ map_err = (self, f) =>
27
+ if self matches Err():
28
+ return f(self)
29
+ else:
30
+ return self
31
+
32
+ OkMeta = class(type):
33
+ __instancecheck__ = (cls, instance) => __tl__.ok(instance)
34
+
35
+ export Ok = class(metaclass=OkMeta):
36
+ __match_args__ = ("value",)
37
+
38
+ __init__ = (self, value) =>
39
+ self.value = value
40
+
41
+ # Since we are using a custom metaclass, we can't derive from Result
42
+ # so need to copy the methods over manually from Result
43
+
44
+ # We could just use the object fallback methods, but this avoids
45
+ # the manual __tl__.vget
46
+ bind_once = Result.bind_once
47
+ bind_gen = Result.bind_gen
48
+ map_err = Result.map_err
49
+
50
+ assert = staticmethod& value =>
51
+ value match:
52
+ BaseException() as e => raise e
53
+ None => raise ValueError("Expected a value, got None")
54
+ default value
55
+
56
+ export Err = BaseException
57
+
58
+ register_global_attr(
59
+ object,
60
+ "map_err",
61
+ Result.map_err
62
+ )
63
+
64
+ register_global_attr(
65
+ object,
66
+ "bind",
67
+ Result.bind_once
68
+ )
69
+
70
+ register_global_attr(
71
+ object,
72
+ "bind_once",
73
+ Result.bind_once
74
+ )
75
+
76
+ register_global_attr(
77
+ object,
78
+ "bind_gen",
79
+ Result.bind_gen
80
+ )
@@ -22,10 +22,11 @@ from .helpers import *
22
22
 
23
23
 
24
24
  __tl__ = SimpleNamespace(
25
+ vget=virtual.vget,
26
+ vhas=virtual.vhas,
25
27
  unpack_record=helpers.unpack_record,
26
28
  set_exports=helpers.set_exports,
27
29
  do=helpers.do,
28
- vget=helpers.vget,
29
30
  ok=helpers.ok,
30
31
  partial=functools.partial,
31
32
  **{name: helpers.__dict__[name] for name in helpers.__all__},
@@ -56,17 +56,17 @@ def ok(obj):
56
56
  def do(f):
57
57
  @wraps(f)
58
58
  def impl(*args, **kwargs):
59
- coro = f(*args, **kwargs)
59
+ gen = f(*args, **kwargs)
60
60
 
61
61
  try:
62
- m = coro.send(None)
62
+ m = gen.send(None)
63
63
  except StopIteration as e:
64
64
  return e.value
65
65
 
66
66
  def recurse(v):
67
67
  nonlocal m
68
68
  try:
69
- m = coro.send(v)
69
+ m = gen.send(v)
70
70
  return vget(m, "bind_once")(recurse)
71
71
  except StopIteration as e:
72
72
  try:
@@ -74,6 +74,10 @@ def do(f):
74
74
  except AttributeError:
75
75
  return e.value
76
76
 
77
- return vget(m, "bind_once")(recurse)
77
+ try:
78
+ print(m, gen)
79
+ return vget(m, "bind_gen")(gen)
80
+ except (NotImplementedError, AttributeError):
81
+ return vget(m, "bind_once")(recurse)
78
82
 
79
83
  return impl
@@ -53,9 +53,13 @@ class TlLoader(Loader):
53
53
  )
54
54
 
55
55
  if module.__name__.startswith("koatl.prelude"):
56
- transpiled_code = transpile(source_code, mode="prelude")
56
+ transpiled_code = transpile(
57
+ source_code, mode="prelude", filename=self.filepath
58
+ )
57
59
  else:
58
- transpiled_code = transpile(source_code, mode="module")
60
+ transpiled_code = transpile(
61
+ source_code, mode="module", filename=self.filepath
62
+ )
59
63
 
60
64
  code = compile(transpiled_code, self.filepath, "exec")
61
65
 
@@ -46,6 +46,33 @@ def vget(obj, name):
46
46
  ) from None
47
47
 
48
48
 
49
+ def vhas(obj, name):
50
+ if hasattr(obj, name):
51
+ return True
52
+
53
+ if name == "iter":
54
+ if isinstance(obj, slice):
55
+ return True
56
+
57
+ try:
58
+ obj.items()
59
+ return True
60
+ except AttributeError:
61
+ pass
62
+
63
+ try:
64
+ iter(obj)
65
+ return True
66
+ except TypeError:
67
+ pass
68
+
69
+ v = fast_vget(obj, name)
70
+ if v is not None:
71
+ return True
72
+
73
+ return False
74
+
75
+
49
76
  def Trait(module, name, methods, *, requires=[]):
50
77
  def fix_methods(type_name, methods):
51
78
  import inspect
@@ -12,7 +12,7 @@ obj = (class:
12
12
  assert_eq((x => x)?(1), 1)
13
13
  assert_eq([1]?[0], 1)
14
14
  assert_eq(obj?.a, 1)
15
- assert_eq(1?.($ + 1), 2)
15
+ assert_eq(1?.($ + 1)(), 2)
16
16
 
17
17
  assert_eq(None ?? 1, 1)
18
18
  assert_eq(int(5) ?? 1, 5)
@@ -26,5 +26,5 @@ assert_eq(type(try [0][5]), IndexError)
26
26
  assert_eq(try 5, 5)
27
27
 
28
28
 
29
- assert_eq((try 5)?.($+1), 6)
30
- assert_eq(type((try x)?.($+1)), NameError)
29
+ assert_eq((try 5)?.($+1)?(), 6)
30
+ assert_eq(type((try x)?.($+1)?()), NameError)
@@ -0,0 +1,37 @@
1
+ import util.assert_eq
2
+
3
+ # basic usage
4
+
5
+ call_with_five = f => f(5)
6
+
7
+ assert_eq(call_with_five($ + 1), 6)
8
+
9
+ res = call_with_five($)
10
+ assert_eq(callable(res), True)
11
+
12
+ assert_eq(callable([1, 2, $]), True)
13
+
14
+
15
+ # weird cases
16
+
17
+ assert_eq((x => x)($ + 1)(1), 2)
18
+
19
+ assert_eq(1
20
+ | $ + 1
21
+ | $ * 2
22
+ | $ * 5, 20)
23
+
24
+ f = $ + 1
25
+
26
+ assert_eq(f(2), 3)
27
+
28
+ f = x => x * 2
29
+ g = f($)
30
+
31
+ assert_eq(g(3), 6)
32
+
33
+ assert_eq(3 | f($), 6)
34
+
35
+ assert_eq(3 | [$, 2, 3], [3, 2, 3])
36
+ f = [$, 2, 3]
37
+ assert_eq(f(3), [3, 2, 3])
@@ -16,4 +16,14 @@ fn = () =>
16
16
  v.append(@321)
17
17
  fn()
18
18
 
19
- assert_eq(v, [123, 222, 321])
19
+ assert_eq(v, [123, 222, 321])
20
+
21
+ v = []
22
+ fn = () =>
23
+ v.append(@123)
24
+ v.append(@Ok(None))
25
+ v.append(@ValueError())
26
+ v.append(@321)
27
+ fn()
28
+
29
+ assert_eq(v, [123, None])
@@ -0,0 +1,2 @@
1
+ wraps(f)& x => x
2
+ y = wraps(f)& x => x
@@ -174,22 +174,22 @@ pub enum Expr<'a> {
174
174
 
175
175
  Call(Box<SExpr<'a>>, Vec<SCallItem<'a>>),
176
176
  Subscript(Box<SExpr<'a>>, Vec<ListItem<'a>>),
177
+ RawAttribute(Box<SExpr<'a>>, SIdent<'a>),
178
+ ScopedAttribute(Box<SExpr<'a>>, Box<SExpr<'a>>),
177
179
  Attribute(Box<SExpr<'a>>, SIdent<'a>),
178
- ScopedExtension(Box<SExpr<'a>>, Box<SExpr<'a>>),
179
- Extension(Box<SExpr<'a>>, SIdent<'a>),
180
180
 
181
181
  MappedCall(Box<SExpr<'a>>, Vec<SCallItem<'a>>),
182
182
  MappedSubscript(Box<SExpr<'a>>, Vec<ListItem<'a>>),
183
+ MappedRawAttribute(Box<SExpr<'a>>, SIdent<'a>),
184
+ MappedScopedAttribute(Box<SExpr<'a>>, Box<SExpr<'a>>),
183
185
  MappedAttribute(Box<SExpr<'a>>, SIdent<'a>),
184
- MappedThen(Box<SExpr<'a>>, Box<SExpr<'a>>),
185
- MappedExtension(Box<SExpr<'a>>, SIdent<'a>),
186
186
 
187
187
  Checked(Box<SExpr<'a>>, Option<Box<SPattern<'a>>>),
188
188
 
189
189
  Fn(Vec<ArgDefItem<'a>>, Box<SExpr<'a>>),
190
190
  Fstr(Spanned<String>, Vec<(SFmtExpr<'a>, Spanned<String>)>),
191
191
 
192
- Decorated(Vec<SExpr<'a>>, Box<SExpr<'a>>),
192
+ Decorated(Box<SExpr<'a>>, Box<SExpr<'a>>),
193
193
 
194
194
  Block(Vec<SStmt<'a>>),
195
195
  }
@@ -121,7 +121,7 @@ where
121
121
  .or_not()
122
122
  .then(qualified_ident.clone())
123
123
  .try_map(|(q, value), _e| {
124
- Ok(if let Expr::Attribute(..) = value.0 {
124
+ Ok(if let Expr::RawAttribute(..) = value.0 {
125
125
  Pattern::Value(value)
126
126
  } else if q.is_some() {
127
127
  Pattern::Value(value)
@@ -588,7 +588,7 @@ where
588
588
  .clone()
589
589
  .foldl_with(
590
590
  symbol(".").ignore_then(ident.clone()).repeated(),
591
- |lhs, rhs, e| (Expr::Attribute(Box::new(lhs), rhs), e.span()),
591
+ |lhs, rhs, e| (Expr::RawAttribute(Box::new(lhs), rhs), e.span()),
592
592
  )
593
593
  .boxed();
594
594
 
@@ -620,19 +620,6 @@ where
620
620
  ))
621
621
  .boxed();
622
622
 
623
- let deco_list = enumeration(expr.clone(), symbol(","))
624
- .delimited_by_with_eol(just(Token::Symbol("[")), just(Token::Symbol("]")))
625
- .labelled("decorators")
626
- .boxed();
627
-
628
- let decorators = symbol("&").ignore_then(deco_list.clone());
629
-
630
- let decorated = decorators
631
- .then(below_pipe.clone())
632
- .map(|(decorators, expr)| Expr::Decorated(decorators, Box::new(expr)))
633
- .spanned()
634
- .labelled("fn");
635
-
636
623
  enum ControlKw {
637
624
  Await,
638
625
  Yield,
@@ -665,7 +652,6 @@ where
665
652
 
666
653
  atom.define(
667
654
  choice((
668
- decorated,
669
655
  ident_expr.clone(),
670
656
  classic_if,
671
657
  classic_match,
@@ -687,10 +673,10 @@ where
687
673
  enum Postfix<'a> {
688
674
  Call(Vec<SCallItem<'a>>),
689
675
  Subscript(Vec<ListItem<'a>>),
690
- Extension(SIdent<'a>),
691
- Then(SExpr<'a>),
692
- ThenCall(SExpr<'a>, Vec<SCallItem<'a>>),
693
676
  Attribute(SIdent<'a>),
677
+ ScopedAttribute(SExpr<'a>),
678
+ ScopedAttributeCall(SExpr<'a>, Vec<SCallItem<'a>>),
679
+ RawAttribute(SIdent<'a>),
694
680
  }
695
681
 
696
682
  let call_args = enumeration(
@@ -735,7 +721,7 @@ where
735
721
 
736
722
  let attribute = symbol(".")
737
723
  .ignore_then(ident.clone())
738
- .map(Postfix::Extension)
724
+ .map(Postfix::Attribute)
739
725
  .labelled("extension-attribute");
740
726
 
741
727
  let then = symbol(".")
@@ -743,18 +729,18 @@ where
743
729
  .then(call_args.or_not())
744
730
  .map(|(rhs, args)| {
745
731
  if let Some(args) = args {
746
- Postfix::ThenCall(rhs, args)
732
+ Postfix::ScopedAttributeCall(rhs, args)
747
733
  } else {
748
- Postfix::Then(rhs)
734
+ Postfix::ScopedAttribute(rhs)
749
735
  }
750
736
  })
751
737
  .labelled("then-attribute")
752
738
  .boxed();
753
739
 
754
- let extension = symbol("!")
740
+ let raw_attr = symbol("!")
755
741
  .ignore_then(ident.clone())
756
- .map(Postfix::Attribute)
757
- .labelled("native-attribute")
742
+ .map(Postfix::RawAttribute)
743
+ .labelled("raw-attribute")
758
744
  .boxed();
759
745
 
760
746
  let postfix = atom
@@ -763,7 +749,7 @@ where
763
749
  symbol("?")
764
750
  .to(1)
765
751
  .or_not()
766
- .then(choice((call, subscript, attribute, then, extension)))
752
+ .then(choice((call, subscript, attribute, then, raw_attr)))
767
753
  .repeated(),
768
754
  |expr, (coal, op), e| -> SExpr {
769
755
  (
@@ -771,34 +757,38 @@ where
771
757
  match op {
772
758
  Postfix::Call(args) => Expr::Call(Box::new(expr), args),
773
759
  Postfix::Subscript(args) => Expr::Subscript(Box::new(expr), args),
774
- Postfix::Attribute(attr) => Expr::Attribute(Box::new(expr), attr),
775
- Postfix::Then(rhs) => {
776
- Expr::ScopedExtension(Box::new(expr), Box::new(rhs))
760
+ Postfix::RawAttribute(attr) => Expr::RawAttribute(Box::new(expr), attr),
761
+ Postfix::ScopedAttribute(rhs) => {
762
+ Expr::ScopedAttribute(Box::new(expr), Box::new(rhs))
777
763
  }
778
- Postfix::ThenCall(rhs, args) => Expr::Call(
764
+ Postfix::ScopedAttributeCall(rhs, args) => Expr::Call(
779
765
  // TODO optimize this case in the AST by skipping partial application
780
766
  Box::new((
781
- Expr::ScopedExtension(Box::new(expr), Box::new(rhs)),
767
+ Expr::ScopedAttribute(Box::new(expr), Box::new(rhs)),
782
768
  e.span(),
783
769
  )),
784
770
  args,
785
771
  ),
786
- Postfix::Extension(rhs) => Expr::Extension(Box::new(expr), rhs),
772
+ Postfix::Attribute(rhs) => Expr::Attribute(Box::new(expr), rhs),
787
773
  }
788
774
  } else {
789
775
  match op {
790
776
  Postfix::Call(args) => Expr::MappedCall(Box::new(expr), args),
791
777
  Postfix::Subscript(args) => Expr::MappedSubscript(Box::new(expr), args),
792
- Postfix::Attribute(attr) => Expr::MappedAttribute(Box::new(expr), attr),
793
- Postfix::Then(rhs) => Expr::MappedThen(Box::new(expr), Box::new(rhs)),
794
- Postfix::ThenCall(rhs, args) => Expr::Call(
778
+ Postfix::RawAttribute(attr) => {
779
+ Expr::MappedRawAttribute(Box::new(expr), attr)
780
+ }
781
+ Postfix::ScopedAttribute(rhs) => {
782
+ Expr::MappedScopedAttribute(Box::new(expr), Box::new(rhs))
783
+ }
784
+ Postfix::ScopedAttributeCall(rhs, args) => Expr::Call(
795
785
  Box::new((
796
- Expr::MappedThen(Box::new(expr), Box::new(rhs)),
786
+ Expr::MappedScopedAttribute(Box::new(expr), Box::new(rhs)),
797
787
  e.span(),
798
788
  )),
799
789
  args,
800
790
  ),
801
- Postfix::Extension(rhs) => Expr::MappedExtension(Box::new(expr), rhs),
791
+ Postfix::Attribute(rhs) => Expr::MappedAttribute(Box::new(expr), rhs),
802
792
  }
803
793
  },
804
794
  e.span(),
@@ -808,6 +798,19 @@ where
808
798
  .labelled("postfix")
809
799
  .boxed();
810
800
 
801
+ let decorator = postfix
802
+ .clone()
803
+ .then(symbol("&").ignore_then(expr.clone()).or_not())
804
+ .map_with(|(lhs, rhs), e| {
805
+ if let Some(rhs) = rhs {
806
+ (Expr::Decorated(Box::new(lhs), Box::new(rhs)), e.span())
807
+ } else {
808
+ lhs
809
+ }
810
+ })
811
+ .labelled("decorator")
812
+ .boxed();
813
+
811
814
  let mut checked = Recursive::<Indirect<TInput, SExpr, TExtra>>::declare();
812
815
 
813
816
  unary.define(
@@ -819,7 +822,7 @@ where
819
822
  }
820
823
  .repeated()
821
824
  .foldr_with(
822
- choice((postfix, checked.clone())),
825
+ choice((decorator, checked.clone())),
823
826
  |op: UnaryOp, rhs: SExpr, e| (Expr::Unary(op, Box::new(rhs)), e.span()),
824
827
  )
825
828
  .labelled("unary-expression")
@@ -147,14 +147,14 @@ impl AstBuilder {
147
147
  attr: impl Into<Cow<'src, str>>,
148
148
  ) -> SExpr<'src> {
149
149
  (
150
- Expr::Attribute(Box::new(value), (attr.into(), self.span)),
150
+ Expr::RawAttribute(Box::new(value), (attr.into(), self.span)),
151
151
  self.span,
152
152
  )
153
153
  }
154
154
 
155
155
  pub fn then<'src>(&self, left: SExpr<'src>, right: SExpr<'src>) -> SExpr<'src> {
156
156
  (
157
- Expr::ScopedExtension(Box::new(left), Box::new(right)),
157
+ Expr::ScopedAttribute(Box::new(left), Box::new(right)),
158
158
  self.span,
159
159
  )
160
160
  }