From 4c205aba1e8d9f2db7d833e93cb147583031088e Mon Sep 17 00:00:00 2001 From: gilch Date: Sun, 21 May 2023 21:41:25 -0600 Subject: [PATCH] Change gensym format --- conftest.py | 6 +- docs/lissp_whirlwind_tour.rst | 212 +++++++++-------- docs/macro_tutorial.rst | 342 +++++++++++++-------------- docs/primer.rst | 37 ++- src/hissp/macros.lissp | 430 +++++++++++++++++----------------- src/hissp/reader.py | 32 ++- tests/test_macros.lissp | 2 +- tests/test_reader.py | 4 +- 8 files changed, 564 insertions(+), 501 deletions(-) diff --git a/conftest.py b/conftest.py index 7b9bee04..ea7ff17d 100644 --- a/conftest.py +++ b/conftest.py @@ -70,14 +70,14 @@ def evaluate(self, example, parser=Lissp()): def norm_gensym_eq(compiled, python): - """The special gensym prefix ``_QzNo..._`` will match regardless of number.""" + """The special gensym prefix ``_Qz...z_`` will match regardless of hash.""" return re.fullmatch( - re.sub(r"_QzNo\d+_", r"_QzNo\\d+_", re.escape(python)), compiled + re.sub(r"_Qz[A-Z2-7]+z_", r"_Qz[A-Z2-7]+z_", re.escape(python)), compiled ) def norm_gensyms(s): - s = re.sub(r"_QzNo\d+_", r"_QzNo000_", s) + s = re.sub(r"_Qz[A-Z2-7]+z_", r"_QzABCDEFGHz_", s) return indent(s, " " * 2).splitlines(True) diff --git a/docs/lissp_whirlwind_tour.rst b/docs/lissp_whirlwind_tour.rst index 0df01410..72c800e2 100644 --- a/docs/lissp_whirlwind_tour.rst +++ b/docs/lissp_whirlwind_tour.rst @@ -982,36 +982,47 @@ Lissp Whirlwind Tour ;;; Full qualification prevents accidental name collisions in - ;;; programmatically generated code. But full qualification doesn't work on - ;;; local variables, which can't be imported. For these, we use a template - ;;; count prefix instead of a qualifier to ensure a variable can only - ;;; be used in the same template it was defined in. The gensym reader - ;;; macro ($#) generates a symbol with the current template's number. - - #> `($#eggs $#spam $#bacon $#spam) ;Generated symbols for macro hygiene. + ;;; programmatically generated code. But full qualification doesn't work + ;;; on local variables, which can't be imported. For these, we use a + ;;; $# (gensym) which adds a prefix containing a hash of the code being + ;;; read, __name__, and a count of the templates the reader has seen, + ;;; instead of a qualifier to ensure a variable can only be used in the + ;;; same template it was defined in. + + #> `($#eggs $#spam $#bacon $#spam) >>> (lambda * _: _)( - ... '_QzNo9_eggs', - ... '_QzNo9_spam', - ... '_QzNo9_bacon', - ... '_QzNo9_spam') - ('_QzNo9_eggs', '_QzNo9_spam', '_QzNo9_bacon', '_QzNo9_spam') - - #> `$#spam ;Template number in name prevents collisions. - >>> '_QzNo10_spam' - '_QzNo10_spam' - - - ;; If you don't specify, by default, the template number is a prefix, + ... '_QzIWMX5OB2z_eggs', + ... '_QzIWMX5OB2z_spam', + ... '_QzIWMX5OB2z_bacon', + ... '_QzIWMX5OB2z_spam') + ('_QzIWMX5OB2z_eggs', '_QzIWMX5OB2z_spam', '_QzIWMX5OB2z_bacon', '_QzIWMX5OB2z_spam') + + ;; Each new template increases the count, so it results in a new hash, + #> `$#spam + >>> '_QzIOSOZAXYz_spam' + '_QzIOSOZAXYz_spam' + + ;; even if the code is identical. + #> `$#spam + >>> '_QzY6OWMZS7z_spam' + '_QzY6OWMZS7z_spam' + + ;;; However, the hashing procedure is fully deteministic, so builds are + ;;; reproducible even when they contain generated symbols. + + ;; If you don't specify, by default, the gensym hash is a prefix, ;; but you can put them anywhere in the symbol; $ marks the positions. - #> `$#spam$.$eggs$ ;Lacking a gensym prefix, it gets fully qualified. - >>> '__main__..spam_QzNo8_._QzNo8_eggs_QzNo8_' - '__main__..spam_QzNo8_._QzNo8_eggs_QzNo8_' + ;; Lacking a gensym prefix, it gets fully qualified by the template. + #> `$#spam$.$eggs$ + >>> '__main__..spam_QzA4IBV7J7z_._QzA4IBV7J7z_eggs_QzA4IBV7J7z_' + '__main__..spam_QzA4IBV7J7z_._QzA4IBV7J7z_eggs_QzA4IBV7J7z_' ;; This is typically used for partially-qualified variables. - #> `,'$#self.$foo ;Interpolation suppressed auto-qualification. - >>> 'self._QzNo9_foo' - 'self._QzNo9_foo' + ;; The interpolation suppressed auto-qualification. + #> `,'$#self.$foo + >>> 'self._Qz7UU6WAD6z_foo' + 'self._Qz7UU6WAD6z_foo' ;;; You can use templates to make collections with interpolated values. @@ -1328,25 +1339,25 @@ Lissp Whirlwind Tour ... 'lambda', ... (lambda * _: _)( ... ':', - ... '_QzNo22_x', + ... '_QzIF7WPGTUz_x', ... x), ... (lambda * _: _)( ... '__main__..QzMaybe_.QzPLUS_', - ... '_QzNo22_x', + ... '_QzIF7WPGTUz_x', ... (lambda * _: _)( ... '__main__..QzMaybe_.QzPLUS_', - ... '_QzNo22_x', - ... '_QzNo22_x')))))) + ... '_QzIF7WPGTUz_x', + ... '_QzIF7WPGTUz_x')))))) #> (once-triple (loud-number 14)) >>> # onceQz_triple - ... (lambda _QzNo22_x=loudQz_number( + ... (lambda _QzIF7WPGTUz_x=loudQz_number( ... (14)): ... __import__('builtins').globals()['QzPLUS_']( - ... _QzNo22_x, + ... _QzIF7WPGTUz_x, ... __import__('builtins').globals()['QzPLUS_']( - ... _QzNo22_x, - ... _QzNo22_x)))() + ... _QzIF7WPGTUz_x, + ... _QzIF7WPGTUz_x)))() 14 42 @@ -1872,12 +1883,13 @@ Lissp Whirlwind Tour ;;; passed in after the primary argument. #> (setattr _macro_ 'L\# en#list) ; (help _macro_.en\#) + #.. >>> setattr( ... _macro_, ... 'LQzHASH_', - ... (lambda *_QzNo84_xs: + ... (lambda *_Qz6RFWTTVXz_xs: ... list( - ... _QzNo84_xs))) + ... _Qz6RFWTTVXz_xs))) #> L#primary @@ -1891,37 +1903,38 @@ Lissp Whirlwind Tour ;; Alias can work on reader macros too! #> (hissp.._macro_.alias M: hissp.._macro_) ; prelude alternative + #.. >>> # hissp.._macro_.alias ... # hissp.macros.._macro_.defmacro ... # hissp.macros.._macro_.let - ... (lambda _QzNo7_fn=(lambda _QzNo27_prime,_QzNo27_reader=None,*_QzNo27_args:( + ... (lambda _QzAW22OE5Kz_fn=(lambda _QzARAQTXTEz_prime,_QzARAQTXTEz_reader=None,*_QzARAQTXTEz_args:( ... 'Aliases ``hissp.._macro_`` as ``MQzCOLON_#``.', ... # hissp.macros.._macro_.ifQz_else ... (lambda b,c,a:c()if b else a())( - ... _QzNo27_reader, + ... _QzARAQTXTEz_reader, ... (lambda : ... __import__('builtins').getattr( ... __import__('hissp')._macro_, ... ('{}{}').format( - ... _QzNo27_reader, + ... _QzARAQTXTEz_reader, ... # hissp.macros.._macro_.ifQz_else ... (lambda b,c,a:c()if b else a())( ... 'hissp.._macro_'.endswith( ... '._macro_'), ... (lambda :'QzHASH_'), ... (lambda :('')))))( - ... _QzNo27_prime, - ... *_QzNo27_args)), + ... _QzARAQTXTEz_prime, + ... *_QzARAQTXTEz_args)), ... (lambda : ... ('{}.{}').format( ... 'hissp.._macro_', - ... _QzNo27_prime))))[-1]):( + ... _QzARAQTXTEz_prime))))[-1]):( ... __import__('builtins').setattr( - ... _QzNo7_fn, + ... _QzAW22OE5Kz_fn, ... '__doc__', ... 'Aliases ``hissp.._macro_`` as ``MQzCOLON_#``.'), ... __import__('builtins').setattr( - ... _QzNo7_fn, + ... _QzAW22OE5Kz_fn, ... '__qualname__', ... ('.').join( ... ('_macro_', @@ -1931,7 +1944,7 @@ Lissp Whirlwind Tour ... __import__('builtins').globals(), ... '_macro_'), ... 'MQzCOLON_QzHASH_', - ... _QzNo7_fn))[-1])() + ... _QzAW22OE5Kz_fn))[-1])() #> M:#!b"Read-time b# via alias." ;Extra arg for alias with (!) >>> b'Read-time b# via alias.' @@ -2227,31 +2240,31 @@ Lissp Whirlwind Tour ... # hissp.macros.._macro_.throwQzSTAR_ ... (lambda g:g.close()or g.throw)(c for c in'')( ... # hissp.macros.._macro_.let - ... (lambda _QzNo130_G=(lambda _QzNo130_x: + ... (lambda _Qz2IKKUCBWz_G=(lambda _Qz2IKKUCBWz_x: ... # hissp.macros.._macro_.ifQz_else ... (lambda b,c,a:c()if b else a())( ... # hissp.macros.._macro_.QzET_QzET_ ... (lambda x0,x1:x0 and x1())( ... __import__('builtins').isinstance( - ... _QzNo130_x, + ... _Qz2IKKUCBWz_x, ... __import__('builtins').type), ... (lambda : ... __import__('builtins').issubclass( - ... _QzNo130_x, + ... _Qz2IKKUCBWz_x, ... __import__('builtins').BaseException))), - ... (lambda :_QzNo130_x()), - ... (lambda :_QzNo130_x))): + ... (lambda :_Qz2IKKUCBWz_x()), + ... (lambda :_Qz2IKKUCBWz_x))): ... # hissp.macros.._macro_.attach ... # hissp.macros.._macro_.let - ... (lambda _QzNo112_target=_QzNo130_G( + ... (lambda _QzWG5WN73Wz_target=_Qz2IKKUCBWz_G( ... Exception):( ... __import__('builtins').setattr( - ... _QzNo112_target, + ... _QzWG5WN73Wz_target, ... '__cause__', - ... _QzNo130_G( + ... _Qz2IKKUCBWz_G( ... Exception( ... ('msg')))), - ... _QzNo112_target)[-1])())()))) + ... _QzWG5WN73Wz_target)[-1])())()))) Exception('msg') @@ -2271,12 +2284,12 @@ Lissp Whirlwind Tour ... (lambda step:( ... # setQzAT_ ... # hissp.macros.._macro_.let - ... (lambda _QzNo29_val=a:( + ... (lambda _QzRMG5GSSIz_val=a:( ... __import__('builtins').setattr( ... step, ... 'Y', - ... _QzNo29_val), - ... _QzNo29_val)[-1])(), + ... _QzRMG5GSSIz_val), + ... _QzRMG5GSSIz_val)[-1])(), ... fibonacci( ... b, ... add( @@ -2298,6 +2311,7 @@ Lissp Whirlwind Tour #.. (when (lt i n) ;Acts like a while loop. #.. (set@ step.Y i) #.. (my-range (add i 1) n)))))) ;Conditional recursion. + #.. >>> # define ... __import__('builtins').globals().update( ... myQz_range=(lambda i,n: @@ -2311,12 +2325,12 @@ Lissp Whirlwind Tour ... (lambda :( ... # setQzAT_ ... # hissp.macros.._macro_.let - ... (lambda _QzNo108_val=i:( + ... (lambda _QzRMG5GSSIz_val=i:( ... __import__('builtins').setattr( ... step, ... 'Y', - ... _QzNo108_val), - ... _QzNo108_val)[-1])(), + ... _QzRMG5GSSIz_val), + ... _QzRMG5GSSIz_val)[-1])(), ... myQz_range( ... add( ... i, @@ -2341,9 +2355,9 @@ Lissp Whirlwind Tour ... (lambda step:( ... # attach ... # hissp.macros.._macro_.let - ... (lambda _QzNo31_target=step:( + ... (lambda _QzWG5WN73Wz_target=step:( ... __import__('builtins').setattr( - ... _QzNo31_target, + ... _QzWG5WN73Wz_target, ... 'Y', ... ((1), ... (2), @@ -2351,10 +2365,10 @@ Lissp Whirlwind Tour ... (4), ... (5),)), ... __import__('builtins').setattr( - ... _QzNo31_target, + ... _QzWG5WN73Wz_target, ... 'F', ... True), - ... _QzNo31_target)[-1])(), + ... _QzWG5WN73Wz_target)[-1])(), ... None)[-1])) <...Ensue object at ...> @@ -2370,6 +2384,7 @@ Lissp Whirlwind Tour #.. (attach step : ;Implicit continuation. #.. Y itr #.. F 1))))) ;The step is an Ensue instance. + #.. >>> # define ... __import__('builtins').globals().update( ... recycle=(lambda itr: @@ -2377,16 +2392,16 @@ Lissp Whirlwind Tour ... (lambda step: ... # attach ... # hissp.macros.._macro_.let - ... (lambda _QzNo31_target=step:( + ... (lambda _QzWG5WN73Wz_target=step:( ... __import__('builtins').setattr( - ... _QzNo31_target, + ... _QzWG5WN73Wz_target, ... 'Y', ... itr), ... __import__('builtins').setattr( - ... _QzNo31_target, + ... _QzWG5WN73Wz_target, ... 'F', ... (1)), - ... _QzNo31_target)[-1])())))) + ... _QzWG5WN73Wz_target)[-1])())))) #> (-> '(1 2 3) recycle (islice 7) list) >>> # Qz_QzGT_ @@ -2410,12 +2425,12 @@ Lissp Whirlwind Tour ... (lambda step:( ... # setQzAT_ ... # hissp.macros.._macro_.let - ... (lambda _QzNo29_val=step.sent:( + ... (lambda _QzRMG5GSSIz_val=step.sent:( ... __import__('builtins').setattr( ... step, ... 'Y', - ... _QzNo29_val), - ... _QzNo29_val)[-1])(), + ... _QzRMG5GSSIz_val), + ... _QzRMG5GSSIz_val)[-1])(), ... step)[-1]))) #> (.send echo None) ;Always send a None first. Same as Python. @@ -2454,12 +2469,12 @@ Lissp Whirlwind Tour ... (lambda step:( ... # setQzAT_ ... # hissp.macros.._macro_.let - ... (lambda _QzNo33_val=msg:( + ... (lambda _QzRMG5GSSIz_val=msg:( ... __import__('builtins').setattr( ... step, ... 'Y', - ... _QzNo33_val), - ... _QzNo33_val)[-1])(), + ... _QzRMG5GSSIz_val), + ... _QzRMG5GSSIz_val)[-1])(), ... Ensue( ... (lambda step: ... print( @@ -2525,16 +2540,16 @@ Lissp Whirlwind Tour ... (lambda step:( ... # attach ... # hissp.macros.._macro_.let - ... (lambda _QzNo35_target=step:( + ... (lambda _QzWG5WN73Wz_target=step:( ... __import__('builtins').setattr( - ... _QzNo35_target, + ... _QzWG5WN73Wz_target, ... 'Y', ... None), ... __import__('builtins').setattr( - ... _QzNo35_target, + ... _QzWG5WN73Wz_target, ... 'X', ... ZeroDivisionError), - ... _QzNo35_target)[-1])(), + ... _QzWG5WN73Wz_target)[-1])(), ... Ensue( ... (lambda step: ... print( @@ -2586,6 +2601,7 @@ Lissp Whirlwind Tour #> (engarde Exception #.. X#(print X.__cause__) ;Unary again. #.. O#(throw-from Exception (Exception "msg"))) ;Nullary/thunk. + #.. >>> engarde( ... Exception, ... (lambda X: @@ -2596,31 +2612,31 @@ Lissp Whirlwind Tour ... # hissp.macros.._macro_.throwQzSTAR_ ... (lambda g:g.close()or g.throw)(c for c in'')( ... # hissp.macros.._macro_.let - ... (lambda _QzNo130_G=(lambda _QzNo130_x: + ... (lambda _Qz2IKKUCBWz_G=(lambda _Qz2IKKUCBWz_x: ... # hissp.macros.._macro_.ifQz_else ... (lambda b,c,a:c()if b else a())( ... # hissp.macros.._macro_.QzET_QzET_ ... (lambda x0,x1:x0 and x1())( ... __import__('builtins').isinstance( - ... _QzNo130_x, + ... _Qz2IKKUCBWz_x, ... __import__('builtins').type), ... (lambda : ... __import__('builtins').issubclass( - ... _QzNo130_x, + ... _Qz2IKKUCBWz_x, ... __import__('builtins').BaseException))), - ... (lambda :_QzNo130_x()), - ... (lambda :_QzNo130_x))): + ... (lambda :_Qz2IKKUCBWz_x()), + ... (lambda :_Qz2IKKUCBWz_x))): ... # hissp.macros.._macro_.attach ... # hissp.macros.._macro_.let - ... (lambda _QzNo112_target=_QzNo130_G( + ... (lambda _QzWG5WN73Wz_target=_Qz2IKKUCBWz_G( ... Exception):( ... __import__('builtins').setattr( - ... _QzNo112_target, + ... _QzWG5WN73Wz_target, ... '__cause__', - ... _QzNo130_G( + ... _Qz2IKKUCBWz_G( ... Exception( ... ('msg')))), - ... _QzNo112_target)[-1])())()))) + ... _QzWG5WN73Wz_target)[-1])())()))) msg @@ -2633,7 +2649,7 @@ Lissp Whirlwind Tour ;;; injected Python here. #> ([#-2:1:-2] "QuaoblcldefHg") - >>> (lambda _QzNo32_G:(_QzNo32_G[-2:1:-2]))( + >>> (lambda _Qz5GEAOGSQz_G:(_Qz5GEAOGSQz_G[-2:1:-2]))( ... ('QuaoblcldefHg')) 'Hello' @@ -2661,9 +2677,9 @@ Lissp Whirlwind Tour #> (en#collections..deque 1 2 3) - >>> (lambda *_QzNo31_xs: + >>> (lambda *_Qz6RFWTTVXz_xs: ... __import__('collections').deque( - ... _QzNo31_xs))( + ... _Qz6RFWTTVXz_xs))( ... (1), ... (2), ... (3)) @@ -2678,34 +2694,34 @@ Lissp Whirlwind Tour >>> # hissp.._macro_.alias ... # hissp.macros.._macro_.defmacro ... # hissp.macros.._macro_.let - ... (lambda _QzNo7_fn=(lambda _QzNo27_prime,_QzNo27_reader=None,*_QzNo27_args:( + ... (lambda _QzAW22OE5Kz_fn=(lambda _QzARAQTXTEz_prime,_QzARAQTXTEz_reader=None,*_QzARAQTXTEz_args:( ... 'Aliases ``hissp.._macro_`` as ``MQzCOLON_#``.', ... # hissp.macros.._macro_.ifQz_else ... (lambda b,c,a:c()if b else a())( - ... _QzNo27_reader, + ... _QzARAQTXTEz_reader, ... (lambda : ... __import__('builtins').getattr( ... __import__('hissp')._macro_, ... ('{}{}').format( - ... _QzNo27_reader, + ... _QzARAQTXTEz_reader, ... # hissp.macros.._macro_.ifQz_else ... (lambda b,c,a:c()if b else a())( ... 'hissp.._macro_'.endswith( ... '._macro_'), ... (lambda :'QzHASH_'), ... (lambda :('')))))( - ... _QzNo27_prime, - ... *_QzNo27_args)), + ... _QzARAQTXTEz_prime, + ... *_QzARAQTXTEz_args)), ... (lambda : ... ('{}.{}').format( ... 'hissp.._macro_', - ... _QzNo27_prime))))[-1]):( + ... _QzARAQTXTEz_prime))))[-1]):( ... __import__('builtins').setattr( - ... _QzNo7_fn, + ... _QzAW22OE5Kz_fn, ... '__doc__', ... 'Aliases ``hissp.._macro_`` as ``MQzCOLON_#``.'), ... __import__('builtins').setattr( - ... _QzNo7_fn, + ... _QzAW22OE5Kz_fn, ... '__qualname__', ... ('.').join( ... ('_macro_', @@ -2715,7 +2731,7 @@ Lissp Whirlwind Tour ... __import__('builtins').globals(), ... '_macro_'), ... 'MQzCOLON_QzHASH_', - ... _QzNo7_fn))[-1])() + ... _QzAW22OE5Kz_fn))[-1])() #> 'M:#alias >>> 'hissp.._macro_.alias' diff --git a/docs/macro_tutorial.rst b/docs/macro_tutorial.rst index b8299bd0..06e01250 100644 --- a/docs/macro_tutorial.rst +++ b/docs/macro_tutorial.rst @@ -491,13 +491,13 @@ Try this definition. #.. `(lambda ,params ,@body)) >>> # defmacro ... # hissp.macros.._macro_.let - ... (lambda _QzNo7_fn=(lambda params,*body: + ... (lambda _QzAW22OE5Kz_fn=(lambda params,*body: ... (lambda * _: _)( ... 'lambda', ... params, ... *body)):( ... __import__('builtins').setattr( - ... _QzNo7_fn, + ... _QzAW22OE5Kz_fn, ... '__qualname__', ... ('.').join( ... ('_macro_', @@ -507,7 +507,7 @@ Try this definition. ... __import__('builtins').globals(), ... '_macro_'), ... 'L', - ... _QzNo7_fn))[-1])() + ... _QzAW22OE5Kz_fn))[-1])() .. code-block:: REPL @@ -573,14 +573,14 @@ that anaphoric macro we did in the `primer`. #.. ,expr)) >>> # defmacro ... # hissp.macros.._macro_.let - ... (lambda _QzNo7_fn=(lambda *expr: + ... (lambda _QzAW22OE5Kz_fn=(lambda *expr: ... (lambda * _: _)( ... 'lambda', ... (lambda * _: _)( ... 'X'), ... expr)):( ... __import__('builtins').setattr( - ... _QzNo7_fn, + ... _QzAW22OE5Kz_fn, ... '__qualname__', ... ('.').join( ... ('_macro_', @@ -590,7 +590,7 @@ that anaphoric macro we did in the `primer`. ... __import__('builtins').globals(), ... '_macro_'), ... 'L', - ... _QzNo7_fn))[-1])() + ... _QzAW22OE5Kz_fn))[-1])() .. code-block:: REPL @@ -645,7 +645,7 @@ Ready? #.. ,expr)) >>> # defmacro ... # hissp.macros.._macro_.let - ... (lambda _QzNo7_fn=(lambda *expr: + ... (lambda _QzAW22OE5Kz_fn=(lambda *expr: ... (lambda * _: _)( ... 'lambda', ... (lambda * _: _)( @@ -653,7 +653,7 @@ Ready? ... 'Y'), ... expr)):( ... __import__('builtins').setattr( - ... _QzNo7_fn, + ... _QzAW22OE5Kz_fn, ... '__qualname__', ... ('.').join( ... ('_macro_', @@ -663,7 +663,7 @@ Ready? ... __import__('builtins').globals(), ... '_macro_'), ... 'L2', - ... _QzNo7_fn))[-1])() + ... _QzAW22OE5Kz_fn))[-1])() .. code-block:: REPL @@ -707,13 +707,13 @@ Don't panic. ... (lambda :( ... # __main__.._macro_.defmacro ... # hissp.macros.._macro_.let - ... (lambda _QzNo7_fn=(lambda *_QzNo36_expr: + ... (lambda _QzAW22OE5Kz_fn=(lambda *_QzQ46NYXTBz_expr: ... (lambda * _: _)( ... 'lambda', ... '', - ... _QzNo36_expr)):( + ... _QzQ46NYXTBz_expr)):( ... __import__('builtins').setattr( - ... _QzNo7_fn, + ... _QzAW22OE5Kz_fn, ... '__qualname__', ... ('.').join( ... ('_macro_', @@ -723,16 +723,16 @@ Don't panic. ... __import__('builtins').globals(), ... '_macro_'), ... 'L0', - ... _QzNo7_fn))[-1])(), + ... _QzAW22OE5Kz_fn))[-1])(), ... # __main__.._macro_.defmacro ... # hissp.macros.._macro_.let - ... (lambda _QzNo7_fn=(lambda *_QzNo36_expr: + ... (lambda _QzAW22OE5Kz_fn=(lambda *_QzQ46NYXTBz_expr: ... (lambda * _: _)( ... 'lambda', ... 'A', - ... _QzNo36_expr)):( + ... _QzQ46NYXTBz_expr)):( ... __import__('builtins').setattr( - ... _QzNo7_fn, + ... _QzAW22OE5Kz_fn, ... '__qualname__', ... ('.').join( ... ('_macro_', @@ -742,16 +742,16 @@ Don't panic. ... __import__('builtins').globals(), ... '_macro_'), ... 'L1', - ... _QzNo7_fn))[-1])(), + ... _QzAW22OE5Kz_fn))[-1])(), ... # __main__.._macro_.defmacro ... # hissp.macros.._macro_.let - ... (lambda _QzNo7_fn=(lambda *_QzNo36_expr: + ... (lambda _QzAW22OE5Kz_fn=(lambda *_QzQ46NYXTBz_expr: ... (lambda * _: _)( ... 'lambda', ... 'AB', - ... _QzNo36_expr)):( + ... _QzQ46NYXTBz_expr)):( ... __import__('builtins').setattr( - ... _QzNo7_fn, + ... _QzAW22OE5Kz_fn, ... '__qualname__', ... ('.').join( ... ('_macro_', @@ -761,16 +761,16 @@ Don't panic. ... __import__('builtins').globals(), ... '_macro_'), ... 'L2', - ... _QzNo7_fn))[-1])(), + ... _QzAW22OE5Kz_fn))[-1])(), ... # __main__.._macro_.defmacro ... # hissp.macros.._macro_.let - ... (lambda _QzNo7_fn=(lambda *_QzNo36_expr: + ... (lambda _QzAW22OE5Kz_fn=(lambda *_QzQ46NYXTBz_expr: ... (lambda * _: _)( ... 'lambda', ... 'ABC', - ... _QzNo36_expr)):( + ... _QzQ46NYXTBz_expr)):( ... __import__('builtins').setattr( - ... _QzNo7_fn, + ... _QzAW22OE5Kz_fn, ... '__qualname__', ... ('.').join( ... ('_macro_', @@ -780,16 +780,16 @@ Don't panic. ... __import__('builtins').globals(), ... '_macro_'), ... 'L3', - ... _QzNo7_fn))[-1])(), + ... _QzAW22OE5Kz_fn))[-1])(), ... # __main__.._macro_.defmacro ... # hissp.macros.._macro_.let - ... (lambda _QzNo7_fn=(lambda *_QzNo36_expr: + ... (lambda _QzAW22OE5Kz_fn=(lambda *_QzQ46NYXTBz_expr: ... (lambda * _: _)( ... 'lambda', ... 'ABCD', - ... _QzNo36_expr)):( + ... _QzQ46NYXTBz_expr)):( ... __import__('builtins').setattr( - ... _QzNo7_fn, + ... _QzAW22OE5Kz_fn, ... '__qualname__', ... ('.').join( ... ('_macro_', @@ -799,16 +799,16 @@ Don't panic. ... __import__('builtins').globals(), ... '_macro_'), ... 'L4', - ... _QzNo7_fn))[-1])(), + ... _QzAW22OE5Kz_fn))[-1])(), ... # __main__.._macro_.defmacro ... # hissp.macros.._macro_.let - ... (lambda _QzNo7_fn=(lambda *_QzNo36_expr: + ... (lambda _QzAW22OE5Kz_fn=(lambda *_QzQ46NYXTBz_expr: ... (lambda * _: _)( ... 'lambda', ... 'ABCDE', - ... _QzNo36_expr)):( + ... _QzQ46NYXTBz_expr)):( ... __import__('builtins').setattr( - ... _QzNo7_fn, + ... _QzAW22OE5Kz_fn, ... '__qualname__', ... ('.').join( ... ('_macro_', @@ -818,16 +818,16 @@ Don't panic. ... __import__('builtins').globals(), ... '_macro_'), ... 'L5', - ... _QzNo7_fn))[-1])(), + ... _QzAW22OE5Kz_fn))[-1])(), ... # __main__.._macro_.defmacro ... # hissp.macros.._macro_.let - ... (lambda _QzNo7_fn=(lambda *_QzNo36_expr: + ... (lambda _QzAW22OE5Kz_fn=(lambda *_QzQ46NYXTBz_expr: ... (lambda * _: _)( ... 'lambda', ... 'ABCDEF', - ... _QzNo36_expr)):( + ... _QzQ46NYXTBz_expr)):( ... __import__('builtins').setattr( - ... _QzNo7_fn, + ... _QzAW22OE5Kz_fn, ... '__qualname__', ... ('.').join( ... ('_macro_', @@ -837,16 +837,16 @@ Don't panic. ... __import__('builtins').globals(), ... '_macro_'), ... 'L6', - ... _QzNo7_fn))[-1])(), + ... _QzAW22OE5Kz_fn))[-1])(), ... # __main__.._macro_.defmacro ... # hissp.macros.._macro_.let - ... (lambda _QzNo7_fn=(lambda *_QzNo36_expr: + ... (lambda _QzAW22OE5Kz_fn=(lambda *_QzQ46NYXTBz_expr: ... (lambda * _: _)( ... 'lambda', ... 'ABCDEFG', - ... _QzNo36_expr)):( + ... _QzQ46NYXTBz_expr)):( ... __import__('builtins').setattr( - ... _QzNo7_fn, + ... _QzAW22OE5Kz_fn, ... '__qualname__', ... ('.').join( ... ('_macro_', @@ -856,16 +856,16 @@ Don't panic. ... __import__('builtins').globals(), ... '_macro_'), ... 'L7', - ... _QzNo7_fn))[-1])(), + ... _QzAW22OE5Kz_fn))[-1])(), ... # __main__.._macro_.defmacro ... # hissp.macros.._macro_.let - ... (lambda _QzNo7_fn=(lambda *_QzNo36_expr: + ... (lambda _QzAW22OE5Kz_fn=(lambda *_QzQ46NYXTBz_expr: ... (lambda * _: _)( ... 'lambda', ... 'ABCDEFGH', - ... _QzNo36_expr)):( + ... _QzQ46NYXTBz_expr)):( ... __import__('builtins').setattr( - ... _QzNo7_fn, + ... _QzAW22OE5Kz_fn, ... '__qualname__', ... ('.').join( ... ('_macro_', @@ -875,16 +875,16 @@ Don't panic. ... __import__('builtins').globals(), ... '_macro_'), ... 'L8', - ... _QzNo7_fn))[-1])(), + ... _QzAW22OE5Kz_fn))[-1])(), ... # __main__.._macro_.defmacro ... # hissp.macros.._macro_.let - ... (lambda _QzNo7_fn=(lambda *_QzNo36_expr: + ... (lambda _QzAW22OE5Kz_fn=(lambda *_QzQ46NYXTBz_expr: ... (lambda * _: _)( ... 'lambda', ... 'ABCDEFGHI', - ... _QzNo36_expr)):( + ... _QzQ46NYXTBz_expr)):( ... __import__('builtins').setattr( - ... _QzNo7_fn, + ... _QzAW22OE5Kz_fn, ... '__qualname__', ... ('.').join( ... ('_macro_', @@ -894,16 +894,16 @@ Don't panic. ... __import__('builtins').globals(), ... '_macro_'), ... 'L9', - ... _QzNo7_fn))[-1])(), + ... _QzAW22OE5Kz_fn))[-1])(), ... # __main__.._macro_.defmacro ... # hissp.macros.._macro_.let - ... (lambda _QzNo7_fn=(lambda *_QzNo36_expr: + ... (lambda _QzAW22OE5Kz_fn=(lambda *_QzQ46NYXTBz_expr: ... (lambda * _: _)( ... 'lambda', ... 'ABCDEFGHIJ', - ... _QzNo36_expr)):( + ... _QzQ46NYXTBz_expr)):( ... __import__('builtins').setattr( - ... _QzNo7_fn, + ... _QzAW22OE5Kz_fn, ... '__qualname__', ... ('.').join( ... ('_macro_', @@ -913,16 +913,16 @@ Don't panic. ... __import__('builtins').globals(), ... '_macro_'), ... 'L10', - ... _QzNo7_fn))[-1])(), + ... _QzAW22OE5Kz_fn))[-1])(), ... # __main__.._macro_.defmacro ... # hissp.macros.._macro_.let - ... (lambda _QzNo7_fn=(lambda *_QzNo36_expr: + ... (lambda _QzAW22OE5Kz_fn=(lambda *_QzQ46NYXTBz_expr: ... (lambda * _: _)( ... 'lambda', ... 'ABCDEFGHIJK', - ... _QzNo36_expr)):( + ... _QzQ46NYXTBz_expr)):( ... __import__('builtins').setattr( - ... _QzNo7_fn, + ... _QzAW22OE5Kz_fn, ... '__qualname__', ... ('.').join( ... ('_macro_', @@ -932,16 +932,16 @@ Don't panic. ... __import__('builtins').globals(), ... '_macro_'), ... 'L11', - ... _QzNo7_fn))[-1])(), + ... _QzAW22OE5Kz_fn))[-1])(), ... # __main__.._macro_.defmacro ... # hissp.macros.._macro_.let - ... (lambda _QzNo7_fn=(lambda *_QzNo36_expr: + ... (lambda _QzAW22OE5Kz_fn=(lambda *_QzQ46NYXTBz_expr: ... (lambda * _: _)( ... 'lambda', ... 'ABCDEFGHIJKL', - ... _QzNo36_expr)):( + ... _QzQ46NYXTBz_expr)):( ... __import__('builtins').setattr( - ... _QzNo7_fn, + ... _QzAW22OE5Kz_fn, ... '__qualname__', ... ('.').join( ... ('_macro_', @@ -951,16 +951,16 @@ Don't panic. ... __import__('builtins').globals(), ... '_macro_'), ... 'L12', - ... _QzNo7_fn))[-1])(), + ... _QzAW22OE5Kz_fn))[-1])(), ... # __main__.._macro_.defmacro ... # hissp.macros.._macro_.let - ... (lambda _QzNo7_fn=(lambda *_QzNo36_expr: + ... (lambda _QzAW22OE5Kz_fn=(lambda *_QzQ46NYXTBz_expr: ... (lambda * _: _)( ... 'lambda', ... 'ABCDEFGHIJKLM', - ... _QzNo36_expr)):( + ... _QzQ46NYXTBz_expr)):( ... __import__('builtins').setattr( - ... _QzNo7_fn, + ... _QzAW22OE5Kz_fn, ... '__qualname__', ... ('.').join( ... ('_macro_', @@ -970,16 +970,16 @@ Don't panic. ... __import__('builtins').globals(), ... '_macro_'), ... 'L13', - ... _QzNo7_fn))[-1])(), + ... _QzAW22OE5Kz_fn))[-1])(), ... # __main__.._macro_.defmacro ... # hissp.macros.._macro_.let - ... (lambda _QzNo7_fn=(lambda *_QzNo36_expr: + ... (lambda _QzAW22OE5Kz_fn=(lambda *_QzQ46NYXTBz_expr: ... (lambda * _: _)( ... 'lambda', ... 'ABCDEFGHIJKLMN', - ... _QzNo36_expr)):( + ... _QzQ46NYXTBz_expr)):( ... __import__('builtins').setattr( - ... _QzNo7_fn, + ... _QzAW22OE5Kz_fn, ... '__qualname__', ... ('.').join( ... ('_macro_', @@ -989,16 +989,16 @@ Don't panic. ... __import__('builtins').globals(), ... '_macro_'), ... 'L14', - ... _QzNo7_fn))[-1])(), + ... _QzAW22OE5Kz_fn))[-1])(), ... # __main__.._macro_.defmacro ... # hissp.macros.._macro_.let - ... (lambda _QzNo7_fn=(lambda *_QzNo36_expr: + ... (lambda _QzAW22OE5Kz_fn=(lambda *_QzQ46NYXTBz_expr: ... (lambda * _: _)( ... 'lambda', ... 'ABCDEFGHIJKLMNO', - ... _QzNo36_expr)):( + ... _QzQ46NYXTBz_expr)):( ... __import__('builtins').setattr( - ... _QzNo7_fn, + ... _QzAW22OE5Kz_fn, ... '__qualname__', ... ('.').join( ... ('_macro_', @@ -1008,16 +1008,16 @@ Don't panic. ... __import__('builtins').globals(), ... '_macro_'), ... 'L15', - ... _QzNo7_fn))[-1])(), + ... _QzAW22OE5Kz_fn))[-1])(), ... # __main__.._macro_.defmacro ... # hissp.macros.._macro_.let - ... (lambda _QzNo7_fn=(lambda *_QzNo36_expr: + ... (lambda _QzAW22OE5Kz_fn=(lambda *_QzQ46NYXTBz_expr: ... (lambda * _: _)( ... 'lambda', ... 'ABCDEFGHIJKLMNOP', - ... _QzNo36_expr)):( + ... _QzQ46NYXTBz_expr)):( ... __import__('builtins').setattr( - ... _QzNo7_fn, + ... _QzAW22OE5Kz_fn, ... '__qualname__', ... ('.').join( ... ('_macro_', @@ -1027,16 +1027,16 @@ Don't panic. ... __import__('builtins').globals(), ... '_macro_'), ... 'L16', - ... _QzNo7_fn))[-1])(), + ... _QzAW22OE5Kz_fn))[-1])(), ... # __main__.._macro_.defmacro ... # hissp.macros.._macro_.let - ... (lambda _QzNo7_fn=(lambda *_QzNo36_expr: + ... (lambda _QzAW22OE5Kz_fn=(lambda *_QzQ46NYXTBz_expr: ... (lambda * _: _)( ... 'lambda', ... 'ABCDEFGHIJKLMNOPQ', - ... _QzNo36_expr)):( + ... _QzQ46NYXTBz_expr)):( ... __import__('builtins').setattr( - ... _QzNo7_fn, + ... _QzAW22OE5Kz_fn, ... '__qualname__', ... ('.').join( ... ('_macro_', @@ -1046,16 +1046,16 @@ Don't panic. ... __import__('builtins').globals(), ... '_macro_'), ... 'L17', - ... _QzNo7_fn))[-1])(), + ... _QzAW22OE5Kz_fn))[-1])(), ... # __main__.._macro_.defmacro ... # hissp.macros.._macro_.let - ... (lambda _QzNo7_fn=(lambda *_QzNo36_expr: + ... (lambda _QzAW22OE5Kz_fn=(lambda *_QzQ46NYXTBz_expr: ... (lambda * _: _)( ... 'lambda', ... 'ABCDEFGHIJKLMNOPQR', - ... _QzNo36_expr)):( + ... _QzQ46NYXTBz_expr)):( ... __import__('builtins').setattr( - ... _QzNo7_fn, + ... _QzAW22OE5Kz_fn, ... '__qualname__', ... ('.').join( ... ('_macro_', @@ -1065,16 +1065,16 @@ Don't panic. ... __import__('builtins').globals(), ... '_macro_'), ... 'L18', - ... _QzNo7_fn))[-1])(), + ... _QzAW22OE5Kz_fn))[-1])(), ... # __main__.._macro_.defmacro ... # hissp.macros.._macro_.let - ... (lambda _QzNo7_fn=(lambda *_QzNo36_expr: + ... (lambda _QzAW22OE5Kz_fn=(lambda *_QzQ46NYXTBz_expr: ... (lambda * _: _)( ... 'lambda', ... 'ABCDEFGHIJKLMNOPQRS', - ... _QzNo36_expr)):( + ... _QzQ46NYXTBz_expr)):( ... __import__('builtins').setattr( - ... _QzNo7_fn, + ... _QzAW22OE5Kz_fn, ... '__qualname__', ... ('.').join( ... ('_macro_', @@ -1084,16 +1084,16 @@ Don't panic. ... __import__('builtins').globals(), ... '_macro_'), ... 'L19', - ... _QzNo7_fn))[-1])(), + ... _QzAW22OE5Kz_fn))[-1])(), ... # __main__.._macro_.defmacro ... # hissp.macros.._macro_.let - ... (lambda _QzNo7_fn=(lambda *_QzNo36_expr: + ... (lambda _QzAW22OE5Kz_fn=(lambda *_QzQ46NYXTBz_expr: ... (lambda * _: _)( ... 'lambda', ... 'ABCDEFGHIJKLMNOPQRST', - ... _QzNo36_expr)):( + ... _QzQ46NYXTBz_expr)):( ... __import__('builtins').setattr( - ... _QzNo7_fn, + ... _QzAW22OE5Kz_fn, ... '__qualname__', ... ('.').join( ... ('_macro_', @@ -1103,16 +1103,16 @@ Don't panic. ... __import__('builtins').globals(), ... '_macro_'), ... 'L20', - ... _QzNo7_fn))[-1])(), + ... _QzAW22OE5Kz_fn))[-1])(), ... # __main__.._macro_.defmacro ... # hissp.macros.._macro_.let - ... (lambda _QzNo7_fn=(lambda *_QzNo36_expr: + ... (lambda _QzAW22OE5Kz_fn=(lambda *_QzQ46NYXTBz_expr: ... (lambda * _: _)( ... 'lambda', ... 'ABCDEFGHIJKLMNOPQRSTU', - ... _QzNo36_expr)):( + ... _QzQ46NYXTBz_expr)):( ... __import__('builtins').setattr( - ... _QzNo7_fn, + ... _QzAW22OE5Kz_fn, ... '__qualname__', ... ('.').join( ... ('_macro_', @@ -1122,16 +1122,16 @@ Don't panic. ... __import__('builtins').globals(), ... '_macro_'), ... 'L21', - ... _QzNo7_fn))[-1])(), + ... _QzAW22OE5Kz_fn))[-1])(), ... # __main__.._macro_.defmacro ... # hissp.macros.._macro_.let - ... (lambda _QzNo7_fn=(lambda *_QzNo36_expr: + ... (lambda _QzAW22OE5Kz_fn=(lambda *_QzQ46NYXTBz_expr: ... (lambda * _: _)( ... 'lambda', ... 'ABCDEFGHIJKLMNOPQRSTUV', - ... _QzNo36_expr)):( + ... _QzQ46NYXTBz_expr)):( ... __import__('builtins').setattr( - ... _QzNo7_fn, + ... _QzAW22OE5Kz_fn, ... '__qualname__', ... ('.').join( ... ('_macro_', @@ -1141,16 +1141,16 @@ Don't panic. ... __import__('builtins').globals(), ... '_macro_'), ... 'L22', - ... _QzNo7_fn))[-1])(), + ... _QzAW22OE5Kz_fn))[-1])(), ... # __main__.._macro_.defmacro ... # hissp.macros.._macro_.let - ... (lambda _QzNo7_fn=(lambda *_QzNo36_expr: + ... (lambda _QzAW22OE5Kz_fn=(lambda *_QzQ46NYXTBz_expr: ... (lambda * _: _)( ... 'lambda', ... 'ABCDEFGHIJKLMNOPQRSTUVW', - ... _QzNo36_expr)):( + ... _QzQ46NYXTBz_expr)):( ... __import__('builtins').setattr( - ... _QzNo7_fn, + ... _QzAW22OE5Kz_fn, ... '__qualname__', ... ('.').join( ... ('_macro_', @@ -1160,16 +1160,16 @@ Don't panic. ... __import__('builtins').globals(), ... '_macro_'), ... 'L23', - ... _QzNo7_fn))[-1])(), + ... _QzAW22OE5Kz_fn))[-1])(), ... # __main__.._macro_.defmacro ... # hissp.macros.._macro_.let - ... (lambda _QzNo7_fn=(lambda *_QzNo36_expr: + ... (lambda _QzAW22OE5Kz_fn=(lambda *_QzQ46NYXTBz_expr: ... (lambda * _: _)( ... 'lambda', ... 'ABCDEFGHIJKLMNOPQRSTUVWX', - ... _QzNo36_expr)):( + ... _QzQ46NYXTBz_expr)):( ... __import__('builtins').setattr( - ... _QzNo7_fn, + ... _QzAW22OE5Kz_fn, ... '__qualname__', ... ('.').join( ... ('_macro_', @@ -1179,16 +1179,16 @@ Don't panic. ... __import__('builtins').globals(), ... '_macro_'), ... 'L24', - ... _QzNo7_fn))[-1])(), + ... _QzAW22OE5Kz_fn))[-1])(), ... # __main__.._macro_.defmacro ... # hissp.macros.._macro_.let - ... (lambda _QzNo7_fn=(lambda *_QzNo36_expr: + ... (lambda _QzAW22OE5Kz_fn=(lambda *_QzQ46NYXTBz_expr: ... (lambda * _: _)( ... 'lambda', ... 'ABCDEFGHIJKLMNOPQRSTUVWXY', - ... _QzNo36_expr)):( + ... _QzQ46NYXTBz_expr)):( ... __import__('builtins').setattr( - ... _QzNo7_fn, + ... _QzAW22OE5Kz_fn, ... '__qualname__', ... ('.').join( ... ('_macro_', @@ -1198,16 +1198,16 @@ Don't panic. ... __import__('builtins').globals(), ... '_macro_'), ... 'L25', - ... _QzNo7_fn))[-1])(), + ... _QzAW22OE5Kz_fn))[-1])(), ... # __main__.._macro_.defmacro ... # hissp.macros.._macro_.let - ... (lambda _QzNo7_fn=(lambda *_QzNo36_expr: + ... (lambda _QzAW22OE5Kz_fn=(lambda *_QzQ46NYXTBz_expr: ... (lambda * _: _)( ... 'lambda', ... 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', - ... _QzNo36_expr)):( + ... _QzQ46NYXTBz_expr)):( ... __import__('builtins').setattr( - ... _QzNo7_fn, + ... _QzAW22OE5Kz_fn, ... '__qualname__', ... ('.').join( ... ('_macro_', @@ -1217,7 +1217,7 @@ Don't panic. ... __import__('builtins').globals(), ... '_macro_'), ... 'L26', - ... _QzNo7_fn))[-1])())[-1])() + ... _QzAW22OE5Kz_fn))[-1])())[-1])() Whoa. @@ -1344,7 +1344,7 @@ We can create numbered X's the same way we created the numbered L's. #.. ,expr)) >>> # defmacro ... # hissp.macros.._macro_.let - ... (lambda _QzNo7_fn=(lambda number,*expr: + ... (lambda _QzAW22OE5Kz_fn=(lambda number,*expr: ... (lambda * _: _)( ... 'lambda', ... map( @@ -1358,7 +1358,7 @@ We can create numbered X's the same way we created the numbered L's. ... number))), ... expr)):( ... __import__('builtins').setattr( - ... _QzNo7_fn, + ... _QzAW22OE5Kz_fn, ... '__qualname__', ... ('.').join( ... ('_macro_', @@ -1368,7 +1368,7 @@ We can create numbered X's the same way we created the numbered L's. ... __import__('builtins').globals(), ... '_macro_'), ... 'L', - ... _QzNo7_fn))[-1])() + ... _QzAW22OE5Kz_fn))[-1])() .. code-block:: REPL @@ -1404,7 +1404,7 @@ Let's make a slight tweak. #.. ,expr)) >>> # defmacro ... # hissp.macros.._macro_.let - ... (lambda _QzNo7_fn=(lambda *expr: + ... (lambda _QzAW22OE5Kz_fn=(lambda *expr: ... (lambda * _: _)( ... 'lambda', ... map( @@ -1419,7 +1419,7 @@ Let's make a slight tweak. ... expr)))), ... expr)):( ... __import__('builtins').setattr( - ... _QzNo7_fn, + ... _QzAW22OE5Kz_fn, ... '__qualname__', ... ('.').join( ... ('_macro_', @@ -1429,7 +1429,7 @@ Let's make a slight tweak. ... __import__('builtins').globals(), ... '_macro_'), ... 'L', - ... _QzNo7_fn))[-1])() + ... _QzAW22OE5Kz_fn))[-1])() What is this ``max-X``? @@ -1702,12 +1702,12 @@ you must define them in ``_macro_`` with a name ending in a ``#``. #.. `(L ,@expr)) >>> # defmacro ... # hissp.macros.._macro_.let - ... (lambda _QzNo7_fn=(lambda expr: + ... (lambda _QzAW22OE5Kz_fn=(lambda expr: ... (lambda * _: _)( ... '__main__.._macro_.L', ... *expr)):( ... __import__('builtins').setattr( - ... _QzNo7_fn, + ... _QzAW22OE5Kz_fn, ... '__qualname__', ... ('.').join( ... ('_macro_', @@ -1717,7 +1717,7 @@ you must define them in ``_macro_`` with a name ending in a ``#``. ... __import__('builtins').globals(), ... '_macro_'), ... 'XQzHASH_', - ... _QzNo7_fn))[-1])() + ... _QzAW22OE5Kz_fn))[-1])() We have to escape the ``#`` with a backslash or the reader will recognize the name as a macro rather than a symbol @@ -1798,7 +1798,7 @@ Catch-All Parameter #.. ,expr)) >>> # defmacro ... # hissp.macros.._macro_.let - ... (lambda _QzNo81_fn=(lambda *expr: + ... (lambda _QzAW22OE5Kz_fn=(lambda *expr: ... (lambda * _: _)( ... 'lambda', ... (lambda * _: _)( @@ -1825,7 +1825,7 @@ Catch-All Parameter ... 'Xi')))), ... expr)):( ... __import__('builtins').setattr( - ... _QzNo81_fn, + ... _QzAW22OE5Kz_fn, ... '__qualname__', ... ('.').join( ... ('_macro_', @@ -1835,7 +1835,7 @@ Catch-All Parameter ... __import__('builtins').globals(), ... '_macro_'), ... 'L', - ... _QzNo81_fn))[-1])() + ... _QzAW22OE5Kz_fn))[-1])() .. code-block:: REPL @@ -1927,7 +1927,7 @@ Here you go: #.. expr))) >>> # defmacro ... # hissp.macros.._macro_.let - ... (lambda _QzNo85_fn=(lambda *expr: + ... (lambda _QzAW22OE5Kz_fn=(lambda *expr: ... (lambda * _: _)( ... 'lambda', ... (lambda * _: _)( @@ -1974,7 +1974,7 @@ Here you go: ... expr)), ... (lambda :expr)))):( ... __import__('builtins').setattr( - ... _QzNo85_fn, + ... _QzAW22OE5Kz_fn, ... '__qualname__', ... ('.').join( ... ('_macro_', @@ -1984,7 +1984,7 @@ Here you go: ... __import__('builtins').globals(), ... '_macro_'), ... 'L', - ... _QzNo85_fn))[-1])() + ... _QzAW22OE5Kz_fn))[-1])() .. code-block:: REPL @@ -2224,12 +2224,12 @@ Lissp gives us a better option. #.. (int x 16)) >>> # defmacro ... # hissp.macros.._macro_.let - ... (lambda _QzNo7_fn=(lambda x: + ... (lambda _QzAW22OE5Kz_fn=(lambda x: ... int( ... x, ... (16))):( ... __import__('builtins').setattr( - ... _QzNo7_fn, + ... _QzAW22OE5Kz_fn, ... '__qualname__', ... ('.').join( ... ('_macro_', @@ -2239,7 +2239,7 @@ Lissp gives us a better option. ... __import__('builtins').globals(), ... '_macro_'), ... 'QzDIGITxONE_6QzHASH_', - ... _QzNo7_fn))[-1])() + ... _QzAW22OE5Kz_fn))[-1])() We've defined a tag that turns hexadecimal strings into ints. And it does it so at *read time*. @@ -2296,13 +2296,13 @@ New version. #.. (int (str x) 16)) >>> # defmacro ... # hissp.macros.._macro_.let - ... (lambda _QzNo7_fn=(lambda x: + ... (lambda _QzAW22OE5Kz_fn=(lambda x: ... int( ... str( ... x), ... (16))):( ... __import__('builtins').setattr( - ... _QzNo7_fn, + ... _QzAW22OE5Kz_fn, ... '__qualname__', ... ('.').join( ... ('_macro_', @@ -2312,7 +2312,7 @@ New version. ... __import__('builtins').globals(), ... '_macro_'), ... 'QzDIGITxONE_6QzHASH_', - ... _QzNo7_fn))[-1])() + ... _QzAW22OE5Kz_fn))[-1])() And now it works as well as the built-in notation. @@ -2396,7 +2396,7 @@ because munging is (mostly) reversible. #.. 16)) >>> # defmacro ... # hissp.macros.._macro_.let - ... (lambda _QzNo7_fn=(lambda x:( + ... (lambda _QzAW22OE5Kz_fn=(lambda x:( ... ('hexadecimal'), ... int( ... __import__('hissp.munger',fromlist='?').demunge( @@ -2404,11 +2404,11 @@ because munging is (mostly) reversible. ... x)), ... (16)))[-1]):( ... __import__('builtins').setattr( - ... _QzNo7_fn, + ... _QzAW22OE5Kz_fn, ... '__doc__', ... ('hexadecimal')), ... __import__('builtins').setattr( - ... _QzNo7_fn, + ... _QzAW22OE5Kz_fn, ... '__qualname__', ... ('.').join( ... ('_macro_', @@ -2418,7 +2418,7 @@ because munging is (mostly) reversible. ... __import__('builtins').globals(), ... '_macro_'), ... 'QzDIGITxONE_6QzHASH_', - ... _QzNo7_fn))[-1])() + ... _QzAW22OE5Kz_fn))[-1])() .. code-block:: REPL @@ -2436,18 +2436,18 @@ Well, with reader macros, you can implement any base you want. #.. (int (str x) 6)) >>> # defmacro ... # hissp.macros.._macro_.let - ... (lambda _QzNo7_fn=(lambda x:( + ... (lambda _QzAW22OE5Kz_fn=(lambda x:( ... ('seximal'), ... int( ... str( ... x), ... (6)))[-1]):( ... __import__('builtins').setattr( - ... _QzNo7_fn, + ... _QzAW22OE5Kz_fn, ... '__doc__', ... ('seximal')), ... __import__('builtins').setattr( - ... _QzNo7_fn, + ... _QzAW22OE5Kz_fn, ... '__qualname__', ... ('.').join( ... ('_macro_', @@ -2457,7 +2457,7 @@ Well, with reader macros, you can implement any base you want. ... __import__('builtins').globals(), ... '_macro_'), ... 'QzDIGITxSIX_QzHASH_', - ... _QzNo7_fn))[-1])() + ... _QzAW22OE5Kz_fn))[-1])() .. code-block:: REPL @@ -2483,7 +2483,7 @@ Or you can add floating-point. Python's notation can't do that. #.. (int x 16)))) >>> # defmacro ... # hissp.macros.._macro_.let - ... (lambda _QzNo7_fn=(lambda x: + ... (lambda _QzAW22OE5Kz_fn=(lambda x: ... # let ... (lambda x=__import__('hissp.munger',fromlist='?').demunge( ... str( @@ -2501,7 +2501,7 @@ Or you can add floating-point. Python's notation can't do that. ... x, ... (16)))))()):( ... __import__('builtins').setattr( - ... _QzNo7_fn, + ... _QzAW22OE5Kz_fn, ... '__qualname__', ... ('.').join( ... ('_macro_', @@ -2511,7 +2511,7 @@ Or you can add floating-point. Python's notation can't do that. ... __import__('builtins').globals(), ... '_macro_'), ... 'QzDIGITxONE_6QzHASH_', - ... _QzNo7_fn))[-1])() + ... _QzAW22OE5Kz_fn))[-1])() .. code-block:: REPL @@ -2618,7 +2618,7 @@ We can improve this a lot with a custom defmacro. #.. `(decimal..Decimal ',(str x))) >>> # defmacro ... # hissp.macros.._macro_.let - ... (lambda _QzNo7_fn=(lambda x: + ... (lambda _QzAW22OE5Kz_fn=(lambda x: ... (lambda * _: _)( ... 'decimal..Decimal', ... (lambda * _: _)( @@ -2626,7 +2626,7 @@ We can improve this a lot with a custom defmacro. ... str( ... x)))):( ... __import__('builtins').setattr( - ... _QzNo7_fn, + ... _QzAW22OE5Kz_fn, ... '__qualname__', ... ('.').join( ... ('_macro_', @@ -2636,7 +2636,7 @@ We can improve this a lot with a custom defmacro. ... __import__('builtins').globals(), ... '_macro_'), ... 'QzDIGITxONE_0QzHASH_', - ... _QzNo7_fn))[-1])() + ... _QzAW22OE5Kz_fn))[-1])() .. code-block:: REPL @@ -2695,7 +2695,7 @@ but a string is not the only alternative available: #.. `(decimal..Decimal ',(getitem x (slice 1 None)))) >>> # defmacro ... # hissp.macros.._macro_.let - ... (lambda _QzNo7_fn=(lambda x: + ... (lambda _QzAW22OE5Kz_fn=(lambda x: ... (lambda * _: _)( ... 'decimal..Decimal', ... (lambda * _: _)( @@ -2706,7 +2706,7 @@ but a string is not the only alternative available: ... (1), ... None))))):( ... __import__('builtins').setattr( - ... _QzNo7_fn, + ... _QzAW22OE5Kz_fn, ... '__qualname__', ... ('.').join( ... ('_macro_', @@ -2716,7 +2716,7 @@ but a string is not the only alternative available: ... __import__('builtins').globals(), ... '_macro_'), ... 'QzDIGITxONE_0QzHASH_', - ... _QzNo7_fn))[-1])() + ... _QzAW22OE5Kz_fn))[-1])() .. code-block:: REPL @@ -2897,14 +2897,14 @@ although you have to be careful. #.. `(op#itemgetter ,(.format "slicer{}" (hissp..demunge e)))) >>> # defmacro ... # hissp.macros.._macro_.let - ... (lambda _QzNo7_fn=(lambda e: + ... (lambda _QzAW22OE5Kz_fn=(lambda e: ... (lambda * _: _)( ... 'operator..itemgetter', ... ('slicer{}').format( ... __import__('hissp').demunge( ... e)))):( ... __import__('builtins').setattr( - ... _QzNo7_fn, + ... _QzAW22OE5Kz_fn, ... '__qualname__', ... ('.').join( ... ('_macro_', @@ -2914,7 +2914,7 @@ although you have to be careful. ... __import__('builtins').globals(), ... '_macro_'), ... 'SQzHASH_', - ... _QzNo7_fn))[-1])() + ... _QzAW22OE5Kz_fn))[-1])() .. code-block:: REPL @@ -2998,7 +2998,7 @@ Putting that all together we get #.. (hissp..demunge e)))) >>> # defmacro ... # hissp.macros.._macro_.let - ... (lambda _QzNo7_fn=(lambda e: + ... (lambda _QzAW22OE5Kz_fn=(lambda e: ... (lambda * _: _)( ... 'operator..itemgetter', ... ('({}[{})').format( @@ -3007,7 +3007,7 @@ Putting that all together we get ... __import__('hissp').demunge( ... e)))):( ... __import__('builtins').setattr( - ... _QzNo7_fn, + ... _QzAW22OE5Kz_fn, ... '__qualname__', ... ('.').join( ... ('_macro_', @@ -3017,7 +3017,7 @@ Putting that all together we get ... __import__('builtins').globals(), ... '_macro_'), ... 'QzLSQB_QzHASH_', - ... _QzNo7_fn))[-1])() + ... _QzAW22OE5Kz_fn))[-1])() Notice that this requires the ``]`` in the symbol it's applied to. This keeps it balanced. It also pretty well ensures the argument is a symbol @@ -3163,7 +3163,7 @@ Our previous macro was almost there. #.. `(lambda ,'a ,(.format "({}[{})" 'a (hissp..demunge e)))) >>> # defmacro ... # hissp.macros.._macro_.let - ... (lambda _QzNo7_fn=(lambda e: + ... (lambda _QzAW22OE5Kz_fn=(lambda e: ... (lambda * _: _)( ... 'lambda', ... 'a', @@ -3172,7 +3172,7 @@ Our previous macro was almost there. ... __import__('hissp').demunge( ... e)))):( ... __import__('builtins').setattr( - ... _QzNo7_fn, + ... _QzAW22OE5Kz_fn, ... '__qualname__', ... ('.').join( ... ('_macro_', @@ -3182,7 +3182,7 @@ Our previous macro was almost there. ... __import__('builtins').globals(), ... '_macro_'), ... 'QzLSQB_QzHASH_', - ... _QzNo7_fn))[-1])() + ... _QzAW22OE5Kz_fn))[-1])() It works. @@ -3254,17 +3254,17 @@ we should suppress the qualification with a gensym instead of a symbol interpola #.. `(lambda ($#G) ,(.format "({}[{})" '$#G (hissp..demunge e)))) >>> # defmacro ... # hissp.macros.._macro_.let - ... (lambda _QzNo7_fn=(lambda e: + ... (lambda _QzAW22OE5Kz_fn=(lambda e: ... (lambda * _: _)( ... 'lambda', ... (lambda * _: _)( - ... '_QzNo26_G'), + ... '_QzAVTK4YRWz_G'), ... ('({}[{})').format( - ... '_QzNo26_G', + ... '_QzAVTK4YRWz_G', ... __import__('hissp').demunge( ... e)))):( ... __import__('builtins').setattr( - ... _QzNo7_fn, + ... _QzAW22OE5Kz_fn, ... '__qualname__', ... ('.').join( ... ('_macro_', @@ -3274,7 +3274,7 @@ we should suppress the qualification with a gensym instead of a symbol interpola ... __import__('builtins').globals(), ... '_macro_'), ... 'QzLSQB_QzHASH_', - ... _QzNo7_fn))[-1])() + ... _QzAW22OE5Kz_fn))[-1])() Read this carefully. ``$#`` only works inside of templates, @@ -3294,11 +3294,11 @@ It works. .. code-block:: REPL #> ([#-1::-2] "abcdefg") - >>> (lambda _QzNo26_G:(_QzNo26_G[-1::-2]))( + >>> (lambda _QzAVTK4YRWz_G:(_QzAVTK4YRWz_G[-1::-2]))( ... ('abcdefg')) 'geca' -Notice the gensym in the expansion (your template number may be diferent than mine), +Notice the gensym in the expansion (your template hash may be diferent than mine), which would prevent the kind of accidental name collision we saw in our `let` ``a`` example. And *this* is the `bundled version `, sans docstring. diff --git a/docs/primer.rst b/docs/primer.rst index 253134ad..7e53014d 100644 --- a/docs/primer.rst +++ b/docs/primer.rst @@ -1563,21 +1563,44 @@ Within a template, the same gensym name always makes the same gensym: #> `($#hiss $#hiss) >>> (lambda * _: _)( - ... '_QzNo41_hiss', - ... '_QzNo41_hiss') - ('_QzNo41_hiss', '_QzNo41_hiss') + ... '_QzTAMTDLDRz_hiss', + ... '_QzTAMTDLDRz_hiss') + ('_QzTAMTDLDRz_hiss', '_QzTAMTDLDRz_hiss') -But each new template increments the counter. +But each new template changes the hash. .. code-block:: REPL - #> `$#hiss - >>> '_QzNo42_hiss' - '_QzNo42_hiss' + #> `($#hiss $#hiss) + >>> (lambda * _: _)( + ... '_QzZSOXD2IOz_hiss', + ... '_QzZSOXD2IOz_hiss') + ('_QzZSOXD2IOz_hiss', '_QzZSOXD2IOz_hiss') Gensyms are mainly used to prevent accidental name collisions in generated code, which is very important for reliable compiler macros. +The 40-bit hash is computed from the entire code string being read +(the whole ``.lissp`` file) +the module's `__name__`, and a count of the templates read so far this session. + +(In the REPL, there is no ``.lissp`` file, +so "the entire code string" is the top-level form entered.) + +A count alone isn't enough. +Files can be compiled individually in different sessions, +which would each start with a fresh counter. +It can ensure templates have a unique name within a file, +but not between files. + +Adding the module's `__name__` isn't enough either, +since it will be re-used for multiple versions of the module. +The code string stands in for the module version, +without resorting to things like tedious manual versioning +or timestamps that would prohibit reproducible builds. +The `__name__` is still required in case different modules happen to have the same code, +which can sometimes happen when they are very short. + Extra +++++ diff --git a/src/hissp/macros.lissp b/src/hissp/macros.lissp index 61024bf6..82869540 100644 --- a/src/hissp/macros.lissp +++ b/src/hissp/macros.lissp @@ -229,46 +229,46 @@ Hidden doctest adds bundled macros for REPL-consistent behavior. .. code-block:: REPL - #> (defmacro p123 (sep) - #.. <<#;Prints 1 2 3 with the given separator - #.. `(print 1 2 3 : sep ,sep)) - >>> # defmacro - ... # hissp.macros.._macro_.let - ... (lambda _QzNo7_fn=(lambda sep:( - ... 'Prints 1 2 3 with the given separator', - ... (lambda * _: _)( - ... 'builtins..print', - ... (1), - ... (2), - ... (3), - ... ':', - ... '__main__..sep', - ... sep))[-1]):( - ... __import__('builtins').setattr( - ... _QzNo7_fn, - ... '__doc__', - ... 'Prints 1 2 3 with the given separator'), - ... __import__('builtins').setattr( - ... _QzNo7_fn, - ... '__qualname__', - ... ('.').join( - ... ('_macro_', - ... 'p123',))), - ... __import__('builtins').setattr( - ... __import__('operator').getitem( - ... __import__('builtins').globals(), - ... '_macro_'), - ... 'p123', - ... _QzNo7_fn))[-1])() - - #> (p123 ::) - >>> # p123 - ... __import__('builtins').print( - ... (1), - ... (2), - ... (3), - ... sep='::') - 1::2::3 + #> (defmacro p123 (sep) + #.. <<#;Prints 1 2 3 with the given separator + #.. `(print 1 2 3 : sep ,sep)) + >>> # defmacro + ... # hissp.macros.._macro_.let + ... (lambda _QzAW22OE5Kz_fn=(lambda sep:( + ... 'Prints 1 2 3 with the given separator', + ... (lambda * _: _)( + ... 'builtins..print', + ... (1), + ... (2), + ... (3), + ... ':', + ... '__main__..sep', + ... sep))[-1]):( + ... __import__('builtins').setattr( + ... _QzAW22OE5Kz_fn, + ... '__doc__', + ... 'Prints 1 2 3 with the given separator'), + ... __import__('builtins').setattr( + ... _QzAW22OE5Kz_fn, + ... '__qualname__', + ... ('.').join( + ... ('_macro_', + ... 'p123',))), + ... __import__('builtins').setattr( + ... __import__('operator').getitem( + ... __import__('builtins').globals(), + ... '_macro_'), + ... 'p123', + ... _QzAW22OE5Kz_fn))[-1])() + + #> (p123 ::) + >>> # p123 + ... __import__('builtins').print( + ... (1), + ... (2), + ... (3), + ... sep='::') + 1::2::3 See also: `<\<# `, `attach`, @@ -565,14 +565,14 @@ Hidden doctest adds bundled macros for REPL-consistent behavior. ... print( ... # setQzAT_ ... # hissp.macros.._macro_.let - ... (lambda _QzNo29_val=__import__('operator').add( + ... (lambda _QzRMG5GSSIz_val=__import__('operator').add( ... (1), ... (1)):( ... __import__('builtins').setattr( ... the, ... 'x', - ... _QzNo29_val), - ... _QzNo29_val)[-1])(), + ... _QzRMG5GSSIz_val), + ... _QzRMG5GSSIz_val)[-1])(), ... the.x))() 2 2 @@ -842,7 +842,7 @@ Hidden doctest adds bundled macros for REPL-consistent behavior. .. code-block:: REPL #> ([#1][::2] '(foo bar)) - >>> (lambda _QzNo76_G:(_QzNo76_G[1][::2]))( + >>> (lambda _Qz5GEAOGSQz_G:(_Qz5GEAOGSQz_G[1][::2]))( ... ('foo', ... 'bar',)) 'br' @@ -866,14 +866,15 @@ Hidden doctest adds bundled macros for REPL-consistent behavior. ... spam=dict()) #> (set! spam 2 10) ; Like operator.setitem, but returns value given. + #.. >>> # setQzBANG_ ... # hissp.macros.._macro_.let - ... (lambda _QzNo28_val=(10):( + ... (lambda _QzE3BPTV2Tz_val=(10):( ... __import__('operator').setitem( ... spam, ... (2), - ... _QzNo28_val), - ... _QzNo28_val)[-1])() + ... _QzE3BPTV2Tz_val), + ... _QzE3BPTV2Tz_val)[-1])() 10 #> spam @@ -902,21 +903,22 @@ Hidden doctest adds bundled macros for REPL-consistent behavior. ... b=(10))) #> (zap! operator..iadd spam 'b 1) ; Augmented item assignment, like +=. + #.. >>> # zapQzBANG_ ... # hissp.macros.._macro_.let - ... (lambda _QzNo30_coll=spam,_QzNo30_key='b': + ... (lambda _QzRDZYRDXSz_coll=spam,_QzRDZYRDXSz_key='b': ... # hissp.macros.._macro_.setQzBANG_ ... # hissp.macros.._macro_.let - ... (lambda _QzNo28_val=__import__('operator').iadd( + ... (lambda _QzE3BPTV2Tz_val=__import__('operator').iadd( ... __import__('operator').getitem( - ... _QzNo30_coll, - ... _QzNo30_key), + ... _QzRDZYRDXSz_coll, + ... _QzRDZYRDXSz_key), ... (1)):( ... __import__('operator').setitem( - ... _QzNo30_coll, - ... _QzNo30_key, - ... _QzNo28_val), - ... _QzNo28_val)[-1])())() + ... _QzRDZYRDXSz_coll, + ... _QzRDZYRDXSz_key, + ... _QzE3BPTV2Tz_val), + ... _QzE3BPTV2Tz_val)[-1])())() 11 #> spam @@ -944,12 +946,12 @@ Hidden doctest adds bundled macros for REPL-consistent behavior. #> (set@ spam.foo 10) >>> # setQzAT_ ... # hissp.macros.._macro_.let - ... (lambda _QzNo27_val=(10):( + ... (lambda _QzRMG5GSSIz_val=(10):( ... __import__('builtins').setattr( ... spam, ... 'foo', - ... _QzNo27_val), - ... _QzNo27_val)[-1])() + ... _QzRMG5GSSIz_val), + ... _QzRMG5GSSIz_val)[-1])() 10 #> spam @@ -982,14 +984,14 @@ Hidden doctest adds bundled macros for REPL-consistent behavior. >>> # zapQzAT_ ... # hissp.macros.._macro_.setQzAT_ ... # hissp.macros.._macro_.let - ... (lambda _QzNo27_val=__import__('operator').iadd( + ... (lambda _QzRMG5GSSIz_val=__import__('operator').iadd( ... spam.foo, ... (1)):( ... __import__('builtins').setattr( ... spam, ... 'foo', - ... _QzNo27_val), - ... _QzNo27_val)[-1])() + ... _QzRMG5GSSIz_val), + ... _QzRMG5GSSIz_val)[-1])() 11 #> spam @@ -1015,20 +1017,20 @@ Hidden doctest adds bundled macros for REPL-consistent behavior. #> (attach (types..SimpleNamespace) _macro_.attach : a 1 b 'Hi) >>> # attach ... # hissp.macros.._macro_.let - ... (lambda _QzNo36_target=__import__('types').SimpleNamespace():( + ... (lambda _QzWG5WN73Wz_target=__import__('types').SimpleNamespace():( ... __import__('builtins').setattr( - ... _QzNo36_target, + ... _QzWG5WN73Wz_target, ... 'attach', ... _macro_.attach), ... __import__('builtins').setattr( - ... _QzNo36_target, + ... _QzWG5WN73Wz_target, ... 'a', ... (1)), ... __import__('builtins').setattr( - ... _QzNo36_target, + ... _QzWG5WN73Wz_target, ... 'b', ... 'Hi'), - ... _QzNo36_target)[-1])() + ... _QzWG5WN73Wz_target)[-1])() namespace(a=1, attach=, b='Hi') See also: `setattr`, `set@`, `locals`. @@ -1057,13 +1059,13 @@ Hidden doctest adds bundled macros for REPL-consistent behavior. #.. .sort #.. (.append 'foo)) >>> # doto - ... (lambda _QzNo20_self=list():( - ... _QzNo20_self.extend( + ... (lambda _QzKIUMBHNZz_self=list():( + ... _QzKIUMBHNZz_self.extend( ... 'bar'), - ... _QzNo20_self.sort(), - ... _QzNo20_self.append( + ... _QzKIUMBHNZz_self.sort(), + ... _QzKIUMBHNZz_self.append( ... 'foo'), - ... _QzNo20_self)[-1])() + ... _QzKIUMBHNZz_self)[-1])() ['a', 'b', 'r', 'foo'] See also: `attach`, `progn`, `-> `. @@ -1088,29 +1090,29 @@ Hidden doctest adds bundled macros for REPL-consistent behavior. .. code-block:: REPL - #> (.-> _macro_ : :* '(x (A b) (C d e))) - >>> _macro_.Qz_QzGT_( - ... *('x', - ... ('A', - ... 'b',), - ... ('C', - ... 'd', - ... 'e',),)) - ('C', ('A', 'x', 'b'), 'd', 'e') - - #> (-> 'a set (en#list 'bc) (en#tuple 'de)) - >>> # Qz_QzGT_ - ... (lambda *_QzNo55_xs: - ... tuple( - ... _QzNo55_xs))( - ... (lambda *_QzNo55_xs: - ... list( - ... _QzNo55_xs))( - ... set( - ... 'a'), - ... 'bc'), - ... 'de') - ([{'a'}, 'bc'], 'de') + #> (.-> _macro_ : :* '(x (A b) (C d e))) + >>> _macro_.Qz_QzGT_( + ... *('x', + ... ('A', + ... 'b',), + ... ('C', + ... 'd', + ... 'e',),)) + ('C', ('A', 'x', 'b'), 'd', 'e') + + #> (-> 'a set (en#list 'bc) (en#tuple 'de)) + >>> # Qz_QzGT_ + ... (lambda *_Qz6RFWTTVXz_xs: + ... tuple( + ... _Qz6RFWTTVXz_xs))( + ... (lambda *_Qz6RFWTTVXz_xs: + ... list( + ... _Qz6RFWTTVXz_xs))( + ... set( + ... 'a'), + ... 'bc'), + ... 'de') + ([{'a'}, 'bc'], 'de') See also: `-\<>>`, `X#`, `get#`. @@ -1130,33 +1132,33 @@ Hidden doctest adds bundled macros for REPL-consistent behavior. .. code-block:: REPL - #> (.-<>> _macro_ : :* '(x Y (:<> A b) (C d e))) - >>> _macro_.Qz_QzLT_QzGT_QzGT_( - ... *('x', - ... 'Y', - ... (':<>', - ... 'A', - ... 'b',), - ... ('C', - ... 'd', - ... 'e',),)) - ('C', 'd', 'e', (('Y', 'x'), 'A', 'b')) - - #> (-<>> 'a set (en#list 'bc) (en#tuple 'de :<> 'fg :<>)) - >>> # Qz_QzLT_QzGT_QzGT_ - ... (lambda *_QzNo55_xs: - ... tuple( - ... _QzNo55_xs))( - ... 'de', - ... (lambda *_QzNo55_xs: - ... list( - ... _QzNo55_xs))( - ... 'bc', - ... set( - ... 'a')), - ... 'fg', - ... ':<>') - ('de', ['bc', {'a'}], 'fg', ':<>') + #> (.-<>> _macro_ : :* '(x Y (:<> A b) (C d e))) + >>> _macro_.Qz_QzLT_QzGT_QzGT_( + ... *('x', + ... 'Y', + ... (':<>', + ... 'A', + ... 'b',), + ... ('C', + ... 'd', + ... 'e',),)) + ('C', 'd', 'e', (('Y', 'x'), 'A', 'b')) + + #> (-<>> 'a set (en#list 'bc) (en#tuple 'de :<> 'fg :<>)) + >>> # Qz_QzLT_QzGT_QzGT_ + ... (lambda *_Qz6RFWTTVXz_xs: + ... tuple( + ... _Qz6RFWTTVXz_xs))( + ... 'de', + ... (lambda *_Qz6RFWTTVXz_xs: + ... list( + ... _Qz6RFWTTVXz_xs))( + ... 'bc', + ... set( + ... 'a')), + ... 'fg', + ... ':<>') + ('de', ['bc', {'a'}], 'fg', ':<>') See also: `->`. " @@ -1327,19 +1329,19 @@ Hidden doctest adds bundled macros for REPL-consistent behavior. #.. (recur-from (@ (op#sub x 1))))) >>> # loopQz_from ... # hissp.macros.._macro_.let - ... (lambda _QzNo121_stack=# hissp.macros..QzMaybe_.QzAT_ + ... (lambda _QzDKFIH6Z2z_stack=# hissp.macros..QzMaybe_.QzAT_ ... (lambda *xs:[*xs])( ... (), ... None, ... ((3),)): ... # hissp.macros.._macro_.let - ... (lambda recurQz_from=_QzNo121_stack.append:( + ... (lambda recurQz_from=_QzDKFIH6Z2z_stack.append:( ... # hissp.macros.._macro_.anyQzSTAR_map ... __import__('builtins').any( ... __import__('itertools').starmap( ... (lambda x:( ... __import__('operator').setitem( - ... _QzNo121_stack, + ... _QzDKFIH6Z2z_stack, ... (0), ... # hissp.macros.._macro_.progn ... (lambda : @@ -1357,11 +1359,11 @@ Hidden doctest adds bundled macros for REPL-consistent behavior. ... (1)))))[-1])))()), ... None)[-1]), ... __import__('builtins').iter( - ... _QzNo121_stack.pop, + ... _QzDKFIH6Z2z_stack.pop, ... None))), ... __import__('operator').itemgetter( ... (0))( - ... _QzNo121_stack))[-1])())() + ... _QzDKFIH6Z2z_stack))[-1])())() 3 2 1 @@ -1522,35 +1524,36 @@ Hidden doctest adds bundled macros for REPL-consistent behavior. .. code-block:: REPL #> (throw-from Exception (Exception 'message)) ;Explicit chaining. + #.. >>> # throwQz_from ... # hissp.macros.._macro_.throwQzSTAR_ ... (lambda g:g.close()or g.throw)(c for c in'')( ... # hissp.macros.._macro_.let - ... (lambda _QzNo130_G=(lambda _QzNo130_x: + ... (lambda _Qz2IKKUCBWz_G=(lambda _Qz2IKKUCBWz_x: ... # hissp.macros.._macro_.ifQz_else ... (lambda b,c,a:c()if b else a())( ... # hissp.macros.._macro_.QzET_QzET_ ... (lambda x0,x1:x0 and x1())( ... __import__('builtins').isinstance( - ... _QzNo130_x, + ... _Qz2IKKUCBWz_x, ... __import__('builtins').type), ... (lambda : ... __import__('builtins').issubclass( - ... _QzNo130_x, + ... _Qz2IKKUCBWz_x, ... __import__('builtins').BaseException))), - ... (lambda :_QzNo130_x()), - ... (lambda :_QzNo130_x))): + ... (lambda :_Qz2IKKUCBWz_x()), + ... (lambda :_Qz2IKKUCBWz_x))): ... # hissp.macros.._macro_.attach ... # hissp.macros.._macro_.let - ... (lambda _QzNo112_target=_QzNo130_G( + ... (lambda _QzWG5WN73Wz_target=_Qz2IKKUCBWz_G( ... Exception):( ... __import__('builtins').setattr( - ... _QzNo112_target, + ... _QzWG5WN73Wz_target, ... '__cause__', - ... _QzNo130_G( + ... _Qz2IKKUCBWz_G( ... Exception( ... 'message'))), - ... _QzNo112_target)[-1])())()) + ... _QzWG5WN73Wz_target)[-1])())()) Traceback (most recent call last): ... Exception @@ -1579,12 +1582,12 @@ Hidden doctest adds bundled macros for REPL-consistent behavior. >>> print( ... # prog1 ... # hissp.macros.._macro_.let - ... (lambda _QzNo28_value1=(0):( + ... (lambda _Qz46BJ7IW6z_value1=(0):( ... print( ... (1)), ... print( ... (2)), - ... _QzNo28_value1)[-1])()) + ... _Qz46BJ7IW6z_value1)[-1])()) 1 2 0 @@ -1599,14 +1602,14 @@ Hidden doctest adds bundled macros for REPL-consistent behavior. #.. (print 2)) >>> # prog1 ... # hissp.macros.._macro_.let - ... (lambda _QzNo35_value1=# progn + ... (lambda _Qz46BJ7IW6z_value1=# progn ... (lambda :( ... print( ... (1)), ... (3))[-1])():( ... print( ... (2)), - ... _QzNo35_value1)[-1])() + ... _Qz46BJ7IW6z_value1)[-1])() 1 2 3 @@ -1648,18 +1651,19 @@ Hidden doctest adds bundled macros for REPL-consistent behavior. ;; .. code-block:: REPL ;; ;; #> (en#list 1 2 3) - ;; >>> (lambda *_QzNo53_xs: + ;; >>> (lambda *_Qz6RFWTTVXz_xs: ;; ... list( - ;; ... _QzNo53_xs))( + ;; ... _Qz6RFWTTVXz_xs))( ;; ... (1), ;; ... (2), ;; ... (3)) ;; [1, 2, 3] ;; ;; #> (en#.extend _ 4 5 6) ; Methods too. - ;; >>> (lambda _QzNo52_self,*_QzNo52_xs: - ;; ... _QzNo52_self.extend( - ;; ... _QzNo52_xs))( + ;; #.. + ;; >>> (lambda _Qz4LWLAFU3z_self,*_Qz4LWLAFU3z_xs: + ;; ... _Qz4LWLAFU3z_self.extend( + ;; ... _Qz4LWLAFU3z_xs))( ;; ... _, ;; ... (4), ;; ... (5), @@ -1672,13 +1676,13 @@ Hidden doctest adds bundled macros for REPL-consistent behavior. ;; #> (define enjoin en#X#(.join "" (map str X))) ;; >>> # define ;; ... __import__('builtins').globals().update( - ;; ... enjoin=(lambda *_QzNo55_xs: + ;; ... enjoin=(lambda *_Qz6RFWTTVXz_xs: ;; ... (lambda X: ;; ... ('').join( ;; ... map( ;; ... str, ;; ... X)))( - ;; ... _QzNo55_xs))) + ;; ... _Qz6RFWTTVXz_xs))) ;; ;; #> (enjoin "Sum: "(op#add 2 3)". Product: "(op#mul 2 3)".") ;; >>> enjoin( @@ -2052,15 +2056,15 @@ except ModuleNotFoundError:pass" .. code-block:: REPL #> (^#:2) - >>> (lambda *_QzNo73_args: + >>> (lambda *_Qz5P6Q3J7Uz_args: ... # hissp.macros.._macro_.let - ... (lambda _QzNo73_stack=__import__('builtins').list( - ... _QzNo73_args):( - ... _QzNo73_stack.reverse(), - ... _QzNo73_stack.append( + ... (lambda _Qz5P6Q3J7Uz_stack=__import__('builtins').list( + ... _Qz5P6Q3J7Uz_args):( + ... _Qz5P6Q3J7Uz_stack.reverse(), + ... _Qz5P6Q3J7Uz_stack.append( ... (2)), ... (), - ... _QzNo73_stack.pop())[-1])())() + ... _Qz5P6Q3J7Uz_stack.pop())[-1])())() 2 Callables (default depth 1) pop args to their depth and push their @@ -2071,23 +2075,23 @@ except ModuleNotFoundError:pass" #> (define decrement ^#sub^@1) >>> # define ... __import__('builtins').globals().update( - ... decrement=(lambda *_QzNo73_args: + ... decrement=(lambda *_Qz5P6Q3J7Uz_args: ... # hissp.macros.._macro_.let - ... (lambda _QzNo73_stack=__import__('builtins').list( - ... _QzNo73_args):( - ... _QzNo73_stack.reverse(), - ... _QzNo73_stack.append( + ... (lambda _Qz5P6Q3J7Uz_stack=__import__('builtins').list( + ... _Qz5P6Q3J7Uz_args):( + ... _Qz5P6Q3J7Uz_stack.reverse(), + ... _Qz5P6Q3J7Uz_stack.append( ... (1)), - ... _QzNo73_stack.append( - ... _QzNo73_stack.pop( + ... _Qz5P6Q3J7Uz_stack.append( + ... _Qz5P6Q3J7Uz_stack.pop( ... (-2))), - ... _QzNo73_stack.append( + ... _Qz5P6Q3J7Uz_stack.append( ... sub( - ... _QzNo73_stack.pop( + ... _Qz5P6Q3J7Uz_stack.pop( ... (-1)), - ... _QzNo73_stack.pop( + ... _Qz5P6Q3J7Uz_stack.pop( ... (-1)))), - ... _QzNo73_stack.pop())[-1])())) + ... _Qz5P6Q3J7Uz_stack.pop())[-1])())) #> (decrement 5) >>> decrement( @@ -2102,21 +2106,21 @@ except ModuleNotFoundError:pass" .. code-block:: REPL #> (^#.__class__.__name__:'spam^ (dict : spam 'eggs)) - >>> (lambda *_QzNo73_args: + >>> (lambda *_Qz5P6Q3J7Uz_args: ... # hissp.macros.._macro_.let - ... (lambda _QzNo73_stack=__import__('builtins').list( - ... _QzNo73_args):( - ... _QzNo73_stack.reverse(), - ... _QzNo73_stack.append( + ... (lambda _Qz5P6Q3J7Uz_stack=__import__('builtins').list( + ... _Qz5P6Q3J7Uz_args):( + ... _Qz5P6Q3J7Uz_stack.reverse(), + ... _Qz5P6Q3J7Uz_stack.append( ... __import__('operator').getitem( - ... _QzNo73_stack.pop(), + ... _Qz5P6Q3J7Uz_stack.pop(), ... 'spam')), ... (), - ... _QzNo73_stack.append( + ... _Qz5P6Q3J7Uz_stack.append( ... __import__('operator').attrgetter( ... '__class__.__name__')( - ... _QzNo73_stack.pop())), - ... _QzNo73_stack.pop())[-1])())( + ... _Qz5P6Q3J7Uz_stack.pop())), + ... _Qz5P6Q3J7Uz_stack.pop())[-1])())( ... dict( ... spam='eggs')) 'str' @@ -2131,25 +2135,25 @@ except ModuleNotFoundError:pass" #> (define prod ^#reduce^mul,) >>> # define ... __import__('builtins').globals().update( - ... prod=(lambda *_QzNo73_args: + ... prod=(lambda *_Qz5P6Q3J7Uz_args: ... # hissp.macros.._macro_.let - ... (lambda _QzNo73_stack=__import__('builtins').list( - ... _QzNo73_args):( - ... _QzNo73_stack.reverse(), - ... _QzNo73_stack.append( + ... (lambda _Qz5P6Q3J7Uz_stack=__import__('builtins').list( + ... _Qz5P6Q3J7Uz_args):( + ... _Qz5P6Q3J7Uz_stack.reverse(), + ... _Qz5P6Q3J7Uz_stack.append( ... mul), - ... _QzNo73_stack.append( + ... _Qz5P6Q3J7Uz_stack.append( ... reduce( - ... _QzNo73_stack.pop( + ... _Qz5P6Q3J7Uz_stack.pop( ... (-1)), - ... _QzNo73_stack.pop( + ... _Qz5P6Q3J7Uz_stack.pop( ... (-1)))), - ... _QzNo73_stack.pop())[-1])())) + ... _Qz5P6Q3J7Uz_stack.pop())[-1])())) #> (en#prod 1 2 3) - >>> (lambda *_QzNo60_xs: + >>> (lambda *_Qz6RFWTTVXz_xs: ... prod( - ... _QzNo60_xs))( + ... _Qz6RFWTTVXz_xs))( ... (1), ... (2), ... (3)) @@ -2158,42 +2162,42 @@ except ModuleNotFoundError:pass" #> (define geomean ^#pow^prod@truediv^1:len&) >>> # define ... __import__('builtins').globals().update( - ... geomean=(lambda *_QzNo73_args: + ... geomean=(lambda *_Qz5P6Q3J7Uz_args: ... # hissp.macros.._macro_.let - ... (lambda _QzNo73_stack=__import__('builtins').list( - ... _QzNo73_args):( - ... _QzNo73_stack.reverse(), - ... _QzNo73_stack.append( + ... (lambda _Qz5P6Q3J7Uz_stack=__import__('builtins').list( + ... _Qz5P6Q3J7Uz_args):( + ... _Qz5P6Q3J7Uz_stack.reverse(), + ... _Qz5P6Q3J7Uz_stack.append( ... (lambda X,Y:X[-1-Y])( - ... _QzNo73_stack, + ... _Qz5P6Q3J7Uz_stack, ... (0))), - ... _QzNo73_stack.append( + ... _Qz5P6Q3J7Uz_stack.append( ... len( - ... _QzNo73_stack.pop( + ... _Qz5P6Q3J7Uz_stack.pop( ... (-1)))), ... (), - ... _QzNo73_stack.append( + ... _Qz5P6Q3J7Uz_stack.append( ... (1)), - ... _QzNo73_stack.append( + ... _Qz5P6Q3J7Uz_stack.append( ... truediv( - ... _QzNo73_stack.pop( + ... _Qz5P6Q3J7Uz_stack.pop( ... (-1)), - ... _QzNo73_stack.pop( + ... _Qz5P6Q3J7Uz_stack.pop( ... (-1)))), - ... _QzNo73_stack.append( - ... _QzNo73_stack.pop( + ... _Qz5P6Q3J7Uz_stack.append( + ... _Qz5P6Q3J7Uz_stack.pop( ... (-2))), - ... _QzNo73_stack.append( + ... _Qz5P6Q3J7Uz_stack.append( ... prod( - ... _QzNo73_stack.pop( + ... _Qz5P6Q3J7Uz_stack.pop( ... (-1)))), - ... _QzNo73_stack.append( + ... _Qz5P6Q3J7Uz_stack.append( ... pow( - ... _QzNo73_stack.pop( + ... _Qz5P6Q3J7Uz_stack.pop( ... (-1)), - ... _QzNo73_stack.pop( + ... _Qz5P6Q3J7Uz_stack.pop( ... (-1)))), - ... _QzNo73_stack.pop())[-1])())) + ... _Qz5P6Q3J7Uz_stack.pop())[-1])())) #> (geomean '(1 10)) >>> geomean( @@ -2275,7 +2279,7 @@ except ModuleNotFoundError:pass" ... (5), ... # hissp.._macro_._spy ... # hissp.macros.._macro_.let - ... (lambda _QzNo73_e=__import__('operator').mul( + ... (lambda _Qz764KZBP5z_e=__import__('operator').mul( ... (7), ... (3)):( ... __import__('builtins').print( @@ -2286,9 +2290,9 @@ except ModuleNotFoundError:pass" ... sort_dicts=(0)), ... ('=>'), ... __import__('builtins').repr( - ... _QzNo73_e), + ... _Qz764KZBP5z_e), ... file=__import__('sys').stdout), - ... _QzNo73_e)[-1])()) + ... _Qz764KZBP5z_e)[-1])()) ('operator..mul', 7, 3) => 21 26 @@ -2305,9 +2309,9 @@ except ModuleNotFoundError:pass" #> time#!sys..stdout(time..sleep .05) >>> # hissp.macros.._macro_.let - ... (lambda _QzNo75_time=__import__('time').time_ns: + ... (lambda _QzPMWTVFTZz_time=__import__('time').time_ns: ... # hissp.macros.._macro_.letQz_from - ... (lambda _QzNo75_start,_QzNo75_val,_QzNo75_end:( + ... (lambda _QzPMWTVFTZz_start,_QzPMWTVFTZz_val,_QzPMWTVFTZz_end:( ... __import__('builtins').print( ... ('time# ran'), ... __import__('pprint').pformat( @@ -2317,19 +2321,19 @@ except ModuleNotFoundError:pass" ... ('in'), ... __import__('operator').truediv( ... __import__('operator').sub( - ... _QzNo75_end, - ... _QzNo75_start), + ... _QzPMWTVFTZz_end, + ... _QzPMWTVFTZz_start), ... __import__('decimal').Decimal( ... (1000000.0))), ... ('ms'), ... file=__import__('sys').stdout), - ... _QzNo75_val)[-1])( + ... _QzPMWTVFTZz_val)[-1])( ... *# hissp.macros.._macro_.QzAT_ ... (lambda *xs:[*xs])( - ... _QzNo75_time(), + ... _QzPMWTVFTZz_time(), ... __import__('time').sleep( ... (0.05)), - ... _QzNo75_time())))() + ... _QzPMWTVFTZz_time())))() time# ran ('time..sleep', 0.05) in ... ms See also: `timeit`. diff --git a/src/hissp/reader.py b/src/hissp/reader.py index 17d99ae4..f8d03259 100644 --- a/src/hissp/reader.py +++ b/src/hissp/reader.py @@ -14,7 +14,9 @@ import ast import builtins +import hashlib import re +from base64 import b32encode from collections import namedtuple from contextlib import contextmanager, nullcontext, suppress from functools import reduce @@ -24,12 +26,25 @@ from pathlib import Path, PurePath from pprint import pformat from threading import Lock -from typing import Any, Iterable, Iterator, NewType, Optional, Tuple, Union +from typing import Any, Iterable, Iterator, NewType, Optional, Tuple, Union, List import hissp.compiler as C from hissp.compiler import Compiler, readerless from hissp.munger import force_qz_encode, munge +GENSYM_BYTES = 5 +""" +The number of bytes gensym `$# ` hashes have. + +The default 5 bytes (40 bits) should be more than sufficient space to +eliminate collisions with typical usage, but for unusual applications, +hash length can be increased, up to a maximum of 32 bytes. +(16 would have more space than UUID4.) + +Each hash character encodes 5 bits (base32 encoding), so 40-bit hashes +typically take 8 characters. +""" + ENTUPLE = ("lambda",(":",":*"," _")," _",) # fmt: skip """ Used by the template macro to make tuples. @@ -156,7 +171,7 @@ def __repr__(self): return f"Extra({list(self)!r})" -def gensym_counter(_count=[0], _lock=Lock()): +def gensym_counter(_count=[0], _lock=Lock()) -> int: """ Call to increment the gensym counter, and return the new count. Used by the gensym reader macro ``$#`` to ensure symbols are unique. @@ -188,7 +203,7 @@ def __init__( def reinit(self): """Reset position, nesting depth, and gensym stack.""" - self.counters = [] + self.counters: List[int] = [] self.context = [] self.depth = [] self._p = 0 @@ -209,6 +224,9 @@ def compile(self, code: str) -> str: def reads(self, code: str) -> Iterable: """Read Hissp forms from code string.""" + self.blake = hashlib.blake2s(digest_size=GENSYM_BYTES) + self.blake.update(code.encode()) + self.blake.update(self.ns.get("__name__", "__main__").encode()) res: Iterable[object] = self.parse(Lexer(code, self.filename)) self.reinit() return res @@ -395,14 +413,16 @@ def gensym(self, form: str): Re-munges any $'s as a gensym counter, or adds it as a prefix if there aren't any. """ - prefix = f"_QzNo{self._get_counter()}_" + blk = self.blake.copy() + blk.update((c := self._get_counter()).to_bytes(1 + c.bit_length() // 8, "big")) + prefix = f"_Qz{b32encode(blk.digest()).rstrip(b'=').decode()}z_" marker = munge("$") if marker not in form: return f"{prefix}{(form)}" # TODO: escape $'s somehow? $$? \$? return form.replace(marker, prefix) - def _get_counter(self): + def _get_counter(self) -> int: index = self.context.count("`") - self.context.count(",") if not self.context or index < 0: raise SyntaxError("Gensym outside of template.", self.position()) from None @@ -538,7 +558,7 @@ def is_qualifiable(symbol): return ( symbol not in {"quote", "__import__"} and not _iskeyword(symbol) - and not re.match(r"_QzNo\d+_", symbol) + and not re.match(r"_Qz[A-Z2-7]+z_", symbol) and all(map(str.isidentifier, symbol.split("."))) ) diff --git a/tests/test_macros.lissp b/tests/test_macros.lissp index 8ef35565..27bfde9f 100644 --- a/tests/test_macros.lissp +++ b/tests/test_macros.lissp @@ -39,7 +39,7 @@ test_inner_gensym (lambda (self) - (self.assertRegex `$#self.$foo "self._QzNo\d+_foo$")) + (self.assertRegex `$#self.$foo "self._Qz[A-Z2-7]+z_foo$")) test_qualified_symbol (lambda (self) diff --git a/tests/test_reader.py b/tests/test_reader.py index 39d22a53..1d06137f 100644 --- a/tests/test_reader.py +++ b/tests/test_reader.py @@ -103,11 +103,11 @@ def test_no_qualification(self): ("entuple", ":", ":?", ("quote", "quote"), ":?", 1), ("entuple", ":", ":?", ("quote", "lambda"), ":?", ":"), ("quote", "__import__"), - ("quote", "_QzNo0_"), + ("quote", "_QzABCDEFGz_"), ("quote", "foo..bar"), ("quote", "foo.")], [*self.parser.reads( - "`(.x) `(quote 1) `(lambda :) `__import__ `_QzNo0_ `foo..bar `foo." + "`(.x) `(quote 1) `(lambda :) `__import__ `_QzABCDEFGz_ `foo..bar `foo." )], ) # fmt: skip