koatl 0.1.23__tar.gz → 0.1.24__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 (116) hide show
  1. {koatl-0.1.23 → koatl-0.1.24}/Cargo.lock +1 -1
  2. {koatl-0.1.23 → koatl-0.1.24}/PKG-INFO +1 -1
  3. {koatl-0.1.23 → koatl-0.1.24}/koatl/Cargo.toml +1 -1
  4. {koatl-0.1.23 → koatl-0.1.24/koatl}/python/koatl/prelude/functional/memo.tl +5 -4
  5. {koatl-0.1.23 → koatl-0.1.24/koatl}/python/koatl/prelude/functional/monad.tl +2 -0
  6. koatl-0.1.24/koatl/python/koatl/prelude/functional/result.tl +131 -0
  7. {koatl-0.1.23 → koatl-0.1.24}/koatl/python/koatl/runtime/helpers.py +5 -0
  8. {koatl-0.1.23 → koatl-0.1.24}/koatl/src/emit_py.rs +20 -3
  9. {koatl-0.1.23 → koatl-0.1.24}/koatl-core/src/resolve_scopes.rs +25 -13
  10. {koatl-0.1.23 → koatl-0.1.24}/koatl-core/src/transform.rs +46 -36
  11. {koatl-0.1.23/koatl → koatl-0.1.24}/python/koatl/prelude/functional/memo.tl +5 -4
  12. {koatl-0.1.23/koatl → koatl-0.1.24}/python/koatl/prelude/functional/monad.tl +2 -0
  13. koatl-0.1.24/python/koatl/prelude/functional/result.tl +131 -0
  14. {koatl-0.1.23 → koatl-0.1.24}/python/koatl/runtime/helpers.py +5 -0
  15. koatl-0.1.23/koatl/python/koatl/prelude/functional/result.tl +0 -90
  16. koatl-0.1.23/python/koatl/prelude/functional/result.tl +0 -90
  17. {koatl-0.1.23 → koatl-0.1.24}/Cargo.toml +0 -0
  18. {koatl-0.1.23 → koatl-0.1.24}/README.md +0 -0
  19. {koatl-0.1.23 → koatl-0.1.24}/koatl/.github/workflows/CI.yml +0 -0
  20. {koatl-0.1.23 → koatl-0.1.24}/koatl/.gitignore +0 -0
  21. {koatl-0.1.23 → koatl-0.1.24}/koatl/LICENSE +0 -0
  22. {koatl-0.1.23 → koatl-0.1.24}/koatl/README.md +0 -0
  23. {koatl-0.1.23 → koatl-0.1.24}/koatl/python/koatl/__init__.py +0 -0
  24. {koatl-0.1.23 → koatl-0.1.24}/koatl/python/koatl/__main__.py +0 -0
  25. {koatl-0.1.23 → koatl-0.1.24}/koatl/python/koatl/cli.py +0 -0
  26. {koatl-0.1.23 → koatl-0.1.24}/koatl/python/koatl/notebook/__init__.py +0 -0
  27. {koatl-0.1.23 → koatl-0.1.24}/koatl/python/koatl/notebook/magic.py +0 -0
  28. {koatl-0.1.23 → koatl-0.1.24}/koatl/python/koatl/prelude/__init__.tl +0 -0
  29. {koatl-0.1.23 → koatl-0.1.24}/koatl/python/koatl/prelude/functional/__init__.tl +0 -0
  30. {koatl-0.1.23 → koatl-0.1.24}/koatl/python/koatl/prelude/functional/async.tl +0 -0
  31. {koatl-0.1.23 → koatl-0.1.24}/koatl/python/koatl/prelude/functional/async_util.py +0 -0
  32. {koatl-0.1.23 → koatl-0.1.24}/koatl/python/koatl/prelude/functional/list.tl +0 -0
  33. {koatl-0.1.23 → koatl-0.1.24}/koatl/python/koatl/prelude/functional/reader.tl +0 -0
  34. {koatl-0.1.23 → koatl-0.1.24}/koatl/python/koatl/prelude/iterable.tl +0 -0
  35. {koatl-0.1.23 → koatl-0.1.24}/koatl/python/koatl/runtime/__init__.py +0 -0
  36. {koatl-0.1.23 → koatl-0.1.24}/koatl/python/koatl/runtime/meta_finder.py +0 -0
  37. {koatl-0.1.23 → koatl-0.1.24}/koatl/python/koatl/runtime/record.py +0 -0
  38. {koatl-0.1.23 → koatl-0.1.24}/koatl/python/koatl/runtime/virtual.py +0 -0
  39. {koatl-0.1.23 → koatl-0.1.24}/koatl/requirements.txt +0 -0
  40. {koatl-0.1.23 → koatl-0.1.24}/koatl/src/lib.rs +0 -0
  41. {koatl-0.1.23 → koatl-0.1.24}/koatl/tests/e2e/base/coal.tl +0 -0
  42. {koatl-0.1.23 → koatl-0.1.24}/koatl/tests/e2e/base/containers.tl +0 -0
  43. {koatl-0.1.23 → koatl-0.1.24}/koatl/tests/e2e/base/decorators.tl +0 -0
  44. {koatl-0.1.23 → koatl-0.1.24}/koatl/tests/e2e/base/destructure-for-and-fn.tl +0 -0
  45. {koatl-0.1.23 → koatl-0.1.24}/koatl/tests/e2e/base/destructure.tl +0 -0
  46. {koatl-0.1.23 → koatl-0.1.24}/koatl/tests/e2e/base/escape_ident.tl +0 -0
  47. {koatl-0.1.23 → koatl-0.1.24}/koatl/tests/e2e/base/fstr.tl +0 -0
  48. {koatl-0.1.23 → koatl-0.1.24}/koatl/tests/e2e/base/functions.tl +0 -0
  49. {koatl-0.1.23 → koatl-0.1.24}/koatl/tests/e2e/base/generator.tl +0 -0
  50. {koatl-0.1.23 → koatl-0.1.24}/koatl/tests/e2e/base/if_expr.tl +0 -0
  51. {koatl-0.1.23 → koatl-0.1.24}/koatl/tests/e2e/base/imports.tl +0 -0
  52. {koatl-0.1.23 → koatl-0.1.24}/koatl/tests/e2e/base/loops.tl +0 -0
  53. {koatl-0.1.23 → koatl-0.1.24}/koatl/tests/e2e/base/match.tl +0 -0
  54. {koatl-0.1.23 → koatl-0.1.24}/koatl/tests/e2e/base/nary-list.tl +0 -0
  55. {koatl-0.1.23 → koatl-0.1.24}/koatl/tests/e2e/base/placeholder.tl +0 -0
  56. {koatl-0.1.23 → koatl-0.1.24}/koatl/tests/e2e/base/precedence.tl +0 -0
  57. {koatl-0.1.23 → koatl-0.1.24}/koatl/tests/e2e/base/scopes.tl +0 -0
  58. {koatl-0.1.23 → koatl-0.1.24}/koatl/tests/e2e/base/semantic_whitespace.tl +0 -0
  59. {koatl-0.1.23 → koatl-0.1.24}/koatl/tests/e2e/base/slice.tl +0 -0
  60. {koatl-0.1.23 → koatl-0.1.24}/koatl/tests/e2e/base/try.tl +0 -0
  61. {koatl-0.1.23 → koatl-0.1.24}/koatl/tests/e2e/destructure.tl +0 -0
  62. {koatl-0.1.23 → koatl-0.1.24}/koatl/tests/e2e/prelude/async.tl +0 -0
  63. {koatl-0.1.23 → koatl-0.1.24}/koatl/tests/e2e/prelude/iterables.tl +0 -0
  64. {koatl-0.1.23 → koatl-0.1.24}/koatl/tests/e2e/prelude/list.tl +0 -0
  65. {koatl-0.1.23 → koatl-0.1.24}/koatl/tests/e2e/prelude/memo.tl +0 -0
  66. {koatl-0.1.23 → koatl-0.1.24}/koatl/tests/e2e/prelude/reader.tl +0 -0
  67. {koatl-0.1.23 → koatl-0.1.24}/koatl/tests/e2e/prelude/result.tl +0 -0
  68. {koatl-0.1.23 → koatl-0.1.24}/koatl/tests/e2e/prelude/virtual.tl +0 -0
  69. {koatl-0.1.23 → koatl-0.1.24}/koatl/tests/e2e/util/__init__.py +0 -0
  70. {koatl-0.1.23 → koatl-0.1.24}/koatl/tests/e2e/util/module0.tl +0 -0
  71. {koatl-0.1.23 → koatl-0.1.24}/koatl/tests/e2e/util/module1.tl +0 -0
  72. {koatl-0.1.23 → koatl-0.1.24}/koatl/tests/e2e/util/module2.tl +0 -0
  73. {koatl-0.1.23 → koatl-0.1.24}/koatl/tests/parse/arith.tl +0 -0
  74. {koatl-0.1.23 → koatl-0.1.24}/koatl/tests/parse/assign.tl +0 -0
  75. {koatl-0.1.23 → koatl-0.1.24}/koatl/tests/parse/block-comments.tl +0 -0
  76. {koatl-0.1.23 → koatl-0.1.24}/koatl/tests/parse/deco.tl +0 -0
  77. {koatl-0.1.23 → koatl-0.1.24}/koatl/tests/parse/func.tl +0 -0
  78. {koatl-0.1.23 → koatl-0.1.24}/koatl/tests/parse/matches.tl +0 -0
  79. {koatl-0.1.23 → koatl-0.1.24}/koatl/tests/test_e2e.py +0 -0
  80. {koatl-0.1.23 → koatl-0.1.24}/koatl/tests/test_parse.py +0 -0
  81. {koatl-0.1.23 → koatl-0.1.24}/koatl-core/Cargo.toml +0 -0
  82. {koatl-0.1.23 → koatl-0.1.24}/koatl-core/parser/Cargo.toml +0 -0
  83. {koatl-0.1.23 → koatl-0.1.24}/koatl-core/parser/src/ast.rs +0 -0
  84. {koatl-0.1.23 → koatl-0.1.24}/koatl-core/parser/src/lexer.rs +0 -0
  85. {koatl-0.1.23 → koatl-0.1.24}/koatl-core/parser/src/lib.rs +0 -0
  86. {koatl-0.1.23 → koatl-0.1.24}/koatl-core/parser/src/parser.rs +0 -0
  87. {koatl-0.1.23 → koatl-0.1.24}/koatl-core/parser/src/util.rs +0 -0
  88. {koatl-0.1.23 → koatl-0.1.24}/koatl-core/parser/tests/lexer.rs +0 -0
  89. {koatl-0.1.23 → koatl-0.1.24}/koatl-core/src/inference.rs +0 -0
  90. {koatl-0.1.23 → koatl-0.1.24}/koatl-core/src/lib.rs +0 -0
  91. {koatl-0.1.23 → koatl-0.1.24}/koatl-core/src/main.rs +0 -0
  92. {koatl-0.1.23 → koatl-0.1.24}/koatl-core/src/parse_timer.rs +0 -0
  93. {koatl-0.1.23 → koatl-0.1.24}/koatl-core/src/parser.rs +0 -0
  94. {koatl-0.1.23 → koatl-0.1.24}/koatl-core/src/py/ast.rs +0 -0
  95. {koatl-0.1.23 → koatl-0.1.24}/koatl-core/src/py/emit.rs +0 -0
  96. {koatl-0.1.23 → koatl-0.1.24}/koatl-core/src/py/mod.rs +0 -0
  97. {koatl-0.1.23 → koatl-0.1.24}/koatl-core/src/py/util.rs +0 -0
  98. {koatl-0.1.23 → koatl-0.1.24}/koatl-core/src/types.rs +0 -0
  99. {koatl-0.1.23 → koatl-0.1.24}/koatl-core/src/util.rs +0 -0
  100. {koatl-0.1.23 → koatl-0.1.24}/pyproject.toml +0 -0
  101. {koatl-0.1.23 → koatl-0.1.24}/python/koatl/__init__.py +0 -0
  102. {koatl-0.1.23 → koatl-0.1.24}/python/koatl/__main__.py +0 -0
  103. {koatl-0.1.23 → koatl-0.1.24}/python/koatl/cli.py +0 -0
  104. {koatl-0.1.23 → koatl-0.1.24}/python/koatl/notebook/__init__.py +0 -0
  105. {koatl-0.1.23 → koatl-0.1.24}/python/koatl/notebook/magic.py +0 -0
  106. {koatl-0.1.23 → koatl-0.1.24}/python/koatl/prelude/__init__.tl +0 -0
  107. {koatl-0.1.23 → koatl-0.1.24}/python/koatl/prelude/functional/__init__.tl +0 -0
  108. {koatl-0.1.23 → koatl-0.1.24}/python/koatl/prelude/functional/async.tl +0 -0
  109. {koatl-0.1.23 → koatl-0.1.24}/python/koatl/prelude/functional/async_util.py +0 -0
  110. {koatl-0.1.23 → koatl-0.1.24}/python/koatl/prelude/functional/list.tl +0 -0
  111. {koatl-0.1.23 → koatl-0.1.24}/python/koatl/prelude/functional/reader.tl +0 -0
  112. {koatl-0.1.23 → koatl-0.1.24}/python/koatl/prelude/iterable.tl +0 -0
  113. {koatl-0.1.23 → koatl-0.1.24}/python/koatl/runtime/__init__.py +0 -0
  114. {koatl-0.1.23 → koatl-0.1.24}/python/koatl/runtime/meta_finder.py +0 -0
  115. {koatl-0.1.23 → koatl-0.1.24}/python/koatl/runtime/record.py +0 -0
  116. {koatl-0.1.23 → koatl-0.1.24}/python/koatl/runtime/virtual.py +0 -0
@@ -99,7 +99,7 @@ checksum = "f4c7245a08504955605670dbf141fceab975f15ca21570696aebe9d2e71576bd"
99
99
 
100
100
  [[package]]
101
101
  name = "koatl"
102
- version = "0.1.23"
102
+ version = "0.1.24"
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.23
3
+ Version: 0.1.24
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.23"
3
+ version = "0.1.24"
4
4
  edition = "2021"
5
5
 
6
6
  [lib]
@@ -1,6 +1,6 @@
1
1
  import collections.defaultdict
2
2
  import functools.wraps
3
- import .result.Ok
3
+ import .result.(Result, Ok)
4
4
  import .Monad
5
5
 
6
6
  export Memo = class(Monad):
@@ -11,7 +11,8 @@ export Memo = class(Monad):
11
11
  __repr__ = self => f"Memo.Cache({self.cache})"
12
12
 
13
13
  try_get = (self, name, deps) =>
14
- try self.cache[name][deps] except KeyError()
14
+ # TODO should try operator return a Result directly?
15
+ Result(try self.cache[name][deps] except KeyError())
15
16
 
16
17
  update = (self, name, deps, value) =>
17
18
  self.cache[name][deps] = value
@@ -23,7 +24,7 @@ export Memo = class(Monad):
23
24
 
24
25
  value = staticmethod& (id, deps, f) =>
25
26
  Memo(ctx =>
26
- if ctx.try_get(id, tuple(deps)) matches Ok() as value:
27
+ if ctx.try_get(id, tuple(deps)) matches Ok(value):
27
28
  return value
28
29
 
29
30
  ctx.update(id, tuple(deps), f())
@@ -34,7 +35,7 @@ export Memo = class(Monad):
34
35
  let deps = (tuple(args), tuple(kwargs.items()))
35
36
 
36
37
  Memo(ctx =>
37
- if ctx.try_get(id, deps) matches Ok() as value:
38
+ if ctx.try_get(id, deps) matches Ok(value):
38
39
  return value
39
40
 
40
41
  let v = f(*args, **kwargs)
@@ -1,6 +1,8 @@
1
1
  import abc
2
2
 
3
3
  export Monad = class(abc.ABC):
4
+ __slots__ = ()
5
+
4
6
  # The default implementation required for `@` syntax that should be overridden by subclasses.
5
7
  bind_once = abc.abstractmethod& (self, f) => None
6
8
 
@@ -0,0 +1,131 @@
1
+ import functools.wraps
2
+ import .monad.Monad
3
+ import koatl.runtime.virtual.register_global_attr
4
+
5
+ export Result = class:
6
+ __slots__ = ()
7
+ __match_args__ = ("value",)
8
+
9
+ __new__ = (cls, value) =>
10
+ if isinstance(value, Result):
11
+ return value
12
+ value.ok then Ok(value) else Err(value)
13
+
14
+ __init__ = (self, *args, **kwargs) =>
15
+ raise ValueError("Result should not be instantiated directly, use Ok or Err")
16
+
17
+ raw = self =>
18
+ """
19
+ Unwraps the value from a Result, making it look like
20
+ a non-monadic Python value.
21
+ """
22
+ if self matches not Result():
23
+ return self
24
+
25
+ if self.ok:
26
+ if self.value.ok:
27
+ return self.value
28
+ else:
29
+ return self
30
+ else:
31
+ if self.value.ok:
32
+ return self
33
+ else:
34
+ return self.value
35
+
36
+ bind_once = (self, f) =>
37
+ self = Result(self)
38
+ if not self.ok:
39
+ return self
40
+
41
+ let v = Result(f(self.value))
42
+
43
+ bind = bind_once
44
+
45
+ bind_gen = (self, gen) =>
46
+ self = Result(self)
47
+ try:
48
+ while True:
49
+ if not self.ok:
50
+ return self
51
+
52
+ self = Result(gen.send(self.value))
53
+ except StopIteration(value=value):
54
+ return Result.pure(value)
55
+
56
+ pure = staticmethod& x => Ok(x)
57
+
58
+ apply = (self, f) =>
59
+ self = Result(self)
60
+ f = Result(f)
61
+
62
+ if not self.ok:
63
+ return self
64
+ if not f.ok:
65
+ return f
66
+
67
+ Ok(f(self))
68
+
69
+ map = (self, f) =>
70
+ self = Result(self)
71
+ if self.ok:
72
+ return Ok(f(self.value))
73
+ return self
74
+
75
+ map_err = (self, f) =>
76
+ self = Result(self)
77
+ if not self.ok:
78
+ return Err(f(self.value))
79
+ return self
80
+
81
+ map_none = (self, f) =>
82
+ self = Result(self)
83
+ if not self.ok and self.value === None:
84
+ return Err(f())
85
+ return self
86
+
87
+ export Ok = class(Result):
88
+ __slots__ = ("value",)
89
+ ok = True
90
+ __new__ = (cls, value) => object.__new__(cls)
91
+ __init__ = (self, value) =>
92
+ if hasattr(self, "value"):
93
+ # This is necessary to prevent overwriting the value
94
+ # since Python's Result.__new__ will call Ok.__init__ again
95
+ # if the object is already created.
96
+ return None
97
+ self.value = value
98
+
99
+ __repr__ = self => f"Ok({repr(self.value)})"
100
+ unwrap = self => self.value
101
+
102
+ export Err = class(Result):
103
+ __slots__ = ("value",)
104
+ ok = False
105
+ __new__ = (cls, value) => object.__new__(cls)
106
+ __init__ = (self, value) =>
107
+ if hasattr(self, "value"):
108
+ return None
109
+ self.value = value
110
+
111
+ __repr__ = self => f"Err({repr(self.value)})"
112
+ unwrap = self =>
113
+ if self.value matches BaseException():
114
+ raise self.value
115
+ raise ValueError(f"Expected Ok, got {repr(self.value)}")
116
+
117
+
118
+ # Provide a default implementation for *most* Result methods
119
+ # ...we shouldn't provide a default for `map` since that
120
+ # would prevent virtual trait lookup. TODO: fix this?
121
+ for name, method in Result.__dict__:
122
+ if name.startswith("_"):
123
+ continue
124
+ if name == "map":
125
+ continue
126
+
127
+ let make_closure = method => (self, *args, **kwargs) => Result.raw(method(self, *args, **kwargs))
128
+
129
+ register_global_attr(object, name, make_closure(method))
130
+
131
+ register_global_attr(object, "ok", ExtensionProperty(__tl__.ok))
@@ -46,6 +46,11 @@ def unpack_record(obj):
46
46
 
47
47
 
48
48
  def ok(obj):
49
+ try:
50
+ return obj.ok
51
+ except AttributeError:
52
+ pass
53
+
49
54
  if obj is None:
50
55
  return False
51
56
  if isinstance(obj, BaseException):
@@ -502,7 +502,7 @@ impl<'src> PyExprExt<'src> for SPyExpr<'src> {
502
502
  ctx.ast_node("Name", (ident, c.emit_py(ctx)?), &self.tl_span)?
503
503
  }
504
504
  PyExpr::Binary(op, left, right) => {
505
- let py_op_str = match op {
505
+ let py_bin_op = match op {
506
506
  PyBinaryOp::Add => Some("Add"),
507
507
  PyBinaryOp::Sub => Some("Sub"),
508
508
  PyBinaryOp::Mult => Some("Mult"),
@@ -512,18 +512,35 @@ impl<'src> PyExprExt<'src> for SPyExpr<'src> {
512
512
  _ => None,
513
513
  };
514
514
 
515
- if let Some(py_op_str) = py_op_str {
515
+ if let Some(py_bin_op) = py_bin_op {
516
516
  return ctx.ast_node(
517
517
  "BinOp",
518
518
  (
519
519
  left.emit_py(ctx)?,
520
- ctx.ast_cls(py_op_str, ())?,
520
+ ctx.ast_cls(py_bin_op, ())?,
521
521
  right.emit_py(ctx)?,
522
522
  ),
523
523
  &self.tl_span,
524
524
  );
525
525
  }
526
526
 
527
+ let py_bool_op = match op {
528
+ PyBinaryOp::And => Some("And"),
529
+ PyBinaryOp::Or => Some("Or"),
530
+ _ => None,
531
+ };
532
+
533
+ if let Some(py_bool_op) = py_bool_op {
534
+ return ctx.ast_node(
535
+ "BoolOp",
536
+ (
537
+ ctx.ast_cls(py_bool_op, ())?,
538
+ [left.emit_py(ctx)?, right.emit_py(ctx)?],
539
+ ),
540
+ &self.tl_span,
541
+ );
542
+ }
543
+
527
544
  let py_cmp_op = match op {
528
545
  PyBinaryOp::Lt => Some("Lt"),
529
546
  PyBinaryOp::Gt => Some("Gt"),
@@ -2,6 +2,7 @@ use std::collections::HashMap;
2
2
  use std::collections::HashSet;
3
3
  use std::fmt::Display;
4
4
 
5
+ use slotmap::Key;
5
6
  use slotmap::SlotMap;
6
7
  use slotmap::new_key_type;
7
8
 
@@ -70,10 +71,10 @@ fn top_scope_and_key<'src, 'state>(
70
71
  #[allow(dead_code)]
71
72
  impl<'src> ResolveState<'src> {
72
73
  fn new(source: &'src str) -> Self {
73
- let mut root_scope = Scope::new();
74
+ let mut root_scope = Scope::new(ScopeKey::null());
74
75
  root_scope.is_global = true;
75
76
 
76
- let err_scope = Scope::new();
77
+ let err_scope = Scope::new(ScopeKey::null());
77
78
 
78
79
  let mut scopes = SlotMap::with_key();
79
80
  let root_scope_key = scopes.insert(root_scope);
@@ -107,6 +108,10 @@ impl<'src> ResolveState<'src> {
107
108
  top_scope(&self.scope_stack, &mut self.scopes)
108
109
  }
109
110
 
111
+ fn top_scope_key(&mut self) -> ScopeKey {
112
+ *self.scope_stack.last_mut().unwrap()
113
+ }
114
+
110
115
  fn top_scope_and_key(&mut self) -> (&mut Scope, ScopeKey) {
111
116
  top_scope_and_key(&self.scope_stack, &mut self.scopes)
112
117
  }
@@ -185,10 +190,10 @@ impl<'src> ResolveState<'src> {
185
190
  where
186
191
  F: FnOnce(&mut ResolveState<'src>) -> Indirect<SExpr<'src>>,
187
192
  {
188
- let mut temp_scope = Scope::new();
189
- temp_scope.is_fn = true;
193
+ let mut dummy_scope = Scope::new(ScopeKey::null());
194
+ dummy_scope.is_fn = true;
190
195
 
191
- let temp_scope_key = self.scopes.insert(temp_scope);
196
+ let temp_scope_key = self.scopes.insert(dummy_scope);
192
197
 
193
198
  let ph_decl = self.declarations.insert_declaration(
194
199
  Ident("x".into()).spanned(span),
@@ -460,6 +465,9 @@ impl Display for Declaration<'_> {
460
465
 
461
466
  #[derive(Debug)]
462
467
  pub struct Scope {
468
+ // TODO make this option
469
+ pub parent: ScopeKey,
470
+
463
471
  pub locals: Vec<DeclarationKey>,
464
472
 
465
473
  pub is_class: bool,
@@ -488,8 +496,9 @@ impl Display for Scope {
488
496
  }
489
497
 
490
498
  impl Scope {
491
- fn new() -> Scope {
499
+ fn new(parent: ScopeKey) -> Scope {
492
500
  Self {
501
+ parent,
493
502
  locals: Vec::new(),
494
503
  lifted_decls: Vec::new(),
495
504
 
@@ -797,7 +806,7 @@ fn pattern_scoped<'src>(
797
806
  state: &mut ResolveState<'src>,
798
807
  pattern: Indirect<SPattern<'src>>,
799
808
  ) -> (Indirect<SPattern<'src>>, ScopeKey, PatternMeta<'src>) {
800
- let scope = Scope::new();
809
+ let scope = Scope::new(state.top_scope_key());
801
810
  let scope_key = state.scopes.insert(scope);
802
811
 
803
812
  let (pattern, meta) = pattern.traverse(state);
@@ -946,7 +955,8 @@ impl<'src> SExprExt<'src> for Indirect<SExpr<'src>> {
946
955
  }
947
956
  new_stmts
948
957
  } else {
949
- let scope = state.scopes.insert(Scope::new());
958
+ let parent = state.top_scope_key();
959
+ let scope = state.scopes.insert(Scope::new(parent));
950
960
  state
951
961
  .scoped(scope, |state| {
952
962
  let mut new_stmts = Vec::new();
@@ -1040,7 +1050,8 @@ impl<'src> SExprExt<'src> for Indirect<SExpr<'src>> {
1040
1050
  let (pattern, scope, _meta) = pattern_scoped(state, pattern);
1041
1051
  (Some(pattern), scope)
1042
1052
  } else {
1043
- (None, state.scopes.insert(Scope::new()))
1053
+ let parent = state.top_scope_key();
1054
+ (None, state.scopes.insert(Scope::new(parent)))
1044
1055
  };
1045
1056
 
1046
1057
  SMatchCase {
@@ -1058,7 +1069,7 @@ impl<'src> SExprExt<'src> for Indirect<SExpr<'src>> {
1058
1069
  Expr::Class(bases, body) => {
1059
1070
  let bases = traverse_call_items(state, bases);
1060
1071
 
1061
- let mut scope = Scope::new();
1072
+ let mut scope = Scope::new(state.top_scope_key());
1062
1073
  scope.is_class = true;
1063
1074
  let scope = state.scopes.insert(scope);
1064
1075
 
@@ -1071,7 +1082,7 @@ impl<'src> SExprExt<'src> for Indirect<SExpr<'src>> {
1071
1082
  Expr::Fn(arg_def_items, body) => {
1072
1083
  let mut decls = vec![];
1073
1084
 
1074
- let mut scope = Scope::new();
1085
+ let mut scope = Scope::new(state.top_scope_key());
1075
1086
  scope.is_fn = true;
1076
1087
  let scope = state.scopes.insert(scope);
1077
1088
 
@@ -1297,7 +1308,7 @@ impl<'src> SExprExt<'src> for Indirect<SExpr<'src>> {
1297
1308
  let mut fn_ctx = FnInfo::new();
1298
1309
  fn_ctx.is_memo = true;
1299
1310
 
1300
- let mut scope = Scope::new();
1311
+ let mut scope = Scope::new(state.top_scope_key());
1301
1312
  scope.is_fn = true;
1302
1313
 
1303
1314
  // TODO it's confusing that we need to
@@ -1467,7 +1478,8 @@ impl<'src> SStmtExt<'src> for Indirect<SStmt<'src>> {
1467
1478
  let (pattern, scope, _meta) = pattern_scoped(state, pattern);
1468
1479
  (Some(pattern), scope)
1469
1480
  } else {
1470
- (None, state.scopes.insert(Scope::new()))
1481
+ let parent = state.top_scope_key();
1482
+ (None, state.scopes.insert(Scope::new(parent)))
1471
1483
  };
1472
1484
 
1473
1485
  let body = state
@@ -14,7 +14,7 @@ use crate::{
14
14
  };
15
15
  use once_cell::sync::Lazy;
16
16
  use parser::ast::*;
17
- use slotmap::SlotMap;
17
+ use slotmap::{Key, SlotMap};
18
18
  use std::hash::{Hash, Hasher};
19
19
 
20
20
  static PY_KWS: &[&str] = &[
@@ -1404,25 +1404,9 @@ fn prepare_py_fn<'src, 'ast>(
1404
1404
  decorators.push(a.tl_builtin("do"));
1405
1405
  }
1406
1406
 
1407
- let mut nonlocals = vec![];
1408
- let mut globals = vec![];
1409
-
1410
- for capture in fn_info.captures.iter() {
1411
- let scope = &ctx.scopes[ctx.declarations[*capture].scope];
1412
- if scope.is_global || scope.is_class {
1413
- globals.push(ctx.decl_py_ident(*capture)?);
1414
- } else {
1415
- nonlocals.push(ctx.decl_py_ident(*capture)?);
1416
- }
1417
- }
1418
-
1419
- if !nonlocals.is_empty() {
1420
- py_body.push(a.nonlocal(nonlocals.iter().map(|x| x.clone()).collect()));
1421
- }
1422
- if !globals.is_empty() {
1423
- py_body.push(a.global(globals.iter().map(|x| x.clone()).collect()));
1424
- }
1407
+ let (py_bindings, _, _) = py_fn_bindings(ctx, fn_info, *span)?;
1425
1408
 
1409
+ py_body.extend(py_bindings);
1426
1410
  py_body.extend(body.pre);
1427
1411
  py_body.push(a.return_(body.value));
1428
1412
  }
@@ -2257,24 +2241,9 @@ impl<'src, 'ast> SExprExt<'src, 'ast> for SExpr<'src> {
2257
2241
  let py_expr = expr.transform(ctx)?;
2258
2242
  let mut py_body = PyBlock::new();
2259
2243
 
2260
- let mut nonlocals = vec![];
2261
- let mut globals = vec![];
2262
-
2263
- for capture in memo_captures.captures.iter() {
2264
- if ctx.scopes[ctx.declarations[*capture].scope].is_global {
2265
- globals.push(ctx.decl_py_ident(*capture)?);
2266
- } else {
2267
- nonlocals.push(ctx.decl_py_ident(*capture)?);
2268
- }
2269
- }
2270
-
2271
- if !nonlocals.is_empty() {
2272
- py_body.push(a.nonlocal(nonlocals.iter().map(|x| x.clone()).collect()));
2273
- }
2274
- if !globals.is_empty() {
2275
- py_body.push(a.global(globals.iter().map(|x| x.clone()).collect()));
2276
- }
2244
+ let (py_bindings, nonlocals, _globals) = py_fn_bindings(ctx, memo_captures, span)?;
2277
2245
 
2246
+ py_body.extend(py_bindings);
2278
2247
  py_body.extend(py_expr.pre);
2279
2248
  py_body.push(a.return_(py_expr.value));
2280
2249
 
@@ -2430,6 +2399,47 @@ impl<'src, 'ast> SExprExt<'src, 'ast> for SExpr<'src> {
2430
2399
  }
2431
2400
  }
2432
2401
 
2402
+ fn py_fn_bindings<'src, 'ast>(
2403
+ ctx: &mut TlCtx<'src, 'ast>,
2404
+ memo_captures: &FnInfo,
2405
+ span: Span,
2406
+ ) -> TlResult<(PyBlock<'src>, Vec<PyIdent<'src>>, Vec<PyIdent<'src>>)> {
2407
+ let a = PyAstBuilder::new(span);
2408
+
2409
+ let mut nonlocals = vec![];
2410
+ let mut globals = vec![];
2411
+ let mut py_body = PyBlock::new();
2412
+
2413
+ for capture in memo_captures.captures.iter() {
2414
+ let mut scope = &ctx.scopes[ctx.declarations[*capture].scope];
2415
+ loop {
2416
+ if scope.parent.is_null() {
2417
+ break;
2418
+ }
2419
+
2420
+ if scope.is_fn || scope.is_class || scope.is_global {
2421
+ break;
2422
+ }
2423
+ scope = &ctx.scopes[scope.parent];
2424
+ }
2425
+
2426
+ if scope.is_global || scope.is_class {
2427
+ globals.push(ctx.decl_py_ident(*capture)?);
2428
+ } else {
2429
+ nonlocals.push(ctx.decl_py_ident(*capture)?);
2430
+ }
2431
+ }
2432
+
2433
+ if !nonlocals.is_empty() {
2434
+ py_body.push(a.nonlocal(nonlocals.iter().map(|x| x.clone()).collect()));
2435
+ }
2436
+ if !globals.is_empty() {
2437
+ py_body.push(a.global(globals.iter().map(|x| x.clone()).collect()));
2438
+ }
2439
+
2440
+ Ok((py_body, nonlocals, globals))
2441
+ }
2442
+
2433
2443
  pub struct TransformOutput<'src> {
2434
2444
  pub py_block: PyBlock<'src>,
2435
2445
  pub exports: Vec<PyIdent<'src>>,
@@ -1,6 +1,6 @@
1
1
  import collections.defaultdict
2
2
  import functools.wraps
3
- import .result.Ok
3
+ import .result.(Result, Ok)
4
4
  import .Monad
5
5
 
6
6
  export Memo = class(Monad):
@@ -11,7 +11,8 @@ export Memo = class(Monad):
11
11
  __repr__ = self => f"Memo.Cache({self.cache})"
12
12
 
13
13
  try_get = (self, name, deps) =>
14
- try self.cache[name][deps] except KeyError()
14
+ # TODO should try operator return a Result directly?
15
+ Result(try self.cache[name][deps] except KeyError())
15
16
 
16
17
  update = (self, name, deps, value) =>
17
18
  self.cache[name][deps] = value
@@ -23,7 +24,7 @@ export Memo = class(Monad):
23
24
 
24
25
  value = staticmethod& (id, deps, f) =>
25
26
  Memo(ctx =>
26
- if ctx.try_get(id, tuple(deps)) matches Ok() as value:
27
+ if ctx.try_get(id, tuple(deps)) matches Ok(value):
27
28
  return value
28
29
 
29
30
  ctx.update(id, tuple(deps), f())
@@ -34,7 +35,7 @@ export Memo = class(Monad):
34
35
  let deps = (tuple(args), tuple(kwargs.items()))
35
36
 
36
37
  Memo(ctx =>
37
- if ctx.try_get(id, deps) matches Ok() as value:
38
+ if ctx.try_get(id, deps) matches Ok(value):
38
39
  return value
39
40
 
40
41
  let v = f(*args, **kwargs)
@@ -1,6 +1,8 @@
1
1
  import abc
2
2
 
3
3
  export Monad = class(abc.ABC):
4
+ __slots__ = ()
5
+
4
6
  # The default implementation required for `@` syntax that should be overridden by subclasses.
5
7
  bind_once = abc.abstractmethod& (self, f) => None
6
8
 
@@ -0,0 +1,131 @@
1
+ import functools.wraps
2
+ import .monad.Monad
3
+ import koatl.runtime.virtual.register_global_attr
4
+
5
+ export Result = class:
6
+ __slots__ = ()
7
+ __match_args__ = ("value",)
8
+
9
+ __new__ = (cls, value) =>
10
+ if isinstance(value, Result):
11
+ return value
12
+ value.ok then Ok(value) else Err(value)
13
+
14
+ __init__ = (self, *args, **kwargs) =>
15
+ raise ValueError("Result should not be instantiated directly, use Ok or Err")
16
+
17
+ raw = self =>
18
+ """
19
+ Unwraps the value from a Result, making it look like
20
+ a non-monadic Python value.
21
+ """
22
+ if self matches not Result():
23
+ return self
24
+
25
+ if self.ok:
26
+ if self.value.ok:
27
+ return self.value
28
+ else:
29
+ return self
30
+ else:
31
+ if self.value.ok:
32
+ return self
33
+ else:
34
+ return self.value
35
+
36
+ bind_once = (self, f) =>
37
+ self = Result(self)
38
+ if not self.ok:
39
+ return self
40
+
41
+ let v = Result(f(self.value))
42
+
43
+ bind = bind_once
44
+
45
+ bind_gen = (self, gen) =>
46
+ self = Result(self)
47
+ try:
48
+ while True:
49
+ if not self.ok:
50
+ return self
51
+
52
+ self = Result(gen.send(self.value))
53
+ except StopIteration(value=value):
54
+ return Result.pure(value)
55
+
56
+ pure = staticmethod& x => Ok(x)
57
+
58
+ apply = (self, f) =>
59
+ self = Result(self)
60
+ f = Result(f)
61
+
62
+ if not self.ok:
63
+ return self
64
+ if not f.ok:
65
+ return f
66
+
67
+ Ok(f(self))
68
+
69
+ map = (self, f) =>
70
+ self = Result(self)
71
+ if self.ok:
72
+ return Ok(f(self.value))
73
+ return self
74
+
75
+ map_err = (self, f) =>
76
+ self = Result(self)
77
+ if not self.ok:
78
+ return Err(f(self.value))
79
+ return self
80
+
81
+ map_none = (self, f) =>
82
+ self = Result(self)
83
+ if not self.ok and self.value === None:
84
+ return Err(f())
85
+ return self
86
+
87
+ export Ok = class(Result):
88
+ __slots__ = ("value",)
89
+ ok = True
90
+ __new__ = (cls, value) => object.__new__(cls)
91
+ __init__ = (self, value) =>
92
+ if hasattr(self, "value"):
93
+ # This is necessary to prevent overwriting the value
94
+ # since Python's Result.__new__ will call Ok.__init__ again
95
+ # if the object is already created.
96
+ return None
97
+ self.value = value
98
+
99
+ __repr__ = self => f"Ok({repr(self.value)})"
100
+ unwrap = self => self.value
101
+
102
+ export Err = class(Result):
103
+ __slots__ = ("value",)
104
+ ok = False
105
+ __new__ = (cls, value) => object.__new__(cls)
106
+ __init__ = (self, value) =>
107
+ if hasattr(self, "value"):
108
+ return None
109
+ self.value = value
110
+
111
+ __repr__ = self => f"Err({repr(self.value)})"
112
+ unwrap = self =>
113
+ if self.value matches BaseException():
114
+ raise self.value
115
+ raise ValueError(f"Expected Ok, got {repr(self.value)}")
116
+
117
+
118
+ # Provide a default implementation for *most* Result methods
119
+ # ...we shouldn't provide a default for `map` since that
120
+ # would prevent virtual trait lookup. TODO: fix this?
121
+ for name, method in Result.__dict__:
122
+ if name.startswith("_"):
123
+ continue
124
+ if name == "map":
125
+ continue
126
+
127
+ let make_closure = method => (self, *args, **kwargs) => Result.raw(method(self, *args, **kwargs))
128
+
129
+ register_global_attr(object, name, make_closure(method))
130
+
131
+ register_global_attr(object, "ok", ExtensionProperty(__tl__.ok))
@@ -46,6 +46,11 @@ def unpack_record(obj):
46
46
 
47
47
 
48
48
  def ok(obj):
49
+ try:
50
+ return obj.ok
51
+ except AttributeError:
52
+ pass
53
+
49
54
  if obj is None:
50
55
  return False
51
56
  if isinstance(obj, BaseException):
@@ -1,90 +0,0 @@
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 = bind_once
12
-
13
- bind_gen = (self, gen) =>
14
- try:
15
- while True:
16
- if not __tl__.ok(self):
17
- return self
18
-
19
- if self matches Ok(value):
20
- self = value
21
-
22
- self = gen.send(self)
23
- except StopIteration(value=value):
24
- if value === None:
25
- return Ok(None)
26
- return value
27
-
28
- pure = staticmethod& x => Ok(x)
29
-
30
- apply = (self, f) =>
31
- if not __tl__.ok(self):
32
- return self
33
- if not __tl__.ok(f):
34
- return f
35
-
36
- # unwrap the Oks - this is a bit weird
37
- # but it allows bare types to be Results
38
- if self matches Ok(value):
39
- self = self.value
40
- if f matches Ok(value):
41
- f = f.value
42
-
43
- f(self)
44
-
45
- # Map must not be defined since it will override any special map
46
- # implementation for traits, specifically for Iterable -
47
- # is there a better way around this (in the vtable implementation)?
48
- # map = ...
49
-
50
- map_err = (self, f) =>
51
- if self matches Err():
52
- return f(self)
53
- else:
54
- return self
55
-
56
- map_none = (self, f) =>
57
- if self matches None:
58
- return f()
59
- else:
60
- return self
61
-
62
- OkMeta = class(type):
63
- __instancecheck__ = (cls, instance) => __tl__.ok(instance)
64
-
65
- export Ok = class(metaclass=OkMeta):
66
- __match_args__ = ("value",)
67
-
68
- __init__ = (self, value) =>
69
- self.value = value
70
-
71
- assert = staticmethod& value =>
72
- value match:
73
- BaseException() as e => raise e
74
- None => raise ValueError("Expected a value, got None")
75
- default value
76
-
77
-
78
- # Since we are using a custom metaclass, we can't derive from Result
79
- # so need to copy the methods over manually from Result
80
-
81
- # We could just use the object fallback methods, but this avoids
82
- # the vget so is slightly faster
83
- for name, method in Result.__dict__:
84
- if name.startswith("_"):
85
- continue
86
-
87
- setattr(Ok, name, method)
88
- register_global_attr(object, name, method)
89
-
90
- export Err = BaseException
@@ -1,90 +0,0 @@
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 = bind_once
12
-
13
- bind_gen = (self, gen) =>
14
- try:
15
- while True:
16
- if not __tl__.ok(self):
17
- return self
18
-
19
- if self matches Ok(value):
20
- self = value
21
-
22
- self = gen.send(self)
23
- except StopIteration(value=value):
24
- if value === None:
25
- return Ok(None)
26
- return value
27
-
28
- pure = staticmethod& x => Ok(x)
29
-
30
- apply = (self, f) =>
31
- if not __tl__.ok(self):
32
- return self
33
- if not __tl__.ok(f):
34
- return f
35
-
36
- # unwrap the Oks - this is a bit weird
37
- # but it allows bare types to be Results
38
- if self matches Ok(value):
39
- self = self.value
40
- if f matches Ok(value):
41
- f = f.value
42
-
43
- f(self)
44
-
45
- # Map must not be defined since it will override any special map
46
- # implementation for traits, specifically for Iterable -
47
- # is there a better way around this (in the vtable implementation)?
48
- # map = ...
49
-
50
- map_err = (self, f) =>
51
- if self matches Err():
52
- return f(self)
53
- else:
54
- return self
55
-
56
- map_none = (self, f) =>
57
- if self matches None:
58
- return f()
59
- else:
60
- return self
61
-
62
- OkMeta = class(type):
63
- __instancecheck__ = (cls, instance) => __tl__.ok(instance)
64
-
65
- export Ok = class(metaclass=OkMeta):
66
- __match_args__ = ("value",)
67
-
68
- __init__ = (self, value) =>
69
- self.value = value
70
-
71
- assert = staticmethod& value =>
72
- value match:
73
- BaseException() as e => raise e
74
- None => raise ValueError("Expected a value, got None")
75
- default value
76
-
77
-
78
- # Since we are using a custom metaclass, we can't derive from Result
79
- # so need to copy the methods over manually from Result
80
-
81
- # We could just use the object fallback methods, but this avoids
82
- # the vget so is slightly faster
83
- for name, method in Result.__dict__:
84
- if name.startswith("_"):
85
- continue
86
-
87
- setattr(Ok, name, method)
88
- register_global_attr(object, name, method)
89
-
90
- export Err = BaseException
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes