koatl 0.1.20__tar.gz → 0.1.22__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 (111) hide show
  1. {koatl-0.1.20 → koatl-0.1.22}/Cargo.lock +1 -1
  2. {koatl-0.1.20 → koatl-0.1.22}/PKG-INFO +1 -1
  3. {koatl-0.1.20 → koatl-0.1.22}/koatl/Cargo.toml +1 -1
  4. {koatl-0.1.20 → koatl-0.1.22/koatl}/python/koatl/prelude/functional/memo.tl +23 -14
  5. {koatl-0.1.20 → koatl-0.1.22}/koatl/python/koatl/runtime/helpers.py +1 -1
  6. {koatl-0.1.20 → koatl-0.1.22}/koatl-core/Cargo.toml +4 -0
  7. {koatl-0.1.20 → koatl-0.1.22}/koatl-core/parser/src/ast.rs +0 -1
  8. {koatl-0.1.20 → koatl-0.1.22}/koatl-core/parser/src/parser.rs +251 -211
  9. {koatl-0.1.20 → koatl-0.1.22}/koatl-core/src/inference.rs +0 -1
  10. {koatl-0.1.20 → koatl-0.1.22}/koatl-core/src/main.rs +0 -2
  11. koatl-0.1.22/koatl-core/src/parse_timer.rs +35 -0
  12. {koatl-0.1.20 → koatl-0.1.22}/koatl-core/src/resolve_scopes.rs +0 -15
  13. {koatl-0.1.20 → koatl-0.1.22}/koatl-core/src/transform.rs +22 -14
  14. {koatl-0.1.20/koatl → koatl-0.1.22}/python/koatl/prelude/functional/memo.tl +23 -14
  15. {koatl-0.1.20 → koatl-0.1.22}/python/koatl/runtime/helpers.py +1 -1
  16. {koatl-0.1.20 → koatl-0.1.22}/Cargo.toml +0 -0
  17. {koatl-0.1.20 → koatl-0.1.22}/README.md +0 -0
  18. {koatl-0.1.20 → koatl-0.1.22}/koatl/.github/workflows/CI.yml +0 -0
  19. {koatl-0.1.20 → koatl-0.1.22}/koatl/.gitignore +0 -0
  20. {koatl-0.1.20 → koatl-0.1.22}/koatl/LICENSE +0 -0
  21. {koatl-0.1.20 → koatl-0.1.22}/koatl/README.md +0 -0
  22. {koatl-0.1.20 → koatl-0.1.22}/koatl/python/koatl/__init__.py +0 -0
  23. {koatl-0.1.20 → koatl-0.1.22}/koatl/python/koatl/__main__.py +0 -0
  24. {koatl-0.1.20 → koatl-0.1.22}/koatl/python/koatl/cli.py +0 -0
  25. {koatl-0.1.20 → koatl-0.1.22}/koatl/python/koatl/notebook/__init__.py +0 -0
  26. {koatl-0.1.20 → koatl-0.1.22}/koatl/python/koatl/notebook/magic.py +0 -0
  27. {koatl-0.1.20 → koatl-0.1.22}/koatl/python/koatl/prelude/__init__.tl +0 -0
  28. {koatl-0.1.20 → koatl-0.1.22}/koatl/python/koatl/prelude/functional/__init__.tl +0 -0
  29. {koatl-0.1.20 → koatl-0.1.22}/koatl/python/koatl/prelude/functional/async.tl +0 -0
  30. {koatl-0.1.20 → koatl-0.1.22}/koatl/python/koatl/prelude/functional/async_util.py +0 -0
  31. {koatl-0.1.20 → koatl-0.1.22}/koatl/python/koatl/prelude/functional/monad.tl +0 -0
  32. {koatl-0.1.20 → koatl-0.1.22}/koatl/python/koatl/prelude/functional/reader.tl +0 -0
  33. {koatl-0.1.20 → koatl-0.1.22}/koatl/python/koatl/prelude/functional/result.tl +0 -0
  34. {koatl-0.1.20 → koatl-0.1.22}/koatl/python/koatl/prelude/iterable.tl +0 -0
  35. {koatl-0.1.20 → koatl-0.1.22}/koatl/python/koatl/runtime/__init__.py +0 -0
  36. {koatl-0.1.20 → koatl-0.1.22}/koatl/python/koatl/runtime/meta_finder.py +0 -0
  37. {koatl-0.1.20 → koatl-0.1.22}/koatl/python/koatl/runtime/record.py +0 -0
  38. {koatl-0.1.20 → koatl-0.1.22}/koatl/python/koatl/runtime/virtual.py +0 -0
  39. {koatl-0.1.20 → koatl-0.1.22}/koatl/requirements.txt +0 -0
  40. {koatl-0.1.20 → koatl-0.1.22}/koatl/src/emit_py.rs +0 -0
  41. {koatl-0.1.20 → koatl-0.1.22}/koatl/src/lib.rs +0 -0
  42. {koatl-0.1.20 → koatl-0.1.22}/koatl/tests/e2e/base/coal.tl +0 -0
  43. {koatl-0.1.20 → koatl-0.1.22}/koatl/tests/e2e/base/containers.tl +0 -0
  44. {koatl-0.1.20 → koatl-0.1.22}/koatl/tests/e2e/base/decorators.tl +0 -0
  45. {koatl-0.1.20 → koatl-0.1.22}/koatl/tests/e2e/base/destructure-for-and-fn.tl +0 -0
  46. {koatl-0.1.20 → koatl-0.1.22}/koatl/tests/e2e/base/destructure.tl +0 -0
  47. {koatl-0.1.20 → koatl-0.1.22}/koatl/tests/e2e/base/escape_ident.tl +0 -0
  48. {koatl-0.1.20 → koatl-0.1.22}/koatl/tests/e2e/base/fstr.tl +0 -0
  49. {koatl-0.1.20 → koatl-0.1.22}/koatl/tests/e2e/base/functions.tl +0 -0
  50. {koatl-0.1.20 → koatl-0.1.22}/koatl/tests/e2e/base/generator.tl +0 -0
  51. {koatl-0.1.20 → koatl-0.1.22}/koatl/tests/e2e/base/if_expr.tl +0 -0
  52. {koatl-0.1.20 → koatl-0.1.22}/koatl/tests/e2e/base/imports.tl +0 -0
  53. {koatl-0.1.20 → koatl-0.1.22}/koatl/tests/e2e/base/loops.tl +0 -0
  54. {koatl-0.1.20 → koatl-0.1.22}/koatl/tests/e2e/base/match.tl +0 -0
  55. {koatl-0.1.20 → koatl-0.1.22}/koatl/tests/e2e/base/nary-list.tl +0 -0
  56. {koatl-0.1.20 → koatl-0.1.22}/koatl/tests/e2e/base/placeholder.tl +0 -0
  57. {koatl-0.1.20 → koatl-0.1.22}/koatl/tests/e2e/base/precedence.tl +0 -0
  58. {koatl-0.1.20 → koatl-0.1.22}/koatl/tests/e2e/base/scopes.tl +0 -0
  59. {koatl-0.1.20 → koatl-0.1.22}/koatl/tests/e2e/base/semantic_whitespace.tl +0 -0
  60. {koatl-0.1.20 → koatl-0.1.22}/koatl/tests/e2e/base/slice.tl +0 -0
  61. {koatl-0.1.20 → koatl-0.1.22}/koatl/tests/e2e/base/try.tl +0 -0
  62. {koatl-0.1.20 → koatl-0.1.22}/koatl/tests/e2e/destructure.tl +0 -0
  63. {koatl-0.1.20 → koatl-0.1.22}/koatl/tests/e2e/prelude/async.tl +0 -0
  64. {koatl-0.1.20 → koatl-0.1.22}/koatl/tests/e2e/prelude/iterables.tl +0 -0
  65. {koatl-0.1.20 → koatl-0.1.22}/koatl/tests/e2e/prelude/memo.tl +0 -0
  66. {koatl-0.1.20 → koatl-0.1.22}/koatl/tests/e2e/prelude/reader.tl +0 -0
  67. {koatl-0.1.20 → koatl-0.1.22}/koatl/tests/e2e/prelude/result.tl +0 -0
  68. {koatl-0.1.20 → koatl-0.1.22}/koatl/tests/e2e/prelude/virtual.tl +0 -0
  69. {koatl-0.1.20 → koatl-0.1.22}/koatl/tests/e2e/util/__init__.py +0 -0
  70. {koatl-0.1.20 → koatl-0.1.22}/koatl/tests/e2e/util/module0.tl +0 -0
  71. {koatl-0.1.20 → koatl-0.1.22}/koatl/tests/e2e/util/module1.tl +0 -0
  72. {koatl-0.1.20 → koatl-0.1.22}/koatl/tests/e2e/util/module2.tl +0 -0
  73. {koatl-0.1.20 → koatl-0.1.22}/koatl/tests/parse/arith.tl +0 -0
  74. {koatl-0.1.20 → koatl-0.1.22}/koatl/tests/parse/assign.tl +0 -0
  75. {koatl-0.1.20 → koatl-0.1.22}/koatl/tests/parse/block-comments.tl +0 -0
  76. {koatl-0.1.20 → koatl-0.1.22}/koatl/tests/parse/deco.tl +0 -0
  77. {koatl-0.1.20 → koatl-0.1.22}/koatl/tests/parse/func.tl +0 -0
  78. {koatl-0.1.20 → koatl-0.1.22}/koatl/tests/parse/matches.tl +0 -0
  79. {koatl-0.1.20 → koatl-0.1.22}/koatl/tests/test_e2e.py +0 -0
  80. {koatl-0.1.20 → koatl-0.1.22}/koatl/tests/test_parse.py +0 -0
  81. {koatl-0.1.20 → koatl-0.1.22}/koatl-core/parser/Cargo.toml +0 -0
  82. {koatl-0.1.20 → koatl-0.1.22}/koatl-core/parser/src/lexer.rs +0 -0
  83. {koatl-0.1.20 → koatl-0.1.22}/koatl-core/parser/src/lib.rs +0 -0
  84. {koatl-0.1.20 → koatl-0.1.22}/koatl-core/parser/src/util.rs +0 -0
  85. {koatl-0.1.20 → koatl-0.1.22}/koatl-core/parser/tests/lexer.rs +0 -0
  86. {koatl-0.1.20 → koatl-0.1.22}/koatl-core/src/lib.rs +0 -0
  87. {koatl-0.1.20 → koatl-0.1.22}/koatl-core/src/parser.rs +0 -0
  88. {koatl-0.1.20 → koatl-0.1.22}/koatl-core/src/py/ast.rs +0 -0
  89. {koatl-0.1.20 → koatl-0.1.22}/koatl-core/src/py/emit.rs +0 -0
  90. {koatl-0.1.20 → koatl-0.1.22}/koatl-core/src/py/mod.rs +0 -0
  91. {koatl-0.1.20 → koatl-0.1.22}/koatl-core/src/py/util.rs +0 -0
  92. {koatl-0.1.20 → koatl-0.1.22}/koatl-core/src/types.rs +0 -0
  93. {koatl-0.1.20 → koatl-0.1.22}/koatl-core/src/util.rs +0 -0
  94. {koatl-0.1.20 → koatl-0.1.22}/pyproject.toml +0 -0
  95. {koatl-0.1.20 → koatl-0.1.22}/python/koatl/__init__.py +0 -0
  96. {koatl-0.1.20 → koatl-0.1.22}/python/koatl/__main__.py +0 -0
  97. {koatl-0.1.20 → koatl-0.1.22}/python/koatl/cli.py +0 -0
  98. {koatl-0.1.20 → koatl-0.1.22}/python/koatl/notebook/__init__.py +0 -0
  99. {koatl-0.1.20 → koatl-0.1.22}/python/koatl/notebook/magic.py +0 -0
  100. {koatl-0.1.20 → koatl-0.1.22}/python/koatl/prelude/__init__.tl +0 -0
  101. {koatl-0.1.20 → koatl-0.1.22}/python/koatl/prelude/functional/__init__.tl +0 -0
  102. {koatl-0.1.20 → koatl-0.1.22}/python/koatl/prelude/functional/async.tl +0 -0
  103. {koatl-0.1.20 → koatl-0.1.22}/python/koatl/prelude/functional/async_util.py +0 -0
  104. {koatl-0.1.20 → koatl-0.1.22}/python/koatl/prelude/functional/monad.tl +0 -0
  105. {koatl-0.1.20 → koatl-0.1.22}/python/koatl/prelude/functional/reader.tl +0 -0
  106. {koatl-0.1.20 → koatl-0.1.22}/python/koatl/prelude/functional/result.tl +0 -0
  107. {koatl-0.1.20 → koatl-0.1.22}/python/koatl/prelude/iterable.tl +0 -0
  108. {koatl-0.1.20 → koatl-0.1.22}/python/koatl/runtime/__init__.py +0 -0
  109. {koatl-0.1.20 → koatl-0.1.22}/python/koatl/runtime/meta_finder.py +0 -0
  110. {koatl-0.1.20 → koatl-0.1.22}/python/koatl/runtime/record.py +0 -0
  111. {koatl-0.1.20 → koatl-0.1.22}/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.20"
102
+ version = "0.1.22"
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.20
3
+ Version: 0.1.22
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.20"
3
+ version = "0.1.22"
4
4
  edition = "2021"
5
5
 
6
6
  [lib]
@@ -8,37 +8,46 @@ export Memo = class(Monad):
8
8
  __init__ = self =>
9
9
  self.cache = defaultdict(dict)
10
10
 
11
- get_or_compute = (self, name, deps, f) =>
12
- if try self.cache[name][deps] except KeyError() matches (Ok() as v):
13
- return v
11
+ __repr__ = self => f"Memo.Cache({self.cache})"
12
+
13
+ try_get = (self, name, deps) =>
14
+ try self.cache[name][deps] except KeyError()
14
15
 
15
- let value = f()
16
+ update = (self, name, deps, value) =>
16
17
  self.cache[name][deps] = value
17
18
  value
18
19
 
19
- __repr__ = self => f"Memo.Cache({self.cache})"
20
-
21
20
  __init__ = (self, f) => self.f = f
22
21
 
23
22
  __repr__ = self => f"Memo(...)"
24
23
 
25
24
  value = staticmethod& (id, deps, f) =>
26
- Memo(ctx => ctx.get_or_compute(id, tuple(deps), f))
25
+ Memo(ctx =>
26
+ if ctx.try_get(id, tuple(deps)) matches Ok() as value:
27
+ return value
28
+
29
+ ctx.update(id, tuple(deps), f())
30
+ )
27
31
 
28
32
  fn = staticmethod& f => wraps(f)& (*args, **kwargs) =>
29
33
  let id = f"{f.__module__}.{f.__qualname__}"
30
34
  let deps = (tuple(args), tuple(kwargs.items()))
31
35
 
32
36
  Memo(ctx =>
33
- ctx.get_or_compute(id, deps, () =>
34
- let v = f(*args, **kwargs)
35
- if v matches Memo():
36
- v = v.run(ctx)
37
- v
38
- )
37
+ if ctx.try_get(id, deps) matches Ok() as value:
38
+ return value
39
+
40
+ let v = f(*args, **kwargs)
41
+ if v matches Memo():
42
+ v = v.run(ctx)
43
+
44
+ ctx.update(id, deps, v)
39
45
  )
40
46
 
41
- run = (self, ctx=Cache()) => self.f(ctx)
47
+ run = (self, ctx=None) =>
48
+ if ctx === None:
49
+ ctx = Memo.Cache()
50
+ self.f(ctx)
42
51
 
43
52
  pure = staticmethod& value => Memo(ctx => value)
44
53
 
@@ -76,7 +76,7 @@ def do(f):
76
76
 
77
77
  try:
78
78
  # TODO: this is a workaround to avoid recursion.
79
- # is it possible to get bind_gen directly from bind_once?
79
+ # is it possible to derive bind_gen directly from bind_once?
80
80
 
81
81
  return vget(m, "bind_gen")(gen)
82
82
  except (NotImplementedError, AttributeError):
@@ -8,3 +8,7 @@ ariadne = "0.5.1"
8
8
  parser = { path = "parser" }
9
9
  once_cell = "1.19.0"
10
10
  slotmap = "1.0.7"
11
+
12
+ [[bin]]
13
+ name = "parse_timer"
14
+ path = "src/parse_timer.rs"
@@ -120,7 +120,6 @@ pub enum DeclType {
120
120
 
121
121
  #[derive(Debug, Clone)]
122
122
  pub enum Stmt<'a, TTree: Tree> {
123
- Module,
124
123
  Decl(Vec<SIdent<'a>>, DeclType),
125
124
  Assign(TTree::Expr, TTree::Expr, Option<DeclType>),
126
125
  Expr(TTree::Expr),
@@ -131,6 +131,7 @@ pub fn match_pattern<'tokens, 'src: 'tokens, TInput, PIdent, PQualIdent, PExpr,
131
131
  ) -> (
132
132
  impl Parser<'tokens, TInput, SPattern<'src>, TExtra<'tokens, 'src>> + Clone,
133
133
  impl Parser<'tokens, TInput, SPattern<'src>, TExtra<'tokens, 'src>> + Clone,
134
+ impl Parser<'tokens, TInput, SPattern<'src>, TExtra<'tokens, 'src>> + Clone,
134
135
  )
135
136
  where
136
137
  TInput: ValueInput<'tokens, Token = Token<'src>, Span = Span>,
@@ -311,7 +312,7 @@ where
311
312
 
312
313
  pattern.define(
313
314
  choice((
314
- as_pattern,
315
+ as_pattern.clone(),
315
316
  value_pattern,
316
317
  closed_pattern.clone(),
317
318
  symbol("_")
@@ -323,6 +324,7 @@ where
323
324
 
324
325
  (
325
326
  closed_pattern.labelled("pattern").as_context(),
327
+ as_pattern.labelled("pattern").as_context(),
326
328
  nary_sequence_pattern.labelled("pattern").as_context(),
327
329
  )
328
330
  }
@@ -475,6 +477,245 @@ where
475
477
  })
476
478
  }
477
479
 
480
+ pub fn statement<'tokens, 'src: 'tokens, TInput, PBody, PTuple, PExpr, PIdent, PPattern>(
481
+ expr_or_inline_stmt_or_block: PBody,
482
+ nary_tuple: PTuple,
483
+ expr: PExpr,
484
+ ident: PIdent,
485
+ nary_pattern: PPattern,
486
+ ) -> (
487
+ impl Parser<'tokens, TInput, SStmt<'src>, TExtra<'tokens, 'src>> + Clone,
488
+ impl Parser<'tokens, TInput, SStmt<'src>, TExtra<'tokens, 'src>> + Clone,
489
+ )
490
+ where
491
+ TInput: ValueInput<'tokens, Token = Token<'src>, Span = Span>,
492
+ PBody: Parser<'tokens, TInput, SExpr<'src>, TExtra<'tokens, 'src>> + Clone + 'tokens,
493
+ PTuple: Parser<'tokens, TInput, SExpr<'src>, TExtra<'tokens, 'src>> + Clone + 'tokens,
494
+ PExpr: Parser<'tokens, TInput, SExpr<'src>, TExtra<'tokens, 'src>> + Clone + 'tokens,
495
+ PIdent: Parser<'tokens, TInput, SIdent<'src>, TExtra<'tokens, 'src>> + Clone + 'tokens,
496
+ PPattern: Parser<'tokens, TInput, SPattern<'src>, TExtra<'tokens, 'src>> + Clone + 'tokens,
497
+ {
498
+ let mut stmt = Recursive::<chumsky::recursive::Indirect<TInput, SStmt, TExtra>>::declare();
499
+ let mut inline_stmt =
500
+ Recursive::<chumsky::recursive::Indirect<TInput, SStmt, TExtra>>::declare();
501
+
502
+ let decl_mod = choice((
503
+ just(Token::Kw("export")).to(DeclType::Export),
504
+ just(Token::Kw("global")).to(DeclType::Global),
505
+ just(Token::Kw("let")).to(DeclType::Let),
506
+ just(Token::Kw("const")).to(DeclType::Const),
507
+ ));
508
+
509
+ let decl_stmt = decl_mod
510
+ .clone()
511
+ .then(ident.clone().separated_by(symbol(",")).collect())
512
+ .map(|(decl, idents)| SStmtInner::Decl(idents, decl))
513
+ .boxed();
514
+
515
+ let assign_lhs = nary_tuple.clone();
516
+ let inline_assign_lhs = expr.clone();
517
+
518
+ let assign_stmt = group((
519
+ decl_mod.clone().or_not(),
520
+ assign_lhs.clone(),
521
+ symbol("=").ignore_then(nary_tuple.clone()),
522
+ ))
523
+ .map(|(decl, lhs, rhs)| SStmtInner::Assign(lhs.indirect(), rhs.indirect(), decl))
524
+ .boxed();
525
+
526
+ let inline_assign_stmt = group((
527
+ decl_mod.clone().or_not(),
528
+ inline_assign_lhs.clone(),
529
+ symbol("=").ignore_then(expr.clone()),
530
+ ))
531
+ .map(|(decl, lhs, rhs)| SStmtInner::Assign(lhs.indirect(), rhs.indirect(), decl))
532
+ .boxed();
533
+
534
+ let expr_stmt = assign_lhs
535
+ .clone()
536
+ .map(|x| SStmtInner::Expr(x.indirect()))
537
+ .boxed();
538
+
539
+ let inline_expr_stmt = inline_assign_lhs
540
+ .clone()
541
+ .map(|x| SStmtInner::Expr(x.indirect()))
542
+ .boxed();
543
+
544
+ let while_stmt = just(Token::Kw("while"))
545
+ .ignore_then(expr.clone())
546
+ .then_ignore(just(START_BLOCK))
547
+ .then(expr_or_inline_stmt_or_block.clone())
548
+ .map(|(cond, body)| SStmtInner::While(cond.indirect(), body.indirect()))
549
+ .labelled("while statement")
550
+ .boxed();
551
+
552
+ let except_block = just(Token::Eol)
553
+ .then(just(Token::Kw("except")))
554
+ .ignore_then(nary_pattern.clone().or_not())
555
+ .boxed()
556
+ .then(just(START_BLOCK).ignore_then(expr_or_inline_stmt_or_block.clone()))
557
+ .map(|(pattern, body)| SMatchCase {
558
+ pattern: pattern.map(|x| x.indirect()),
559
+ guard: None,
560
+ body: body.indirect(),
561
+ })
562
+ .labelled("except block")
563
+ .boxed();
564
+
565
+ let finally_block = one_of([Token::Eol])
566
+ .then(just(Token::Kw("finally")))
567
+ .then(just(START_BLOCK))
568
+ .ignore_then(expr_or_inline_stmt_or_block.clone())
569
+ .labelled("finally block")
570
+ .boxed();
571
+
572
+ let try_stmt = just(Token::Kw("try"))
573
+ .then(just(START_BLOCK))
574
+ .ignore_then(group((
575
+ expr_or_inline_stmt_or_block.clone(),
576
+ except_block.repeated().collect(),
577
+ finally_block.or_not(),
578
+ )))
579
+ .map(|(body, excepts, finally)| {
580
+ SStmtInner::Try(body.indirect(), excepts, finally.map(|x| x.indirect()))
581
+ })
582
+ .labelled("try statement")
583
+ .boxed();
584
+
585
+ let for_stmt = just(Token::Kw("for"))
586
+ .ignore_then(group((
587
+ nary_pattern.clone().then_ignore(just(Token::Kw("in"))),
588
+ expr.clone().then_ignore(just(START_BLOCK)),
589
+ expr_or_inline_stmt_or_block.clone(),
590
+ )))
591
+ .map(|(decl, iter, body)| {
592
+ SStmtInner::For(decl.indirect(), iter.indirect(), body.indirect())
593
+ })
594
+ .labelled("for statement")
595
+ .boxed();
596
+
597
+ let return_stmt = just(Token::Kw("return"))
598
+ .ignore_then(nary_tuple.clone())
599
+ .map(|x| SStmtInner::Return(x.indirect()))
600
+ .labelled("return statement")
601
+ .boxed();
602
+
603
+ let inline_return_stmt = just(Token::Kw("return"))
604
+ .ignore_then(expr.clone())
605
+ .map(|x| SStmtInner::Return(x.indirect()))
606
+ .labelled("inline return statement")
607
+ .boxed();
608
+
609
+ let assert_stmt = just(Token::Ident("assert"))
610
+ .ignore_then(expr.clone())
611
+ .then(symbol(",").ignore_then(expr.clone()).or_not())
612
+ .map(|(x, y)| SStmtInner::Assert(x.indirect(), y.map(|y| y.indirect())))
613
+ .labelled("assert statement")
614
+ .boxed();
615
+
616
+ let raise_stmt = just(Token::Kw("raise"))
617
+ .ignore_then(nary_tuple.clone().or_not())
618
+ .map(|x| SStmtInner::Raise(x.map(|x| x.indirect())))
619
+ .labelled("raise statement")
620
+ .boxed();
621
+
622
+ let inline_raise_stmt = just(Token::Kw("raise"))
623
+ .ignore_then(expr.clone().or_not())
624
+ .map(|x| SStmtInner::Raise(x.map(|x| x.indirect())))
625
+ .labelled("inline raise statement")
626
+ .boxed();
627
+
628
+ let break_stmt = just(Token::Kw("break"))
629
+ .map(|_| SStmtInner::Break)
630
+ .labelled("break statement")
631
+ .boxed();
632
+
633
+ let continue_stmt = just(Token::Kw("continue"))
634
+ .map(|_| SStmtInner::Continue)
635
+ .labelled("continue statement")
636
+ .boxed();
637
+
638
+ let import_stmt = just(Token::Kw("export"))
639
+ .to(1)
640
+ .or_not()
641
+ .then_ignore(just(Token::Kw("import")))
642
+ .then(group((
643
+ symbol(".").repeated().count(),
644
+ ident
645
+ .clone()
646
+ .then_ignore(symbol("."))
647
+ .repeated()
648
+ .collect()
649
+ .boxed(),
650
+ choice((
651
+ enumeration(
652
+ ident
653
+ .clone()
654
+ .then(just(Token::Kw("as")).ignore_then(ident.clone()).or_not()),
655
+ symbol(","),
656
+ )
657
+ .delimited_by_with_eol(symbol("("), symbol(")"))
658
+ .map(ImportList::Leaves)
659
+ .boxed(),
660
+ just(Token::Symbol("*")).map(|_| ImportList::Star),
661
+ ident
662
+ .clone()
663
+ .then(just(Token::Kw("as")).ignore_then(ident.clone()).or_not())
664
+ .map(|x| ImportList::Leaves(vec![x]))
665
+ .boxed(),
666
+ ))
667
+ .boxed(),
668
+ )))
669
+ .map(|(reexport, (level, trunk, import_list))| {
670
+ SStmtInner::Import(ImportStmt {
671
+ trunk,
672
+ imports: import_list,
673
+ level,
674
+ reexport: reexport.is_some(),
675
+ })
676
+ })
677
+ .labelled("import statement")
678
+ .boxed();
679
+
680
+ stmt.define(
681
+ choice((
682
+ decl_stmt.then_ignore(just(Token::Eol)),
683
+ assign_stmt.then_ignore(just(Token::Eol)),
684
+ expr_stmt.then_ignore(just(Token::Eol)),
685
+ while_stmt.clone().then_ignore(just(Token::Eol)),
686
+ for_stmt.clone().then_ignore(just(Token::Eol)),
687
+ return_stmt.then_ignore(just(Token::Eol)),
688
+ assert_stmt.then_ignore(just(Token::Eol)),
689
+ raise_stmt.then_ignore(just(Token::Eol)),
690
+ break_stmt.clone().then_ignore(just(Token::Eol)),
691
+ continue_stmt.clone().then_ignore(just(Token::Eol)),
692
+ import_stmt.then_ignore(just(Token::Eol)),
693
+ try_stmt.then_ignore(just(Token::Eol)),
694
+ ))
695
+ .labelled("statement")
696
+ .map_with(|x, e| x.spanned(e.span()))
697
+ .boxed(),
698
+ );
699
+
700
+ inline_stmt.define(
701
+ choice((
702
+ inline_assign_stmt,
703
+ inline_expr_stmt,
704
+ while_stmt,
705
+ for_stmt,
706
+ inline_return_stmt,
707
+ inline_raise_stmt,
708
+ break_stmt,
709
+ continue_stmt,
710
+ ))
711
+ .labelled("inline-statement")
712
+ .map_with(|x, e| x.spanned(e.span()))
713
+ .boxed(),
714
+ );
715
+
716
+ (stmt, inline_stmt)
717
+ }
718
+
478
719
  pub fn parser<'tokens, 'src: 'tokens, TInput>()
479
720
  -> impl Parser<'tokens, TInput, SExpr<'src>, TExtra<'tokens, 'src>> + Clone
480
721
  where
@@ -483,6 +724,7 @@ where
483
724
  let mut stmt = Recursive::<chumsky::recursive::Indirect<TInput, SStmt, TExtra>>::declare();
484
725
  let mut inline_stmt =
485
726
  Recursive::<chumsky::recursive::Indirect<TInput, SStmt, TExtra>>::declare();
727
+
486
728
  let mut atom = Recursive::<chumsky::recursive::Indirect<TInput, SExpr, TExtra>>::declare();
487
729
  let mut expr = Recursive::<chumsky::recursive::Indirect<TInput, SExpr, TExtra>>::declare();
488
730
  let mut unary = Recursive::<chumsky::recursive::Indirect<TInput, SExpr, TExtra>>::declare();
@@ -722,7 +964,7 @@ where
722
964
  )
723
965
  .boxed();
724
966
 
725
- let (closed_pattern, nary_pattern) = match_pattern(
967
+ let (closed_pattern, as_pattern, nary_pattern) = match_pattern(
726
968
  ident.clone(),
727
969
  qualified_ident.clone(),
728
970
  expr.clone(),
@@ -1113,7 +1355,7 @@ where
1113
1355
  .then(
1114
1356
  just(Token::Ident("matches"))
1115
1357
  .ignore_then(just(Token::Kw("not")).to(0).or_not())
1116
- .then(closed_pattern.clone())
1358
+ .then(as_pattern.clone())
1117
1359
  .or_not(),
1118
1360
  )
1119
1361
  .map_with(|(expr, matches_part), e| {
@@ -1181,218 +1423,16 @@ where
1181
1423
  binary6.labelled("expression").as_context().boxed(), // .memoized(),
1182
1424
  );
1183
1425
 
1184
- // Statements
1185
-
1186
- let decl_mod = choice((
1187
- just(Token::Kw("export")).to(DeclType::Export),
1188
- just(Token::Kw("global")).to(DeclType::Global),
1189
- just(Token::Kw("let")).to(DeclType::Let),
1190
- just(Token::Kw("const")).to(DeclType::Const),
1191
- ));
1192
-
1193
- let decl_stmt = decl_mod
1194
- .clone()
1195
- .then(ident.clone().separated_by(symbol(",")).collect())
1196
- .map(|(decl, idents)| SStmtInner::Decl(idents, decl))
1197
- .boxed();
1198
-
1199
- let assign_stmt = group((
1200
- decl_mod.clone().or_not(),
1426
+ let (stmt_, inline_stmt_) = statement(
1427
+ expr_or_inline_stmt_or_block.clone(),
1201
1428
  nary_tuple.clone(),
1202
- symbol("=").ignore_then(nary_tuple.clone()),
1203
- ))
1204
- .map(|(decl, lhs, rhs)| SStmtInner::Assign(lhs.indirect(), rhs.indirect(), decl))
1205
- .boxed();
1206
-
1207
- let inline_assign_stmt = group((
1208
- decl_mod.clone().or_not(),
1209
1429
  expr.clone(),
1210
- symbol("=").ignore_then(expr.clone()),
1211
- ))
1212
- .map(|(decl, lhs, rhs)| SStmtInner::Assign(lhs.indirect(), rhs.indirect(), decl))
1213
- .boxed();
1214
-
1215
- let expr_stmt = nary_tuple
1216
- .clone()
1217
- .map(|x| SStmtInner::Expr(x.indirect()))
1218
- .boxed();
1219
-
1220
- let inline_expr_stmt = expr.clone().map(|x| SStmtInner::Expr(x.indirect())).boxed();
1221
-
1222
- let while_stmt = just(Token::Kw("while"))
1223
- .ignore_then(expr.clone())
1224
- .then_ignore(just(START_BLOCK))
1225
- .then(expr_or_inline_stmt_or_block.clone())
1226
- .map(|(cond, body)| SStmtInner::While(cond.indirect(), body.indirect()))
1227
- .labelled("while statement")
1228
- .boxed();
1229
-
1230
- let except_block = just(Token::Eol)
1231
- .then(just(Token::Kw("except")))
1232
- .ignore_then(nary_pattern.clone().or_not())
1233
- .boxed()
1234
- .then(just(START_BLOCK).ignore_then(expr_or_inline_stmt_or_block.clone()))
1235
- .map(|(pattern, body)| SMatchCase {
1236
- pattern: pattern.map(|x| x.indirect()),
1237
- guard: None,
1238
- body: body.indirect(),
1239
- })
1240
- .labelled("except block")
1241
- .boxed();
1242
-
1243
- let finally_block = one_of([Token::Eol])
1244
- .then(just(Token::Kw("finally")))
1245
- .then(just(START_BLOCK))
1246
- .ignore_then(expr_or_inline_stmt_or_block.clone())
1247
- .labelled("finally block")
1248
- .boxed();
1249
-
1250
- let try_stmt = just(Token::Kw("try"))
1251
- .then(just(START_BLOCK))
1252
- .ignore_then(group((
1253
- expr_or_inline_stmt_or_block.clone(),
1254
- except_block.repeated().collect(),
1255
- finally_block.or_not(),
1256
- )))
1257
- .map(|(body, excepts, finally)| {
1258
- SStmtInner::Try(body.indirect(), excepts, finally.map(|x| x.indirect()))
1259
- })
1260
- .labelled("try statement")
1261
- .boxed();
1262
-
1263
- let for_stmt = just(Token::Kw("for"))
1264
- .ignore_then(group((
1265
- nary_pattern.clone().then_ignore(just(Token::Kw("in"))),
1266
- expr.clone().then_ignore(just(START_BLOCK)),
1267
- expr_or_inline_stmt_or_block.clone(),
1268
- )))
1269
- .map(|(decl, iter, body)| {
1270
- SStmtInner::For(decl.indirect(), iter.indirect(), body.indirect())
1271
- })
1272
- .labelled("for statement")
1273
- .boxed();
1274
-
1275
- let return_stmt = just(Token::Kw("return"))
1276
- .ignore_then(nary_tuple.clone())
1277
- .map(|x| SStmtInner::Return(x.indirect()))
1278
- .labelled("return statement")
1279
- .boxed();
1280
-
1281
- let inline_return_stmt = just(Token::Kw("return"))
1282
- .ignore_then(expr.clone())
1283
- .map(|x| SStmtInner::Return(x.indirect()))
1284
- .labelled("inline return statement")
1285
- .boxed();
1286
-
1287
- let assert_stmt = just(Token::Ident("assert"))
1288
- .ignore_then(expr.clone())
1289
- .then(symbol(",").ignore_then(expr.clone()).or_not())
1290
- .map(|(x, y)| SStmtInner::Assert(x.indirect(), y.map(|y| y.indirect())))
1291
- .labelled("assert statement")
1292
- .boxed();
1293
-
1294
- let raise_stmt = just(Token::Kw("raise"))
1295
- .ignore_then(nary_tuple.clone().or_not())
1296
- .map(|x| SStmtInner::Raise(x.map(|x| x.indirect())))
1297
- .labelled("raise statement")
1298
- .boxed();
1299
-
1300
- let inline_raise_stmt = just(Token::Kw("raise"))
1301
- .ignore_then(expr.clone().or_not())
1302
- .map(|x| SStmtInner::Raise(x.map(|x| x.indirect())))
1303
- .labelled("inline raise statement")
1304
- .boxed();
1305
-
1306
- let break_stmt = just(Token::Kw("break"))
1307
- .map(|_| SStmtInner::Break)
1308
- .labelled("break statement")
1309
- .boxed();
1310
-
1311
- let continue_stmt = just(Token::Kw("continue"))
1312
- .map(|_| SStmtInner::Continue)
1313
- .labelled("continue statement")
1314
- .boxed();
1315
-
1316
- let import_stmt = just(Token::Kw("export"))
1317
- .to(1)
1318
- .or_not()
1319
- .then_ignore(just(Token::Kw("import")))
1320
- .then(group((
1321
- symbol(".").repeated().count(),
1322
- ident
1323
- .clone()
1324
- .then_ignore(symbol("."))
1325
- .repeated()
1326
- .collect()
1327
- .boxed(),
1328
- choice((
1329
- enumeration(
1330
- ident
1331
- .clone()
1332
- .then(just(Token::Kw("as")).ignore_then(ident.clone()).or_not()),
1333
- symbol(","),
1334
- )
1335
- .delimited_by_with_eol(symbol("("), symbol(")"))
1336
- .map(ImportList::Leaves)
1337
- .boxed(),
1338
- just(Token::Symbol("*")).map(|_| ImportList::Star),
1339
- ident
1340
- .clone()
1341
- .then(just(Token::Kw("as")).ignore_then(ident.clone()).or_not())
1342
- .map(|x| ImportList::Leaves(vec![x]))
1343
- .boxed(),
1344
- ))
1345
- .boxed(),
1346
- )))
1347
- .map(|(reexport, (level, trunk, import_list))| {
1348
- SStmtInner::Import(ImportStmt {
1349
- trunk,
1350
- imports: import_list,
1351
- level,
1352
- reexport: reexport.is_some(),
1353
- })
1354
- })
1355
- .labelled("import statement")
1356
- .boxed();
1357
-
1358
- let module_stmt = just(Token::Kw("module")).map(|_| SStmtInner::Module);
1359
-
1360
- stmt.define(
1361
- choice((
1362
- decl_stmt.then_ignore(just(Token::Eol)),
1363
- assign_stmt.then_ignore(just(Token::Eol)),
1364
- expr_stmt.then_ignore(just(Token::Eol)),
1365
- module_stmt.then_ignore(just(Token::Eol)),
1366
- while_stmt.clone().then_ignore(just(Token::Eol)),
1367
- for_stmt.clone().then_ignore(just(Token::Eol)),
1368
- return_stmt.then_ignore(just(Token::Eol)),
1369
- assert_stmt.then_ignore(just(Token::Eol)),
1370
- raise_stmt.then_ignore(just(Token::Eol)),
1371
- break_stmt.clone().then_ignore(just(Token::Eol)),
1372
- continue_stmt.clone().then_ignore(just(Token::Eol)),
1373
- import_stmt.then_ignore(just(Token::Eol)),
1374
- try_stmt.then_ignore(just(Token::Eol)),
1375
- ))
1376
- .labelled("statement")
1377
- .map_with(|x, e| x.spanned(e.span()))
1378
- .boxed(),
1430
+ ident.clone(),
1431
+ nary_pattern.clone(),
1379
1432
  );
1380
1433
 
1381
- inline_stmt.define(
1382
- choice((
1383
- inline_assign_stmt,
1384
- inline_expr_stmt,
1385
- while_stmt,
1386
- for_stmt,
1387
- inline_return_stmt,
1388
- inline_raise_stmt,
1389
- break_stmt,
1390
- continue_stmt,
1391
- ))
1392
- .labelled("inline-statement")
1393
- .map_with(|x, e| x.spanned(e.span()))
1394
- .boxed(),
1395
- );
1434
+ stmt.define(stmt_.labelled("statement").boxed());
1435
+ inline_stmt.define(inline_stmt_.labelled("inline-statement").boxed());
1396
1436
 
1397
1437
  block.labelled("program")
1398
1438
  }
@@ -53,7 +53,6 @@ impl<'src, 'ast> SStmtExt<'src, 'ast> for Indirect<SStmt<'src>> {
53
53
  }
54
54
  Stmt::Raise(..) | Stmt::Return(..) | Stmt::Break | Stmt::Continue => Type::Bottom,
55
55
  Stmt::Import(..) => Type::NoReturn,
56
- Stmt::Module => Type::NoReturn,
57
56
  Stmt::Decl(..) => Type::NoReturn,
58
57
  }
59
58
  }
@@ -1,5 +1,3 @@
1
- #![allow(unused_variables)]
2
-
3
1
  use std::{
4
2
  io::Write,
5
3
  process::{Command, Stdio},
@@ -0,0 +1,35 @@
1
+ use std::time::Instant;
2
+
3
+ use koatl_core::parse_tl;
4
+
5
+ fn main() -> Result<(), Box<dyn std::error::Error>> {
6
+ let filename = std::env::args().nth(1).ok_or("Missing filename argument")?;
7
+ let src = std::fs::read_to_string(&filename).unwrap();
8
+
9
+ let now = Instant::now();
10
+
11
+ let n = 1000;
12
+
13
+ for _ in 0..n {
14
+ match parse_tl(&src) {
15
+ Ok(_) => {}
16
+ Err(errs) => {
17
+ errs.0.into_iter().for_each(|e| {
18
+ eprintln!("Error: {}", e.message);
19
+ if let Some(span) = e.span {
20
+ eprintln!("At span: {:?}", span);
21
+ }
22
+ });
23
+ return Err("Parsing failed".into());
24
+ }
25
+ }
26
+ }
27
+
28
+ println!(
29
+ "Parsed {} in {}us",
30
+ filename,
31
+ now.elapsed().as_nanos() as f64 / 1000.0 / n as f64
32
+ );
33
+
34
+ Ok(())
35
+ }
@@ -213,13 +213,6 @@ impl<'src> ResolveState<'src> {
213
213
  let placeholder_ctx = self.placeholder_stack.pop().unwrap();
214
214
 
215
215
  if placeholder_ctx.activated {
216
- if ph_fn_ctx.is_async || ph_fn_ctx.is_generator || ph_fn_ctx.is_do {
217
- self.errors.extend(simple_err(
218
- "Await, bind, and yield are not allowed in placeholder functions",
219
- placeholder_ctx.span,
220
- ));
221
- }
222
-
223
216
  ph_fn_ctx.is_placeholder = true;
224
217
 
225
218
  ph_fn_ctx.arg_names.push(placeholder_ctx.arg_decl);
@@ -1323,13 +1316,6 @@ impl<'src> SExprExt<'src> for Indirect<SExpr<'src>> {
1323
1316
 
1324
1317
  let fn_ctx = state.fn_stack.pop().unwrap();
1325
1318
 
1326
- if fn_ctx.is_async || fn_ctx.is_generator || fn_ctx.is_do {
1327
- state.errors.extend(simple_err(
1328
- "Memo expressions cannot be async, generator, or do",
1329
- span,
1330
- ));
1331
- }
1332
-
1333
1319
  state.memo_captures.insert(inner.as_ref().into(), fn_ctx);
1334
1320
 
1335
1321
  Expr::Memo(inner)
@@ -1555,7 +1541,6 @@ impl<'src> SStmtExt<'src> for Indirect<SStmt<'src>> {
1555
1541
  Stmt::Import(import_stmt)
1556
1542
  }
1557
1543
  Stmt::Break => Stmt::Break,
1558
- Stmt::Module => Stmt::Module,
1559
1544
  Stmt::Continue => Stmt::Continue,
1560
1545
  };
1561
1546
 
@@ -15,6 +15,7 @@ use crate::{
15
15
  use once_cell::sync::Lazy;
16
16
  use parser::ast::*;
17
17
  use slotmap::SlotMap;
18
+ use std::hash::{Hash, Hasher};
18
19
 
19
20
  static PY_KWS: &[&str] = &[
20
21
  "and", "as", "assert", "break", "class", "continue", "def", "del", "elif", "else", "except",
@@ -1978,12 +1979,6 @@ impl<'src> SStmtExt<'src> for SStmt<'src> {
1978
1979
  pre.push(a.import(aliases));
1979
1980
  };
1980
1981
  }
1981
- Stmt::Module => {
1982
- return Err(simple_err(
1983
- "Module statements are not allowed in the transform phase",
1984
- span,
1985
- ));
1986
- }
1987
1982
  };
1988
1983
 
1989
1984
  Ok(pre)
@@ -2285,20 +2280,26 @@ impl<'src, 'ast> SExprExt<'src, 'ast> for SExpr<'src> {
2285
2280
 
2286
2281
  let callback = pre.bind(make_fn_exp(
2287
2282
  ctx,
2288
- FnDef::PyFnDef(vec![], py_body, false, false),
2283
+ FnDef::PyFnDef(vec![], py_body, memo_captures.is_do, memo_captures.is_async),
2289
2284
  &span,
2290
2285
  )?);
2291
2286
 
2292
2287
  let linecol = ctx.line_cache.linecol(span.start);
2293
2288
 
2294
- a.yield_(a.call(
2289
+ let memo_call = a.call(
2295
2290
  a.tl_builtin("memo"),
2296
2291
  vec![
2297
- PyCallItem::Arg(
2298
- a.str(
2299
- format!("{}:{}:{}", ctx.filename, linecol.0, linecol.1)
2300
- )
2301
- ),
2292
+ PyCallItem::Arg(a.str(format!(
2293
+ "{}:{}:{}:{:08x}",
2294
+ ctx.filename,
2295
+ linecol.0,
2296
+ linecol.1,
2297
+ {
2298
+ let mut hasher = std::collections::hash_map::DefaultHasher::new();
2299
+ ctx.source[span.start..span.end].hash(&mut hasher);
2300
+ hasher.finish() as u32
2301
+ }
2302
+ ))),
2302
2303
  PyCallItem::Arg(
2303
2304
  a.tuple(
2304
2305
  nonlocals
@@ -2310,7 +2311,14 @@ impl<'src, 'ast> SExprExt<'src, 'ast> for SExpr<'src> {
2310
2311
  ),
2311
2312
  PyCallItem::Arg(callback),
2312
2313
  ],
2313
- ))
2314
+ );
2315
+
2316
+ if memo_captures.is_do {
2317
+ // TODO should we really automatically bind a monadic expression for convenience?
2318
+ a.yield_(a.yield_(memo_call))
2319
+ } else {
2320
+ a.yield_(memo_call)
2321
+ }
2314
2322
  }
2315
2323
  Expr::Await(expr) => a.await_(pre.bind(expr.transform(ctx)?)),
2316
2324
  Expr::Yield(expr) => a.yield_(pre.bind(expr.transform(ctx)?)),
@@ -8,37 +8,46 @@ export Memo = class(Monad):
8
8
  __init__ = self =>
9
9
  self.cache = defaultdict(dict)
10
10
 
11
- get_or_compute = (self, name, deps, f) =>
12
- if try self.cache[name][deps] except KeyError() matches (Ok() as v):
13
- return v
11
+ __repr__ = self => f"Memo.Cache({self.cache})"
12
+
13
+ try_get = (self, name, deps) =>
14
+ try self.cache[name][deps] except KeyError()
14
15
 
15
- let value = f()
16
+ update = (self, name, deps, value) =>
16
17
  self.cache[name][deps] = value
17
18
  value
18
19
 
19
- __repr__ = self => f"Memo.Cache({self.cache})"
20
-
21
20
  __init__ = (self, f) => self.f = f
22
21
 
23
22
  __repr__ = self => f"Memo(...)"
24
23
 
25
24
  value = staticmethod& (id, deps, f) =>
26
- Memo(ctx => ctx.get_or_compute(id, tuple(deps), f))
25
+ Memo(ctx =>
26
+ if ctx.try_get(id, tuple(deps)) matches Ok() as value:
27
+ return value
28
+
29
+ ctx.update(id, tuple(deps), f())
30
+ )
27
31
 
28
32
  fn = staticmethod& f => wraps(f)& (*args, **kwargs) =>
29
33
  let id = f"{f.__module__}.{f.__qualname__}"
30
34
  let deps = (tuple(args), tuple(kwargs.items()))
31
35
 
32
36
  Memo(ctx =>
33
- ctx.get_or_compute(id, deps, () =>
34
- let v = f(*args, **kwargs)
35
- if v matches Memo():
36
- v = v.run(ctx)
37
- v
38
- )
37
+ if ctx.try_get(id, deps) matches Ok() as value:
38
+ return value
39
+
40
+ let v = f(*args, **kwargs)
41
+ if v matches Memo():
42
+ v = v.run(ctx)
43
+
44
+ ctx.update(id, deps, v)
39
45
  )
40
46
 
41
- run = (self, ctx=Cache()) => self.f(ctx)
47
+ run = (self, ctx=None) =>
48
+ if ctx === None:
49
+ ctx = Memo.Cache()
50
+ self.f(ctx)
42
51
 
43
52
  pure = staticmethod& value => Memo(ctx => value)
44
53
 
@@ -76,7 +76,7 @@ def do(f):
76
76
 
77
77
  try:
78
78
  # TODO: this is a workaround to avoid recursion.
79
- # is it possible to get bind_gen directly from bind_once?
79
+ # is it possible to derive bind_gen directly from bind_once?
80
80
 
81
81
  return vget(m, "bind_gen")(gen)
82
82
  except (NotImplementedError, AttributeError):
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