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.
- {koatl-0.1.12 → koatl-0.1.14}/Cargo.lock +1 -1
- {koatl-0.1.12 → koatl-0.1.14}/PKG-INFO +1 -1
- {koatl-0.1.12 → koatl-0.1.14}/koatl/Cargo.toml +1 -1
- {koatl-0.1.12 → koatl-0.1.14/koatl}/python/koatl/cli.py +2 -2
- {koatl-0.1.12 → koatl-0.1.14/koatl}/python/koatl/prelude/functional/__init__.tl +3 -2
- koatl-0.1.14/koatl/python/koatl/prelude/functional/async.tl +42 -0
- koatl-0.1.14/koatl/python/koatl/prelude/functional/monad.tl +12 -0
- koatl-0.1.14/koatl/python/koatl/prelude/functional/reader.tl +33 -0
- koatl-0.1.14/koatl/python/koatl/prelude/functional/result.tl +80 -0
- {koatl-0.1.12 → koatl-0.1.14/koatl}/python/koatl/runtime/__init__.py +2 -1
- {koatl-0.1.12 → koatl-0.1.14/koatl}/python/koatl/runtime/helpers.py +8 -4
- {koatl-0.1.12 → koatl-0.1.14}/koatl/python/koatl/runtime/meta_finder.py +6 -2
- {koatl-0.1.12 → koatl-0.1.14/koatl}/python/koatl/runtime/virtual.py +27 -0
- {koatl-0.1.12 → koatl-0.1.14}/koatl/tests/e2e/base/coal.tl +3 -3
- koatl-0.1.14/koatl/tests/e2e/base/placeholder.tl +37 -0
- koatl-0.1.12/koatl/tests/e2e/prelude/ok.tl → koatl-0.1.14/koatl/tests/e2e/prelude/result.tl +11 -1
- koatl-0.1.14/koatl/tests/parse/deco.tl +2 -0
- {koatl-0.1.12 → koatl-0.1.14}/koatl-core/parser/src/ast.rs +5 -5
- {koatl-0.1.12 → koatl-0.1.14}/koatl-core/parser/src/parser.rs +41 -38
- {koatl-0.1.12 → koatl-0.1.14}/koatl-core/parser/src/util.rs +2 -2
- {koatl-0.1.12 → koatl-0.1.14}/koatl-core/src/transform.rs +187 -199
- {koatl-0.1.12/koatl → koatl-0.1.14}/python/koatl/cli.py +2 -2
- {koatl-0.1.12/koatl → koatl-0.1.14}/python/koatl/prelude/functional/__init__.tl +3 -2
- koatl-0.1.14/python/koatl/prelude/functional/async.tl +42 -0
- koatl-0.1.14/python/koatl/prelude/functional/monad.tl +12 -0
- koatl-0.1.14/python/koatl/prelude/functional/reader.tl +33 -0
- koatl-0.1.14/python/koatl/prelude/functional/result.tl +80 -0
- {koatl-0.1.12/koatl → koatl-0.1.14}/python/koatl/runtime/__init__.py +2 -1
- {koatl-0.1.12/koatl → koatl-0.1.14}/python/koatl/runtime/helpers.py +8 -4
- {koatl-0.1.12 → koatl-0.1.14}/python/koatl/runtime/meta_finder.py +6 -2
- {koatl-0.1.12/koatl → koatl-0.1.14}/python/koatl/runtime/virtual.py +27 -0
- koatl-0.1.12/koatl/python/koatl/prelude/functional/async.tl +0 -38
- koatl-0.1.12/koatl/python/koatl/prelude/functional/ok.tl +0 -51
- koatl-0.1.12/koatl/python/koatl/prelude/functional/reader.tl +0 -24
- koatl-0.1.12/koatl/tests/e2e/base/placeholder.tl +0 -23
- koatl-0.1.12/koatl/tests/parse/deco.tl +0 -2
- koatl-0.1.12/python/koatl/prelude/functional/async.tl +0 -38
- koatl-0.1.12/python/koatl/prelude/functional/ok.tl +0 -51
- koatl-0.1.12/python/koatl/prelude/functional/reader.tl +0 -24
- {koatl-0.1.12 → koatl-0.1.14}/Cargo.toml +0 -0
- {koatl-0.1.12 → koatl-0.1.14}/README.md +0 -0
- {koatl-0.1.12 → koatl-0.1.14}/koatl/.github/workflows/CI.yml +0 -0
- {koatl-0.1.12 → koatl-0.1.14}/koatl/.gitignore +0 -0
- {koatl-0.1.12 → koatl-0.1.14}/koatl/LICENSE +0 -0
- {koatl-0.1.12 → koatl-0.1.14}/koatl/README.md +0 -0
- {koatl-0.1.12 → koatl-0.1.14}/koatl/python/koatl/__init__.py +0 -0
- {koatl-0.1.12 → koatl-0.1.14}/koatl/python/koatl/__main__.py +0 -0
- {koatl-0.1.12 → koatl-0.1.14}/koatl/python/koatl/notebook/__init__.py +0 -0
- {koatl-0.1.12 → koatl-0.1.14}/koatl/python/koatl/notebook/magic.py +0 -0
- {koatl-0.1.12 → koatl-0.1.14}/koatl/python/koatl/prelude/__init__.tl +0 -0
- {koatl-0.1.12 → koatl-0.1.14}/koatl/python/koatl/prelude/functional/async_util.py +0 -0
- {koatl-0.1.12 → koatl-0.1.14}/koatl/python/koatl/prelude/iterable.tl +0 -0
- {koatl-0.1.12 → koatl-0.1.14}/koatl/python/koatl/runtime/record.py +0 -0
- {koatl-0.1.12 → koatl-0.1.14}/koatl/requirements.txt +0 -0
- {koatl-0.1.12 → koatl-0.1.14}/koatl/src/emit_py.rs +0 -0
- {koatl-0.1.12 → koatl-0.1.14}/koatl/src/lib.rs +0 -0
- {koatl-0.1.12 → koatl-0.1.14}/koatl/tests/e2e/base/containers.tl +0 -0
- {koatl-0.1.12 → koatl-0.1.14}/koatl/tests/e2e/base/decorators.tl +0 -0
- {koatl-0.1.12 → koatl-0.1.14}/koatl/tests/e2e/base/destructure-for-and-fn.tl +0 -0
- {koatl-0.1.12 → koatl-0.1.14}/koatl/tests/e2e/base/destructure.tl +0 -0
- {koatl-0.1.12 → koatl-0.1.14}/koatl/tests/e2e/base/escape_ident.tl +0 -0
- {koatl-0.1.12 → koatl-0.1.14}/koatl/tests/e2e/base/fstr.tl +0 -0
- {koatl-0.1.12 → koatl-0.1.14}/koatl/tests/e2e/base/functions.tl +0 -0
- {koatl-0.1.12 → koatl-0.1.14}/koatl/tests/e2e/base/generator.tl +0 -0
- {koatl-0.1.12 → koatl-0.1.14}/koatl/tests/e2e/base/if_expr.tl +0 -0
- {koatl-0.1.12 → koatl-0.1.14}/koatl/tests/e2e/base/imports.tl +0 -0
- {koatl-0.1.12 → koatl-0.1.14}/koatl/tests/e2e/base/iterables.tl +0 -0
- {koatl-0.1.12 → koatl-0.1.14}/koatl/tests/e2e/base/loops.tl +0 -0
- {koatl-0.1.12 → koatl-0.1.14}/koatl/tests/e2e/base/match.tl +0 -0
- {koatl-0.1.12 → koatl-0.1.14}/koatl/tests/e2e/base/nary-list.tl +0 -0
- {koatl-0.1.12 → koatl-0.1.14}/koatl/tests/e2e/base/precedence.tl +0 -0
- {koatl-0.1.12 → koatl-0.1.14}/koatl/tests/e2e/base/semantic_whitespace.tl +0 -0
- {koatl-0.1.12 → koatl-0.1.14}/koatl/tests/e2e/base/slice.tl +0 -0
- {koatl-0.1.12 → koatl-0.1.14}/koatl/tests/e2e/base/try.tl +0 -0
- {koatl-0.1.12 → koatl-0.1.14}/koatl/tests/e2e/destructure.tl +0 -0
- {koatl-0.1.12 → koatl-0.1.14}/koatl/tests/e2e/prelude/async.tl +0 -0
- {koatl-0.1.12 → koatl-0.1.14}/koatl/tests/e2e/prelude/reader.tl +0 -0
- {koatl-0.1.12 → koatl-0.1.14}/koatl/tests/e2e/prelude/virtual.tl +0 -0
- {koatl-0.1.12 → koatl-0.1.14}/koatl/tests/e2e/util/__init__.py +0 -0
- {koatl-0.1.12 → koatl-0.1.14}/koatl/tests/e2e/util/module0.tl +0 -0
- {koatl-0.1.12 → koatl-0.1.14}/koatl/tests/e2e/util/module1.tl +0 -0
- {koatl-0.1.12 → koatl-0.1.14}/koatl/tests/e2e/util/module2.tl +0 -0
- {koatl-0.1.12 → koatl-0.1.14}/koatl/tests/parse/arith.tl +0 -0
- {koatl-0.1.12 → koatl-0.1.14}/koatl/tests/parse/assign.tl +0 -0
- {koatl-0.1.12 → koatl-0.1.14}/koatl/tests/parse/func.tl +0 -0
- {koatl-0.1.12 → koatl-0.1.14}/koatl/tests/parse/matches.tl +0 -0
- {koatl-0.1.12 → koatl-0.1.14}/koatl/tests/test_e2e.py +0 -0
- {koatl-0.1.12 → koatl-0.1.14}/koatl/tests/test_parse.py +0 -0
- {koatl-0.1.12 → koatl-0.1.14}/koatl-core/Cargo.toml +0 -0
- {koatl-0.1.12 → koatl-0.1.14}/koatl-core/parser/Cargo.toml +0 -0
- {koatl-0.1.12 → koatl-0.1.14}/koatl-core/parser/src/lexer.rs +0 -0
- {koatl-0.1.12 → koatl-0.1.14}/koatl-core/parser/src/lib.rs +0 -0
- {koatl-0.1.12 → koatl-0.1.14}/koatl-core/parser/tests/lexer.rs +0 -0
- {koatl-0.1.12 → koatl-0.1.14}/koatl-core/src/lib.rs +0 -0
- {koatl-0.1.12 → koatl-0.1.14}/koatl-core/src/linecol.rs +0 -0
- {koatl-0.1.12 → koatl-0.1.14}/koatl-core/src/main.rs +0 -0
- {koatl-0.1.12 → koatl-0.1.14}/koatl-core/src/parser.rs +0 -0
- {koatl-0.1.12 → koatl-0.1.14}/koatl-core/src/py/ast.rs +0 -0
- {koatl-0.1.12 → koatl-0.1.14}/koatl-core/src/py/emit.rs +0 -0
- {koatl-0.1.12 → koatl-0.1.14}/koatl-core/src/py/mod.rs +0 -0
- {koatl-0.1.12 → koatl-0.1.14}/koatl-core/src/py/util.rs +0 -0
- {koatl-0.1.12 → koatl-0.1.14}/pyproject.toml +0 -0
- {koatl-0.1.12 → koatl-0.1.14}/python/koatl/__init__.py +0 -0
- {koatl-0.1.12 → koatl-0.1.14}/python/koatl/__main__.py +0 -0
- {koatl-0.1.12 → koatl-0.1.14}/python/koatl/notebook/__init__.py +0 -0
- {koatl-0.1.12 → koatl-0.1.14}/python/koatl/notebook/magic.py +0 -0
- {koatl-0.1.12 → koatl-0.1.14}/python/koatl/prelude/__init__.tl +0 -0
- {koatl-0.1.12 → koatl-0.1.14}/python/koatl/prelude/functional/async_util.py +0 -0
- {koatl-0.1.12 → koatl-0.1.14}/python/koatl/prelude/iterable.tl +0 -0
- {koatl-0.1.12 → koatl-0.1.14}/python/koatl/runtime/record.py +0 -0
|
@@ -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 .
|
|
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 = &
|
|
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
|
-
|
|
59
|
+
gen = f(*args, **kwargs)
|
|
60
60
|
|
|
61
61
|
try:
|
|
62
|
-
m =
|
|
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 =
|
|
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
|
-
|
|
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(
|
|
56
|
+
transpiled_code = transpile(
|
|
57
|
+
source_code, mode="prelude", filename=self.filepath
|
|
58
|
+
)
|
|
57
59
|
else:
|
|
58
|
-
transpiled_code = transpile(
|
|
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])
|
|
@@ -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(
|
|
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::
|
|
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::
|
|
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::
|
|
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::
|
|
732
|
+
Postfix::ScopedAttributeCall(rhs, args)
|
|
747
733
|
} else {
|
|
748
|
-
Postfix::
|
|
734
|
+
Postfix::ScopedAttribute(rhs)
|
|
749
735
|
}
|
|
750
736
|
})
|
|
751
737
|
.labelled("then-attribute")
|
|
752
738
|
.boxed();
|
|
753
739
|
|
|
754
|
-
let
|
|
740
|
+
let raw_attr = symbol("!")
|
|
755
741
|
.ignore_then(ident.clone())
|
|
756
|
-
.map(Postfix::
|
|
757
|
-
.labelled("
|
|
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,
|
|
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::
|
|
775
|
-
Postfix::
|
|
776
|
-
Expr::
|
|
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::
|
|
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::
|
|
767
|
+
Expr::ScopedAttribute(Box::new(expr), Box::new(rhs)),
|
|
782
768
|
e.span(),
|
|
783
769
|
)),
|
|
784
770
|
args,
|
|
785
771
|
),
|
|
786
|
-
Postfix::
|
|
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::
|
|
793
|
-
|
|
794
|
-
|
|
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::
|
|
786
|
+
Expr::MappedScopedAttribute(Box::new(expr), Box::new(rhs)),
|
|
797
787
|
e.span(),
|
|
798
788
|
)),
|
|
799
789
|
args,
|
|
800
790
|
),
|
|
801
|
-
Postfix::
|
|
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((
|
|
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::
|
|
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::
|
|
157
|
+
Expr::ScopedAttribute(Box::new(left), Box::new(right)),
|
|
158
158
|
self.span,
|
|
159
159
|
)
|
|
160
160
|
}
|