3333from unpythonic .it import flatmap , uniqify , rev
3434from unpythonic .fun import curry as curryf , _currycall as currycall , identity
3535from unpythonic .dynscope import dyn
36- from unpythonic .lispylet import letrec as letrecf , let as letf , _dlet as dletf
36+ from unpythonic .lispylet import letrec as letrecf , let as letf , \
37+ _dlet as dletf , _blet as bletf
3738from unpythonic .seq import do as dof , begin as beginf
3839from unpythonic .fup import fupdate
3940from unpythonic .misc import namelambda
@@ -584,7 +585,7 @@ def count():
584585 **CAUTION**: assignment to the let environment is ``name << value``;
585586 the regular syntax ``name = value`` creates a local variable.
586587 """
587- return _dletimpl (tree , args , "let" , gen_sym )
588+ return _dletimpl (tree , args , "let" , "decorate" , gen_sym )
588589
589590@macros .decorator
590591def dletrec (tree , args , * , gen_sym , ** kw ):
@@ -601,11 +602,38 @@ def f(x):
601602
602603 Same cautions apply as to ``dlet``.
603604 """
604- return _dletimpl (tree , args , "letrec" , gen_sym )
605+ return _dletimpl (tree , args , "letrec" , "decorate" , gen_sym )
606+
607+ @macros .decorator
608+ def blet (tree , args , * , gen_sym , ** kw ):
609+ """[syntax, decorator] def --> let block.
610+
611+ Example::
612+
613+ @blet((x, 21))
614+ def result():
615+ return 2*x
616+ assert result == 42
617+ """
618+ return _dletimpl (tree , args , "let" , "call" , gen_sym )
619+ @macros .decorator
620+ def bletrec (tree , args , * , gen_sym , ** kw ):
621+ """[syntax, decorator] def --> letrec block.
622+
623+ Example::
624+
625+ @bletrec((evenp, lambda x: (x == 0) or oddp(x - 1)),
626+ (oddp, lambda x: (x != 0) and evenp(x - 1)))
627+ def result():
628+ return evenp(42)
629+ assert result is True
630+ """
631+ return _dletimpl (tree , args , "letrec" , "call" , gen_sym )
605632
606633# Very similar to _letimpl, but perhaps more readable to keep these separate.
607- def _dletimpl (tree , args , mode , gen_sym ):
634+ def _dletimpl (tree , args , mode , kind , gen_sym ):
608635 assert mode in ("let" , "letrec" )
636+ assert kind in ("decorate" , "call" )
609637
610638 if not args :
611639 return tree
@@ -621,8 +649,9 @@ def _dletimpl(tree, args, mode, gen_sym):
621649 values = [t1 (b ) for b in values ]
622650 tree = t2 (tree )
623651
652+ letter = dletf if kind == "decorate" else bletf
624653 binding_pairs = [q [(u [k ], ast_literal [v ])] for k , v in zip (names , values )]
625- tree .decorator_list = tree .decorator_list + [hq [dletf ((ast_literal [binding_pairs ],), mode = u [mode ], _envname = u [e ])]]
654+ tree .decorator_list = tree .decorator_list + [hq [letter ((ast_literal [binding_pairs ],), mode = u [mode ], _envname = u [e ])]]
626655 tree .args .kwonlyargs = tree .args .kwonlyargs + [arg (arg = e )]
627656 tree .args .kw_defaults = tree .args .kw_defaults + [None ]
628657 return tree
@@ -632,7 +661,34 @@ def dletseq(tree, args, gen_sym, **kw):
632661 """[syntax, decorator] Decorator version of letseq, for 'letseq over def'.
633662
634663 Expands to nested function definitions, each with one ``dlet`` decorator.
664+
665+ Example::
666+
667+ @dletseq((x, 1),
668+ (x, x+1),
669+ (x, x+2))
670+ def g(a):
671+ return a + x
672+ assert g(10) == 14
635673 """
674+ return _dletseqimpl (tree , args , "decorate" , gen_sym )
675+
676+ @macros .decorator
677+ def bletseq (tree , args , gen_sym , ** kw ):
678+ """[syntax, decorator] def --> letseq block.
679+
680+ Example::
681+
682+ @bletseq((x, 1),
683+ (x, x+1),
684+ (x, x+2))
685+ def result():
686+ return x
687+ assert result == 4
688+ """
689+ return _dletseqimpl (tree , args , "call" , gen_sym )
690+
691+ def _dletseqimpl (tree , args , kind , gen_sym ):
636692 # What we want:
637693 #
638694 # @dletseq((x, 1),
@@ -655,19 +711,21 @@ def dletseq(tree, args, gen_sym, **kw):
655711 # return g2()
656712 # assert g() == 4
657713 #
714+ assert kind in ("decorate" , "call" )
658715 if not args :
659716 return tree
660717
661718 userargs = tree .args # original arguments to the def
662719 fname = tree .name
663720 noargs = arguments (args = [], kwonlyargs = [], vararg = None , kwarg = None ,
664721 defaults = [], kw_defaults = [])
665- iname = gen_sym ("inner" )
722+ iname = gen_sym ("{}_inner" . format ( fname ) )
666723 tree .args = noargs
667724 tree .name = iname
668725
669726 * rest , last = args
670- innerdef = dlet .transform (tree , last )
727+ dletter = dlet if kind == "decorate" else blet
728+ innerdef = dletter .transform (tree , last )
671729
672730 # optimization: in the final step, no need to generate a wrapper function
673731 if not rest :
@@ -679,12 +737,13 @@ def dletseq(tree, args, gen_sym, **kw):
679737 innerdef .args .kw_defaults += tmpargs .kw_defaults
680738 return innerdef
681739
740+ ret = Return (value = q [name [iname ]()]) if kind == "decorate" else Return (value = q [name [iname ]])
682741 outer = FunctionDef (name = fname , args = userargs ,
683- body = [innerdef , Return ( value = q [ name [ iname ]()]) ],
742+ body = [innerdef , ret ],
684743 decorator_list = [],
685744 returns = None ) # no return type annotation
686745 outer = copy_location (outer , tree )
687- return dletseq . transform (outer , * rest )
746+ return _dletseqimpl (outer , rest , kind , gen_sym )
688747
689748# -----------------------------------------------------------------------------
690749
0 commit comments