koatl 0.1.13__tar.gz → 0.1.15__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.13 → koatl-0.1.15}/Cargo.lock +2 -1
  2. {koatl-0.1.13 → koatl-0.1.15}/PKG-INFO +1 -1
  3. {koatl-0.1.13 → koatl-0.1.15}/koatl/Cargo.toml +1 -1
  4. {koatl-0.1.13 → koatl-0.1.15/koatl}/python/koatl/cli.py +2 -2
  5. {koatl-0.1.13 → koatl-0.1.15}/koatl/python/koatl/notebook/__init__.py +14 -5
  6. {koatl-0.1.13 → koatl-0.1.15/koatl}/python/koatl/prelude/functional/__init__.tl +5 -4
  7. koatl-0.1.15/koatl/python/koatl/prelude/functional/async.tl +43 -0
  8. koatl-0.1.15/koatl/python/koatl/prelude/functional/monad.tl +12 -0
  9. koatl-0.1.15/koatl/python/koatl/prelude/functional/reader.tl +31 -0
  10. koatl-0.1.15/koatl/python/koatl/prelude/functional/result.tl +80 -0
  11. {koatl-0.1.13 → koatl-0.1.15}/koatl/python/koatl/prelude/iterable.tl +3 -3
  12. {koatl-0.1.13 → koatl-0.1.15}/koatl/python/koatl/runtime/__init__.py +3 -1
  13. {koatl-0.1.13 → koatl-0.1.15}/koatl/python/koatl/runtime/helpers.py +10 -4
  14. {koatl-0.1.13 → koatl-0.1.15/koatl}/python/koatl/runtime/meta_finder.py +6 -2
  15. {koatl-0.1.13 → koatl-0.1.15/koatl}/python/koatl/runtime/virtual.py +27 -0
  16. {koatl-0.1.13 → koatl-0.1.15}/koatl/src/emit_py.rs +24 -11
  17. {koatl-0.1.13 → koatl-0.1.15}/koatl/src/lib.rs +1 -1
  18. {koatl-0.1.13 → koatl-0.1.15}/koatl/tests/e2e/base/coal.tl +5 -4
  19. {koatl-0.1.13 → koatl-0.1.15}/koatl/tests/e2e/base/if_expr.tl +1 -1
  20. koatl-0.1.15/koatl/tests/e2e/base/scopes.tl +49 -0
  21. {koatl-0.1.13 → koatl-0.1.15}/koatl/tests/e2e/base/semantic_whitespace.tl +2 -2
  22. koatl-0.1.13/koatl/tests/e2e/prelude/ok.tl → koatl-0.1.15/koatl/tests/e2e/prelude/result.tl +11 -1
  23. koatl-0.1.15/koatl/tests/parse/deco.tl +2 -0
  24. {koatl-0.1.13 → koatl-0.1.15}/koatl/tests/test_e2e.py +26 -9
  25. {koatl-0.1.13 → koatl-0.1.15}/koatl-core/Cargo.toml +1 -0
  26. {koatl-0.1.13 → koatl-0.1.15}/koatl-core/parser/Cargo.toml +1 -1
  27. {koatl-0.1.13 → koatl-0.1.15}/koatl-core/parser/src/ast.rs +56 -40
  28. {koatl-0.1.13 → koatl-0.1.15}/koatl-core/parser/src/lexer.rs +2 -2
  29. {koatl-0.1.13 → koatl-0.1.15}/koatl-core/parser/src/parser.rs +235 -169
  30. {koatl-0.1.13 → koatl-0.1.15}/koatl-core/parser/src/util.rs +33 -36
  31. {koatl-0.1.13 → koatl-0.1.15}/koatl-core/src/lib.rs +2 -2
  32. {koatl-0.1.13 → koatl-0.1.15}/koatl-core/src/main.rs +1 -0
  33. {koatl-0.1.13 → koatl-0.1.15}/koatl-core/src/py/ast.rs +19 -12
  34. {koatl-0.1.13 → koatl-0.1.15}/koatl-core/src/py/emit.rs +16 -2
  35. {koatl-0.1.13 → koatl-0.1.15}/koatl-core/src/py/util.rs +18 -2
  36. {koatl-0.1.13 → koatl-0.1.15}/koatl-core/src/transform.rs +1596 -1189
  37. {koatl-0.1.13/koatl → koatl-0.1.15}/python/koatl/cli.py +2 -2
  38. {koatl-0.1.13 → koatl-0.1.15}/python/koatl/notebook/__init__.py +14 -5
  39. {koatl-0.1.13/koatl → koatl-0.1.15}/python/koatl/prelude/functional/__init__.tl +5 -4
  40. koatl-0.1.15/python/koatl/prelude/functional/async.tl +43 -0
  41. koatl-0.1.15/python/koatl/prelude/functional/monad.tl +12 -0
  42. koatl-0.1.15/python/koatl/prelude/functional/reader.tl +31 -0
  43. koatl-0.1.15/python/koatl/prelude/functional/result.tl +80 -0
  44. {koatl-0.1.13 → koatl-0.1.15}/python/koatl/prelude/iterable.tl +3 -3
  45. {koatl-0.1.13 → koatl-0.1.15}/python/koatl/runtime/__init__.py +3 -1
  46. {koatl-0.1.13 → koatl-0.1.15}/python/koatl/runtime/helpers.py +10 -4
  47. {koatl-0.1.13/koatl → koatl-0.1.15}/python/koatl/runtime/meta_finder.py +6 -2
  48. {koatl-0.1.13/koatl → koatl-0.1.15}/python/koatl/runtime/virtual.py +27 -0
  49. koatl-0.1.13/koatl/python/koatl/prelude/functional/async.tl +0 -38
  50. koatl-0.1.13/koatl/python/koatl/prelude/functional/ok.tl +0 -51
  51. koatl-0.1.13/koatl/python/koatl/prelude/functional/reader.tl +0 -24
  52. koatl-0.1.13/koatl/tests/parse/deco.tl +0 -2
  53. koatl-0.1.13/python/koatl/prelude/functional/async.tl +0 -38
  54. koatl-0.1.13/python/koatl/prelude/functional/ok.tl +0 -51
  55. koatl-0.1.13/python/koatl/prelude/functional/reader.tl +0 -24
  56. {koatl-0.1.13 → koatl-0.1.15}/Cargo.toml +0 -0
  57. {koatl-0.1.13 → koatl-0.1.15}/README.md +0 -0
  58. {koatl-0.1.13 → koatl-0.1.15}/koatl/.github/workflows/CI.yml +0 -0
  59. {koatl-0.1.13 → koatl-0.1.15}/koatl/.gitignore +0 -0
  60. {koatl-0.1.13 → koatl-0.1.15}/koatl/LICENSE +0 -0
  61. {koatl-0.1.13 → koatl-0.1.15}/koatl/README.md +0 -0
  62. {koatl-0.1.13 → koatl-0.1.15}/koatl/python/koatl/__init__.py +0 -0
  63. {koatl-0.1.13 → koatl-0.1.15}/koatl/python/koatl/__main__.py +0 -0
  64. {koatl-0.1.13 → koatl-0.1.15}/koatl/python/koatl/notebook/magic.py +0 -0
  65. {koatl-0.1.13 → koatl-0.1.15}/koatl/python/koatl/prelude/__init__.tl +0 -0
  66. {koatl-0.1.13 → koatl-0.1.15}/koatl/python/koatl/prelude/functional/async_util.py +0 -0
  67. {koatl-0.1.13 → koatl-0.1.15}/koatl/python/koatl/runtime/record.py +0 -0
  68. {koatl-0.1.13 → koatl-0.1.15}/koatl/requirements.txt +0 -0
  69. {koatl-0.1.13 → koatl-0.1.15}/koatl/tests/e2e/base/containers.tl +0 -0
  70. {koatl-0.1.13 → koatl-0.1.15}/koatl/tests/e2e/base/decorators.tl +0 -0
  71. {koatl-0.1.13 → koatl-0.1.15}/koatl/tests/e2e/base/destructure-for-and-fn.tl +0 -0
  72. {koatl-0.1.13 → koatl-0.1.15}/koatl/tests/e2e/base/destructure.tl +0 -0
  73. {koatl-0.1.13 → koatl-0.1.15}/koatl/tests/e2e/base/escape_ident.tl +0 -0
  74. {koatl-0.1.13 → koatl-0.1.15}/koatl/tests/e2e/base/fstr.tl +0 -0
  75. {koatl-0.1.13 → koatl-0.1.15}/koatl/tests/e2e/base/functions.tl +0 -0
  76. {koatl-0.1.13 → koatl-0.1.15}/koatl/tests/e2e/base/generator.tl +0 -0
  77. {koatl-0.1.13 → koatl-0.1.15}/koatl/tests/e2e/base/imports.tl +0 -0
  78. {koatl-0.1.13 → koatl-0.1.15}/koatl/tests/e2e/base/iterables.tl +0 -0
  79. {koatl-0.1.13 → koatl-0.1.15}/koatl/tests/e2e/base/loops.tl +0 -0
  80. {koatl-0.1.13 → koatl-0.1.15}/koatl/tests/e2e/base/match.tl +0 -0
  81. {koatl-0.1.13 → koatl-0.1.15}/koatl/tests/e2e/base/nary-list.tl +0 -0
  82. {koatl-0.1.13 → koatl-0.1.15}/koatl/tests/e2e/base/placeholder.tl +0 -0
  83. {koatl-0.1.13 → koatl-0.1.15}/koatl/tests/e2e/base/precedence.tl +0 -0
  84. {koatl-0.1.13 → koatl-0.1.15}/koatl/tests/e2e/base/slice.tl +0 -0
  85. {koatl-0.1.13 → koatl-0.1.15}/koatl/tests/e2e/base/try.tl +0 -0
  86. {koatl-0.1.13 → koatl-0.1.15}/koatl/tests/e2e/destructure.tl +0 -0
  87. {koatl-0.1.13 → koatl-0.1.15}/koatl/tests/e2e/prelude/async.tl +0 -0
  88. {koatl-0.1.13 → koatl-0.1.15}/koatl/tests/e2e/prelude/reader.tl +0 -0
  89. {koatl-0.1.13 → koatl-0.1.15}/koatl/tests/e2e/prelude/virtual.tl +0 -0
  90. {koatl-0.1.13 → koatl-0.1.15}/koatl/tests/e2e/util/__init__.py +0 -0
  91. {koatl-0.1.13 → koatl-0.1.15}/koatl/tests/e2e/util/module0.tl +0 -0
  92. {koatl-0.1.13 → koatl-0.1.15}/koatl/tests/e2e/util/module1.tl +0 -0
  93. {koatl-0.1.13 → koatl-0.1.15}/koatl/tests/e2e/util/module2.tl +0 -0
  94. {koatl-0.1.13 → koatl-0.1.15}/koatl/tests/parse/arith.tl +0 -0
  95. {koatl-0.1.13 → koatl-0.1.15}/koatl/tests/parse/assign.tl +0 -0
  96. {koatl-0.1.13 → koatl-0.1.15}/koatl/tests/parse/func.tl +0 -0
  97. {koatl-0.1.13 → koatl-0.1.15}/koatl/tests/parse/matches.tl +0 -0
  98. {koatl-0.1.13 → koatl-0.1.15}/koatl/tests/test_parse.py +0 -0
  99. {koatl-0.1.13 → koatl-0.1.15}/koatl-core/parser/src/lib.rs +0 -0
  100. {koatl-0.1.13 → koatl-0.1.15}/koatl-core/parser/tests/lexer.rs +0 -0
  101. {koatl-0.1.13 → koatl-0.1.15}/koatl-core/src/linecol.rs +0 -0
  102. {koatl-0.1.13 → koatl-0.1.15}/koatl-core/src/parser.rs +0 -0
  103. {koatl-0.1.13 → koatl-0.1.15}/koatl-core/src/py/mod.rs +0 -0
  104. {koatl-0.1.13 → koatl-0.1.15}/pyproject.toml +0 -0
  105. {koatl-0.1.13 → koatl-0.1.15}/python/koatl/__init__.py +0 -0
  106. {koatl-0.1.13 → koatl-0.1.15}/python/koatl/__main__.py +0 -0
  107. {koatl-0.1.13 → koatl-0.1.15}/python/koatl/notebook/magic.py +0 -0
  108. {koatl-0.1.13 → koatl-0.1.15}/python/koatl/prelude/__init__.tl +0 -0
  109. {koatl-0.1.13 → koatl-0.1.15}/python/koatl/prelude/functional/async_util.py +0 -0
  110. {koatl-0.1.13 → koatl-0.1.15}/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.13"
102
+ version = "0.1.15"
103
103
  dependencies = [
104
104
  "ariadne",
105
105
  "koatl-core",
@@ -112,6 +112,7 @@ name = "koatl-core"
112
112
  version = "0.1.0"
113
113
  dependencies = [
114
114
  "ariadne",
115
+ "once_cell",
115
116
  "parser",
116
117
  ]
117
118
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: koatl
3
- Version: 0.1.13
3
+ Version: 0.1.15
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.13"
3
+ version = "0.1.15"
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__"}
@@ -21,14 +21,23 @@ def source_code_transformer(lines):
21
21
  return lines
22
22
 
23
23
 
24
- def import_prelude(namespace):
25
- exec("from koatl.runtime import *", namespace)
26
- exec("from koatl.prelude import *", namespace)
24
+ def try_import_prelude(namespace):
25
+ try:
26
+ exec("from koatl.runtime import *", namespace)
27
+ exec("from koatl.prelude import *", namespace)
28
+ except Exception as e:
29
+ import traceback
30
+
31
+ print(
32
+ "There was an error importing the Koatl prelude. Some features may not work."
33
+ )
34
+ traceback.print_exc()
27
35
 
28
36
 
29
37
  def load_ipython_extension(ipython):
30
- import_prelude(ipython.user_ns)
31
- print("koatl enabled")
38
+ print("Switched notebook to Koatl.")
39
+
40
+ try_import_prelude(ipython.user_ns)
32
41
 
33
42
  ttm = ipython.input_transformer_manager
34
43
 
@@ -1,15 +1,16 @@
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
10
11
  [*fs] =>
11
- composed = (*args, **kwargs) =>
12
- value = fs[-1](*args, **kwargs)
12
+ let composed = (*args, **kwargs) =>
13
+ let value = fs[-1](*args, **kwargs)
13
14
  for f in fs[..-1..-1]:
14
15
  value = f(value)
15
16
  value
@@ -0,0 +1,43 @@
1
+ import functools.wraps
2
+ import asyncio
3
+
4
+ import .async_util
5
+ import .monad.Monad
6
+
7
+ export Async = class(Monad):
8
+ __init__ = (self, awaitable) => self.generator = awaitable.__await__()
9
+
10
+ __await__ = self => self.generator
11
+
12
+ __repr__ = self => "Async(...)"
13
+
14
+ from_generator_fn = staticmethod& (generator_fn, *args, **kwargs) =>
15
+ let m = object.__new__(Async)
16
+ m.generator = generator_fn(*args, **kwargs)
17
+ return m
18
+
19
+ run = self => asyncio.run(async_util.to_coro(self))
20
+
21
+ bind_once = (self, f) => Async.from_generator_fn& () =>
22
+ let result = f(yield from self.__await__())
23
+
24
+ if hasattr(result, "__await__"):
25
+ return yield from result.__await__()
26
+
27
+ return result
28
+
29
+ bind_gen = (self, gen) => Async.from_generator_fn& () =>
30
+ try:
31
+ while True:
32
+ self = gen.send(yield from self.__await__())
33
+ except StopIteration(value=value):
34
+ return value
35
+
36
+ pure = staticmethod& x => Async.from_generator_fn& () =>
37
+ return x
38
+ yield None
39
+
40
+ sleep = staticmethod& x => Async(asyncio.sleep(x))
41
+
42
+ #- TODO: Why is asyncio.gather eager? -#
43
+ 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,31 @@
1
+ import functools.wraps
2
+ import .monad.Monad
3
+
4
+ export Reader = class(Monad):
5
+ __init__ = (self, fn) => self.fn = fn
6
+
7
+ __repr__ = self => "Reader(...)"
8
+
9
+ run = (self, ctx) => self.fn(ctx)
10
+
11
+ bind_once = (self, f) => Reader& ctx =>
12
+ let v = f(self.fn(ctx))
13
+ if v matches Reader():
14
+ v.fn(ctx)
15
+ else:
16
+ v
17
+
18
+ bind_gen = (self, gen) => Reader& ctx =>
19
+ try:
20
+ while True:
21
+ self = gen.send(self.fn(ctx))
22
+ except StopIteration(value=value):
23
+ return value
24
+
25
+ NoKey = object()
26
+
27
+ ask = staticmethod& (key=NoKey) => Reader(
28
+ key === Reader.NoKey then ctx => ctx else ctx => ctx[key]
29
+ )
30
+
31
+ 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
+ )
@@ -13,7 +13,7 @@ methods = {
13
13
  yield from f(i)
14
14
 
15
15
  fold: (x, init, f) =>
16
- acc = init
16
+ let acc = init
17
17
  for i in x:
18
18
  acc = f(acc, i)
19
19
  acc
@@ -25,7 +25,7 @@ methods = {
25
25
  return None
26
26
 
27
27
  last: (x, f) =>
28
- result = None
28
+ let result = None
29
29
  for i in x:
30
30
  if f(i):
31
31
  result = i
@@ -38,7 +38,7 @@ methods = {
38
38
  raise IndexError("Index out of range")
39
39
 
40
40
  sum: x =>
41
- acc = 0
41
+ let acc = 0
42
42
  for i in x:
43
43
  acc = acc + i
44
44
  acc
@@ -22,10 +22,12 @@ from .helpers import *
22
22
 
23
23
 
24
24
  __tl__ = SimpleNamespace(
25
+ slice=slice,
26
+ vget=virtual.vget,
27
+ vhas=virtual.vhas,
25
28
  unpack_record=helpers.unpack_record,
26
29
  set_exports=helpers.set_exports,
27
30
  do=helpers.do,
28
- vget=helpers.vget,
29
31
  ok=helpers.ok,
30
32
  partial=functools.partial,
31
33
  **{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,12 @@ def do(f):
74
74
  except AttributeError:
75
75
  return e.value
76
76
 
77
- return vget(m, "bind_once")(recurse)
77
+ try:
78
+ # TODO: this is a workaround to avoid recursion.
79
+ # is it possible to get bind_gen directly from bind_once?
80
+
81
+ return vget(m, "bind_gen")(gen)
82
+ except (NotImplementedError, AttributeError):
83
+ return vget(m, "bind_once")(recurse)
78
84
 
79
85
  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="no_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
@@ -333,18 +333,31 @@ impl<'src> PyStmtExt<'src> for SPyStmt<'src> {
333
333
  &self.tl_span,
334
334
  )
335
335
  }
336
- PyStmt::FnDef(name, args, body, decorators) => {
337
- let arguments = args.emit_py(ctx)?;
338
- let body_ast = body.emit_py(ctx)?;
339
- let decorators = decorators.emit_py(ctx)?;
340
-
341
- ctx.ast_node(
342
- "FunctionDef",
343
- (name.as_ref(), arguments, body_ast, decorators),
344
- &self.tl_span,
345
- )
336
+ PyStmt::FnDef(fndef) => {
337
+ let arguments = fndef.args.emit_py(ctx)?;
338
+ let body_ast = fndef.body.emit_py(ctx)?;
339
+ let decorators = fndef.decorators.emit_py(ctx)?;
340
+
341
+ if fndef.async_ {
342
+ ctx.ast_node(
343
+ "AsyncFunctionDef",
344
+ (fndef.name.as_ref(), arguments, body_ast, decorators),
345
+ &self.tl_span,
346
+ )
347
+ } else {
348
+ ctx.ast_node(
349
+ "FunctionDef",
350
+ (fndef.name.as_ref(), arguments, body_ast, decorators),
351
+ &self.tl_span,
352
+ )
353
+ }
346
354
  }
347
- PyStmt::ClassDef(name, bases, body, decorators) => {
355
+ PyStmt::ClassDef(PyClassDef {
356
+ name,
357
+ bases,
358
+ body,
359
+ decorators,
360
+ }) => {
348
361
  let mut bases_ast = Vec::new();
349
362
  let mut keywords_ast = Vec::new();
350
363
 
@@ -14,7 +14,7 @@ use pyo3::{
14
14
  fn get_option(mode: &str) -> PyResult<TranspileOptions> {
15
15
  Ok(match mode {
16
16
  "module" => TranspileOptions::module(),
17
- "prelude" => TranspileOptions::prelude(),
17
+ "no_prelude" => TranspileOptions::no_prelude(),
18
18
  "interactive" => TranspileOptions::interactive(),
19
19
  "script" => TranspileOptions::script(),
20
20
  _ => {
@@ -1,9 +1,10 @@
1
1
  import util.assert_eq
2
2
 
3
- assert_eq(None?(1)?(2), None)
4
- assert_eq(None?[1]?.a, None)
5
- assert_eq(None?.a, None)
6
- assert_eq(None?.(a), None)
3
+ none = None
4
+ assert_eq(none?(1)?(2), None)
5
+ assert_eq(none?[1]?.a, None)
6
+ assert_eq(none?.a, None)
7
+ assert_eq(none?.(a), None)
7
8
 
8
9
  obj = (class:
9
10
  a = 1
@@ -10,7 +10,7 @@ assert_eq(a, 1)
10
10
  a = if False:
11
11
  2 * 4
12
12
  else:
13
- x = 4 * 8
13
+ let x = 4 * 8
14
14
  x * 2
15
15
 
16
16
  assert_eq(a, 4 * 8 * 2)
@@ -0,0 +1,49 @@
1
+ import util.assert_eq
2
+
3
+ test = 1
4
+ if True:
5
+ test = 2
6
+ assert_eq(test, 2)
7
+
8
+ let test = 3
9
+ assert_eq(test, 3)
10
+
11
+ test = 4
12
+ assert_eq(test, 4)
13
+
14
+ assert_eq(test, 2)
15
+
16
+ f = () =>
17
+ let test = 5
18
+ assert_eq(test, 5)
19
+
20
+ f()
21
+ assert_eq(test, 2)
22
+
23
+ f = () =>
24
+ test = 5
25
+ let g = () =>
26
+ test = 6
27
+ g()
28
+ assert_eq(test, 6)
29
+
30
+ f()
31
+
32
+
33
+ f = () =>
34
+ test = 5
35
+ let g = () =>
36
+ let test = 6
37
+ g()
38
+ assert_eq(test, 5)
39
+
40
+ f()
41
+
42
+ test = 0
43
+
44
+ f = test =>
45
+ test = 1
46
+ assert_eq(test, 1)
47
+
48
+ f(1)
49
+ assert_eq(test, 0)
@@ -64,7 +64,7 @@ assert_eq([
64
64
  apply = (x, y) => x(y)
65
65
  assert_eq(apply(
66
66
  x =>
67
- y = x * 2
67
+ let y = x * 2
68
68
  y * 2
69
69
  8
70
70
  ), 8 * 2 * 2)
@@ -72,7 +72,7 @@ assert_eq(apply(
72
72
  assert_eq(
73
73
  apply(
74
74
  x =>
75
- y = x * 2
75
+ let y = x * 2
76
76
  y * 2
77
77
  8
78
78
  )
@@ -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
@@ -6,10 +6,9 @@ from pathlib import Path
6
6
  sys.path.append(str(Path(__file__).parent / "e2e"))
7
7
 
8
8
 
9
- def get_test_data():
9
+ def get_test_data(dirs):
10
10
  data_dirs = [
11
- Path(__file__).parent / "e2e" / "base",
12
- Path(__file__).parent / "e2e" / "prelude",
11
+ Path(__file__).parent / "e2e" / dirs,
13
12
  ]
14
13
 
15
14
  test_cases = []
@@ -20,13 +19,32 @@ def get_test_data():
20
19
  return test_cases
21
20
 
22
21
 
23
- @pytest.mark.parametrize("test_file", get_test_data())
24
- def test_e2e_native_emit(test_file):
22
+ @pytest.mark.parametrize("test_file", get_test_data("base"))
23
+ def test_e2e_native_emit_base(test_file):
24
+ e2e_native_emit(test_file, "no_prelude")
25
+
26
+
27
+ @pytest.mark.parametrize("test_file", get_test_data("prelude"))
28
+ def test_e2e_native_emit_prelude(test_file):
29
+ e2e_native_emit(test_file, "script")
30
+
31
+
32
+ @pytest.mark.parametrize("test_file", get_test_data("base"))
33
+ def test_e2e_base(test_file):
34
+ e2e(test_file, "no_prelude")
35
+
36
+
37
+ @pytest.mark.parametrize("test_file", get_test_data("prelude"))
38
+ def test_e2e_prelude(test_file):
39
+ e2e(test_file, "script")
40
+
41
+
42
+ def e2e_native_emit(test_file, mode):
25
43
  import linecache
26
44
 
27
45
  with open(test_file, "r") as f:
28
46
  source = f.read()
29
- source, source_map = koatl.transpile_raw(source, mode="script")
47
+ source, source_map = koatl.transpile_raw(source, mode=mode)
30
48
 
31
49
  global_dict = {}
32
50
 
@@ -46,6 +64,5 @@ def test_e2e_native_emit(test_file):
46
64
  print("end", test_file)
47
65
 
48
66
 
49
- @pytest.mark.parametrize("test_file", get_test_data())
50
- def test_e2e(test_file):
51
- koatl.cli.run_from_path(test_file, mode="script")
67
+ def e2e(test_file, mode):
68
+ koatl.cli.run_from_path(test_file, mode=mode)
@@ -6,3 +6,4 @@ edition = "2024"
6
6
  [dependencies]
7
7
  ariadne = "0.5.1"
8
8
  parser = { path = "parser" }
9
+ once_cell = "1.19.0"
@@ -4,4 +4,4 @@ version = "0.1.0"
4
4
  edition = "2024"
5
5
 
6
6
  [dependencies]
7
- chumsky = "0.10.1"
7
+ chumsky = { version="0.10.1", features=["memoization"] }