From 92b4fee0544a72d010c9b661bc86fafc7b3ea678 Mon Sep 17 00:00:00 2001 From: gilch Date: Sat, 20 Jul 2024 12:17:46 -0600 Subject: [PATCH 01/17] Use prelude tag in EDN example --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 0d55f663f..b706fff5b 100644 --- a/README.md +++ b/README.md @@ -405,7 +405,7 @@ which includes Clojure-like persistent data structures. ```EDN 0 ; from garden_of_edn import _this_file_as_main_; """#" -(hissp/_macro_.prelude) +#hissp/prelude . (defmacro #hissp/$"m#" t (tuple (.extend [(quote pyrsistent/m) (quote .)] t))) (defmacro #hissp/$"j#" j (complex 0 j)) From 8c0e8909e52b8df0587375c4e11c3550c2627f88 Mon Sep 17 00:00:00 2001 From: gilch Date: Mon, 29 Jul 2024 15:08:05 -0600 Subject: [PATCH 02/17] Add missing copyright and license comments Sphinx likes to generate a few files for inclusion with documentation source with normal usage, but they don't include copyright and license information, so they probably don't care to enforce it. (Just being thorough.) --- .coveragerc | 3 +++ .gitignore | 10 ++++++++++ CONTRIBUTING.md | 4 ++++ docs/Makefile | 4 +++- docs/conf.py | 35 +++++++++++++++++++++++++++++++---- docs/make.bat | 4 +++- 6 files changed, 54 insertions(+), 6 deletions(-) diff --git a/.coveragerc b/.coveragerc index 6581fd555..b65c04b22 100644 --- a/.coveragerc +++ b/.coveragerc @@ -1,3 +1,6 @@ +# This configuration file is part of Hissp's test suite, +# Copyright 2019, 2024 Matthew Egan Odendahl +# SPDX-License-Identifier: Apache-2.0 [run] source=. omit= diff --git a/.gitignore b/.gitignore index a7faf47e4..b6467d0b0 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,12 @@ +# File adapted from GitHub's public-domain Python .gitignore file. +# See https://github.com/github/gitignore/blob/main/Python.gitignore +# for their current version. No copyright is claimed on public-domain +# portions. +# +# This configuration file is part of the Hissp source code repository, +# copyright 2019, 2020, 2023, 2024 Matthew Egan Odendahl +# SPDX-License-Identifier: Apache-2.0 + # Byte-compiled / optimized / DLL files __pycache__/ *.py[cod] @@ -18,6 +27,7 @@ lib/ lib64/ parts/ sdist/ +setup/ var/ wheels/ *.egg-info/ diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 8dac59ed6..e78f33b7a 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,3 +1,7 @@ + ## Contributing There are many ways to contribute to an open-source project, even without writing code. diff --git a/docs/Makefile b/docs/Makefile index 1bf89748c..b8ed81763 100644 --- a/docs/Makefile +++ b/docs/Makefile @@ -1,4 +1,6 @@ -# Sphinx-generated file. See https://www.sphinx-doc.org for copyright and license. +# Sphinx generated this file. See https://www.sphinx-doc.org for copyright and license. +# SPDX-License-Identifier: BSD-2-Clause + # Minimal makefile for Sphinx documentation # diff --git a/docs/conf.py b/docs/conf.py index 44d00acc0..51c77365d 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -1,6 +1,33 @@ -# Adapted from Sphinx configuration template. Changes -# copyright 2019, 2020, 2021, 2022, 2023 Matthew Egan Odendahl -# SPDX-License-Identifier: Apache-2.0 +# Adapted from Sphinx configuration template. Modifications +# copyright 2019, 2020, 2021, 2022, 2023, 2024 Matthew Egan Odendahl +# SPDX-License-Identifier: Apache-2.0 AND BSD-2-Clause + +# [https://github.com/sphinx-doc/sphinx/blob/v4.2.0/AUTHORS] +# Copyright (c) 2007-2021 by the Sphinx team (see AUTHORS file). +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# +# * Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # Configuration file for the Sphinx documentation builder. # @@ -28,7 +55,7 @@ # -- Project information ----------------------------------------------------- project = "Hissp" -copyright = "2019, 2020, 2021, 2022, 2023 Matthew Egan Odendahl" +copyright = "2019, 2020, 2021, 2022, 2023, 2024 Matthew Egan Odendahl" author = "Matthew Egan Odendahl" diff --git a/docs/make.bat b/docs/make.bat index cfe9ebd14..041f4e899 100644 --- a/docs/make.bat +++ b/docs/make.bat @@ -1,4 +1,6 @@ -REM Sphinx-generated file. See https://www.sphinx-doc.org for copyright and license. +@REM Sphinx generated this file. +@REM SPDX-License-Identifier: BSD-2-Clause + @ECHO OFF pushd %~dp0 From 59ca9f8a3c27396bfaf55700921d4daf6e433336 Mon Sep 17 00:00:00 2001 From: gilch Date: Sun, 4 Aug 2024 16:09:10 -0600 Subject: [PATCH 03/17] Factor out _identity() The macroexpand_all() documentation is more clear this way than for a couple of opaque lambdas as before. --- src/hissp/compiler.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/hissp/compiler.py b/src/hissp/compiler.py index 4bee34a03..17c33d54e 100644 --- a/src/hissp/compiler.py +++ b/src/hissp/compiler.py @@ -640,7 +640,11 @@ def macroexpand(form, ns=None): form = expanded -def macroexpand_all(form, ns=None, *, preprocess=lambda x: x, postprocess=lambda x: x): +def _identity(x): + return x + + +def macroexpand_all(form, ns=None, *, preprocess=_identity, postprocess=_identity): """Recursively macroexpand everything possible from the outside-in. Pipes outer form through preprocess, `macroexpand`, and postprocess, From d91492c7a6875a59bb970c5472e6365b30be0228 Mon Sep 17 00:00:00 2001 From: gilch Date: Sun, 4 Aug 2024 16:11:34 -0600 Subject: [PATCH 04/17] Fix reference warning I don't think you'll need a link to document a builtin here. The alternatives might be `globals` or `globals()`, which seem even more confusing. --- src/hissp/compiler.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hissp/compiler.py b/src/hissp/compiler.py index 17c33d54e..cdd8036e1 100644 --- a/src/hissp/compiler.py +++ b/src/hissp/compiler.py @@ -613,7 +613,7 @@ def macroexpand1(form, ns=None): If form is not a macro form, returns it unaltered. Uses the current `NS` (available in a `macro_context`), unless - an alternative mapping (such as `globals()`) is provided. + an alternative mapping (such as ``globals()``) is provided. """ if type(form) is not tuple or not form or form[0] in {"quote", "lambda"}: return form From ef335643e12eb37d224df46851ac9338db3339cb Mon Sep 17 00:00:00 2001 From: gilch Date: Tue, 13 Aug 2024 11:06:59 -0600 Subject: [PATCH 05/17] Change wiki icon to open book This is closer to GitHub's icon for it. --- docs/README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/README.md b/docs/README.md index 95cdecd1a..f80884d67 100644 --- a/docs/README.md +++ b/docs/README.md @@ -1,5 +1,5 @@ # Hissp Documentation @@ -15,7 +15,7 @@ ${\boldsymbol {\color{royalblue}{(}\color{green}{\textsf -}\color{gold}{)}\color [**m**] [Community Chat](https://gitter.im/hissp-lang/community) ⭐ [On GitHub (Source Code)](https://github.com/gilch/hissp) 🗪 [Discussions Page](https://github.com/gilch/hissp/discussions) -🕸 [Hissp Wiki](https://github.com/gilch/hissp/wiki) +📖 [Hissp Wiki](https://github.com/gilch/hissp/wiki) ## Building Docs Hissp proper has no dependencies, but its documentation is built with Sphinx. From c03c420b034674f6fc8d743cbf97e501f750e04b Mon Sep 17 00:00:00 2001 From: gilch Date: Tue, 13 Aug 2024 16:17:32 -0600 Subject: [PATCH 06/17] Add refresh# and subrepl# --- src/hissp/macros.lissp | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/src/hissp/macros.lissp b/src/hissp/macros.lissp index b0c33ed28..e5f7feb66 100644 --- a/src/hissp/macros.lissp +++ b/src/hissp/macros.lissp @@ -2782,3 +2782,29 @@ except ModuleNotFoundError:pass" (if-else __debug__ `(avow ,e ,predicate ,@args) e)) + +(defmacro refresh\# (module) + "For interactive use. Attempt to recompile and reload a module. + + There must be a corresponding ``.lissp`` file present to recompile. + The module must have ``__name__`` and ``__package__`` attributes. + + A `:` argument will attempt to recompile the current module. + + Reloading the main module (which would have side effects) is not + supported. Send the REPL updated top-level definitions individually or + restart the REPL instead. A corresponding compiled Python file is not + required for a ``.lissp`` file run as the main module. + + See also: `subrepl#`. + " + `(let ($#ns ,(if-else (op#eq ': module) + `(globals) + `(vars ,module))) + (hissp.reader..transpile (.get $#ns "__package__") + (.get $#ns "__name__")) + (importlib..reload (importlib..import_module (.get $#ns "__name__"))))) + +(defmacro subrepl\# (module) + "For interactive use. Start a Lissp subREPL in the given module." + `(hissp..interact (vars ,module))) From 311ac6d6d8f02cafc4b7d1f6fe1b3d65440132cb Mon Sep 17 00:00:00 2001 From: gilch Date: Tue, 13 Aug 2024 16:18:46 -0600 Subject: [PATCH 07/17] Consistently use single-character sets Linter wants me to use \ instead, but I think this is more legible. --- src/hissp/reader.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/hissp/reader.py b/src/hissp/reader.py index 28c05baa1..453caeb7c 100644 --- a/src/hissp/reader.py +++ b/src/hissp/reader.py @@ -68,8 +68,8 @@ (?P[\n ]+) |(?P(?:[ ]*;.*\n)+) |(?P\s) # Other whitespace not allowed. - |(?P\() - |(?P\)) + |(?P[(]) + |(?P[)]) |(?P ,@ |['`,] From 37f6e3135fa1b55b8af053c843223d0f7f39e18d Mon Sep 17 00:00:00 2001 From: gilch Date: Tue, 13 Aug 2024 16:19:18 -0600 Subject: [PATCH 08/17] Rework lambda text layout Increase gensym prefix separation for legibility fix inconsistent indent Simplify Compiler.body Add drop for lambda as default edge case fix README fix whirlwind tour fix primer fix compiler doctest fix inner gensym test fix test_cmd fix macro_tutorial fix macros docstrings --- README.md | 28 +- docs/lissp_whirlwind_tour.rst | 498 ++++--- docs/macro_tutorial.rst | 2367 ++++++++++++++++++--------------- docs/primer.rst | 226 ++-- src/hissp/compiler.py | 83 +- src/hissp/macros.lissp | 1511 +++++++++++---------- src/hissp/reader.py | 2 +- tests/test_cmd.py | 8 +- tests/test_macros.lissp | 2 +- 9 files changed, 2603 insertions(+), 2122 deletions(-) diff --git a/README.md b/README.md index b706fff5b..edbf94e9b 100644 --- a/README.md +++ b/README.md @@ -83,9 +83,9 @@ which are compiled to Python code, >>> python_code = readerless(hissp_code) >>> print(python_code) (lambda name: - print( - 'Hello', - name)) + print( + 'Hello', + name)) ``` and evaluated by Python. @@ -134,13 +134,13 @@ Strings also have a few special cases: ... ) ... >>> print(readerless(adv_hissp_code)) -(lambda name='world':( - print( - 'Hello,'), - print( - *name.upper(), - sep=':', - file=__import__('sys').stdout))[-1]) +(lambda name='world': + (print( + 'Hello,'), + print( + *name.upper(), + sep=':', + file=__import__('sys').stdout)) [-1]) >>> greetier = eval(readerless(adv_hissp_code)) >>> greetier() Hello, @@ -195,12 +195,12 @@ branch( 0==1, # thunk (lambda : - print( - 'yes')), + print( + 'yes')), # thunk (lambda : - print( - 'no'))) + print( + 'no'))) >>> eval(expansion) no diff --git a/docs/lissp_whirlwind_tour.rst b/docs/lissp_whirlwind_tour.rst index 27af98c1a..e866d7a5c 100644 --- a/docs/lissp_whirlwind_tour.rst +++ b/docs/lissp_whirlwind_tour.rst @@ -587,11 +587,13 @@ Lissp Whirlwind Tour #.. (.title salutation) #.. name)))) >>> globals().update( - ... greet=(lambda salutation,name: - ... print( - ... ('{}, {}!').format( - ... salutation.title(), - ... name)))) + ... greet=( + ... lambda salutation, + ... name: + ... print( + ... ('{}, {}!').format( + ... salutation.title(), + ... name)))) #> (greet "hello" "World") >>> greet( @@ -618,13 +620,13 @@ Lissp Whirlwind Tour #.. 1))) >>> globals().update( ... factorial_I=(lambda i: - ... __import__('functools').reduce( - ... __import__('operator').mul, - ... range( - ... i, - ... (0), - ... (-1)), - ... (1)))) + ... __import__('functools').reduce( + ... __import__('operator').mul, + ... range( + ... i, + ... (0), + ... (-1)), + ... (1)))) #> (factorial_I 0) >>> factorial_I( @@ -676,7 +678,10 @@ Lissp Whirlwind Tour >>> __import__('operator').setitem( ... boolQz_QzGT_caller, ... True, - ... (lambda L,R:L())) + ... ( + ... lambda L, + ... R: + ... L())) ;; False calls right. @@ -684,7 +689,10 @@ Lissp Whirlwind Tour >>> __import__('operator').setitem( ... boolQz_QzGT_caller, ... False, - ... (lambda L,R:R())) + ... ( + ... lambda L, + ... R: + ... R())) #> (.update (globals) @@ -693,13 +701,16 @@ Lissp Whirlwind Tour #.. ((operator..getitem bool->caller (bool condition)) #.. then_thunk else_thunk))) >>> globals().update( - ... ternary=(lambda condition,then_thunk,else_thunk: - ... __import__('operator').getitem( - ... boolQz_QzGT_caller, - ... bool( - ... condition))( - ... then_thunk, - ... else_thunk))) + ... ternary=( + ... lambda condition, + ... then_thunk, + ... else_thunk: + ... __import__('operator').getitem( + ... boolQz_QzGT_caller, + ... bool( + ... condition))( + ... then_thunk, + ... else_thunk))) ;;;; 8.3 Obligatory Factorial II @@ -714,18 +725,18 @@ Lissp Whirlwind Tour #.. (operator..mul i (factorial_II (operator..sub i 1))))))) >>> globals().update( ... factorial_II=(lambda i: - ... ternary( - ... __import__('operator').le( - ... i, - ... (1)), - ... (lambda :(1)), - ... (lambda : - ... __import__('operator').mul( + ... ternary( + ... __import__('operator').le( ... i, - ... factorial_II( - ... __import__('operator').sub( + ... (1)), + ... (lambda : (1)), + ... (lambda : + ... __import__('operator').mul( ... i, - ... (1)))))))) + ... factorial_II( + ... __import__('operator').sub( + ... i, + ... (1)))))))) #> (factorial_II 5) >>> factorial_II( @@ -746,70 +757,123 @@ Lissp Whirlwind Tour #.. (print (globals)) #.. (print (locals)) ;side effects #.. b) ;last value is returned - >>> (lambda a,b,/,c,d,e=(1),f=(2),*args,h=(4),i,j=(1),**kwargs:( - ... print( - ... globals()), - ... print( - ... locals()), - ... b)[-1]) + >>> ( + ... lambda a, + ... b, + ... /, + ... c, + ... d, + ... e=(1), + ... f=(2), + ... *args, + ... h=(4), + ... i, + ... j=(1), + ... **kwargs: + ... (print( + ... globals()), + ... print( + ... locals()), + ... b) [-1]) at 0x...> #> (lambda (: a :? b :? c 1)) ;Note the : separator like calls. - >>> (lambda a,b,c=(1):()) + >>> ( + ... lambda a, + ... b, + ... c=(1): + ... ()) at 0x...> #> (lambda (a : b :? c 1)) ;`a` now implicitly paired with :?. - >>> (lambda a,b,c=(1):()) + >>> ( + ... lambda a, + ... b, + ... c=(1): + ... ()) at 0x...> #> (lambda (a b : c 1)) ;Next isn't paired with :?. The : stops here. - >>> (lambda a,b,c=(1):()) + >>> ( + ... lambda a, + ... b, + ... c=(1): + ... ()) at 0x...> #> (lambda (: :* a)) ;Star arg must pair with star, as Python. - >>> (lambda *a:()) + >>> (lambda *a: ()) at 0x...> #> (lambda (: :* :? x :?)) ;Empty star arg, so x is keyword only. - >>> (lambda *,x:()) + >>> ( + ... lambda *, + ... x: + ... ()) at 0x...> #> (lambda (:* : x :?)) ;Slid : over one. Still a kwonly. - >>> (lambda *,x:()) + >>> ( + ... lambda *, + ... x: + ... ()) at 0x...> #> (lambda (:* x :)) ;Implicit :? is the same. Compare. - >>> (lambda *,x:()) + >>> ( + ... lambda *, + ... x: + ... ()) at 0x...> #> (lambda (:* a)) ;Kwonly! Not star arg! Final : implied. - >>> (lambda *,a:()) + >>> ( + ... lambda *, + ... a: + ... ()) at 0x...> #> (lambda (a b : x None y None)) ;Normal, then positional defaults. - >>> (lambda a,b,x=None,y=None:()) + >>> ( + ... lambda a, + ... b, + ... x=None, + ... y=None: + ... ()) at 0x...> #> (lambda (:* a b : x None y None)) ;Keyword only, then keyword defaults. - >>> (lambda *,a,b,x=None,y=None:()) + >>> ( + ... lambda *, + ... a, + ... b, + ... x=None, + ... y=None: + ... ()) at 0x...> #> (lambda (spam eggs) eggs) ;Simple cases look like other Lisps, but - >>> (lambda spam,eggs:eggs) + >>> ( + ... lambda spam, + ... eggs: + ... eggs) at 0x...> #> ((lambda abc ; params not strictly required to be a tuple. #.. (print c b a)) ;There are three parameters. #.. 3 2 1) - >>> (lambda a,b,c: - ... print( - ... c, - ... b, - ... a))( + >>> ( + ... lambda a, + ... b, + ... c: + ... print( + ... c, + ... b, + ... a))( ... (3), ... (2), ... (1)) @@ -817,17 +881,17 @@ Lissp Whirlwind Tour #> (lambda (:)) ;Explicit : still allowed with no params. - >>> (lambda :()) + >>> (lambda : ()) at 0x...> #> (lambda : (print "oops")) ;Thunk resembles Python. >>> (lambda : - ... print( - ... ('oops'))) + ... print( + ... ('oops'))) at 0x...> #> ((lambda :x1 x)) ;Control words are strings are iterable. - >>> (lambda x=1:x)() + >>> (lambda x=1: x)() 1 @@ -943,13 +1007,13 @@ Lissp Whirlwind Tour ':?' #> ((lambda (: a :?) a)) ;Oops, not quite! Contextual meaning here. - >>> (lambda a:a)() + >>> (lambda a: a)() Traceback (most recent call last): ... TypeError: () missing 1 required positional argument: 'a' #> ((lambda (: a (quote :?)) a)) ;Just a string. Even in context. - >>> (lambda a=':?':a)() + >>> (lambda a=':?': a)() ':?' @@ -991,7 +1055,7 @@ Lissp Whirlwind Tour #> `(print "Hi") ;Code as data. Seems to act like quote. - >>> (lambda * _: _)( + >>> (lambda * _: _)( ... 'builtins..print', ... "('Hi')") ('builtins..print', "('Hi')") @@ -1012,34 +1076,34 @@ Lissp Whirlwind Tour (('lambda', (':', ':*', ' _'), ' _'), ':', ':?', ('quote', 'builtins..print'), ':?', ('quote', "('Hi')")) #> `(print ,(.upper "Hi")) ;Unquote (,) interpolates. - >>> (lambda * _: _)( + >>> (lambda * _: _)( ... 'builtins..print', ... ('Hi').upper()) ('builtins..print', 'HI') #> `(,'foo+2 foo+2) ;Interpolations not auto-qualified! - >>> (lambda * _: _)( + >>> (lambda * _: _)( ... 'fooQzPLUS_2', ... '__main__..fooQzPLUS_2') ('fooQzPLUS_2', '__main__..fooQzPLUS_2') #> `(print ,@"abc") ;Splice unquote (,@) interpolates and unpacks. - >>> (lambda * _: _)( + >>> (lambda * _: _)( ... 'builtins..print', ... *('abc')) ('builtins..print', 'a', 'b', 'c') #> `(print (.upper "abc")) ;Template quoting is recursive - >>> (lambda * _: _)( + >>> (lambda * _: _)( ... 'builtins..print', - ... (lambda * _: _)( + ... (lambda * _: _)( ... '.upper', ... "('abc')")) ('builtins..print', ('.upper', "('abc')")) #> `(print ,@(.upper "abc")) ; unless suppressed by an unquote. - >>> (lambda * _: _)( + >>> (lambda * _: _)( ... 'builtins..print', ... *('abc').upper()) ('builtins..print', 'A', 'B', 'C') @@ -1054,22 +1118,22 @@ Lissp Whirlwind Tour ;;; a count of the templates the reader has seen so far. #> `($#eggs $#spam $#bacon $#spam) - >>> (lambda * _: _)( - ... '_QzIWMX5OB2z_eggs', - ... '_QzIWMX5OB2z_spam', - ... '_QzIWMX5OB2z_bacon', - ... '_QzIWMX5OB2z_spam') - ('_QzIWMX5OB2z_eggs', '_QzIWMX5OB2z_spam', '_QzIWMX5OB2z_bacon', '_QzIWMX5OB2z_spam') + >>> (lambda * _: _)( + ... '_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' + >>> '_QzIOSOZAXYz___spam' + '_QzIOSOZAXYz___spam' ;; even if the code is identical. #> `$#spam - >>> '_QzY6OWMZS7z_spam' - '_QzY6OWMZS7z_spam' + >>> '_QzY6OWMZS7z___spam' + '_QzY6OWMZS7z___spam' ;;; However, the hashing procedure is fully deterministic, so builds are ;;; reproducible even when they contain generated symbols. @@ -1078,16 +1142,16 @@ Lissp Whirlwind Tour ;; but you can put them anywhere in the symbol; $ marks the positions. ;; 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_' + >>> '__main__..spam_QzA4IBV7J7z___._QzA4IBV7J7z___eggs_QzA4IBV7J7z___' + '__main__..spam_QzA4IBV7J7z___._QzA4IBV7J7z___eggs_QzA4IBV7J7z___' ;; This is typically used for partially-qualified variables, ;; i.e., with an explicit namespace that is not a module handle. ;; The interpolation suppressed auto-qualification. #> `,'$#self.$foo - >>> 'self._Qz7UU6WAD6z_foo' - 'self._Qz7UU6WAD6z_foo' + >>> 'self._Qz7UU6WAD6z___foo' + 'self._Qz7UU6WAD6z___foo' ;;; You can use templates to make collections with interpolated values. @@ -1100,7 +1164,7 @@ Lissp Whirlwind Tour #.. ,(+ 1 1) #.. ,(+ 1 2))) >>> list( - ... (lambda * _: _)( + ... (lambda * _: _)( ... *('abc'), ... (1), ... QzPLUS_( @@ -1113,16 +1177,16 @@ Lissp Whirlwind Tour #> `(0 "a" 'b) ;Beware of "" tokens and symbols. - >>> (lambda * _: _)( + >>> (lambda * _: _)( ... (0), ... "('a')", - ... (lambda * _: _)( + ... (lambda * _: _)( ... 'quote', ... '__main__..b')) (0, "('a')", ('quote', '__main__..b')) #> `(,0 ,"a" ,'b) ;Just unquote everything in data templates. - >>> (lambda * _: _)( + >>> (lambda * _: _)( ... (0), ... ('a'), ... 'b') @@ -1133,14 +1197,14 @@ Lissp Whirlwind Tour #.. ,@(.items (dict : spam "eggs" foo 2)) ;dict unpacking #.. (,3 ,4))) >>> dict( - ... (lambda * _: _)( - ... (lambda * _: _)( + ... (lambda * _: _)( + ... (lambda * _: _)( ... (0), ... (1)), ... *dict( ... spam=('eggs'), ... foo=(2)).items(), - ... (lambda * _: _)( + ... (lambda * _: _)( ... (3), ... (4)))) {0: 1, 'spam': 'eggs', 'foo': 2, 3: 4} @@ -1156,14 +1220,16 @@ Lissp Whirlwind Tour #.. (lambda (key value) #.. `(.update (globals) : ,key ,value))) >>> globals().update( - ... assign=(lambda key,value: - ... (lambda * _: _)( - ... '.update', - ... (lambda * _: _)( - ... 'builtins..globals'), - ... ':', - ... key, - ... value))) + ... assign=( + ... lambda key, + ... value: + ... (lambda * _: _)( + ... '.update', + ... (lambda * _: _)( + ... 'builtins..globals'), + ... ':', + ... key, + ... value))) ;; Notice the arguments to it are quoted. @@ -1278,13 +1344,13 @@ Lissp Whirlwind Tour ... _macro_, ... 'triple', ... (lambda x: - ... (lambda * _: _)( - ... '__main__..QzMaybe_.QzPLUS_', - ... x, - ... (lambda * _: _)( + ... (lambda * _: _)( ... '__main__..QzMaybe_.QzPLUS_', ... x, - ... x)))) + ... (lambda * _: _)( + ... '__main__..QzMaybe_.QzPLUS_', + ... x, + ... x)))) #> (triple 4) ;12 >>> # triple @@ -1302,10 +1368,10 @@ Lissp Whirlwind Tour #.. x)) >>> # define ... __import__('builtins').globals().update( - ... loudQz_number=(lambda x:( - ... print( - ... x), - ... x)[-1])) + ... loudQz_number=(lambda x: + ... (print( + ... x), + ... x) [-1])) #> (triple (loud-number 14)) ;Triples the *code*, not just the *value*. >>> # triple @@ -1329,11 +1395,11 @@ Lissp Whirlwind Tour #.. (+ x (+ x x))) #.. (loud-number 14)) >>> (lambda x: - ... QzPLUS_( - ... x, ... QzPLUS_( ... x, - ... x)))( + ... QzPLUS_( + ... x, + ... x)))( ... loudQz_number( ... (14))) 14 @@ -1343,13 +1409,14 @@ Lissp Whirlwind Tour ;; Python also allows us to use a default argument up front. #> ((lambda (: x (loud-number 14)) #.. (+ x (+ x x)))) - >>> (lambda x=loudQz_number( - ... (14)): - ... QzPLUS_( - ... x, + >>> ( + ... lambda x=loudQz_number( + ... (14)): ... QzPLUS_( ... x, - ... x)))() + ... QzPLUS_( + ... x, + ... x)))() 14 42 @@ -1364,29 +1431,29 @@ Lissp Whirlwind Tour ... _macro_, ... 'oopsQz_triple', ... (lambda expression: - ... (lambda * _: _)( - ... (lambda * _: _)( - ... 'lambda', - ... (lambda * _: _)( - ... ':', - ... '__main__..x', - ... expression), - ... (lambda * _: _)( - ... '__main__..QzMaybe_.QzPLUS_', - ... '__main__..x', - ... (lambda * _: _)( + ... (lambda * _: _)( + ... (lambda * _: _)( + ... 'lambda', + ... (lambda * _: _)( + ... ':', + ... '__main__..x', + ... expression), + ... (lambda * _: _)( ... '__main__..QzMaybe_.QzPLUS_', ... '__main__..x', - ... '__main__..x')))))) + ... (lambda * _: _)( + ... '__main__..QzMaybe_.QzPLUS_', + ... '__main__..x', + ... '__main__..x')))))) #> (oops-triple 14) ;Oops. Templates qualify symbols! >>> # oopsQz_triple ... (lambda __main__..x=(14): - ... __import__('builtins').globals()['QzPLUS_']( - ... __import__('builtins').globals()['x'], ... __import__('builtins').globals()['QzPLUS_']( ... __import__('builtins').globals()['x'], - ... __import__('builtins').globals()['x'])))() + ... __import__('builtins').globals()['QzPLUS_']( + ... __import__('builtins').globals()['x'], + ... __import__('builtins').globals()['x'])))() Traceback (most recent call last): ... (lambda __main__..x=(14): @@ -1405,30 +1472,31 @@ Lissp Whirlwind Tour ... _macro_, ... 'onceQz_triple', ... (lambda x: - ... (lambda * _: _)( - ... (lambda * _: _)( - ... 'lambda', - ... (lambda * _: _)( - ... ':', - ... '_QzIF7WPGTUz_x', - ... x), - ... (lambda * _: _)( - ... '__main__..QzMaybe_.QzPLUS_', - ... '_QzIF7WPGTUz_x', - ... (lambda * _: _)( + ... (lambda * _: _)( + ... (lambda * _: _)( + ... 'lambda', + ... (lambda * _: _)( + ... ':', + ... '_QzIF7WPGTUz___x', + ... x), + ... (lambda * _: _)( ... '__main__..QzMaybe_.QzPLUS_', - ... '_QzIF7WPGTUz_x', - ... '_QzIF7WPGTUz_x')))))) + ... '_QzIF7WPGTUz___x', + ... (lambda * _: _)( + ... '__main__..QzMaybe_.QzPLUS_', + ... '_QzIF7WPGTUz___x', + ... '_QzIF7WPGTUz___x')))))) #> (once-triple (loud-number 14)) >>> # onceQz_triple - ... (lambda _QzIF7WPGTUz_x=loudQz_number( - ... (14)): - ... __import__('builtins').globals()['QzPLUS_']( - ... _QzIF7WPGTUz_x, + ... ( + ... lambda _QzIF7WPGTUz___x=loudQz_number( + ... (14)): ... __import__('builtins').globals()['QzPLUS_']( - ... _QzIF7WPGTUz_x, - ... _QzIF7WPGTUz_x)))() + ... _QzIF7WPGTUz___x, + ... __import__('builtins').globals()['QzPLUS_']( + ... _QzIF7WPGTUz___x, + ... _QzIF7WPGTUz___x)))() 14 42 @@ -1440,7 +1508,7 @@ Lissp Whirlwind Tour ;;; and omits it otherwise. #> `(+ 1 2 3 4) - >>> (lambda * _: _)( + >>> (lambda * _: _)( ... '__main__..QzMaybe_.QzPLUS_', ... (1), ... (2), @@ -1462,17 +1530,19 @@ Lissp Whirlwind Tour >>> setattr( ... _macro_, ... 'QzPLUS_', - ... (lambda first=(0),*args: - ... (lambda * _: _)( - ... first, - ... (lambda * _: _)( - ... 'operator..add', + ... ( + ... lambda first=(0), + ... *args: + ... (lambda * _: _)( ... first, - ... (lambda * _: _)( - ... '__main__..QzMaybe_.QzPLUS_', - ... *args))).__getitem__( - ... bool( - ... args)))) + ... (lambda * _: _)( + ... 'operator..add', + ... first, + ... (lambda * _: _)( + ... '__main__..QzMaybe_.QzPLUS_', + ... *args))).__getitem__( + ... bool( + ... args)))) #> (+ 1 2 3 4) >>> # QzPLUS_ @@ -1492,7 +1562,7 @@ Lissp Whirlwind Tour ;; Notice that a new template doesn't qualify + with QzMaybe_ now that ;; it detects a macro with that name. #> `(+ 1 2 3 4) - >>> (lambda * _: _)( + >>> (lambda * _: _)( ... '__main__.._macro_.QzPLUS_', ... (1), ... (2), @@ -1513,21 +1583,24 @@ Lissp Whirlwind Tour >>> setattr( ... _macro_, ... 'QzSTAR_', - ... (lambda first=(1),second=(1),*args: - ... (lambda * _: _)( - ... (lambda * _: _)( - ... 'operator..mul', - ... first, - ... second), - ... (lambda * _: _)( - ... '__main__..QzMaybe_.QzSTAR_', - ... (lambda * _: _)( + ... ( + ... lambda first=(1), + ... second=(1), + ... *args: + ... (lambda * _: _)( + ... (lambda * _: _)( ... 'operator..mul', ... first, ... second), - ... *args)).__getitem__( - ... bool( - ... args)))) + ... (lambda * _: _)( + ... '__main__..QzMaybe_.QzSTAR_', + ... (lambda * _: _)( + ... 'operator..mul', + ... first, + ... second), + ... *args)).__getitem__( + ... bool( + ... args)))) ;; Notice that the stacked expansion comments left by the compiler @@ -1566,11 +1639,13 @@ Lissp Whirlwind Tour #> (functools..reduce (lambda xy (* x y)) ;Invocation, not argument. #.. '(1 2 3 4)) >>> __import__('functools').reduce( - ... (lambda x,y: - ... # QzSTAR_ - ... __import__('operator').mul( - ... x, - ... y)), + ... ( + ... lambda x, + ... y: + ... # QzSTAR_ + ... __import__('operator').mul( + ... x, + ... y)), ... ((1), ... (2), ... (3), @@ -1594,23 +1669,25 @@ Lissp Whirlwind Tour ... _macro_, ... 'XY', ... (lambda *body: - ... (lambda * _: _)( - ... 'lambda', - ... (lambda * _: _)( - ... 'X', - ... 'Y'), - ... body))) + ... (lambda * _: _)( + ... 'lambda', + ... (lambda * _: _)( + ... 'X', + ... 'Y'), + ... body))) #> (functools..reduce (XY * X Y) ;Invocation, not argument! #.. '(1 2 3 4)) >>> __import__('functools').reduce( ... # XY - ... (lambda X,Y: - ... # QzSTAR_ - ... __import__('operator').mul( - ... X, - ... Y)), + ... ( + ... lambda X, + ... Y: + ... # QzSTAR_ + ... __import__('operator').mul( + ... X, + ... Y)), ... ((1), ... (2), ... (3), @@ -1619,12 +1696,14 @@ Lissp Whirlwind Tour #> ((XY + Y X) "Eggs" "Spam") >>> # XY - ... (lambda X,Y: - ... # QzPLUS_ - ... __import__('operator').add( - ... Y, - ... # __main__..QzMaybe_.QzPLUS_ - ... X))( + ... ( + ... lambda X, + ... Y: + ... # QzPLUS_ + ... __import__('operator').add( + ... Y, + ... # __main__..QzMaybe_.QzPLUS_ + ... X))( ... ('Eggs'), ... ('Spam')) 'SpamEggs' @@ -1667,14 +1746,14 @@ Lissp Whirlwind Tour ... _macro_, ... 'p123', ... (lambda sep: - ... (lambda * _: _)( - ... 'builtins..print', - ... (1), - ... (2), - ... (3), - ... ':', - ... '__main__..sep', - ... sep))) + ... (lambda * _: _)( + ... 'builtins..print', + ... (1), + ... (2), + ... (3), + ... ':', + ... '__main__..sep', + ... sep))) ;; Note the : didn't have to be quoted here, because it's in a macro @@ -1740,8 +1819,8 @@ Lissp Whirlwind Tour >>> any( ... map( ... (lambda f: - ... __import__('os').remove( - ... f)), + ... __import__('os').remove( + ... f)), ... ('eggs.lissp', ... 'spam.lissp', ... 'spam.py', @@ -1943,7 +2022,11 @@ Lissp Whirlwind Tour ;; Hissp may not have operators, but Python does. #> (lambda abc |(-b + (b**2 - 4*a*c)**0.5)/(2*a)|) - >>> (lambda a,b,c:(-b + (b**2 - 4*a*c)**0.5)/(2*a)) + >>> ( + ... lambda a, + ... b, + ... c: + ... (-b + (b**2 - 4*a*c)**0.5)/(2*a)) at 0x...> @@ -1952,9 +2035,12 @@ Lissp Whirlwind Tour #> (lambda abc #.. .#"(-b + (b**2 - 4*a*c)**0.5) #.. /(2*a)") - >>> (lambda a,b,c: - ... (-b + (b**2 - 4*a*c)**0.5) - ... /(2*a)) + >>> ( + ... lambda a, + ... b, + ... c: + ... (-b + (b**2 - 4*a*c)**0.5) + ... /(2*a)) at 0x...> diff --git a/docs/macro_tutorial.rst b/docs/macro_tutorial.rst index c748dde15..754d9991c 100644 --- a/docs/macro_tutorial.rst +++ b/docs/macro_tutorial.rst @@ -417,9 +417,9 @@ Inject: ... __import__('builtins').globals().update( ... squares=map( ... (lambda x: - ... mul( - ... x, - ... x)), + ... mul( + ... x, + ... x)), ... range( ... (10)))) @@ -587,23 +587,26 @@ Try this definition. #.. `(lambda ,params ,@body)) >>> # defmacro ... # hissp.macros.._macro_.let - ... (lambda _QzAW22OE5Kz_fn=(lambda params,*body: - ... (lambda * _: _)( - ... 'lambda', - ... params, - ... *body)):( - ... __import__('builtins').setattr( - ... _QzAW22OE5Kz_fn, - ... '__qualname__', - ... ('.').join( - ... ('_macro_', - ... 'L',))), - ... __import__('builtins').setattr( - ... __import__('operator').getitem( - ... __import__('builtins').globals(), - ... '_macro_'), - ... 'L', - ... _QzAW22OE5Kz_fn))[-1])() + ... ( + ... lambda _QzAW22OE5Kz___fn=( + ... lambda params, + ... *body: + ... (lambda * _: _)( + ... 'lambda', + ... params, + ... *body)): + ... (__import__('builtins').setattr( + ... _QzAW22OE5Kz___fn, + ... '__qualname__', + ... ('.').join( + ... ('_macro_', + ... 'L',))), + ... __import__('builtins').setattr( + ... __import__('operator').getitem( + ... __import__('builtins').globals(), + ... '_macro_'), + ... 'L', + ... _QzAW22OE5Kz___fn)) [-1])() .. code-block:: REPL @@ -614,9 +617,9 @@ Try this definition. ... map( ... # L ... (lambda x: - ... QzSTAR_( - ... x, - ... x)), + ... QzSTAR_( + ... x, + ... x)), ... range( ... (10)))) [0, 1, 4, 9, 16, 25, 36, 49, 64, 81] @@ -675,24 +678,25 @@ that `anaphoric macro ` we did in the `primer`. #.. ,expr)) >>> # defmacro ... # hissp.macros.._macro_.let - ... (lambda _QzAW22OE5Kz_fn=(lambda *expr: - ... (lambda * _: _)( - ... 'lambda', - ... (lambda * _: _)( - ... 'X'), - ... expr)):( - ... __import__('builtins').setattr( - ... _QzAW22OE5Kz_fn, - ... '__qualname__', - ... ('.').join( - ... ('_macro_', - ... 'L',))), - ... __import__('builtins').setattr( - ... __import__('operator').getitem( - ... __import__('builtins').globals(), - ... '_macro_'), - ... 'L', - ... _QzAW22OE5Kz_fn))[-1])() + ... ( + ... lambda _QzAW22OE5Kz___fn=(lambda *expr: + ... (lambda * _: _)( + ... 'lambda', + ... (lambda * _: _)( + ... 'X'), + ... expr)): + ... (__import__('builtins').setattr( + ... _QzAW22OE5Kz___fn, + ... '__qualname__', + ... ('.').join( + ... ('_macro_', + ... 'L',))), + ... __import__('builtins').setattr( + ... __import__('operator').getitem( + ... __import__('builtins').globals(), + ... '_macro_'), + ... 'L', + ... _QzAW22OE5Kz___fn)) [-1])() .. code-block:: REPL @@ -702,9 +706,9 @@ that `anaphoric macro ` we did in the `primer`. ... map( ... # L ... (lambda X: - ... QzSTAR_( - ... X, - ... X)), + ... QzSTAR_( + ... X, + ... X)), ... range( ... (10)))) [0, 1, 4, 9, 16, 25, 36, 49, 64, 81] @@ -774,35 +778,38 @@ Ready? #.. ,expr)) >>> # defmacro ... # hissp.macros.._macro_.let - ... (lambda _QzAW22OE5Kz_fn=(lambda *expr: - ... (lambda * _: _)( - ... 'lambda', - ... (lambda * _: _)( - ... 'X', - ... 'Y'), - ... expr)):( - ... __import__('builtins').setattr( - ... _QzAW22OE5Kz_fn, - ... '__qualname__', - ... ('.').join( - ... ('_macro_', - ... 'L2',))), - ... __import__('builtins').setattr( - ... __import__('operator').getitem( - ... __import__('builtins').globals(), - ... '_macro_'), - ... 'L2', - ... _QzAW22OE5Kz_fn))[-1])() + ... ( + ... lambda _QzAW22OE5Kz___fn=(lambda *expr: + ... (lambda * _: _)( + ... 'lambda', + ... (lambda * _: _)( + ... 'X', + ... 'Y'), + ... expr)): + ... (__import__('builtins').setattr( + ... _QzAW22OE5Kz___fn, + ... '__qualname__', + ... ('.').join( + ... ('_macro_', + ... 'L2',))), + ... __import__('builtins').setattr( + ... __import__('operator').getitem( + ... __import__('builtins').globals(), + ... '_macro_'), + ... 'L2', + ... _QzAW22OE5Kz___fn)) [-1])() .. code-block:: REPL #> (L2 * X Y) >>> # L2 - ... (lambda X,Y: - ... QzSTAR_( - ... X, - ... Y)) + ... ( + ... lambda X, + ... Y: + ... QzSTAR_( + ... X, + ... Y)) at ...> That's another easy template. @@ -833,520 +840,547 @@ Don't panic. #.. ,$#expr))) #.. (range 27))) >>> # __main__.._macro_.progn - ... (lambda :( - ... # __main__.._macro_.defmacro - ... # hissp.macros.._macro_.let - ... (lambda _QzAW22OE5Kz_fn=(lambda *_QzQ46NYXTBz_expr: - ... (lambda * _: _)( - ... 'lambda', - ... '', - ... _QzQ46NYXTBz_expr)):( - ... __import__('builtins').setattr( - ... _QzAW22OE5Kz_fn, - ... '__qualname__', - ... ('.').join( - ... ('_macro_', - ... 'L0',))), - ... __import__('builtins').setattr( - ... __import__('operator').getitem( - ... __import__('builtins').globals(), - ... '_macro_'), - ... 'L0', - ... _QzAW22OE5Kz_fn))[-1])(), - ... # __main__.._macro_.defmacro - ... # hissp.macros.._macro_.let - ... (lambda _QzAW22OE5Kz_fn=(lambda *_QzQ46NYXTBz_expr: - ... (lambda * _: _)( - ... 'lambda', - ... 'A', - ... _QzQ46NYXTBz_expr)):( - ... __import__('builtins').setattr( - ... _QzAW22OE5Kz_fn, - ... '__qualname__', - ... ('.').join( - ... ('_macro_', - ... 'L1',))), - ... __import__('builtins').setattr( - ... __import__('operator').getitem( - ... __import__('builtins').globals(), - ... '_macro_'), - ... 'L1', - ... _QzAW22OE5Kz_fn))[-1])(), - ... # __main__.._macro_.defmacro - ... # hissp.macros.._macro_.let - ... (lambda _QzAW22OE5Kz_fn=(lambda *_QzQ46NYXTBz_expr: - ... (lambda * _: _)( - ... 'lambda', - ... 'AB', - ... _QzQ46NYXTBz_expr)):( - ... __import__('builtins').setattr( - ... _QzAW22OE5Kz_fn, - ... '__qualname__', - ... ('.').join( - ... ('_macro_', - ... 'L2',))), - ... __import__('builtins').setattr( - ... __import__('operator').getitem( - ... __import__('builtins').globals(), - ... '_macro_'), - ... 'L2', - ... _QzAW22OE5Kz_fn))[-1])(), - ... # __main__.._macro_.defmacro - ... # hissp.macros.._macro_.let - ... (lambda _QzAW22OE5Kz_fn=(lambda *_QzQ46NYXTBz_expr: - ... (lambda * _: _)( - ... 'lambda', - ... 'ABC', - ... _QzQ46NYXTBz_expr)):( - ... __import__('builtins').setattr( - ... _QzAW22OE5Kz_fn, - ... '__qualname__', - ... ('.').join( - ... ('_macro_', - ... 'L3',))), - ... __import__('builtins').setattr( - ... __import__('operator').getitem( - ... __import__('builtins').globals(), - ... '_macro_'), - ... 'L3', - ... _QzAW22OE5Kz_fn))[-1])(), - ... # __main__.._macro_.defmacro - ... # hissp.macros.._macro_.let - ... (lambda _QzAW22OE5Kz_fn=(lambda *_QzQ46NYXTBz_expr: - ... (lambda * _: _)( - ... 'lambda', - ... 'ABCD', - ... _QzQ46NYXTBz_expr)):( - ... __import__('builtins').setattr( - ... _QzAW22OE5Kz_fn, - ... '__qualname__', - ... ('.').join( - ... ('_macro_', - ... 'L4',))), - ... __import__('builtins').setattr( - ... __import__('operator').getitem( - ... __import__('builtins').globals(), - ... '_macro_'), - ... 'L4', - ... _QzAW22OE5Kz_fn))[-1])(), - ... # __main__.._macro_.defmacro - ... # hissp.macros.._macro_.let - ... (lambda _QzAW22OE5Kz_fn=(lambda *_QzQ46NYXTBz_expr: - ... (lambda * _: _)( - ... 'lambda', - ... 'ABCDE', - ... _QzQ46NYXTBz_expr)):( - ... __import__('builtins').setattr( - ... _QzAW22OE5Kz_fn, - ... '__qualname__', - ... ('.').join( - ... ('_macro_', - ... 'L5',))), - ... __import__('builtins').setattr( - ... __import__('operator').getitem( - ... __import__('builtins').globals(), - ... '_macro_'), - ... 'L5', - ... _QzAW22OE5Kz_fn))[-1])(), - ... # __main__.._macro_.defmacro - ... # hissp.macros.._macro_.let - ... (lambda _QzAW22OE5Kz_fn=(lambda *_QzQ46NYXTBz_expr: - ... (lambda * _: _)( - ... 'lambda', - ... 'ABCDEF', - ... _QzQ46NYXTBz_expr)):( - ... __import__('builtins').setattr( - ... _QzAW22OE5Kz_fn, - ... '__qualname__', - ... ('.').join( - ... ('_macro_', - ... 'L6',))), - ... __import__('builtins').setattr( - ... __import__('operator').getitem( - ... __import__('builtins').globals(), - ... '_macro_'), - ... 'L6', - ... _QzAW22OE5Kz_fn))[-1])(), - ... # __main__.._macro_.defmacro - ... # hissp.macros.._macro_.let - ... (lambda _QzAW22OE5Kz_fn=(lambda *_QzQ46NYXTBz_expr: - ... (lambda * _: _)( - ... 'lambda', - ... 'ABCDEFG', - ... _QzQ46NYXTBz_expr)):( - ... __import__('builtins').setattr( - ... _QzAW22OE5Kz_fn, - ... '__qualname__', - ... ('.').join( - ... ('_macro_', - ... 'L7',))), - ... __import__('builtins').setattr( - ... __import__('operator').getitem( - ... __import__('builtins').globals(), - ... '_macro_'), - ... 'L7', - ... _QzAW22OE5Kz_fn))[-1])(), - ... # __main__.._macro_.defmacro - ... # hissp.macros.._macro_.let - ... (lambda _QzAW22OE5Kz_fn=(lambda *_QzQ46NYXTBz_expr: - ... (lambda * _: _)( - ... 'lambda', - ... 'ABCDEFGH', - ... _QzQ46NYXTBz_expr)):( - ... __import__('builtins').setattr( - ... _QzAW22OE5Kz_fn, - ... '__qualname__', - ... ('.').join( - ... ('_macro_', - ... 'L8',))), - ... __import__('builtins').setattr( - ... __import__('operator').getitem( - ... __import__('builtins').globals(), - ... '_macro_'), - ... 'L8', - ... _QzAW22OE5Kz_fn))[-1])(), - ... # __main__.._macro_.defmacro - ... # hissp.macros.._macro_.let - ... (lambda _QzAW22OE5Kz_fn=(lambda *_QzQ46NYXTBz_expr: - ... (lambda * _: _)( - ... 'lambda', - ... 'ABCDEFGHI', - ... _QzQ46NYXTBz_expr)):( - ... __import__('builtins').setattr( - ... _QzAW22OE5Kz_fn, - ... '__qualname__', - ... ('.').join( - ... ('_macro_', - ... 'L9',))), - ... __import__('builtins').setattr( - ... __import__('operator').getitem( - ... __import__('builtins').globals(), - ... '_macro_'), - ... 'L9', - ... _QzAW22OE5Kz_fn))[-1])(), - ... # __main__.._macro_.defmacro - ... # hissp.macros.._macro_.let - ... (lambda _QzAW22OE5Kz_fn=(lambda *_QzQ46NYXTBz_expr: - ... (lambda * _: _)( - ... 'lambda', - ... 'ABCDEFGHIJ', - ... _QzQ46NYXTBz_expr)):( - ... __import__('builtins').setattr( - ... _QzAW22OE5Kz_fn, - ... '__qualname__', - ... ('.').join( - ... ('_macro_', - ... 'L10',))), - ... __import__('builtins').setattr( - ... __import__('operator').getitem( - ... __import__('builtins').globals(), - ... '_macro_'), - ... 'L10', - ... _QzAW22OE5Kz_fn))[-1])(), - ... # __main__.._macro_.defmacro - ... # hissp.macros.._macro_.let - ... (lambda _QzAW22OE5Kz_fn=(lambda *_QzQ46NYXTBz_expr: - ... (lambda * _: _)( - ... 'lambda', - ... 'ABCDEFGHIJK', - ... _QzQ46NYXTBz_expr)):( - ... __import__('builtins').setattr( - ... _QzAW22OE5Kz_fn, - ... '__qualname__', - ... ('.').join( - ... ('_macro_', - ... 'L11',))), - ... __import__('builtins').setattr( - ... __import__('operator').getitem( - ... __import__('builtins').globals(), - ... '_macro_'), - ... 'L11', - ... _QzAW22OE5Kz_fn))[-1])(), - ... # __main__.._macro_.defmacro - ... # hissp.macros.._macro_.let - ... (lambda _QzAW22OE5Kz_fn=(lambda *_QzQ46NYXTBz_expr: - ... (lambda * _: _)( - ... 'lambda', - ... 'ABCDEFGHIJKL', - ... _QzQ46NYXTBz_expr)):( - ... __import__('builtins').setattr( - ... _QzAW22OE5Kz_fn, - ... '__qualname__', - ... ('.').join( - ... ('_macro_', - ... 'L12',))), - ... __import__('builtins').setattr( - ... __import__('operator').getitem( - ... __import__('builtins').globals(), - ... '_macro_'), - ... 'L12', - ... _QzAW22OE5Kz_fn))[-1])(), - ... # __main__.._macro_.defmacro - ... # hissp.macros.._macro_.let - ... (lambda _QzAW22OE5Kz_fn=(lambda *_QzQ46NYXTBz_expr: - ... (lambda * _: _)( - ... 'lambda', - ... 'ABCDEFGHIJKLM', - ... _QzQ46NYXTBz_expr)):( - ... __import__('builtins').setattr( - ... _QzAW22OE5Kz_fn, - ... '__qualname__', - ... ('.').join( - ... ('_macro_', - ... 'L13',))), - ... __import__('builtins').setattr( - ... __import__('operator').getitem( - ... __import__('builtins').globals(), - ... '_macro_'), - ... 'L13', - ... _QzAW22OE5Kz_fn))[-1])(), - ... # __main__.._macro_.defmacro - ... # hissp.macros.._macro_.let - ... (lambda _QzAW22OE5Kz_fn=(lambda *_QzQ46NYXTBz_expr: - ... (lambda * _: _)( - ... 'lambda', - ... 'ABCDEFGHIJKLMN', - ... _QzQ46NYXTBz_expr)):( - ... __import__('builtins').setattr( - ... _QzAW22OE5Kz_fn, - ... '__qualname__', - ... ('.').join( - ... ('_macro_', - ... 'L14',))), - ... __import__('builtins').setattr( - ... __import__('operator').getitem( - ... __import__('builtins').globals(), - ... '_macro_'), - ... 'L14', - ... _QzAW22OE5Kz_fn))[-1])(), - ... # __main__.._macro_.defmacro - ... # hissp.macros.._macro_.let - ... (lambda _QzAW22OE5Kz_fn=(lambda *_QzQ46NYXTBz_expr: - ... (lambda * _: _)( - ... 'lambda', - ... 'ABCDEFGHIJKLMNO', - ... _QzQ46NYXTBz_expr)):( - ... __import__('builtins').setattr( - ... _QzAW22OE5Kz_fn, - ... '__qualname__', - ... ('.').join( - ... ('_macro_', - ... 'L15',))), - ... __import__('builtins').setattr( - ... __import__('operator').getitem( - ... __import__('builtins').globals(), - ... '_macro_'), - ... 'L15', - ... _QzAW22OE5Kz_fn))[-1])(), - ... # __main__.._macro_.defmacro - ... # hissp.macros.._macro_.let - ... (lambda _QzAW22OE5Kz_fn=(lambda *_QzQ46NYXTBz_expr: - ... (lambda * _: _)( - ... 'lambda', - ... 'ABCDEFGHIJKLMNOP', - ... _QzQ46NYXTBz_expr)):( - ... __import__('builtins').setattr( - ... _QzAW22OE5Kz_fn, - ... '__qualname__', - ... ('.').join( - ... ('_macro_', - ... 'L16',))), - ... __import__('builtins').setattr( - ... __import__('operator').getitem( - ... __import__('builtins').globals(), - ... '_macro_'), - ... 'L16', - ... _QzAW22OE5Kz_fn))[-1])(), - ... # __main__.._macro_.defmacro - ... # hissp.macros.._macro_.let - ... (lambda _QzAW22OE5Kz_fn=(lambda *_QzQ46NYXTBz_expr: - ... (lambda * _: _)( - ... 'lambda', - ... 'ABCDEFGHIJKLMNOPQ', - ... _QzQ46NYXTBz_expr)):( - ... __import__('builtins').setattr( - ... _QzAW22OE5Kz_fn, - ... '__qualname__', - ... ('.').join( - ... ('_macro_', - ... 'L17',))), - ... __import__('builtins').setattr( - ... __import__('operator').getitem( - ... __import__('builtins').globals(), - ... '_macro_'), - ... 'L17', - ... _QzAW22OE5Kz_fn))[-1])(), - ... # __main__.._macro_.defmacro - ... # hissp.macros.._macro_.let - ... (lambda _QzAW22OE5Kz_fn=(lambda *_QzQ46NYXTBz_expr: - ... (lambda * _: _)( - ... 'lambda', - ... 'ABCDEFGHIJKLMNOPQR', - ... _QzQ46NYXTBz_expr)):( - ... __import__('builtins').setattr( - ... _QzAW22OE5Kz_fn, - ... '__qualname__', - ... ('.').join( - ... ('_macro_', - ... 'L18',))), - ... __import__('builtins').setattr( - ... __import__('operator').getitem( - ... __import__('builtins').globals(), - ... '_macro_'), - ... 'L18', - ... _QzAW22OE5Kz_fn))[-1])(), - ... # __main__.._macro_.defmacro - ... # hissp.macros.._macro_.let - ... (lambda _QzAW22OE5Kz_fn=(lambda *_QzQ46NYXTBz_expr: - ... (lambda * _: _)( - ... 'lambda', - ... 'ABCDEFGHIJKLMNOPQRS', - ... _QzQ46NYXTBz_expr)):( - ... __import__('builtins').setattr( - ... _QzAW22OE5Kz_fn, - ... '__qualname__', - ... ('.').join( - ... ('_macro_', - ... 'L19',))), - ... __import__('builtins').setattr( - ... __import__('operator').getitem( - ... __import__('builtins').globals(), - ... '_macro_'), - ... 'L19', - ... _QzAW22OE5Kz_fn))[-1])(), - ... # __main__.._macro_.defmacro - ... # hissp.macros.._macro_.let - ... (lambda _QzAW22OE5Kz_fn=(lambda *_QzQ46NYXTBz_expr: - ... (lambda * _: _)( - ... 'lambda', - ... 'ABCDEFGHIJKLMNOPQRST', - ... _QzQ46NYXTBz_expr)):( - ... __import__('builtins').setattr( - ... _QzAW22OE5Kz_fn, - ... '__qualname__', - ... ('.').join( - ... ('_macro_', - ... 'L20',))), - ... __import__('builtins').setattr( - ... __import__('operator').getitem( - ... __import__('builtins').globals(), - ... '_macro_'), - ... 'L20', - ... _QzAW22OE5Kz_fn))[-1])(), - ... # __main__.._macro_.defmacro - ... # hissp.macros.._macro_.let - ... (lambda _QzAW22OE5Kz_fn=(lambda *_QzQ46NYXTBz_expr: - ... (lambda * _: _)( - ... 'lambda', - ... 'ABCDEFGHIJKLMNOPQRSTU', - ... _QzQ46NYXTBz_expr)):( - ... __import__('builtins').setattr( - ... _QzAW22OE5Kz_fn, - ... '__qualname__', - ... ('.').join( - ... ('_macro_', - ... 'L21',))), - ... __import__('builtins').setattr( - ... __import__('operator').getitem( - ... __import__('builtins').globals(), - ... '_macro_'), - ... 'L21', - ... _QzAW22OE5Kz_fn))[-1])(), - ... # __main__.._macro_.defmacro - ... # hissp.macros.._macro_.let - ... (lambda _QzAW22OE5Kz_fn=(lambda *_QzQ46NYXTBz_expr: - ... (lambda * _: _)( - ... 'lambda', - ... 'ABCDEFGHIJKLMNOPQRSTUV', - ... _QzQ46NYXTBz_expr)):( - ... __import__('builtins').setattr( - ... _QzAW22OE5Kz_fn, - ... '__qualname__', - ... ('.').join( - ... ('_macro_', - ... 'L22',))), - ... __import__('builtins').setattr( - ... __import__('operator').getitem( - ... __import__('builtins').globals(), - ... '_macro_'), - ... 'L22', - ... _QzAW22OE5Kz_fn))[-1])(), - ... # __main__.._macro_.defmacro - ... # hissp.macros.._macro_.let - ... (lambda _QzAW22OE5Kz_fn=(lambda *_QzQ46NYXTBz_expr: - ... (lambda * _: _)( - ... 'lambda', - ... 'ABCDEFGHIJKLMNOPQRSTUVW', - ... _QzQ46NYXTBz_expr)):( - ... __import__('builtins').setattr( - ... _QzAW22OE5Kz_fn, - ... '__qualname__', - ... ('.').join( - ... ('_macro_', - ... 'L23',))), - ... __import__('builtins').setattr( - ... __import__('operator').getitem( - ... __import__('builtins').globals(), - ... '_macro_'), - ... 'L23', - ... _QzAW22OE5Kz_fn))[-1])(), - ... # __main__.._macro_.defmacro - ... # hissp.macros.._macro_.let - ... (lambda _QzAW22OE5Kz_fn=(lambda *_QzQ46NYXTBz_expr: - ... (lambda * _: _)( - ... 'lambda', - ... 'ABCDEFGHIJKLMNOPQRSTUVWX', - ... _QzQ46NYXTBz_expr)):( - ... __import__('builtins').setattr( - ... _QzAW22OE5Kz_fn, - ... '__qualname__', - ... ('.').join( - ... ('_macro_', - ... 'L24',))), - ... __import__('builtins').setattr( - ... __import__('operator').getitem( - ... __import__('builtins').globals(), - ... '_macro_'), - ... 'L24', - ... _QzAW22OE5Kz_fn))[-1])(), - ... # __main__.._macro_.defmacro - ... # hissp.macros.._macro_.let - ... (lambda _QzAW22OE5Kz_fn=(lambda *_QzQ46NYXTBz_expr: - ... (lambda * _: _)( - ... 'lambda', - ... 'ABCDEFGHIJKLMNOPQRSTUVWXY', - ... _QzQ46NYXTBz_expr)):( - ... __import__('builtins').setattr( - ... _QzAW22OE5Kz_fn, - ... '__qualname__', - ... ('.').join( - ... ('_macro_', - ... 'L25',))), - ... __import__('builtins').setattr( - ... __import__('operator').getitem( - ... __import__('builtins').globals(), - ... '_macro_'), - ... 'L25', - ... _QzAW22OE5Kz_fn))[-1])(), - ... # __main__.._macro_.defmacro - ... # hissp.macros.._macro_.let - ... (lambda _QzAW22OE5Kz_fn=(lambda *_QzQ46NYXTBz_expr: - ... (lambda * _: _)( - ... 'lambda', - ... 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', - ... _QzQ46NYXTBz_expr)):( - ... __import__('builtins').setattr( - ... _QzAW22OE5Kz_fn, - ... '__qualname__', - ... ('.').join( - ... ('_macro_', - ... 'L26',))), - ... __import__('builtins').setattr( - ... __import__('operator').getitem( - ... __import__('builtins').globals(), - ... '_macro_'), - ... 'L26', - ... _QzAW22OE5Kz_fn))[-1])())[-1])() + ... (lambda : + ... (# __main__.._macro_.defmacro + ... # hissp.macros.._macro_.let + ... ( + ... lambda _Qz2D5FNHXZz___fn=(lambda *_QzXDFV7JLKz___expr: + ... (lambda * _: _)( + ... 'lambda', + ... '', + ... _QzXDFV7JLKz___expr)): + ... (__import__('builtins').setattr( + ... _Qz2D5FNHXZz___fn, + ... '__qualname__', + ... ('.').join( + ... ('_macro_', + ... 'L0',))), + ... __import__('builtins').setattr( + ... __import__('operator').getitem( + ... __import__('builtins').globals(), + ... '_macro_'), + ... 'L0', + ... _Qz2D5FNHXZz___fn)) [-1])(), + ... # __main__.._macro_.defmacro + ... # hissp.macros.._macro_.let + ... ( + ... lambda _Qz2D5FNHXZz___fn=(lambda *_QzXDFV7JLKz___expr: + ... (lambda * _: _)( + ... 'lambda', + ... 'A', + ... _QzXDFV7JLKz___expr)): + ... (__import__('builtins').setattr( + ... _Qz2D5FNHXZz___fn, + ... '__qualname__', + ... ('.').join( + ... ('_macro_', + ... 'L1',))), + ... __import__('builtins').setattr( + ... __import__('operator').getitem( + ... __import__('builtins').globals(), + ... '_macro_'), + ... 'L1', + ... _Qz2D5FNHXZz___fn)) [-1])(), + ... # __main__.._macro_.defmacro + ... # hissp.macros.._macro_.let + ... ( + ... lambda _Qz2D5FNHXZz___fn=(lambda *_QzXDFV7JLKz___expr: + ... (lambda * _: _)( + ... 'lambda', + ... 'AB', + ... _QzXDFV7JLKz___expr)): + ... (__import__('builtins').setattr( + ... _Qz2D5FNHXZz___fn, + ... '__qualname__', + ... ('.').join( + ... ('_macro_', + ... 'L2',))), + ... __import__('builtins').setattr( + ... __import__('operator').getitem( + ... __import__('builtins').globals(), + ... '_macro_'), + ... 'L2', + ... _Qz2D5FNHXZz___fn)) [-1])(), + ... # __main__.._macro_.defmacro + ... # hissp.macros.._macro_.let + ... ( + ... lambda _Qz2D5FNHXZz___fn=(lambda *_QzXDFV7JLKz___expr: + ... (lambda * _: _)( + ... 'lambda', + ... 'ABC', + ... _QzXDFV7JLKz___expr)): + ... (__import__('builtins').setattr( + ... _Qz2D5FNHXZz___fn, + ... '__qualname__', + ... ('.').join( + ... ('_macro_', + ... 'L3',))), + ... __import__('builtins').setattr( + ... __import__('operator').getitem( + ... __import__('builtins').globals(), + ... '_macro_'), + ... 'L3', + ... _Qz2D5FNHXZz___fn)) [-1])(), + ... # __main__.._macro_.defmacro + ... # hissp.macros.._macro_.let + ... ( + ... lambda _Qz2D5FNHXZz___fn=(lambda *_QzXDFV7JLKz___expr: + ... (lambda * _: _)( + ... 'lambda', + ... 'ABCD', + ... _QzXDFV7JLKz___expr)): + ... (__import__('builtins').setattr( + ... _Qz2D5FNHXZz___fn, + ... '__qualname__', + ... ('.').join( + ... ('_macro_', + ... 'L4',))), + ... __import__('builtins').setattr( + ... __import__('operator').getitem( + ... __import__('builtins').globals(), + ... '_macro_'), + ... 'L4', + ... _Qz2D5FNHXZz___fn)) [-1])(), + ... # __main__.._macro_.defmacro + ... # hissp.macros.._macro_.let + ... ( + ... lambda _Qz2D5FNHXZz___fn=(lambda *_QzXDFV7JLKz___expr: + ... (lambda * _: _)( + ... 'lambda', + ... 'ABCDE', + ... _QzXDFV7JLKz___expr)): + ... (__import__('builtins').setattr( + ... _Qz2D5FNHXZz___fn, + ... '__qualname__', + ... ('.').join( + ... ('_macro_', + ... 'L5',))), + ... __import__('builtins').setattr( + ... __import__('operator').getitem( + ... __import__('builtins').globals(), + ... '_macro_'), + ... 'L5', + ... _Qz2D5FNHXZz___fn)) [-1])(), + ... # __main__.._macro_.defmacro + ... # hissp.macros.._macro_.let + ... ( + ... lambda _Qz2D5FNHXZz___fn=(lambda *_QzXDFV7JLKz___expr: + ... (lambda * _: _)( + ... 'lambda', + ... 'ABCDEF', + ... _QzXDFV7JLKz___expr)): + ... (__import__('builtins').setattr( + ... _Qz2D5FNHXZz___fn, + ... '__qualname__', + ... ('.').join( + ... ('_macro_', + ... 'L6',))), + ... __import__('builtins').setattr( + ... __import__('operator').getitem( + ... __import__('builtins').globals(), + ... '_macro_'), + ... 'L6', + ... _Qz2D5FNHXZz___fn)) [-1])(), + ... # __main__.._macro_.defmacro + ... # hissp.macros.._macro_.let + ... ( + ... lambda _Qz2D5FNHXZz___fn=(lambda *_QzXDFV7JLKz___expr: + ... (lambda * _: _)( + ... 'lambda', + ... 'ABCDEFG', + ... _QzXDFV7JLKz___expr)): + ... (__import__('builtins').setattr( + ... _Qz2D5FNHXZz___fn, + ... '__qualname__', + ... ('.').join( + ... ('_macro_', + ... 'L7',))), + ... __import__('builtins').setattr( + ... __import__('operator').getitem( + ... __import__('builtins').globals(), + ... '_macro_'), + ... 'L7', + ... _Qz2D5FNHXZz___fn)) [-1])(), + ... # __main__.._macro_.defmacro + ... # hissp.macros.._macro_.let + ... ( + ... lambda _Qz2D5FNHXZz___fn=(lambda *_QzXDFV7JLKz___expr: + ... (lambda * _: _)( + ... 'lambda', + ... 'ABCDEFGH', + ... _QzXDFV7JLKz___expr)): + ... (__import__('builtins').setattr( + ... _Qz2D5FNHXZz___fn, + ... '__qualname__', + ... ('.').join( + ... ('_macro_', + ... 'L8',))), + ... __import__('builtins').setattr( + ... __import__('operator').getitem( + ... __import__('builtins').globals(), + ... '_macro_'), + ... 'L8', + ... _Qz2D5FNHXZz___fn)) [-1])(), + ... # __main__.._macro_.defmacro + ... # hissp.macros.._macro_.let + ... ( + ... lambda _Qz2D5FNHXZz___fn=(lambda *_QzXDFV7JLKz___expr: + ... (lambda * _: _)( + ... 'lambda', + ... 'ABCDEFGHI', + ... _QzXDFV7JLKz___expr)): + ... (__import__('builtins').setattr( + ... _Qz2D5FNHXZz___fn, + ... '__qualname__', + ... ('.').join( + ... ('_macro_', + ... 'L9',))), + ... __import__('builtins').setattr( + ... __import__('operator').getitem( + ... __import__('builtins').globals(), + ... '_macro_'), + ... 'L9', + ... _Qz2D5FNHXZz___fn)) [-1])(), + ... # __main__.._macro_.defmacro + ... # hissp.macros.._macro_.let + ... ( + ... lambda _Qz2D5FNHXZz___fn=(lambda *_QzXDFV7JLKz___expr: + ... (lambda * _: _)( + ... 'lambda', + ... 'ABCDEFGHIJ', + ... _QzXDFV7JLKz___expr)): + ... (__import__('builtins').setattr( + ... _Qz2D5FNHXZz___fn, + ... '__qualname__', + ... ('.').join( + ... ('_macro_', + ... 'L10',))), + ... __import__('builtins').setattr( + ... __import__('operator').getitem( + ... __import__('builtins').globals(), + ... '_macro_'), + ... 'L10', + ... _Qz2D5FNHXZz___fn)) [-1])(), + ... # __main__.._macro_.defmacro + ... # hissp.macros.._macro_.let + ... ( + ... lambda _Qz2D5FNHXZz___fn=(lambda *_QzXDFV7JLKz___expr: + ... (lambda * _: _)( + ... 'lambda', + ... 'ABCDEFGHIJK', + ... _QzXDFV7JLKz___expr)): + ... (__import__('builtins').setattr( + ... _Qz2D5FNHXZz___fn, + ... '__qualname__', + ... ('.').join( + ... ('_macro_', + ... 'L11',))), + ... __import__('builtins').setattr( + ... __import__('operator').getitem( + ... __import__('builtins').globals(), + ... '_macro_'), + ... 'L11', + ... _Qz2D5FNHXZz___fn)) [-1])(), + ... # __main__.._macro_.defmacro + ... # hissp.macros.._macro_.let + ... ( + ... lambda _Qz2D5FNHXZz___fn=(lambda *_QzXDFV7JLKz___expr: + ... (lambda * _: _)( + ... 'lambda', + ... 'ABCDEFGHIJKL', + ... _QzXDFV7JLKz___expr)): + ... (__import__('builtins').setattr( + ... _Qz2D5FNHXZz___fn, + ... '__qualname__', + ... ('.').join( + ... ('_macro_', + ... 'L12',))), + ... __import__('builtins').setattr( + ... __import__('operator').getitem( + ... __import__('builtins').globals(), + ... '_macro_'), + ... 'L12', + ... _Qz2D5FNHXZz___fn)) [-1])(), + ... # __main__.._macro_.defmacro + ... # hissp.macros.._macro_.let + ... ( + ... lambda _Qz2D5FNHXZz___fn=(lambda *_QzXDFV7JLKz___expr: + ... (lambda * _: _)( + ... 'lambda', + ... 'ABCDEFGHIJKLM', + ... _QzXDFV7JLKz___expr)): + ... (__import__('builtins').setattr( + ... _Qz2D5FNHXZz___fn, + ... '__qualname__', + ... ('.').join( + ... ('_macro_', + ... 'L13',))), + ... __import__('builtins').setattr( + ... __import__('operator').getitem( + ... __import__('builtins').globals(), + ... '_macro_'), + ... 'L13', + ... _Qz2D5FNHXZz___fn)) [-1])(), + ... # __main__.._macro_.defmacro + ... # hissp.macros.._macro_.let + ... ( + ... lambda _Qz2D5FNHXZz___fn=(lambda *_QzXDFV7JLKz___expr: + ... (lambda * _: _)( + ... 'lambda', + ... 'ABCDEFGHIJKLMN', + ... _QzXDFV7JLKz___expr)): + ... (__import__('builtins').setattr( + ... _Qz2D5FNHXZz___fn, + ... '__qualname__', + ... ('.').join( + ... ('_macro_', + ... 'L14',))), + ... __import__('builtins').setattr( + ... __import__('operator').getitem( + ... __import__('builtins').globals(), + ... '_macro_'), + ... 'L14', + ... _Qz2D5FNHXZz___fn)) [-1])(), + ... # __main__.._macro_.defmacro + ... # hissp.macros.._macro_.let + ... ( + ... lambda _Qz2D5FNHXZz___fn=(lambda *_QzXDFV7JLKz___expr: + ... (lambda * _: _)( + ... 'lambda', + ... 'ABCDEFGHIJKLMNO', + ... _QzXDFV7JLKz___expr)): + ... (__import__('builtins').setattr( + ... _Qz2D5FNHXZz___fn, + ... '__qualname__', + ... ('.').join( + ... ('_macro_', + ... 'L15',))), + ... __import__('builtins').setattr( + ... __import__('operator').getitem( + ... __import__('builtins').globals(), + ... '_macro_'), + ... 'L15', + ... _Qz2D5FNHXZz___fn)) [-1])(), + ... # __main__.._macro_.defmacro + ... # hissp.macros.._macro_.let + ... ( + ... lambda _Qz2D5FNHXZz___fn=(lambda *_QzXDFV7JLKz___expr: + ... (lambda * _: _)( + ... 'lambda', + ... 'ABCDEFGHIJKLMNOP', + ... _QzXDFV7JLKz___expr)): + ... (__import__('builtins').setattr( + ... _Qz2D5FNHXZz___fn, + ... '__qualname__', + ... ('.').join( + ... ('_macro_', + ... 'L16',))), + ... __import__('builtins').setattr( + ... __import__('operator').getitem( + ... __import__('builtins').globals(), + ... '_macro_'), + ... 'L16', + ... _Qz2D5FNHXZz___fn)) [-1])(), + ... # __main__.._macro_.defmacro + ... # hissp.macros.._macro_.let + ... ( + ... lambda _Qz2D5FNHXZz___fn=(lambda *_QzXDFV7JLKz___expr: + ... (lambda * _: _)( + ... 'lambda', + ... 'ABCDEFGHIJKLMNOPQ', + ... _QzXDFV7JLKz___expr)): + ... (__import__('builtins').setattr( + ... _Qz2D5FNHXZz___fn, + ... '__qualname__', + ... ('.').join( + ... ('_macro_', + ... 'L17',))), + ... __import__('builtins').setattr( + ... __import__('operator').getitem( + ... __import__('builtins').globals(), + ... '_macro_'), + ... 'L17', + ... _Qz2D5FNHXZz___fn)) [-1])(), + ... # __main__.._macro_.defmacro + ... # hissp.macros.._macro_.let + ... ( + ... lambda _Qz2D5FNHXZz___fn=(lambda *_QzXDFV7JLKz___expr: + ... (lambda * _: _)( + ... 'lambda', + ... 'ABCDEFGHIJKLMNOPQR', + ... _QzXDFV7JLKz___expr)): + ... (__import__('builtins').setattr( + ... _Qz2D5FNHXZz___fn, + ... '__qualname__', + ... ('.').join( + ... ('_macro_', + ... 'L18',))), + ... __import__('builtins').setattr( + ... __import__('operator').getitem( + ... __import__('builtins').globals(), + ... '_macro_'), + ... 'L18', + ... _Qz2D5FNHXZz___fn)) [-1])(), + ... # __main__.._macro_.defmacro + ... # hissp.macros.._macro_.let + ... ( + ... lambda _Qz2D5FNHXZz___fn=(lambda *_QzXDFV7JLKz___expr: + ... (lambda * _: _)( + ... 'lambda', + ... 'ABCDEFGHIJKLMNOPQRS', + ... _QzXDFV7JLKz___expr)): + ... (__import__('builtins').setattr( + ... _Qz2D5FNHXZz___fn, + ... '__qualname__', + ... ('.').join( + ... ('_macro_', + ... 'L19',))), + ... __import__('builtins').setattr( + ... __import__('operator').getitem( + ... __import__('builtins').globals(), + ... '_macro_'), + ... 'L19', + ... _Qz2D5FNHXZz___fn)) [-1])(), + ... # __main__.._macro_.defmacro + ... # hissp.macros.._macro_.let + ... ( + ... lambda _Qz2D5FNHXZz___fn=(lambda *_QzXDFV7JLKz___expr: + ... (lambda * _: _)( + ... 'lambda', + ... 'ABCDEFGHIJKLMNOPQRST', + ... _QzXDFV7JLKz___expr)): + ... (__import__('builtins').setattr( + ... _Qz2D5FNHXZz___fn, + ... '__qualname__', + ... ('.').join( + ... ('_macro_', + ... 'L20',))), + ... __import__('builtins').setattr( + ... __import__('operator').getitem( + ... __import__('builtins').globals(), + ... '_macro_'), + ... 'L20', + ... _Qz2D5FNHXZz___fn)) [-1])(), + ... # __main__.._macro_.defmacro + ... # hissp.macros.._macro_.let + ... ( + ... lambda _Qz2D5FNHXZz___fn=(lambda *_QzXDFV7JLKz___expr: + ... (lambda * _: _)( + ... 'lambda', + ... 'ABCDEFGHIJKLMNOPQRSTU', + ... _QzXDFV7JLKz___expr)): + ... (__import__('builtins').setattr( + ... _Qz2D5FNHXZz___fn, + ... '__qualname__', + ... ('.').join( + ... ('_macro_', + ... 'L21',))), + ... __import__('builtins').setattr( + ... __import__('operator').getitem( + ... __import__('builtins').globals(), + ... '_macro_'), + ... 'L21', + ... _Qz2D5FNHXZz___fn)) [-1])(), + ... # __main__.._macro_.defmacro + ... # hissp.macros.._macro_.let + ... ( + ... lambda _Qz2D5FNHXZz___fn=(lambda *_QzXDFV7JLKz___expr: + ... (lambda * _: _)( + ... 'lambda', + ... 'ABCDEFGHIJKLMNOPQRSTUV', + ... _QzXDFV7JLKz___expr)): + ... (__import__('builtins').setattr( + ... _Qz2D5FNHXZz___fn, + ... '__qualname__', + ... ('.').join( + ... ('_macro_', + ... 'L22',))), + ... __import__('builtins').setattr( + ... __import__('operator').getitem( + ... __import__('builtins').globals(), + ... '_macro_'), + ... 'L22', + ... _Qz2D5FNHXZz___fn)) [-1])(), + ... # __main__.._macro_.defmacro + ... # hissp.macros.._macro_.let + ... ( + ... lambda _Qz2D5FNHXZz___fn=(lambda *_QzXDFV7JLKz___expr: + ... (lambda * _: _)( + ... 'lambda', + ... 'ABCDEFGHIJKLMNOPQRSTUVW', + ... _QzXDFV7JLKz___expr)): + ... (__import__('builtins').setattr( + ... _Qz2D5FNHXZz___fn, + ... '__qualname__', + ... ('.').join( + ... ('_macro_', + ... 'L23',))), + ... __import__('builtins').setattr( + ... __import__('operator').getitem( + ... __import__('builtins').globals(), + ... '_macro_'), + ... 'L23', + ... _Qz2D5FNHXZz___fn)) [-1])(), + ... # __main__.._macro_.defmacro + ... # hissp.macros.._macro_.let + ... ( + ... lambda _Qz2D5FNHXZz___fn=(lambda *_QzXDFV7JLKz___expr: + ... (lambda * _: _)( + ... 'lambda', + ... 'ABCDEFGHIJKLMNOPQRSTUVWX', + ... _QzXDFV7JLKz___expr)): + ... (__import__('builtins').setattr( + ... _Qz2D5FNHXZz___fn, + ... '__qualname__', + ... ('.').join( + ... ('_macro_', + ... 'L24',))), + ... __import__('builtins').setattr( + ... __import__('operator').getitem( + ... __import__('builtins').globals(), + ... '_macro_'), + ... 'L24', + ... _Qz2D5FNHXZz___fn)) [-1])(), + ... # __main__.._macro_.defmacro + ... # hissp.macros.._macro_.let + ... ( + ... lambda _Qz2D5FNHXZz___fn=(lambda *_QzXDFV7JLKz___expr: + ... (lambda * _: _)( + ... 'lambda', + ... 'ABCDEFGHIJKLMNOPQRSTUVWXY', + ... _QzXDFV7JLKz___expr)): + ... (__import__('builtins').setattr( + ... _Qz2D5FNHXZz___fn, + ... '__qualname__', + ... ('.').join( + ... ('_macro_', + ... 'L25',))), + ... __import__('builtins').setattr( + ... __import__('operator').getitem( + ... __import__('builtins').globals(), + ... '_macro_'), + ... 'L25', + ... _Qz2D5FNHXZz___fn)) [-1])(), + ... # __main__.._macro_.defmacro + ... # hissp.macros.._macro_.let + ... ( + ... lambda _Qz2D5FNHXZz___fn=(lambda *_QzXDFV7JLKz___expr: + ... (lambda * _: _)( + ... 'lambda', + ... 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', + ... _QzXDFV7JLKz___expr)): + ... (__import__('builtins').setattr( + ... _Qz2D5FNHXZz___fn, + ... '__qualname__', + ... ('.').join( + ... ('_macro_', + ... 'L26',))), + ... __import__('builtins').setattr( + ... __import__('operator').getitem( + ... __import__('builtins').globals(), + ... '_macro_'), + ... 'L26', + ... _Qz2D5FNHXZz___fn)) [-1])()) [-1])() Whoa. @@ -1358,12 +1392,15 @@ It totally works too. #> ((L3 add C (add A B)) #.. "A" "B" "C") >>> # L3 - ... (lambda A,B,C: - ... add( - ... C, + ... ( + ... lambda A, + ... B, + ... C: ... add( - ... A, - ... B)))( + ... C, + ... add( + ... A, + ... B)))( ... ('A'), ... ('B'), ... ('C')) @@ -1371,19 +1408,60 @@ It totally works too. #> (L26) >>> # L26 - ... (lambda A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z:()) + ... ( + ... lambda A, + ... B, + ... C, + ... D, + ... E, + ... F, + ... G, + ... H, + ... I, + ... J, + ... K, + ... L, + ... M, + ... N, + ... O, + ... P, + ... Q, + ... R, + ... S, + ... T, + ... U, + ... V, + ... W, + ... X, + ... Y, + ... Z: + ... ()) at ...> #> (L13) >>> # L13 - ... (lambda A,B,C,D,E,F,G,H,I,J,K,L,M:()) + ... ( + ... lambda A, + ... B, + ... C, + ... D, + ... E, + ... F, + ... G, + ... H, + ... I, + ... J, + ... K, + ... L, + ... M: + ... ()) at ...> #> ((L0 print "Hello, World!")) >>> # L0 ... (lambda : - ... print( - ... ('Hello, World!')))() + ... print( + ... ('Hello, World!')))() Hello, World! How does this work? @@ -1487,31 +1565,34 @@ We can create numbered X's the same way we created the numbered L's. #.. ,expr)) >>> # defmacro ... # hissp.macros.._macro_.let - ... (lambda _QzAW22OE5Kz_fn=(lambda number,*expr: - ... (lambda * _: _)( - ... 'lambda', - ... map( - ... (lambda i: - ... ('X{}').format( - ... i)), - ... range( - ... (1), - ... add( - ... (1), - ... number))), - ... expr)):( - ... __import__('builtins').setattr( - ... _QzAW22OE5Kz_fn, - ... '__qualname__', - ... ('.').join( - ... ('_macro_', - ... 'L',))), - ... __import__('builtins').setattr( - ... __import__('operator').getitem( - ... __import__('builtins').globals(), - ... '_macro_'), - ... 'L', - ... _QzAW22OE5Kz_fn))[-1])() + ... ( + ... lambda _QzAW22OE5Kz___fn=( + ... lambda number, + ... *expr: + ... (lambda * _: _)( + ... 'lambda', + ... map( + ... (lambda i: + ... ('X{}').format( + ... i)), + ... range( + ... (1), + ... add( + ... (1), + ... number))), + ... expr)): + ... (__import__('builtins').setattr( + ... _QzAW22OE5Kz___fn, + ... '__qualname__', + ... ('.').join( + ... ('_macro_', + ... 'L',))), + ... __import__('builtins').setattr( + ... __import__('operator').getitem( + ... __import__('builtins').globals(), + ... '_macro_'), + ... 'L', + ... _QzAW22OE5Kz___fn)) [-1])() .. tip:: @@ -1530,15 +1611,28 @@ We can create numbered X's the same way we created the numbered L's. #> (L 10) >>> # L - ... (lambda X1,X2,X3,X4,X5,X6,X7,X8,X9,X10:()) + ... ( + ... lambda X1, + ... X2, + ... X3, + ... X4, + ... X5, + ... X6, + ... X7, + ... X8, + ... X9, + ... X10: + ... ()) at ...> #> ((L 2 add X1 X2) "A" "B") >>> # L - ... (lambda X1,X2: - ... add( - ... X1, - ... X2))( + ... ( + ... lambda X1, + ... X2: + ... add( + ... X1, + ... X2))( ... ('A'), ... ('B')) 'AB' @@ -1559,32 +1653,33 @@ Let's make a slight tweak. #.. ,expr)) >>> # defmacro ... # hissp.macros.._macro_.let - ... (lambda _QzAW22OE5Kz_fn=(lambda *expr: - ... (lambda * _: _)( - ... 'lambda', - ... map( - ... (lambda i: - ... ('X{}').format( - ... i)), - ... range( - ... (1), - ... add( - ... (1), - ... maxQz_X( - ... expr)))), - ... expr)):( - ... __import__('builtins').setattr( - ... _QzAW22OE5Kz_fn, - ... '__qualname__', - ... ('.').join( - ... ('_macro_', - ... 'L',))), - ... __import__('builtins').setattr( - ... __import__('operator').getitem( - ... __import__('builtins').globals(), - ... '_macro_'), - ... 'L', - ... _QzAW22OE5Kz_fn))[-1])() + ... ( + ... lambda _QzAW22OE5Kz___fn=(lambda *expr: + ... (lambda * _: _)( + ... 'lambda', + ... map( + ... (lambda i: + ... ('X{}').format( + ... i)), + ... range( + ... (1), + ... add( + ... (1), + ... maxQz_X( + ... expr)))), + ... expr)): + ... (__import__('builtins').setattr( + ... _QzAW22OE5Kz___fn, + ... '__qualname__', + ... ('.').join( + ... ('_macro_', + ... 'L',))), + ... __import__('builtins').setattr( + ... __import__('operator').getitem( + ... __import__('builtins').globals(), + ... '_macro_'), + ... 'L', + ... _QzAW22OE5Kz___fn)) [-1])() What is this ``max-X``? @@ -1609,31 +1704,41 @@ Can we just iterate through the expression and check? >>> # define ... __import__('builtins').globals().update( ... maxQz_X=(lambda expr: - ... max( - ... map( - ... (lambda x: - ... # ors - ... (lambda x0,x1:x0 or x1())( - ... # when - ... (lambda b,c:c()if b else())( - ... is_( - ... str, - ... type( - ... x)), - ... (lambda : - ... # let - ... (lambda match=__import__('re').fullmatch( - ... ('X([1-9][0-9]*)'), - ... x): - ... # when - ... (lambda b,c:c()if b else())( - ... match, - ... (lambda : - ... int( - ... match.group( - ... (1))))))())), - ... (lambda :(0)))), - ... expr)))) + ... max( + ... map( + ... (lambda x: + ... # ors + ... ( + ... lambda x0, + ... x1: + ... x0 or x1())( + ... # when + ... ( + ... lambda b, + ... c: + ... c()if b else())( + ... is_( + ... str, + ... type( + ... x)), + ... (lambda : + ... # let + ... ( + ... lambda match=__import__('re').fullmatch( + ... ('X([1-9][0-9]*)'), + ... x): + ... # when + ... ( + ... lambda b, + ... c: + ... c()if b else())( + ... match, + ... (lambda : + ... int( + ... match.group( + ... (1))))))())), + ... (lambda : (0)))), + ... expr)))) Does that make sense? @@ -1652,10 +1757,12 @@ It gets the parameters right: #> ((L add X2 X1) : :* "AB") >>> # L - ... (lambda X1,X2: - ... add( - ... X2, - ... X1))( + ... ( + ... lambda X1, + ... X2: + ... add( + ... X2, + ... X1))( ... *('AB')) 'BA' @@ -1667,11 +1774,11 @@ Pretty cool. #.. : :* "BAR") >>> # L ... (lambda X1: - ... add( - ... X1, ... add( - ... X2, - ... X3)))( + ... X1, + ... add( + ... X2, + ... X3)))( ... *('BAR')) Traceback (most recent call last): File "", line 2, in @@ -1697,22 +1804,26 @@ This sounds like a job for recursion. >>> # define ... __import__('builtins').globals().update( ... flatten=(lambda form: - ... __import__('itertools').chain.from_iterable( - ... map( - ... (lambda x: - ... # ifQz_else - ... (lambda b,c,a:c()if b else a())( - ... is_( - ... type( - ... x), - ... tuple), - ... (lambda : - ... flatten( - ... x)), - ... (lambda : - ... (lambda * _: _)( - ... x)))), - ... form)))) + ... __import__('itertools').chain.from_iterable( + ... map( + ... (lambda x: + ... # ifQz_else + ... ( + ... lambda b, + ... c, + ... a: + ... c()if b else a())( + ... is_( + ... type( + ... x), + ... tuple), + ... (lambda : + ... flatten( + ... x)), + ... (lambda : + ... (lambda * _: _)( + ... x)))), + ... form)))) More bundled macros here. @@ -1736,32 +1847,42 @@ Now we can fix ``max-X``. >>> # define ... __import__('builtins').globals().update( ... maxQz_X=(lambda expr: - ... max( - ... map( - ... (lambda x: - ... # ors - ... (lambda x0,x1:x0 or x1())( - ... # when - ... (lambda b,c:c()if b else())( - ... is_( - ... str, - ... type( - ... x)), - ... (lambda : - ... # let - ... (lambda match=__import__('re').fullmatch( - ... ('X([1-9][0-9]*)'), - ... x): - ... # when - ... (lambda b,c:c()if b else())( - ... match, - ... (lambda : - ... int( - ... match.group( - ... (1))))))())), - ... (lambda :(0)))), - ... flatten( - ... expr))))) + ... max( + ... map( + ... (lambda x: + ... # ors + ... ( + ... lambda x0, + ... x1: + ... x0 or x1())( + ... # when + ... ( + ... lambda b, + ... c: + ... c()if b else())( + ... is_( + ... str, + ... type( + ... x)), + ... (lambda : + ... # let + ... ( + ... lambda match=__import__('re').fullmatch( + ... ('X([1-9][0-9]*)'), + ... x): + ... # when + ... ( + ... lambda b, + ... c: + ... c()if b else())( + ... match, + ... (lambda : + ... int( + ... match.group( + ... (1))))))())), + ... (lambda : (0)))), + ... flatten( + ... expr))))) Let's try again. @@ -1771,12 +1892,15 @@ Let's try again. #> ((L add X1 (add X2 X3)) #.. : :* "BAR") >>> # L - ... (lambda X1,X2,X3: - ... add( - ... X1, + ... ( + ... lambda X1, + ... X2, + ... X3: ... add( - ... X2, - ... X3)))( + ... X1, + ... add( + ... X2, + ... X3)))( ... *('BAR')) 'BAR' @@ -1855,9 +1979,9 @@ You can use the resulting macro as a shorter lambda for higher-order functions: ... map( ... # L ... (lambda X1: - ... add( - ... X1, - ... X1)), + ... add( + ... X1, + ... X1)), ... range( ... (10)))) [0, 2, 4, 6, 8, 10, 12, 14, 16, 18] @@ -1879,22 +2003,23 @@ you must define them in ``_macro_`` with a name ending in a ``#``. #.. `(L ,@expr)) >>> # defmacro ... # hissp.macros.._macro_.let - ... (lambda _QzAW22OE5Kz_fn=(lambda expr: - ... (lambda * _: _)( - ... '__main__.._macro_.L', - ... *expr)):( - ... __import__('builtins').setattr( - ... _QzAW22OE5Kz_fn, - ... '__qualname__', - ... ('.').join( - ... ('_macro_', - ... 'XQzHASH_',))), - ... __import__('builtins').setattr( - ... __import__('operator').getitem( - ... __import__('builtins').globals(), - ... '_macro_'), - ... 'XQzHASH_', - ... _QzAW22OE5Kz_fn))[-1])() + ... ( + ... lambda _QzAW22OE5Kz___fn=(lambda expr: + ... (lambda * _: _)( + ... '__main__.._macro_.L', + ... *expr)): + ... (__import__('builtins').setattr( + ... _QzAW22OE5Kz___fn, + ... '__qualname__', + ... ('.').join( + ... ('_macro_', + ... 'XQzHASH_',))), + ... __import__('builtins').setattr( + ... __import__('operator').getitem( + ... __import__('builtins').globals(), + ... '_macro_'), + ... 'XQzHASH_', + ... _QzAW22OE5Kz___fn)) [-1])() We have to escape the ``#`` with a backslash or the reader will parse the name as a tag rather than a symbol @@ -1911,9 +2036,9 @@ It's the way you invoke it (with a reader ``tag#``) that makes it happen at read ... map( ... # __main__.._macro_.L ... (lambda X1: - ... add( - ... X1, - ... X1)), + ... add( + ... X1, + ... X1)), ... range( ... (10)))) [0, 2, 4, 6, 8, 10, 12, 14, 16, 18] @@ -1925,9 +2050,9 @@ It's the way you invoke it (with a reader ``tag#``) that makes it happen at read ... # XQzHASH_ ... # __main__.._macro_.L ... (lambda X1: - ... add( - ... X1, - ... X1)), + ... add( + ... X1, + ... X1)), ... range( ... (10)))) [0, 2, 4, 6, 8, 10, 12, 14, 16, 18] @@ -1975,54 +2100,61 @@ Catch-All Parameter #.. ,expr)) >>> # defmacro ... # hissp.macros.._macro_.let - ... (lambda _QzAW22OE5Kz_fn=(lambda *expr: - ... (lambda * _: _)( - ... 'lambda', - ... (lambda * _: _)( - ... *map( - ... (lambda i: - ... ('X{}').format( - ... i)), - ... range( - ... (1), - ... add( - ... (1), - ... maxQz_X( - ... expr)))), - ... ':', - ... *# when - ... (lambda b,c:c()if b else())( - ... contains( - ... flatten( - ... expr), - ... 'Xi'), - ... (lambda : - ... (lambda * _: _)( - ... ':*', - ... 'Xi')))), - ... expr)):( - ... __import__('builtins').setattr( - ... _QzAW22OE5Kz_fn, - ... '__qualname__', - ... ('.').join( - ... ('_macro_', - ... 'L',))), - ... __import__('builtins').setattr( - ... __import__('operator').getitem( - ... __import__('builtins').globals(), - ... '_macro_'), - ... 'L', - ... _QzAW22OE5Kz_fn))[-1])() + ... ( + ... lambda _QzAW22OE5Kz___fn=(lambda *expr: + ... (lambda * _: _)( + ... 'lambda', + ... (lambda * _: _)( + ... *map( + ... (lambda i: + ... ('X{}').format( + ... i)), + ... range( + ... (1), + ... add( + ... (1), + ... maxQz_X( + ... expr)))), + ... ':', + ... *# when + ... ( + ... lambda b, + ... c: + ... c()if b else())( + ... contains( + ... flatten( + ... expr), + ... 'Xi'), + ... (lambda : + ... (lambda * _: _)( + ... ':*', + ... 'Xi')))), + ... expr)): + ... (__import__('builtins').setattr( + ... _QzAW22OE5Kz___fn, + ... '__qualname__', + ... ('.').join( + ... ('_macro_', + ... 'L',))), + ... __import__('builtins').setattr( + ... __import__('operator').getitem( + ... __import__('builtins').globals(), + ... '_macro_'), + ... 'L', + ... _QzAW22OE5Kz___fn)) [-1])() .. code-block:: REPL #> (X#(print X1 X2 Xi) 1 2 3 4 5) >>> # __main__.._macro_.L - ... (lambda X1,X2,*Xi: - ... print( - ... X1, - ... X2, - ... Xi))( + ... ( + ... lambda X1, + ... X2, + ... *Xi: + ... print( + ... X1, + ... X2, + ... Xi))( ... (1), ... (2), ... (3), @@ -2106,64 +2238,75 @@ Here you go: #.. expr))) >>> # defmacro ... # hissp.macros.._macro_.let - ... (lambda _QzAW22OE5Kz_fn=(lambda *expr: - ... (lambda * _: _)( - ... 'lambda', - ... (lambda * _: _)( - ... *map( - ... (lambda i: - ... ('X{}').format( - ... i)), - ... range( - ... (1), - ... add( - ... (1), - ... # ors - ... (lambda x0,x1:x0 or x1())( - ... maxQz_X( - ... expr), - ... (lambda : - ... contains( - ... flatten( - ... expr), - ... 'X')))))), - ... ':', - ... *# when - ... (lambda b,c:c()if b else())( - ... contains( - ... flatten( - ... expr), - ... 'Xi'), - ... (lambda : - ... (lambda * _: _)( - ... ':*', - ... 'Xi')))), - ... # ifQz_else - ... (lambda b,c,a:c()if b else a())( - ... contains( - ... flatten( - ... expr), - ... 'X'), - ... (lambda : - ... (lambda * _: _)( - ... '__main__.._macro_.let', - ... (lambda * _: _)( - ... 'X', - ... 'X1'), - ... expr)), - ... (lambda :expr)))):( - ... __import__('builtins').setattr( - ... _QzAW22OE5Kz_fn, - ... '__qualname__', - ... ('.').join( - ... ('_macro_', - ... 'L',))), - ... __import__('builtins').setattr( - ... __import__('operator').getitem( - ... __import__('builtins').globals(), - ... '_macro_'), - ... 'L', - ... _QzAW22OE5Kz_fn))[-1])() + ... ( + ... lambda _QzAW22OE5Kz___fn=(lambda *expr: + ... (lambda * _: _)( + ... 'lambda', + ... (lambda * _: _)( + ... *map( + ... (lambda i: + ... ('X{}').format( + ... i)), + ... range( + ... (1), + ... add( + ... (1), + ... # ors + ... ( + ... lambda x0, + ... x1: + ... x0 or x1())( + ... maxQz_X( + ... expr), + ... (lambda : + ... contains( + ... flatten( + ... expr), + ... 'X')))))), + ... ':', + ... *# when + ... ( + ... lambda b, + ... c: + ... c()if b else())( + ... contains( + ... flatten( + ... expr), + ... 'Xi'), + ... (lambda : + ... (lambda * _: _)( + ... ':*', + ... 'Xi')))), + ... # ifQz_else + ... ( + ... lambda b, + ... c, + ... a: + ... c()if b else a())( + ... contains( + ... flatten( + ... expr), + ... 'X'), + ... (lambda : + ... (lambda * _: _)( + ... '__main__.._macro_.let', + ... (lambda * _: _)( + ... 'X', + ... 'X1'), + ... expr)), + ... (lambda : expr)))): + ... (__import__('builtins').setattr( + ... _QzAW22OE5Kz___fn, + ... '__qualname__', + ... ('.').join( + ... ('_macro_', + ... 'L',))), + ... __import__('builtins').setattr( + ... __import__('operator').getitem( + ... __import__('builtins').globals(), + ... '_macro_'), + ... 'L', + ... _QzAW22OE5Kz___fn)) [-1])() .. code-block:: REPL @@ -2172,11 +2315,11 @@ Here you go: ... map( ... # __main__.._macro_.L ... (lambda X1: - ... # __main__.._macro_.let - ... (lambda X=X1: - ... add( - ... X, - ... X1))()), + ... # __main__.._macro_.let + ... (lambda X=X1: + ... add( + ... X, + ... X1))()), ... range( ... (10)))) [0, 2, 4, 6, 8, 10, 12, 14, 16, 18] @@ -2289,7 +2432,7 @@ But what if we had kept the ``X``? #> X#(|(-X2 + (X2**2 - 4*X1*X3)**0.5)/(2*X1)|) >>> # __main__.._macro_.L - ... (lambda :(-X2 + (X2**2 - 4*X1*X3)**0.5)/(2*X1)()) + ... (lambda : (-X2 + (X2**2 - 4*X1*X3)**0.5)/(2*X1)()) at ...> Look at the Python compilation. @@ -2308,9 +2451,9 @@ This doesn't look too bad if you think of it like a fraction bar. #.. |(2*X1)|) >>> # __main__.._macro_.L ... (lambda : - ... truediv( - ... (-X2 + (X2**2 - 4*X1*X3)**0.5), - ... (2*X1))) + ... truediv( + ... (-X2 + (X2**2 - 4*X1*X3)**0.5), + ... (2*X1))) at ...> Now the formula looks right, @@ -2442,22 +2585,23 @@ Lissp gives us a better option. #.. (int x 16)) >>> # defmacro ... # hissp.macros.._macro_.let - ... (lambda _QzAW22OE5Kz_fn=(lambda x: - ... int( - ... x, - ... (16))):( - ... __import__('builtins').setattr( - ... _QzAW22OE5Kz_fn, - ... '__qualname__', - ... ('.').join( - ... ('_macro_', - ... 'QzDIGITxONE_6QzHASH_',))), - ... __import__('builtins').setattr( - ... __import__('operator').getitem( - ... __import__('builtins').globals(), - ... '_macro_'), - ... 'QzDIGITxONE_6QzHASH_', - ... _QzAW22OE5Kz_fn))[-1])() + ... ( + ... lambda _QzAW22OE5Kz___fn=(lambda x: + ... int( + ... x, + ... (16))): + ... (__import__('builtins').setattr( + ... _QzAW22OE5Kz___fn, + ... '__qualname__', + ... ('.').join( + ... ('_macro_', + ... 'QzDIGITxONE_6QzHASH_',))), + ... __import__('builtins').setattr( + ... __import__('operator').getitem( + ... __import__('builtins').globals(), + ... '_macro_'), + ... 'QzDIGITxONE_6QzHASH_', + ... _QzAW22OE5Kz___fn)) [-1])() We've defined a tag that turns hexadecimal strings into ints. And it does it so at *read time*. @@ -2514,23 +2658,24 @@ New version. #.. (int (str x) 16)) >>> # defmacro ... # hissp.macros.._macro_.let - ... (lambda _QzAW22OE5Kz_fn=(lambda x: - ... int( - ... str( - ... x), - ... (16))):( - ... __import__('builtins').setattr( - ... _QzAW22OE5Kz_fn, - ... '__qualname__', - ... ('.').join( - ... ('_macro_', - ... 'QzDIGITxONE_6QzHASH_',))), - ... __import__('builtins').setattr( - ... __import__('operator').getitem( - ... __import__('builtins').globals(), - ... '_macro_'), - ... 'QzDIGITxONE_6QzHASH_', - ... _QzAW22OE5Kz_fn))[-1])() + ... ( + ... lambda _QzAW22OE5Kz___fn=(lambda x: + ... int( + ... str( + ... x), + ... (16))): + ... (__import__('builtins').setattr( + ... _QzAW22OE5Kz___fn, + ... '__qualname__', + ... ('.').join( + ... ('_macro_', + ... 'QzDIGITxONE_6QzHASH_',))), + ... __import__('builtins').setattr( + ... __import__('operator').getitem( + ... __import__('builtins').globals(), + ... '_macro_'), + ... 'QzDIGITxONE_6QzHASH_', + ... _QzAW22OE5Kz___fn)) [-1])() And now it works as well as the built-in notation. @@ -2615,29 +2760,30 @@ because munging is (mostly) reversible. #.. 16)) >>> # defmacro ... # hissp.macros.._macro_.let - ... (lambda _QzAW22OE5Kz_fn=(lambda x:( - ... ('hexadecimal'), - ... int( - ... __import__('hissp').demunge( - ... str( - ... x)), - ... (16)))[-1]):( - ... __import__('builtins').setattr( - ... _QzAW22OE5Kz_fn, - ... '__doc__', - ... ('hexadecimal')), - ... __import__('builtins').setattr( - ... _QzAW22OE5Kz_fn, - ... '__qualname__', - ... ('.').join( - ... ('_macro_', - ... 'QzDIGITxONE_6QzHASH_',))), - ... __import__('builtins').setattr( - ... __import__('operator').getitem( - ... __import__('builtins').globals(), - ... '_macro_'), - ... 'QzDIGITxONE_6QzHASH_', - ... _QzAW22OE5Kz_fn))[-1])() + ... ( + ... lambda _QzAW22OE5Kz___fn=(lambda x: + ... (('hexadecimal'), + ... int( + ... __import__('hissp').demunge( + ... str( + ... x)), + ... (16))) [-1]): + ... (__import__('builtins').setattr( + ... _QzAW22OE5Kz___fn, + ... '__doc__', + ... ('hexadecimal')), + ... __import__('builtins').setattr( + ... _QzAW22OE5Kz___fn, + ... '__qualname__', + ... ('.').join( + ... ('_macro_', + ... 'QzDIGITxONE_6QzHASH_',))), + ... __import__('builtins').setattr( + ... __import__('operator').getitem( + ... __import__('builtins').globals(), + ... '_macro_'), + ... 'QzDIGITxONE_6QzHASH_', + ... _QzAW22OE5Kz___fn)) [-1])() .. code-block:: REPL @@ -2656,28 +2802,29 @@ Well, with reader macros, you can implement any base you want. #.. (int (str x) 6)) >>> # defmacro ... # hissp.macros.._macro_.let - ... (lambda _QzAW22OE5Kz_fn=(lambda x:( - ... ('seximal'), - ... int( - ... str( - ... x), - ... (6)))[-1]):( - ... __import__('builtins').setattr( - ... _QzAW22OE5Kz_fn, - ... '__doc__', - ... ('seximal')), - ... __import__('builtins').setattr( - ... _QzAW22OE5Kz_fn, - ... '__qualname__', - ... ('.').join( - ... ('_macro_', - ... 'QzDIGITxSIX_QzHASH_',))), - ... __import__('builtins').setattr( - ... __import__('operator').getitem( - ... __import__('builtins').globals(), - ... '_macro_'), - ... 'QzDIGITxSIX_QzHASH_', - ... _QzAW22OE5Kz_fn))[-1])() + ... ( + ... lambda _QzAW22OE5Kz___fn=(lambda x: + ... (('seximal'), + ... int( + ... str( + ... x), + ... (6))) [-1]): + ... (__import__('builtins').setattr( + ... _QzAW22OE5Kz___fn, + ... '__doc__', + ... ('seximal')), + ... __import__('builtins').setattr( + ... _QzAW22OE5Kz___fn, + ... '__qualname__', + ... ('.').join( + ... ('_macro_', + ... 'QzDIGITxSIX_QzHASH_',))), + ... __import__('builtins').setattr( + ... __import__('operator').getitem( + ... __import__('builtins').globals(), + ... '_macro_'), + ... 'QzDIGITxSIX_QzHASH_', + ... _QzAW22OE5Kz___fn)) [-1])() .. code-block:: REPL @@ -2703,35 +2850,41 @@ Or you can add floating-point. Python's literal notation can't do that. #.. (int x 16)))) >>> # defmacro ... # hissp.macros.._macro_.let - ... (lambda _QzAW22OE5Kz_fn=(lambda x: - ... # let - ... (lambda x=__import__('hissp').demunge( - ... str( - ... x)): - ... # ifQz_else - ... (lambda b,c,a:c()if b else a())( - ... __import__('re').search( - ... ('[.Pp]'), - ... x), - ... (lambda : - ... float.fromhex( - ... x)), - ... (lambda : - ... int( - ... x, - ... (16)))))()):( - ... __import__('builtins').setattr( - ... _QzAW22OE5Kz_fn, - ... '__qualname__', - ... ('.').join( - ... ('_macro_', - ... 'QzDIGITxONE_6QzHASH_',))), - ... __import__('builtins').setattr( - ... __import__('operator').getitem( - ... __import__('builtins').globals(), - ... '_macro_'), - ... 'QzDIGITxONE_6QzHASH_', - ... _QzAW22OE5Kz_fn))[-1])() + ... ( + ... lambda _QzAW22OE5Kz___fn=(lambda x: + ... # let + ... ( + ... lambda x=__import__('hissp').demunge( + ... str( + ... x)): + ... # ifQz_else + ... ( + ... lambda b, + ... c, + ... a: + ... c()if b else a())( + ... __import__('re').search( + ... ('[.Pp]'), + ... x), + ... (lambda : + ... float.fromhex( + ... x)), + ... (lambda : + ... int( + ... x, + ... (16)))))()): + ... (__import__('builtins').setattr( + ... _QzAW22OE5Kz___fn, + ... '__qualname__', + ... ('.').join( + ... ('_macro_', + ... 'QzDIGITxONE_6QzHASH_',))), + ... __import__('builtins').setattr( + ... __import__('operator').getitem( + ... __import__('builtins').globals(), + ... '_macro_'), + ... 'QzDIGITxONE_6QzHASH_', + ... _QzAW22OE5Kz___fn)) [-1])() .. code-block:: REPL @@ -2843,25 +2996,26 @@ We can improve this a lot with a custom defmacro. #.. `(decimal..Decimal ',(str x))) >>> # defmacro ... # hissp.macros.._macro_.let - ... (lambda _QzAW22OE5Kz_fn=(lambda x: - ... (lambda * _: _)( - ... 'decimal..Decimal', - ... (lambda * _: _)( - ... 'quote', - ... str( - ... x)))):( - ... __import__('builtins').setattr( - ... _QzAW22OE5Kz_fn, - ... '__qualname__', - ... ('.').join( - ... ('_macro_', - ... 'QzDIGITxONE_0QzHASH_',))), - ... __import__('builtins').setattr( - ... __import__('operator').getitem( - ... __import__('builtins').globals(), - ... '_macro_'), - ... 'QzDIGITxONE_0QzHASH_', - ... _QzAW22OE5Kz_fn))[-1])() + ... ( + ... lambda _QzAW22OE5Kz___fn=(lambda x: + ... (lambda * _: _)( + ... 'decimal..Decimal', + ... (lambda * _: _)( + ... 'quote', + ... str( + ... x)))): + ... (__import__('builtins').setattr( + ... _QzAW22OE5Kz___fn, + ... '__qualname__', + ... ('.').join( + ... ('_macro_', + ... 'QzDIGITxONE_0QzHASH_',))), + ... __import__('builtins').setattr( + ... __import__('operator').getitem( + ... __import__('builtins').globals(), + ... '_macro_'), + ... 'QzDIGITxONE_0QzHASH_', + ... _QzAW22OE5Kz___fn)) [-1])() .. code-block:: REPL @@ -2921,28 +3075,29 @@ but a ``||`` fragment is not the only alternative available: #.. `(decimal..Decimal ',(getitem x (slice 1 None)))) >>> # defmacro ... # hissp.macros.._macro_.let - ... (lambda _QzAW22OE5Kz_fn=(lambda x: - ... (lambda * _: _)( - ... 'decimal..Decimal', - ... (lambda * _: _)( - ... 'quote', - ... getitem( - ... x, - ... slice( - ... (1), - ... None))))):( - ... __import__('builtins').setattr( - ... _QzAW22OE5Kz_fn, - ... '__qualname__', - ... ('.').join( - ... ('_macro_', - ... 'QzDIGITxONE_0QzHASH_',))), - ... __import__('builtins').setattr( - ... __import__('operator').getitem( - ... __import__('builtins').globals(), - ... '_macro_'), - ... 'QzDIGITxONE_0QzHASH_', - ... _QzAW22OE5Kz_fn))[-1])() + ... ( + ... lambda _QzAW22OE5Kz___fn=(lambda x: + ... (lambda * _: _)( + ... 'decimal..Decimal', + ... (lambda * _: _)( + ... 'quote', + ... getitem( + ... x, + ... slice( + ... (1), + ... None))))): + ... (__import__('builtins').setattr( + ... _QzAW22OE5Kz___fn, + ... '__qualname__', + ... ('.').join( + ... ('_macro_', + ... 'QzDIGITxONE_0QzHASH_',))), + ... __import__('builtins').setattr( + ... __import__('operator').getitem( + ... __import__('builtins').globals(), + ... '_macro_'), + ... 'QzDIGITxONE_0QzHASH_', + ... _QzAW22OE5Kz___fn)) [-1])() .. code-block:: REPL @@ -3006,7 +3161,7 @@ but that adds significant overhead. #> (let (x "abcdefg") |x[-1::-2]|) >>> # let - ... (lambda x=('abcdefg'):x[-1::-2])() + ... (lambda x=('abcdefg'): x[-1::-2])() 'geca' .. TODO: (X#.#"X[-1::-2]" "abcdefg") @@ -3064,9 +3219,15 @@ Search Hissp's docs if you can't figure out what they do.) ... 'Slicer', ... (), ... # QzPCENT_ - ... (lambda x0,x1:{x0:x1})( + ... ( + ... lambda x0, + ... x1: + ... {x0:x1})( ... '__getitem__', - ... (lambda X,Y:Y)))()) + ... ( + ... lambda X, + ... Y: + ... Y)))()) #> |slicer[-1::-2]| >>> slicer[-1::-2] @@ -3127,24 +3288,25 @@ so we could include that and the ``itemgetter`` call in the expansion. #.. `(op#itemgetter ,(.format "slicer{}" (hissp..demunge e)))) >>> # defmacro ... # hissp.macros.._macro_.let - ... (lambda _QzAW22OE5Kz_fn=(lambda e: - ... (lambda * _: _)( - ... 'operator..itemgetter', - ... ('slicer{}').format( - ... __import__('hissp').demunge( - ... e)))):( - ... __import__('builtins').setattr( - ... _QzAW22OE5Kz_fn, - ... '__qualname__', - ... ('.').join( - ... ('_macro_', - ... 'SQzHASH_',))), - ... __import__('builtins').setattr( - ... __import__('operator').getitem( - ... __import__('builtins').globals(), - ... '_macro_'), - ... 'SQzHASH_', - ... _QzAW22OE5Kz_fn))[-1])() + ... ( + ... lambda _QzAW22OE5Kz___fn=(lambda e: + ... (lambda * _: _)( + ... 'operator..itemgetter', + ... ('slicer{}').format( + ... __import__('hissp').demunge( + ... e)))): + ... (__import__('builtins').setattr( + ... _QzAW22OE5Kz___fn, + ... '__qualname__', + ... ('.').join( + ... ('_macro_', + ... 'SQzHASH_',))), + ... __import__('builtins').setattr( + ... __import__('operator').getitem( + ... __import__('builtins').globals(), + ... '_macro_'), + ... 'SQzHASH_', + ... _QzAW22OE5Kz___fn)) [-1])() .. code-block:: REPL @@ -3233,26 +3395,27 @@ Putting that all together we get #.. (hissp..demunge e)))) >>> # defmacro ... # hissp.macros.._macro_.let - ... (lambda _QzAW22OE5Kz_fn=(lambda e: - ... (lambda * _: _)( - ... 'operator..itemgetter', - ... ('({}[{})').format( - ... __import__('hissp').readerless( - ... '__main__..slicer'), - ... __import__('hissp').demunge( - ... e)))):( - ... __import__('builtins').setattr( - ... _QzAW22OE5Kz_fn, - ... '__qualname__', - ... ('.').join( - ... ('_macro_', - ... 'QzLSQB_QzHASH_',))), - ... __import__('builtins').setattr( - ... __import__('operator').getitem( - ... __import__('builtins').globals(), - ... '_macro_'), - ... 'QzLSQB_QzHASH_', - ... _QzAW22OE5Kz_fn))[-1])() + ... ( + ... lambda _QzAW22OE5Kz___fn=(lambda e: + ... (lambda * _: _)( + ... 'operator..itemgetter', + ... ('({}[{})').format( + ... __import__('hissp').readerless( + ... '__main__..slicer'), + ... __import__('hissp').demunge( + ... e)))): + ... (__import__('builtins').setattr( + ... _QzAW22OE5Kz___fn, + ... '__qualname__', + ... ('.').join( + ... ('_macro_', + ... 'QzLSQB_QzHASH_',))), + ... __import__('builtins').setattr( + ... __import__('operator').getitem( + ... __import__('builtins').globals(), + ... '_macro_'), + ... 'QzLSQB_QzHASH_', + ... _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 @@ -3281,7 +3444,7 @@ Now look at what we can do. ... __import__('operator').itemgetter( ... (__import__('builtins').globals()['slicer'][0]))( ... # QzAT_ - ... (lambda *xs:[*xs])( + ... (lambda *xs: [*xs])( ... ('abc')))) 'cba' @@ -3371,7 +3534,7 @@ Compare. 'geca' #> ((lambda a |a[-1::-2]|) "abcdefg") - >>> (lambda a:a[-1::-2])( + >>> (lambda a: a[-1::-2])( ... ('abcdefg')) 'geca' @@ -3393,7 +3556,7 @@ The lambda object, on the other hand, is opaque. .. code-block:: REPL #> (lambda a |a[-1::-2]|) - >>> (lambda a:a[-1::-2]) + >>> (lambda a: a[-1::-2]) at 0x...> But if we can eliminate the ``Slicer`` class altogether, @@ -3408,26 +3571,27 @@ Our previous macro was almost there. #.. `(lambda ,'a ,(.format "({}[{})" 'a (hissp..demunge e)))) >>> # defmacro ... # hissp.macros.._macro_.let - ... (lambda _QzAW22OE5Kz_fn=(lambda e: - ... (lambda * _: _)( - ... 'lambda', - ... 'a', - ... ('({}[{})').format( - ... 'a', - ... __import__('hissp').demunge( - ... e)))):( - ... __import__('builtins').setattr( - ... _QzAW22OE5Kz_fn, - ... '__qualname__', - ... ('.').join( - ... ('_macro_', - ... 'QzLSQB_QzHASH_',))), - ... __import__('builtins').setattr( - ... __import__('operator').getitem( - ... __import__('builtins').globals(), - ... '_macro_'), - ... 'QzLSQB_QzHASH_', - ... _QzAW22OE5Kz_fn))[-1])() + ... ( + ... lambda _QzAW22OE5Kz___fn=(lambda e: + ... (lambda * _: _)( + ... 'lambda', + ... 'a', + ... ('({}[{})').format( + ... 'a', + ... __import__('hissp').demunge( + ... e)))): + ... (__import__('builtins').setattr( + ... _QzAW22OE5Kz___fn, + ... '__qualname__', + ... ('.').join( + ... ('_macro_', + ... 'QzLSQB_QzHASH_',))), + ... __import__('builtins').setattr( + ... __import__('operator').getitem( + ... __import__('builtins').globals(), + ... '_macro_'), + ... 'QzLSQB_QzHASH_', + ... _QzAW22OE5Kz___fn)) [-1])() It works. @@ -3439,7 +3603,7 @@ It works. ('lambda', 'a', '(a[-1::-2])') #> ([#-1::-2] "abcdefg") - >>> (lambda a:(a[-1::-2]))( + >>> (lambda a: (a[-1::-2]))( ... ('abcdefg')) 'geca' @@ -3448,7 +3612,7 @@ Maybe even better than expected. .. code-block:: REPL #> ([#1][1] '(foo bar)) - >>> (lambda a:(a[1][1]))( + >>> (lambda a: (a[1][1]))( ... ('foo', ... 'bar',)) 'a' @@ -3467,8 +3631,8 @@ but there's a subtle flaw which is reason enough not to follow through with that #.. ([#a::-2] "abcdefg")) >>> # let ... (lambda a=(-1): - ... (lambda a:(a[a::-2]))( - ... ('abcdefg')))() + ... (lambda a: (a[a::-2]))( + ... ('abcdefg')))() Traceback (most recent call last): ... TypeError: slice indices must be integers or None or have an __index__ method @@ -3481,8 +3645,8 @@ Yet it works fine with ``b``. #.. ([#b::-2] "abcdefg")) >>> # let ... (lambda b=(-1): - ... (lambda a:(a[b::-2]))( - ... ('abcdefg')))() + ... (lambda a: (a[b::-2]))( + ... ('abcdefg')))() 'geca' See the problem? @@ -3499,27 +3663,28 @@ 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 _QzAW22OE5Kz_fn=(lambda e: - ... (lambda * _: _)( - ... 'lambda', - ... (lambda * _: _)( - ... '_QzAVTK4YRWz_G'), - ... ('({}[{})').format( - ... '_QzAVTK4YRWz_G', - ... __import__('hissp').demunge( - ... e)))):( - ... __import__('builtins').setattr( - ... _QzAW22OE5Kz_fn, - ... '__qualname__', - ... ('.').join( - ... ('_macro_', - ... 'QzLSQB_QzHASH_',))), - ... __import__('builtins').setattr( - ... __import__('operator').getitem( - ... __import__('builtins').globals(), - ... '_macro_'), - ... 'QzLSQB_QzHASH_', - ... _QzAW22OE5Kz_fn))[-1])() + ... ( + ... lambda _QzAW22OE5Kz___fn=(lambda e: + ... (lambda * _: _)( + ... 'lambda', + ... (lambda * _: _)( + ... '_QzAVTK4YRWz___G'), + ... ('({}[{})').format( + ... '_QzAVTK4YRWz___G', + ... __import__('hissp').demunge( + ... e)))): + ... (__import__('builtins').setattr( + ... _QzAW22OE5Kz___fn, + ... '__qualname__', + ... ('.').join( + ... ('_macro_', + ... 'QzLSQB_QzHASH_',))), + ... __import__('builtins').setattr( + ... __import__('operator').getitem( + ... __import__('builtins').globals(), + ... '_macro_'), + ... 'QzLSQB_QzHASH_', + ... _QzAW22OE5Kz___fn)) [-1])() Read this carefully. ``$#`` only works inside of templates, @@ -3539,7 +3704,7 @@ It works. .. code-block:: REPL #> ([#-1::-2] "abcdefg") - >>> (lambda _QzAVTK4YRWz_G:(_QzAVTK4YRWz_G[-1::-2]))( + >>> (lambda _QzAVTK4YRWz___G: (_QzAVTK4YRWz___G[-1::-2]))( ... ('abcdefg')) 'geca' diff --git a/docs/primer.rst b/docs/primer.rst index 4341b5d10..5aa1a423a 100644 --- a/docs/primer.rst +++ b/docs/primer.rst @@ -92,9 +92,9 @@ and returns its Python translation as a string. >>> python_translation = readerless(hissp_program) >>> print(python_translation) (lambda name: - print( - 'Hello', - name)) + print( + 'Hello', + name)) Python can then run this program as normal. @@ -147,12 +147,16 @@ Let's use it. ... ('lambda',('name') ... ,('print',q('Hello'),'name',),) ... ) -"(lambda n,a,m,e:\n print(\n 'Hello',\n name))" +"(\n lambda n,\n a,\n m,\n e:\n print(\n 'Hello',\n name))" >>> print(_) # Remember, _ is the last result that wasn't None. -(lambda n,a,m,e: - print( - 'Hello', - name)) +( + lambda n, + a, + m, + e: + print( + 'Hello', + name)) >>> eval(_)('World') Traceback (most recent call last): File "", line 1, in @@ -187,12 +191,12 @@ with the comma this time. ... ('lambda',('name',) ... ,('print',q('Hello'),'name',),) ... ) -"(lambda name:\n print(\n 'Hello',\n name))" +"(lambda name:\n print(\n 'Hello',\n name))" >>> print(_) (lambda name: - print( - 'Hello', - name)) + print( + 'Hello', + name)) That's better. @@ -310,9 +314,9 @@ Here's our first Hissp program again written that way: #> (|lambda| (|name|) #.. (|print| (|quote| |Hello|) |name|)) >>> (lambda name: - ... print( - ... 'Hello', - ... name)) + ... print( + ... 'Hello', + ... name)) at 0x...> #> (|_| (|quote| |World|)) @@ -744,7 +748,18 @@ Hissp can represent all of Python's parameter types this way. #.. j 1 ; another kwonly parameter with a default value #.. :** kwargs) ; packs keyword args into a dict #.. 42) - >>> (lambda a,/,b,e=(1),f=(2),*args,h=(4),i,j=(1),**kwargs:(42)) + >>> ( + ... lambda a, + ... /, + ... b, + ... e=(1), + ... f=(2), + ... *args, + ... h=(4), + ... i, + ... j=(1), + ... **kwargs: + ... (42)) at ...> The parameter name goes on the left of the pairs, and the default goes on the right. @@ -780,7 +795,18 @@ of a pair with a ``:?``. #.. :* args h 4 i :? j 1 ; kwonly #.. :** kwargs) #.. 42) - >>> (lambda a,/,b,e=(1),f=(2),*args,h=(4),i,j=(1),**kwargs:(42)) + >>> ( + ... lambda a, + ... /, + ... b, + ... e=(1), + ... f=(2), + ... *args, + ... h=(4), + ... i, + ... j=(1), + ... **kwargs: + ... (42)) at ...> Each element before the ``:`` is implicitly paired with @@ -799,12 +825,14 @@ respectively: #.. (print args) #.. (print kwargs) ; Body expressions evaluate in order. #.. 42) ; The last value is returned. - >>> (lambda *args,**kwargs:( - ... print( - ... args), - ... print( - ... kwargs), - ... (42))[-1]) + >>> ( + ... lambda *args, + ... **kwargs: + ... (print( + ... args), + ... print( + ... kwargs), + ... (42)) [-1]) at ...> #> (_ 1 : b :c) @@ -823,7 +851,13 @@ in which case an empty tuple is implied: .. code-block:: REPL #> (lambda (: a 1 :/ :? :* :? b :? c 2)) - >>> (lambda a=(1),/,*,b,c=(2):()) + >>> ( + ... lambda a=(1), + ... /, + ... *, + ... b, + ... c=(2): + ... ()) at ...> Positional-only parameters with defaults must appear after the ``:``, @@ -839,23 +873,31 @@ Not having it is the same as putting it last: .. code-block:: REPL #> (lambda (a b c :)) ; No pairs after ':'. - >>> (lambda a,b,c:()) + >>> ( + ... lambda a, + ... b, + ... c: + ... ()) at ...> #> (lambda (a b c)) ; The ':' was omitted. - >>> (lambda a,b,c:()) + >>> ( + ... lambda a, + ... b, + ... c: + ... ()) at ...> #> (lambda (:)) ; Colon isn't doing anything. - >>> (lambda :()) + >>> (lambda : ()) at ...> #> (lambda ()) ; You can omit it. - >>> (lambda :()) + >>> (lambda : ()) at ...> #> (lambda :) ; This also works (guess why), and is idiomatic in Lissp. - >>> (lambda :()) + >>> (lambda : ()) at ...> The ``:`` is required if there are any explicit pairs, @@ -864,7 +906,7 @@ even if there are no ``:?`` pairs: .. code-block:: REPL #> (lambda (: :** kwargs)) - >>> (lambda **kwargs:()) + >>> (lambda **kwargs: ()) at ...> Calls @@ -1545,7 +1587,7 @@ The template quote works much like a normal quote: (1, 2, 3) #> `(1 2 3) ; template quote - >>> (lambda * _: _)( + >>> (lambda * _: _)( ... (1), ... (2), ... (3)) @@ -1570,7 +1612,7 @@ much like a format string: (1, 2, ('operator..add', 1, 2)) #> `(1 2 ,(operator..add 1 2)) ; template and unquote - >>> (lambda * _: _)( + >>> (lambda * _: _)( ... (1), ... (2), ... __import__('operator').add( @@ -1583,7 +1625,7 @@ The splice unquote is similar, but unpacks its result: .. code-block:: REPL #> `(:a ,@"bcd" :e) - >>> (lambda * _: _)( + >>> (lambda * _: _)( ... ':a', ... *('bcd'), ... ':e') @@ -1623,9 +1665,9 @@ then it's easier to read. ... ,':*',"('bcd')" ... ,':?',('operator..mul', 2, 3,),) ... ) -"(lambda * _: _)(\n ':a',\n *('bcd'),\n __import__('operator').mul(\n (2),\n (3)))" +"(lambda * _: _)(\n ':a',\n *('bcd'),\n __import__('operator').mul(\n (2),\n (3)))" >>> print(_) -(lambda * _: _)( +(lambda * _: _)( ':a', *('bcd'), __import__('operator').mul( @@ -1656,20 +1698,20 @@ Within a template, the same gensym name always makes the same gensym: .. code-block:: REPL #> `($#hiss $#hiss) - >>> (lambda * _: _)( - ... '_QzTAMTDLDRz_hiss', - ... '_QzTAMTDLDRz_hiss') - ('_QzTAMTDLDRz_hiss', '_QzTAMTDLDRz_hiss') + >>> (lambda * _: _)( + ... '_QzTAMTDLDRz___hiss', + ... '_QzTAMTDLDRz___hiss') + ('_QzTAMTDLDRz___hiss', '_QzTAMTDLDRz___hiss') But each new template changes the prefix hash. .. code-block:: REPL #> `($#hiss $#hiss) - >>> (lambda * _: _)( - ... '_QzZSOXD2IOz_hiss', - ... '_QzZSOXD2IOz_hiss') - ('_QzZSOXD2IOz_hiss', '_QzZSOXD2IOz_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. @@ -1762,9 +1804,9 @@ Let's try it: ... _macro_, ... 'hello', ... (lambda : - ... ('print', - ... ('quote', - ... 'hello',),))) + ... ('print', + ... ('quote', + ... 'hello',),))) #> (hello) >>> # hello @@ -1783,12 +1825,12 @@ Let's give it one. Use a template: ... _macro_, ... 'greet', ... (lambda name: - ... (lambda * _: _)( - ... 'builtins..print', - ... (lambda * _: _)( - ... 'quote', - ... '__main__..Hello'), - ... name))) + ... (lambda * _: _)( + ... 'builtins..print', + ... (lambda * _: _)( + ... 'quote', + ... '__main__..Hello'), + ... name))) #> (greet 'Bob) >>> # greet @@ -1810,7 +1852,7 @@ with `builtins` (if applicable) or the current ``__name__`` 'builtins..int' #> `(int spam) - >>> (lambda * _: _)( + >>> (lambda * _: _)( ... 'builtins..int', ... '__main__..spam') ('builtins..int', '__main__..spam') @@ -1837,8 +1879,8 @@ If the gensym hash is *not* in prefix position, it doesn't count as local, and g .. code-block:: REPL #> `$#spam.$eggs - >>> '__main__..spam._Qz6AE4GUT3z_eggs' - '__main__..spam._Qz6AE4GUT3z_eggs' + >>> '__main__..spam._Qz6AE4GUT3z___eggs' + '__main__..spam._Qz6AE4GUT3z___eggs' A ``_macro_`` namespace is not the same as its module. @@ -1849,14 +1891,14 @@ A ``_macro_`` namespace is not the same as its module. ... _macro_, ... 'p123', ... (lambda : - ... (lambda * _: _)( - ... '__main__..QzMaybe_.p', - ... (1), - ... (2), - ... (3), - ... ':', - ... '__main__..sep', - ... ':'))) + ... (lambda * _: _)( + ... '__main__..QzMaybe_.p', + ... (1), + ... (2), + ... (3), + ... ':', + ... '__main__..sep', + ... ':'))) Notice the ``QzMaybe_`` qualifying ``p``, which means the reader could not determine if ``p`` should be qualified as a global or as a macro, @@ -1904,9 +1946,9 @@ We can resolve the ``QzMaybe_`` the other way by defining a ``p`` macro. ... _macro_, ... 'p', ... (lambda *args: - ... (lambda * _: _)( - ... 'builtins..print', - ... *args))) + ... (lambda * _: _)( + ... 'builtins..print', + ... *args))) #> (p123) >>> # p123 @@ -1929,13 +1971,13 @@ symbol. (Like a quoted symbol): .. code-block:: REPL #> `(float inf) - >>> (lambda * _: _)( + >>> (lambda * _: _)( ... 'builtins..float', ... '__main__..inf') ('builtins..float', '__main__..inf') #> `(float ,'inf) - >>> (lambda * _: _)( + >>> (lambda * _: _)( ... 'builtins..float', ... 'inf') ('builtins..float', 'inf') @@ -1950,12 +1992,12 @@ Note the three reader macros in a row: ``','``. ... _macro_, ... 'greet', ... (lambda name: - ... (lambda * _: _)( - ... 'builtins..print', - ... (lambda * _: _)( - ... 'quote', - ... 'Hello'), - ... name))) + ... (lambda * _: _)( + ... 'builtins..print', + ... (lambda * _: _)( + ... 'quote', + ... 'Hello'), + ... name))) #> (greet 'Bob) >>> # greet @@ -1975,10 +2017,10 @@ a "" token might have been a better idea: ... _macro_, ... 'greet', ... (lambda name: - ... (lambda * _: _)( - ... 'builtins..print', - ... "('Hello')", - ... name))) + ... (lambda * _: _)( + ... 'builtins..print', + ... "('Hello')", + ... name))) #> (greet 'Bob) >>> # greet @@ -2003,27 +2045,27 @@ But there are times when a function will not do: ... _macro_, ... 'QzPCENT_', ... (lambda *body: - ... (lambda * _: _)( - ... 'lambda', - ... (lambda * _: _)( - ... 'QzPCENT_'), - ... body))) + ... (lambda * _: _)( + ... 'lambda', + ... (lambda * _: _)( + ... 'QzPCENT_'), + ... body))) #> ((lambda (%) #.. (print (.upper %))) ;This lambda expression #.. "q") >>> (lambda QzPCENT_: - ... print( - ... QzPCENT_.upper()))( + ... print( + ... QzPCENT_.upper()))( ... ('q')) Q #> ((% print (.upper %)) ; can now be abbreviated. - ... "q") + #.. "q") >>> # QzPCENT_ ... (lambda QzPCENT_: - ... print( - ... QzPCENT_.upper()))( + ... print( + ... QzPCENT_.upper()))( ... ('q')) Q @@ -2033,10 +2075,10 @@ But there are times when a function will not do: ... map( ... # QzPCENT_ ... (lambda QzPCENT_: - ... print( - ... QzPCENT_.upper(), - ... (':'), - ... QzPCENT_)), + ... print( + ... QzPCENT_.upper(), + ... (':'), + ... QzPCENT_)), ... ('abc'))) A : a B : b diff --git a/src/hissp/compiler.py b/src/hissp/compiler.py index cdd8036e1..897896cef 100644 --- a/src/hissp/compiler.py +++ b/src/hissp/compiler.py @@ -28,6 +28,8 @@ MACRO = f"..{MACROS}." MAYBE = "..QzMaybe_." RE_MACRO = re.compile(rf"({re.escape(MACRO)}|{re.escape(MAYBE)})") +_PARAM_INDENT = f"\n{len('(lambda ')*' '}" +_BODY_INDENT = f"\n{4*' '}" NS = ContextVar("NS", default=None) """ @@ -201,14 +203,26 @@ def function(self, form: Tuple) -> str: Parameter types are the same as Python's. For example, - >>> readerless( + >>> print(readerless( ... ('lambda', ('a',':/','b' ... ,':', 'e',1, 'f',2 ... ,':*','args', 'h',4, 'i',':?', 'j',1 ... ,':**','kwargs',) ... ,42,) - ... ) - '(lambda a,/,b,e=(1),f=(2),*args,h=(4),i,j=(1),**kwargs:(42))' + ... )) + ( + lambda a, + /, + b, + e=(1), + f=(2), + *args, + h=(4), + i, + j=(1), + **kwargs: + (42)) + The special control words ``:*`` and ``:**`` designate the remainder of the positional and keyword parameters, respectively. @@ -220,42 +234,62 @@ def function(self, form: Tuple) -> str: ... ,('print','args',) ... ,('print','kwargs',),) ... )) - (lambda *args,**kwargs:( - print( - args), - print( - kwargs))[-1]) + ( + lambda *args, + **kwargs: + (print( + args), + print( + kwargs)) [-1]) You can omit the right of a pair with ``:?`` (except the final ``**kwargs``). Also note that the body can be empty. - >>> readerless( + >>> print(readerless( ... ('lambda', (':','a',1, ':/',':?', ':*',':?', 'b',':?', 'c',2,),), - ... ) - '(lambda a=(1),/,*,b,c=(2):())' + ... )) + ( + lambda a=(1), + /, + *, + b, + c=(2): + ()) The ``:`` may be omitted if there are no paired parameters. - >>> readerless(('lambda', ('a','b','c',':',),),) - '(lambda a,b,c:())' - >>> readerless(('lambda', ('a','b','c',),),) - '(lambda a,b,c:())' + >>> print(readerless(('lambda', ('a','b','c',':',),),)) + ( + lambda a, + b, + c: + ()) + >>> print(readerless(('lambda', ('a','b','c',),),)) + ( + lambda a, + b, + c: + ()) >>> readerless(('lambda', (':',),),) - '(lambda :())' + '(lambda : ())' >>> readerless(('lambda', (),),) - '(lambda :())' + '(lambda : ())' The ``:`` is required if there are any pair parameters, even if there are no single parameters: >>> readerless(('lambda', (':',':**','kwargs',),),) - '(lambda **kwargs:())' + '(lambda **kwargs: ())' """ fn, parameters, *body = form assert fn == "lambda" - return f"(lambda {self.parameters(parameters)}:{self.body(body)})" + parameters, body = self.parameters(parameters), self.body(body) + param_has_nl = "\n" in parameters + drop = param_has_nl * "\n " + sep = ("\n" in body or param_has_nl) * f"\n{3 * ' '}" + return f"({drop}lambda {parameters}:{sep}{body})" @_trace def parameters(self, parameters: Iterable) -> str: @@ -276,17 +310,16 @@ def parameters(self, parameters: Iterable) -> str: r.append(k) else: r.append(f"{k}={self.form(v)}") - return ",".join(r) + return ",\n".join(r).replace("\n", _PARAM_INDENT) @_trace def body(self, body: list) -> str: """Compile body of `function`.""" + body = tuple(map(self.form, body)) if len(body) > 1: - return f"({_join_args(*map(self.form, body))})[-1]" - if not body: - return "()" - result = self.form(body[0]) - return ("\n" * ("\n" in result) + result).replace("\n", "\n ") + result = ",\n".join(body).replace("\n", _BODY_INDENT) + return f"({result}) [-1]" + return f" {body and body[0]}".replace("\n", _BODY_INDENT) @_trace def invocation(self, form: Tuple) -> str: diff --git a/src/hissp/macros.lissp b/src/hissp/macros.lissp index e5f7feb66..3f982caa6 100644 --- a/src/hissp/macros.lissp +++ b/src/hissp/macros.lissp @@ -108,17 +108,21 @@ Hidden doctest adds bundled macros for REPL-consistent behavior. ... __import__('builtins').any( ... __import__('builtins').map( ... (lambda c: - ... # ifQz_else - ... (lambda b,c,a:c()if b else a())( - ... __import__('operator').eq( - ... c, - ... 'b'), - ... (lambda : - ... print( - ... 'Yes')), - ... (lambda : - ... print( - ... 'No')))), + ... # ifQz_else + ... ( + ... lambda b, + ... c, + ... a: + ... c()if b else a())( + ... __import__('operator').eq( + ... c, + ... 'b'), + ... (lambda : + ... print( + ... 'Yes')), + ... (lambda : + ... print( + ... 'No')))), ... 'ab')) No Yes @@ -142,12 +146,12 @@ Hidden doctest adds bundled macros for REPL-consistent behavior. #.. 3)) >>> print( ... # progn - ... (lambda :( - ... print( - ... (1)), - ... print( - ... (2)), - ... (3))[-1])()) + ... (lambda : + ... (print( + ... (1)), + ... print( + ... (2)), + ... (3)) [-1])()) 1 2 3 @@ -174,18 +178,21 @@ Hidden doctest adds bundled macros for REPL-consistent behavior. >>> # anyQz_map ... __import__('builtins').any( ... __import__('builtins').map( - ... (lambda c:( - ... print( - ... c), - ... # when - ... (lambda b,c:c()if b else())( - ... __import__('operator').eq( - ... c, - ... 'b'), - ... (lambda :( - ... print( - ... 'found'), - ... ':break')[-1])))[-1]), + ... (lambda c: + ... (print( + ... c), + ... # when + ... ( + ... lambda b, + ... c: + ... c()if b else())( + ... __import__('operator').eq( + ... c, + ... 'b'), + ... (lambda : + ... (print( + ... 'found'), + ... ':break') [-1]))) [-1]), ... 'abcd')) a b @@ -212,14 +219,17 @@ Hidden doctest adds bundled macros for REPL-consistent behavior. ... __import__('builtins').any( ... __import__('builtins').map( ... (lambda c: - ... # unless - ... (lambda b,a:()if b else a())( - ... __import__('operator').eq( - ... c, - ... 'b'), - ... (lambda : - ... print( - ... c)))), + ... # unless + ... ( + ... lambda b, + ... a: + ... ()if b else a())( + ... __import__('operator').eq( + ... c, + ... 'b'), + ... (lambda : + ... print( + ... c)))), ... 'abcd')) a c @@ -246,20 +256,24 @@ Hidden doctest adds bundled macros for REPL-consistent behavior. #.. (print x y)) ;Outer variables shadowed. #.. (print x y)) ;Inner went out of scope. >>> # let - ... (lambda x='a',y='b':( - ... print( - ... x, - ... y), - ... # let - ... (lambda x='x',y=__import__('operator').concat( - ... x, - ... x): + ... ( + ... lambda x='a', + ... y='b': + ... (print( + ... x, + ... y), + ... # let + ... ( + ... lambda x='x', + ... y=__import__('operator').concat( + ... x, + ... x): + ... print( + ... x, + ... y))(), ... print( ... x, - ... y))(), - ... print( - ... x, - ... y))[-1])() + ... y)) [-1])() a b x aa a b @@ -291,32 +305,33 @@ Hidden doctest adds bundled macros for REPL-consistent behavior. #.. `(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])() + ... ( + ... 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 @@ -404,15 +419,18 @@ Hidden doctest adds bundled macros for REPL-consistent behavior. #> (defonce CACHE (types..SimpleNamespace : x 1)) >>> # defonce ... # hissp.macros.._macro_.unless - ... (lambda b,a:()if b else a())( + ... ( + ... lambda b, + ... a: + ... ()if b else a())( ... __import__('operator').contains( ... __import__('builtins').globals(), ... 'CACHE'), ... (lambda : - ... # hissp.macros.._macro_.define - ... __import__('builtins').globals().update( - ... CACHE=__import__('types').SimpleNamespace( - ... x=(1))))) + ... # hissp.macros.._macro_.define + ... __import__('builtins').globals().update( + ... CACHE=__import__('types').SimpleNamespace( + ... x=(1))))) #> (setattr CACHE 'x 42) >>> setattr( @@ -424,20 +442,23 @@ Hidden doctest adds bundled macros for REPL-consistent behavior. #.. (types..SimpleNamespace : x 1))) >>> # defonce ... # hissp.macros.._macro_.unless - ... (lambda b,a:()if b else a())( + ... ( + ... lambda b, + ... a: + ... ()if b else a())( ... __import__('operator').contains( ... __import__('builtins').globals(), ... 'CACHE'), ... (lambda : - ... # hissp.macros.._macro_.define - ... __import__('builtins').globals().update( - ... CACHE=# progn - ... (lambda :( - ... print( - ... 'not', - ... 'evaluated'), - ... __import__('types').SimpleNamespace( - ... x=(1)))[-1])()))) + ... # hissp.macros.._macro_.define + ... __import__('builtins').globals().update( + ... CACHE=# progn + ... (lambda : + ... (print( + ... 'not', + ... 'evaluated'), + ... __import__('types').SimpleNamespace( + ... x=(1))) [-1])()))) () #> CACHE ; The second defonce had no effect. @@ -467,19 +488,22 @@ Hidden doctest adds bundled macros for REPL-consistent behavior. ;; ... __import__('builtins').globals().update( ;; ... Point2D=__import__('builtins').type( ;; ... 'Point2D', - ;; ... (lambda * _: _)( + ;; ... (lambda * _: _)( ;; ... tuple), ;; ... __import__('builtins').dict( ;; ... __doc__=('Simple ordered pair.'), - ;; ... __new__=(lambda cls,x,y: - ;; ... tuple.__new__( - ;; ... cls, - ;; ... (lambda * _: _)( - ;; ... x, - ;; ... y))), + ;; ... __new__=( + ;; ... lambda cls, + ;; ... x, + ;; ... y: + ;; ... tuple.__new__( + ;; ... cls, + ;; ... (lambda * _: _)( + ;; ... x, + ;; ... y))), ;; ... __repr__=(lambda self: - ;; ... ('Point2D({!r}, {!r})').format( - ;; ... *self))))) + ;; ... ('Point2D({!r}, {!r})').format( + ;; ... *self))))) ;; ;; #> (Point2D 1 2) ;; >>> Point2D( @@ -500,11 +524,14 @@ Hidden doctest adds bundled macros for REPL-consistent behavior. ;; ... __import__('builtins').globals().update( ;; ... Foo=__import__('builtins').type( ;; ... 'Foo', - ;; ... (lambda * _: _)(), + ;; ... (lambda * _: _)(), ;; ... __import__('builtins').dict( - ;; ... __init_subclass__=(lambda cls,/,**kwargs: - ;; ... print( - ;; ... kwargs))))) + ;; ... __init_subclass__=( + ;; ... lambda cls, + ;; ... /, + ;; ... **kwargs: + ;; ... print( + ;; ... kwargs))))) ;; ;; #> (deftype Bar (Foo : a 1 b 2)) ;; >>> # deftype @@ -512,7 +539,7 @@ Hidden doctest adds bundled macros for REPL-consistent behavior. ;; ... __import__('builtins').globals().update( ;; ... Bar=__import__('builtins').type( ;; ... 'Bar', - ;; ... (lambda * _: _)( + ;; ... (lambda * _: _)( ;; ... Foo), ;; ... __import__('builtins').dict(), ;; ... a=(1), @@ -542,11 +569,14 @@ Hidden doctest adds bundled macros for REPL-consistent behavior. #> (let-from (a b : :* cs) 'ABCDEFG #.. (print cs b a)) >>> # letQz_from - ... (lambda a,b,*cs: - ... print( - ... cs, - ... b, - ... a))( + ... ( + ... lambda a, + ... b, + ... *cs: + ... print( + ... cs, + ... b, + ... a))( ... *'ABCDEFG') ('C', 'D', 'E', 'F', 'G') B A @@ -575,23 +605,29 @@ Hidden doctest adds bundled macros for REPL-consistent behavior. #.. (print a b c d)) >>> # letQzSTAR_from ... # hissp.macros.._macro_.letQz_from - ... (lambda ab,cd: - ... # hissp.macros..QzMaybe_.letQzSTAR_from - ... # hissp.macros.._macro_.letQz_from - ... (lambda a,b: + ... ( + ... lambda ab, + ... cd: ... # hissp.macros..QzMaybe_.letQzSTAR_from ... # hissp.macros.._macro_.letQz_from - ... (lambda c,d: - ... # hissp.macros..QzMaybe_.letQzSTAR_from - ... # hissp.macros.._macro_.progn - ... (lambda : - ... print( - ... a, - ... b, - ... c, - ... d))())( - ... *cd))( - ... *ab))( + ... ( + ... lambda a, + ... b: + ... # hissp.macros..QzMaybe_.letQzSTAR_from + ... # hissp.macros.._macro_.letQz_from + ... ( + ... lambda c, + ... d: + ... # hissp.macros..QzMaybe_.letQzSTAR_from + ... # hissp.macros.._macro_.progn + ... (lambda : + ... print( + ... a, + ... b, + ... c, + ... d))())( + ... *cd))( + ... *ab))( ... *_.items()) A B C D @@ -601,21 +637,27 @@ Hidden doctest adds bundled macros for REPL-consistent behavior. #.. (print a b c d)) >>> # letQzSTAR_from ... # hissp.macros.._macro_.letQz_from - ... (lambda ab,cd: - ... # hissp.macros..QzMaybe_.letQzSTAR_from - ... # hissp.macros.._macro_.letQz_from - ... (lambda a,b,c,d: + ... ( + ... lambda ab, + ... cd: ... # hissp.macros..QzMaybe_.letQzSTAR_from - ... # hissp.macros.._macro_.progn - ... (lambda : - ... print( - ... a, - ... b, - ... c, - ... d))())( - ... *(lambda * _: _)( - ... *ab, - ... *cd)))( + ... # hissp.macros.._macro_.letQz_from + ... ( + ... lambda a, + ... b, + ... c, + ... d: + ... # hissp.macros..QzMaybe_.letQzSTAR_from + ... # hissp.macros.._macro_.progn + ... (lambda : + ... print( + ... a, + ... b, + ... c, + ... d))())( + ... *(lambda * _: _)( + ... *ab, + ... *cd)))( ... *_.items()) A B C D @@ -624,13 +666,17 @@ Hidden doctest adds bundled macros for REPL-consistent behavior. #.. `(,@(.keys _) ,@(.values _)) ; Not always this easy. #.. (print a b c d)) >>> # letQz_from - ... (lambda a,c,b,d: - ... print( - ... a, - ... b, - ... c, - ... d))( - ... *(lambda * _: _)( + ... ( + ... lambda a, + ... c, + ... b, + ... d: + ... print( + ... a, + ... b, + ... c, + ... d))( + ... *(lambda * _: _)( ... *_.keys(), ... *_.values())) A B C D @@ -656,18 +702,19 @@ Hidden doctest adds bundled macros for REPL-consistent behavior. #.. my.x) >>> # hissp.macros.._macro_.let ... (lambda my=__import__('types').SimpleNamespace(): - ... print( - ... # setQzAT_ - ... # hissp.macros.._macro_.let - ... (lambda _QzRMG5GSSIz_val=__import__('operator').add( - ... (1), - ... (1)):( - ... __import__('builtins').setattr( - ... my, - ... 'x', - ... _QzRMG5GSSIz_val), - ... _QzRMG5GSSIz_val)[-1])(), - ... my.x))() + ... print( + ... # setQzAT_ + ... # hissp.macros.._macro_.let + ... ( + ... lambda _QzRMG5GSSIz___val=__import__('operator').add( + ... (1), + ... (1)): + ... (__import__('builtins').setattr( + ... my, + ... 'x', + ... _QzRMG5GSSIz___val), + ... _QzRMG5GSSIz___val) [-1])(), + ... my.x))() 2 2 ``my#my`` is a shorthand for a new empty namespace. @@ -704,9 +751,9 @@ Hidden doctest adds bundled macros for REPL-consistent behavior. ;; >>> list( ;; ... map( ;; ... (lambda X: - ;; ... # QzAT_ - ;; ... (lambda *xs:[*xs])( - ;; ... X)), + ;; ... # QzAT_ + ;; ... (lambda *xs: [*xs])( + ;; ... X)), ;; ... ('abc'))) ;; [['a'], ['b'], ['c']] ;; @@ -717,7 +764,7 @@ Hidden doctest adds bundled macros for REPL-consistent behavior. ;; #> (define teen? X#|13<=X<20|) ;; >>> # define ;; ... __import__('builtins').globals().update( - ;; ... teenQzQUERY_=(lambda X:13<=X<20)) + ;; ... teenQzQUERY_=(lambda X: 13<=X<20)) ;; ;; #> (teen? 12.5) ;; >>> teenQzQUERY_( @@ -734,7 +781,7 @@ Hidden doctest adds bundled macros for REPL-consistent behavior. ;; .. code-block:: REPL ;; ;; #> (X#X.upper "shout") - ;; >>> (lambda X:X.upper)( + ;; >>> (lambda X: X.upper)( ;; ... ('shout')) ;; ;; @@ -745,7 +792,7 @@ Hidden doctest adds bundled macros for REPL-consistent behavior. ;; #> (define class-name X#X.__class__.__name__) ; Attributes chain. ;; >>> # define ;; ... __import__('builtins').globals().update( - ;; ... classQz_name=(lambda X:X.__class__.__name__)) + ;; ... classQz_name=(lambda X: X.__class__.__name__)) ;; ;; #> (class-name object) ;; >>> classQz_name( @@ -770,10 +817,12 @@ Hidden doctest adds bundled macros for REPL-consistent behavior. #> (functools..reduce XY#(op#concat Y X) 'abcd) >>> __import__('functools').reduce( - ... (lambda X,Y: - ... __import__('operator').concat( - ... Y, - ... X)), + ... ( + ... lambda X, + ... Y: + ... __import__('operator').concat( + ... Y, + ... X)), ... 'abcd') 'dcba' @@ -788,7 +837,11 @@ Hidden doctest adds bundled macros for REPL-consistent behavior. ;; .. code-block:: REPL ;; ;; #> (XYZ#|X*Y == Z| : X math..pi Y 2 Z math..tau) - ;; >>> (lambda X,Y,Z:X*Y == Z)( + ;; >>> ( + ;; ... lambda X, + ;; ... Y, + ;; ... Z: + ;; ... X*Y == Z)( ;; ... X=__import__('math').pi, ;; ... Y=(2), ;; ... Z=__import__('math').tau) @@ -805,7 +858,12 @@ Hidden doctest adds bundled macros for REPL-consistent behavior. ;; .. code-block:: REPL ;; ;; #> (XYZW#|X[Y:Z:W]| "QuaoblcldefHg" -2 1 -2) - ;; >>> (lambda X,Y,Z,W:X[Y:Z:W])( + ;; >>> ( + ;; ... lambda X, + ;; ... Y, + ;; ... Z, + ;; ... W: + ;; ... X[Y:Z:W])( ;; ... ('QuaoblcldefHg'), ;; ... (-2), ;; ... (1), @@ -826,39 +884,47 @@ Hidden doctest adds bundled macros for REPL-consistent behavior. ;; >>> # hissp.._macro_.alias ;; ... # hissp.macros.._macro_.defmacro ;; ... # hissp.macros.._macro_.let - ;; ... (lambda _Qz2D5FNHXZz_fn=(lambda _QzE4JATHEUz_attr,*_QzE4JATHEUz_args,**_QzE4JATHEUz_kwargs:( - ;; ... 'Aliases ``hissp.._macro_`` as ``HQzCOLON_#``.', - ;; ... # hissp.macros.._macro_.ifQz_else - ;; ... (lambda b,c,a:c()if b else a())( - ;; ... _QzE4JATHEUz_args, - ;; ... (lambda : - ;; ... __import__('builtins').getattr( - ;; ... __import__('hissp')._macro_, - ;; ... ('{}{}').format( - ;; ... _QzE4JATHEUz_attr, - ;; ... 'QzHASH_'))( - ;; ... *_QzE4JATHEUz_args, - ;; ... **_QzE4JATHEUz_kwargs)), - ;; ... (lambda : - ;; ... ('{}.{}').format( - ;; ... 'hissp.._macro_', - ;; ... _QzE4JATHEUz_attr))))[-1]):( - ;; ... __import__('builtins').setattr( - ;; ... _Qz2D5FNHXZz_fn, - ;; ... '__doc__', - ;; ... 'Aliases ``hissp.._macro_`` as ``HQzCOLON_#``.'), - ;; ... __import__('builtins').setattr( - ;; ... _Qz2D5FNHXZz_fn, - ;; ... '__qualname__', - ;; ... ('.').join( - ;; ... ('_macro_', - ;; ... 'HQzCOLON_QzHASH_',))), - ;; ... __import__('builtins').setattr( - ;; ... __import__('operator').getitem( - ;; ... __import__('builtins').globals(), - ;; ... '_macro_'), - ;; ... 'HQzCOLON_QzHASH_', - ;; ... _Qz2D5FNHXZz_fn))[-1])() + ;; ... ( + ;; ... lambda _Qz2D5FNHXZz___fn=( + ;; ... lambda _QzE4JATHEUz___attr, + ;; ... *_QzE4JATHEUz___args, + ;; ... **_QzE4JATHEUz___kwargs: + ;; ... ('Aliases ``hissp.._macro_`` as ``HQzCOLON_#``.', + ;; ... # hissp.macros.._macro_.ifQz_else + ;; ... ( + ;; ... lambda b, + ;; ... c, + ;; ... a: + ;; ... c()if b else a())( + ;; ... _QzE4JATHEUz___args, + ;; ... (lambda : + ;; ... __import__('builtins').getattr( + ;; ... __import__('hissp')._macro_, + ;; ... ('{}{}').format( + ;; ... _QzE4JATHEUz___attr, + ;; ... 'QzHASH_'))( + ;; ... *_QzE4JATHEUz___args, + ;; ... **_QzE4JATHEUz___kwargs)), + ;; ... (lambda : + ;; ... ('{}.{}').format( + ;; ... 'hissp.._macro_', + ;; ... _QzE4JATHEUz___attr)))) [-1]): + ;; ... (__import__('builtins').setattr( + ;; ... _Qz2D5FNHXZz___fn, + ;; ... '__doc__', + ;; ... 'Aliases ``hissp.._macro_`` as ``HQzCOLON_#``.'), + ;; ... __import__('builtins').setattr( + ;; ... _Qz2D5FNHXZz___fn, + ;; ... '__qualname__', + ;; ... ('.').join( + ;; ... ('_macro_', + ;; ... 'HQzCOLON_QzHASH_',))), + ;; ... __import__('builtins').setattr( + ;; ... __import__('operator').getitem( + ;; ... __import__('builtins').globals(), + ;; ... '_macro_'), + ;; ... 'HQzCOLON_QzHASH_', + ;; ... _Qz2D5FNHXZz___fn)) [-1])() ;; ;; #> 'H:#alias ;; >>> 'hissp.._macro_.alias' @@ -960,18 +1026,18 @@ Hidden doctest adds bundled macros for REPL-consistent behavior. >>> # hissp.macros.._macro_.define ... __import__('builtins').globals().update( ... spam=# hissp.macros.._macro_.progn - ... (lambda :( - ... # hissp.macros.._macro_.define - ... __import__('builtins').globals().update( - ... spam=# hissp.macros.._macro_.progn - ... (lambda :( - ... # define - ... __import__('builtins').globals().update( - ... spam='spam'), - ... str.title( - ... spam))[-1])()), - ... str.swapcase( - ... spam))[-1])()) + ... (lambda : + ... (# hissp.macros.._macro_.define + ... __import__('builtins').globals().update( + ... spam=# hissp.macros.._macro_.progn + ... (lambda : + ... (# define + ... __import__('builtins').globals().update( + ... spam='spam'), + ... str.title( + ... spam)) [-1])()), + ... str.swapcase( + ... spam)) [-1])()) #> spam >>> spam @@ -990,7 +1056,7 @@ Hidden doctest adds bundled macros for REPL-consistent behavior. .. code-block:: REPL #> ([#1][::2] '(foo bar)) - >>> (lambda _Qz5GEAOGSQz_G:(_Qz5GEAOGSQz_G[1][::2]))( + >>> (lambda _Qz5GEAOGSQz___G: (_Qz5GEAOGSQz___G[1][::2]))( ... ('foo', ... 'bar',)) 'br' @@ -1017,12 +1083,12 @@ Hidden doctest adds bundled macros for REPL-consistent behavior. #.. >>> # setQzBANG_ ... # hissp.macros.._macro_.let - ... (lambda _QzE3BPTV2Tz_val=(10):( - ... __import__('operator').setitem( - ... spam, - ... (2), - ... _QzE3BPTV2Tz_val), - ... _QzE3BPTV2Tz_val)[-1])() + ... (lambda _QzE3BPTV2Tz___val=(10): + ... (__import__('operator').setitem( + ... spam, + ... (2), + ... _QzE3BPTV2Tz___val), + ... _QzE3BPTV2Tz___val) [-1])() 10 #> spam @@ -1054,19 +1120,22 @@ Hidden doctest adds bundled macros for REPL-consistent behavior. #.. >>> # zapQzBANG_ ... # hissp.macros.._macro_.let - ... (lambda _QzRDZYRDXSz_coll=spam,_QzRDZYRDXSz_key='b': - ... # hissp.macros.._macro_.setQzBANG_ - ... # hissp.macros.._macro_.let - ... (lambda _QzE3BPTV2Tz_val=__import__('operator').iadd( - ... __import__('operator').getitem( - ... _QzRDZYRDXSz_coll, - ... _QzRDZYRDXSz_key), - ... (1)):( - ... __import__('operator').setitem( - ... _QzRDZYRDXSz_coll, - ... _QzRDZYRDXSz_key, - ... _QzE3BPTV2Tz_val), - ... _QzE3BPTV2Tz_val)[-1])())() + ... ( + ... lambda _QzRDZYRDXSz___coll=spam, + ... _QzRDZYRDXSz___key='b': + ... # hissp.macros.._macro_.setQzBANG_ + ... # hissp.macros.._macro_.let + ... ( + ... lambda _QzE3BPTV2Tz___val=__import__('operator').iadd( + ... __import__('operator').getitem( + ... _QzRDZYRDXSz___coll, + ... _QzRDZYRDXSz___key), + ... (1)): + ... (__import__('operator').setitem( + ... _QzRDZYRDXSz___coll, + ... _QzRDZYRDXSz___key, + ... _QzE3BPTV2Tz___val), + ... _QzE3BPTV2Tz___val) [-1])())() 11 #> spam @@ -1094,12 +1163,12 @@ Hidden doctest adds bundled macros for REPL-consistent behavior. #> (set@ spam.foo 10) >>> # setQzAT_ ... # hissp.macros.._macro_.let - ... (lambda _QzRMG5GSSIz_val=(10):( - ... __import__('builtins').setattr( - ... spam, - ... 'foo', - ... _QzRMG5GSSIz_val), - ... _QzRMG5GSSIz_val)[-1])() + ... (lambda _QzRMG5GSSIz___val=(10): + ... (__import__('builtins').setattr( + ... spam, + ... 'foo', + ... _QzRMG5GSSIz___val), + ... _QzRMG5GSSIz___val) [-1])() 10 #> spam @@ -1132,14 +1201,15 @@ Hidden doctest adds bundled macros for REPL-consistent behavior. >>> # zapQzAT_ ... # hissp.macros.._macro_.setQzAT_ ... # hissp.macros.._macro_.let - ... (lambda _QzRMG5GSSIz_val=__import__('operator').iadd( - ... spam.foo, - ... (1)):( - ... __import__('builtins').setattr( - ... spam, - ... 'foo', - ... _QzRMG5GSSIz_val), - ... _QzRMG5GSSIz_val)[-1])() + ... ( + ... lambda _QzRMG5GSSIz___val=__import__('operator').iadd( + ... spam.foo, + ... (1)): + ... (__import__('builtins').setattr( + ... spam, + ... 'foo', + ... _QzRMG5GSSIz___val), + ... _QzRMG5GSSIz___val) [-1])() 11 #> spam @@ -1164,20 +1234,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 _QzWG5WN73Wz_target=__import__('types').SimpleNamespace():( - ... __import__('builtins').setattr( - ... _QzWG5WN73Wz_target, - ... 'attach', - ... _macro_.attach), - ... __import__('builtins').setattr( - ... _QzWG5WN73Wz_target, - ... 'a', - ... (1)), - ... __import__('builtins').setattr( - ... _QzWG5WN73Wz_target, - ... 'b', - ... 'Hi'), - ... _QzWG5WN73Wz_target)[-1])() + ... (lambda _QzWG5WN73Wz___target=__import__('types').SimpleNamespace(): + ... (__import__('builtins').setattr( + ... _QzWG5WN73Wz___target, + ... 'attach', + ... _macro_.attach), + ... __import__('builtins').setattr( + ... _QzWG5WN73Wz___target, + ... 'a', + ... (1)), + ... __import__('builtins').setattr( + ... _QzWG5WN73Wz___target, + ... 'b', + ... 'Hi'), + ... _QzWG5WN73Wz___target) [-1])() namespace(a=1, attach=, b='Hi') See also: `setattr`, `set@`, `vars`. @@ -1206,13 +1276,13 @@ Hidden doctest adds bundled macros for REPL-consistent behavior. #.. .sort #.. (.append 'foo)) >>> # doto - ... (lambda _QzKIUMBHNZz_self=list():( - ... _QzKIUMBHNZz_self.extend( - ... 'bar'), - ... _QzKIUMBHNZz_self.sort(), - ... _QzKIUMBHNZz_self.append( - ... 'foo'), - ... _QzKIUMBHNZz_self)[-1])() + ... (lambda _QzKIUMBHNZz___self=list(): + ... (_QzKIUMBHNZz___self.extend( + ... 'bar'), + ... _QzKIUMBHNZz___self.sort(), + ... _QzKIUMBHNZz___self.append( + ... 'foo'), + ... _QzKIUMBHNZz___self) [-1])() ['a', 'b', 'r', 'foo'] See also: `attach`, `progn`, `-> `. @@ -1249,12 +1319,12 @@ Hidden doctest adds bundled macros for REPL-consistent behavior. #> (-> 'a set (en#list 'bc) (en#tuple 'de)) >>> # Qz_QzGT_ - ... (lambda *_Qz6RFWTTVXz_xs: - ... tuple( - ... _Qz6RFWTTVXz_xs))( - ... (lambda *_Qz6RFWTTVXz_xs: - ... list( - ... _Qz6RFWTTVXz_xs))( + ... (lambda *_Qz6RFWTTVXz___xs: + ... tuple( + ... _Qz6RFWTTVXz___xs))( + ... (lambda *_Qz6RFWTTVXz___xs: + ... list( + ... _Qz6RFWTTVXz___xs))( ... set( ... 'a'), ... 'bc'), @@ -1293,13 +1363,13 @@ Hidden doctest adds bundled macros for REPL-consistent behavior. #> (-<>> 'a set (en#list 'bc) (en#tuple 'de :<> 'fg :<>)) >>> # Qz_QzLT_QzGT_QzGT_ - ... (lambda *_Qz6RFWTTVXz_xs: - ... tuple( - ... _Qz6RFWTTVXz_xs))( + ... (lambda *_Qz6RFWTTVXz___xs: + ... tuple( + ... _Qz6RFWTTVXz___xs))( ... 'de', - ... (lambda *_Qz6RFWTTVXz_xs: - ... list( - ... _Qz6RFWTTVXz_xs))( + ... (lambda *_Qz6RFWTTVXz___xs: + ... list( + ... _Qz6RFWTTVXz___xs))( ... 'bc', ... set( ... 'a')), @@ -1342,34 +1412,43 @@ Hidden doctest adds bundled macros for REPL-consistent behavior. ... __import__('builtins').any( ... __import__('builtins').map( ... (lambda x: - ... # cond - ... (lambda x0,x1,x2,x3,x4,x5,x6,x7:x1()if x0 else x3()if x2()else x5()if x4()else x7()if x6()else())( - ... __import__('operator').lt( - ... x, - ... (0)), - ... (lambda : - ... print( - ... ':Negative')), - ... (lambda : - ... __import__('operator').eq( + ... # cond + ... ( + ... lambda x0, + ... x1, + ... x2, + ... x3, + ... x4, + ... x5, + ... x6, + ... x7: + ... x1()if x0 else x3()if x2()else x5()if x4()else x7()if x6()else())( + ... __import__('operator').lt( ... x, - ... (0))), - ... (lambda : - ... print( - ... ':Zero')), - ... (lambda : - ... __import__('operator').gt( - ... x, - ... (0))), - ... (lambda : - ... print( - ... ':Positive')), - ... (lambda :':else'), - ... (lambda : - ... print( - ... ':Not-a-Number')))), + ... (0)), + ... (lambda : + ... print( + ... ':Negative')), + ... (lambda : + ... __import__('operator').eq( + ... x, + ... (0))), + ... (lambda : + ... print( + ... ':Zero')), + ... (lambda : + ... __import__('operator').gt( + ... x, + ... (0))), + ... (lambda : + ... print( + ... ':Positive')), + ... (lambda : ':else'), + ... (lambda : + ... print( + ... ':Not-a-Number')))), ... # QzAT_ - ... (lambda *xs:[*xs])( + ... (lambda *xs: [*xs])( ... (-0.6), ... (-0.0), ... (42.0), @@ -1405,14 +1484,14 @@ Hidden doctest adds bundled macros for REPL-consistent behavior. >>> # anyQz_map ... __import__('builtins').any( ... __import__('builtins').map( - ... (lambda index:( - ... print( - ... index, - ... end=':'), - ... not( - ... __import__('operator').mod( + ... (lambda index: + ... (print( ... index, - ... (7))))[-1]), + ... end=':'), + ... not( + ... __import__('operator').mod( + ... index, + ... (7)))) [-1]), ... range( ... (1), ... (11)))) @@ -1438,11 +1517,13 @@ Hidden doctest adds bundled macros for REPL-consistent behavior. >>> # anyQzSTAR_map ... __import__('builtins').any( ... __import__('itertools').starmap( - ... (lambda i,c: - ... print( - ... __import__('operator').mul( - ... i, - ... c))), + ... ( + ... lambda i, + ... c: + ... print( + ... __import__('operator').mul( + ... i, + ... c))), ... enumerate( ... 'abc', ... (1)))) @@ -1477,41 +1558,45 @@ Hidden doctest adds bundled macros for REPL-consistent behavior. #.. (recur-from (@ (op#sub x 1))))) >>> # loopQz_from ... # hissp.macros.._macro_.let - ... (lambda _QzDKFIH6Z2z_stack=# hissp.macros..QzMaybe_.QzAT_ - ... (lambda *xs:[*xs])( - ... (), - ... None, - ... ((3),)): - ... # hissp.macros.._macro_.let - ... (lambda recurQz_from=_QzDKFIH6Z2z_stack.append:( - ... # hissp.macros.._macro_.anyQzSTAR_map - ... __import__('builtins').any( - ... __import__('itertools').starmap( - ... (lambda x:( - ... __import__('operator').setitem( - ... _QzDKFIH6Z2z_stack, - ... (0), - ... # hissp.macros.._macro_.progn - ... (lambda : - ... # when - ... (lambda b,c:c()if b else())( - ... x, - ... (lambda :( - ... print( - ... x), - ... recurQz_from( - ... # QzAT_ - ... (lambda *xs:[*xs])( - ... __import__('operator').sub( + ... ( + ... lambda _QzDKFIH6Z2z___stack=# hissp.macros..QzMaybe_.QzAT_ + ... (lambda *xs: [*xs])( + ... (), + ... None, + ... ((3),)): + ... # hissp.macros.._macro_.let + ... (lambda recurQz_from=_QzDKFIH6Z2z___stack.append: + ... (# hissp.macros.._macro_.anyQzSTAR_map + ... __import__('builtins').any( + ... __import__('itertools').starmap( + ... (lambda x: + ... (__import__('operator').setitem( + ... _QzDKFIH6Z2z___stack, + ... (0), + ... # hissp.macros.._macro_.progn + ... (lambda : + ... # when + ... ( + ... lambda b, + ... c: + ... c()if b else())( ... x, - ... (1)))))[-1])))()), - ... None)[-1]), - ... __import__('builtins').iter( - ... _QzDKFIH6Z2z_stack.pop, - ... None))), - ... __import__('operator').itemgetter( - ... (0))( - ... _QzDKFIH6Z2z_stack))[-1])())() + ... (lambda : + ... (print( + ... x), + ... recurQz_from( + ... # QzAT_ + ... (lambda *xs: [*xs])( + ... __import__('operator').sub( + ... x, + ... (1))))) [-1])))()), + ... None) [-1]), + ... __import__('builtins').iter( + ... _QzDKFIH6Z2z___stack.pop, + ... None))), + ... __import__('operator').itemgetter( + ... (0))( + ... _QzDKFIH6Z2z___stack)) [-1])())() 3 2 1 @@ -1537,26 +1622,36 @@ Hidden doctest adds bundled macros for REPL-consistent behavior. #> (ands True True False) ; and finds the False >>> # ands - ... (lambda x0,x1,x2:x0 and x1()and x2())( + ... ( + ... lambda x0, + ... x1, + ... x2: + ... x0 and x1()and x2())( ... True, - ... (lambda :True), - ... (lambda :False)) + ... (lambda : True), + ... (lambda : False)) False #> (ands False (print 'oops)) ; Shortcutting. >>> # ands - ... (lambda x0,x1:x0 and x1())( + ... ( + ... lambda x0, + ... x1: + ... x0 and x1())( ... False, ... (lambda : - ... print( - ... 'oops'))) + ... print( + ... 'oops'))) False #> (ands True 42) >>> # ands - ... (lambda x0,x1:x0 and x1())( + ... ( + ... lambda x0, + ... x1: + ... x0 and x1())( ... True, - ... (lambda :(42))) + ... (lambda : (42))) 42 #> (ands) @@ -1589,27 +1684,38 @@ Hidden doctest adds bundled macros for REPL-consistent behavior. #> (ors True (print 'oops)) ; Shortcutting. >>> # ors - ... (lambda x0,x1:x0 or x1())( + ... ( + ... lambda x0, + ... x1: + ... x0 or x1())( ... True, ... (lambda : - ... print( - ... 'oops'))) + ... print( + ... 'oops'))) True #> (ors 42 False) >>> # ors - ... (lambda x0,x1:x0 or x1())( + ... ( + ... lambda x0, + ... x1: + ... x0 or x1())( ... (42), - ... (lambda :False)) + ... (lambda : False)) 42 #> (ors () False 0 1) ; or seeks the truth >>> # ors - ... (lambda x0,x1,x2,x3:x0 or x1()or x2()or x3())( + ... ( + ... lambda x0, + ... x1, + ... x2, + ... x3: + ... x0 or x1()or x2()or x3())( ... (), - ... (lambda :False), - ... (lambda :(0)), - ... (lambda :(1))) + ... (lambda : False), + ... (lambda : (0)), + ... (lambda : (1))) 1 #> (ors False) @@ -1679,31 +1785,40 @@ Hidden doctest adds bundled macros for REPL-consistent behavior. ... # hissp.macros.._macro_.throwQzSTAR_ ... (lambda g:g.close()or g.throw)(c for c in'')( ... # hissp.macros.._macro_.let - ... (lambda _Qz2IKKUCBWz_G=(lambda _Qz2IKKUCBWz_x: - ... # hissp.macros.._macro_.ifQz_else - ... (lambda b,c,a:c()if b else a())( - ... # hissp.macros.._macro_.ands - ... (lambda x0,x1:x0 and x1())( - ... __import__('builtins').isinstance( - ... _Qz2IKKUCBWz_x, - ... __import__('builtins').type), - ... (lambda : - ... __import__('builtins').issubclass( - ... _Qz2IKKUCBWz_x, - ... __import__('builtins').BaseException))), - ... (lambda :_Qz2IKKUCBWz_x()), - ... (lambda :_Qz2IKKUCBWz_x))): - ... # hissp.macros.._macro_.attach - ... # hissp.macros.._macro_.let - ... (lambda _QzWG5WN73Wz_target=_Qz2IKKUCBWz_G( - ... Exception):( - ... __import__('builtins').setattr( - ... _QzWG5WN73Wz_target, - ... '__cause__', - ... _Qz2IKKUCBWz_G( - ... Exception( - ... 'message'))), - ... _QzWG5WN73Wz_target)[-1])())()) + ... ( + ... lambda _Qz2IKKUCBWz___G=(lambda _Qz2IKKUCBWz___x: + ... # hissp.macros.._macro_.ifQz_else + ... ( + ... lambda b, + ... c, + ... a: + ... c()if b else a())( + ... # hissp.macros.._macro_.ands + ... ( + ... lambda x0, + ... x1: + ... x0 and x1())( + ... __import__('builtins').isinstance( + ... _Qz2IKKUCBWz___x, + ... __import__('builtins').type), + ... (lambda : + ... __import__('builtins').issubclass( + ... _Qz2IKKUCBWz___x, + ... __import__('builtins').BaseException))), + ... (lambda : _Qz2IKKUCBWz___x()), + ... (lambda : _Qz2IKKUCBWz___x))): + ... # hissp.macros.._macro_.attach + ... # hissp.macros.._macro_.let + ... ( + ... lambda _QzWG5WN73Wz___target=_Qz2IKKUCBWz___G( + ... Exception): + ... (__import__('builtins').setattr( + ... _QzWG5WN73Wz___target, + ... '__cause__', + ... _Qz2IKKUCBWz___G( + ... Exception( + ... 'message'))), + ... _QzWG5WN73Wz___target) [-1])())()) Traceback (most recent call last): ... Exception @@ -1732,12 +1847,12 @@ Hidden doctest adds bundled macros for REPL-consistent behavior. >>> print( ... # prog1 ... # hissp.macros.._macro_.let - ... (lambda _Qz46BJ7IW6z_value1=(0):( - ... print( - ... (1)), - ... print( - ... (2)), - ... _Qz46BJ7IW6z_value1)[-1])()) + ... (lambda _Qz46BJ7IW6z___value1=(0): + ... (print( + ... (1)), + ... print( + ... (2)), + ... _Qz46BJ7IW6z___value1) [-1])()) 1 2 0 @@ -1752,14 +1867,15 @@ Hidden doctest adds bundled macros for REPL-consistent behavior. #.. (print 2)) >>> # prog1 ... # hissp.macros.._macro_.let - ... (lambda _Qz46BJ7IW6z_value1=# progn - ... (lambda :( - ... print( - ... (1)), - ... (3))[-1])():( - ... print( - ... (2)), - ... _Qz46BJ7IW6z_value1)[-1])() + ... ( + ... lambda _Qz46BJ7IW6z___value1=# progn + ... (lambda : + ... (print( + ... (1)), + ... (3)) [-1])(): + ... (print( + ... (2)), + ... _Qz46BJ7IW6z___value1) [-1])() 1 2 3 @@ -1804,9 +1920,9 @@ Hidden doctest adds bundled macros for REPL-consistent behavior. ;; .. code-block:: REPL ;; ;; #> (en#list 1 2 3) - ;; >>> (lambda *_Qz6RFWTTVXz_xs: - ;; ... list( - ;; ... _Qz6RFWTTVXz_xs))( + ;; >>> (lambda *_Qz6RFWTTVXz___xs: + ;; ... list( + ;; ... _Qz6RFWTTVXz___xs))( ;; ... (1), ;; ... (2), ;; ... (3)) @@ -1814,9 +1930,11 @@ Hidden doctest adds bundled macros for REPL-consistent behavior. ;; ;; #> (en#.extend _ 4 5 6) ; Methods too. ;; #.. - ;; >>> (lambda _Qz4LWLAFU3z_self,*_Qz4LWLAFU3z_xs: - ;; ... _Qz4LWLAFU3z_self.extend( - ;; ... _Qz4LWLAFU3z_xs))( + ;; >>> ( + ;; ... lambda _Qz4LWLAFU3z___self, + ;; ... *_Qz4LWLAFU3z___xs: + ;; ... _Qz4LWLAFU3z___self.extend( + ;; ... _Qz4LWLAFU3z___xs))( ;; ... _, ;; ... (4), ;; ... (5), @@ -1829,13 +1947,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 *_Qz6RFWTTVXz_xs: - ;; ... (lambda X: - ;; ... ('').join( - ;; ... map( - ;; ... str, - ;; ... X)))( - ;; ... _Qz6RFWTTVXz_xs))) + ;; ... enjoin=(lambda *_Qz6RFWTTVXz___xs: + ;; ... (lambda X: + ;; ... ('').join( + ;; ... map( + ;; ... str, + ;; ... X)))( + ;; ... _Qz6RFWTTVXz___xs))) ;; ;; #> (enjoin "Sum: "(op#add 2 3)". Product: "(op#mul 2 3)".") ;; >>> enjoin( @@ -1875,7 +1993,7 @@ Hidden doctest adds bundled macros for REPL-consistent behavior. ;; ;; #> (@ :* "AB" (math..sqrt 9) :* "XY" 2 1) ;; >>> # QzAT_ - ;; ... (lambda *xs:[*xs])( + ;; ... (lambda *xs: [*xs])( ;; ... *('AB'), ;; ... __import__('math').sqrt( ;; ... (9)), @@ -1905,10 +2023,10 @@ Hidden doctest adds bundled macros for REPL-consistent behavior. #> (# 1 :* (@ 1 2 3) 4) ;Set, with unpacking. >>> # QzHASH_ - ... (lambda *xs:{*xs})( + ... (lambda *xs: {*xs})( ... (1), ... *# QzAT_ - ... (lambda *xs:[*xs])( + ... (lambda *xs: [*xs])( ... (1), ... (2), ... (3)), @@ -1936,7 +2054,13 @@ Hidden doctest adds bundled macros for REPL-consistent behavior. #> (% 1 2 :** (dict : x 3 y 4) 5 6) ;Dict, with mapping unpacking. >>> # QzPCENT_ - ... (lambda x0,x1,x3,x4,x5:{x0:x1,**x3,x4:x5})( + ... ( + ... lambda x0, + ... x1, + ... x3, + ... x4, + ... x5: + ... {x0:x1,**x3,x4:x5})( ... (1), ... (2), ... dict( @@ -2092,13 +2216,13 @@ Hidden doctest adds bundled macros for REPL-consistent behavior. ;; #.. (lambda e (print "Oops!") e) ;handler (returns exception) ;; #.. truediv 6 0) ;calls it on your behalf ;; >>> engarde( - ;; ... (lambda * _: _)( + ;; ... (lambda * _: _)( ;; ... FloatingPointError, ;; ... ZeroDivisionError), - ;; ... (lambda e:( - ;; ... print( - ;; ... ('Oops!')), - ;; ... e)[-1]), + ;; ... (lambda e: + ;; ... (print( + ;; ... ('Oops!')), + ;; ... e) [-1]), ;; ... truediv, ;; ... (6), ;; ... (0)) @@ -2135,8 +2259,8 @@ Hidden doctest adds bundled macros for REPL-consistent behavior. ;; ... engarde, ;; ... ZeroDivisionError, ;; ... (lambda e: - ;; ... print( - ;; ... ('It means what you want it to mean.'))), + ;; ... print( + ;; ... ('It means what you want it to mean.'))), ;; ... truediv, ;; ... ('6'), ;; ... (0)) @@ -2147,37 +2271,46 @@ Hidden doctest adds bundled macros for REPL-consistent behavior. ;; #.. (lambda : (throw-from Exception (Exception "msg")))) ;; >>> engarde( ;; ... Exception, - ;; ... (lambda x:x.__cause__), + ;; ... (lambda x: x.__cause__), ;; ... (lambda : - ;; ... # throwQz_from - ;; ... # hissp.macros.._macro_.throwQzSTAR_ - ;; ... (lambda g:g.close()or g.throw)(c for c in'')( - ;; ... # hissp.macros.._macro_.let - ;; ... (lambda _Qz2IKKUCBWz_G=(lambda _Qz2IKKUCBWz_x: - ;; ... # hissp.macros.._macro_.ifQz_else - ;; ... (lambda b,c,a:c()if b else a())( - ;; ... # hissp.macros.._macro_.ands - ;; ... (lambda x0,x1:x0 and x1())( - ;; ... __import__('builtins').isinstance( - ;; ... _Qz2IKKUCBWz_x, - ;; ... __import__('builtins').type), - ;; ... (lambda : - ;; ... __import__('builtins').issubclass( - ;; ... _Qz2IKKUCBWz_x, - ;; ... __import__('builtins').BaseException))), - ;; ... (lambda :_Qz2IKKUCBWz_x()), - ;; ... (lambda :_Qz2IKKUCBWz_x))): - ;; ... # hissp.macros.._macro_.attach + ;; ... # throwQz_from + ;; ... # hissp.macros.._macro_.throwQzSTAR_ + ;; ... (lambda g:g.close()or g.throw)(c for c in'')( ;; ... # hissp.macros.._macro_.let - ;; ... (lambda _QzWG5WN73Wz_target=_Qz2IKKUCBWz_G( - ;; ... Exception):( - ;; ... __import__('builtins').setattr( - ;; ... _QzWG5WN73Wz_target, - ;; ... '__cause__', - ;; ... _Qz2IKKUCBWz_G( - ;; ... Exception( - ;; ... ('msg')))), - ;; ... _QzWG5WN73Wz_target)[-1])())()))) + ;; ... ( + ;; ... lambda _Qz2IKKUCBWz___G=(lambda _Qz2IKKUCBWz___x: + ;; ... # hissp.macros.._macro_.ifQz_else + ;; ... ( + ;; ... lambda b, + ;; ... c, + ;; ... a: + ;; ... c()if b else a())( + ;; ... # hissp.macros.._macro_.ands + ;; ... ( + ;; ... lambda x0, + ;; ... x1: + ;; ... x0 and x1())( + ;; ... __import__('builtins').isinstance( + ;; ... _Qz2IKKUCBWz___x, + ;; ... __import__('builtins').type), + ;; ... (lambda : + ;; ... __import__('builtins').issubclass( + ;; ... _Qz2IKKUCBWz___x, + ;; ... __import__('builtins').BaseException))), + ;; ... (lambda : _Qz2IKKUCBWz___x()), + ;; ... (lambda : _Qz2IKKUCBWz___x))): + ;; ... # hissp.macros.._macro_.attach + ;; ... # hissp.macros.._macro_.let + ;; ... ( + ;; ... lambda _QzWG5WN73Wz___target=_Qz2IKKUCBWz___G( + ;; ... Exception): + ;; ... (__import__('builtins').setattr( + ;; ... _QzWG5WN73Wz___target, + ;; ... '__cause__', + ;; ... _Qz2IKKUCBWz___G( + ;; ... Exception( + ;; ... ('msg')))), + ;; ... _QzWG5WN73Wz___target) [-1])())()))) ;; Exception('msg') ;; ;; Ensue examples @@ -2191,22 +2324,24 @@ Hidden doctest adds bundled macros for REPL-consistent behavior. ;; #.. (fibonacci b (add a b)))))) ;; >>> # define ;; ... __import__('builtins').globals().update( - ;; ... fibonacci=(lambda a=(1),b=(1): - ;; ... Ensue( - ;; ... (lambda step:( - ;; ... # setQzAT_ - ;; ... # hissp.macros.._macro_.let - ;; ... (lambda _QzRMG5GSSIz_val=a:( - ;; ... __import__('builtins').setattr( - ;; ... step, - ;; ... 'Y', - ;; ... _QzRMG5GSSIz_val), - ;; ... _QzRMG5GSSIz_val)[-1])(), - ;; ... fibonacci( - ;; ... b, - ;; ... add( - ;; ... a, - ;; ... b)))[-1])))) + ;; ... fibonacci=( + ;; ... lambda a=(1), + ;; ... b=(1): + ;; ... Ensue( + ;; ... (lambda step: + ;; ... (# setQzAT_ + ;; ... # hissp.macros.._macro_.let + ;; ... (lambda _QzRMG5GSSIz___val=a: + ;; ... (__import__('builtins').setattr( + ;; ... step, + ;; ... 'Y', + ;; ... _QzRMG5GSSIz___val), + ;; ... _QzRMG5GSSIz___val) [-1])(), + ;; ... fibonacci( + ;; ... b, + ;; ... add( + ;; ... a, + ;; ... b))) [-1])))) ;; ;; #> (list (islice (fibonacci) 7)) ;; >>> list( @@ -2224,28 +2359,33 @@ Hidden doctest adds bundled macros for REPL-consistent behavior. ;; #.. ;; >>> # define ;; ... __import__('builtins').globals().update( - ;; ... myQz_range=(lambda i,n: - ;; ... Ensue( - ;; ... (lambda step: - ;; ... # when - ;; ... (lambda b,c:c()if b else())( - ;; ... lt( - ;; ... i, - ;; ... n), - ;; ... (lambda :( - ;; ... # setQzAT_ - ;; ... # hissp.macros.._macro_.let - ;; ... (lambda _QzRMG5GSSIz_val=i:( - ;; ... __import__('builtins').setattr( - ;; ... step, - ;; ... 'Y', - ;; ... _QzRMG5GSSIz_val), - ;; ... _QzRMG5GSSIz_val)[-1])(), - ;; ... myQz_range( - ;; ... add( + ;; ... myQz_range=( + ;; ... lambda i, + ;; ... n: + ;; ... Ensue( + ;; ... (lambda step: + ;; ... # when + ;; ... ( + ;; ... lambda b, + ;; ... c: + ;; ... c()if b else())( + ;; ... lt( ;; ... i, - ;; ... (1)), - ;; ... n))[-1])))))) + ;; ... n), + ;; ... (lambda : + ;; ... (# setQzAT_ + ;; ... # hissp.macros.._macro_.let + ;; ... (lambda _QzRMG5GSSIz___val=i: + ;; ... (__import__('builtins').setattr( + ;; ... step, + ;; ... 'Y', + ;; ... _QzRMG5GSSIz___val), + ;; ... _QzRMG5GSSIz___val) [-1])(), + ;; ... myQz_range( + ;; ... add( + ;; ... i, + ;; ... (1)), + ;; ... n)) [-1])))))) ;; ;; #> (list (my-range 1 6)) ;; >>> list( @@ -2260,24 +2400,24 @@ Hidden doctest adds bundled macros for REPL-consistent behavior. ;; #.. Y '(1 2 3 4 5)) ;; #.. None)) ;; >>> Ensue( - ;; ... (lambda step:( - ;; ... # attach - ;; ... # hissp.macros.._macro_.let - ;; ... (lambda _QzWG5WN73Wz_target=step:( - ;; ... __import__('builtins').setattr( - ;; ... _QzWG5WN73Wz_target, - ;; ... 'F', - ;; ... True), - ;; ... __import__('builtins').setattr( - ;; ... _QzWG5WN73Wz_target, - ;; ... 'Y', - ;; ... ((1), - ;; ... (2), - ;; ... (3), - ;; ... (4), - ;; ... (5),)), - ;; ... _QzWG5WN73Wz_target)[-1])(), - ;; ... None)[-1])) + ;; ... (lambda step: + ;; ... (# attach + ;; ... # hissp.macros.._macro_.let + ;; ... (lambda _QzWG5WN73Wz___target=step: + ;; ... (__import__('builtins').setattr( + ;; ... _QzWG5WN73Wz___target, + ;; ... 'F', + ;; ... True), + ;; ... __import__('builtins').setattr( + ;; ... _QzWG5WN73Wz___target, + ;; ... 'Y', + ;; ... ((1), + ;; ... (2), + ;; ... (3), + ;; ... (4), + ;; ... (5),)), + ;; ... _QzWG5WN73Wz___target) [-1])(), + ;; ... None) [-1])) ;; <...Ensue object at ...> ;; ;; #> (list _) @@ -2293,20 +2433,20 @@ Hidden doctest adds bundled macros for REPL-consistent behavior. ;; >>> # define ;; ... __import__('builtins').globals().update( ;; ... recycle=(lambda itr: - ;; ... Ensue( - ;; ... (lambda step: - ;; ... # attach - ;; ... # hissp.macros.._macro_.let - ;; ... (lambda _QzWG5WN73Wz_target=step:( - ;; ... __import__('builtins').setattr( - ;; ... _QzWG5WN73Wz_target, - ;; ... 'Y', - ;; ... itr), - ;; ... __import__('builtins').setattr( - ;; ... _QzWG5WN73Wz_target, - ;; ... 'F', - ;; ... (1)), - ;; ... _QzWG5WN73Wz_target)[-1])())))) + ;; ... Ensue( + ;; ... (lambda step: + ;; ... # attach + ;; ... # hissp.macros.._macro_.let + ;; ... (lambda _QzWG5WN73Wz___target=step: + ;; ... (__import__('builtins').setattr( + ;; ... _QzWG5WN73Wz___target, + ;; ... 'Y', + ;; ... itr), + ;; ... __import__('builtins').setattr( + ;; ... _QzWG5WN73Wz___target, + ;; ... 'F', + ;; ... (1)), + ;; ... _QzWG5WN73Wz___target) [-1])())))) ;; ;; #> (-> '(1 2 3) recycle (islice 7) list) ;; >>> # Qz_QzGT_ @@ -2326,16 +2466,16 @@ Hidden doctest adds bundled macros for REPL-consistent behavior. ;; >>> # define ;; ... __import__('builtins').globals().update( ;; ... echo=Ensue( - ;; ... (lambda step:( - ;; ... # setQzAT_ - ;; ... # hissp.macros.._macro_.let - ;; ... (lambda _QzRMG5GSSIz_val=step.sent:( - ;; ... __import__('builtins').setattr( - ;; ... step, - ;; ... 'Y', - ;; ... _QzRMG5GSSIz_val), - ;; ... _QzRMG5GSSIz_val)[-1])(), - ;; ... step)[-1]))) + ;; ... (lambda step: + ;; ... (# setQzAT_ + ;; ... # hissp.macros.._macro_.let + ;; ... (lambda _QzRMG5GSSIz___val=step.sent: + ;; ... (__import__('builtins').setattr( + ;; ... step, + ;; ... 'Y', + ;; ... _QzRMG5GSSIz___val), + ;; ... _QzRMG5GSSIz___val) [-1])(), + ;; ... step) [-1]))) ;; ;; #> (.send echo None) ; Always send a None first. Same as Python. ;; >>> echo.send( @@ -2366,25 +2506,25 @@ Hidden doctest adds bundled macros for REPL-consistent behavior. ;; >>> # define ;; ... __import__('builtins').globals().update( ;; ... wrap=__import__('contextlib').contextmanager( - ;; ... (lambda msg:( - ;; ... print( - ;; ... ('enter'), - ;; ... msg), - ;; ... Ensue( - ;; ... (lambda step:( - ;; ... # setQzAT_ - ;; ... # hissp.macros.._macro_.let - ;; ... (lambda _QzRMG5GSSIz_val=msg:( - ;; ... __import__('builtins').setattr( - ;; ... step, - ;; ... 'Y', - ;; ... _QzRMG5GSSIz_val), - ;; ... _QzRMG5GSSIz_val)[-1])(), - ;; ... Ensue( - ;; ... (lambda step: - ;; ... print( - ;; ... ('exit'), - ;; ... msg))))[-1])))[-1]))) + ;; ... (lambda msg: + ;; ... (print( + ;; ... ('enter'), + ;; ... msg), + ;; ... Ensue( + ;; ... (lambda step: + ;; ... (# setQzAT_ + ;; ... # hissp.macros.._macro_.let + ;; ... (lambda _QzRMG5GSSIz___val=msg: + ;; ... (__import__('builtins').setattr( + ;; ... step, + ;; ... 'Y', + ;; ... _QzRMG5GSSIz___val), + ;; ... _QzRMG5GSSIz___val) [-1])(), + ;; ... Ensue( + ;; ... (lambda step: + ;; ... print( + ;; ... ('exit'), + ;; ... msg)))) [-1]))) [-1]))) ;; ;; #> (enter (wrap 'A) ;; #.. (lambda a (print a))) @@ -2392,8 +2532,8 @@ Hidden doctest adds bundled macros for REPL-consistent behavior. ;; ... wrap( ;; ... 'A'), ;; ... (lambda a: - ;; ... print( - ;; ... a))) + ;; ... print( + ;; ... a))) ;; enter A ;; A ;; exit A @@ -2411,11 +2551,14 @@ Hidden doctest adds bundled macros for REPL-consistent behavior. ;; ... enter, ;; ... wrap( ;; ... 'C'), - ;; ... (lambda a,b,c: - ;; ... print( - ;; ... a, - ;; ... b, - ;; ... c))) + ;; ... ( + ;; ... lambda a, + ;; ... b, + ;; ... c: + ;; ... print( + ;; ... a, + ;; ... b, + ;; ... c))) ;; enter A ;; enter B ;; enter C @@ -2437,34 +2580,34 @@ Hidden doctest adds bundled macros for REPL-consistent behavior. ;; ... __import__('builtins').globals().update( ;; ... suppressQz_zde=__import__('contextlib').contextmanager( ;; ... (lambda : - ;; ... Ensue( - ;; ... (lambda step:( - ;; ... # attach - ;; ... # hissp.macros.._macro_.let - ;; ... (lambda _QzWG5WN73Wz_target=step:( - ;; ... __import__('builtins').setattr( - ;; ... _QzWG5WN73Wz_target, - ;; ... 'Y', - ;; ... None), - ;; ... __import__('builtins').setattr( - ;; ... _QzWG5WN73Wz_target, - ;; ... 'X', - ;; ... ZeroDivisionError), - ;; ... _QzWG5WN73Wz_target)[-1])(), - ;; ... Ensue( - ;; ... (lambda step: - ;; ... print( - ;; ... ('Caught a'), - ;; ... step.sent))))[-1]))))) + ;; ... Ensue( + ;; ... (lambda step: + ;; ... (# attach + ;; ... # hissp.macros.._macro_.let + ;; ... (lambda _QzWG5WN73Wz___target=step: + ;; ... (__import__('builtins').setattr( + ;; ... _QzWG5WN73Wz___target, + ;; ... 'Y', + ;; ... None), + ;; ... __import__('builtins').setattr( + ;; ... _QzWG5WN73Wz___target, + ;; ... 'X', + ;; ... ZeroDivisionError), + ;; ... _QzWG5WN73Wz___target) [-1])(), + ;; ... Ensue( + ;; ... (lambda step: + ;; ... print( + ;; ... ('Caught a'), + ;; ... step.sent)))) [-1]))))) ;; ;; #> (enter (suppress-zde) ;; #.. (lambda _ (truediv 1 0))) ;; >>> enter( ;; ... suppressQz_zde(), ;; ... (lambda _: - ;; ... truediv( - ;; ... (1), - ;; ... (0)))) + ;; ... truediv( + ;; ... (1), + ;; ... (0)))) ;; Caught a division by zero ;; ;; ;; No exception, so step.sent was .send() value. @@ -2473,9 +2616,9 @@ Hidden doctest adds bundled macros for REPL-consistent behavior. ;; >>> enter( ;; ... suppressQz_zde(), ;; ... (lambda _: - ;; ... truediv( - ;; ... (4), - ;; ... (2)))) + ;; ... truediv( + ;; ... (4), + ;; ... (2)))) ;; Caught a None ;; 2.0 ;; @@ -2484,10 +2627,10 @@ Hidden doctest adds bundled macros for REPL-consistent behavior. ;; >>> enter( ;; ... suppressQz_zde(), ;; ... (lambda _: - ;; ... # throw - ;; ... # hissp.macros.._macro_.throwQzSTAR_ - ;; ... (lambda g:g.close()or g.throw)(c for c in'')( - ;; ... Exception))) + ;; ... # throw + ;; ... # hissp.macros.._macro_.throwQzSTAR_ + ;; ... (lambda g:g.close()or g.throw)(c for c in'')( + ;; ... Exception))) ;; Traceback (most recent call last): ;; ... ;; Exception @@ -2539,22 +2682,22 @@ except ModuleNotFoundError:pass" ;; ... __import__('builtins').any( ;; ... __import__('builtins').map( ;; ... (lambda x: - ;; ... # case - ;; ... __import__('operator').getitem( - ;; ... # hissp.macros.._macro_.QzAT_ - ;; ... (lambda *xs:[*xs])( - ;; ... (lambda : - ;; ... print( - ;; ... ('odd'))), - ;; ... (lambda : - ;; ... print( - ;; ... ('even'))), - ;; ... (lambda : - ;; ... print( - ;; ... ('default')))), - ;; ... {1: 0, 3: 0, 'spam': 0, 0: 1, 2: 1, '42': 1}.get( - ;; ... x, - ;; ... (-1)))()), + ;; ... # case + ;; ... __import__('operator').getitem( + ;; ... # hissp.macros.._macro_.QzAT_ + ;; ... (lambda *xs: [*xs])( + ;; ... (lambda : + ;; ... print( + ;; ... ('odd'))), + ;; ... (lambda : + ;; ... print( + ;; ... ('even'))), + ;; ... (lambda : + ;; ... print( + ;; ... ('default')))), + ;; ... {1: 0, 3: 0, 'spam': 0, 0: 1, 2: 1, '42': 1}.get( + ;; ... x, + ;; ... (-1)))()), ;; ... ((1), ;; ... (2), ;; ... 'spam', @@ -2604,20 +2747,21 @@ except ModuleNotFoundError:pass" ... (5), ... # hissp.._macro_._spy ... # hissp.macros.._macro_.let - ... (lambda _Qz764KZBP5z_e=__import__('operator').mul( - ... (7), - ... (3)):( - ... __import__('builtins').print( - ... __import__('pprint').pformat( - ... ('operator..mul', - ... (7), - ... (3),), - ... sort_dicts=(0)), - ... ('=>'), - ... __import__('builtins').repr( - ... _Qz764KZBP5z_e), - ... file=__import__('sys').stdout), - ... _Qz764KZBP5z_e)[-1])()) + ... ( + ... lambda _Qz764KZBP5z___e=__import__('operator').mul( + ... (7), + ... (3)): + ... (__import__('builtins').print( + ... __import__('pprint').pformat( + ... ('operator..mul', + ... (7), + ... (3),), + ... sort_dicts=(0)), + ... ('=>'), + ... __import__('builtins').repr( + ... _Qz764KZBP5z___e), + ... file=__import__('sys').stdout), + ... _Qz764KZBP5z___e) [-1])()) ('operator..mul', 7, 3) => 21 26 @@ -2634,31 +2778,34 @@ except ModuleNotFoundError:pass" #> time##file=#sys..stdout(time..sleep .05) >>> # hissp.macros.._macro_.let - ... (lambda _QzPMWTVFTZz_time=__import__('time').time_ns: - ... # hissp.macros.._macro_.letQz_from - ... (lambda _QzPMWTVFTZz_start,_QzPMWTVFTZz_val,_QzPMWTVFTZz_end:( - ... __import__('builtins').print( - ... ('time# ran'), - ... __import__('pprint').pformat( - ... ('time..sleep', - ... (0.05),), - ... sort_dicts=(0)), - ... ('in'), - ... __import__('operator').truediv( - ... __import__('operator').sub( - ... _QzPMWTVFTZz_end, - ... _QzPMWTVFTZz_start), - ... __import__('decimal').Decimal( - ... (1000000.0))), - ... ('ms'), - ... file=__import__('sys').stdout), - ... _QzPMWTVFTZz_val)[-1])( - ... *# hissp.macros.._macro_.QzAT_ - ... (lambda *xs:[*xs])( - ... _QzPMWTVFTZz_time(), - ... __import__('time').sleep( - ... (0.05)), - ... _QzPMWTVFTZz_time())))() + ... (lambda _QzPMWTVFTZz___time=__import__('time').time_ns: + ... # hissp.macros.._macro_.letQz_from + ... ( + ... lambda _QzPMWTVFTZz___start, + ... _QzPMWTVFTZz___val, + ... _QzPMWTVFTZz___end: + ... (__import__('builtins').print( + ... ('time# ran'), + ... __import__('pprint').pformat( + ... ('time..sleep', + ... (0.05),), + ... sort_dicts=(0)), + ... ('in'), + ... __import__('operator').truediv( + ... __import__('operator').sub( + ... _QzPMWTVFTZz___end, + ... _QzPMWTVFTZz___start), + ... __import__('decimal').Decimal( + ... (1000000.0))), + ... ('ms'), + ... file=__import__('sys').stdout), + ... _QzPMWTVFTZz___val) [-1])( + ... *# hissp.macros.._macro_.QzAT_ + ... (lambda *xs: [*xs])( + ... _QzPMWTVFTZz___time(), + ... __import__('time').sleep( + ... (0.05)), + ... _QzPMWTVFTZz___time())))() time# ran ('time..sleep', 0.05) in ... ms See also: `timeit`. @@ -2696,20 +2843,23 @@ except ModuleNotFoundError:pass" ;; #.. it "That's odd.") ;; >>> # avow ;; ... # hissp.macros.._macro_.let - ;; ... (lambda it=(7):( - ;; ... # hissp.macros.._macro_.unless - ;; ... (lambda b,a:()if b else a())( - ;; ... # hissp.macros.._macro_.Qz_QzGT_ - ;; ... (lambda X:X%2 == 0)( - ;; ... it), - ;; ... (lambda : - ;; ... # hissp.macros.._macro_.throw - ;; ... # hissp.macros.._macro_.throwQzSTAR_ - ;; ... (lambda g:g.close()or g.throw)(c for c in'')( - ;; ... __import__('builtins').AssertionError( - ;; ... it, - ;; ... ("That's odd."))))), - ;; ... it)[-1])() + ;; ... (lambda it=(7): + ;; ... (# hissp.macros.._macro_.unless + ;; ... ( + ;; ... lambda b, + ;; ... a: + ;; ... ()if b else a())( + ;; ... # hissp.macros.._macro_.Qz_QzGT_ + ;; ... (lambda X: X%2 == 0)( + ;; ... it), + ;; ... (lambda : + ;; ... # hissp.macros.._macro_.throw + ;; ... # hissp.macros.._macro_.throwQzSTAR_ + ;; ... (lambda g:g.close()or g.throw)(c for c in'')( + ;; ... __import__('builtins').AssertionError( + ;; ... it, + ;; ... ("That's odd."))))), + ;; ... it) [-1])() ;; Traceback (most recent call last): ;; ... ;; AssertionError: (7, "That's odd.") @@ -2759,20 +2909,23 @@ except ModuleNotFoundError:pass" ;; >>> # assure ;; ... # hissp.macros.._macro_.avow ;; ... # hissp.macros.._macro_.let - ;; ... (lambda it=(7):( - ;; ... # hissp.macros.._macro_.unless - ;; ... (lambda b,a:()if b else a())( - ;; ... # hissp.macros.._macro_.Qz_QzGT_ - ;; ... (lambda X:X%2 == 0)( - ;; ... it), - ;; ... (lambda : - ;; ... # hissp.macros.._macro_.throw - ;; ... # hissp.macros.._macro_.throwQzSTAR_ - ;; ... (lambda g:g.close()or g.throw)(c for c in'')( - ;; ... __import__('builtins').AssertionError( - ;; ... it, - ;; ... ("That's odd."))))), - ;; ... it)[-1])() + ;; ... (lambda it=(7): + ;; ... (# hissp.macros.._macro_.unless + ;; ... ( + ;; ... lambda b, + ;; ... a: + ;; ... ()if b else a())( + ;; ... # hissp.macros.._macro_.Qz_QzGT_ + ;; ... (lambda X: X%2 == 0)( + ;; ... it), + ;; ... (lambda : + ;; ... # hissp.macros.._macro_.throw + ;; ... # hissp.macros.._macro_.throwQzSTAR_ + ;; ... (lambda g:g.close()or g.throw)(c for c in'')( + ;; ... __import__('builtins').AssertionError( + ;; ... it, + ;; ... ("That's odd."))))), + ;; ... it) [-1])() ;; Traceback (most recent call last): ;; ... ;; AssertionError: (7, "That's odd.") diff --git a/src/hissp/reader.py b/src/hissp/reader.py index 453caeb7c..0231fcc34 100644 --- a/src/hissp/reader.py +++ b/src/hissp/reader.py @@ -432,7 +432,7 @@ def gensym(self, form: str): """ 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_" + prefix = f"_Qz{b32encode(blk.digest()).rstrip(b'=').decode()}z___" marker = munge("$") if marker not in form: return f"{prefix}{form}" diff --git a/tests/test_cmd.py b/tests/test_cmd.py index d89271c65..77e4d3143 100644 --- a/tests/test_cmd.py +++ b/tests/test_cmd.py @@ -285,10 +285,12 @@ def test_compile_error(): "> #> ", "< (lambda :x)", "! >>> # CompileError\n", "! \n", - "! (lambda (> > > >>':x'<< < < <)\n", + "! (\n", + "! lambda (> > > >>':x'<< < < <)\n", "! # Compiler.parameters() CompileError:\n", "! # Incomplete pair.\n", - "! :())\n", + "! :\n", + "! ())\n", "> #> ", ) # fmt: skip @@ -301,7 +303,7 @@ def test_interact(): "! ... y=(2))\n", "> #> ", "< (let (x 42) (hissp..interact))\n", "! >>> # let\n", - "! ... (lambda x=(42):__import__('hissp').interact())()\n", + "! ... (lambda x=(42): __import__('hissp').interact())()\n", f"! {BANNER}", "> #> ", "< x\n", "! >>> x\n", diff --git a/tests/test_macros.lissp b/tests/test_macros.lissp index 8f169710d..be8d35db9 100644 --- a/tests/test_macros.lissp +++ b/tests/test_macros.lissp @@ -39,7 +39,7 @@ hissp..alias#* test_inner_gensym (lambda (self) - (self.assertRegex `$#self.$foo "self._Qz[A-Z2-7]+z_foo$")) + (self.assertRegex `$#self.$foo "self._Qz[A-Z2-7]+z___foo$")) test_qualified_symbol (lambda (self) From fb5acbc688437da2b838fb6dba99a98192bb4c93 Mon Sep 17 00:00:00 2001 From: gilch Date: Wed, 14 Aug 2024 19:56:19 -0600 Subject: [PATCH 09/17] Drop down multiline lambda body bracket Compile lambda params on one line in simple cases fix lissp_whirlwind_tour.rst fix README.md fix macro_tutorial.rst fix primer.rst fix Compiler.function docstring fix macros.lissp docstrings --- README.md | 12 +- docs/lissp_whirlwind_tour.rst | 152 ++++----- docs/macro_tutorial.rst | 559 ++++++++++++++++++---------------- docs/primer.rst | 71 ++--- src/hissp/compiler.py | 31 +- src/hissp/macros.lissp | 539 ++++++++++++++++---------------- tests/test_cmd.py | 2 +- 7 files changed, 677 insertions(+), 689 deletions(-) diff --git a/README.md b/README.md index edbf94e9b..fc47dc8ff 100644 --- a/README.md +++ b/README.md @@ -85,7 +85,8 @@ which are compiled to Python code, (lambda name: print( 'Hello', - name)) + name) +) ``` and evaluated by Python. @@ -140,7 +141,8 @@ Strings also have a few special cases: print( *name.upper(), sep=':', - file=__import__('sys').stdout)) [-1]) + file=__import__('sys').stdout)) [-1] +) >>> greetier = eval(readerless(adv_hissp_code)) >>> greetier() Hello, @@ -196,11 +198,13 @@ branch( # thunk (lambda : print( - 'yes')), + 'yes') + ), # thunk (lambda : print( - 'no'))) + 'no') + )) >>> eval(expansion) no diff --git a/docs/lissp_whirlwind_tour.rst b/docs/lissp_whirlwind_tour.rst index e866d7a5c..ec96bcfed 100644 --- a/docs/lissp_whirlwind_tour.rst +++ b/docs/lissp_whirlwind_tour.rst @@ -587,13 +587,12 @@ Lissp Whirlwind Tour #.. (.title salutation) #.. name)))) >>> globals().update( - ... greet=( - ... lambda salutation, - ... name: + ... greet=(lambda salutation, name: ... print( ... ('{}, {}!').format( ... salutation.title(), - ... name)))) + ... name)) + ... )) #> (greet "hello" "World") >>> greet( @@ -626,7 +625,8 @@ Lissp Whirlwind Tour ... i, ... (0), ... (-1)), - ... (1)))) + ... (1)) + ... )) #> (factorial_I 0) >>> factorial_I( @@ -678,10 +678,7 @@ Lissp Whirlwind Tour >>> __import__('operator').setitem( ... boolQz_QzGT_caller, ... True, - ... ( - ... lambda L, - ... R: - ... L())) + ... (lambda L, R: L())) ;; False calls right. @@ -689,10 +686,7 @@ Lissp Whirlwind Tour >>> __import__('operator').setitem( ... boolQz_QzGT_caller, ... False, - ... ( - ... lambda L, - ... R: - ... R())) + ... (lambda L, R: R())) #> (.update (globals) @@ -701,16 +695,14 @@ Lissp Whirlwind Tour #.. ((operator..getitem bool->caller (bool condition)) #.. then_thunk else_thunk))) >>> globals().update( - ... ternary=( - ... lambda condition, - ... then_thunk, - ... else_thunk: + ... ternary=(lambda condition, then_thunk, else_thunk: ... __import__('operator').getitem( ... boolQz_QzGT_caller, ... bool( ... condition))( ... then_thunk, - ... else_thunk))) + ... else_thunk) + ... )) ;;;; 8.3 Obligatory Factorial II @@ -736,7 +728,9 @@ Lissp Whirlwind Tour ... factorial_II( ... __import__('operator').sub( ... i, - ... (1)))))))) + ... (1)))) + ... )) + ... )) #> (factorial_II 5) >>> factorial_II( @@ -774,7 +768,8 @@ Lissp Whirlwind Tour ... globals()), ... print( ... locals()), - ... b) [-1]) + ... b) [-1] + ... ) at 0x...> @@ -808,31 +803,19 @@ Lissp Whirlwind Tour at 0x...> #> (lambda (: :* :? x :?)) ;Empty star arg, so x is keyword only. - >>> ( - ... lambda *, - ... x: - ... ()) + >>> (lambda *, x: ()) at 0x...> #> (lambda (:* : x :?)) ;Slid : over one. Still a kwonly. - >>> ( - ... lambda *, - ... x: - ... ()) + >>> (lambda *, x: ()) at 0x...> #> (lambda (:* x :)) ;Implicit :? is the same. Compare. - >>> ( - ... lambda *, - ... x: - ... ()) + >>> (lambda *, x: ()) at 0x...> #> (lambda (:* a)) ;Kwonly! Not star arg! Final : implied. - >>> ( - ... lambda *, - ... a: - ... ()) + >>> (lambda *, a: ()) at 0x...> @@ -857,23 +840,18 @@ Lissp Whirlwind Tour #> (lambda (spam eggs) eggs) ;Simple cases look like other Lisps, but - >>> ( - ... lambda spam, - ... eggs: - ... eggs) + >>> (lambda spam, eggs: eggs) at 0x...> #> ((lambda abc ; params not strictly required to be a tuple. #.. (print c b a)) ;There are three parameters. #.. 3 2 1) - >>> ( - ... lambda a, - ... b, - ... c: + >>> (lambda a, b, c: ... print( ... c, ... b, - ... a))( + ... a) + ... )( ... (3), ... (2), ... (1)) @@ -887,7 +865,8 @@ Lissp Whirlwind Tour #> (lambda : (print "oops")) ;Thunk resembles Python. >>> (lambda : ... print( - ... ('oops'))) + ... ('oops')) + ... ) at 0x...> #> ((lambda :x1 x)) ;Control words are strings are iterable. @@ -1220,16 +1199,15 @@ Lissp Whirlwind Tour #.. (lambda (key value) #.. `(.update (globals) : ,key ,value))) >>> globals().update( - ... assign=( - ... lambda key, - ... value: + ... assign=(lambda key, value: ... (lambda * _: _)( ... '.update', ... (lambda * _: _)( ... 'builtins..globals'), ... ':', ... key, - ... value))) + ... value) + ... )) ;; Notice the arguments to it are quoted. @@ -1350,7 +1328,8 @@ Lissp Whirlwind Tour ... (lambda * _: _)( ... '__main__..QzMaybe_.QzPLUS_', ... x, - ... x)))) + ... x)) + ... )) #> (triple 4) ;12 >>> # triple @@ -1371,7 +1350,8 @@ Lissp Whirlwind Tour ... loudQz_number=(lambda x: ... (print( ... x), - ... x) [-1])) + ... x) [-1] + ... )) #> (triple (loud-number 14)) ;Triples the *code*, not just the *value*. >>> # triple @@ -1399,7 +1379,8 @@ Lissp Whirlwind Tour ... x, ... QzPLUS_( ... x, - ... x)))( + ... x)) + ... )( ... loudQz_number( ... (14))) 14 @@ -1416,7 +1397,8 @@ Lissp Whirlwind Tour ... x, ... QzPLUS_( ... x, - ... x)))() + ... x)) + ... )() 14 42 @@ -1444,7 +1426,8 @@ Lissp Whirlwind Tour ... (lambda * _: _)( ... '__main__..QzMaybe_.QzPLUS_', ... '__main__..x', - ... '__main__..x')))))) + ... '__main__..x')))) + ... )) #> (oops-triple 14) ;Oops. Templates qualify symbols! >>> # oopsQz_triple @@ -1453,7 +1436,8 @@ Lissp Whirlwind Tour ... __import__('builtins').globals()['x'], ... __import__('builtins').globals()['QzPLUS_']( ... __import__('builtins').globals()['x'], - ... __import__('builtins').globals()['x'])))() + ... __import__('builtins').globals()['x'])) + ... )() Traceback (most recent call last): ... (lambda __main__..x=(14): @@ -1485,7 +1469,8 @@ Lissp Whirlwind Tour ... (lambda * _: _)( ... '__main__..QzMaybe_.QzPLUS_', ... '_QzIF7WPGTUz___x', - ... '_QzIF7WPGTUz___x')))))) + ... '_QzIF7WPGTUz___x')))) + ... )) #> (once-triple (loud-number 14)) >>> # onceQz_triple @@ -1496,7 +1481,8 @@ Lissp Whirlwind Tour ... _QzIF7WPGTUz___x, ... __import__('builtins').globals()['QzPLUS_']( ... _QzIF7WPGTUz___x, - ... _QzIF7WPGTUz___x)))() + ... _QzIF7WPGTUz___x)) + ... )() 14 42 @@ -1542,7 +1528,8 @@ Lissp Whirlwind Tour ... '__main__..QzMaybe_.QzPLUS_', ... *args))).__getitem__( ... bool( - ... args)))) + ... args)) + ... )) #> (+ 1 2 3 4) >>> # QzPLUS_ @@ -1600,7 +1587,8 @@ Lissp Whirlwind Tour ... second), ... *args)).__getitem__( ... bool( - ... args)))) + ... args)) + ... )) ;; Notice that the stacked expansion comments left by the compiler @@ -1639,13 +1627,12 @@ Lissp Whirlwind Tour #> (functools..reduce (lambda xy (* x y)) ;Invocation, not argument. #.. '(1 2 3 4)) >>> __import__('functools').reduce( - ... ( - ... lambda x, - ... y: + ... (lambda x, y: ... # QzSTAR_ ... __import__('operator').mul( ... x, - ... y)), + ... y) + ... ), ... ((1), ... (2), ... (3), @@ -1674,20 +1661,20 @@ Lissp Whirlwind Tour ... (lambda * _: _)( ... 'X', ... 'Y'), - ... body))) + ... body) + ... )) #> (functools..reduce (XY * X Y) ;Invocation, not argument! #.. '(1 2 3 4)) >>> __import__('functools').reduce( ... # XY - ... ( - ... lambda X, - ... Y: + ... (lambda X, Y: ... # QzSTAR_ ... __import__('operator').mul( ... X, - ... Y)), + ... Y) + ... ), ... ((1), ... (2), ... (3), @@ -1696,14 +1683,13 @@ Lissp Whirlwind Tour #> ((XY + Y X) "Eggs" "Spam") >>> # XY - ... ( - ... lambda X, - ... Y: + ... (lambda X, Y: ... # QzPLUS_ ... __import__('operator').add( ... Y, ... # __main__..QzMaybe_.QzPLUS_ - ... X))( + ... X) + ... )( ... ('Eggs'), ... ('Spam')) 'SpamEggs' @@ -1753,7 +1739,8 @@ Lissp Whirlwind Tour ... (3), ... ':', ... '__main__..sep', - ... sep))) + ... sep) + ... )) ;; Note the : didn't have to be quoted here, because it's in a macro @@ -1820,7 +1807,8 @@ Lissp Whirlwind Tour ... map( ... (lambda f: ... __import__('os').remove( - ... f)), + ... f) + ... ), ... ('eggs.lissp', ... 'spam.lissp', ... 'spam.py', @@ -2022,11 +2010,7 @@ Lissp Whirlwind Tour ;; Hissp may not have operators, but Python does. #> (lambda abc |(-b + (b**2 - 4*a*c)**0.5)/(2*a)|) - >>> ( - ... lambda a, - ... b, - ... c: - ... (-b + (b**2 - 4*a*c)**0.5)/(2*a)) + >>> (lambda a, b, c: (-b + (b**2 - 4*a*c)**0.5)/(2*a)) at 0x...> @@ -2035,12 +2019,10 @@ Lissp Whirlwind Tour #> (lambda abc #.. .#"(-b + (b**2 - 4*a*c)**0.5) #.. /(2*a)") - >>> ( - ... lambda a, - ... b, - ... c: + >>> (lambda a, b, c: ... (-b + (b**2 - 4*a*c)**0.5) - ... /(2*a)) + ... /(2*a) + ... ) at 0x...> diff --git a/docs/macro_tutorial.rst b/docs/macro_tutorial.rst index 754d9991c..ff2f3bea1 100644 --- a/docs/macro_tutorial.rst +++ b/docs/macro_tutorial.rst @@ -419,7 +419,8 @@ Inject: ... (lambda x: ... mul( ... x, - ... x)), + ... x) + ... ), ... range( ... (10)))) @@ -588,13 +589,12 @@ Try this definition. >>> # defmacro ... # hissp.macros.._macro_.let ... ( - ... lambda _QzAW22OE5Kz___fn=( - ... lambda params, - ... *body: + ... lambda _QzAW22OE5Kz___fn=(lambda params, *body: ... (lambda * _: _)( ... 'lambda', ... params, - ... *body)): + ... *body) + ... ): ... (__import__('builtins').setattr( ... _QzAW22OE5Kz___fn, ... '__qualname__', @@ -606,7 +606,8 @@ Try this definition. ... __import__('builtins').globals(), ... '_macro_'), ... 'L', - ... _QzAW22OE5Kz___fn)) [-1])() + ... _QzAW22OE5Kz___fn)) [-1] + ... )() .. code-block:: REPL @@ -619,7 +620,8 @@ Try this definition. ... (lambda x: ... QzSTAR_( ... x, - ... x)), + ... x) + ... ), ... range( ... (10)))) [0, 1, 4, 9, 16, 25, 36, 49, 64, 81] @@ -684,7 +686,8 @@ that `anaphoric macro ` we did in the `primer`. ... 'lambda', ... (lambda * _: _)( ... 'X'), - ... expr)): + ... expr) + ... ): ... (__import__('builtins').setattr( ... _QzAW22OE5Kz___fn, ... '__qualname__', @@ -696,7 +699,8 @@ that `anaphoric macro ` we did in the `primer`. ... __import__('builtins').globals(), ... '_macro_'), ... 'L', - ... _QzAW22OE5Kz___fn)) [-1])() + ... _QzAW22OE5Kz___fn)) [-1] + ... )() .. code-block:: REPL @@ -708,7 +712,8 @@ that `anaphoric macro ` we did in the `primer`. ... (lambda X: ... QzSTAR_( ... X, - ... X)), + ... X) + ... ), ... range( ... (10)))) [0, 1, 4, 9, 16, 25, 36, 49, 64, 81] @@ -785,7 +790,8 @@ Ready? ... (lambda * _: _)( ... 'X', ... 'Y'), - ... expr)): + ... expr) + ... ): ... (__import__('builtins').setattr( ... _QzAW22OE5Kz___fn, ... '__qualname__', @@ -797,19 +803,19 @@ Ready? ... __import__('builtins').globals(), ... '_macro_'), ... 'L2', - ... _QzAW22OE5Kz___fn)) [-1])() + ... _QzAW22OE5Kz___fn)) [-1] + ... )() .. code-block:: REPL #> (L2 * X Y) >>> # L2 - ... ( - ... lambda X, - ... Y: + ... (lambda X, Y: ... QzSTAR_( ... X, - ... Y)) + ... Y) + ... ) at ...> That's another easy template. @@ -848,7 +854,8 @@ Don't panic. ... (lambda * _: _)( ... 'lambda', ... '', - ... _QzXDFV7JLKz___expr)): + ... _QzXDFV7JLKz___expr) + ... ): ... (__import__('builtins').setattr( ... _Qz2D5FNHXZz___fn, ... '__qualname__', @@ -860,7 +867,8 @@ Don't panic. ... __import__('builtins').globals(), ... '_macro_'), ... 'L0', - ... _Qz2D5FNHXZz___fn)) [-1])(), + ... _Qz2D5FNHXZz___fn)) [-1] + ... )(), ... # __main__.._macro_.defmacro ... # hissp.macros.._macro_.let ... ( @@ -868,7 +876,8 @@ Don't panic. ... (lambda * _: _)( ... 'lambda', ... 'A', - ... _QzXDFV7JLKz___expr)): + ... _QzXDFV7JLKz___expr) + ... ): ... (__import__('builtins').setattr( ... _Qz2D5FNHXZz___fn, ... '__qualname__', @@ -880,7 +889,8 @@ Don't panic. ... __import__('builtins').globals(), ... '_macro_'), ... 'L1', - ... _Qz2D5FNHXZz___fn)) [-1])(), + ... _Qz2D5FNHXZz___fn)) [-1] + ... )(), ... # __main__.._macro_.defmacro ... # hissp.macros.._macro_.let ... ( @@ -888,7 +898,8 @@ Don't panic. ... (lambda * _: _)( ... 'lambda', ... 'AB', - ... _QzXDFV7JLKz___expr)): + ... _QzXDFV7JLKz___expr) + ... ): ... (__import__('builtins').setattr( ... _Qz2D5FNHXZz___fn, ... '__qualname__', @@ -900,7 +911,8 @@ Don't panic. ... __import__('builtins').globals(), ... '_macro_'), ... 'L2', - ... _Qz2D5FNHXZz___fn)) [-1])(), + ... _Qz2D5FNHXZz___fn)) [-1] + ... )(), ... # __main__.._macro_.defmacro ... # hissp.macros.._macro_.let ... ( @@ -908,7 +920,8 @@ Don't panic. ... (lambda * _: _)( ... 'lambda', ... 'ABC', - ... _QzXDFV7JLKz___expr)): + ... _QzXDFV7JLKz___expr) + ... ): ... (__import__('builtins').setattr( ... _Qz2D5FNHXZz___fn, ... '__qualname__', @@ -920,7 +933,8 @@ Don't panic. ... __import__('builtins').globals(), ... '_macro_'), ... 'L3', - ... _Qz2D5FNHXZz___fn)) [-1])(), + ... _Qz2D5FNHXZz___fn)) [-1] + ... )(), ... # __main__.._macro_.defmacro ... # hissp.macros.._macro_.let ... ( @@ -928,7 +942,8 @@ Don't panic. ... (lambda * _: _)( ... 'lambda', ... 'ABCD', - ... _QzXDFV7JLKz___expr)): + ... _QzXDFV7JLKz___expr) + ... ): ... (__import__('builtins').setattr( ... _Qz2D5FNHXZz___fn, ... '__qualname__', @@ -940,7 +955,8 @@ Don't panic. ... __import__('builtins').globals(), ... '_macro_'), ... 'L4', - ... _Qz2D5FNHXZz___fn)) [-1])(), + ... _Qz2D5FNHXZz___fn)) [-1] + ... )(), ... # __main__.._macro_.defmacro ... # hissp.macros.._macro_.let ... ( @@ -948,7 +964,8 @@ Don't panic. ... (lambda * _: _)( ... 'lambda', ... 'ABCDE', - ... _QzXDFV7JLKz___expr)): + ... _QzXDFV7JLKz___expr) + ... ): ... (__import__('builtins').setattr( ... _Qz2D5FNHXZz___fn, ... '__qualname__', @@ -960,7 +977,8 @@ Don't panic. ... __import__('builtins').globals(), ... '_macro_'), ... 'L5', - ... _Qz2D5FNHXZz___fn)) [-1])(), + ... _Qz2D5FNHXZz___fn)) [-1] + ... )(), ... # __main__.._macro_.defmacro ... # hissp.macros.._macro_.let ... ( @@ -968,7 +986,8 @@ Don't panic. ... (lambda * _: _)( ... 'lambda', ... 'ABCDEF', - ... _QzXDFV7JLKz___expr)): + ... _QzXDFV7JLKz___expr) + ... ): ... (__import__('builtins').setattr( ... _Qz2D5FNHXZz___fn, ... '__qualname__', @@ -980,7 +999,8 @@ Don't panic. ... __import__('builtins').globals(), ... '_macro_'), ... 'L6', - ... _Qz2D5FNHXZz___fn)) [-1])(), + ... _Qz2D5FNHXZz___fn)) [-1] + ... )(), ... # __main__.._macro_.defmacro ... # hissp.macros.._macro_.let ... ( @@ -988,7 +1008,8 @@ Don't panic. ... (lambda * _: _)( ... 'lambda', ... 'ABCDEFG', - ... _QzXDFV7JLKz___expr)): + ... _QzXDFV7JLKz___expr) + ... ): ... (__import__('builtins').setattr( ... _Qz2D5FNHXZz___fn, ... '__qualname__', @@ -1000,7 +1021,8 @@ Don't panic. ... __import__('builtins').globals(), ... '_macro_'), ... 'L7', - ... _Qz2D5FNHXZz___fn)) [-1])(), + ... _Qz2D5FNHXZz___fn)) [-1] + ... )(), ... # __main__.._macro_.defmacro ... # hissp.macros.._macro_.let ... ( @@ -1008,7 +1030,8 @@ Don't panic. ... (lambda * _: _)( ... 'lambda', ... 'ABCDEFGH', - ... _QzXDFV7JLKz___expr)): + ... _QzXDFV7JLKz___expr) + ... ): ... (__import__('builtins').setattr( ... _Qz2D5FNHXZz___fn, ... '__qualname__', @@ -1020,7 +1043,8 @@ Don't panic. ... __import__('builtins').globals(), ... '_macro_'), ... 'L8', - ... _Qz2D5FNHXZz___fn)) [-1])(), + ... _Qz2D5FNHXZz___fn)) [-1] + ... )(), ... # __main__.._macro_.defmacro ... # hissp.macros.._macro_.let ... ( @@ -1028,7 +1052,8 @@ Don't panic. ... (lambda * _: _)( ... 'lambda', ... 'ABCDEFGHI', - ... _QzXDFV7JLKz___expr)): + ... _QzXDFV7JLKz___expr) + ... ): ... (__import__('builtins').setattr( ... _Qz2D5FNHXZz___fn, ... '__qualname__', @@ -1040,7 +1065,8 @@ Don't panic. ... __import__('builtins').globals(), ... '_macro_'), ... 'L9', - ... _Qz2D5FNHXZz___fn)) [-1])(), + ... _Qz2D5FNHXZz___fn)) [-1] + ... )(), ... # __main__.._macro_.defmacro ... # hissp.macros.._macro_.let ... ( @@ -1048,7 +1074,8 @@ Don't panic. ... (lambda * _: _)( ... 'lambda', ... 'ABCDEFGHIJ', - ... _QzXDFV7JLKz___expr)): + ... _QzXDFV7JLKz___expr) + ... ): ... (__import__('builtins').setattr( ... _Qz2D5FNHXZz___fn, ... '__qualname__', @@ -1060,7 +1087,8 @@ Don't panic. ... __import__('builtins').globals(), ... '_macro_'), ... 'L10', - ... _Qz2D5FNHXZz___fn)) [-1])(), + ... _Qz2D5FNHXZz___fn)) [-1] + ... )(), ... # __main__.._macro_.defmacro ... # hissp.macros.._macro_.let ... ( @@ -1068,7 +1096,8 @@ Don't panic. ... (lambda * _: _)( ... 'lambda', ... 'ABCDEFGHIJK', - ... _QzXDFV7JLKz___expr)): + ... _QzXDFV7JLKz___expr) + ... ): ... (__import__('builtins').setattr( ... _Qz2D5FNHXZz___fn, ... '__qualname__', @@ -1080,7 +1109,8 @@ Don't panic. ... __import__('builtins').globals(), ... '_macro_'), ... 'L11', - ... _Qz2D5FNHXZz___fn)) [-1])(), + ... _Qz2D5FNHXZz___fn)) [-1] + ... )(), ... # __main__.._macro_.defmacro ... # hissp.macros.._macro_.let ... ( @@ -1088,7 +1118,8 @@ Don't panic. ... (lambda * _: _)( ... 'lambda', ... 'ABCDEFGHIJKL', - ... _QzXDFV7JLKz___expr)): + ... _QzXDFV7JLKz___expr) + ... ): ... (__import__('builtins').setattr( ... _Qz2D5FNHXZz___fn, ... '__qualname__', @@ -1100,7 +1131,8 @@ Don't panic. ... __import__('builtins').globals(), ... '_macro_'), ... 'L12', - ... _Qz2D5FNHXZz___fn)) [-1])(), + ... _Qz2D5FNHXZz___fn)) [-1] + ... )(), ... # __main__.._macro_.defmacro ... # hissp.macros.._macro_.let ... ( @@ -1108,7 +1140,8 @@ Don't panic. ... (lambda * _: _)( ... 'lambda', ... 'ABCDEFGHIJKLM', - ... _QzXDFV7JLKz___expr)): + ... _QzXDFV7JLKz___expr) + ... ): ... (__import__('builtins').setattr( ... _Qz2D5FNHXZz___fn, ... '__qualname__', @@ -1120,7 +1153,8 @@ Don't panic. ... __import__('builtins').globals(), ... '_macro_'), ... 'L13', - ... _Qz2D5FNHXZz___fn)) [-1])(), + ... _Qz2D5FNHXZz___fn)) [-1] + ... )(), ... # __main__.._macro_.defmacro ... # hissp.macros.._macro_.let ... ( @@ -1128,7 +1162,8 @@ Don't panic. ... (lambda * _: _)( ... 'lambda', ... 'ABCDEFGHIJKLMN', - ... _QzXDFV7JLKz___expr)): + ... _QzXDFV7JLKz___expr) + ... ): ... (__import__('builtins').setattr( ... _Qz2D5FNHXZz___fn, ... '__qualname__', @@ -1140,7 +1175,8 @@ Don't panic. ... __import__('builtins').globals(), ... '_macro_'), ... 'L14', - ... _Qz2D5FNHXZz___fn)) [-1])(), + ... _Qz2D5FNHXZz___fn)) [-1] + ... )(), ... # __main__.._macro_.defmacro ... # hissp.macros.._macro_.let ... ( @@ -1148,7 +1184,8 @@ Don't panic. ... (lambda * _: _)( ... 'lambda', ... 'ABCDEFGHIJKLMNO', - ... _QzXDFV7JLKz___expr)): + ... _QzXDFV7JLKz___expr) + ... ): ... (__import__('builtins').setattr( ... _Qz2D5FNHXZz___fn, ... '__qualname__', @@ -1160,7 +1197,8 @@ Don't panic. ... __import__('builtins').globals(), ... '_macro_'), ... 'L15', - ... _Qz2D5FNHXZz___fn)) [-1])(), + ... _Qz2D5FNHXZz___fn)) [-1] + ... )(), ... # __main__.._macro_.defmacro ... # hissp.macros.._macro_.let ... ( @@ -1168,7 +1206,8 @@ Don't panic. ... (lambda * _: _)( ... 'lambda', ... 'ABCDEFGHIJKLMNOP', - ... _QzXDFV7JLKz___expr)): + ... _QzXDFV7JLKz___expr) + ... ): ... (__import__('builtins').setattr( ... _Qz2D5FNHXZz___fn, ... '__qualname__', @@ -1180,7 +1219,8 @@ Don't panic. ... __import__('builtins').globals(), ... '_macro_'), ... 'L16', - ... _Qz2D5FNHXZz___fn)) [-1])(), + ... _Qz2D5FNHXZz___fn)) [-1] + ... )(), ... # __main__.._macro_.defmacro ... # hissp.macros.._macro_.let ... ( @@ -1188,7 +1228,8 @@ Don't panic. ... (lambda * _: _)( ... 'lambda', ... 'ABCDEFGHIJKLMNOPQ', - ... _QzXDFV7JLKz___expr)): + ... _QzXDFV7JLKz___expr) + ... ): ... (__import__('builtins').setattr( ... _Qz2D5FNHXZz___fn, ... '__qualname__', @@ -1200,7 +1241,8 @@ Don't panic. ... __import__('builtins').globals(), ... '_macro_'), ... 'L17', - ... _Qz2D5FNHXZz___fn)) [-1])(), + ... _Qz2D5FNHXZz___fn)) [-1] + ... )(), ... # __main__.._macro_.defmacro ... # hissp.macros.._macro_.let ... ( @@ -1208,7 +1250,8 @@ Don't panic. ... (lambda * _: _)( ... 'lambda', ... 'ABCDEFGHIJKLMNOPQR', - ... _QzXDFV7JLKz___expr)): + ... _QzXDFV7JLKz___expr) + ... ): ... (__import__('builtins').setattr( ... _Qz2D5FNHXZz___fn, ... '__qualname__', @@ -1220,7 +1263,8 @@ Don't panic. ... __import__('builtins').globals(), ... '_macro_'), ... 'L18', - ... _Qz2D5FNHXZz___fn)) [-1])(), + ... _Qz2D5FNHXZz___fn)) [-1] + ... )(), ... # __main__.._macro_.defmacro ... # hissp.macros.._macro_.let ... ( @@ -1228,7 +1272,8 @@ Don't panic. ... (lambda * _: _)( ... 'lambda', ... 'ABCDEFGHIJKLMNOPQRS', - ... _QzXDFV7JLKz___expr)): + ... _QzXDFV7JLKz___expr) + ... ): ... (__import__('builtins').setattr( ... _Qz2D5FNHXZz___fn, ... '__qualname__', @@ -1240,7 +1285,8 @@ Don't panic. ... __import__('builtins').globals(), ... '_macro_'), ... 'L19', - ... _Qz2D5FNHXZz___fn)) [-1])(), + ... _Qz2D5FNHXZz___fn)) [-1] + ... )(), ... # __main__.._macro_.defmacro ... # hissp.macros.._macro_.let ... ( @@ -1248,7 +1294,8 @@ Don't panic. ... (lambda * _: _)( ... 'lambda', ... 'ABCDEFGHIJKLMNOPQRST', - ... _QzXDFV7JLKz___expr)): + ... _QzXDFV7JLKz___expr) + ... ): ... (__import__('builtins').setattr( ... _Qz2D5FNHXZz___fn, ... '__qualname__', @@ -1260,7 +1307,8 @@ Don't panic. ... __import__('builtins').globals(), ... '_macro_'), ... 'L20', - ... _Qz2D5FNHXZz___fn)) [-1])(), + ... _Qz2D5FNHXZz___fn)) [-1] + ... )(), ... # __main__.._macro_.defmacro ... # hissp.macros.._macro_.let ... ( @@ -1268,7 +1316,8 @@ Don't panic. ... (lambda * _: _)( ... 'lambda', ... 'ABCDEFGHIJKLMNOPQRSTU', - ... _QzXDFV7JLKz___expr)): + ... _QzXDFV7JLKz___expr) + ... ): ... (__import__('builtins').setattr( ... _Qz2D5FNHXZz___fn, ... '__qualname__', @@ -1280,7 +1329,8 @@ Don't panic. ... __import__('builtins').globals(), ... '_macro_'), ... 'L21', - ... _Qz2D5FNHXZz___fn)) [-1])(), + ... _Qz2D5FNHXZz___fn)) [-1] + ... )(), ... # __main__.._macro_.defmacro ... # hissp.macros.._macro_.let ... ( @@ -1288,7 +1338,8 @@ Don't panic. ... (lambda * _: _)( ... 'lambda', ... 'ABCDEFGHIJKLMNOPQRSTUV', - ... _QzXDFV7JLKz___expr)): + ... _QzXDFV7JLKz___expr) + ... ): ... (__import__('builtins').setattr( ... _Qz2D5FNHXZz___fn, ... '__qualname__', @@ -1300,7 +1351,8 @@ Don't panic. ... __import__('builtins').globals(), ... '_macro_'), ... 'L22', - ... _Qz2D5FNHXZz___fn)) [-1])(), + ... _Qz2D5FNHXZz___fn)) [-1] + ... )(), ... # __main__.._macro_.defmacro ... # hissp.macros.._macro_.let ... ( @@ -1308,7 +1360,8 @@ Don't panic. ... (lambda * _: _)( ... 'lambda', ... 'ABCDEFGHIJKLMNOPQRSTUVW', - ... _QzXDFV7JLKz___expr)): + ... _QzXDFV7JLKz___expr) + ... ): ... (__import__('builtins').setattr( ... _Qz2D5FNHXZz___fn, ... '__qualname__', @@ -1320,7 +1373,8 @@ Don't panic. ... __import__('builtins').globals(), ... '_macro_'), ... 'L23', - ... _Qz2D5FNHXZz___fn)) [-1])(), + ... _Qz2D5FNHXZz___fn)) [-1] + ... )(), ... # __main__.._macro_.defmacro ... # hissp.macros.._macro_.let ... ( @@ -1328,7 +1382,8 @@ Don't panic. ... (lambda * _: _)( ... 'lambda', ... 'ABCDEFGHIJKLMNOPQRSTUVWX', - ... _QzXDFV7JLKz___expr)): + ... _QzXDFV7JLKz___expr) + ... ): ... (__import__('builtins').setattr( ... _Qz2D5FNHXZz___fn, ... '__qualname__', @@ -1340,7 +1395,8 @@ Don't panic. ... __import__('builtins').globals(), ... '_macro_'), ... 'L24', - ... _Qz2D5FNHXZz___fn)) [-1])(), + ... _Qz2D5FNHXZz___fn)) [-1] + ... )(), ... # __main__.._macro_.defmacro ... # hissp.macros.._macro_.let ... ( @@ -1348,7 +1404,8 @@ Don't panic. ... (lambda * _: _)( ... 'lambda', ... 'ABCDEFGHIJKLMNOPQRSTUVWXY', - ... _QzXDFV7JLKz___expr)): + ... _QzXDFV7JLKz___expr) + ... ): ... (__import__('builtins').setattr( ... _Qz2D5FNHXZz___fn, ... '__qualname__', @@ -1360,7 +1417,8 @@ Don't panic. ... __import__('builtins').globals(), ... '_macro_'), ... 'L25', - ... _Qz2D5FNHXZz___fn)) [-1])(), + ... _Qz2D5FNHXZz___fn)) [-1] + ... )(), ... # __main__.._macro_.defmacro ... # hissp.macros.._macro_.let ... ( @@ -1368,7 +1426,8 @@ Don't panic. ... (lambda * _: _)( ... 'lambda', ... 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', - ... _QzXDFV7JLKz___expr)): + ... _QzXDFV7JLKz___expr) + ... ): ... (__import__('builtins').setattr( ... _Qz2D5FNHXZz___fn, ... '__qualname__', @@ -1380,7 +1439,9 @@ Don't panic. ... __import__('builtins').globals(), ... '_macro_'), ... 'L26', - ... _Qz2D5FNHXZz___fn)) [-1])()) [-1])() + ... _Qz2D5FNHXZz___fn)) [-1] + ... )()) [-1] + ... )() Whoa. @@ -1392,15 +1453,13 @@ It totally works too. #> ((L3 add C (add A B)) #.. "A" "B" "C") >>> # L3 - ... ( - ... lambda A, - ... B, - ... C: + ... (lambda A, B, C: ... add( ... C, ... add( ... A, - ... B)))( + ... B)) + ... )( ... ('A'), ... ('B'), ... ('C')) @@ -1408,60 +1467,20 @@ It totally works too. #> (L26) >>> # L26 - ... ( - ... lambda A, - ... B, - ... C, - ... D, - ... E, - ... F, - ... G, - ... H, - ... I, - ... J, - ... K, - ... L, - ... M, - ... N, - ... O, - ... P, - ... Q, - ... R, - ... S, - ... T, - ... U, - ... V, - ... W, - ... X, - ... Y, - ... Z: - ... ()) + ... (lambda A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V, W, X, Y, Z: ()) at ...> #> (L13) >>> # L13 - ... ( - ... lambda A, - ... B, - ... C, - ... D, - ... E, - ... F, - ... G, - ... H, - ... I, - ... J, - ... K, - ... L, - ... M: - ... ()) + ... (lambda A, B, C, D, E, F, G, H, I, J, K, L, M: ()) at ...> #> ((L0 print "Hello, World!")) >>> # L0 ... (lambda : ... print( - ... ('Hello, World!')))() + ... ('Hello, World!')) + ... )() Hello, World! How does this work? @@ -1566,21 +1585,21 @@ We can create numbered X's the same way we created the numbered L's. >>> # defmacro ... # hissp.macros.._macro_.let ... ( - ... lambda _QzAW22OE5Kz___fn=( - ... lambda number, - ... *expr: + ... lambda _QzAW22OE5Kz___fn=(lambda number, *expr: ... (lambda * _: _)( ... 'lambda', ... map( ... (lambda i: ... ('X{}').format( - ... i)), + ... i) + ... ), ... range( ... (1), ... add( ... (1), ... number))), - ... expr)): + ... expr) + ... ): ... (__import__('builtins').setattr( ... _QzAW22OE5Kz___fn, ... '__qualname__', @@ -1592,7 +1611,8 @@ We can create numbered X's the same way we created the numbered L's. ... __import__('builtins').globals(), ... '_macro_'), ... 'L', - ... _QzAW22OE5Kz___fn)) [-1])() + ... _QzAW22OE5Kz___fn)) [-1] + ... )() .. tip:: @@ -1611,28 +1631,16 @@ We can create numbered X's the same way we created the numbered L's. #> (L 10) >>> # L - ... ( - ... lambda X1, - ... X2, - ... X3, - ... X4, - ... X5, - ... X6, - ... X7, - ... X8, - ... X9, - ... X10: - ... ()) + ... (lambda X1, X2, X3, X4, X5, X6, X7, X8, X9, X10: ()) at ...> #> ((L 2 add X1 X2) "A" "B") >>> # L - ... ( - ... lambda X1, - ... X2: + ... (lambda X1, X2: ... add( ... X1, - ... X2))( + ... X2) + ... )( ... ('A'), ... ('B')) 'AB' @@ -1660,14 +1668,16 @@ Let's make a slight tweak. ... map( ... (lambda i: ... ('X{}').format( - ... i)), + ... i) + ... ), ... range( ... (1), ... add( ... (1), ... maxQz_X( ... expr)))), - ... expr)): + ... expr) + ... ): ... (__import__('builtins').setattr( ... _QzAW22OE5Kz___fn, ... '__qualname__', @@ -1679,7 +1689,8 @@ Let's make a slight tweak. ... __import__('builtins').globals(), ... '_macro_'), ... 'L', - ... _QzAW22OE5Kz___fn)) [-1])() + ... _QzAW22OE5Kz___fn)) [-1] + ... )() What is this ``max-X``? @@ -1708,15 +1719,9 @@ Can we just iterate through the expression and check? ... map( ... (lambda x: ... # ors - ... ( - ... lambda x0, - ... x1: - ... x0 or x1())( + ... (lambda x0, x1: x0 or x1())( ... # when - ... ( - ... lambda b, - ... c: - ... c()if b else())( + ... (lambda b, c: c()if b else())( ... is_( ... str, ... type( @@ -1728,17 +1733,19 @@ Can we just iterate through the expression and check? ... ('X([1-9][0-9]*)'), ... x): ... # when - ... ( - ... lambda b, - ... c: - ... c()if b else())( + ... (lambda b, c: c()if b else())( ... match, ... (lambda : ... int( ... match.group( - ... (1))))))())), - ... (lambda : (0)))), - ... expr)))) + ... (1))) + ... )) + ... )() + ... )), + ... (lambda : (0))) + ... ), + ... expr)) + ... )) Does that make sense? @@ -1757,12 +1764,11 @@ It gets the parameters right: #> ((L add X2 X1) : :* "AB") >>> # L - ... ( - ... lambda X1, - ... X2: + ... (lambda X1, X2: ... add( ... X2, - ... X1))( + ... X1) + ... )( ... *('AB')) 'BA' @@ -1778,7 +1784,8 @@ Pretty cool. ... X1, ... add( ... X2, - ... X3)))( + ... X3)) + ... )( ... *('BAR')) Traceback (most recent call last): File "", line 2, in @@ -1808,22 +1815,22 @@ This sounds like a job for recursion. ... map( ... (lambda x: ... # ifQz_else - ... ( - ... lambda b, - ... c, - ... a: - ... c()if b else a())( + ... (lambda b, c, a: c()if b else a())( ... is_( ... type( ... x), ... tuple), ... (lambda : ... flatten( - ... x)), + ... x) + ... ), ... (lambda : ... (lambda * _: _)( - ... x)))), - ... form)))) + ... x) + ... )) + ... ), + ... form)) + ... )) More bundled macros here. @@ -1851,15 +1858,9 @@ Now we can fix ``max-X``. ... map( ... (lambda x: ... # ors - ... ( - ... lambda x0, - ... x1: - ... x0 or x1())( + ... (lambda x0, x1: x0 or x1())( ... # when - ... ( - ... lambda b, - ... c: - ... c()if b else())( + ... (lambda b, c: c()if b else())( ... is_( ... str, ... type( @@ -1871,18 +1872,20 @@ Now we can fix ``max-X``. ... ('X([1-9][0-9]*)'), ... x): ... # when - ... ( - ... lambda b, - ... c: - ... c()if b else())( + ... (lambda b, c: c()if b else())( ... match, ... (lambda : ... int( ... match.group( - ... (1))))))())), - ... (lambda : (0)))), + ... (1))) + ... )) + ... )() + ... )), + ... (lambda : (0))) + ... ), ... flatten( - ... expr))))) + ... expr))) + ... )) Let's try again. @@ -1892,15 +1895,13 @@ Let's try again. #> ((L add X1 (add X2 X3)) #.. : :* "BAR") >>> # L - ... ( - ... lambda X1, - ... X2, - ... X3: + ... (lambda X1, X2, X3: ... add( ... X1, ... add( ... X2, - ... X3)))( + ... X3)) + ... )( ... *('BAR')) 'BAR' @@ -1981,7 +1982,8 @@ You can use the resulting macro as a shorter lambda for higher-order functions: ... (lambda X1: ... add( ... X1, - ... X1)), + ... X1) + ... ), ... range( ... (10)))) [0, 2, 4, 6, 8, 10, 12, 14, 16, 18] @@ -2007,7 +2009,8 @@ you must define them in ``_macro_`` with a name ending in a ``#``. ... lambda _QzAW22OE5Kz___fn=(lambda expr: ... (lambda * _: _)( ... '__main__.._macro_.L', - ... *expr)): + ... *expr) + ... ): ... (__import__('builtins').setattr( ... _QzAW22OE5Kz___fn, ... '__qualname__', @@ -2019,7 +2022,8 @@ you must define them in ``_macro_`` with a name ending in a ``#``. ... __import__('builtins').globals(), ... '_macro_'), ... 'XQzHASH_', - ... _QzAW22OE5Kz___fn)) [-1])() + ... _QzAW22OE5Kz___fn)) [-1] + ... )() We have to escape the ``#`` with a backslash or the reader will parse the name as a tag rather than a symbol @@ -2038,7 +2042,8 @@ It's the way you invoke it (with a reader ``tag#``) that makes it happen at read ... (lambda X1: ... add( ... X1, - ... X1)), + ... X1) + ... ), ... range( ... (10)))) [0, 2, 4, 6, 8, 10, 12, 14, 16, 18] @@ -2052,7 +2057,8 @@ It's the way you invoke it (with a reader ``tag#``) that makes it happen at read ... (lambda X1: ... add( ... X1, - ... X1)), + ... X1) + ... ), ... range( ... (10)))) [0, 2, 4, 6, 8, 10, 12, 14, 16, 18] @@ -2108,7 +2114,8 @@ Catch-All Parameter ... *map( ... (lambda i: ... ('X{}').format( - ... i)), + ... i) + ... ), ... range( ... (1), ... add( @@ -2117,10 +2124,7 @@ Catch-All Parameter ... expr)))), ... ':', ... *# when - ... ( - ... lambda b, - ... c: - ... c()if b else())( + ... (lambda b, c: c()if b else())( ... contains( ... flatten( ... expr), @@ -2128,8 +2132,10 @@ Catch-All Parameter ... (lambda : ... (lambda * _: _)( ... ':*', - ... 'Xi')))), - ... expr)): + ... 'Xi') + ... ))), + ... expr) + ... ): ... (__import__('builtins').setattr( ... _QzAW22OE5Kz___fn, ... '__qualname__', @@ -2141,20 +2147,19 @@ Catch-All Parameter ... __import__('builtins').globals(), ... '_macro_'), ... 'L', - ... _QzAW22OE5Kz___fn)) [-1])() + ... _QzAW22OE5Kz___fn)) [-1] + ... )() .. code-block:: REPL #> (X#(print X1 X2 Xi) 1 2 3 4 5) >>> # __main__.._macro_.L - ... ( - ... lambda X1, - ... X2, - ... *Xi: + ... (lambda X1, X2, *Xi: ... print( ... X1, ... X2, - ... Xi))( + ... Xi) + ... )( ... (1), ... (2), ... (3), @@ -2246,29 +2251,25 @@ Here you go: ... *map( ... (lambda i: ... ('X{}').format( - ... i)), + ... i) + ... ), ... range( ... (1), ... add( ... (1), ... # ors - ... ( - ... lambda x0, - ... x1: - ... x0 or x1())( + ... (lambda x0, x1: x0 or x1())( ... maxQz_X( ... expr), ... (lambda : ... contains( ... flatten( ... expr), - ... 'X')))))), + ... 'X') + ... ))))), ... ':', ... *# when - ... ( - ... lambda b, - ... c: - ... c()if b else())( + ... (lambda b, c: c()if b else())( ... contains( ... flatten( ... expr), @@ -2276,13 +2277,10 @@ Here you go: ... (lambda : ... (lambda * _: _)( ... ':*', - ... 'Xi')))), + ... 'Xi') + ... ))), ... # ifQz_else - ... ( - ... lambda b, - ... c, - ... a: - ... c()if b else a())( + ... (lambda b, c, a: c()if b else a())( ... contains( ... flatten( ... expr), @@ -2293,8 +2291,10 @@ Here you go: ... (lambda * _: _)( ... 'X', ... 'X1'), - ... expr)), - ... (lambda : expr)))): + ... expr) + ... ), + ... (lambda : expr))) + ... ): ... (__import__('builtins').setattr( ... _QzAW22OE5Kz___fn, ... '__qualname__', @@ -2306,7 +2306,8 @@ Here you go: ... __import__('builtins').globals(), ... '_macro_'), ... 'L', - ... _QzAW22OE5Kz___fn)) [-1])() + ... _QzAW22OE5Kz___fn)) [-1] + ... )() .. code-block:: REPL @@ -2319,7 +2320,9 @@ Here you go: ... (lambda X=X1: ... add( ... X, - ... X1))()), + ... X1) + ... )() + ... ), ... range( ... (10)))) [0, 2, 4, 6, 8, 10, 12, 14, 16, 18] @@ -2453,7 +2456,8 @@ This doesn't look too bad if you think of it like a fraction bar. ... (lambda : ... truediv( ... (-X2 + (X2**2 - 4*X1*X3)**0.5), - ... (2*X1))) + ... (2*X1)) + ... ) at ...> Now the formula looks right, @@ -2589,7 +2593,8 @@ Lissp gives us a better option. ... lambda _QzAW22OE5Kz___fn=(lambda x: ... int( ... x, - ... (16))): + ... (16)) + ... ): ... (__import__('builtins').setattr( ... _QzAW22OE5Kz___fn, ... '__qualname__', @@ -2601,7 +2606,8 @@ Lissp gives us a better option. ... __import__('builtins').globals(), ... '_macro_'), ... 'QzDIGITxONE_6QzHASH_', - ... _QzAW22OE5Kz___fn)) [-1])() + ... _QzAW22OE5Kz___fn)) [-1] + ... )() We've defined a tag that turns hexadecimal strings into ints. And it does it so at *read time*. @@ -2663,7 +2669,8 @@ New version. ... int( ... str( ... x), - ... (16))): + ... (16)) + ... ): ... (__import__('builtins').setattr( ... _QzAW22OE5Kz___fn, ... '__qualname__', @@ -2675,7 +2682,8 @@ New version. ... __import__('builtins').globals(), ... '_macro_'), ... 'QzDIGITxONE_6QzHASH_', - ... _QzAW22OE5Kz___fn)) [-1])() + ... _QzAW22OE5Kz___fn)) [-1] + ... )() And now it works as well as the built-in notation. @@ -2767,7 +2775,8 @@ because munging is (mostly) reversible. ... __import__('hissp').demunge( ... str( ... x)), - ... (16))) [-1]): + ... (16))) [-1] + ... ): ... (__import__('builtins').setattr( ... _QzAW22OE5Kz___fn, ... '__doc__', @@ -2783,7 +2792,8 @@ because munging is (mostly) reversible. ... __import__('builtins').globals(), ... '_macro_'), ... 'QzDIGITxONE_6QzHASH_', - ... _QzAW22OE5Kz___fn)) [-1])() + ... _QzAW22OE5Kz___fn)) [-1] + ... )() .. code-block:: REPL @@ -2808,7 +2818,8 @@ Well, with reader macros, you can implement any base you want. ... int( ... str( ... x), - ... (6))) [-1]): + ... (6))) [-1] + ... ): ... (__import__('builtins').setattr( ... _QzAW22OE5Kz___fn, ... '__doc__', @@ -2824,7 +2835,8 @@ Well, with reader macros, you can implement any base you want. ... __import__('builtins').globals(), ... '_macro_'), ... 'QzDIGITxSIX_QzHASH_', - ... _QzAW22OE5Kz___fn)) [-1])() + ... _QzAW22OE5Kz___fn)) [-1] + ... )() .. code-block:: REPL @@ -2858,21 +2870,21 @@ Or you can add floating-point. Python's literal notation can't do that. ... str( ... x)): ... # ifQz_else - ... ( - ... lambda b, - ... c, - ... a: - ... c()if b else a())( + ... (lambda b, c, a: c()if b else a())( ... __import__('re').search( ... ('[.Pp]'), ... x), ... (lambda : ... float.fromhex( - ... x)), + ... x) + ... ), ... (lambda : ... int( ... x, - ... (16)))))()): + ... (16)) + ... )) + ... )() + ... ): ... (__import__('builtins').setattr( ... _QzAW22OE5Kz___fn, ... '__qualname__', @@ -2884,7 +2896,8 @@ Or you can add floating-point. Python's literal notation can't do that. ... __import__('builtins').globals(), ... '_macro_'), ... 'QzDIGITxONE_6QzHASH_', - ... _QzAW22OE5Kz___fn)) [-1])() + ... _QzAW22OE5Kz___fn)) [-1] + ... )() .. code-block:: REPL @@ -3003,7 +3016,8 @@ We can improve this a lot with a custom defmacro. ... (lambda * _: _)( ... 'quote', ... str( - ... x)))): + ... x))) + ... ): ... (__import__('builtins').setattr( ... _QzAW22OE5Kz___fn, ... '__qualname__', @@ -3015,7 +3029,8 @@ We can improve this a lot with a custom defmacro. ... __import__('builtins').globals(), ... '_macro_'), ... 'QzDIGITxONE_0QzHASH_', - ... _QzAW22OE5Kz___fn)) [-1])() + ... _QzAW22OE5Kz___fn)) [-1] + ... )() .. code-block:: REPL @@ -3085,7 +3100,8 @@ but a ``||`` fragment is not the only alternative available: ... x, ... slice( ... (1), - ... None))))): + ... None)))) + ... ): ... (__import__('builtins').setattr( ... _QzAW22OE5Kz___fn, ... '__qualname__', @@ -3097,7 +3113,8 @@ but a ``||`` fragment is not the only alternative available: ... __import__('builtins').globals(), ... '_macro_'), ... 'QzDIGITxONE_0QzHASH_', - ... _QzAW22OE5Kz___fn)) [-1])() + ... _QzAW22OE5Kz___fn)) [-1] + ... )() .. code-block:: REPL @@ -3219,15 +3236,9 @@ Search Hissp's docs if you can't figure out what they do.) ... 'Slicer', ... (), ... # QzPCENT_ - ... ( - ... lambda x0, - ... x1: - ... {x0:x1})( + ... (lambda x0, x1: {x0:x1})( ... '__getitem__', - ... ( - ... lambda X, - ... Y: - ... Y)))()) + ... (lambda X, Y: Y)))()) #> |slicer[-1::-2]| >>> slicer[-1::-2] @@ -3294,7 +3305,8 @@ so we could include that and the ``itemgetter`` call in the expansion. ... 'operator..itemgetter', ... ('slicer{}').format( ... __import__('hissp').demunge( - ... e)))): + ... e))) + ... ): ... (__import__('builtins').setattr( ... _QzAW22OE5Kz___fn, ... '__qualname__', @@ -3306,7 +3318,8 @@ so we could include that and the ``itemgetter`` call in the expansion. ... __import__('builtins').globals(), ... '_macro_'), ... 'SQzHASH_', - ... _QzAW22OE5Kz___fn)) [-1])() + ... _QzAW22OE5Kz___fn)) [-1] + ... )() .. code-block:: REPL @@ -3403,7 +3416,8 @@ Putting that all together we get ... __import__('hissp').readerless( ... '__main__..slicer'), ... __import__('hissp').demunge( - ... e)))): + ... e))) + ... ): ... (__import__('builtins').setattr( ... _QzAW22OE5Kz___fn, ... '__qualname__', @@ -3415,7 +3429,8 @@ Putting that all together we get ... __import__('builtins').globals(), ... '_macro_'), ... 'QzLSQB_QzHASH_', - ... _QzAW22OE5Kz___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 @@ -3579,7 +3594,8 @@ Our previous macro was almost there. ... ('({}[{})').format( ... 'a', ... __import__('hissp').demunge( - ... e)))): + ... e))) + ... ): ... (__import__('builtins').setattr( ... _QzAW22OE5Kz___fn, ... '__qualname__', @@ -3591,7 +3607,8 @@ Our previous macro was almost there. ... __import__('builtins').globals(), ... '_macro_'), ... 'QzLSQB_QzHASH_', - ... _QzAW22OE5Kz___fn)) [-1])() + ... _QzAW22OE5Kz___fn)) [-1] + ... )() It works. @@ -3632,7 +3649,8 @@ but there's a subtle flaw which is reason enough not to follow through with that >>> # let ... (lambda a=(-1): ... (lambda a: (a[a::-2]))( - ... ('abcdefg')))() + ... ('abcdefg')) + ... )() Traceback (most recent call last): ... TypeError: slice indices must be integers or None or have an __index__ method @@ -3646,7 +3664,8 @@ Yet it works fine with ``b``. >>> # let ... (lambda b=(-1): ... (lambda a: (a[b::-2]))( - ... ('abcdefg')))() + ... ('abcdefg')) + ... )() 'geca' See the problem? @@ -3672,7 +3691,8 @@ we should suppress the qualification with a gensym instead of a symbol interpola ... ('({}[{})').format( ... '_QzAVTK4YRWz___G', ... __import__('hissp').demunge( - ... e)))): + ... e))) + ... ): ... (__import__('builtins').setattr( ... _QzAW22OE5Kz___fn, ... '__qualname__', @@ -3684,7 +3704,8 @@ we should suppress the qualification with a gensym instead of a symbol interpola ... __import__('builtins').globals(), ... '_macro_'), ... 'QzLSQB_QzHASH_', - ... _QzAW22OE5Kz___fn)) [-1])() + ... _QzAW22OE5Kz___fn)) [-1] + ... )() Read this carefully. ``$#`` only works inside of templates, diff --git a/docs/primer.rst b/docs/primer.rst index 5aa1a423a..7b0dfb31b 100644 --- a/docs/primer.rst +++ b/docs/primer.rst @@ -94,7 +94,8 @@ and returns its Python translation as a string. (lambda name: print( 'Hello', - name)) + name) +) Python can then run this program as normal. @@ -147,16 +148,13 @@ Let's use it. ... ('lambda',('name') ... ,('print',q('Hello'),'name',),) ... ) -"(\n lambda n,\n a,\n m,\n e:\n print(\n 'Hello',\n name))" +"(lambda n, a, m, e:\n print(\n 'Hello',\n name)\n)" >>> print(_) # Remember, _ is the last result that wasn't None. -( - lambda n, - a, - m, - e: +(lambda n, a, m, e: print( 'Hello', - name)) + name) +) >>> eval(_)('World') Traceback (most recent call last): File "", line 1, in @@ -191,12 +189,13 @@ with the comma this time. ... ('lambda',('name',) ... ,('print',q('Hello'),'name',),) ... ) -"(lambda name:\n print(\n 'Hello',\n name))" +"(lambda name:\n print(\n 'Hello',\n name)\n)" >>> print(_) (lambda name: print( 'Hello', - name)) + name) +) That's better. @@ -316,7 +315,8 @@ Here's our first Hissp program again written that way: >>> (lambda name: ... print( ... 'Hello', - ... name)) + ... name) + ... ) at 0x...> #> (|_| (|quote| |World|)) @@ -825,14 +825,13 @@ respectively: #.. (print args) #.. (print kwargs) ; Body expressions evaluate in order. #.. 42) ; The last value is returned. - >>> ( - ... lambda *args, - ... **kwargs: + >>> (lambda *args, **kwargs: ... (print( ... args), ... print( ... kwargs), - ... (42)) [-1]) + ... (42)) [-1] + ... ) at ...> #> (_ 1 : b :c) @@ -873,19 +872,11 @@ Not having it is the same as putting it last: .. code-block:: REPL #> (lambda (a b c :)) ; No pairs after ':'. - >>> ( - ... lambda a, - ... b, - ... c: - ... ()) + >>> (lambda a, b, c: ()) at ...> #> (lambda (a b c)) ; The ':' was omitted. - >>> ( - ... lambda a, - ... b, - ... c: - ... ()) + >>> (lambda a, b, c: ()) at ...> #> (lambda (:)) ; Colon isn't doing anything. @@ -1806,7 +1797,8 @@ Let's try it: ... (lambda : ... ('print', ... ('quote', - ... 'hello',),))) + ... 'hello',),) + ... )) #> (hello) >>> # hello @@ -1830,7 +1822,8 @@ Let's give it one. Use a template: ... (lambda * _: _)( ... 'quote', ... '__main__..Hello'), - ... name))) + ... name) + ... )) #> (greet 'Bob) >>> # greet @@ -1898,7 +1891,8 @@ A ``_macro_`` namespace is not the same as its module. ... (3), ... ':', ... '__main__..sep', - ... ':'))) + ... ':') + ... )) Notice the ``QzMaybe_`` qualifying ``p``, which means the reader could not determine if ``p`` should be qualified as a global or as a macro, @@ -1948,7 +1942,8 @@ We can resolve the ``QzMaybe_`` the other way by defining a ``p`` macro. ... (lambda *args: ... (lambda * _: _)( ... 'builtins..print', - ... *args))) + ... *args) + ... )) #> (p123) >>> # p123 @@ -1997,7 +1992,8 @@ Note the three reader macros in a row: ``','``. ... (lambda * _: _)( ... 'quote', ... 'Hello'), - ... name))) + ... name) + ... )) #> (greet 'Bob) >>> # greet @@ -2020,7 +2016,8 @@ a "" token might have been a better idea: ... (lambda * _: _)( ... 'builtins..print', ... "('Hello')", - ... name))) + ... name) + ... )) #> (greet 'Bob) >>> # greet @@ -2049,14 +2046,16 @@ But there are times when a function will not do: ... 'lambda', ... (lambda * _: _)( ... 'QzPCENT_'), - ... body))) + ... body) + ... )) #> ((lambda (%) #.. (print (.upper %))) ;This lambda expression #.. "q") >>> (lambda QzPCENT_: ... print( - ... QzPCENT_.upper()))( + ... QzPCENT_.upper()) + ... )( ... ('q')) Q @@ -2065,7 +2064,8 @@ But there are times when a function will not do: >>> # QzPCENT_ ... (lambda QzPCENT_: ... print( - ... QzPCENT_.upper()))( + ... QzPCENT_.upper()) + ... )( ... ('q')) Q @@ -2078,7 +2078,8 @@ But there are times when a function will not do: ... print( ... QzPCENT_.upper(), ... (':'), - ... QzPCENT_)), + ... QzPCENT_) + ... ), ... ('abc'))) A : a B : b diff --git a/src/hissp/compiler.py b/src/hissp/compiler.py index 897896cef..5d4f774a3 100644 --- a/src/hissp/compiler.py +++ b/src/hissp/compiler.py @@ -234,13 +234,12 @@ def function(self, form: Tuple) -> str: ... ,('print','args',) ... ,('print','kwargs',),) ... )) - ( - lambda *args, - **kwargs: + (lambda *args, **kwargs: (print( args), print( - kwargs)) [-1]) + kwargs)) [-1] + ) You can omit the right of a pair with ``:?`` (except the final ``**kwargs``). @@ -260,17 +259,9 @@ def function(self, form: Tuple) -> str: The ``:`` may be omitted if there are no paired parameters. >>> print(readerless(('lambda', ('a','b','c',':',),),)) - ( - lambda a, - b, - c: - ()) + (lambda a, b, c: ()) >>> print(readerless(('lambda', ('a','b','c',),),)) - ( - lambda a, - b, - c: - ()) + (lambda a, b, c: ()) >>> readerless(('lambda', (':',),),) '(lambda : ())' >>> readerless(('lambda', (),),) @@ -286,10 +277,10 @@ def function(self, form: Tuple) -> str: fn, parameters, *body = form assert fn == "lambda" parameters, body = self.parameters(parameters), self.body(body) - param_has_nl = "\n" in parameters - drop = param_has_nl * "\n " - sep = ("\n" in body or param_has_nl) * f"\n{3 * ' '}" - return f"({drop}lambda {parameters}:{sep}{body})" + param_has_nl, body_has_nl = "\n" in parameters, "\n" in body + begin, end = param_has_nl * "\n ", body_has_nl * "\n" + middle = (body_has_nl or param_has_nl) * f"\n{3*' '}" + return f"({begin}lambda {parameters}:{middle}{body}{end})" @_trace def parameters(self, parameters: Iterable) -> str: @@ -299,6 +290,7 @@ def parameters(self, parameters: Iterable) -> str: {":/": "/", ":*": "*"}.get(a, a) for a in takewhile(lambda a: a != ":", parameters) ] + sep = ", " for k, v in _pairs(parameters): if k == ":*": r.append("*" if v == ":?" else f"*{v}") @@ -310,7 +302,8 @@ def parameters(self, parameters: Iterable) -> str: r.append(k) else: r.append(f"{k}={self.form(v)}") - return ",\n".join(r).replace("\n", _PARAM_INDENT) + sep = ",\n" + return sep.join(r).replace("\n", _PARAM_INDENT) @_trace def body(self, body: list) -> str: diff --git a/src/hissp/macros.lissp b/src/hissp/macros.lissp index 3f982caa6..631712e3a 100644 --- a/src/hissp/macros.lissp +++ b/src/hissp/macros.lissp @@ -109,20 +109,19 @@ Hidden doctest adds bundled macros for REPL-consistent behavior. ... __import__('builtins').map( ... (lambda c: ... # ifQz_else - ... ( - ... lambda b, - ... c, - ... a: - ... c()if b else a())( + ... (lambda b, c, a: c()if b else a())( ... __import__('operator').eq( ... c, ... 'b'), ... (lambda : ... print( - ... 'Yes')), + ... 'Yes') + ... ), ... (lambda : ... print( - ... 'No')))), + ... 'No') + ... )) + ... ), ... 'ab')) No Yes @@ -151,7 +150,8 @@ Hidden doctest adds bundled macros for REPL-consistent behavior. ... (1)), ... print( ... (2)), - ... (3)) [-1])()) + ... (3)) [-1] + ... )()) 1 2 3 @@ -182,17 +182,16 @@ Hidden doctest adds bundled macros for REPL-consistent behavior. ... (print( ... c), ... # when - ... ( - ... lambda b, - ... c: - ... c()if b else())( + ... (lambda b, c: c()if b else())( ... __import__('operator').eq( ... c, ... 'b'), ... (lambda : ... (print( ... 'found'), - ... ':break') [-1]))) [-1]), + ... ':break') [-1] + ... ))) [-1] + ... ), ... 'abcd')) a b @@ -220,16 +219,15 @@ Hidden doctest adds bundled macros for REPL-consistent behavior. ... __import__('builtins').map( ... (lambda c: ... # unless - ... ( - ... lambda b, - ... a: - ... ()if b else a())( + ... (lambda b, a: ()if b else a())( ... __import__('operator').eq( ... c, ... 'b'), ... (lambda : ... print( - ... c)))), + ... c) + ... )) + ... ), ... 'abcd')) a c @@ -270,10 +268,12 @@ Hidden doctest adds bundled macros for REPL-consistent behavior. ... x): ... print( ... x, - ... y))(), + ... y) + ... )(), ... print( ... x, - ... y)) [-1])() + ... y)) [-1] + ... )() a b x aa a b @@ -315,7 +315,8 @@ Hidden doctest adds bundled macros for REPL-consistent behavior. ... (3), ... ':', ... '__main__..sep', - ... sep)) [-1]): + ... sep)) [-1] + ... ): ... (__import__('builtins').setattr( ... _QzAW22OE5Kz___fn, ... '__doc__', @@ -331,7 +332,8 @@ Hidden doctest adds bundled macros for REPL-consistent behavior. ... __import__('builtins').globals(), ... '_macro_'), ... 'p123', - ... _QzAW22OE5Kz___fn)) [-1])() + ... _QzAW22OE5Kz___fn)) [-1] + ... )() #> (p123 ::) >>> # p123 @@ -419,10 +421,7 @@ Hidden doctest adds bundled macros for REPL-consistent behavior. #> (defonce CACHE (types..SimpleNamespace : x 1)) >>> # defonce ... # hissp.macros.._macro_.unless - ... ( - ... lambda b, - ... a: - ... ()if b else a())( + ... (lambda b, a: ()if b else a())( ... __import__('operator').contains( ... __import__('builtins').globals(), ... 'CACHE'), @@ -430,7 +429,8 @@ Hidden doctest adds bundled macros for REPL-consistent behavior. ... # hissp.macros.._macro_.define ... __import__('builtins').globals().update( ... CACHE=__import__('types').SimpleNamespace( - ... x=(1))))) + ... x=(1))) + ... )) #> (setattr CACHE 'x 42) >>> setattr( @@ -442,10 +442,7 @@ Hidden doctest adds bundled macros for REPL-consistent behavior. #.. (types..SimpleNamespace : x 1))) >>> # defonce ... # hissp.macros.._macro_.unless - ... ( - ... lambda b, - ... a: - ... ()if b else a())( + ... (lambda b, a: ()if b else a())( ... __import__('operator').contains( ... __import__('builtins').globals(), ... 'CACHE'), @@ -458,7 +455,9 @@ Hidden doctest adds bundled macros for REPL-consistent behavior. ... 'not', ... 'evaluated'), ... __import__('types').SimpleNamespace( - ... x=(1))) [-1])()))) + ... x=(1))) [-1] + ... )()) + ... )) () #> CACHE ; The second defonce had no effect. @@ -492,18 +491,17 @@ Hidden doctest adds bundled macros for REPL-consistent behavior. ;; ... tuple), ;; ... __import__('builtins').dict( ;; ... __doc__=('Simple ordered pair.'), - ;; ... __new__=( - ;; ... lambda cls, - ;; ... x, - ;; ... y: + ;; ... __new__=(lambda cls, x, y: ;; ... tuple.__new__( ;; ... cls, ;; ... (lambda * _: _)( ;; ... x, - ;; ... y))), + ;; ... y)) + ;; ... ), ;; ... __repr__=(lambda self: ;; ... ('Point2D({!r}, {!r})').format( - ;; ... *self))))) + ;; ... *self) + ;; ... )))) ;; ;; #> (Point2D 1 2) ;; >>> Point2D( @@ -526,12 +524,10 @@ Hidden doctest adds bundled macros for REPL-consistent behavior. ;; ... 'Foo', ;; ... (lambda * _: _)(), ;; ... __import__('builtins').dict( - ;; ... __init_subclass__=( - ;; ... lambda cls, - ;; ... /, - ;; ... **kwargs: + ;; ... __init_subclass__=(lambda cls, /, **kwargs: ;; ... print( - ;; ... kwargs))))) + ;; ... kwargs) + ;; ... )))) ;; ;; #> (deftype Bar (Foo : a 1 b 2)) ;; >>> # deftype @@ -569,14 +565,12 @@ Hidden doctest adds bundled macros for REPL-consistent behavior. #> (let-from (a b : :* cs) 'ABCDEFG #.. (print cs b a)) >>> # letQz_from - ... ( - ... lambda a, - ... b, - ... *cs: + ... (lambda a, b, *cs: ... print( ... cs, ... b, - ... a))( + ... a) + ... )( ... *'ABCDEFG') ('C', 'D', 'E', 'F', 'G') B A @@ -605,19 +599,13 @@ Hidden doctest adds bundled macros for REPL-consistent behavior. #.. (print a b c d)) >>> # letQzSTAR_from ... # hissp.macros.._macro_.letQz_from - ... ( - ... lambda ab, - ... cd: + ... (lambda ab, cd: ... # hissp.macros..QzMaybe_.letQzSTAR_from ... # hissp.macros.._macro_.letQz_from - ... ( - ... lambda a, - ... b: + ... (lambda a, b: ... # hissp.macros..QzMaybe_.letQzSTAR_from ... # hissp.macros.._macro_.letQz_from - ... ( - ... lambda c, - ... d: + ... (lambda c, d: ... # hissp.macros..QzMaybe_.letQzSTAR_from ... # hissp.macros.._macro_.progn ... (lambda : @@ -625,9 +613,13 @@ Hidden doctest adds bundled macros for REPL-consistent behavior. ... a, ... b, ... c, - ... d))())( - ... *cd))( - ... *ab))( + ... d) + ... )() + ... )( + ... *cd) + ... )( + ... *ab) + ... )( ... *_.items()) A B C D @@ -637,16 +629,10 @@ Hidden doctest adds bundled macros for REPL-consistent behavior. #.. (print a b c d)) >>> # letQzSTAR_from ... # hissp.macros.._macro_.letQz_from - ... ( - ... lambda ab, - ... cd: + ... (lambda ab, cd: ... # hissp.macros..QzMaybe_.letQzSTAR_from ... # hissp.macros.._macro_.letQz_from - ... ( - ... lambda a, - ... b, - ... c, - ... d: + ... (lambda a, b, c, d: ... # hissp.macros..QzMaybe_.letQzSTAR_from ... # hissp.macros.._macro_.progn ... (lambda : @@ -654,10 +640,13 @@ Hidden doctest adds bundled macros for REPL-consistent behavior. ... a, ... b, ... c, - ... d))())( + ... d) + ... )() + ... )( ... *(lambda * _: _)( ... *ab, - ... *cd)))( + ... *cd)) + ... )( ... *_.items()) A B C D @@ -666,16 +655,13 @@ Hidden doctest adds bundled macros for REPL-consistent behavior. #.. `(,@(.keys _) ,@(.values _)) ; Not always this easy. #.. (print a b c d)) >>> # letQz_from - ... ( - ... lambda a, - ... c, - ... b, - ... d: + ... (lambda a, c, b, d: ... print( ... a, ... b, ... c, - ... d))( + ... d) + ... )( ... *(lambda * _: _)( ... *_.keys(), ... *_.values())) @@ -713,8 +699,10 @@ Hidden doctest adds bundled macros for REPL-consistent behavior. ... my, ... 'x', ... _QzRMG5GSSIz___val), - ... _QzRMG5GSSIz___val) [-1])(), - ... my.x))() + ... _QzRMG5GSSIz___val) [-1] + ... )(), + ... my.x) + ... )() 2 2 ``my#my`` is a shorthand for a new empty namespace. @@ -753,7 +741,8 @@ Hidden doctest adds bundled macros for REPL-consistent behavior. ;; ... (lambda X: ;; ... # QzAT_ ;; ... (lambda *xs: [*xs])( - ;; ... X)), + ;; ... X) + ;; ... ), ;; ... ('abc'))) ;; [['a'], ['b'], ['c']] ;; @@ -817,12 +806,11 @@ Hidden doctest adds bundled macros for REPL-consistent behavior. #> (functools..reduce XY#(op#concat Y X) 'abcd) >>> __import__('functools').reduce( - ... ( - ... lambda X, - ... Y: + ... (lambda X, Y: ... __import__('operator').concat( ... Y, - ... X)), + ... X) + ... ), ... 'abcd') 'dcba' @@ -837,11 +825,7 @@ Hidden doctest adds bundled macros for REPL-consistent behavior. ;; .. code-block:: REPL ;; ;; #> (XYZ#|X*Y == Z| : X math..pi Y 2 Z math..tau) - ;; >>> ( - ;; ... lambda X, - ;; ... Y, - ;; ... Z: - ;; ... X*Y == Z)( + ;; >>> (lambda X, Y, Z: X*Y == Z)( ;; ... X=__import__('math').pi, ;; ... Y=(2), ;; ... Z=__import__('math').tau) @@ -858,12 +842,7 @@ Hidden doctest adds bundled macros for REPL-consistent behavior. ;; .. code-block:: REPL ;; ;; #> (XYZW#|X[Y:Z:W]| "QuaoblcldefHg" -2 1 -2) - ;; >>> ( - ;; ... lambda X, - ;; ... Y, - ;; ... Z, - ;; ... W: - ;; ... X[Y:Z:W])( + ;; >>> (lambda X, Y, Z, W: X[Y:Z:W])( ;; ... ('QuaoblcldefHg'), ;; ... (-2), ;; ... (1), @@ -885,17 +864,10 @@ Hidden doctest adds bundled macros for REPL-consistent behavior. ;; ... # hissp.macros.._macro_.defmacro ;; ... # hissp.macros.._macro_.let ;; ... ( - ;; ... lambda _Qz2D5FNHXZz___fn=( - ;; ... lambda _QzE4JATHEUz___attr, - ;; ... *_QzE4JATHEUz___args, - ;; ... **_QzE4JATHEUz___kwargs: + ;; ... lambda _Qz2D5FNHXZz___fn=(lambda _QzE4JATHEUz___attr, *_QzE4JATHEUz___args, **_QzE4JATHEUz___kwargs: ;; ... ('Aliases ``hissp.._macro_`` as ``HQzCOLON_#``.', ;; ... # hissp.macros.._macro_.ifQz_else - ;; ... ( - ;; ... lambda b, - ;; ... c, - ;; ... a: - ;; ... c()if b else a())( + ;; ... (lambda b, c, a: c()if b else a())( ;; ... _QzE4JATHEUz___args, ;; ... (lambda : ;; ... __import__('builtins').getattr( @@ -904,11 +876,14 @@ Hidden doctest adds bundled macros for REPL-consistent behavior. ;; ... _QzE4JATHEUz___attr, ;; ... 'QzHASH_'))( ;; ... *_QzE4JATHEUz___args, - ;; ... **_QzE4JATHEUz___kwargs)), + ;; ... **_QzE4JATHEUz___kwargs) + ;; ... ), ;; ... (lambda : ;; ... ('{}.{}').format( ;; ... 'hissp.._macro_', - ;; ... _QzE4JATHEUz___attr)))) [-1]): + ;; ... _QzE4JATHEUz___attr) + ;; ... ))) [-1] + ;; ... ): ;; ... (__import__('builtins').setattr( ;; ... _Qz2D5FNHXZz___fn, ;; ... '__doc__', @@ -924,7 +899,8 @@ Hidden doctest adds bundled macros for REPL-consistent behavior. ;; ... __import__('builtins').globals(), ;; ... '_macro_'), ;; ... 'HQzCOLON_QzHASH_', - ;; ... _Qz2D5FNHXZz___fn)) [-1])() + ;; ... _Qz2D5FNHXZz___fn)) [-1] + ;; ... )() ;; ;; #> 'H:#alias ;; >>> 'hissp.._macro_.alias' @@ -1035,9 +1011,11 @@ Hidden doctest adds bundled macros for REPL-consistent behavior. ... __import__('builtins').globals().update( ... spam='spam'), ... str.title( - ... spam)) [-1])()), + ... spam)) [-1] + ... )()), ... str.swapcase( - ... spam)) [-1])()) + ... spam)) [-1] + ... )()) #> spam >>> spam @@ -1088,7 +1066,8 @@ Hidden doctest adds bundled macros for REPL-consistent behavior. ... spam, ... (2), ... _QzE3BPTV2Tz___val), - ... _QzE3BPTV2Tz___val) [-1])() + ... _QzE3BPTV2Tz___val) [-1] + ... )() 10 #> spam @@ -1135,7 +1114,9 @@ Hidden doctest adds bundled macros for REPL-consistent behavior. ... _QzRDZYRDXSz___coll, ... _QzRDZYRDXSz___key, ... _QzE3BPTV2Tz___val), - ... _QzE3BPTV2Tz___val) [-1])())() + ... _QzE3BPTV2Tz___val) [-1] + ... )() + ... )() 11 #> spam @@ -1168,7 +1149,8 @@ Hidden doctest adds bundled macros for REPL-consistent behavior. ... spam, ... 'foo', ... _QzRMG5GSSIz___val), - ... _QzRMG5GSSIz___val) [-1])() + ... _QzRMG5GSSIz___val) [-1] + ... )() 10 #> spam @@ -1209,7 +1191,8 @@ Hidden doctest adds bundled macros for REPL-consistent behavior. ... spam, ... 'foo', ... _QzRMG5GSSIz___val), - ... _QzRMG5GSSIz___val) [-1])() + ... _QzRMG5GSSIz___val) [-1] + ... )() 11 #> spam @@ -1247,7 +1230,8 @@ Hidden doctest adds bundled macros for REPL-consistent behavior. ... _QzWG5WN73Wz___target, ... 'b', ... 'Hi'), - ... _QzWG5WN73Wz___target) [-1])() + ... _QzWG5WN73Wz___target) [-1] + ... )() namespace(a=1, attach=, b='Hi') See also: `setattr`, `set@`, `vars`. @@ -1282,7 +1266,8 @@ Hidden doctest adds bundled macros for REPL-consistent behavior. ... _QzKIUMBHNZz___self.sort(), ... _QzKIUMBHNZz___self.append( ... 'foo'), - ... _QzKIUMBHNZz___self) [-1])() + ... _QzKIUMBHNZz___self) [-1] + ... )() ['a', 'b', 'r', 'foo'] See also: `attach`, `progn`, `-> `. @@ -1321,10 +1306,12 @@ Hidden doctest adds bundled macros for REPL-consistent behavior. >>> # Qz_QzGT_ ... (lambda *_Qz6RFWTTVXz___xs: ... tuple( - ... _Qz6RFWTTVXz___xs))( + ... _Qz6RFWTTVXz___xs) + ... )( ... (lambda *_Qz6RFWTTVXz___xs: ... list( - ... _Qz6RFWTTVXz___xs))( + ... _Qz6RFWTTVXz___xs) + ... )( ... set( ... 'a'), ... 'bc'), @@ -1365,11 +1352,13 @@ Hidden doctest adds bundled macros for REPL-consistent behavior. >>> # Qz_QzLT_QzGT_QzGT_ ... (lambda *_Qz6RFWTTVXz___xs: ... tuple( - ... _Qz6RFWTTVXz___xs))( + ... _Qz6RFWTTVXz___xs) + ... )( ... 'de', ... (lambda *_Qz6RFWTTVXz___xs: ... list( - ... _Qz6RFWTTVXz___xs))( + ... _Qz6RFWTTVXz___xs) + ... )( ... 'bc', ... set( ... 'a')), @@ -1413,40 +1402,38 @@ Hidden doctest adds bundled macros for REPL-consistent behavior. ... __import__('builtins').map( ... (lambda x: ... # cond - ... ( - ... lambda x0, - ... x1, - ... x2, - ... x3, - ... x4, - ... x5, - ... x6, - ... x7: - ... x1()if x0 else x3()if x2()else x5()if x4()else x7()if x6()else())( + ... (lambda x0, x1, x2, x3, x4, x5, x6, x7: x1()if x0 else x3()if x2()else x5()if x4()else x7()if x6()else())( ... __import__('operator').lt( ... x, ... (0)), ... (lambda : ... print( - ... ':Negative')), + ... ':Negative') + ... ), ... (lambda : ... __import__('operator').eq( ... x, - ... (0))), + ... (0)) + ... ), ... (lambda : ... print( - ... ':Zero')), + ... ':Zero') + ... ), ... (lambda : ... __import__('operator').gt( ... x, - ... (0))), + ... (0)) + ... ), ... (lambda : ... print( - ... ':Positive')), + ... ':Positive') + ... ), ... (lambda : ':else'), ... (lambda : ... print( - ... ':Not-a-Number')))), + ... ':Not-a-Number') + ... )) + ... ), ... # QzAT_ ... (lambda *xs: [*xs])( ... (-0.6), @@ -1491,7 +1478,8 @@ Hidden doctest adds bundled macros for REPL-consistent behavior. ... not( ... __import__('operator').mod( ... index, - ... (7)))) [-1]), + ... (7)))) [-1] + ... ), ... range( ... (1), ... (11)))) @@ -1517,13 +1505,12 @@ Hidden doctest adds bundled macros for REPL-consistent behavior. >>> # anyQzSTAR_map ... __import__('builtins').any( ... __import__('itertools').starmap( - ... ( - ... lambda i, - ... c: + ... (lambda i, c: ... print( ... __import__('operator').mul( ... i, - ... c))), + ... c)) + ... ), ... enumerate( ... 'abc', ... (1)))) @@ -1576,10 +1563,7 @@ Hidden doctest adds bundled macros for REPL-consistent behavior. ... # hissp.macros.._macro_.progn ... (lambda : ... # when - ... ( - ... lambda b, - ... c: - ... c()if b else())( + ... (lambda b, c: c()if b else())( ... x, ... (lambda : ... (print( @@ -1589,14 +1573,19 @@ Hidden doctest adds bundled macros for REPL-consistent behavior. ... (lambda *xs: [*xs])( ... __import__('operator').sub( ... x, - ... (1))))) [-1])))()), - ... None) [-1]), + ... (1))))) [-1] + ... )) + ... )()), + ... None) [-1] + ... ), ... __import__('builtins').iter( ... _QzDKFIH6Z2z___stack.pop, ... None))), ... __import__('operator').itemgetter( ... (0))( - ... _QzDKFIH6Z2z___stack)) [-1])())() + ... _QzDKFIH6Z2z___stack)) [-1] + ... )() + ... )() 3 2 1 @@ -1622,11 +1611,7 @@ Hidden doctest adds bundled macros for REPL-consistent behavior. #> (ands True True False) ; and finds the False >>> # ands - ... ( - ... lambda x0, - ... x1, - ... x2: - ... x0 and x1()and x2())( + ... (lambda x0, x1, x2: x0 and x1()and x2())( ... True, ... (lambda : True), ... (lambda : False)) @@ -1634,22 +1619,17 @@ Hidden doctest adds bundled macros for REPL-consistent behavior. #> (ands False (print 'oops)) ; Shortcutting. >>> # ands - ... ( - ... lambda x0, - ... x1: - ... x0 and x1())( + ... (lambda x0, x1: x0 and x1())( ... False, ... (lambda : ... print( - ... 'oops'))) + ... 'oops') + ... )) False #> (ands True 42) >>> # ands - ... ( - ... lambda x0, - ... x1: - ... x0 and x1())( + ... (lambda x0, x1: x0 and x1())( ... True, ... (lambda : (42))) 42 @@ -1684,34 +1664,24 @@ Hidden doctest adds bundled macros for REPL-consistent behavior. #> (ors True (print 'oops)) ; Shortcutting. >>> # ors - ... ( - ... lambda x0, - ... x1: - ... x0 or x1())( + ... (lambda x0, x1: x0 or x1())( ... True, ... (lambda : ... print( - ... 'oops'))) + ... 'oops') + ... )) True #> (ors 42 False) >>> # ors - ... ( - ... lambda x0, - ... x1: - ... x0 or x1())( + ... (lambda x0, x1: x0 or x1())( ... (42), ... (lambda : False)) 42 #> (ors () False 0 1) ; or seeks the truth >>> # ors - ... ( - ... lambda x0, - ... x1, - ... x2, - ... x3: - ... x0 or x1()or x2()or x3())( + ... (lambda x0, x1, x2, x3: x0 or x1()or x2()or x3())( ... (), ... (lambda : False), ... (lambda : (0)), @@ -1788,25 +1758,20 @@ Hidden doctest adds bundled macros for REPL-consistent behavior. ... ( ... lambda _Qz2IKKUCBWz___G=(lambda _Qz2IKKUCBWz___x: ... # hissp.macros.._macro_.ifQz_else - ... ( - ... lambda b, - ... c, - ... a: - ... c()if b else a())( + ... (lambda b, c, a: c()if b else a())( ... # hissp.macros.._macro_.ands - ... ( - ... lambda x0, - ... x1: - ... x0 and x1())( + ... (lambda x0, x1: x0 and x1())( ... __import__('builtins').isinstance( ... _Qz2IKKUCBWz___x, ... __import__('builtins').type), ... (lambda : ... __import__('builtins').issubclass( ... _Qz2IKKUCBWz___x, - ... __import__('builtins').BaseException))), + ... __import__('builtins').BaseException) + ... )), ... (lambda : _Qz2IKKUCBWz___x()), - ... (lambda : _Qz2IKKUCBWz___x))): + ... (lambda : _Qz2IKKUCBWz___x)) + ... ): ... # hissp.macros.._macro_.attach ... # hissp.macros.._macro_.let ... ( @@ -1818,7 +1783,9 @@ Hidden doctest adds bundled macros for REPL-consistent behavior. ... _Qz2IKKUCBWz___G( ... Exception( ... 'message'))), - ... _QzWG5WN73Wz___target) [-1])())()) + ... _QzWG5WN73Wz___target) [-1] + ... )() + ... )()) Traceback (most recent call last): ... Exception @@ -1852,7 +1819,8 @@ Hidden doctest adds bundled macros for REPL-consistent behavior. ... (1)), ... print( ... (2)), - ... _Qz46BJ7IW6z___value1) [-1])()) + ... _Qz46BJ7IW6z___value1) [-1] + ... )()) 1 2 0 @@ -1872,10 +1840,12 @@ Hidden doctest adds bundled macros for REPL-consistent behavior. ... (lambda : ... (print( ... (1)), - ... (3)) [-1])(): + ... (3)) [-1] + ... )(): ... (print( ... (2)), - ... _Qz46BJ7IW6z___value1) [-1])() + ... _Qz46BJ7IW6z___value1) [-1] + ... )() 1 2 3 @@ -1922,7 +1892,8 @@ Hidden doctest adds bundled macros for REPL-consistent behavior. ;; #> (en#list 1 2 3) ;; >>> (lambda *_Qz6RFWTTVXz___xs: ;; ... list( - ;; ... _Qz6RFWTTVXz___xs))( + ;; ... _Qz6RFWTTVXz___xs) + ;; ... )( ;; ... (1), ;; ... (2), ;; ... (3)) @@ -1930,11 +1901,10 @@ Hidden doctest adds bundled macros for REPL-consistent behavior. ;; ;; #> (en#.extend _ 4 5 6) ; Methods too. ;; #.. - ;; >>> ( - ;; ... lambda _Qz4LWLAFU3z___self, - ;; ... *_Qz4LWLAFU3z___xs: + ;; >>> (lambda _Qz4LWLAFU3z___self, *_Qz4LWLAFU3z___xs: ;; ... _Qz4LWLAFU3z___self.extend( - ;; ... _Qz4LWLAFU3z___xs))( + ;; ... _Qz4LWLAFU3z___xs) + ;; ... )( ;; ... _, ;; ... (4), ;; ... (5), @@ -1952,8 +1922,10 @@ Hidden doctest adds bundled macros for REPL-consistent behavior. ;; ... ('').join( ;; ... map( ;; ... str, - ;; ... X)))( - ;; ... _Qz6RFWTTVXz___xs))) + ;; ... X)) + ;; ... )( + ;; ... _Qz6RFWTTVXz___xs) + ;; ... )) ;; ;; #> (enjoin "Sum: "(op#add 2 3)". Product: "(op#mul 2 3)".") ;; >>> enjoin( @@ -1973,12 +1945,12 @@ Hidden doctest adds bundled macros for REPL-consistent behavior. ;; ;; See also: `X# `. ;; - (if-else (ands (op#is_ str (type f)) - (.startswith f ".")) - `(lambda ($#self : :* $#xs) - (,f $#self $#xs)) - `(lambda (: :* $#xs) - (,f $#xs)))) + (if-else (ands (op#is_ str (type f)) + (.startswith f ".")) + `(lambda ($#self : :* $#xs) + (,f $#self $#xs)) + `(lambda (: :* $#xs) + (,f $#xs)))) ;;;; Collection @@ -2054,13 +2026,7 @@ Hidden doctest adds bundled macros for REPL-consistent behavior. #> (% 1 2 :** (dict : x 3 y 4) 5 6) ;Dict, with mapping unpacking. >>> # QzPCENT_ - ... ( - ... lambda x0, - ... x1, - ... x3, - ... x4, - ... x5: - ... {x0:x1,**x3,x4:x5})( + ... (lambda x0, x1, x3, x4, x5: {x0:x1,**x3,x4:x5})( ... (1), ... (2), ... dict( @@ -2222,7 +2188,8 @@ Hidden doctest adds bundled macros for REPL-consistent behavior. ;; ... (lambda e: ;; ... (print( ;; ... ('Oops!')), - ;; ... e) [-1]), + ;; ... e) [-1] + ;; ... ), ;; ... truediv, ;; ... (6), ;; ... (0)) @@ -2260,7 +2227,8 @@ Hidden doctest adds bundled macros for REPL-consistent behavior. ;; ... ZeroDivisionError, ;; ... (lambda e: ;; ... print( - ;; ... ('It means what you want it to mean.'))), + ;; ... ('It means what you want it to mean.')) + ;; ... ), ;; ... truediv, ;; ... ('6'), ;; ... (0)) @@ -2280,25 +2248,20 @@ Hidden doctest adds bundled macros for REPL-consistent behavior. ;; ... ( ;; ... lambda _Qz2IKKUCBWz___G=(lambda _Qz2IKKUCBWz___x: ;; ... # hissp.macros.._macro_.ifQz_else - ;; ... ( - ;; ... lambda b, - ;; ... c, - ;; ... a: - ;; ... c()if b else a())( + ;; ... (lambda b, c, a: c()if b else a())( ;; ... # hissp.macros.._macro_.ands - ;; ... ( - ;; ... lambda x0, - ;; ... x1: - ;; ... x0 and x1())( + ;; ... (lambda x0, x1: x0 and x1())( ;; ... __import__('builtins').isinstance( ;; ... _Qz2IKKUCBWz___x, ;; ... __import__('builtins').type), ;; ... (lambda : ;; ... __import__('builtins').issubclass( ;; ... _Qz2IKKUCBWz___x, - ;; ... __import__('builtins').BaseException))), + ;; ... __import__('builtins').BaseException) + ;; ... )), ;; ... (lambda : _Qz2IKKUCBWz___x()), - ;; ... (lambda : _Qz2IKKUCBWz___x))): + ;; ... (lambda : _Qz2IKKUCBWz___x)) + ;; ... ): ;; ... # hissp.macros.._macro_.attach ;; ... # hissp.macros.._macro_.let ;; ... ( @@ -2310,7 +2273,10 @@ Hidden doctest adds bundled macros for REPL-consistent behavior. ;; ... _Qz2IKKUCBWz___G( ;; ... Exception( ;; ... ('msg')))), - ;; ... _QzWG5WN73Wz___target) [-1])())()))) + ;; ... _QzWG5WN73Wz___target) [-1] + ;; ... )() + ;; ... )()) + ;; ... )) ;; Exception('msg') ;; ;; Ensue examples @@ -2336,12 +2302,15 @@ Hidden doctest adds bundled macros for REPL-consistent behavior. ;; ... step, ;; ... 'Y', ;; ... _QzRMG5GSSIz___val), - ;; ... _QzRMG5GSSIz___val) [-1])(), + ;; ... _QzRMG5GSSIz___val) [-1] + ;; ... )(), ;; ... fibonacci( ;; ... b, ;; ... add( ;; ... a, - ;; ... b))) [-1])))) + ;; ... b))) [-1] + ;; ... )) + ;; ... )) ;; ;; #> (list (islice (fibonacci) 7)) ;; >>> list( @@ -2359,16 +2328,11 @@ Hidden doctest adds bundled macros for REPL-consistent behavior. ;; #.. ;; >>> # define ;; ... __import__('builtins').globals().update( - ;; ... myQz_range=( - ;; ... lambda i, - ;; ... n: + ;; ... myQz_range=(lambda i, n: ;; ... Ensue( ;; ... (lambda step: ;; ... # when - ;; ... ( - ;; ... lambda b, - ;; ... c: - ;; ... c()if b else())( + ;; ... (lambda b, c: c()if b else())( ;; ... lt( ;; ... i, ;; ... n), @@ -2380,12 +2344,16 @@ Hidden doctest adds bundled macros for REPL-consistent behavior. ;; ... step, ;; ... 'Y', ;; ... _QzRMG5GSSIz___val), - ;; ... _QzRMG5GSSIz___val) [-1])(), + ;; ... _QzRMG5GSSIz___val) [-1] + ;; ... )(), ;; ... myQz_range( ;; ... add( ;; ... i, ;; ... (1)), - ;; ... n)) [-1])))))) + ;; ... n)) [-1] + ;; ... )) + ;; ... )) + ;; ... )) ;; ;; #> (list (my-range 1 6)) ;; >>> list( @@ -2416,8 +2384,10 @@ Hidden doctest adds bundled macros for REPL-consistent behavior. ;; ... (3), ;; ... (4), ;; ... (5),)), - ;; ... _QzWG5WN73Wz___target) [-1])(), - ;; ... None) [-1])) + ;; ... _QzWG5WN73Wz___target) [-1] + ;; ... )(), + ;; ... None) [-1] + ;; ... )) ;; <...Ensue object at ...> ;; ;; #> (list _) @@ -2446,7 +2416,10 @@ Hidden doctest adds bundled macros for REPL-consistent behavior. ;; ... _QzWG5WN73Wz___target, ;; ... 'F', ;; ... (1)), - ;; ... _QzWG5WN73Wz___target) [-1])())))) + ;; ... _QzWG5WN73Wz___target) [-1] + ;; ... )() + ;; ... )) + ;; ... )) ;; ;; #> (-> '(1 2 3) recycle (islice 7) list) ;; >>> # Qz_QzGT_ @@ -2474,8 +2447,10 @@ Hidden doctest adds bundled macros for REPL-consistent behavior. ;; ... step, ;; ... 'Y', ;; ... _QzRMG5GSSIz___val), - ;; ... _QzRMG5GSSIz___val) [-1])(), - ;; ... step) [-1]))) + ;; ... _QzRMG5GSSIz___val) [-1] + ;; ... )(), + ;; ... step) [-1] + ;; ... ))) ;; ;; #> (.send echo None) ; Always send a None first. Same as Python. ;; >>> echo.send( @@ -2519,12 +2494,16 @@ Hidden doctest adds bundled macros for REPL-consistent behavior. ;; ... step, ;; ... 'Y', ;; ... _QzRMG5GSSIz___val), - ;; ... _QzRMG5GSSIz___val) [-1])(), + ;; ... _QzRMG5GSSIz___val) [-1] + ;; ... )(), ;; ... Ensue( ;; ... (lambda step: ;; ... print( ;; ... ('exit'), - ;; ... msg)))) [-1]))) [-1]))) + ;; ... msg) + ;; ... ))) [-1] + ;; ... ))) [-1] + ;; ... ))) ;; ;; #> (enter (wrap 'A) ;; #.. (lambda a (print a))) @@ -2533,7 +2512,8 @@ Hidden doctest adds bundled macros for REPL-consistent behavior. ;; ... 'A'), ;; ... (lambda a: ;; ... print( - ;; ... a))) + ;; ... a) + ;; ... )) ;; enter A ;; A ;; exit A @@ -2551,14 +2531,12 @@ Hidden doctest adds bundled macros for REPL-consistent behavior. ;; ... enter, ;; ... wrap( ;; ... 'C'), - ;; ... ( - ;; ... lambda a, - ;; ... b, - ;; ... c: + ;; ... (lambda a, b, c: ;; ... print( ;; ... a, ;; ... b, - ;; ... c))) + ;; ... c) + ;; ... )) ;; enter A ;; enter B ;; enter C @@ -2593,12 +2571,16 @@ Hidden doctest adds bundled macros for REPL-consistent behavior. ;; ... _QzWG5WN73Wz___target, ;; ... 'X', ;; ... ZeroDivisionError), - ;; ... _QzWG5WN73Wz___target) [-1])(), + ;; ... _QzWG5WN73Wz___target) [-1] + ;; ... )(), ;; ... Ensue( ;; ... (lambda step: ;; ... print( ;; ... ('Caught a'), - ;; ... step.sent)))) [-1]))))) + ;; ... step.sent) + ;; ... ))) [-1] + ;; ... )) + ;; ... ))) ;; ;; #> (enter (suppress-zde) ;; #.. (lambda _ (truediv 1 0))) @@ -2607,7 +2589,8 @@ Hidden doctest adds bundled macros for REPL-consistent behavior. ;; ... (lambda _: ;; ... truediv( ;; ... (1), - ;; ... (0)))) + ;; ... (0)) + ;; ... )) ;; Caught a division by zero ;; ;; ;; No exception, so step.sent was .send() value. @@ -2618,7 +2601,8 @@ Hidden doctest adds bundled macros for REPL-consistent behavior. ;; ... (lambda _: ;; ... truediv( ;; ... (4), - ;; ... (2)))) + ;; ... (2)) + ;; ... )) ;; Caught a None ;; 2.0 ;; @@ -2630,7 +2614,8 @@ Hidden doctest adds bundled macros for REPL-consistent behavior. ;; ... # throw ;; ... # hissp.macros.._macro_.throwQzSTAR_ ;; ... (lambda g:g.close()or g.throw)(c for c in'')( - ;; ... Exception))) + ;; ... Exception) + ;; ... )) ;; Traceback (most recent call last): ;; ... ;; Exception @@ -2688,16 +2673,20 @@ except ModuleNotFoundError:pass" ;; ... (lambda *xs: [*xs])( ;; ... (lambda : ;; ... print( - ;; ... ('odd'))), + ;; ... ('odd')) + ;; ... ), ;; ... (lambda : ;; ... print( - ;; ... ('even'))), + ;; ... ('even')) + ;; ... ), ;; ... (lambda : ;; ... print( - ;; ... ('default')))), + ;; ... ('default')) + ;; ... )), ;; ... {1: 0, 3: 0, 'spam': 0, 0: 1, 2: 1, '42': 1}.get( ;; ... x, - ;; ... (-1)))()), + ;; ... (-1)))() + ;; ... ), ;; ... ((1), ;; ... (2), ;; ... 'spam', @@ -2761,7 +2750,8 @@ except ModuleNotFoundError:pass" ... __import__('builtins').repr( ... _Qz764KZBP5z___e), ... file=__import__('sys').stdout), - ... _Qz764KZBP5z___e) [-1])()) + ... _Qz764KZBP5z___e) [-1] + ... )()) ('operator..mul', 7, 3) => 21 26 @@ -2780,10 +2770,7 @@ except ModuleNotFoundError:pass" >>> # hissp.macros.._macro_.let ... (lambda _QzPMWTVFTZz___time=__import__('time').time_ns: ... # hissp.macros.._macro_.letQz_from - ... ( - ... lambda _QzPMWTVFTZz___start, - ... _QzPMWTVFTZz___val, - ... _QzPMWTVFTZz___end: + ... (lambda _QzPMWTVFTZz___start, _QzPMWTVFTZz___val, _QzPMWTVFTZz___end: ... (__import__('builtins').print( ... ('time# ran'), ... __import__('pprint').pformat( @@ -2799,13 +2786,15 @@ except ModuleNotFoundError:pass" ... (1000000.0))), ... ('ms'), ... file=__import__('sys').stdout), - ... _QzPMWTVFTZz___val) [-1])( + ... _QzPMWTVFTZz___val) [-1] + ... )( ... *# hissp.macros.._macro_.QzAT_ ... (lambda *xs: [*xs])( ... _QzPMWTVFTZz___time(), ... __import__('time').sleep( ... (0.05)), - ... _QzPMWTVFTZz___time())))() + ... _QzPMWTVFTZz___time())) + ... )() time# ran ('time..sleep', 0.05) in ... ms See also: `timeit`. @@ -2845,10 +2834,7 @@ except ModuleNotFoundError:pass" ;; ... # hissp.macros.._macro_.let ;; ... (lambda it=(7): ;; ... (# hissp.macros.._macro_.unless - ;; ... ( - ;; ... lambda b, - ;; ... a: - ;; ... ()if b else a())( + ;; ... (lambda b, a: ()if b else a())( ;; ... # hissp.macros.._macro_.Qz_QzGT_ ;; ... (lambda X: X%2 == 0)( ;; ... it), @@ -2858,8 +2844,10 @@ except ModuleNotFoundError:pass" ;; ... (lambda g:g.close()or g.throw)(c for c in'')( ;; ... __import__('builtins').AssertionError( ;; ... it, - ;; ... ("That's odd."))))), - ;; ... it) [-1])() + ;; ... ("That's odd."))) + ;; ... )), + ;; ... it) [-1] + ;; ... )() ;; Traceback (most recent call last): ;; ... ;; AssertionError: (7, "That's odd.") @@ -2911,10 +2899,7 @@ except ModuleNotFoundError:pass" ;; ... # hissp.macros.._macro_.let ;; ... (lambda it=(7): ;; ... (# hissp.macros.._macro_.unless - ;; ... ( - ;; ... lambda b, - ;; ... a: - ;; ... ()if b else a())( + ;; ... (lambda b, a: ()if b else a())( ;; ... # hissp.macros.._macro_.Qz_QzGT_ ;; ... (lambda X: X%2 == 0)( ;; ... it), @@ -2924,8 +2909,10 @@ except ModuleNotFoundError:pass" ;; ... (lambda g:g.close()or g.throw)(c for c in'')( ;; ... __import__('builtins').AssertionError( ;; ... it, - ;; ... ("That's odd."))))), - ;; ... it) [-1])() + ;; ... ("That's odd."))) + ;; ... )), + ;; ... it) [-1] + ;; ... )() ;; Traceback (most recent call last): ;; ... ;; AssertionError: (7, "That's odd.") diff --git a/tests/test_cmd.py b/tests/test_cmd.py index 77e4d3143..e2097ad31 100644 --- a/tests/test_cmd.py +++ b/tests/test_cmd.py @@ -1,4 +1,4 @@ -# Copyright 2020, 2021, 2022 Matthew Egan Odendahl +# Copyright 2020, 2021, 2022, 2024 Matthew Egan Odendahl # SPDX-License-Identifier: Apache-2.0 import subprocess as sp From 22d113a8ef99b78f252a292dc616b1d34294065e Mon Sep 17 00:00:00 2001 From: gilch Date: Thu, 15 Aug 2024 17:31:05 -0600 Subject: [PATCH 10/17] Move refresh#, subrepl# to hissp.__init__ And rewrite in readerless. --- src/hissp/__init__.py | 37 +++++++++++++++++++++++++++++++++++++ src/hissp/macros.lissp | 26 -------------------------- 2 files changed, 37 insertions(+), 26 deletions(-) diff --git a/src/hissp/__init__.py b/src/hissp/__init__.py index c6b1052a6..ff0f13702 100644 --- a/src/hissp/__init__.py +++ b/src/hissp/__init__.py @@ -86,3 +86,40 @@ def alias(abbreviation, qualifier="hissp.macros.._macro_"): See `hissp.macros._macro_.alias`. """ return "hissp.macros.._macro_.alias", abbreviation, qualifier + + +def refresh(module): + """REPL convenience tag to recompile and reload a module. + + Usage: ``hissp..refresh#foo.`` where ``foo.`` evaluates to a module. + + There must be a corresponding ``.lissp`` file present to recompile. + The module must have a ``__name__``. + + ``hissp..refresh#:`` will attempt to recompile the current module. + + Refreshing the main module (which would have side effects) is not + supported. Send the REPL updated top-level definitions individually + or restart the REPL instead. A corresponding compiled Python file is + not required for a ``.lissp`` file run as the main module. + + See also: `subrepl`, `hissp.reader.transpile`, `importlib.reload`. + """ + ns = ("builtins..globals",) if module == ":" else ("builtins..vars", module) + return ( + (('lambda',(':','ns',ns,) + ,('hissp.reader..transpile',('.get','ns',('quote','__package__',),) + ,'ns["__name__"].rpartition(".")[-1]',) + ,('importlib..reload', + ('importlib..import_module',('.get','ns',('quote','__name__',),),),),),) + ) # fmt: skip + + +def subrepl(module): + """Convenience tag to start a Lissp subREPL in the given module. + + Usage: ``hissp..subrepl#foo.`` where ``foo.`` evaluates to a module. + + See also: `hissp.repl.interact`. + """ + return "hissp..interact", ("builtins..vars", module) diff --git a/src/hissp/macros.lissp b/src/hissp/macros.lissp index 631712e3a..6ed65a621 100644 --- a/src/hissp/macros.lissp +++ b/src/hissp/macros.lissp @@ -2922,29 +2922,3 @@ except ModuleNotFoundError:pass" (if-else __debug__ `(avow ,e ,predicate ,@args) e)) - -(defmacro refresh\# (module) - "For interactive use. Attempt to recompile and reload a module. - - There must be a corresponding ``.lissp`` file present to recompile. - The module must have ``__name__`` and ``__package__`` attributes. - - A `:` argument will attempt to recompile the current module. - - Reloading the main module (which would have side effects) is not - supported. Send the REPL updated top-level definitions individually or - restart the REPL instead. A corresponding compiled Python file is not - required for a ``.lissp`` file run as the main module. - - See also: `subrepl#`. - " - `(let ($#ns ,(if-else (op#eq ': module) - `(globals) - `(vars ,module))) - (hissp.reader..transpile (.get $#ns "__package__") - (.get $#ns "__name__")) - (importlib..reload (importlib..import_module (.get $#ns "__name__"))))) - -(defmacro subrepl\# (module) - "For interactive use. Start a Lissp subREPL in the given module." - `(hissp..interact (vars ,module))) From 1d7ae9143b3f31bd7f1c08f4daa68241182efde2 Mon Sep 17 00:00:00 2001 From: gilch Date: Mon, 19 Aug 2024 00:32:02 -0600 Subject: [PATCH 11/17] Expand style guide Add Shadowing subsection Add Prefer Shorter Definitions subsection Add Newlines subsection Expand Comment Styles intro and rationale --- docs/style_guide.rst | 550 +++++++++++++++++++++++++++++++++++++++---- 1 file changed, 505 insertions(+), 45 deletions(-) diff --git a/docs/style_guide.rst b/docs/style_guide.rst index 589da4e02..0f39ddd88 100644 --- a/docs/style_guide.rst +++ b/docs/style_guide.rst @@ -1,4 +1,4 @@ -.. Copyright 2020, 2021, 2022, 2023 Matthew Egan Odendahl +.. Copyright 2020, 2021, 2022, 2023, 2024 Matthew Egan Odendahl SPDX-License-Identifier: CC-BY-SA-4.0 .. Hidden doctest adds bundled macros for REPL-consistent behavior. @@ -15,15 +15,16 @@ Why have a style guide? Code was made for the human, not only for the machine, otherwise we'd all still be writing programs in binary. -Style is not merely a matter of aesthetics. -Consistency lifts a burden from the mind, and, -with experience, improves human performance. -Style is a practical matter. - -Code is written once, and rewritten many times. -It is *read* much more than it is written, -and often by multiple individuals, -so making code easy to read and edit is that much more important than making it easy to write. +Style is a practical matter, +not mere aesthetics. +Consistency lifts a burden from the mind, +improving the performance of the human. + +Code is written once, but rewritten many times. +Code is *read* more than it is written, +and often by multiple individuals. +Therefore, +making code easy to read and edit is much more important than making it easy to write. Learning style is as much about learning to *read* code as it is about learning to write it. Style is the starting point for legibility, @@ -31,6 +32,9 @@ but good style doesn't excuse bad design. Good style is consistent, but good design is elegant. The more elegant designs often employ concepts novices would consider arcane. Choose elegance anyway. +Assume a competent audience. +Learn the concepts yourself. +Consider your design. Refactor your code. Doing that well is an art, but beyond the scope of a style guide. @@ -49,7 +53,7 @@ Don't Count the Brackets ======================== It is impossible for the human to comprehend the code of a nontrivial program in totality; -working memory is too small. +our working memory is too small. We handle complexity by chunking it into hierarchies of labeled black boxes within boxes within boxes. Mental recursive trees. @@ -143,7 +147,7 @@ with Lisp, you have to take on the extra responsibility to keep these two block delimiters in sync. This is hard to do consistently without good editor support. But *because* the brackets make it easy to parse (for a computer), -editor support for Lisp is really very good. +Lisp has structural editing tools that few other languages can match. Emacs can do it, but it's got a bit of a learning curve. For a beginner, try installing `Parinfer `_ in a supported editor, like `Pulsar `_. @@ -339,7 +343,7 @@ We can still unambiguously reconstruct the trails. abc xyz" -The ``"`` is not a bracket, +The closing ``"`` is not a bracket, so we don't delete it or ignore it. Alignment Styles @@ -347,19 +351,29 @@ Alignment Styles The remaining rules are more a matter of that *practical consistency*. Exactly what rules *implement* that consistency matter much less -than the consistency itself. -Know what the rules are for -so you know when to break them. -Sometimes differences of opinion come down to taste. +than the consistency itself, +but it's better if the rules are not too complicated. +A good style guide must be *opinionated* to achieve that consistency. + +Consistency with a style guide is good for the community. +Consistency within a project is a higher priority. +Legibility is paramount. + +When there are gray areas, +don't forget there are better and worse options among the shades. Use your best judgement. -It's not always black and white, -but there are better and worse options among the shades of gray. +This guide often includes a rationale for its recommendations. +Understand what the rules are for so you know when to break them. Lisp is one of the oldest programming languages in common use. It has splintered into many dialects (Lissp among them), with a common culture, but without perfect agreement in all details. Lissp's recommended style is based on these, with some small modifications for its own unique features. +Expect the opinions herein to evolve as Hissp does. + +Some rules pertain to the use of Hissp's bundled macros. +The use of the bundled macros is completely optional. Tuples :::::: @@ -390,12 +404,16 @@ E.g. `dict.update` (on `globals`), `let`, `@##`, `attach`, `doto`. Try to avoid blank lines within forms. You may need them for separating groups whose elements span lines or to separate methods in long classes. -This is a code smell indicating your form may be too complex. +This desire for "paragraphs" is a code smell indicating your form may be too complex. You can use comment lines to separate internal groups instead, but consider refactoring. +Longer imperative entry-point scripts (main and the like) +should be segmented by `let` indentation or similar implied progn forms +without resorting to blank lines. + Blank lines are OK in docstrings, -but comment strings (`<\<#`) -instead of ``""`` tokens are preferred for docstrings when they have more than a single paragraph. +but comment strings (`<\<#`) instead of ``""`` +tokens are preferred for docstrings when they have more than a single paragraph. Keep the elements in a tuple aligned to start on the same column. Treat sibling groups equally: @@ -422,7 +440,7 @@ Your code should look like these examples, recursively applied to subforms: data3 _#/) ;Trails NEVER get their own line. ; But you can hold it open with a discarded item. - ; The / is the usual choice in Lissp, reminiscent of XML. + ; This XML-style / doorstop is the norm in Lissp. (function arg1 arg2 arg3) ;Typical for calls that fit on one line. @@ -494,6 +512,21 @@ Your code should look like these examples, recursively applied to subforms: kw2 kwarg2) + (dict : a 1 b 2 c 3) ;Preferred + + (dict : a 1 ;Standard, but could have fit on one line. + b 2 + c 3) + + (dict : a 1 ;Acceptable if : is first, but be consistent. + b 2 ;Note the alignment with the previous line. + c 3) + + (function arg1 ;Bad. : not first. Weird extra levels. + arg2 + : kw1 kwarg1 + kw2 kwarg2 + (macro special1 special2 special3 ;Macros can have their own alignment rules. body1 ; Simpler macros may look the same as functions. body2 ; Special/body is common. Lambda is also like this. @@ -527,7 +560,7 @@ Your code should look like these examples, recursively applied to subforms: default2 value2) body) - ;; Parameter groups are separated by lines. Pairs are separated by extra space. + ;; Parameter groups are separated by lines. Pairs are separated by an extra space. (lambda (a b :/ ;positional-only group c d ;normal group : e 1 f 2 ;colon group @@ -550,14 +583,12 @@ you may have to turn it off in places. .. code-block:: Python - # fmt: off ('define','fib' ,('lambda',('n',) ,('ifQz_else',('operator..le','n',2,) ,'n' ,('operator..add',('fib',('operator..sub','n',1,),) - ,('fib',('operator..sub','n',2,),),),),),) - # fmt: on + ,('fib',('operator..sub','n',2,),),),),),) # fmt: skip There are a few things to note about tuple commas in readerless. The last element always ends with one (commas are used as terminators, @@ -635,12 +666,48 @@ not just the fact that it's a call. print truediv 6 0) ;(truediv 6 0) is a deferred call, so groups. - (.update (globals) : ;OK. Easier for linewise version control. - + operator..add - - operator..sub - * operator..mul + (partial foo 0 : spam 1 eggs 2) ;Preferred. Note extra space. + + (partial foo ;OK. Standard if above line is too long. + 0 + : spam 1 + eggs 2) + + (partial ;OK. Standard if above line is too long. + foo + 0 + : spam 1 + eggs 2) + + (partial foo 0 ;OK. Deferred call groups. + : spam 1 + eggs 2) + + (partial foo 0 ;Bad. Weird extra indent levels. + : spam 1 + eggs 2) + + (partial foo 0 : ;Avoid. Trailing : is easy to miss. + spam 1 ; : grouped on wrong side. + eggs 2) + + (partial foo : spam 1 ;OK. : first, sort of. Deferred call group. + eggs 2) + + (partial foo : spam 1 ;Bad. Meaningless groupings. + eggs 2) + + (partial foo ;OK. Meaningful groups. + 0 ; foo is acting as the head. + : spam 1 + eggs 2) + + (.update (globals) : ;OK. : on wrong side, but easier + + operator..add ; for linewise version control. + - operator..sub ; Sometimes worth it, but + * operator..mul ; use this style sparingly. / operator..truediv - _#/) + _#/) ;Doorstop holding ) on this line. (.update (globals) ;Preferred. Standard style. : + operator..add @@ -675,10 +742,62 @@ this can be done at read time instead: DON'T INTERRUPT THE FLOW. +Notice the escaped initial newline. +This is optional, +but allows the first line to be aligned with the rest. Because the string was injected (``.#``), don't forget to quote it (``'``), or the compiler will assume the string contents are Python code to be inlined. +Remember that `<\<#` can also make multiline strings. + +.. code-block:: REPL + + #> (print (.upper <<# + #.. ;; These lines + #.. ;; don't interrupt + #.. ;; the flow. + #.. _#/)) + >>> print( + ... "These lines\ndon't interrupt\nthe flow.".upper()) + THESE LINES + DON'T INTERRUPT + THE FLOW. + +Notice the required doorstop and identical compilation. +You can avoid the doorstop by using the `->` macro. + +.. code-block:: REPL + + #> (print (-> <<# + #.. ;; These lines + #.. ;; don't interrupt + #.. ;; the flow. + #.. .upper)) + >>> print( + ... # Qz_QzGT_ + ... "These lines\ndon't interrupt\nthe flow.".upper()) + THESE LINES + DON'T INTERRUPT + THE FLOW. + +The following more compact style is acceptable. +It's similar to not escaping the initial newline in a ``""`` string, +so the first line isn't aligned. The comment block still parses properly. + +.. code-block:: REPL + + #> (print (-> <<# ; These lines + #.. ;; don't interrupt + #.. ;; the flow. + #.. .upper)) + >>> print( + ... # Qz_QzGT_ + ... "These lines\ndon't interrupt\nthe flow.".upper()) + THESE LINES + DON'T INTERRUPT + THE FLOW. + With the principal exception of docstrings, long multiline strings should be declared at the `top level`_ and referenced by name. @@ -707,10 +826,79 @@ Put the closing quote for any multiline docstring on its own line. Comment Styles :::::::::::::: +Remember, readability counts. +Commentary should create clarity, not confusion. + Avoid adding superfluous "what"-comments that are obvious from looking at the code. -(Except perhaps when writing beginner documentation ;) +(Except perhaps when writing language documentation for beginners ;) Prefer "why"-comments that describe rationale or intent. +Your code is probably not as "self-documenting" as you think it is. +Assume your reader is competent, not omniscient. + +If "what"-comments still seem necessary, +consider how to make the code itself clearer, +so the "what"-comments would become obvious by looking at the code. + +Software development is fundamentally research, not manufacturing or construction. +URLs citing sources used can be appropriate, +especially for copied/adapted code, but also for rationale or technique. +Don't just drop in a URL; say what it's for. +URLs are not the only type of reference. + +Comments are appropriate for pointing out issues that cannot be fixed yet, +perhaps awaiting a library update. +Code that is only needed temporarily +(perhaps working around issues that cannot be fixed yet) +should have a comment with removal criteria. +Comments can be appropriate for pointing out non-obvious coupling between files, +on both sides, and should be positioned close to likely changes. + +Some programmers these days are so afraid of stale comments that they +refuse to document their code at all, +and remove what comments they can find. +This is agile culture taken too far. +Good names are important, but they aren't enough, +and don't excuse neglect of commentary. +Names can become stale too; they're not immune just because they're code. + +"Working software over comprehensive documentation" +doesn't mean literally zero documentation. +It doesn't even mean asymptotically zero documentation as an ideal to strive for. +It means that the documentation is not what delivers the bulk of the value, +and that thorough documentation does not excuse software that doesn't work +(or doesn't work yet). + +Version control commit messages are also documentation. +Those are attached to particular versions, so they can't become stale, +and aren't a burden to maintain, but they're still valuable history. +You can write more than a single line. +Take the opportunity to explain what you were thinking. +A few sentences don't take that much time, but can save a lot later. + +Documentation is a burden, just as code is a liability. +Don't accept more of either than delivers value. +Remove or fix bad comments, as appropriate. +Check the version control history for more clues. + +Prefer documentation that is located as close as possible to what it documents, +so it doesn't get out of sync as easily, +and then actually read the commentary before modifying existing code. + +Don't manually write separate API docs. +Generate it from your docstrings with something like Sphinx. +A docstring in a script, with doctests, +is better than a manually-written separate README file +with the same information. + +Prefer assertions over comments documenting assumptions. +These don't go stale, or you'd notice. +Of the assertion types, prefer `avow` over `assure` over `doctest` over `unittest`, +which is best for more thorough tests of edge cases that would otherwise +bloat the more local documentation too much. +Functional tests are also a kind of documentation. +Readability counts, even there, and testing commentary can be especially valuable. +Functional tests make good debugging entry points. .. code-block:: Lissp @@ -767,6 +955,10 @@ comment styles follow the same rules as normal Python.) Lisp traditionally uses margin comments instead (as described below), but this inline style is also common in Clojure. +Avoid obtuse abbreviations just to make a comment fit in line. +When a comment needs to be longer to be clear, +use a different comment style instead. + Margin Comments ;X ++++++++++++++++++ @@ -820,7 +1012,7 @@ then it's a margin comment. Indent it to the margin. Avoid using either margin or inline comments in any situation that would result in a dangling bracket. It's not acceptable for the comment to follow the bracket either, if the comment isn't about the whole tuple. -You may instead hold open the bracket with ``_#/)``, +You may instead hold open the bracket with a doorstop ``_#/)``, convert the comment to a discarded string ``_#"NB foo")``, or (if appropriate) use a form/group ``;;`` comment above the item, as described below. @@ -830,6 +1022,8 @@ or (if appropriate) use a form/group ``;;`` comment above the item, as described Comments about the next form (or group) begin with two semicolons and a space ``;; x``, and are indented to align as if they were forms, and are not followed by a blank line. +These comments can be continued with additional lines with the same indent and beginning, +forming a comment block. Commented-out code does not belong in version control, but disabling code without deleting it can be helpful during development. @@ -845,6 +1039,8 @@ Top-level commentary lines not attached to any form in particular begin with three semicolons and a space ``;;; Foo Bar``. Top-level comments are separated from code with a blank line. They are not indented. +These comments can be continued with additional lines with the same beginning, +forming a comment block. Standard usage for more than two semicolons varies with Lisp dialect, but they are consistently ony for the `top level`_ and have no indent. @@ -854,7 +1050,10 @@ but differ on which is which. To avoid confusion, do not use triple-semicolon comments as headings at all. -Prefer module docstrings over top-level comments where applicable +Prefer a module docstring over top-level comments where applicable. +Remember that a `<\<#` +applied to a comment block compiles to a string literal, +which can be a docstring. ;;;; Headings +++++++++++++ @@ -866,6 +1065,7 @@ and are written in ``Title Case`` by default. Headings are for the `top level`_ only; they aren't nested in forms; they get their own line and start at the beginning of it. They have a blank line before (unless it's the first line) and after. +They should not have additional continuation lines. They organize the code into sections. Headings can be decorated with symbol characters to make them more emphatic. @@ -933,13 +1133,17 @@ Start at the top and work your way down: there should be only one H1 in a file (the title); keep the H2's for your major sections; and proceed in numerical order H3, H4, etc., without skipping any heading levels. -This will minimize the number of heading style changes you need to make if you later find that you need another level. +This will minimize the number of heading style changes you need to make +if you later find that you need another level. (This means that if you do not use all six levels, you will not have any undecorated H6's at all.) +Multiple H1s might be acceptable for large projects distributed as a single concatenated +Lissp file, where they'd head what would normally be modules in separate files. _#_#_#The Discard Macro +++++++++++++++++++++++ -The discard macro ``_#`` applied to a ``""`` token is acceptable for long block comments. +The discard macro ``_#`` applied to a ``""`` token is acceptable for long block comments +at the top level. Several discard macros may be used in a row to comment out that many forms following them. @@ -950,7 +1154,8 @@ executing any reader macros). As with line comments, commented-out code does not belong in shared version control; old versions should be in old commits. -Move the functionality you need to keep out of the comments or into scripts. +Move the manually-executed functionality you need to keep out of the comments +and into functions run by a `name_equals_main` guard or separate scripts. Move the experiments you want to keep running to assertions (See `assure`, `unittest`, and `doctest`). @@ -974,17 +1179,19 @@ or newlines and ``;;`` lines would spread things out too much, it is acceptable to additionally use discarded symbols like ``_#,`` within a line to indicate greater separation than the extra spaces. +These are also used in the doorstop ``_#/`` used to hold open a trail of brackets. + "Docstrings" ++++++++++++ -Prefer docstrings over comments where applicable. +Prefer docstrings over semicolon comments where applicable. Docstrings describe interface and usage; they are not for irrelevant implementation details internal to their containing object. "Private" helper functions/classes/modules (conventionally named with a leading underscore) need not have docstrings at all, -but again, prefer docstrings over comments when applicable, +but still, prefer docstrings over comments when applicable, in which case they describe an interface internal to their object's container, but still do not describe their object's implementation details. @@ -995,8 +1202,8 @@ The ``lambda`` special form does not create docstrings. However, you can attach a ``.__doc__`` attribute to the lambda object after creating it, e.g., using the `attach` macro. -The bundled `deftype` macro does not have any special case for docstrings. -Instead add a ``__doc__`` as its first key. +The bundled `once-deftype` macro does not have any special case for docstrings. +Instead add a ``__doc__`` attribute. Indent docstrings to the same column as their opening ``"`` even when using something like the attach macro. @@ -1020,7 +1227,7 @@ MyST Markdown also has pretty good support now. You can automatically generate API documentation with either of these. Anaphoric or code string–injection macros are potential gotchas. -Docstrings for them should include the word "Anaphoric" or "Injection" up front. +Docstrings for these should include the word "Anaphoric" or "Injection" up front. Anaphoric macro docstrings should also state what the anaphors are, named in doubled backticks. @@ -1079,6 +1286,205 @@ let the munger do the munging for you. Avoid writing anything in the Quotez style yourself. (This can confuse the demunger and risks collision with compiler-generated names like gensyms.) +Abbreviated (even single-character) +local identifiers are acceptable if their lexical scope is very small, +preferably within the same line or the next few, +especially if their initial binding makes their meaning clear. +This includes `X#` and friends. +Parameter names of public-facing functions are considered part of their interface, +since they can be passed as kwargs, +and should be more descriptive in most cases. +Single-letter names following a strong mathematical or coding conventions +may be clear enough even over wider scopes. + +It's idiomatic in Lissp to use a symbol as the parameters when they'd each be one +(non-munging) character. + +.. code-block:: Lissp + + (lambda abc (print c b a)) ;Preferred + + (lambda (a b c) ;OK + (print c b a)) + + ;;; This goes for macro arguments directly used as params too. + + (let-from abc 'XYZ (print c b a)) ;Preferred + + (let-from (a b c) ;OK + 'XYZ + (print c b a)) + + (any*map kv (.items (dict : a 1 b 2)) ;Preferred + (print k v)) + + (any*map (k v) ;OK + (.items (dict : a 1 b 2)) + (print k v)) + +Avoid abbreviating local identifiers otherwise. +Remember to optimize for readability rather that writability; +don't make the reader guess, +but assume a competent audience. +Avoid excessively long names; bloat is not readable either. +Descriptive names do not excuse bad design. + +Conventional short names include, but are not limited to, +* ``i`` and ``j``, in that order, for integer indexes, +* ``k`` and ``v`` for "key" and "value" when iterating over a mapping, +* ``kvs`` for a mapping (or other iterable of key-value pairs). +* ``ks`` or ``vs`` for iterables of keys or of values. +* ``xss`` or ``yss` for iterables of iterables. +* ``xs`` or ``ys`` for iterables, especially if pulled from ``xss`` or ``yss``. +* ``x`` or ``y`` for elements pulled, especially from ``xs`` or ``ys``. +* ``f``, or ``g`` for function parameters or locals. +* ``n`` for an integer parameter, especially if it's a size. +* ``s`` for a string parameter or local. +* ``b`` for a boolean parameter. +* ``e`` for an exception. + +Throwaway locals should begin with an underscore. +Some macros or higher-order functions require you to create a binding even when it's useless. +For example, :ref:`engarde `'s exception handler must accept an exception. +If you're going to use it, you can call it ``e``, +but if you're not, call it ``_e`` instead. +Don't let this stop you from using `X#` to make a handler, +or when otherwise appropriate. + +In rare cases, a function may have a mutable default used as a cache. +Often it's better to put this cache somewhere else, +but sometimes definition time is the right level. +Use an argument name starting with an underscore to indicate this is a "private" +implementation detail not meant to be part of the function's interface. +These parameters should not be passed in, except perhaps by tests. +This doesn't conflict with the throwaway case because the existence of the default +argument distinguishes them. + +Shadowing +::::::::: + +While frowned upon in Python with its relatively small number of builtins, +using a built-in function name as a local is more acceptable in a Lisp-2 +which typically has a lot more built-in functions and separate +function and variable namespaces anyway. + +Although Hissp is dynamic enough to change this, it is a Lisp-1 by default, +because Python also uses a common namespace for both. +Lisp-1s often avoid shadowed function names by using awkward workaround abbreviations, +like ``lst`` for ``list``. +One can get used to these, but they do impair readability. +Python's solution is to append an underscore to unavailable names. +This convention is acceptable in Hissp, +but occasionally the appended name is also taken. +A modified Smalltalk-like convention like ``a-list`` is also acceptable, +or ``a_list`` especially for a parameter that might be called with syntax like +``a_list=foo`` from Python code, to avoid munging. + +Shadowing locals is acceptable, +and can be thought of as a reassignment. +Local binding forms have a restricted lexical scope +which makes them easier to reason about than Python's local (re)assignment statements. +Hissp functions often immediately convert parameters to a more useful form in a `let` +and shadow them with the same names. +Be more careful in imperative scripts where lexical scopes can be larger. +Consider if multiple smaller scopes are more readable. + +Shadowing of builtins is a source of potential errors, +so it is preferable that you do not, +but lexical scoping handles this acceptably. +This preference should be extended to a module's globals, including the `prelude`'s +star-imports of `operator` and `itertools`. +Python's naming conventions for classes (``CapWords``) and "constants" +(``UPPER_CASE_WITH_UNDERSCORES``) usually prevents local collisions with those, +but function and module names can be a problem. +Prefer aliases over defining globals of module type. + +Name top-level helper functions that are only being used inside your module +(or by tests, internal or not) with a leading underscore. +This is the Python convention for a "private" global, +although not much enforces it. +You can always rename these later if you need to. +You'll only have to update usages in the module. +(The reverse is harder, but shouldn't be done while there are any external usages left.) +This aids in readability, because it makes it easy to tell +what functions are interface and what's implementation detail. +It also narrows the space of possible local collisions to the public interface functions. + +However, memorizing which names are off-limits puts an undue burden on the writer, +especially for a REPL-driven rather than IDE-driven language like Lissp. +For reasonably short functions, it's clear what the locals are from their binding forms. +Macro definitions should be robust enough to handle a shadowed builtin. +Lissp's template syntax makes this fairly easy as it qualifies symbols by default. +You have to go out of your way to turn this off for anaphors. + +You are free to use the fully-qualified names in handwritten code as well. +Using a fully-qualified name is preferred over +changing a shadowing parameter name in an established public-facing function. +Parameter names are considered part of the interface, +especially when they can be passed as kwargs +(includes normal positional parameters, not just the kwonlies). +Changing positional-only parameters is more acceptable, +but beware that this change does show up in `help`, +automated API documentation, and the like. + +For these reasons, shadowing a global or builtins isn't considered unacceptable in Lissp +like it is in other languages you might know. +It's better to avoid it, but don't worry about it too much, +and don't go out of your way to correct it either. + +Aliasing and Imports +:::::::::::::::::::: + +Avoid repeating the name of the containing module or package when writing definitions, +because they may be accessed through an alias or as a module attribute. + +The reader should not have to guess what an alias means when jumping into an unfamiliar file. +Use consistent aliases within a project. +Usually, this means the alias is the module name, but not its containing packages, +unless there is a shorter well-known name in the community +(like ``np#`` for NumPy or ``op#`` for operators) +or for an internal module well-known within your project. + +When you want an alias both for a module and its macro namespace, +use the alias for its macro namespace and define a +global with the same name for the module: + +.. code-block:: Lissp + + (alias baz foo.bar.baz.._macro_.) + (define _baz foo.bar.baz.) + + ;; Use a macro like + (baz#my-macro ...) + + ;; Use a callable like + (_baz.my-callable ...) + +Non-Hissp Python modules don't have a macro namespace and won't have this conflict. +Aliases may be preferable in that case, +because they have the advantage of never colliding with your module's global function names, +although would use up a tag name instead, +you probably won't have as many of those. + +Avoid redefining (non-module) globals from other modules. +Just access them from the module they belong to. +This improves readability, +and for internal project modules, +improves reloadability during REPL-driven development. +Otherwise, instead of just refreshing the module with the updated definition, +every module redefining it would have to be reloaded as well. + +Sometimes separate packages use the same module name internally. +Aliases are allowed to contain a dot. +(Fully-qualified tags have a double dot.) +Usually, you'd alias as the library's root package name followed by a dot, +followed by the module name. +Given Python's "flat is better than nested" culture, +many library packages have no subpackages, +so this may not be any shorter than using the fully-qualified name. + +Prefer using aliases over attaching macros to `_macro_`. + Method Syntax vs Attribute Calls :::::::::::::::::::::::::::::::: @@ -1092,7 +1498,7 @@ Which is preferred then depends on whether ``bar`` is a namespace or an argument For a namespace, prefer ``bar.foo``. Internal use of ``self`` in methods and ``cls`` in classmethods, is also more namespace than argument. -For an argument, i.e. other method calls, prefer ``.foo bar``. +For an argument, i.e., other method calls, prefer ``.foo bar``. .. code-block:: Lissp @@ -1102,7 +1508,7 @@ For an argument, i.e. other method calls, prefer ``.foo bar``. ;;;; Arguments (.upper "hi") ;Preferred. - ("hi".upper) ;SyntaxError + ("hi".upper) ;SyntaxError. (.upper greeting) ;Preferred. (greeting.upper) ;Bad. @@ -1123,6 +1529,8 @@ For an argument, i.e. other method calls, prefer ``.foo bar``. ;; self as namespace, self.accumulator as argument (.append self.accumulator x) ;Good use of both. +.. TODO: consider usage recommendations for individual bundled macros. + The End of the Line =================== @@ -1211,6 +1619,58 @@ even in an implied group. (gt lxs lys) (print ">") :else (print "0"))))) +Prefer Shorter Definitions +:::::::::::::::::::::::::: + +Pure functions and especially methods of a class should be kept very short, +implementing a single easily-testable concept or perhaps a few very closely related ones. +Build up a vocabulary of definitions so the requisite function becomes easily expressible. +Function definition bodies should be no more than 10 lines, and usually no more than 5. +That's not counting comments, assertions, or parameters. + +This rule doesn't apply to imperative scripts used near the top of the call stack +(main, or similar entry points) +once the pure functional bits have been factored out. +At that point, lexical locality is more important for readability, +so it's better to leave them long than to break them up. + +Avoid more than four heterogeneous positional parameters without a very good reason. +This limit doesn't apply to homogeneous star args or kwonly arguments (usually options), +although that isn't license to overcomplicate functions. +The order of arguments is often meaningless, +and imposing any particular permutation becomes harder to justify the more there are. +Zero or one positional parameters have one obvious answer. Two only has two to consider. +These are fine. Three has six. Are you sure you picked the best one? +Four already has 24 permutations, which, realistically, +you're not likely to consider exhaustively, +so you need a good reason to nail at least one of them down. +It just gets worse from there. The factorial sequence grows pretty quickly. +Why not make it easy and use meaningful names instead of meaningless positions? +Kwonly is there for you. + +Remember that macro definitions can use helper functions. +Some macros are effectively a convenience wrapper over what could otherwise be a function. +It's best to implement and provide that function as well, +because functions can be easier to compose and pass as arguments. + +Newlines +:::::::: + +Prefer Unix-style LF over the Dos/Windows CRLF for files in version control +that might be used on non-Windows systems. +(Macintosh CR files are obsolete. Modern MacOS and Linux use LF.) +Even on Windows, most code editors can handle LF files. +When in doubt, pick LF. + +A file that does not end in a newline is not (strictly speaking) a text file; +they're line *terminators*, not separators. +Although some tooling can handle this particular malformation gracefully, +the Lissp reader cannot in all cases. + +`transpile_file` (used by `transpile` and `transpile_packaged`) +always produces LF ``.py`` files, even on Windows. +Python doesn't mind. + Avoid Trailing Whitespace ::::::::::::::::::::::::: From 27688b5b8ca3e1a71e19671203e7ec079f342b85 Mon Sep 17 00:00:00 2001 From: gilch Date: Mon, 19 Aug 2024 00:33:39 -0600 Subject: [PATCH 12/17] Reword some lissp_whirlwind_tour.rst comments up to section 15 --- docs/lissp_whirlwind_tour.rst | 30 ++++++++++++++++++------------ 1 file changed, 18 insertions(+), 12 deletions(-) diff --git a/docs/lissp_whirlwind_tour.rst b/docs/lissp_whirlwind_tour.rst index ec96bcfed..e67783126 100644 --- a/docs/lissp_whirlwind_tour.rst +++ b/docs/lissp_whirlwind_tour.rst @@ -1,4 +1,4 @@ -.. Copyright 2020, 2021, 2022, 2023 Matthew Egan Odendahl +.. Copyright 2020, 2021, 2022, 2023, 2024 Matthew Egan Odendahl SPDX-License-Identifier: Apache-2.0 .. This hidden doctest adds bundled macros for REPL-consistent behavior. @@ -38,6 +38,11 @@ Lissp Whirlwind Tour Familiarity with another Lisp dialect is not assumed, but helpful. If you get confused or stuck, look for the Hissp community chat or try the more expository Hissp Primer. + + You are expected to read through the sections in order. New concepts + will be presented incrementally. Examples of a new concept will + otherwise be limited to what has been demonstrated so far, which may + not be their most natural expression. " ;;;; 1 Installation @@ -149,7 +154,7 @@ Lissp Whirlwind Tour ;;;; 3 Simple Tuples - ;; Tuples group any atoms with (). Data tuples start with '. + ;; Tuples can group any atoms with (). Data tuples start with an apostrophe. #> '(None 2 3) >>> (None, ... (2), @@ -255,7 +260,7 @@ Lissp Whirlwind Tour ... (3),)) {1, 2, 3} - #> (dict '((1 2) (3 4))) ;Uses nested tuples. + #> (dict '((1 2) (3 4))) ;Note the nested tuples! >>> dict( ... (((1), ... (2),), @@ -314,7 +319,7 @@ Lissp Whirlwind Tour ;;; Data fragments compile to string literals. - #> '|1+1| ;Data fragments also start with '. + #> '|1+1| ;Make data fragments with an apostrophe. >>> '1+1' '1+1' @@ -363,16 +368,16 @@ Lissp Whirlwind Tour >>> 'Qz_QzLT_QzGT_QzGT_' 'Qz_QzLT_QzGT_QzGT_' - #> :-<>> ;Don't represent identifiers, don't munge. + #> :-<>> ;Doesn't represent identifier; doesn't munge. >>> ':-<>>' ':-<>>' - #> : ;Still a control word. + #> : ;Shortest a control word. >>> ':' ':' - ;;;; 6.2 Escaping + ;;;; 6.2 Escaping with \ #> 'SPAM\ \"\(\)\;EGGS ;These would terminate a symbol if not escaped. >>> 'SPAMQzSPACE_QzQUOT_QzLPAR_QzRPAR_QzSEMI_EGGS' @@ -879,7 +884,7 @@ Lissp Whirlwind Tour ;;; Quote is the only other special form. Looks like a call, but isn't. ;;; A "form" is any Hissp data that can be evaluated. - ;;; Not all data is a valid program in Hissp. E.g. ``(7 42)`` is a + ;;; Not all data is a valid program in Hissp. E.g., ``(7 42)`` is a ;;; tuple, containing the integers 7 in the function position, and 42 ;;; after in the first argument position. It would compile to a ;;; syntactically-valid Python program, but evaluation would crash, @@ -1818,7 +1823,7 @@ Lissp Whirlwind Tour ;;;; 14 The Bundled Macros - ;;; To make it more usable, the REPL comes with the bundled macros + ;;; As a convenience, the REPL comes with the bundled macros ;;; already defined at start up. They're in the _macro_ namespace. (dir _macro_) @@ -1840,6 +1845,7 @@ Lissp Whirlwind Tour ;;; fully-qualified names. ;;; The bundled macros have individual docstrings with usage examples. + ;;; At this point in the tour, you should be able to understand them. (help _macro_.define) @@ -1867,17 +1873,17 @@ Lissp Whirlwind Tour ;;; Familiarize yourself with a macro suite, such as the bundled macros. ;;; It makes Hissp that much more usable. - ;;;; 15 Advanced Reader Macros + ;;;; 15 Advanced Reader Tags ;;;; 15.1 The Discard Macro #> _#"The discard reader macro _# omits the next form. #..It's a way to comment out code structurally. #..It can also make block comments like this one. + #..(But the need to escape double quotes might make ;; comments easier.) #..This would show up when compiled if not for _#. #..Of course, a string expression like this one wouldn't do anything - #..in Python, even if it were compiled in. But the need to escape double - #..quotes might make ;; comments easier. + #..in Python, even if it were compiled in. #.." >>> From b2a5d498ec1c0ffdb81d8f3b8a7303cec16ee4b7 Mon Sep 17 00:00:00 2001 From: gilch Date: Mon, 19 Aug 2024 00:34:47 -0600 Subject: [PATCH 13/17] Made some edits for clarity --- docs/primer.rst | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/docs/primer.rst b/docs/primer.rst index 7b0dfb31b..4c5d6ca99 100644 --- a/docs/primer.rst +++ b/docs/primer.rst @@ -440,7 +440,7 @@ If you've got a fragment surrounded by double quotes (``"``), you can drop the ` .. code-block:: REPL #> "Say \"Cheese!\" - #..\u263a" ; Notice it includes parentheses. + #..\u263a" ; Note the parentheses. >>> ('Say "Cheese!"\n☺') 'Say "Cheese!"\n☺' @@ -506,16 +506,17 @@ The Lissp symbol tokens are read in as strings, just like fragments. In other Lisps, symbols are a data type in their own right, but symbols only exist as a *reader syntax* in Lissp, where they represent the subset of Hissp-level strings that can act as identifiers. -Python has no built in symbol type +Python has no built-in symbol type and instead uses strings pervasively whenever it has to represent identifiers. -Symbols in Lissp become strings in Hissp which become identifiers in Python, +In summary, +symbols in Lissp become strings in Hissp which become identifiers in Python, unless they're quoted, in which case they become string literals in Python. Attributes ---------- -Symbols can have internal ``.``\ s to access attributes. +Symbols can have internal ``.``\ s to access attributes, same as Python. .. code-block:: REPL @@ -1746,7 +1747,7 @@ it is expanded as well (this pattern is known as a *recursive macro*), which is an ability that the reader macros lack. The compiler recognizes a callable as a macro if it is invoked directly -from a ``_macro_`` namespace: +from a fully-qualified ``_macro_`` namespace: .. code-block:: REPL @@ -2135,9 +2136,9 @@ with the name of each top-level ``.lissp`` file, or ``.lissp`` file in the corresponding package, respectively:: - from hissp import transpile + import hissp - transpile(__package__, "spam", "eggs", "etc") + hissp.transpile(__package__, "spam", "eggs", "etc") Or equivalently in Lissp, used either at the REPL or if the main module is written in Lissp: @@ -2156,7 +2157,9 @@ which gives you fine-grained control over what gets compiled when. Before distributing a Lissp project to users who won't be modifying it, compilation could be disabled or removed altogether, -especially when not distributing the .lissp sources. +especially when not distributing the ``.lissp`` sources. +If you don't want the ``hissp`` package to be a dependency, +make sure you remove or disable imports of it as well. .. Note:: You normally *do* want to recompile the whole project during development. @@ -2245,7 +2248,7 @@ and there would be no such attribute. .. rubric:: Footnotes -.. [#EOF] End Of File. Usually Ctrl-D, but enter Ctrl-Z on Windows. +.. [#EOF] End Of File. Usually Ctrl+D, but enter Ctrl+Z on Windows. This doesn't quit Python if the REPL was launched from Python, unlike ``(exit)``. From 06deb0a608a7c415386e09711ce0f82140b285ae Mon Sep 17 00:00:00 2001 From: gilch Date: Tue, 20 Aug 2024 12:58:36 -0600 Subject: [PATCH 14/17] Show full compilation in Sybil errors ParseLissp error messages now show full compiled output without genysm normalization (in addition to the normed diff), to make doctest updates easier. --- conftest.py | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/conftest.py b/conftest.py index ea7ff17d6..c679d9666 100644 --- a/conftest.py +++ b/conftest.py @@ -58,13 +58,19 @@ def evaluate(self, example, parser=Lissp()): parser.compiler.ns = example.namespace hissp = parser.reads(lissp) compiled = parser.compiler.compile(hissp) + "\n" - assert norm_gensym_eq(compiled, python), " \n" + "".join( - context_diff( - norm_gensyms(python), - norm_gensyms(compiled), - fromfile="expected in doc", - tofile="actually compiled to", - ) + assert norm_gensym_eq(compiled, python), "".join( + [ + " \nGENSYM-NORMALIZED DIFF:\n", + *context_diff( + norm_gensyms(python), + norm_gensyms(compiled), + fromfile="expected in doc", + tofile="actually compiled to", + ), + "FULL COMPILATION:\n>>> ", + compiled[:-1].replace("\n", "\n... "), + "\n", + ] ) return super().evaluate(example) From 7cf9c83bc5731ae40a3a7af84a9997f2215868af Mon Sep 17 00:00:00 2001 From: gilch Date: Mon, 19 Aug 2024 00:36:02 -0600 Subject: [PATCH 15/17] New once-deftype & defun system Methods should now be defined after the class in most cases. This allows module reloads to patch in existing instaces. `define` and derivatives (bundled macros beginning with `def`) can now define attributes anywhere, not just globals. `set@` and `zap@` can now define globals as well. Unlike a def, they return the value assigned. The decorator tag `@#` is now compatible with methods, but not classes, but `once-defftype` has a body of decorators to be applied once and reloadable class decorators can be applied afterward using `zap@`. --- src/hissp/macros.lissp | 670 ++++++++++++++++++++++++++-------------- tests/test_macros.lissp | 426 ++++++++++++------------- 2 files changed, 633 insertions(+), 463 deletions(-) diff --git a/src/hissp/macros.lissp b/src/hissp/macros.lissp index 6ed65a621..4ac782a10 100644 --- a/src/hissp/macros.lissp +++ b/src/hissp/macros.lissp @@ -9,11 +9,11 @@ Python or in other Lisps. These are not intended to be a standard library for general use, but do bring Hissp up to a basic standard of utility without adding dependencies, which may suffice in some cases. -Because of certain deliberate restrictions in design, there are no -dependencies in their expansions either, meaning compiled Hissp code -utilizing the bundled macros need not have Hissp installed to work, only -the Python standard library. All helper code must therefore be inlined, -resulting in larger expansions than might otherwise be necessary. +Because of deliberate design restrictions, there are no dependencies in +their expansions either, meaning compiled Hissp code utilizing the +bundled macros need not have Hissp installed to work, only the Python +standard library. All helper code must therefore be inlined, resulting +in larger expansions than might otherwise be necessary. They also have no prerequisite initialization, beyond what is available in a standard Python module. For example, a ``_macro_`` namespace need @@ -38,31 +38,30 @@ Python `conditional expression`, immediately called with the subexpressions as arguments. " +;;; Don't let the size of this file intimidate you. Most of the lines +;;; are documentation. After you remove the comments, docstrings, and +;;; blank lines, only about 300 lines of actual code remain. +;;; ;;; This module is not necessarily a good example of how you should ;;; write Lissp or Lissp macros. Besides the design restrictions ;;; mentioned in the module docstring above, the macros defined here ;;; were not available at the start, so some had to be bootstrapped ;;; without the benefit of a complete macro suite. - +;;; ;;; These macros don't create compiled dependencies on Hissp, but that ;;; doesn't mean you can't depend on your own code. Hissp's qualified ;;; symbols, and Lissp's template syntax that automatically creates ;;; them, are there to make helper functions easy to use in ;;; macroexpansions. Use them. - -;;; However, the restriction on text-substitution is still recommended. +;;; +;;; However, the restriction on text substitution is still recommended. ;;; Many useful advanced macros must process the expansion of other ;;; macros, but they require syntax trees to work on. Text hides that ;;; structure. If you want to go that route, you might as well use `ast` -;;; and ``exec()` and forget about Hissp. Nevertheless, text +;;; and `exec()` and forget about Hissp. Nevertheless, text ;;; substitution is available, and judicious use can improve performance ;;; and maintainability. -;;; Don't let the size of this file intimidate you. Most of the lines -;;; are documentation. After you remove the comments, docstrings, and -;;; blank lines, only about 300 lines of actual code remain. - - _#" Hidden doctest adds bundled macros for REPL-consistent behavior. #> (.update (globals) : _macro_ (types..SimpleNamespace : :** (vars hissp.._macro_))) @@ -286,10 +285,12 @@ Hidden doctest adds bundled macros for REPL-consistent behavior. ;;;; - Post-Bootstrap - ;;; --- -;;;; Definition +;;;; Defining Variables + +;;; see also from Bootstrap: let ;; Define the real defmacro using the bootstrap macros. -(defmacro defmacro (name parameters : docstring () :* body) +(defmacro defmacro (name parameters : docstring () :* body) "Creates a new macro for the current module. If there's no local ``_macro_`` namespace (at compile time), creates @@ -364,199 +365,6 @@ Hidden doctest adds bundled macros for REPL-consistent behavior. ',name ,$fn))))) -(defmacro <<\# (comment) - `',(.contents comment)) -(setattr - _macro_.<<\# '__doc__ - <<# - ;; ``<<#`` 'comment string' reader macro. - ;; - ;; Converts a block of line comments to a raw string. - ;; Roughly equivalent to ``'hissp.reader..Comment.contents#``. - ;; - ;; .. code-block:: REPL - ;; - ;; #> <<# - ;; #..;; You won't have to - ;; #..;; escape the "quotes". - ;; #.. - ;; >>> 'You won\'t have to\nescape the "quotes".' - ;; 'You won\'t have to\nescape the "quotes".' - ;; - ;; See also: `triple-quoted string`. - ;; - _#/) - -(defmacro define (name value) - "Assigns a global the value in the current module. - - .. code-block:: REPL - - #> (define SPAM 'tomato) - >>> # define - ... __import__('builtins').globals().update( - ... SPAM='tomato') - - #> SPAM - >>> SPAM - 'tomato' - - See also: - `globals`, `dict.update`, `defonce`, `def`, `assignment`, `global`. - " - `(.update (globals) - : ,name - ,value)) - -(defmacro defonce (name value) - "Assigns a global the value in the current module, unless it exists. - - Like `define`, but won't overwrite an existing global. - Useful when sending the whole file to the REPL repeatedly or when - using `importlib.reload` and you want to cache an expensive object - instead of re-initializing it every time. - - .. code-block:: REPL - - #> (defonce CACHE (types..SimpleNamespace : x 1)) - >>> # defonce - ... # hissp.macros.._macro_.unless - ... (lambda b, a: ()if b else a())( - ... __import__('operator').contains( - ... __import__('builtins').globals(), - ... 'CACHE'), - ... (lambda : - ... # hissp.macros.._macro_.define - ... __import__('builtins').globals().update( - ... CACHE=__import__('types').SimpleNamespace( - ... x=(1))) - ... )) - - #> (setattr CACHE 'x 42) - >>> setattr( - ... CACHE, - ... 'x', - ... (42)) - - #> (defonce CACHE (progn (print 'not 'evaluated) - #.. (types..SimpleNamespace : x 1))) - >>> # defonce - ... # hissp.macros.._macro_.unless - ... (lambda b, a: ()if b else a())( - ... __import__('operator').contains( - ... __import__('builtins').globals(), - ... 'CACHE'), - ... (lambda : - ... # hissp.macros.._macro_.define - ... __import__('builtins').globals().update( - ... CACHE=# progn - ... (lambda : - ... (print( - ... 'not', - ... 'evaluated'), - ... __import__('types').SimpleNamespace( - ... x=(1))) [-1] - ... )()) - ... )) - () - - #> CACHE ; The second defonce had no effect. - >>> CACHE - namespace(x=42) - - " - `(unless (operator..contains (globals) ',name) - (define ,name ,value))) - -(defmacro deftype (name bases : :* body) - <<# - ;; Defines a type (class) in the current module. - ;; - ;; Key-value pairs are implied by position in the body. - ;; - ;; .. code-block:: REPL - ;; - ;; #> (deftype Point2D (tuple) - ;; #.. __doc__ "Simple ordered pair." - ;; #.. __new__ (lambda (cls x y) - ;; #.. (.__new__ tuple cls `(,x ,y))) - ;; #.. __repr__ (lambda (self) - ;; #.. (.format "Point2D({!r}, {!r})" : :* self))) - ;; >>> # deftype - ;; ... # hissp.macros.._macro_.define - ;; ... __import__('builtins').globals().update( - ;; ... Point2D=__import__('builtins').type( - ;; ... 'Point2D', - ;; ... (lambda * _: _)( - ;; ... tuple), - ;; ... __import__('builtins').dict( - ;; ... __doc__=('Simple ordered pair.'), - ;; ... __new__=(lambda cls, x, y: - ;; ... tuple.__new__( - ;; ... cls, - ;; ... (lambda * _: _)( - ;; ... x, - ;; ... y)) - ;; ... ), - ;; ... __repr__=(lambda self: - ;; ... ('Point2D({!r}, {!r})').format( - ;; ... *self) - ;; ... )))) - ;; - ;; #> (Point2D 1 2) - ;; >>> Point2D( - ;; ... (1), - ;; ... (2)) - ;; Point2D(1, 2) - ;; - ;; Also supports kwds in the bases tuple for - ;; `object.__init_subclass__`. Separate with a ``:``. - ;; - ;; .. code-block:: REPL - ;; - ;; #> (deftype Foo () - ;; #.. __init_subclass__ (lambda (cls :/ : :** kwargs) - ;; #.. (print kwargs))) - ;; >>> # deftype - ;; ... # hissp.macros.._macro_.define - ;; ... __import__('builtins').globals().update( - ;; ... Foo=__import__('builtins').type( - ;; ... 'Foo', - ;; ... (lambda * _: _)(), - ;; ... __import__('builtins').dict( - ;; ... __init_subclass__=(lambda cls, /, **kwargs: - ;; ... print( - ;; ... kwargs) - ;; ... )))) - ;; - ;; #> (deftype Bar (Foo : a 1 b 2)) - ;; >>> # deftype - ;; ... # hissp.macros.._macro_.define - ;; ... __import__('builtins').globals().update( - ;; ... Bar=__import__('builtins').type( - ;; ... 'Bar', - ;; ... (lambda * _: _)( - ;; ... Foo), - ;; ... __import__('builtins').dict(), - ;; ... a=(1), - ;; ... b=(2))) - ;; {'a': 1, 'b': 2} - ;; - ;; See also: `attach`, `type`, `@#`, :keyword:`class`, - ;; `types.new_class` - ;; - (let (ibases (iter bases)) - `(define ,name - (type ',name (,hissp.reader..ENTUPLE - ,@(itertools..takewhile (lambda x (operator..ne x ':)) - ibases)) - (dict : ,@body) - : ,@ibases)))) - -;;;; Locals - -;;; see also from Bootstrap: let - (defmacro let-from (syms itr : :* body) "``let-from`` Create listed locals from iterable. @@ -675,6 +483,322 @@ Hidden doctest adds bundled macros for REPL-consistent behavior. ,@body)) `(progn ,@body))) +(defmacro define (qualname value) + "Assigns an attribute the value. + + The namespace part of the qualname may be fully qualified or start + from a name in scope. An empty namespace part assigns an attribute of + the current module. + + .. code-block:: REPL + + #> (define SPAM 'tomato) + >>> # define + ... __import__('builtins').globals().update( + ... SPAM='tomato') + + #> SPAM + >>> SPAM + 'tomato' + + See also: `globals`, `dict.update`, `once-define`, `def`, + `assignment`, `global`. + " + (let-from (ns _dot attr) (.rpartition qualname ".") + (if-else ns + `(setattr ,ns ',attr ,value) + `(.update (globals) : ,qualname ,value)))) + +(defmacro once-define (qualname value) + "Defines an attribute, unless it exists. + + Like `define`, but won't overwrite an existing attribute. + Useful when sending the whole file to the REPL repeatedly or when + using `importlib.reload` and you want to cache an expensive object + instead of re-initializing it every time. + + .. code-block:: REPL + + #> (once-define CACHE (types..SimpleNamespace : x 1)) + >>> # onceQz_define + ... # hissp.macros.._macro_.unless + ... (lambda b, a: ()if b else a())( + ... __import__('operator').contains( + ... __import__('builtins').globals(), + ... 'CACHE'), + ... (lambda : + ... # hissp.macros.._macro_.define + ... __import__('builtins').globals().update( + ... CACHE=__import__('types').SimpleNamespace( + ... x=(1))) + ... )) + + #> (setattr CACHE 'x 42) + >>> setattr( + ... CACHE, + ... 'x', + ... (42)) + + #> (once-define CACHE (progn (print 'not 'evaluated) + #.. (types..SimpleNamespace : x 1))) + >>> # onceQz_define + ... # hissp.macros.._macro_.unless + ... (lambda b, a: ()if b else a())( + ... __import__('operator').contains( + ... __import__('builtins').globals(), + ... 'CACHE'), + ... (lambda : + ... # hissp.macros.._macro_.define + ... __import__('builtins').globals().update( + ... CACHE=# progn + ... (lambda : + ... (print( + ... 'not', + ... 'evaluated'), + ... __import__('types').SimpleNamespace( + ... x=(1))) [-1] + ... )()) + ... )) + () + + #> CACHE ; The second once-define had no effect. + >>> CACHE + namespace(x=42) + + " + `(unless ,(let-from (ns _dot attr) (.rpartition qualname ".") + (if-else ns + `(hasattr ,ns ',attr) + `(operator..contains (globals) ',attr))) + (define ,qualname ,value))) + +(defmacro once-deftype (qualname bases : :* decorators) + 'hissp.reader..Comment.contents# + ;; Defines a type (class), unless it exists. + ;; + ;; Add class attributes afterwards using `define` or `defun`, and + ;; class decorators afterwards using `zap@`. These run again on module + ;; reload and patch in existing instances. + ;; + ;; ``decorators`` apply in the order written (first applies first), + ;; unless the type exists (not reapplied on reloads). Beware that type + ;; attributes defined afterwards will not be available for the + ;; ``decorators`` to operate upon. A decorator can add attributes for + ;; subsequent decorators to operate upon, however, and a decorator may + ;; be a lambda defined in line. It is possible to add arbitrary + ;; attributes at definition time this way, but remember that + ;; ``decorators`` don't run again on reloads, so changes here cannot + ;; simply be reloaded with the module the way attributes defined + ;; afterwards can. + ;; + ;; .. code-block:: REPL + ;; + ;; #> (once-deftype Point2D (tuple) + ;; #.. ;; Example of setting an attr with an internal decorator. + ;; #.. X#(attach X : __doc__ "Simple ordered pair.")) + ;; >>> # onceQz_deftype + ;; ... # hissp.macros.._macro_.onceQz_define + ;; ... # hissp.macros.._macro_.unless + ;; ... (lambda b, a: ()if b else a())( + ;; ... __import__('operator').contains( + ;; ... __import__('builtins').globals(), + ;; ... 'Point2D'), + ;; ... (lambda : + ;; ... # hissp.macros.._macro_.define + ;; ... __import__('builtins').globals().update( + ;; ... Point2D=(lambda X: + ;; ... # attach + ;; ... # hissp.macros.._macro_.let + ;; ... (lambda _QzVIBDGDLYz___target=X: + ;; ... (__import__('builtins').setattr( + ;; ... _QzVIBDGDLYz___target, + ;; ... '__doc__', + ;; ... ('Simple ordered pair.')), + ;; ... _QzVIBDGDLYz___target) [-1] + ;; ... )() + ;; ... )( + ;; ... __import__('builtins').type( + ;; ... 'Point2D', + ;; ... (lambda * _: _)( + ;; ... tuple), + ;; ... {}))) + ;; ... )) + ;; + ;; #> Point2D.__doc__ + ;; >>> Point2D.__doc__ + ;; 'Simple ordered pair.' + ;; + ;; #> (define Point2D.__doc__ + ;; #.. "Attributes can also be defined afterwards.") + ;; >>> # define + ;; ... __import__('builtins').setattr( + ;; ... Point2D, + ;; ... '__doc__', + ;; ... ('Attributes can also be defined afterwards.')) + ;; + ;; #> Point2D.__doc__ + ;; >>> Point2D.__doc__ + ;; 'Attributes can also be defined afterwards.' + ;; + ;; #> (defun Point2D.__new__ (cls x y) + ;; #.. (.__new__ tuple cls `(,x ,y))) + ;; >>> # defun + ;; ... # hissp.macros.._macro_.define + ;; ... __import__('builtins').setattr( + ;; ... Point2D, + ;; ... '__new__', + ;; ... # hissp.macros..QzMaybe_.fun + ;; ... # hissp.macros.._macro_.let + ;; ... ( + ;; ... lambda _QzEC6PADPWz___lambda=(lambda cls, x, y: + ;; ... tuple.__new__( + ;; ... cls, + ;; ... (lambda * _: _)( + ;; ... x, + ;; ... y)) + ;; ... ): + ;; ... (__import__('builtins').setattr( + ;; ... _QzEC6PADPWz___lambda, + ;; ... ('__code__'), + ;; ... _QzEC6PADPWz___lambda.__code__.replace( + ;; ... co_name='__new__')), + ;; ... __import__('builtins').setattr( + ;; ... _QzEC6PADPWz___lambda, + ;; ... ('__name__'), + ;; ... '__new__'), + ;; ... __import__('builtins').setattr( + ;; ... _QzEC6PADPWz___lambda, + ;; ... ('__qualname__'), + ;; ... 'Point2D.__new__'), + ;; ... _QzEC6PADPWz___lambda) [-1] + ;; ... )()) + ;; + ;; #> (defun Point2D.__repr__ (self) + ;; #.. (.format "Point2D({!r}, {!r})" : :* self)) + ;; >>> # defun + ;; ... # hissp.macros.._macro_.define + ;; ... __import__('builtins').setattr( + ;; ... Point2D, + ;; ... '__repr__', + ;; ... # hissp.macros..QzMaybe_.fun + ;; ... # hissp.macros.._macro_.let + ;; ... ( + ;; ... lambda _QzEC6PADPWz___lambda=(lambda self: + ;; ... ('Point2D({!r}, {!r})').format( + ;; ... *self) + ;; ... ): + ;; ... (__import__('builtins').setattr( + ;; ... _QzEC6PADPWz___lambda, + ;; ... ('__code__'), + ;; ... _QzEC6PADPWz___lambda.__code__.replace( + ;; ... co_name='__repr__')), + ;; ... __import__('builtins').setattr( + ;; ... _QzEC6PADPWz___lambda, + ;; ... ('__name__'), + ;; ... '__repr__'), + ;; ... __import__('builtins').setattr( + ;; ... _QzEC6PADPWz___lambda, + ;; ... ('__qualname__'), + ;; ... 'Point2D.__repr__'), + ;; ... _QzEC6PADPWz___lambda) [-1] + ;; ... )()) + ;; + ;; #> (Point2D 1 2) + ;; >>> Point2D( + ;; ... (1), + ;; ... (2)) + ;; Point2D(1, 2) + ;; + ;; Also supports kwds in the bases tuple for + ;; `object.__init_subclass__`. Separate with a ``:``. + ;; + ;; .. code-block:: REPL + ;; + ;; #> @##classmethod + ;; #..(defun Point2D.__init_subclass__ (cls :/ : :** kwargs) + ;; #.. "Just displays inputs" + ;; #.. (print kwargs)) + ;; >>> # hissp.macros.._macro_.define + ;; ... __import__('builtins').setattr( + ;; ... Point2D, + ;; ... '__init_subclass__', + ;; ... # hissp.macros.._macro_.progn + ;; ... (lambda : + ;; ... (# defun + ;; ... # hissp.macros.._macro_.define + ;; ... __import__('builtins').setattr( + ;; ... Point2D, + ;; ... '__init_subclass__', + ;; ... # hissp.macros..QzMaybe_.fun + ;; ... # hissp.macros.._macro_.let + ;; ... ( + ;; ... lambda _QzEC6PADPWz___lambda=(lambda cls, /, **kwargs: + ;; ... print( + ;; ... kwargs) + ;; ... ): + ;; ... (__import__('builtins').setattr( + ;; ... _QzEC6PADPWz___lambda, + ;; ... ('__doc__'), + ;; ... ('Just displays inputs')), + ;; ... __import__('builtins').setattr( + ;; ... _QzEC6PADPWz___lambda, + ;; ... ('__code__'), + ;; ... _QzEC6PADPWz___lambda.__code__.replace( + ;; ... co_name='__init_subclass__')), + ;; ... __import__('builtins').setattr( + ;; ... _QzEC6PADPWz___lambda, + ;; ... ('__name__'), + ;; ... '__init_subclass__'), + ;; ... __import__('builtins').setattr( + ;; ... _QzEC6PADPWz___lambda, + ;; ... ('__qualname__'), + ;; ... 'Point2D.__init_subclass__'), + ;; ... _QzEC6PADPWz___lambda) [-1] + ;; ... )()), + ;; ... classmethod( + ;; ... Point2D.__init_subclass__)) [-1] + ;; ... )()) + ;; + ;; #> (once-deftype ASubclass (Point2D : a 1 b 2)) + ;; >>> # onceQz_deftype + ;; ... # hissp.macros.._macro_.onceQz_define + ;; ... # hissp.macros.._macro_.unless + ;; ... (lambda b, a: ()if b else a())( + ;; ... __import__('operator').contains( + ;; ... __import__('builtins').globals(), + ;; ... 'ASubclass'), + ;; ... (lambda : + ;; ... # hissp.macros.._macro_.define + ;; ... __import__('builtins').globals().update( + ;; ... ASubclass=__import__('builtins').type( + ;; ... 'ASubclass', + ;; ... (lambda * _: _)( + ;; ... Point2D), + ;; ... {}, + ;; ... a=(1), + ;; ... b=(2))) + ;; ... )) + ;; {'a': 1, 'b': 2} + ;; + ;; See also: `attach`, `type`, `@#`, :keyword:`class`, + ;; `types.new_class`. + ;; + (let (ibases (iter bases) + name |qualname.rpartition('.')[-1]|) + `(once-define ,qualname + ,(functools..reduce + (lambda (cls f) `(,f ,cls)) + decorators + `(type ',name (,hissp.reader..ENTUPLE + ,@(itertools..takewhile (lambda x (operator..ne x ':)) + ibases)) + ,(dict) + : ,@ibases))))) + +(defmacro defun (qualname params : :* body) + "Define a named function with optional docstring." + `(define ,qualname (fun ,qualname ,params ,@body))) + (defmacro my\# e "``my#`` Anaphoric. `let` ``my`` be a fresh `types.SimpleNamespace` in a lexical scope surrounding e. @@ -718,6 +842,29 @@ Hidden doctest adds bundled macros for REPL-consistent behavior. ;;;; Abbreviations +(defmacro <<\# (comment) + `',(.contents comment)) +(setattr + _macro_.<<\# '__doc__ + <<# + ;; ``<<#`` 'comment string' reader macro. + ;; + ;; Converts a block of line comments to a raw string. + ;; Roughly equivalent to ``'hissp.reader..Comment.contents#``. + ;; + ;; .. code-block:: REPL + ;; + ;; #> <<# + ;; #..;; You won't have to + ;; #..;; escape the "quotes". + ;; #.. + ;; >>> 'You won\'t have to\nescape the "quotes".' + ;; 'You won\'t have to\nescape the "quotes".' + ;; + ;; See also: `triple-quoted string`. + ;; + _#/) + (defmacro O\# e "``O#`` 'thunk' Make ``e`` an anonymous function with no parameters. @@ -941,9 +1088,9 @@ Hidden doctest adds bundled macros for REPL-consistent behavior. (alias i itertools.) (alias op operator.) -(defmacro chain\# (itr) +(defmacro chain\# (xss) "``chain#`` Abbreviation for `itertools.chain.from_iterable`" - `(i#chain.from_iterable ,itr)) + `(i#chain.from_iterable ,xss)) (defmacro get\# e <<# @@ -985,14 +1132,16 @@ Hidden doctest adds bundled macros for REPL-consistent behavior. `(op#itemgetter ,e)) (defmacro @\# (decoration definition) - "``@#`` 'decorator' applies ``decoration`` to a global and reassigns. + "``@#`` 'decorator' applies ``decoration`` to definition & reassigns. - ``definition`` form must assign a global identified by its first arg. - Expands to a `define`, meaning decorators can stack. + ``definition`` form must assign an attribute identified by its first + arg. Expands to a `define`, meaning decorators can stack. - Decorator syntax is for global definitions, like `define` and - `deftype`, and would work on any global definition macro that has - the (unqualified) defined name as its first argument. + Decorator syntax is for definitions, like `define` and + `defun`, and would work on any definition macro that has + the definition name as its first argument. + + Use `zap@` to decorate an attribute after its definition. .. code-block:: REPL @@ -1022,8 +1171,8 @@ Hidden doctest adds bundled macros for REPL-consistent behavior. 'sPAM' " - (let (name (get#1 definition)) - `(define ,name (progn ,definition (,decoration ,name))))) + (let (qualname (get#1 definition)) + `(define ,qualname (progn ,definition (,decoration ,qualname))))) (defmacro \[\# e "``[#`` 'subscript' Injection. Python's subscription operator. @@ -1130,41 +1279,65 @@ Hidden doctest adds bundled macros for REPL-consistent behavior. (set! $#coll $#key (,op (op#getitem $#coll $#key) ,@args)))) -(defmacro set@ (name val) +(defmacro set@ (qualname val) "``set@`` 'setat' Assigns an attribute, returns the value. Mnemonic: set @tribute. + The namespace part of the qualname may be fully qualified or start + from a name in scope. An empty namespace part sets an attribute of the + current module. + .. code-block:: REPL - #> (define spam (types..SimpleNamespace)) - >>> # define - ... __import__('builtins').globals().update( - ... spam=__import__('types').SimpleNamespace()) + #> (set@ spam (types..SimpleNamespace)) + >>> # setQzAT_ + ... # hissp.macros.._macro_.let + ... (lambda _QzHMXBVFRDz___val=__import__('types').SimpleNamespace(): + ... (# hissp.macros.._macro_.define + ... __import__('builtins').globals().update( + ... spam=_QzHMXBVFRDz___val), + ... _QzHMXBVFRDz___val) [-1] + ... )() + namespace() - #> (set@ spam.foo 10) + #> (set@ spam.foo (types..SimpleNamespace)) >>> # setQzAT_ ... # hissp.macros.._macro_.let - ... (lambda _QzRMG5GSSIz___val=(10): + ... (lambda _QzHMXBVFRDz___val=__import__('types').SimpleNamespace(): ... (__import__('builtins').setattr( ... spam, ... 'foo', - ... _QzRMG5GSSIz___val), - ... _QzRMG5GSSIz___val) [-1] + ... _QzHMXBVFRDz___val), + ... _QzHMXBVFRDz___val) [-1] ... )() - 10 + namespace() + + #> (set@ spam.foo.bar 4) + >>> # setQzAT_ + ... # hissp.macros.._macro_.let + ... (lambda _QzHMXBVFRDz___val=(4): + ... (__import__('builtins').setattr( + ... spam.foo, + ... 'bar', + ... _QzHMXBVFRDz___val), + ... _QzHMXBVFRDz___val) [-1] + ... )() + 4 #> spam >>> spam - namespace(foo=10) + namespace(foo=namespace(bar=4)) See also: `attach`, `delattr`, `zap@`, `setattr`. " - (let-from (ns _ attr) (.rpartition name ".") - `(let ($#val ,val) - (setattr ,ns ',attr $#val) - $#val))) - -(defmacro zap@ (op name : :* args) + (let-from (ns _dot attr) (.rpartition qualname ".") + `(let ($#val ,val) + ,(if-else ns + `(setattr ,ns ',attr ,'$#val) + `(define ,attr ,'$#val)) + $#val))) + +(defmacro zap@ (op qualname : :* args) "``zap@`` 'zapat' Augmented attribute assignment operator. The current attribute value becomes the first argument. @@ -1203,7 +1376,7 @@ Hidden doctest adds bundled macros for REPL-consistent behavior. See also: `set@`, `zap!`, `operator.iadd`, `augassign`. " - `(set@ ,name (,op ,name ,@args))) + `(set@ ,qualname (,op ,qualname ,@args))) (defmacro attach (target : :* args) "Attaches the named variables to the target as attributes. @@ -1245,6 +1418,29 @@ Hidden doctest adds bundled macros for REPL-consistent behavior. iargs) ,$target)))) +(defmacro fun (qualname params : maybe-docstring () :* body) + "A lambda enhanced with a qualname and optionally a docstring. + + Hissp's (and Python's) lambda syntax do not have docstrings. Named + lambdas improve REPL transparency and error messages, at the cost of + some configuration overhead to set the name in the three places Python + requires. + + Used by `defun`. Not recommended for otherwise anonymous functions due + to the additional overhead. + " + (let*from ((name : :* _xs) (reversed (.split qualname '. 1)) + (doc top) (if-else (hissp.reader..is_hissp_string maybe-docstring) + `(,X#`((setattr ,X "__doc__" ,maybe-docstring)) + ()) + `(,X#() (,maybe-docstring)))) + `(let ($#lambda (lambda ,params ,@top ,@body)) + ,@(doc '$#lambda) + (setattr $#lambda "__code__" (.replace $#lambda.__code__ : co_name ',name)) + (setattr $#lambda "__name__" ',name) + (setattr $#lambda "__qualname__" ',qualname) + $#lambda))) + (defmacro doto (self : :* invocations) "Configure an object. diff --git a/tests/test_macros.lissp b/tests/test_macros.lissp index be8d35db9..64d056e74 100644 --- a/tests/test_macros.lissp +++ b/tests/test_macros.lissp @@ -2,245 +2,219 @@ ;;; Copyright 2019, 2020, 2024 Matthew Egan Odendahl ;;; SPDX-License-Identifier: Apache-2.0 -hissp..alias#* +hissp..alias#H -(*#define enlist +(H#define enlist (lambda (: :* a) (list a))) -(*#defmacro tqs () +(H#defmacro tqs () `(enlist 'enlist)) -(*#defmacro tqs2 () +(H#defmacro tqs2 () "test qualified symbol, with docstring" `(enlist 'enlist)) -(*#defmacro nil () None) - -(*#deftype TestMacros (unittest..TestCase) - test_same_gensym - (lambda (self) - (self.assertEqual : :* `($#test $#test))) - - test_different_gensym - (lambda (self) - (self.assertNotEqual `$#test `$#test)) - - test_nested_gensym - (lambda (self) - (self.assertNotEqual : :* `('$#test `$#test))) - - test_unquote_gensym - (lambda (self) - (self.assertEqual : :* `($#test ,'$#test))) - - test_nested_unquote_gensym - (lambda (self) - (self.assertEqual : :* `($#test `,,'$#test))) - - test_inner_gensym - (lambda (self) - (self.assertRegex `$#self.$foo "self._Qz[A-Z2-7]+z___foo$")) - - test_qualified_symbol - (lambda (self) - (self.assertEqual (tqs) - (enlist "tests.test_macros..enlist"))) - - test_none_doc - (lambda (self) - (self.assertIsNone _macro_.tqs.__doc__)) - - test_qualified_symbol2 - (lambda (self) - (self.assertEqual (tqs2) - (enlist "tests.test_macros..enlist"))) - - test_doc - (lambda (self) - (self.assertEqual _macro_.tqs2.__doc__ "test qualified symbol, with docstring")) - - test_expand_none - (lambda (self) - (self.assertIsNone (nil))) - - test_let - (lambda (self) - (*#let (x 1 - y 2) - (self.assertEqual x 1) - (self.assertEqual y 2))) - - test_doto - (lambda (self) - (self.assertEqual (*#doto (list) - (.append 3) - (.extend (enlist 1 2)) - (.sort)) - (enlist 1 2 3))) - - test_if-else - (lambda (self) - (self.assertEqual (*#if-else False :yes :no) :no) - (self.assertEqual (*#if-else True :yes :no) :yes) - (*#let (xs (list)) - (*#if-else False - (.append xs :yes) - (.append xs :no)) - (*#if-else True - (.append xs :yes) - (.append xs :no)) - (self.assertEqual xs (enlist ":no" ":yes")))) - - test_cond - (lambda (self) - (*#let (xs (list)) - (.append xs (*#cond)) - (*#cond False (.append xs :oops)) - (*#cond :else (.append xs 1)) - (*#cond False (.append xs :oops) - :else (.append xs 2)) - (*#cond True (.append xs 3) - :else (.append xs :oops)) - (*#cond - False (.append xs :oops) - 0 (.append xs :oops) - True (.append xs 4) - () (.append xs :oops)) - (self.assertEqual xs (enlist () 1 2 3 4)))) - - test_any-map - (lambda (self) - (*#let (xs (list)) - (*#any-map i (range 1 10) - (.append xs i) - (operator..not_ (operator..mod i 7))) - (self.assertEqual xs (enlist 1 2 3 4 5 6 7)))) - - test_ands - (lambda (self) - (*#let (xs (list)) - (*#doto xs - (.append (*#ands)) - (.append (*#ands 0)) - (.append (*#ands 1)) - (.append (*#ands 0 (.append xs :oops))) - (.append (*#ands 1 (.append xs 2))) - (.append (*#ands True - (.append xs 3) - (.append xs :oops))) - (.append (*#ands True - (*#progn (.append xs 4) - :oops) - (.append xs 5))) - (.append (*#ands 1 2 (*#progn (.append xs 6) 7)))) - (self.assertEqual (enlist True 0 1 0 2 None 3 None 4 5 None 6 7) - xs))) - - test_ors - (lambda (self) - (*#let (xs (list)) - (*#doto xs - (.append (*#ors)) - (.append (*#ors 0)) - (.append (*#ors 1)) - (.append (*#ors 2 (.append xs :oops))) - (.append (*#ors 0 (.append xs 3))) - (.append (*#ors 0 (.append xs 5) 6))) - (self.assertEqual (enlist () 0 1 2 3 None 5 6) - xs))) - - test_progn - (lambda (self) - (self.assertEqual (*#let (xs (list)) - (*#progn - (.append xs 1) - (.extend xs "bc") - xs)) - (enlist 1 "b" "c"))) - - test_prog1 - (lambda (self) - (*#let (xs (list)) - (.append xs (*#prog1 3 - (.append xs 1) - (.append xs 2))) - (self.assertEqual (enlist 1 2 3) xs))) - - test_attach - (lambda (self) - (*#let (ns (types..SimpleNamespace) - x 1 - y 2 - z 3) - (*#attach ns x y z : p 4 q 5 r 6) - (self.assertEqual (types..SimpleNamespace : x 1 y 2 z 3 p 4 q 5 r 6) - ns))) - - test_when - (lambda (self) - (*#let (xs (list)) - (*#when 1 - (.append xs 1) - (.append xs 2)) - (*#when 0 - (.append xs :oops) - (.append xs :oops)) - (self.assertEqual (enlist 1 2) xs))) - - test_unless - (lambda (self) - (*#let (xs (list)) - (*#unless 0 - (.append xs 1) - (.append xs 2)) - (*#unless 1 - (.append xs :oops) - (.append xs :oops)) - (self.assertEqual (enlist 1 2) xs))) - - test_-> - (lambda (self) - (self.assertEqual (*#-> "-x-" (.replace "x" "y") (.strip "-") .upper) - "Y")) - - test_-<>> - (lambda (self) - (self.assertEqual (*#-<>> (range 3) - (map (lambda (x) (operator..mul x x))) - (filter (lambda (x) ; even? - (operator..eq 0 (operator..mod x 2)))) - (enumerate :<> 100) - list) - (enlist '(100 0) '(101 4)))) - - test_prelude - (lambda (self) - (*#let (ns (dict)) - (*#prelude ns) - (self.assertEqual (set operator..__all__) - (.intersection (set operator..__all__) - (.keys ns))) - ;; Asserts everything public in itertools is in ns. - (*#let (members (set (itertools..filterfalse (lambda x (.startswith x "_")) - (dir itertools.)))) - (self.assertEqual members (.intersection members (.keys ns)))) - (self.assertIn '_macro_ ns))) - - test_string_newline - (lambda (self) - (self.assertEqual "\ +(H#defmacro nil () None) + +(H#once-deftype TestMacros (unittest..TestCase)) + +(H#defun TestMacros.test_same_gensym (self) + (self.assertEqual : :* `($#test $#test))) + +(H#defun TestMacros.test_different_gensym (self) + (self.assertNotEqual `$#test `$#test)) + +(H#defun TestMacros.test_nested_gensym (self) + (self.assertNotEqual : :* `('$#test `$#test))) + +(H#defun TestMacros.test_unquote_gensym (self) + (self.assertEqual : :* `($#test ,'$#test))) + +(H#defun TestMacros.test_nested_unquote_gensym (self) + (self.assertEqual : :* `($#test `,,'$#test))) + +(H#defun TestMacros.test_inner_gensym (self) + (self.assertRegex `$#self.$foo "self._Qz[A-Z2-7]+z___foo$")) + +(H#defun TestMacros.test_qualified_symbol (self) + (self.assertEqual (tqs) + (enlist "tests.test_macros..enlist"))) + +(H#defun TestMacros.test_none_doc (self) + (self.assertIsNone _macro_.tqs.__doc__)) + +(H#defun TestMacros.test_qualified_symbol2 (self) + (self.assertEqual (tqs2) + (enlist "tests.test_macros..enlist"))) + +(H#defun TestMacros.test_doc (self) + (self.assertEqual _macro_.tqs2.__doc__ "test qualified symbol, with docstring")) + +(H#defun TestMacros.test_expand_none (self) + (self.assertIsNone (nil))) + +(H#defun TestMacros.test_let (self) + (H#let (x 1 + y 2) + (self.assertEqual x 1) + (self.assertEqual y 2))) + +(H#defun TestMacros.test_doto (self) + (self.assertEqual (H#doto (list) + (.append 3) + (.extend (enlist 1 2)) + (.sort)) + (enlist 1 2 3))) + +(H#defun TestMacros.test_if-else (self) + (self.assertEqual (H#if-else False :yes :no) :no) + (self.assertEqual (H#if-else True :yes :no) :yes) + (H#let (xs (list)) + (H#if-else False + (.append xs :yes) + (.append xs :no)) + (H#if-else True + (.append xs :yes) + (.append xs :no)) + (self.assertEqual xs (enlist ":no" ":yes")))) + +(H#defun TestMacros.test_cond (self) + (H#let (xs (list)) + (.append xs (H#cond)) + (H#cond False (.append xs :oops)) + (H#cond :else (.append xs 1)) + (H#cond False (.append xs :oops) + :else (.append xs 2)) + (H#cond True (.append xs 3) + :else (.append xs :oops)) + (H#cond + False (.append xs :oops) + 0 (.append xs :oops) + True (.append xs 4) + () (.append xs :oops)) + (self.assertEqual xs (enlist () 1 2 3 4)))) + +(H#defun TestMacros.test_any-map (self) + (H#let (xs (list)) + (H#any-map i (range 1 10) + (.append xs i) + (operator..not_ (operator..mod i 7))) + (self.assertEqual xs (enlist 1 2 3 4 5 6 7)))) + +(H#defun TestMacros.test_ands (self) + (H#let (xs (list)) + (H#doto xs + (.append (H#ands)) + (.append (H#ands 0)) + (.append (H#ands 1)) + (.append (H#ands 0 (.append xs :oops))) + (.append (H#ands 1 (.append xs 2))) + (.append (H#ands True + (.append xs 3) + (.append xs :oops))) + (.append (H#ands True + (H#progn (.append xs 4) + :oops) + (.append xs 5))) + (.append (H#ands 1 2 (H#progn (.append xs 6) 7)))) + (self.assertEqual (enlist True 0 1 0 2 None 3 None 4 5 None 6 7) + xs))) + +(H#defun TestMacros.test_ors (self) + (H#let (xs (list)) + (H#doto xs + (.append (H#ors)) + (.append (H#ors 0)) + (.append (H#ors 1)) + (.append (H#ors 2 (.append xs :oops))) + (.append (H#ors 0 (.append xs 3))) + (.append (H#ors 0 (.append xs 5) 6))) + (self.assertEqual (enlist () 0 1 2 3 None 5 6) + xs))) + +(H#defun TestMacros.test_progn (self) + (self.assertEqual (H#let (xs (list)) + (H#progn + (.append xs 1) + (.extend xs "bc") + xs)) + (enlist 1 "b" "c"))) + +(H#defun TestMacros.test_prog1 (self) + (H#let (xs (list)) + (.append xs (H#prog1 3 + (.append xs 1) + (.append xs 2))) + (self.assertEqual (enlist 1 2 3) xs))) + +(H#defun TestMacros.test_attach (self) + (H#let (ns (types..SimpleNamespace) + x 1 + y 2 + z 3) + (H#attach ns x y z : p 4 q 5 r 6) + (self.assertEqual (types..SimpleNamespace : x 1 y 2 z 3 p 4 q 5 r 6) + ns))) + +(H#defun TestMacros.test_when (self) + (H#let (xs (list)) + (H#when 1 + (.append xs 1) + (.append xs 2)) + (H#when 0 + (.append xs :oops) + (.append xs :oops)) + (self.assertEqual (enlist 1 2) xs))) + +(H#defun TestMacros.test_unless (self) + (H#let (xs (list)) + (H#unless 0 + (.append xs 1) + (.append xs 2)) + (H#unless 1 + (.append xs :oops) + (.append xs :oops)) + (self.assertEqual (enlist 1 2) xs))) + +(H#defun TestMacros.test_-> (self) + (self.assertEqual (H#-> "-x-" (.replace "x" "y") (.strip "-") .upper) + "Y")) + +(H#defun TestMacros.test_-<>> (self) + (self.assertEqual (H#-<>> (range 3) + (map (lambda (x) (operator..mul x x))) + (filter (lambda (x) ; even? + (operator..eq 0 (operator..mod x 2)))) + (enumerate :<> 100) + list) + (enlist '(100 0) '(101 4)))) + +(H#defun TestMacros.test_prelude (self) + (H#let (ns (dict)) + (H#prelude ns) + (self.assertEqual (set operator..__all__) + (.intersection (set operator..__all__) + (.keys ns))) + ;; Asserts everything public in itertools is in ns. + (H#let (members (set (itertools..filterfalse (lambda x (.startswith x "_")) + (dir itertools.)))) + (self.assertEqual members (.intersection members (.keys ns)))) + (self.assertIn '_macro_ ns))) + +(H#defun TestMacros.test_string_newline (self) + (self.assertEqual "\ foo\ bar\nbaz" - "foobar + "foobar baz") - (self.assertEqual " + (self.assertEqual " foo bar " - "\n\nfoo\nbar\n")) + "\n\nfoo\nbar\n")) + +(H#defun TestMacros.test_string_reader_macro (self) + (self.assertEqual fractions..Fraction#.#"1/3" + .#(fractions..Fraction 1 3))) - test_string_reader_macro - (lambda (self) - (self.assertEqual fractions..Fraction#.#"1/3" - .#(fractions..Fraction 1 3)))) From 1d86d49075c08e9ecbbdb4fe86eb1795713673e8 Mon Sep 17 00:00:00 2001 From: gilch Date: Tue, 20 Aug 2024 14:09:42 -0600 Subject: [PATCH 16/17] Rework defmacro Now in terms of the more correct `fun`. Use a SimpleNamespace for hissp.macros._macro_ Rename once-deftype to deftypeonce Rename once-define to defonce again --- docs/lissp_whirlwind_tour.rst | 12 +- docs/macro_tutorial.rst | 2499 +++++++++++++++++++-------------- docs/style_guide.rst | 2 +- src/hissp/macros.lissp | 610 ++++---- tests/test_macros.lissp | 2 +- 5 files changed, 1730 insertions(+), 1395 deletions(-) diff --git a/docs/lissp_whirlwind_tour.rst b/docs/lissp_whirlwind_tour.rst index e67783126..360175179 100644 --- a/docs/lissp_whirlwind_tour.rst +++ b/docs/lissp_whirlwind_tour.rst @@ -1828,18 +1828,20 @@ Lissp Whirlwind Tour (dir _macro_) - ;;; This is a copy of of the following module. + ;;; This is a copy of of the following namespace. - #> hissp.._macro_ - >>> __import__('hissp')._macro_ - + hissp.macros.._macro_ - (dir hissp.._macro_) + (dir hissp.macros.._macro_) ;;; Notice its containing module. Take a minute to read its docstring. (help hissp.macros.) + ;;; As a convenience, hissp.__init__ imports it as well: + + hissp.._macro_ + ;;; The macros will still be available from there even if you clobber ;;; your _macro_ copy. Recall that you can invoke macros using their ;;; fully-qualified names. diff --git a/docs/macro_tutorial.rst b/docs/macro_tutorial.rst index ff2f3bea1..e93d3b231 100644 --- a/docs/macro_tutorial.rst +++ b/docs/macro_tutorial.rst @@ -247,8 +247,7 @@ And push it to the REPL as well: ... ' except s.X as e:v=e\n' ... ' return k\n' ... "_macro_=__import__('types').SimpleNamespace()\n" - ... "try:exec('from hissp.macros._macro_ import *',vars(_macro_))\n" - ... 'except ModuleNotFoundError:pass'), + ... "vars(_macro_).update(vars(__import__('hissp')._macro_))"), ... __import__('builtins').globals()) .. caution:: @@ -587,27 +586,34 @@ Try this definition. #> (defmacro L (params : :* body) #.. `(lambda ,params ,@body)) >>> # defmacro - ... # hissp.macros.._macro_.let - ... ( - ... lambda _QzAW22OE5Kz___fn=(lambda params, *body: - ... (lambda * _: _)( - ... 'lambda', - ... params, - ... *body) - ... ): - ... (__import__('builtins').setattr( - ... _QzAW22OE5Kz___fn, - ... '__qualname__', - ... ('.').join( - ... ('_macro_', - ... 'L',))), - ... __import__('builtins').setattr( - ... __import__('operator').getitem( - ... __import__('builtins').globals(), - ... '_macro_'), - ... 'L', - ... _QzAW22OE5Kz___fn)) [-1] - ... )() + ... __import__('builtins').setattr( + ... __import__('builtins').globals().get( + ... ('_macro_')), + ... 'L', + ... # hissp.macros.._macro_.fun + ... # hissp.macros.._macro_.let + ... ( + ... lambda _QzTXNQFMN3z___lambda=(lambda params, *body: + ... (lambda * _: _)( + ... 'lambda', + ... params, + ... *body) + ... ): + ... (__import__('builtins').setattr( + ... _QzTXNQFMN3z___lambda, + ... ('__code__'), + ... _QzTXNQFMN3z___lambda.__code__.replace( + ... co_name='L')), + ... __import__('builtins').setattr( + ... _QzTXNQFMN3z___lambda, + ... ('__name__'), + ... 'L'), + ... __import__('builtins').setattr( + ... _QzTXNQFMN3z___lambda, + ... ('__qualname__'), + ... '_macro_.L'), + ... _QzTXNQFMN3z___lambda) [-1] + ... )()) .. code-block:: REPL @@ -679,28 +685,35 @@ that `anaphoric macro ` we did in the `primer`. #.. `(lambda (,'X) ; Interpolate anaphors to prevent qualification! #.. ,expr)) >>> # defmacro - ... # hissp.macros.._macro_.let - ... ( - ... lambda _QzAW22OE5Kz___fn=(lambda *expr: - ... (lambda * _: _)( - ... 'lambda', + ... __import__('builtins').setattr( + ... __import__('builtins').globals().get( + ... ('_macro_')), + ... 'L', + ... # hissp.macros.._macro_.fun + ... # hissp.macros.._macro_.let + ... ( + ... lambda _QzTXNQFMN3z___lambda=(lambda *expr: ... (lambda * _: _)( - ... 'X'), - ... expr) - ... ): - ... (__import__('builtins').setattr( - ... _QzAW22OE5Kz___fn, - ... '__qualname__', - ... ('.').join( - ... ('_macro_', - ... 'L',))), - ... __import__('builtins').setattr( - ... __import__('operator').getitem( - ... __import__('builtins').globals(), - ... '_macro_'), - ... 'L', - ... _QzAW22OE5Kz___fn)) [-1] - ... )() + ... 'lambda', + ... (lambda * _: _)( + ... 'X'), + ... expr) + ... ): + ... (__import__('builtins').setattr( + ... _QzTXNQFMN3z___lambda, + ... ('__code__'), + ... _QzTXNQFMN3z___lambda.__code__.replace( + ... co_name='L')), + ... __import__('builtins').setattr( + ... _QzTXNQFMN3z___lambda, + ... ('__name__'), + ... 'L'), + ... __import__('builtins').setattr( + ... _QzTXNQFMN3z___lambda, + ... ('__qualname__'), + ... '_macro_.L'), + ... _QzTXNQFMN3z___lambda) [-1] + ... )()) .. code-block:: REPL @@ -782,29 +795,36 @@ Ready? #.. `(lambda (,'X ,'Y) #.. ,expr)) >>> # defmacro - ... # hissp.macros.._macro_.let - ... ( - ... lambda _QzAW22OE5Kz___fn=(lambda *expr: - ... (lambda * _: _)( - ... 'lambda', + ... __import__('builtins').setattr( + ... __import__('builtins').globals().get( + ... ('_macro_')), + ... 'L2', + ... # hissp.macros.._macro_.fun + ... # hissp.macros.._macro_.let + ... ( + ... lambda _QzTXNQFMN3z___lambda=(lambda *expr: ... (lambda * _: _)( - ... 'X', - ... 'Y'), - ... expr) - ... ): - ... (__import__('builtins').setattr( - ... _QzAW22OE5Kz___fn, - ... '__qualname__', - ... ('.').join( - ... ('_macro_', - ... 'L2',))), - ... __import__('builtins').setattr( - ... __import__('operator').getitem( - ... __import__('builtins').globals(), - ... '_macro_'), - ... 'L2', - ... _QzAW22OE5Kz___fn)) [-1] - ... )() + ... 'lambda', + ... (lambda * _: _)( + ... 'X', + ... 'Y'), + ... expr) + ... ): + ... (__import__('builtins').setattr( + ... _QzTXNQFMN3z___lambda, + ... ('__code__'), + ... _QzTXNQFMN3z___lambda.__code__.replace( + ... co_name='L2')), + ... __import__('builtins').setattr( + ... _QzTXNQFMN3z___lambda, + ... ('__name__'), + ... 'L2'), + ... __import__('builtins').setattr( + ... _QzTXNQFMN3z___lambda, + ... ('__qualname__'), + ... '_macro_.L2'), + ... _QzTXNQFMN3z___lambda) [-1] + ... )()) .. code-block:: REPL @@ -848,599 +868,788 @@ Don't panic. >>> # __main__.._macro_.progn ... (lambda : ... (# __main__.._macro_.defmacro - ... # hissp.macros.._macro_.let - ... ( - ... lambda _Qz2D5FNHXZz___fn=(lambda *_QzXDFV7JLKz___expr: - ... (lambda * _: _)( - ... 'lambda', - ... '', - ... _QzXDFV7JLKz___expr) - ... ): - ... (__import__('builtins').setattr( - ... _Qz2D5FNHXZz___fn, - ... '__qualname__', - ... ('.').join( - ... ('_macro_', - ... 'L0',))), - ... __import__('builtins').setattr( - ... __import__('operator').getitem( - ... __import__('builtins').globals(), - ... '_macro_'), - ... 'L0', - ... _Qz2D5FNHXZz___fn)) [-1] - ... )(), + ... __import__('builtins').setattr( + ... __import__('builtins').globals().get( + ... ('_macro_')), + ... 'L0', + ... # hissp.macros.._macro_.fun + ... # hissp.macros.._macro_.let + ... ( + ... lambda _QzTXNQFMN3z___lambda=(lambda *_QzWWNCOLRLz___expr: + ... (lambda * _: _)( + ... 'lambda', + ... '', + ... _QzWWNCOLRLz___expr) + ... ): + ... (__import__('builtins').setattr( + ... _QzTXNQFMN3z___lambda, + ... ('__code__'), + ... _QzTXNQFMN3z___lambda.__code__.replace( + ... co_name='L0')), + ... __import__('builtins').setattr( + ... _QzTXNQFMN3z___lambda, + ... ('__name__'), + ... 'L0'), + ... __import__('builtins').setattr( + ... _QzTXNQFMN3z___lambda, + ... ('__qualname__'), + ... '_macro_.L0'), + ... _QzTXNQFMN3z___lambda) [-1] + ... )()), ... # __main__.._macro_.defmacro - ... # hissp.macros.._macro_.let - ... ( - ... lambda _Qz2D5FNHXZz___fn=(lambda *_QzXDFV7JLKz___expr: - ... (lambda * _: _)( - ... 'lambda', - ... 'A', - ... _QzXDFV7JLKz___expr) - ... ): - ... (__import__('builtins').setattr( - ... _Qz2D5FNHXZz___fn, - ... '__qualname__', - ... ('.').join( - ... ('_macro_', - ... 'L1',))), - ... __import__('builtins').setattr( - ... __import__('operator').getitem( - ... __import__('builtins').globals(), - ... '_macro_'), - ... 'L1', - ... _Qz2D5FNHXZz___fn)) [-1] - ... )(), + ... __import__('builtins').setattr( + ... __import__('builtins').globals().get( + ... ('_macro_')), + ... 'L1', + ... # hissp.macros.._macro_.fun + ... # hissp.macros.._macro_.let + ... ( + ... lambda _QzTXNQFMN3z___lambda=(lambda *_QzWWNCOLRLz___expr: + ... (lambda * _: _)( + ... 'lambda', + ... 'A', + ... _QzWWNCOLRLz___expr) + ... ): + ... (__import__('builtins').setattr( + ... _QzTXNQFMN3z___lambda, + ... ('__code__'), + ... _QzTXNQFMN3z___lambda.__code__.replace( + ... co_name='L1')), + ... __import__('builtins').setattr( + ... _QzTXNQFMN3z___lambda, + ... ('__name__'), + ... 'L1'), + ... __import__('builtins').setattr( + ... _QzTXNQFMN3z___lambda, + ... ('__qualname__'), + ... '_macro_.L1'), + ... _QzTXNQFMN3z___lambda) [-1] + ... )()), ... # __main__.._macro_.defmacro - ... # hissp.macros.._macro_.let - ... ( - ... lambda _Qz2D5FNHXZz___fn=(lambda *_QzXDFV7JLKz___expr: - ... (lambda * _: _)( - ... 'lambda', - ... 'AB', - ... _QzXDFV7JLKz___expr) - ... ): - ... (__import__('builtins').setattr( - ... _Qz2D5FNHXZz___fn, - ... '__qualname__', - ... ('.').join( - ... ('_macro_', - ... 'L2',))), - ... __import__('builtins').setattr( - ... __import__('operator').getitem( - ... __import__('builtins').globals(), - ... '_macro_'), - ... 'L2', - ... _Qz2D5FNHXZz___fn)) [-1] - ... )(), + ... __import__('builtins').setattr( + ... __import__('builtins').globals().get( + ... ('_macro_')), + ... 'L2', + ... # hissp.macros.._macro_.fun + ... # hissp.macros.._macro_.let + ... ( + ... lambda _QzTXNQFMN3z___lambda=(lambda *_QzWWNCOLRLz___expr: + ... (lambda * _: _)( + ... 'lambda', + ... 'AB', + ... _QzWWNCOLRLz___expr) + ... ): + ... (__import__('builtins').setattr( + ... _QzTXNQFMN3z___lambda, + ... ('__code__'), + ... _QzTXNQFMN3z___lambda.__code__.replace( + ... co_name='L2')), + ... __import__('builtins').setattr( + ... _QzTXNQFMN3z___lambda, + ... ('__name__'), + ... 'L2'), + ... __import__('builtins').setattr( + ... _QzTXNQFMN3z___lambda, + ... ('__qualname__'), + ... '_macro_.L2'), + ... _QzTXNQFMN3z___lambda) [-1] + ... )()), ... # __main__.._macro_.defmacro - ... # hissp.macros.._macro_.let - ... ( - ... lambda _Qz2D5FNHXZz___fn=(lambda *_QzXDFV7JLKz___expr: - ... (lambda * _: _)( - ... 'lambda', - ... 'ABC', - ... _QzXDFV7JLKz___expr) - ... ): - ... (__import__('builtins').setattr( - ... _Qz2D5FNHXZz___fn, - ... '__qualname__', - ... ('.').join( - ... ('_macro_', - ... 'L3',))), - ... __import__('builtins').setattr( - ... __import__('operator').getitem( - ... __import__('builtins').globals(), - ... '_macro_'), - ... 'L3', - ... _Qz2D5FNHXZz___fn)) [-1] - ... )(), + ... __import__('builtins').setattr( + ... __import__('builtins').globals().get( + ... ('_macro_')), + ... 'L3', + ... # hissp.macros.._macro_.fun + ... # hissp.macros.._macro_.let + ... ( + ... lambda _QzTXNQFMN3z___lambda=(lambda *_QzWWNCOLRLz___expr: + ... (lambda * _: _)( + ... 'lambda', + ... 'ABC', + ... _QzWWNCOLRLz___expr) + ... ): + ... (__import__('builtins').setattr( + ... _QzTXNQFMN3z___lambda, + ... ('__code__'), + ... _QzTXNQFMN3z___lambda.__code__.replace( + ... co_name='L3')), + ... __import__('builtins').setattr( + ... _QzTXNQFMN3z___lambda, + ... ('__name__'), + ... 'L3'), + ... __import__('builtins').setattr( + ... _QzTXNQFMN3z___lambda, + ... ('__qualname__'), + ... '_macro_.L3'), + ... _QzTXNQFMN3z___lambda) [-1] + ... )()), ... # __main__.._macro_.defmacro - ... # hissp.macros.._macro_.let - ... ( - ... lambda _Qz2D5FNHXZz___fn=(lambda *_QzXDFV7JLKz___expr: - ... (lambda * _: _)( - ... 'lambda', - ... 'ABCD', - ... _QzXDFV7JLKz___expr) - ... ): - ... (__import__('builtins').setattr( - ... _Qz2D5FNHXZz___fn, - ... '__qualname__', - ... ('.').join( - ... ('_macro_', - ... 'L4',))), - ... __import__('builtins').setattr( - ... __import__('operator').getitem( - ... __import__('builtins').globals(), - ... '_macro_'), - ... 'L4', - ... _Qz2D5FNHXZz___fn)) [-1] - ... )(), + ... __import__('builtins').setattr( + ... __import__('builtins').globals().get( + ... ('_macro_')), + ... 'L4', + ... # hissp.macros.._macro_.fun + ... # hissp.macros.._macro_.let + ... ( + ... lambda _QzTXNQFMN3z___lambda=(lambda *_QzWWNCOLRLz___expr: + ... (lambda * _: _)( + ... 'lambda', + ... 'ABCD', + ... _QzWWNCOLRLz___expr) + ... ): + ... (__import__('builtins').setattr( + ... _QzTXNQFMN3z___lambda, + ... ('__code__'), + ... _QzTXNQFMN3z___lambda.__code__.replace( + ... co_name='L4')), + ... __import__('builtins').setattr( + ... _QzTXNQFMN3z___lambda, + ... ('__name__'), + ... 'L4'), + ... __import__('builtins').setattr( + ... _QzTXNQFMN3z___lambda, + ... ('__qualname__'), + ... '_macro_.L4'), + ... _QzTXNQFMN3z___lambda) [-1] + ... )()), ... # __main__.._macro_.defmacro - ... # hissp.macros.._macro_.let - ... ( - ... lambda _Qz2D5FNHXZz___fn=(lambda *_QzXDFV7JLKz___expr: - ... (lambda * _: _)( - ... 'lambda', - ... 'ABCDE', - ... _QzXDFV7JLKz___expr) - ... ): - ... (__import__('builtins').setattr( - ... _Qz2D5FNHXZz___fn, - ... '__qualname__', - ... ('.').join( - ... ('_macro_', - ... 'L5',))), - ... __import__('builtins').setattr( - ... __import__('operator').getitem( - ... __import__('builtins').globals(), - ... '_macro_'), - ... 'L5', - ... _Qz2D5FNHXZz___fn)) [-1] - ... )(), + ... __import__('builtins').setattr( + ... __import__('builtins').globals().get( + ... ('_macro_')), + ... 'L5', + ... # hissp.macros.._macro_.fun + ... # hissp.macros.._macro_.let + ... ( + ... lambda _QzTXNQFMN3z___lambda=(lambda *_QzWWNCOLRLz___expr: + ... (lambda * _: _)( + ... 'lambda', + ... 'ABCDE', + ... _QzWWNCOLRLz___expr) + ... ): + ... (__import__('builtins').setattr( + ... _QzTXNQFMN3z___lambda, + ... ('__code__'), + ... _QzTXNQFMN3z___lambda.__code__.replace( + ... co_name='L5')), + ... __import__('builtins').setattr( + ... _QzTXNQFMN3z___lambda, + ... ('__name__'), + ... 'L5'), + ... __import__('builtins').setattr( + ... _QzTXNQFMN3z___lambda, + ... ('__qualname__'), + ... '_macro_.L5'), + ... _QzTXNQFMN3z___lambda) [-1] + ... )()), ... # __main__.._macro_.defmacro - ... # hissp.macros.._macro_.let - ... ( - ... lambda _Qz2D5FNHXZz___fn=(lambda *_QzXDFV7JLKz___expr: - ... (lambda * _: _)( - ... 'lambda', - ... 'ABCDEF', - ... _QzXDFV7JLKz___expr) - ... ): - ... (__import__('builtins').setattr( - ... _Qz2D5FNHXZz___fn, - ... '__qualname__', - ... ('.').join( - ... ('_macro_', - ... 'L6',))), - ... __import__('builtins').setattr( - ... __import__('operator').getitem( - ... __import__('builtins').globals(), - ... '_macro_'), - ... 'L6', - ... _Qz2D5FNHXZz___fn)) [-1] - ... )(), + ... __import__('builtins').setattr( + ... __import__('builtins').globals().get( + ... ('_macro_')), + ... 'L6', + ... # hissp.macros.._macro_.fun + ... # hissp.macros.._macro_.let + ... ( + ... lambda _QzTXNQFMN3z___lambda=(lambda *_QzWWNCOLRLz___expr: + ... (lambda * _: _)( + ... 'lambda', + ... 'ABCDEF', + ... _QzWWNCOLRLz___expr) + ... ): + ... (__import__('builtins').setattr( + ... _QzTXNQFMN3z___lambda, + ... ('__code__'), + ... _QzTXNQFMN3z___lambda.__code__.replace( + ... co_name='L6')), + ... __import__('builtins').setattr( + ... _QzTXNQFMN3z___lambda, + ... ('__name__'), + ... 'L6'), + ... __import__('builtins').setattr( + ... _QzTXNQFMN3z___lambda, + ... ('__qualname__'), + ... '_macro_.L6'), + ... _QzTXNQFMN3z___lambda) [-1] + ... )()), ... # __main__.._macro_.defmacro - ... # hissp.macros.._macro_.let - ... ( - ... lambda _Qz2D5FNHXZz___fn=(lambda *_QzXDFV7JLKz___expr: - ... (lambda * _: _)( - ... 'lambda', - ... 'ABCDEFG', - ... _QzXDFV7JLKz___expr) - ... ): - ... (__import__('builtins').setattr( - ... _Qz2D5FNHXZz___fn, - ... '__qualname__', - ... ('.').join( - ... ('_macro_', - ... 'L7',))), - ... __import__('builtins').setattr( - ... __import__('operator').getitem( - ... __import__('builtins').globals(), - ... '_macro_'), - ... 'L7', - ... _Qz2D5FNHXZz___fn)) [-1] - ... )(), + ... __import__('builtins').setattr( + ... __import__('builtins').globals().get( + ... ('_macro_')), + ... 'L7', + ... # hissp.macros.._macro_.fun + ... # hissp.macros.._macro_.let + ... ( + ... lambda _QzTXNQFMN3z___lambda=(lambda *_QzWWNCOLRLz___expr: + ... (lambda * _: _)( + ... 'lambda', + ... 'ABCDEFG', + ... _QzWWNCOLRLz___expr) + ... ): + ... (__import__('builtins').setattr( + ... _QzTXNQFMN3z___lambda, + ... ('__code__'), + ... _QzTXNQFMN3z___lambda.__code__.replace( + ... co_name='L7')), + ... __import__('builtins').setattr( + ... _QzTXNQFMN3z___lambda, + ... ('__name__'), + ... 'L7'), + ... __import__('builtins').setattr( + ... _QzTXNQFMN3z___lambda, + ... ('__qualname__'), + ... '_macro_.L7'), + ... _QzTXNQFMN3z___lambda) [-1] + ... )()), ... # __main__.._macro_.defmacro - ... # hissp.macros.._macro_.let - ... ( - ... lambda _Qz2D5FNHXZz___fn=(lambda *_QzXDFV7JLKz___expr: - ... (lambda * _: _)( - ... 'lambda', - ... 'ABCDEFGH', - ... _QzXDFV7JLKz___expr) - ... ): - ... (__import__('builtins').setattr( - ... _Qz2D5FNHXZz___fn, - ... '__qualname__', - ... ('.').join( - ... ('_macro_', - ... 'L8',))), - ... __import__('builtins').setattr( - ... __import__('operator').getitem( - ... __import__('builtins').globals(), - ... '_macro_'), - ... 'L8', - ... _Qz2D5FNHXZz___fn)) [-1] - ... )(), + ... __import__('builtins').setattr( + ... __import__('builtins').globals().get( + ... ('_macro_')), + ... 'L8', + ... # hissp.macros.._macro_.fun + ... # hissp.macros.._macro_.let + ... ( + ... lambda _QzTXNQFMN3z___lambda=(lambda *_QzWWNCOLRLz___expr: + ... (lambda * _: _)( + ... 'lambda', + ... 'ABCDEFGH', + ... _QzWWNCOLRLz___expr) + ... ): + ... (__import__('builtins').setattr( + ... _QzTXNQFMN3z___lambda, + ... ('__code__'), + ... _QzTXNQFMN3z___lambda.__code__.replace( + ... co_name='L8')), + ... __import__('builtins').setattr( + ... _QzTXNQFMN3z___lambda, + ... ('__name__'), + ... 'L8'), + ... __import__('builtins').setattr( + ... _QzTXNQFMN3z___lambda, + ... ('__qualname__'), + ... '_macro_.L8'), + ... _QzTXNQFMN3z___lambda) [-1] + ... )()), ... # __main__.._macro_.defmacro - ... # hissp.macros.._macro_.let - ... ( - ... lambda _Qz2D5FNHXZz___fn=(lambda *_QzXDFV7JLKz___expr: - ... (lambda * _: _)( - ... 'lambda', - ... 'ABCDEFGHI', - ... _QzXDFV7JLKz___expr) - ... ): - ... (__import__('builtins').setattr( - ... _Qz2D5FNHXZz___fn, - ... '__qualname__', - ... ('.').join( - ... ('_macro_', - ... 'L9',))), - ... __import__('builtins').setattr( - ... __import__('operator').getitem( - ... __import__('builtins').globals(), - ... '_macro_'), - ... 'L9', - ... _Qz2D5FNHXZz___fn)) [-1] - ... )(), + ... __import__('builtins').setattr( + ... __import__('builtins').globals().get( + ... ('_macro_')), + ... 'L9', + ... # hissp.macros.._macro_.fun + ... # hissp.macros.._macro_.let + ... ( + ... lambda _QzTXNQFMN3z___lambda=(lambda *_QzWWNCOLRLz___expr: + ... (lambda * _: _)( + ... 'lambda', + ... 'ABCDEFGHI', + ... _QzWWNCOLRLz___expr) + ... ): + ... (__import__('builtins').setattr( + ... _QzTXNQFMN3z___lambda, + ... ('__code__'), + ... _QzTXNQFMN3z___lambda.__code__.replace( + ... co_name='L9')), + ... __import__('builtins').setattr( + ... _QzTXNQFMN3z___lambda, + ... ('__name__'), + ... 'L9'), + ... __import__('builtins').setattr( + ... _QzTXNQFMN3z___lambda, + ... ('__qualname__'), + ... '_macro_.L9'), + ... _QzTXNQFMN3z___lambda) [-1] + ... )()), ... # __main__.._macro_.defmacro - ... # hissp.macros.._macro_.let - ... ( - ... lambda _Qz2D5FNHXZz___fn=(lambda *_QzXDFV7JLKz___expr: - ... (lambda * _: _)( - ... 'lambda', - ... 'ABCDEFGHIJ', - ... _QzXDFV7JLKz___expr) - ... ): - ... (__import__('builtins').setattr( - ... _Qz2D5FNHXZz___fn, - ... '__qualname__', - ... ('.').join( - ... ('_macro_', - ... 'L10',))), - ... __import__('builtins').setattr( - ... __import__('operator').getitem( - ... __import__('builtins').globals(), - ... '_macro_'), - ... 'L10', - ... _Qz2D5FNHXZz___fn)) [-1] - ... )(), + ... __import__('builtins').setattr( + ... __import__('builtins').globals().get( + ... ('_macro_')), + ... 'L10', + ... # hissp.macros.._macro_.fun + ... # hissp.macros.._macro_.let + ... ( + ... lambda _QzTXNQFMN3z___lambda=(lambda *_QzWWNCOLRLz___expr: + ... (lambda * _: _)( + ... 'lambda', + ... 'ABCDEFGHIJ', + ... _QzWWNCOLRLz___expr) + ... ): + ... (__import__('builtins').setattr( + ... _QzTXNQFMN3z___lambda, + ... ('__code__'), + ... _QzTXNQFMN3z___lambda.__code__.replace( + ... co_name='L10')), + ... __import__('builtins').setattr( + ... _QzTXNQFMN3z___lambda, + ... ('__name__'), + ... 'L10'), + ... __import__('builtins').setattr( + ... _QzTXNQFMN3z___lambda, + ... ('__qualname__'), + ... '_macro_.L10'), + ... _QzTXNQFMN3z___lambda) [-1] + ... )()), ... # __main__.._macro_.defmacro - ... # hissp.macros.._macro_.let - ... ( - ... lambda _Qz2D5FNHXZz___fn=(lambda *_QzXDFV7JLKz___expr: - ... (lambda * _: _)( - ... 'lambda', - ... 'ABCDEFGHIJK', - ... _QzXDFV7JLKz___expr) - ... ): - ... (__import__('builtins').setattr( - ... _Qz2D5FNHXZz___fn, - ... '__qualname__', - ... ('.').join( - ... ('_macro_', - ... 'L11',))), - ... __import__('builtins').setattr( - ... __import__('operator').getitem( - ... __import__('builtins').globals(), - ... '_macro_'), - ... 'L11', - ... _Qz2D5FNHXZz___fn)) [-1] - ... )(), + ... __import__('builtins').setattr( + ... __import__('builtins').globals().get( + ... ('_macro_')), + ... 'L11', + ... # hissp.macros.._macro_.fun + ... # hissp.macros.._macro_.let + ... ( + ... lambda _QzTXNQFMN3z___lambda=(lambda *_QzWWNCOLRLz___expr: + ... (lambda * _: _)( + ... 'lambda', + ... 'ABCDEFGHIJK', + ... _QzWWNCOLRLz___expr) + ... ): + ... (__import__('builtins').setattr( + ... _QzTXNQFMN3z___lambda, + ... ('__code__'), + ... _QzTXNQFMN3z___lambda.__code__.replace( + ... co_name='L11')), + ... __import__('builtins').setattr( + ... _QzTXNQFMN3z___lambda, + ... ('__name__'), + ... 'L11'), + ... __import__('builtins').setattr( + ... _QzTXNQFMN3z___lambda, + ... ('__qualname__'), + ... '_macro_.L11'), + ... _QzTXNQFMN3z___lambda) [-1] + ... )()), ... # __main__.._macro_.defmacro - ... # hissp.macros.._macro_.let - ... ( - ... lambda _Qz2D5FNHXZz___fn=(lambda *_QzXDFV7JLKz___expr: - ... (lambda * _: _)( - ... 'lambda', - ... 'ABCDEFGHIJKL', - ... _QzXDFV7JLKz___expr) - ... ): - ... (__import__('builtins').setattr( - ... _Qz2D5FNHXZz___fn, - ... '__qualname__', - ... ('.').join( - ... ('_macro_', - ... 'L12',))), - ... __import__('builtins').setattr( - ... __import__('operator').getitem( - ... __import__('builtins').globals(), - ... '_macro_'), - ... 'L12', - ... _Qz2D5FNHXZz___fn)) [-1] - ... )(), + ... __import__('builtins').setattr( + ... __import__('builtins').globals().get( + ... ('_macro_')), + ... 'L12', + ... # hissp.macros.._macro_.fun + ... # hissp.macros.._macro_.let + ... ( + ... lambda _QzTXNQFMN3z___lambda=(lambda *_QzWWNCOLRLz___expr: + ... (lambda * _: _)( + ... 'lambda', + ... 'ABCDEFGHIJKL', + ... _QzWWNCOLRLz___expr) + ... ): + ... (__import__('builtins').setattr( + ... _QzTXNQFMN3z___lambda, + ... ('__code__'), + ... _QzTXNQFMN3z___lambda.__code__.replace( + ... co_name='L12')), + ... __import__('builtins').setattr( + ... _QzTXNQFMN3z___lambda, + ... ('__name__'), + ... 'L12'), + ... __import__('builtins').setattr( + ... _QzTXNQFMN3z___lambda, + ... ('__qualname__'), + ... '_macro_.L12'), + ... _QzTXNQFMN3z___lambda) [-1] + ... )()), ... # __main__.._macro_.defmacro - ... # hissp.macros.._macro_.let - ... ( - ... lambda _Qz2D5FNHXZz___fn=(lambda *_QzXDFV7JLKz___expr: - ... (lambda * _: _)( - ... 'lambda', - ... 'ABCDEFGHIJKLM', - ... _QzXDFV7JLKz___expr) - ... ): - ... (__import__('builtins').setattr( - ... _Qz2D5FNHXZz___fn, - ... '__qualname__', - ... ('.').join( - ... ('_macro_', - ... 'L13',))), - ... __import__('builtins').setattr( - ... __import__('operator').getitem( - ... __import__('builtins').globals(), - ... '_macro_'), - ... 'L13', - ... _Qz2D5FNHXZz___fn)) [-1] - ... )(), + ... __import__('builtins').setattr( + ... __import__('builtins').globals().get( + ... ('_macro_')), + ... 'L13', + ... # hissp.macros.._macro_.fun + ... # hissp.macros.._macro_.let + ... ( + ... lambda _QzTXNQFMN3z___lambda=(lambda *_QzWWNCOLRLz___expr: + ... (lambda * _: _)( + ... 'lambda', + ... 'ABCDEFGHIJKLM', + ... _QzWWNCOLRLz___expr) + ... ): + ... (__import__('builtins').setattr( + ... _QzTXNQFMN3z___lambda, + ... ('__code__'), + ... _QzTXNQFMN3z___lambda.__code__.replace( + ... co_name='L13')), + ... __import__('builtins').setattr( + ... _QzTXNQFMN3z___lambda, + ... ('__name__'), + ... 'L13'), + ... __import__('builtins').setattr( + ... _QzTXNQFMN3z___lambda, + ... ('__qualname__'), + ... '_macro_.L13'), + ... _QzTXNQFMN3z___lambda) [-1] + ... )()), ... # __main__.._macro_.defmacro - ... # hissp.macros.._macro_.let - ... ( - ... lambda _Qz2D5FNHXZz___fn=(lambda *_QzXDFV7JLKz___expr: - ... (lambda * _: _)( - ... 'lambda', - ... 'ABCDEFGHIJKLMN', - ... _QzXDFV7JLKz___expr) - ... ): - ... (__import__('builtins').setattr( - ... _Qz2D5FNHXZz___fn, - ... '__qualname__', - ... ('.').join( - ... ('_macro_', - ... 'L14',))), - ... __import__('builtins').setattr( - ... __import__('operator').getitem( - ... __import__('builtins').globals(), - ... '_macro_'), - ... 'L14', - ... _Qz2D5FNHXZz___fn)) [-1] - ... )(), + ... __import__('builtins').setattr( + ... __import__('builtins').globals().get( + ... ('_macro_')), + ... 'L14', + ... # hissp.macros.._macro_.fun + ... # hissp.macros.._macro_.let + ... ( + ... lambda _QzTXNQFMN3z___lambda=(lambda *_QzWWNCOLRLz___expr: + ... (lambda * _: _)( + ... 'lambda', + ... 'ABCDEFGHIJKLMN', + ... _QzWWNCOLRLz___expr) + ... ): + ... (__import__('builtins').setattr( + ... _QzTXNQFMN3z___lambda, + ... ('__code__'), + ... _QzTXNQFMN3z___lambda.__code__.replace( + ... co_name='L14')), + ... __import__('builtins').setattr( + ... _QzTXNQFMN3z___lambda, + ... ('__name__'), + ... 'L14'), + ... __import__('builtins').setattr( + ... _QzTXNQFMN3z___lambda, + ... ('__qualname__'), + ... '_macro_.L14'), + ... _QzTXNQFMN3z___lambda) [-1] + ... )()), ... # __main__.._macro_.defmacro - ... # hissp.macros.._macro_.let - ... ( - ... lambda _Qz2D5FNHXZz___fn=(lambda *_QzXDFV7JLKz___expr: - ... (lambda * _: _)( - ... 'lambda', - ... 'ABCDEFGHIJKLMNO', - ... _QzXDFV7JLKz___expr) - ... ): - ... (__import__('builtins').setattr( - ... _Qz2D5FNHXZz___fn, - ... '__qualname__', - ... ('.').join( - ... ('_macro_', - ... 'L15',))), - ... __import__('builtins').setattr( - ... __import__('operator').getitem( - ... __import__('builtins').globals(), - ... '_macro_'), - ... 'L15', - ... _Qz2D5FNHXZz___fn)) [-1] - ... )(), + ... __import__('builtins').setattr( + ... __import__('builtins').globals().get( + ... ('_macro_')), + ... 'L15', + ... # hissp.macros.._macro_.fun + ... # hissp.macros.._macro_.let + ... ( + ... lambda _QzTXNQFMN3z___lambda=(lambda *_QzWWNCOLRLz___expr: + ... (lambda * _: _)( + ... 'lambda', + ... 'ABCDEFGHIJKLMNO', + ... _QzWWNCOLRLz___expr) + ... ): + ... (__import__('builtins').setattr( + ... _QzTXNQFMN3z___lambda, + ... ('__code__'), + ... _QzTXNQFMN3z___lambda.__code__.replace( + ... co_name='L15')), + ... __import__('builtins').setattr( + ... _QzTXNQFMN3z___lambda, + ... ('__name__'), + ... 'L15'), + ... __import__('builtins').setattr( + ... _QzTXNQFMN3z___lambda, + ... ('__qualname__'), + ... '_macro_.L15'), + ... _QzTXNQFMN3z___lambda) [-1] + ... )()), ... # __main__.._macro_.defmacro - ... # hissp.macros.._macro_.let - ... ( - ... lambda _Qz2D5FNHXZz___fn=(lambda *_QzXDFV7JLKz___expr: - ... (lambda * _: _)( - ... 'lambda', - ... 'ABCDEFGHIJKLMNOP', - ... _QzXDFV7JLKz___expr) - ... ): - ... (__import__('builtins').setattr( - ... _Qz2D5FNHXZz___fn, - ... '__qualname__', - ... ('.').join( - ... ('_macro_', - ... 'L16',))), - ... __import__('builtins').setattr( - ... __import__('operator').getitem( - ... __import__('builtins').globals(), - ... '_macro_'), - ... 'L16', - ... _Qz2D5FNHXZz___fn)) [-1] - ... )(), + ... __import__('builtins').setattr( + ... __import__('builtins').globals().get( + ... ('_macro_')), + ... 'L16', + ... # hissp.macros.._macro_.fun + ... # hissp.macros.._macro_.let + ... ( + ... lambda _QzTXNQFMN3z___lambda=(lambda *_QzWWNCOLRLz___expr: + ... (lambda * _: _)( + ... 'lambda', + ... 'ABCDEFGHIJKLMNOP', + ... _QzWWNCOLRLz___expr) + ... ): + ... (__import__('builtins').setattr( + ... _QzTXNQFMN3z___lambda, + ... ('__code__'), + ... _QzTXNQFMN3z___lambda.__code__.replace( + ... co_name='L16')), + ... __import__('builtins').setattr( + ... _QzTXNQFMN3z___lambda, + ... ('__name__'), + ... 'L16'), + ... __import__('builtins').setattr( + ... _QzTXNQFMN3z___lambda, + ... ('__qualname__'), + ... '_macro_.L16'), + ... _QzTXNQFMN3z___lambda) [-1] + ... )()), ... # __main__.._macro_.defmacro - ... # hissp.macros.._macro_.let - ... ( - ... lambda _Qz2D5FNHXZz___fn=(lambda *_QzXDFV7JLKz___expr: - ... (lambda * _: _)( - ... 'lambda', - ... 'ABCDEFGHIJKLMNOPQ', - ... _QzXDFV7JLKz___expr) - ... ): - ... (__import__('builtins').setattr( - ... _Qz2D5FNHXZz___fn, - ... '__qualname__', - ... ('.').join( - ... ('_macro_', - ... 'L17',))), - ... __import__('builtins').setattr( - ... __import__('operator').getitem( - ... __import__('builtins').globals(), - ... '_macro_'), - ... 'L17', - ... _Qz2D5FNHXZz___fn)) [-1] - ... )(), + ... __import__('builtins').setattr( + ... __import__('builtins').globals().get( + ... ('_macro_')), + ... 'L17', + ... # hissp.macros.._macro_.fun + ... # hissp.macros.._macro_.let + ... ( + ... lambda _QzTXNQFMN3z___lambda=(lambda *_QzWWNCOLRLz___expr: + ... (lambda * _: _)( + ... 'lambda', + ... 'ABCDEFGHIJKLMNOPQ', + ... _QzWWNCOLRLz___expr) + ... ): + ... (__import__('builtins').setattr( + ... _QzTXNQFMN3z___lambda, + ... ('__code__'), + ... _QzTXNQFMN3z___lambda.__code__.replace( + ... co_name='L17')), + ... __import__('builtins').setattr( + ... _QzTXNQFMN3z___lambda, + ... ('__name__'), + ... 'L17'), + ... __import__('builtins').setattr( + ... _QzTXNQFMN3z___lambda, + ... ('__qualname__'), + ... '_macro_.L17'), + ... _QzTXNQFMN3z___lambda) [-1] + ... )()), ... # __main__.._macro_.defmacro - ... # hissp.macros.._macro_.let - ... ( - ... lambda _Qz2D5FNHXZz___fn=(lambda *_QzXDFV7JLKz___expr: - ... (lambda * _: _)( - ... 'lambda', - ... 'ABCDEFGHIJKLMNOPQR', - ... _QzXDFV7JLKz___expr) - ... ): - ... (__import__('builtins').setattr( - ... _Qz2D5FNHXZz___fn, - ... '__qualname__', - ... ('.').join( - ... ('_macro_', - ... 'L18',))), - ... __import__('builtins').setattr( - ... __import__('operator').getitem( - ... __import__('builtins').globals(), - ... '_macro_'), - ... 'L18', - ... _Qz2D5FNHXZz___fn)) [-1] - ... )(), + ... __import__('builtins').setattr( + ... __import__('builtins').globals().get( + ... ('_macro_')), + ... 'L18', + ... # hissp.macros.._macro_.fun + ... # hissp.macros.._macro_.let + ... ( + ... lambda _QzTXNQFMN3z___lambda=(lambda *_QzWWNCOLRLz___expr: + ... (lambda * _: _)( + ... 'lambda', + ... 'ABCDEFGHIJKLMNOPQR', + ... _QzWWNCOLRLz___expr) + ... ): + ... (__import__('builtins').setattr( + ... _QzTXNQFMN3z___lambda, + ... ('__code__'), + ... _QzTXNQFMN3z___lambda.__code__.replace( + ... co_name='L18')), + ... __import__('builtins').setattr( + ... _QzTXNQFMN3z___lambda, + ... ('__name__'), + ... 'L18'), + ... __import__('builtins').setattr( + ... _QzTXNQFMN3z___lambda, + ... ('__qualname__'), + ... '_macro_.L18'), + ... _QzTXNQFMN3z___lambda) [-1] + ... )()), ... # __main__.._macro_.defmacro - ... # hissp.macros.._macro_.let - ... ( - ... lambda _Qz2D5FNHXZz___fn=(lambda *_QzXDFV7JLKz___expr: - ... (lambda * _: _)( - ... 'lambda', - ... 'ABCDEFGHIJKLMNOPQRS', - ... _QzXDFV7JLKz___expr) - ... ): - ... (__import__('builtins').setattr( - ... _Qz2D5FNHXZz___fn, - ... '__qualname__', - ... ('.').join( - ... ('_macro_', - ... 'L19',))), - ... __import__('builtins').setattr( - ... __import__('operator').getitem( - ... __import__('builtins').globals(), - ... '_macro_'), - ... 'L19', - ... _Qz2D5FNHXZz___fn)) [-1] - ... )(), + ... __import__('builtins').setattr( + ... __import__('builtins').globals().get( + ... ('_macro_')), + ... 'L19', + ... # hissp.macros.._macro_.fun + ... # hissp.macros.._macro_.let + ... ( + ... lambda _QzTXNQFMN3z___lambda=(lambda *_QzWWNCOLRLz___expr: + ... (lambda * _: _)( + ... 'lambda', + ... 'ABCDEFGHIJKLMNOPQRS', + ... _QzWWNCOLRLz___expr) + ... ): + ... (__import__('builtins').setattr( + ... _QzTXNQFMN3z___lambda, + ... ('__code__'), + ... _QzTXNQFMN3z___lambda.__code__.replace( + ... co_name='L19')), + ... __import__('builtins').setattr( + ... _QzTXNQFMN3z___lambda, + ... ('__name__'), + ... 'L19'), + ... __import__('builtins').setattr( + ... _QzTXNQFMN3z___lambda, + ... ('__qualname__'), + ... '_macro_.L19'), + ... _QzTXNQFMN3z___lambda) [-1] + ... )()), ... # __main__.._macro_.defmacro - ... # hissp.macros.._macro_.let - ... ( - ... lambda _Qz2D5FNHXZz___fn=(lambda *_QzXDFV7JLKz___expr: - ... (lambda * _: _)( - ... 'lambda', - ... 'ABCDEFGHIJKLMNOPQRST', - ... _QzXDFV7JLKz___expr) - ... ): - ... (__import__('builtins').setattr( - ... _Qz2D5FNHXZz___fn, - ... '__qualname__', - ... ('.').join( - ... ('_macro_', - ... 'L20',))), - ... __import__('builtins').setattr( - ... __import__('operator').getitem( - ... __import__('builtins').globals(), - ... '_macro_'), - ... 'L20', - ... _Qz2D5FNHXZz___fn)) [-1] - ... )(), + ... __import__('builtins').setattr( + ... __import__('builtins').globals().get( + ... ('_macro_')), + ... 'L20', + ... # hissp.macros.._macro_.fun + ... # hissp.macros.._macro_.let + ... ( + ... lambda _QzTXNQFMN3z___lambda=(lambda *_QzWWNCOLRLz___expr: + ... (lambda * _: _)( + ... 'lambda', + ... 'ABCDEFGHIJKLMNOPQRST', + ... _QzWWNCOLRLz___expr) + ... ): + ... (__import__('builtins').setattr( + ... _QzTXNQFMN3z___lambda, + ... ('__code__'), + ... _QzTXNQFMN3z___lambda.__code__.replace( + ... co_name='L20')), + ... __import__('builtins').setattr( + ... _QzTXNQFMN3z___lambda, + ... ('__name__'), + ... 'L20'), + ... __import__('builtins').setattr( + ... _QzTXNQFMN3z___lambda, + ... ('__qualname__'), + ... '_macro_.L20'), + ... _QzTXNQFMN3z___lambda) [-1] + ... )()), ... # __main__.._macro_.defmacro - ... # hissp.macros.._macro_.let - ... ( - ... lambda _Qz2D5FNHXZz___fn=(lambda *_QzXDFV7JLKz___expr: - ... (lambda * _: _)( - ... 'lambda', - ... 'ABCDEFGHIJKLMNOPQRSTU', - ... _QzXDFV7JLKz___expr) - ... ): - ... (__import__('builtins').setattr( - ... _Qz2D5FNHXZz___fn, - ... '__qualname__', - ... ('.').join( - ... ('_macro_', - ... 'L21',))), - ... __import__('builtins').setattr( - ... __import__('operator').getitem( - ... __import__('builtins').globals(), - ... '_macro_'), - ... 'L21', - ... _Qz2D5FNHXZz___fn)) [-1] - ... )(), + ... __import__('builtins').setattr( + ... __import__('builtins').globals().get( + ... ('_macro_')), + ... 'L21', + ... # hissp.macros.._macro_.fun + ... # hissp.macros.._macro_.let + ... ( + ... lambda _QzTXNQFMN3z___lambda=(lambda *_QzWWNCOLRLz___expr: + ... (lambda * _: _)( + ... 'lambda', + ... 'ABCDEFGHIJKLMNOPQRSTU', + ... _QzWWNCOLRLz___expr) + ... ): + ... (__import__('builtins').setattr( + ... _QzTXNQFMN3z___lambda, + ... ('__code__'), + ... _QzTXNQFMN3z___lambda.__code__.replace( + ... co_name='L21')), + ... __import__('builtins').setattr( + ... _QzTXNQFMN3z___lambda, + ... ('__name__'), + ... 'L21'), + ... __import__('builtins').setattr( + ... _QzTXNQFMN3z___lambda, + ... ('__qualname__'), + ... '_macro_.L21'), + ... _QzTXNQFMN3z___lambda) [-1] + ... )()), ... # __main__.._macro_.defmacro - ... # hissp.macros.._macro_.let - ... ( - ... lambda _Qz2D5FNHXZz___fn=(lambda *_QzXDFV7JLKz___expr: - ... (lambda * _: _)( - ... 'lambda', - ... 'ABCDEFGHIJKLMNOPQRSTUV', - ... _QzXDFV7JLKz___expr) - ... ): - ... (__import__('builtins').setattr( - ... _Qz2D5FNHXZz___fn, - ... '__qualname__', - ... ('.').join( - ... ('_macro_', - ... 'L22',))), - ... __import__('builtins').setattr( - ... __import__('operator').getitem( - ... __import__('builtins').globals(), - ... '_macro_'), - ... 'L22', - ... _Qz2D5FNHXZz___fn)) [-1] - ... )(), + ... __import__('builtins').setattr( + ... __import__('builtins').globals().get( + ... ('_macro_')), + ... 'L22', + ... # hissp.macros.._macro_.fun + ... # hissp.macros.._macro_.let + ... ( + ... lambda _QzTXNQFMN3z___lambda=(lambda *_QzWWNCOLRLz___expr: + ... (lambda * _: _)( + ... 'lambda', + ... 'ABCDEFGHIJKLMNOPQRSTUV', + ... _QzWWNCOLRLz___expr) + ... ): + ... (__import__('builtins').setattr( + ... _QzTXNQFMN3z___lambda, + ... ('__code__'), + ... _QzTXNQFMN3z___lambda.__code__.replace( + ... co_name='L22')), + ... __import__('builtins').setattr( + ... _QzTXNQFMN3z___lambda, + ... ('__name__'), + ... 'L22'), + ... __import__('builtins').setattr( + ... _QzTXNQFMN3z___lambda, + ... ('__qualname__'), + ... '_macro_.L22'), + ... _QzTXNQFMN3z___lambda) [-1] + ... )()), ... # __main__.._macro_.defmacro - ... # hissp.macros.._macro_.let - ... ( - ... lambda _Qz2D5FNHXZz___fn=(lambda *_QzXDFV7JLKz___expr: - ... (lambda * _: _)( - ... 'lambda', - ... 'ABCDEFGHIJKLMNOPQRSTUVW', - ... _QzXDFV7JLKz___expr) - ... ): - ... (__import__('builtins').setattr( - ... _Qz2D5FNHXZz___fn, - ... '__qualname__', - ... ('.').join( - ... ('_macro_', - ... 'L23',))), - ... __import__('builtins').setattr( - ... __import__('operator').getitem( - ... __import__('builtins').globals(), - ... '_macro_'), - ... 'L23', - ... _Qz2D5FNHXZz___fn)) [-1] - ... )(), + ... __import__('builtins').setattr( + ... __import__('builtins').globals().get( + ... ('_macro_')), + ... 'L23', + ... # hissp.macros.._macro_.fun + ... # hissp.macros.._macro_.let + ... ( + ... lambda _QzTXNQFMN3z___lambda=(lambda *_QzWWNCOLRLz___expr: + ... (lambda * _: _)( + ... 'lambda', + ... 'ABCDEFGHIJKLMNOPQRSTUVW', + ... _QzWWNCOLRLz___expr) + ... ): + ... (__import__('builtins').setattr( + ... _QzTXNQFMN3z___lambda, + ... ('__code__'), + ... _QzTXNQFMN3z___lambda.__code__.replace( + ... co_name='L23')), + ... __import__('builtins').setattr( + ... _QzTXNQFMN3z___lambda, + ... ('__name__'), + ... 'L23'), + ... __import__('builtins').setattr( + ... _QzTXNQFMN3z___lambda, + ... ('__qualname__'), + ... '_macro_.L23'), + ... _QzTXNQFMN3z___lambda) [-1] + ... )()), ... # __main__.._macro_.defmacro - ... # hissp.macros.._macro_.let - ... ( - ... lambda _Qz2D5FNHXZz___fn=(lambda *_QzXDFV7JLKz___expr: - ... (lambda * _: _)( - ... 'lambda', - ... 'ABCDEFGHIJKLMNOPQRSTUVWX', - ... _QzXDFV7JLKz___expr) - ... ): - ... (__import__('builtins').setattr( - ... _Qz2D5FNHXZz___fn, - ... '__qualname__', - ... ('.').join( - ... ('_macro_', - ... 'L24',))), - ... __import__('builtins').setattr( - ... __import__('operator').getitem( - ... __import__('builtins').globals(), - ... '_macro_'), - ... 'L24', - ... _Qz2D5FNHXZz___fn)) [-1] - ... )(), + ... __import__('builtins').setattr( + ... __import__('builtins').globals().get( + ... ('_macro_')), + ... 'L24', + ... # hissp.macros.._macro_.fun + ... # hissp.macros.._macro_.let + ... ( + ... lambda _QzTXNQFMN3z___lambda=(lambda *_QzWWNCOLRLz___expr: + ... (lambda * _: _)( + ... 'lambda', + ... 'ABCDEFGHIJKLMNOPQRSTUVWX', + ... _QzWWNCOLRLz___expr) + ... ): + ... (__import__('builtins').setattr( + ... _QzTXNQFMN3z___lambda, + ... ('__code__'), + ... _QzTXNQFMN3z___lambda.__code__.replace( + ... co_name='L24')), + ... __import__('builtins').setattr( + ... _QzTXNQFMN3z___lambda, + ... ('__name__'), + ... 'L24'), + ... __import__('builtins').setattr( + ... _QzTXNQFMN3z___lambda, + ... ('__qualname__'), + ... '_macro_.L24'), + ... _QzTXNQFMN3z___lambda) [-1] + ... )()), ... # __main__.._macro_.defmacro - ... # hissp.macros.._macro_.let - ... ( - ... lambda _Qz2D5FNHXZz___fn=(lambda *_QzXDFV7JLKz___expr: - ... (lambda * _: _)( - ... 'lambda', - ... 'ABCDEFGHIJKLMNOPQRSTUVWXY', - ... _QzXDFV7JLKz___expr) - ... ): - ... (__import__('builtins').setattr( - ... _Qz2D5FNHXZz___fn, - ... '__qualname__', - ... ('.').join( - ... ('_macro_', - ... 'L25',))), - ... __import__('builtins').setattr( - ... __import__('operator').getitem( - ... __import__('builtins').globals(), - ... '_macro_'), - ... 'L25', - ... _Qz2D5FNHXZz___fn)) [-1] - ... )(), + ... __import__('builtins').setattr( + ... __import__('builtins').globals().get( + ... ('_macro_')), + ... 'L25', + ... # hissp.macros.._macro_.fun + ... # hissp.macros.._macro_.let + ... ( + ... lambda _QzTXNQFMN3z___lambda=(lambda *_QzWWNCOLRLz___expr: + ... (lambda * _: _)( + ... 'lambda', + ... 'ABCDEFGHIJKLMNOPQRSTUVWXY', + ... _QzWWNCOLRLz___expr) + ... ): + ... (__import__('builtins').setattr( + ... _QzTXNQFMN3z___lambda, + ... ('__code__'), + ... _QzTXNQFMN3z___lambda.__code__.replace( + ... co_name='L25')), + ... __import__('builtins').setattr( + ... _QzTXNQFMN3z___lambda, + ... ('__name__'), + ... 'L25'), + ... __import__('builtins').setattr( + ... _QzTXNQFMN3z___lambda, + ... ('__qualname__'), + ... '_macro_.L25'), + ... _QzTXNQFMN3z___lambda) [-1] + ... )()), ... # __main__.._macro_.defmacro - ... # hissp.macros.._macro_.let - ... ( - ... lambda _Qz2D5FNHXZz___fn=(lambda *_QzXDFV7JLKz___expr: - ... (lambda * _: _)( - ... 'lambda', - ... 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', - ... _QzXDFV7JLKz___expr) - ... ): - ... (__import__('builtins').setattr( - ... _Qz2D5FNHXZz___fn, - ... '__qualname__', - ... ('.').join( - ... ('_macro_', - ... 'L26',))), - ... __import__('builtins').setattr( - ... __import__('operator').getitem( - ... __import__('builtins').globals(), - ... '_macro_'), - ... 'L26', - ... _Qz2D5FNHXZz___fn)) [-1] - ... )()) [-1] + ... __import__('builtins').setattr( + ... __import__('builtins').globals().get( + ... ('_macro_')), + ... 'L26', + ... # hissp.macros.._macro_.fun + ... # hissp.macros.._macro_.let + ... ( + ... lambda _QzTXNQFMN3z___lambda=(lambda *_QzWWNCOLRLz___expr: + ... (lambda * _: _)( + ... 'lambda', + ... 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', + ... _QzWWNCOLRLz___expr) + ... ): + ... (__import__('builtins').setattr( + ... _QzTXNQFMN3z___lambda, + ... ('__code__'), + ... _QzTXNQFMN3z___lambda.__code__.replace( + ... co_name='L26')), + ... __import__('builtins').setattr( + ... _QzTXNQFMN3z___lambda, + ... ('__name__'), + ... 'L26'), + ... __import__('builtins').setattr( + ... _QzTXNQFMN3z___lambda, + ... ('__qualname__'), + ... '_macro_.L26'), + ... _QzTXNQFMN3z___lambda) [-1] + ... )())) [-1] ... )() Whoa. @@ -1583,36 +1792,43 @@ We can create numbered X's the same way we created the numbered L's. #.. (range 1 (add 1 number))) #.. ,expr)) >>> # defmacro - ... # hissp.macros.._macro_.let - ... ( - ... lambda _QzAW22OE5Kz___fn=(lambda number, *expr: - ... (lambda * _: _)( - ... 'lambda', - ... map( - ... (lambda i: - ... ('X{}').format( - ... i) - ... ), - ... range( - ... (1), - ... add( + ... __import__('builtins').setattr( + ... __import__('builtins').globals().get( + ... ('_macro_')), + ... 'L', + ... # hissp.macros.._macro_.fun + ... # hissp.macros.._macro_.let + ... ( + ... lambda _QzTXNQFMN3z___lambda=(lambda number, *expr: + ... (lambda * _: _)( + ... 'lambda', + ... map( + ... (lambda i: + ... ('X{}').format( + ... i) + ... ), + ... range( ... (1), - ... number))), - ... expr) - ... ): - ... (__import__('builtins').setattr( - ... _QzAW22OE5Kz___fn, - ... '__qualname__', - ... ('.').join( - ... ('_macro_', - ... 'L',))), - ... __import__('builtins').setattr( - ... __import__('operator').getitem( - ... __import__('builtins').globals(), - ... '_macro_'), - ... 'L', - ... _QzAW22OE5Kz___fn)) [-1] - ... )() + ... add( + ... (1), + ... number))), + ... expr) + ... ): + ... (__import__('builtins').setattr( + ... _QzTXNQFMN3z___lambda, + ... ('__code__'), + ... _QzTXNQFMN3z___lambda.__code__.replace( + ... co_name='L')), + ... __import__('builtins').setattr( + ... _QzTXNQFMN3z___lambda, + ... ('__name__'), + ... 'L'), + ... __import__('builtins').setattr( + ... _QzTXNQFMN3z___lambda, + ... ('__qualname__'), + ... '_macro_.L'), + ... _QzTXNQFMN3z___lambda) [-1] + ... )()) .. tip:: @@ -1660,37 +1876,44 @@ Let's make a slight tweak. #.. (range 1 (add 1 (max-X expr)))) #.. ,expr)) >>> # defmacro - ... # hissp.macros.._macro_.let - ... ( - ... lambda _QzAW22OE5Kz___fn=(lambda *expr: - ... (lambda * _: _)( - ... 'lambda', - ... map( - ... (lambda i: - ... ('X{}').format( - ... i) - ... ), - ... range( - ... (1), - ... add( + ... __import__('builtins').setattr( + ... __import__('builtins').globals().get( + ... ('_macro_')), + ... 'L', + ... # hissp.macros.._macro_.fun + ... # hissp.macros.._macro_.let + ... ( + ... lambda _QzTXNQFMN3z___lambda=(lambda *expr: + ... (lambda * _: _)( + ... 'lambda', + ... map( + ... (lambda i: + ... ('X{}').format( + ... i) + ... ), + ... range( ... (1), - ... maxQz_X( - ... expr)))), - ... expr) - ... ): - ... (__import__('builtins').setattr( - ... _QzAW22OE5Kz___fn, - ... '__qualname__', - ... ('.').join( - ... ('_macro_', - ... 'L',))), - ... __import__('builtins').setattr( - ... __import__('operator').getitem( - ... __import__('builtins').globals(), - ... '_macro_'), - ... 'L', - ... _QzAW22OE5Kz___fn)) [-1] - ... )() + ... add( + ... (1), + ... maxQz_X( + ... expr)))), + ... expr) + ... ): + ... (__import__('builtins').setattr( + ... _QzTXNQFMN3z___lambda, + ... ('__code__'), + ... _QzTXNQFMN3z___lambda.__code__.replace( + ... co_name='L')), + ... __import__('builtins').setattr( + ... _QzTXNQFMN3z___lambda, + ... ('__name__'), + ... 'L'), + ... __import__('builtins').setattr( + ... _QzTXNQFMN3z___lambda, + ... ('__qualname__'), + ... '_macro_.L'), + ... _QzTXNQFMN3z___lambda) [-1] + ... )()) What is this ``max-X``? @@ -2003,27 +2226,35 @@ you must define them in ``_macro_`` with a name ending in a ``#``. #> (defmacro X\# (expr) #.. `(L ,@expr)) + FULL COMPILATION: >>> # defmacro - ... # hissp.macros.._macro_.let - ... ( - ... lambda _QzAW22OE5Kz___fn=(lambda expr: - ... (lambda * _: _)( - ... '__main__.._macro_.L', - ... *expr) - ... ): - ... (__import__('builtins').setattr( - ... _QzAW22OE5Kz___fn, - ... '__qualname__', - ... ('.').join( - ... ('_macro_', - ... 'XQzHASH_',))), - ... __import__('builtins').setattr( - ... __import__('operator').getitem( - ... __import__('builtins').globals(), - ... '_macro_'), - ... 'XQzHASH_', - ... _QzAW22OE5Kz___fn)) [-1] - ... )() + ... __import__('builtins').setattr( + ... __import__('builtins').globals().get( + ... ('_macro_')), + ... 'XQzHASH_', + ... # hissp.macros.._macro_.fun + ... # hissp.macros.._macro_.let + ... ( + ... lambda _QzTXNQFMN3z___lambda=(lambda expr: + ... (lambda * _: _)( + ... '__main__.._macro_.L', + ... *expr) + ... ): + ... (__import__('builtins').setattr( + ... _QzTXNQFMN3z___lambda, + ... ('__code__'), + ... _QzTXNQFMN3z___lambda.__code__.replace( + ... co_name='XQzHASH_')), + ... __import__('builtins').setattr( + ... _QzTXNQFMN3z___lambda, + ... ('__name__'), + ... 'XQzHASH_'), + ... __import__('builtins').setattr( + ... _QzTXNQFMN3z___lambda, + ... ('__qualname__'), + ... '_macro_.XQzHASH_'), + ... _QzTXNQFMN3z___lambda) [-1] + ... )()) We have to escape the ``#`` with a backslash or the reader will parse the name as a tag rather than a symbol @@ -2105,50 +2336,57 @@ Catch-All Parameter #.. `(:* ,'Xi))) #.. ,expr)) >>> # defmacro - ... # hissp.macros.._macro_.let - ... ( - ... lambda _QzAW22OE5Kz___fn=(lambda *expr: - ... (lambda * _: _)( - ... 'lambda', + ... __import__('builtins').setattr( + ... __import__('builtins').globals().get( + ... ('_macro_')), + ... 'L', + ... # hissp.macros.._macro_.fun + ... # hissp.macros.._macro_.let + ... ( + ... lambda _QzTXNQFMN3z___lambda=(lambda *expr: ... (lambda * _: _)( - ... *map( - ... (lambda i: - ... ('X{}').format( - ... i) - ... ), - ... range( - ... (1), - ... add( + ... 'lambda', + ... (lambda * _: _)( + ... *map( + ... (lambda i: + ... ('X{}').format( + ... i) + ... ), + ... range( ... (1), - ... maxQz_X( - ... expr)))), - ... ':', - ... *# when - ... (lambda b, c: c()if b else())( - ... contains( - ... flatten( - ... expr), - ... 'Xi'), - ... (lambda : - ... (lambda * _: _)( - ... ':*', - ... 'Xi') - ... ))), - ... expr) - ... ): - ... (__import__('builtins').setattr( - ... _QzAW22OE5Kz___fn, - ... '__qualname__', - ... ('.').join( - ... ('_macro_', - ... 'L',))), - ... __import__('builtins').setattr( - ... __import__('operator').getitem( - ... __import__('builtins').globals(), - ... '_macro_'), - ... 'L', - ... _QzAW22OE5Kz___fn)) [-1] - ... )() + ... add( + ... (1), + ... maxQz_X( + ... expr)))), + ... ':', + ... *# when + ... (lambda b, c: c()if b else())( + ... contains( + ... flatten( + ... expr), + ... 'Xi'), + ... (lambda : + ... (lambda * _: _)( + ... ':*', + ... 'Xi') + ... ))), + ... expr) + ... ): + ... (__import__('builtins').setattr( + ... _QzTXNQFMN3z___lambda, + ... ('__code__'), + ... _QzTXNQFMN3z___lambda.__code__.replace( + ... co_name='L')), + ... __import__('builtins').setattr( + ... _QzTXNQFMN3z___lambda, + ... ('__name__'), + ... 'L'), + ... __import__('builtins').setattr( + ... _QzTXNQFMN3z___lambda, + ... ('__qualname__'), + ... '_macro_.L'), + ... _QzTXNQFMN3z___lambda) [-1] + ... )()) .. code-block:: REPL @@ -2242,72 +2480,79 @@ Here you go: #.. ,expr) #.. expr))) >>> # defmacro - ... # hissp.macros.._macro_.let - ... ( - ... lambda _QzAW22OE5Kz___fn=(lambda *expr: - ... (lambda * _: _)( - ... 'lambda', + ... __import__('builtins').setattr( + ... __import__('builtins').globals().get( + ... ('_macro_')), + ... 'L', + ... # hissp.macros.._macro_.fun + ... # hissp.macros.._macro_.let + ... ( + ... lambda _QzTXNQFMN3z___lambda=(lambda *expr: ... (lambda * _: _)( - ... *map( - ... (lambda i: - ... ('X{}').format( - ... i) - ... ), - ... range( - ... (1), - ... add( + ... 'lambda', + ... (lambda * _: _)( + ... *map( + ... (lambda i: + ... ('X{}').format( + ... i) + ... ), + ... range( ... (1), - ... # ors - ... (lambda x0, x1: x0 or x1())( - ... maxQz_X( - ... expr), - ... (lambda : - ... contains( - ... flatten( - ... expr), - ... 'X') - ... ))))), - ... ':', - ... *# when - ... (lambda b, c: c()if b else())( - ... contains( - ... flatten( - ... expr), - ... 'Xi'), - ... (lambda : - ... (lambda * _: _)( - ... ':*', - ... 'Xi') - ... ))), - ... # ifQz_else - ... (lambda b, c, a: c()if b else a())( - ... contains( - ... flatten( - ... expr), - ... 'X'), - ... (lambda : - ... (lambda * _: _)( - ... '__main__.._macro_.let', + ... add( + ... (1), + ... # ors + ... (lambda x0, x1: x0 or x1())( + ... maxQz_X( + ... expr), + ... (lambda : + ... contains( + ... flatten( + ... expr), + ... 'X') + ... ))))), + ... ':', + ... *# when + ... (lambda b, c: c()if b else())( + ... contains( + ... flatten( + ... expr), + ... 'Xi'), + ... (lambda : + ... (lambda * _: _)( + ... ':*', + ... 'Xi') + ... ))), + ... # ifQz_else + ... (lambda b, c, a: c()if b else a())( + ... contains( + ... flatten( + ... expr), + ... 'X'), + ... (lambda : ... (lambda * _: _)( - ... 'X', - ... 'X1'), - ... expr) - ... ), - ... (lambda : expr))) - ... ): - ... (__import__('builtins').setattr( - ... _QzAW22OE5Kz___fn, - ... '__qualname__', - ... ('.').join( - ... ('_macro_', - ... 'L',))), - ... __import__('builtins').setattr( - ... __import__('operator').getitem( - ... __import__('builtins').globals(), - ... '_macro_'), - ... 'L', - ... _QzAW22OE5Kz___fn)) [-1] - ... )() + ... '__main__.._macro_.let', + ... (lambda * _: _)( + ... 'X', + ... 'X1'), + ... expr) + ... ), + ... (lambda : expr))) + ... ): + ... (__import__('builtins').setattr( + ... _QzTXNQFMN3z___lambda, + ... ('__code__'), + ... _QzTXNQFMN3z___lambda.__code__.replace( + ... co_name='L')), + ... __import__('builtins').setattr( + ... _QzTXNQFMN3z___lambda, + ... ('__name__'), + ... 'L'), + ... __import__('builtins').setattr( + ... _QzTXNQFMN3z___lambda, + ... ('__qualname__'), + ... '_macro_.L'), + ... _QzTXNQFMN3z___lambda) [-1] + ... )()) .. code-block:: REPL @@ -2342,7 +2587,7 @@ and ``True`` is a special case of ``1`` in Python. Writing tests is a little beyond the scope of this lesson, but you can use `assure` forms at the top level or subclass the standard library - `unittest.TestCase` class in Lissp (with a `deftype`), + `unittest.TestCase` class in Lissp (with a `deftypeonce` and `defun`\ s), just like Python. .. topic:: Exercise: refactoring @@ -2588,26 +2833,33 @@ Lissp gives us a better option. #> (defmacro \16\# (x) #.. (int x 16)) >>> # defmacro - ... # hissp.macros.._macro_.let - ... ( - ... lambda _QzAW22OE5Kz___fn=(lambda x: - ... int( - ... x, - ... (16)) - ... ): - ... (__import__('builtins').setattr( - ... _QzAW22OE5Kz___fn, - ... '__qualname__', - ... ('.').join( - ... ('_macro_', - ... 'QzDIGITxONE_6QzHASH_',))), - ... __import__('builtins').setattr( - ... __import__('operator').getitem( - ... __import__('builtins').globals(), - ... '_macro_'), - ... 'QzDIGITxONE_6QzHASH_', - ... _QzAW22OE5Kz___fn)) [-1] - ... )() + ... __import__('builtins').setattr( + ... __import__('builtins').globals().get( + ... ('_macro_')), + ... 'QzDIGITxONE_6QzHASH_', + ... # hissp.macros.._macro_.fun + ... # hissp.macros.._macro_.let + ... ( + ... lambda _QzTXNQFMN3z___lambda=(lambda x: + ... int( + ... x, + ... (16)) + ... ): + ... (__import__('builtins').setattr( + ... _QzTXNQFMN3z___lambda, + ... ('__code__'), + ... _QzTXNQFMN3z___lambda.__code__.replace( + ... co_name='QzDIGITxONE_6QzHASH_')), + ... __import__('builtins').setattr( + ... _QzTXNQFMN3z___lambda, + ... ('__name__'), + ... 'QzDIGITxONE_6QzHASH_'), + ... __import__('builtins').setattr( + ... _QzTXNQFMN3z___lambda, + ... ('__qualname__'), + ... '_macro_.QzDIGITxONE_6QzHASH_'), + ... _QzTXNQFMN3z___lambda) [-1] + ... )()) We've defined a tag that turns hexadecimal strings into ints. And it does it so at *read time*. @@ -2663,27 +2915,34 @@ New version. #> (defmacro \16\# (x) #.. (int (str x) 16)) >>> # defmacro - ... # hissp.macros.._macro_.let - ... ( - ... lambda _QzAW22OE5Kz___fn=(lambda x: - ... int( - ... str( - ... x), - ... (16)) - ... ): - ... (__import__('builtins').setattr( - ... _QzAW22OE5Kz___fn, - ... '__qualname__', - ... ('.').join( - ... ('_macro_', - ... 'QzDIGITxONE_6QzHASH_',))), - ... __import__('builtins').setattr( - ... __import__('operator').getitem( - ... __import__('builtins').globals(), - ... '_macro_'), - ... 'QzDIGITxONE_6QzHASH_', - ... _QzAW22OE5Kz___fn)) [-1] - ... )() + ... __import__('builtins').setattr( + ... __import__('builtins').globals().get( + ... ('_macro_')), + ... 'QzDIGITxONE_6QzHASH_', + ... # hissp.macros.._macro_.fun + ... # hissp.macros.._macro_.let + ... ( + ... lambda _QzTXNQFMN3z___lambda=(lambda x: + ... int( + ... str( + ... x), + ... (16)) + ... ): + ... (__import__('builtins').setattr( + ... _QzTXNQFMN3z___lambda, + ... ('__code__'), + ... _QzTXNQFMN3z___lambda.__code__.replace( + ... co_name='QzDIGITxONE_6QzHASH_')), + ... __import__('builtins').setattr( + ... _QzTXNQFMN3z___lambda, + ... ('__name__'), + ... 'QzDIGITxONE_6QzHASH_'), + ... __import__('builtins').setattr( + ... _QzTXNQFMN3z___lambda, + ... ('__qualname__'), + ... '_macro_.QzDIGITxONE_6QzHASH_'), + ... _QzTXNQFMN3z___lambda) [-1] + ... )()) And now it works as well as the built-in notation. @@ -2767,33 +3026,39 @@ because munging is (mostly) reversible. #.. (int (hissp..demunge (str x)) #.. 16)) >>> # defmacro - ... # hissp.macros.._macro_.let - ... ( - ... lambda _QzAW22OE5Kz___fn=(lambda x: - ... (('hexadecimal'), - ... int( - ... __import__('hissp').demunge( - ... str( - ... x)), - ... (16))) [-1] - ... ): - ... (__import__('builtins').setattr( - ... _QzAW22OE5Kz___fn, - ... '__doc__', - ... ('hexadecimal')), - ... __import__('builtins').setattr( - ... _QzAW22OE5Kz___fn, - ... '__qualname__', - ... ('.').join( - ... ('_macro_', - ... 'QzDIGITxONE_6QzHASH_',))), - ... __import__('builtins').setattr( - ... __import__('operator').getitem( - ... __import__('builtins').globals(), - ... '_macro_'), - ... 'QzDIGITxONE_6QzHASH_', - ... _QzAW22OE5Kz___fn)) [-1] - ... )() + ... __import__('builtins').setattr( + ... __import__('builtins').globals().get( + ... ('_macro_')), + ... 'QzDIGITxONE_6QzHASH_', + ... # hissp.macros.._macro_.fun + ... # hissp.macros.._macro_.let + ... ( + ... lambda _QzTXNQFMN3z___lambda=(lambda x: + ... int( + ... __import__('hissp').demunge( + ... str( + ... x)), + ... (16)) + ... ): + ... (__import__('builtins').setattr( + ... _QzTXNQFMN3z___lambda, + ... ('__doc__'), + ... ('hexadecimal')), + ... __import__('builtins').setattr( + ... _QzTXNQFMN3z___lambda, + ... ('__code__'), + ... _QzTXNQFMN3z___lambda.__code__.replace( + ... co_name='QzDIGITxONE_6QzHASH_')), + ... __import__('builtins').setattr( + ... _QzTXNQFMN3z___lambda, + ... ('__name__'), + ... 'QzDIGITxONE_6QzHASH_'), + ... __import__('builtins').setattr( + ... _QzTXNQFMN3z___lambda, + ... ('__qualname__'), + ... '_macro_.QzDIGITxONE_6QzHASH_'), + ... _QzTXNQFMN3z___lambda) [-1] + ... )()) .. code-block:: REPL @@ -2811,32 +3076,38 @@ Well, with reader macros, you can implement any base you want. #.. "seximal" #.. (int (str x) 6)) >>> # defmacro - ... # hissp.macros.._macro_.let - ... ( - ... lambda _QzAW22OE5Kz___fn=(lambda x: - ... (('seximal'), - ... int( - ... str( - ... x), - ... (6))) [-1] - ... ): - ... (__import__('builtins').setattr( - ... _QzAW22OE5Kz___fn, - ... '__doc__', - ... ('seximal')), - ... __import__('builtins').setattr( - ... _QzAW22OE5Kz___fn, - ... '__qualname__', - ... ('.').join( - ... ('_macro_', - ... 'QzDIGITxSIX_QzHASH_',))), - ... __import__('builtins').setattr( - ... __import__('operator').getitem( - ... __import__('builtins').globals(), - ... '_macro_'), - ... 'QzDIGITxSIX_QzHASH_', - ... _QzAW22OE5Kz___fn)) [-1] - ... )() + ... __import__('builtins').setattr( + ... __import__('builtins').globals().get( + ... ('_macro_')), + ... 'QzDIGITxSIX_QzHASH_', + ... # hissp.macros.._macro_.fun + ... # hissp.macros.._macro_.let + ... ( + ... lambda _QzTXNQFMN3z___lambda=(lambda x: + ... int( + ... str( + ... x), + ... (6)) + ... ): + ... (__import__('builtins').setattr( + ... _QzTXNQFMN3z___lambda, + ... ('__doc__'), + ... ('seximal')), + ... __import__('builtins').setattr( + ... _QzTXNQFMN3z___lambda, + ... ('__code__'), + ... _QzTXNQFMN3z___lambda.__code__.replace( + ... co_name='QzDIGITxSIX_QzHASH_')), + ... __import__('builtins').setattr( + ... _QzTXNQFMN3z___lambda, + ... ('__name__'), + ... 'QzDIGITxSIX_QzHASH_'), + ... __import__('builtins').setattr( + ... _QzTXNQFMN3z___lambda, + ... ('__qualname__'), + ... '_macro_.QzDIGITxSIX_QzHASH_'), + ... _QzTXNQFMN3z___lambda) [-1] + ... )()) .. code-block:: REPL @@ -2861,43 +3132,50 @@ Or you can add floating-point. Python's literal notation can't do that. #.. (float.fromhex x) #.. (int x 16)))) >>> # defmacro - ... # hissp.macros.._macro_.let - ... ( - ... lambda _QzAW22OE5Kz___fn=(lambda x: - ... # let - ... ( - ... lambda x=__import__('hissp').demunge( - ... str( - ... x)): - ... # ifQz_else - ... (lambda b, c, a: c()if b else a())( - ... __import__('re').search( - ... ('[.Pp]'), - ... x), - ... (lambda : - ... float.fromhex( - ... x) - ... ), - ... (lambda : - ... int( - ... x, - ... (16)) - ... )) - ... )() - ... ): - ... (__import__('builtins').setattr( - ... _QzAW22OE5Kz___fn, - ... '__qualname__', - ... ('.').join( - ... ('_macro_', - ... 'QzDIGITxONE_6QzHASH_',))), - ... __import__('builtins').setattr( - ... __import__('operator').getitem( - ... __import__('builtins').globals(), - ... '_macro_'), - ... 'QzDIGITxONE_6QzHASH_', - ... _QzAW22OE5Kz___fn)) [-1] - ... )() + ... __import__('builtins').setattr( + ... __import__('builtins').globals().get( + ... ('_macro_')), + ... 'QzDIGITxONE_6QzHASH_', + ... # hissp.macros.._macro_.fun + ... # hissp.macros.._macro_.let + ... ( + ... lambda _QzTXNQFMN3z___lambda=(lambda x: + ... # let + ... ( + ... lambda x=__import__('hissp').demunge( + ... str( + ... x)): + ... # ifQz_else + ... (lambda b, c, a: c()if b else a())( + ... __import__('re').search( + ... ('[.Pp]'), + ... x), + ... (lambda : + ... float.fromhex( + ... x) + ... ), + ... (lambda : + ... int( + ... x, + ... (16)) + ... )) + ... )() + ... ): + ... (__import__('builtins').setattr( + ... _QzTXNQFMN3z___lambda, + ... ('__code__'), + ... _QzTXNQFMN3z___lambda.__code__.replace( + ... co_name='QzDIGITxONE_6QzHASH_')), + ... __import__('builtins').setattr( + ... _QzTXNQFMN3z___lambda, + ... ('__name__'), + ... 'QzDIGITxONE_6QzHASH_'), + ... __import__('builtins').setattr( + ... _QzTXNQFMN3z___lambda, + ... ('__qualname__'), + ... '_macro_.QzDIGITxONE_6QzHASH_'), + ... _QzTXNQFMN3z___lambda) [-1] + ... )()) .. code-block:: REPL @@ -3008,29 +3286,36 @@ We can improve this a lot with a custom defmacro. #> (defmacro \10\# (x) #.. `(decimal..Decimal ',(str x))) >>> # defmacro - ... # hissp.macros.._macro_.let - ... ( - ... lambda _QzAW22OE5Kz___fn=(lambda x: - ... (lambda * _: _)( - ... 'decimal..Decimal', + ... __import__('builtins').setattr( + ... __import__('builtins').globals().get( + ... ('_macro_')), + ... 'QzDIGITxONE_0QzHASH_', + ... # hissp.macros.._macro_.fun + ... # hissp.macros.._macro_.let + ... ( + ... lambda _QzTXNQFMN3z___lambda=(lambda x: ... (lambda * _: _)( - ... 'quote', - ... str( - ... x))) - ... ): - ... (__import__('builtins').setattr( - ... _QzAW22OE5Kz___fn, - ... '__qualname__', - ... ('.').join( - ... ('_macro_', - ... 'QzDIGITxONE_0QzHASH_',))), - ... __import__('builtins').setattr( - ... __import__('operator').getitem( - ... __import__('builtins').globals(), - ... '_macro_'), - ... 'QzDIGITxONE_0QzHASH_', - ... _QzAW22OE5Kz___fn)) [-1] - ... )() + ... 'decimal..Decimal', + ... (lambda * _: _)( + ... 'quote', + ... str( + ... x))) + ... ): + ... (__import__('builtins').setattr( + ... _QzTXNQFMN3z___lambda, + ... ('__code__'), + ... _QzTXNQFMN3z___lambda.__code__.replace( + ... co_name='QzDIGITxONE_0QzHASH_')), + ... __import__('builtins').setattr( + ... _QzTXNQFMN3z___lambda, + ... ('__name__'), + ... 'QzDIGITxONE_0QzHASH_'), + ... __import__('builtins').setattr( + ... _QzTXNQFMN3z___lambda, + ... ('__qualname__'), + ... '_macro_.QzDIGITxONE_0QzHASH_'), + ... _QzTXNQFMN3z___lambda) [-1] + ... )()) .. code-block:: REPL @@ -3089,32 +3374,39 @@ but a ``||`` fragment is not the only alternative available: #> (defmacro \10\# (x) #.. `(decimal..Decimal ',(getitem x (slice 1 None)))) >>> # defmacro - ... # hissp.macros.._macro_.let - ... ( - ... lambda _QzAW22OE5Kz___fn=(lambda x: - ... (lambda * _: _)( - ... 'decimal..Decimal', + ... __import__('builtins').setattr( + ... __import__('builtins').globals().get( + ... ('_macro_')), + ... 'QzDIGITxONE_0QzHASH_', + ... # hissp.macros.._macro_.fun + ... # hissp.macros.._macro_.let + ... ( + ... lambda _QzTXNQFMN3z___lambda=(lambda x: ... (lambda * _: _)( - ... 'quote', - ... getitem( - ... x, - ... slice( - ... (1), - ... None)))) - ... ): - ... (__import__('builtins').setattr( - ... _QzAW22OE5Kz___fn, - ... '__qualname__', - ... ('.').join( - ... ('_macro_', - ... 'QzDIGITxONE_0QzHASH_',))), - ... __import__('builtins').setattr( - ... __import__('operator').getitem( - ... __import__('builtins').globals(), - ... '_macro_'), - ... 'QzDIGITxONE_0QzHASH_', - ... _QzAW22OE5Kz___fn)) [-1] - ... )() + ... 'decimal..Decimal', + ... (lambda * _: _)( + ... 'quote', + ... getitem( + ... x, + ... slice( + ... (1), + ... None)))) + ... ): + ... (__import__('builtins').setattr( + ... _QzTXNQFMN3z___lambda, + ... ('__code__'), + ... _QzTXNQFMN3z___lambda.__code__.replace( + ... co_name='QzDIGITxONE_0QzHASH_')), + ... __import__('builtins').setattr( + ... _QzTXNQFMN3z___lambda, + ... ('__name__'), + ... 'QzDIGITxONE_0QzHASH_'), + ... __import__('builtins').setattr( + ... _QzTXNQFMN3z___lambda, + ... ('__qualname__'), + ... '_macro_.QzDIGITxONE_0QzHASH_'), + ... _QzTXNQFMN3z___lambda) [-1] + ... )()) .. code-block:: REPL @@ -3298,28 +3590,35 @@ so we could include that and the ``itemgetter`` call in the expansion. #> (defmacro S\# e #.. `(op#itemgetter ,(.format "slicer{}" (hissp..demunge e)))) >>> # defmacro - ... # hissp.macros.._macro_.let - ... ( - ... lambda _QzAW22OE5Kz___fn=(lambda e: - ... (lambda * _: _)( - ... 'operator..itemgetter', - ... ('slicer{}').format( - ... __import__('hissp').demunge( - ... e))) - ... ): - ... (__import__('builtins').setattr( - ... _QzAW22OE5Kz___fn, - ... '__qualname__', - ... ('.').join( - ... ('_macro_', - ... 'SQzHASH_',))), - ... __import__('builtins').setattr( - ... __import__('operator').getitem( - ... __import__('builtins').globals(), - ... '_macro_'), - ... 'SQzHASH_', - ... _QzAW22OE5Kz___fn)) [-1] - ... )() + ... __import__('builtins').setattr( + ... __import__('builtins').globals().get( + ... ('_macro_')), + ... 'SQzHASH_', + ... # hissp.macros.._macro_.fun + ... # hissp.macros.._macro_.let + ... ( + ... lambda _QzTXNQFMN3z___lambda=(lambda e: + ... (lambda * _: _)( + ... 'operator..itemgetter', + ... ('slicer{}').format( + ... __import__('hissp').demunge( + ... e))) + ... ): + ... (__import__('builtins').setattr( + ... _QzTXNQFMN3z___lambda, + ... ('__code__'), + ... _QzTXNQFMN3z___lambda.__code__.replace( + ... co_name='SQzHASH_')), + ... __import__('builtins').setattr( + ... _QzTXNQFMN3z___lambda, + ... ('__name__'), + ... 'SQzHASH_'), + ... __import__('builtins').setattr( + ... _QzTXNQFMN3z___lambda, + ... ('__qualname__'), + ... '_macro_.SQzHASH_'), + ... _QzTXNQFMN3z___lambda) [-1] + ... )()) .. code-block:: REPL @@ -3407,30 +3706,37 @@ Putting that all together we get #.. `(op#itemgetter ,(.format "({}[{})" (hissp..readerless `slicer) #.. (hissp..demunge e)))) >>> # defmacro - ... # hissp.macros.._macro_.let - ... ( - ... lambda _QzAW22OE5Kz___fn=(lambda e: - ... (lambda * _: _)( - ... 'operator..itemgetter', - ... ('({}[{})').format( - ... __import__('hissp').readerless( - ... '__main__..slicer'), - ... __import__('hissp').demunge( - ... e))) - ... ): - ... (__import__('builtins').setattr( - ... _QzAW22OE5Kz___fn, - ... '__qualname__', - ... ('.').join( - ... ('_macro_', - ... 'QzLSQB_QzHASH_',))), - ... __import__('builtins').setattr( - ... __import__('operator').getitem( - ... __import__('builtins').globals(), - ... '_macro_'), - ... 'QzLSQB_QzHASH_', - ... _QzAW22OE5Kz___fn)) [-1] - ... )() + ... __import__('builtins').setattr( + ... __import__('builtins').globals().get( + ... ('_macro_')), + ... 'QzLSQB_QzHASH_', + ... # hissp.macros.._macro_.fun + ... # hissp.macros.._macro_.let + ... ( + ... lambda _QzTXNQFMN3z___lambda=(lambda e: + ... (lambda * _: _)( + ... 'operator..itemgetter', + ... ('({}[{})').format( + ... __import__('hissp').readerless( + ... '__main__..slicer'), + ... __import__('hissp').demunge( + ... e))) + ... ): + ... (__import__('builtins').setattr( + ... _QzTXNQFMN3z___lambda, + ... ('__code__'), + ... _QzTXNQFMN3z___lambda.__code__.replace( + ... co_name='QzLSQB_QzHASH_')), + ... __import__('builtins').setattr( + ... _QzTXNQFMN3z___lambda, + ... ('__name__'), + ... 'QzLSQB_QzHASH_'), + ... __import__('builtins').setattr( + ... _QzTXNQFMN3z___lambda, + ... ('__qualname__'), + ... '_macro_.QzLSQB_QzHASH_'), + ... _QzTXNQFMN3z___lambda) [-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 @@ -3585,30 +3891,37 @@ Our previous macro was almost there. #> (defmacro \[\# e #.. `(lambda ,'a ,(.format "({}[{})" 'a (hissp..demunge e)))) >>> # defmacro - ... # hissp.macros.._macro_.let - ... ( - ... lambda _QzAW22OE5Kz___fn=(lambda e: - ... (lambda * _: _)( - ... 'lambda', - ... 'a', - ... ('({}[{})').format( + ... __import__('builtins').setattr( + ... __import__('builtins').globals().get( + ... ('_macro_')), + ... 'QzLSQB_QzHASH_', + ... # hissp.macros.._macro_.fun + ... # hissp.macros.._macro_.let + ... ( + ... lambda _QzTXNQFMN3z___lambda=(lambda e: + ... (lambda * _: _)( + ... 'lambda', ... 'a', - ... __import__('hissp').demunge( - ... e))) - ... ): - ... (__import__('builtins').setattr( - ... _QzAW22OE5Kz___fn, - ... '__qualname__', - ... ('.').join( - ... ('_macro_', - ... 'QzLSQB_QzHASH_',))), - ... __import__('builtins').setattr( - ... __import__('operator').getitem( - ... __import__('builtins').globals(), - ... '_macro_'), - ... 'QzLSQB_QzHASH_', - ... _QzAW22OE5Kz___fn)) [-1] - ... )() + ... ('({}[{})').format( + ... 'a', + ... __import__('hissp').demunge( + ... e))) + ... ): + ... (__import__('builtins').setattr( + ... _QzTXNQFMN3z___lambda, + ... ('__code__'), + ... _QzTXNQFMN3z___lambda.__code__.replace( + ... co_name='QzLSQB_QzHASH_')), + ... __import__('builtins').setattr( + ... _QzTXNQFMN3z___lambda, + ... ('__name__'), + ... 'QzLSQB_QzHASH_'), + ... __import__('builtins').setattr( + ... _QzTXNQFMN3z___lambda, + ... ('__qualname__'), + ... '_macro_.QzLSQB_QzHASH_'), + ... _QzTXNQFMN3z___lambda) [-1] + ... )()) It works. @@ -3680,32 +3993,40 @@ we should suppress the qualification with a gensym instead of a symbol interpola #> (defmacro \[\# e #.. `(lambda ($#G) ,(.format "({}[{})" '$#G (hissp..demunge e)))) + FULL COMPILATION: >>> # defmacro - ... # hissp.macros.._macro_.let - ... ( - ... lambda _QzAW22OE5Kz___fn=(lambda e: - ... (lambda * _: _)( - ... 'lambda', + ... __import__('builtins').setattr( + ... __import__('builtins').globals().get( + ... ('_macro_')), + ... 'QzLSQB_QzHASH_', + ... # hissp.macros.._macro_.fun + ... # hissp.macros.._macro_.let + ... ( + ... lambda _QzTXNQFMN3z___lambda=(lambda e: ... (lambda * _: _)( - ... '_QzAVTK4YRWz___G'), - ... ('({}[{})').format( - ... '_QzAVTK4YRWz___G', - ... __import__('hissp').demunge( - ... e))) - ... ): - ... (__import__('builtins').setattr( - ... _QzAW22OE5Kz___fn, - ... '__qualname__', - ... ('.').join( - ... ('_macro_', - ... 'QzLSQB_QzHASH_',))), - ... __import__('builtins').setattr( - ... __import__('operator').getitem( - ... __import__('builtins').globals(), - ... '_macro_'), - ... 'QzLSQB_QzHASH_', - ... _QzAW22OE5Kz___fn)) [-1] - ... )() + ... 'lambda', + ... (lambda * _: _)( + ... '_QzEC6PADPWz___G'), + ... ('({}[{})').format( + ... '_QzEC6PADPWz___G', + ... __import__('hissp').demunge( + ... e))) + ... ): + ... (__import__('builtins').setattr( + ... _QzTXNQFMN3z___lambda, + ... ('__code__'), + ... _QzTXNQFMN3z___lambda.__code__.replace( + ... co_name='QzLSQB_QzHASH_')), + ... __import__('builtins').setattr( + ... _QzTXNQFMN3z___lambda, + ... ('__name__'), + ... 'QzLSQB_QzHASH_'), + ... __import__('builtins').setattr( + ... _QzTXNQFMN3z___lambda, + ... ('__qualname__'), + ... '_macro_.QzLSQB_QzHASH_'), + ... _QzTXNQFMN3z___lambda) [-1] + ... )()) Read this carefully. ``$#`` only works inside of templates, diff --git a/docs/style_guide.rst b/docs/style_guide.rst index 0f39ddd88..3df48deb1 100644 --- a/docs/style_guide.rst +++ b/docs/style_guide.rst @@ -1202,7 +1202,7 @@ The ``lambda`` special form does not create docstrings. However, you can attach a ``.__doc__`` attribute to the lambda object after creating it, e.g., using the `attach` macro. -The bundled `once-deftype` macro does not have any special case for docstrings. +The bundled `deftypeonce` macro does not have any special case for docstrings. Instead add a ``__doc__`` attribute. Indent docstrings to the same column as their opening ``"`` diff --git a/src/hissp/macros.lissp b/src/hissp/macros.lissp index 4ac782a10..374c4c548 100644 --- a/src/hissp/macros.lissp +++ b/src/hissp/macros.lissp @@ -76,21 +76,29 @@ Hidden doctest adds bundled macros for REPL-consistent behavior. ;;; --- ;; Bootstrap macro namespace using builtins. -(.update (globals) : _macro_ (types..ModuleType (.format "{}._macro_" __name__))) -(operator..setitem sys..modules _macro_.__name__ _macro_) +(.update (globals) : _macro_ (types..SimpleNamespace)) +(setattr _macro_ '__doc__ "Hissp's bundled macro namespace.") ;;; YO DAWG, I HERD YOU LIKE MACROS ;;; SO I PUT A BOOTSTRAP defmacro IN YOUR _macro_ SO YOU CAN defmacro A ;;; REAL defmacro WHILE YOU DEFINE ALL YOUR MACROS! -;; Simplified bootstrap version assumes ideal conditions to avoid branching. +;; Simplified bootstrap version. +;; Yes, Python really sets the name in three different places! (setattr _macro_ 'defmacro (lambda (name parameters docstring : :* body) `((lambda (: $#G (lambda ,parameters ,@body)) - (setattr $#G ','__doc__ ,docstring) - (setattr $#G ','__qualname__ (.join "." '(,'_macro_ ,name))) - (setattr _macro_ ',name $#G))))) + ;; Assume the presence of a docstring-- + (setattr $#G ','__doc__ ,docstring) ; Needed for help(). + ;; --and of the _macro_ namespace to avoid branching. + (setattr _macro_ ',name $#G) + ;; Needed for tracebacks. + (setattr $#G ','__code__ (.replace $#G.__code__ : co_name ',name)) + ;; Also needed for help(). + (setattr $#G ','__name__ ',name) + ;; Needed for repr(). + (setattr $#G ','__qualname__ (.join "." '(,'_macro_ ,name))))))) (defmacro if-else (test consequent alternate) "``if-else`` Basic ternary branching construct. @@ -158,85 +166,7 @@ Hidden doctest adds bundled macros for REPL-consistent behavior. See also: `prog1`, `Expression statements `. " ;; TODO: consider flattening nested progns - `((lambda : - ,@body))) - -(defmacro when (condition : :* body) - "When the condition is true, - evaluates each expression in sequence for side effects, - resulting in the value of the last. - Otherwise, skips them and returns ``()``. - - .. code-block:: REPL - - #> (any-map c 'abcd - #.. (print c) - #.. (when (op#eq c 'b) - #.. (print 'found) - #.. :break)) - >>> # anyQz_map - ... __import__('builtins').any( - ... __import__('builtins').map( - ... (lambda c: - ... (print( - ... c), - ... # when - ... (lambda b, c: c()if b else())( - ... __import__('operator').eq( - ... c, - ... 'b'), - ... (lambda : - ... (print( - ... 'found'), - ... ':break') [-1] - ... ))) [-1] - ... ), - ... 'abcd')) - a - b - found - True - - See also: `if-else`, `unless`, `if`. - " - `((lambda ,'bc |c()if b else()|) ; boolean, consequent - ,condition (lambda : ,@body))) - -(defmacro unless (condition : :* body) - "Unless the condition is true, - evaluates each expression in sequence for side effects, - resulting in the value of the last. - Otherwise, skips them and returns ``()``. - - .. code-block:: REPL - - #> (any-map c 'abcd - #.. (unless (op#eq c 'b) - #.. (print c))) - >>> # anyQz_map - ... __import__('builtins').any( - ... __import__('builtins').map( - ... (lambda c: - ... # unless - ... (lambda b, a: ()if b else a())( - ... __import__('operator').eq( - ... c, - ... 'b'), - ... (lambda : - ... print( - ... c) - ... )) - ... ), - ... 'abcd')) - a - c - d - False - - See also: `when`. - " - `((lambda ,'ba |()if b else a()|) ; boolean, alternate - ,condition (lambda : ,@body))) + `((lambda : ,@body))) (defmacro let (pairs : :* body) "Creates local variables. Pairs are implied by position. @@ -282,89 +212,6 @@ Hidden doctest adds bundled macros for REPL-consistent behavior. `((lambda (: ,@pairs) ,@body))) -;;;; - Post-Bootstrap - -;;; --- - -;;;; Defining Variables - -;;; see also from Bootstrap: let - -;; Define the real defmacro using the bootstrap macros. -(defmacro defmacro (name parameters : docstring () :* body) - "Creates a new macro for the current module. - - If there's no local ``_macro_`` namespace (at compile time), creates - one using `types.ModuleType` (at runtime). If there's a docstring, - stores it as the new lambda's ``__doc__``. Adds the ``_macro_`` prefix - to the lambda's ``__qualname__``. Saves the lambda in ``_macro_`` - using the given attribute name. - - .. 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 _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`, - `lambda `. - " - (let ($fn `$#fn) - (let (fn `(lambda ,parameters ,docstring ,@body) - ns (unless (operator..contains (.get hissp.compiler..NS) '_macro_) - `((.update (globals) : _macro_ (types..ModuleType ','_macro_)))) - dc (when (hissp.reader..is_hissp_string docstring) - `((setattr ,$fn ','__doc__ ,docstring))) - qn `(setattr ,$fn ','__qualname__ (.join "." '(,'_macro_ ,name)))) - `(let (,$fn ,fn) - ,@ns - ,@dc - ,qn - (setattr (operator..getitem (builtins..globals) - ','_macro_) - ',name - ,$fn))))) - (defmacro let-from (syms itr : :* body) "``let-from`` Create listed locals from iterable. @@ -384,8 +231,7 @@ Hidden doctest adds bundled macros for REPL-consistent behavior. See also: `let`, `let*from`, `assignment`. " - `((lambda ,syms - ,@body) + `((lambda ,syms ,@body) : :* ,itr)) (defmacro let*from (pairs : :* body) @@ -483,6 +329,151 @@ Hidden doctest adds bundled macros for REPL-consistent behavior. ,@body)) `(progn ,@body))) +(defmacro fun (qualname params : maybe-docstring () :* body) + "A lambda enhanced with a qualname and optionally a docstring. + + Hissp's (and Python's) lambda syntax do not have docstrings. Named + lambdas improve REPL transparency and error messages, at the cost of + some configuration overhead to set the name in the three places Python + requires. + + Used by `defun`. Not recommended for otherwise anonymous functions due + to the additional overhead. + " + (let*from ((name : :* _xs) (reversed (.split qualname '. 1)) + (doc top) (if-else (hissp.reader..is_hissp_string maybe-docstring) + `(,(lambda x `((setattr ,x "__doc__" ,maybe-docstring))) + ()) + `(,(lambda x) + (,maybe-docstring)))) + `(let ($#lambda (lambda ,params ,@top ,@body)) + ,@(doc '$#lambda) ; Used by help(). + ;; Used by tracebacks. + (setattr $#lambda "__code__" (.replace $#lambda.__code__ : co_name ',name)) + ;; Used by help(). + (setattr $#lambda "__name__" ',name) + ;; Used by repr(). + (setattr $#lambda "__qualname__" ',qualname) + $#lambda))) + +(defmacro unless (condition : :* body) + "Unless the condition is true, + evaluates each expression in sequence for side effects, + resulting in the value of the last. + Otherwise, skips them and returns ``()``. + + .. code-block:: REPL + + #> (any-map c 'abcd + #.. (unless (op#eq c 'b) + #.. (print c))) + >>> # anyQz_map + ... __import__('builtins').any( + ... __import__('builtins').map( + ... (lambda c: + ... # unless + ... (lambda b, a: ()if b else a())( + ... __import__('operator').eq( + ... c, + ... 'b'), + ... (lambda : + ... print( + ... c) + ... )) + ... ), + ... 'abcd')) + a + c + d + False + + See also: `when`. + " + `((lambda ,'ba |()if b else a()|) ; boolean, alternate + ,condition (lambda : ,@body))) + +;;;; - Post-Bootstrap - +;;; --- + +;;;; Binding Variables + +;;; See also: let, let-from, and let*from in Bootstrap. + +;; Define the real defmacro using the bootstrap macros. +(defmacro defmacro (name parameters : :* body) + "Creates a new macro for the current module. + + If there's no local ``_macro_`` namespace (at compile time), adds code + to create one using `types.SimpleNamespace` (at runtime), if it's + still not there. If there's a docstring, stores it as the new lambda's + ``__doc__``. Adds the ``_macro_`` prefix to the lambda's + ``__qualname__``. Saves the lambda in ``_macro_`` using the given + attribute name. + + .. code-block:: REPL + + #> (defmacro p123 (sep) + #.. <<#;Prints 1 2 3 with the given separator + #.. `(print 1 2 3 : sep ,sep)) + >>> # defmacro + ... __import__('builtins').setattr( + ... __import__('builtins').globals().get( + ... ('_macro_')), + ... 'p123', + ... # hissp.macros.._macro_.fun + ... # hissp.macros.._macro_.let + ... ( + ... lambda _QzTXNQFMN3z___lambda=(lambda sep: + ... (lambda * _: _)( + ... 'builtins..print', + ... (1), + ... (2), + ... (3), + ... ':', + ... '__main__..sep', + ... sep) + ... ): + ... (__import__('builtins').setattr( + ... _QzTXNQFMN3z___lambda, + ... ('__doc__'), + ... 'Prints 1 2 3 with the given separator'), + ... __import__('builtins').setattr( + ... _QzTXNQFMN3z___lambda, + ... ('__code__'), + ... _QzTXNQFMN3z___lambda.__code__.replace( + ... co_name='p123')), + ... __import__('builtins').setattr( + ... _QzTXNQFMN3z___lambda, + ... ('__name__'), + ... 'p123'), + ... __import__('builtins').setattr( + ... _QzTXNQFMN3z___lambda, + ... ('__qualname__'), + ... '_macro_.p123'), + ... _QzTXNQFMN3z___lambda) [-1] + ... )()) + + #> (p123 ::) + >>> # p123 + ... __import__('builtins').print( + ... (1), + ... (2), + ... (3), + ... sep='::') + 1::2::3 + + See also: + `<\\<# `, `attach`, + `lambda `. + " + (let (form `(setattr (.get (globals) "_macro_") + ',name + (fun ,(.format "_macro_.{}" name) ,parameters ,@body))) + (if-else (operator..contains (.get hissp.compiler..NS) '_macro_) + form + `(progn (.setdefault (globals) "_macro_" (types..SimpleNamespace)) + ,form)))) + (defmacro define (qualname value) "Assigns an attribute the value. @@ -501,15 +492,19 @@ Hidden doctest adds bundled macros for REPL-consistent behavior. >>> SPAM 'tomato' - See also: `globals`, `dict.update`, `once-define`, `def`, - `assignment`, `global`. + See also: `globals`, `dict.update`, `defonce`, + `def`, `assignment`, `global`. " (let-from (ns _dot attr) (.rpartition qualname ".") (if-else ns `(setattr ,ns ',attr ,value) `(.update (globals) : ,qualname ,value)))) -(defmacro once-define (qualname value) +(defmacro defun (qualname params : :* body) + "Define a named function with optional docstring." + `(define ,qualname (fun ,qualname ,params ,@body))) + +(defmacro defonce (qualname value) "Defines an attribute, unless it exists. Like `define`, but won't overwrite an existing attribute. @@ -519,8 +514,8 @@ Hidden doctest adds bundled macros for REPL-consistent behavior. .. code-block:: REPL - #> (once-define CACHE (types..SimpleNamespace : x 1)) - >>> # onceQz_define + #> (defonce CACHE (types..SimpleNamespace : x 1)) + >>> # defonce ... # hissp.macros.._macro_.unless ... (lambda b, a: ()if b else a())( ... __import__('operator').contains( @@ -539,9 +534,9 @@ Hidden doctest adds bundled macros for REPL-consistent behavior. ... 'x', ... (42)) - #> (once-define CACHE (progn (print 'not 'evaluated) - #.. (types..SimpleNamespace : x 1))) - >>> # onceQz_define + #> (defonce CACHE (progn (print 'not 'evaluated) + #.. (types..SimpleNamespace : x 1))) + >>> # defonce ... # hissp.macros.._macro_.unless ... (lambda b, a: ()if b else a())( ... __import__('operator').contains( @@ -561,7 +556,7 @@ Hidden doctest adds bundled macros for REPL-consistent behavior. ... )) () - #> CACHE ; The second once-define had no effect. + #> CACHE ; The second defonce had no effect. >>> CACHE namespace(x=42) @@ -572,32 +567,33 @@ Hidden doctest adds bundled macros for REPL-consistent behavior. `(operator..contains (globals) ',attr))) (define ,qualname ,value))) -(defmacro once-deftype (qualname bases : :* decorators) +(defmacro deftypeonce (qualname bases : :* once-decorators) 'hissp.reader..Comment.contents# ;; Defines a type (class), unless it exists. ;; - ;; Add class attributes afterwards using `define` or `defun`, and - ;; class decorators afterwards using `zap@`. These run again on module - ;; reload and patch in existing instances. - ;; - ;; ``decorators`` apply in the order written (first applies first), - ;; unless the type exists (not reapplied on reloads). Beware that type - ;; attributes defined afterwards will not be available for the - ;; ``decorators`` to operate upon. A decorator can add attributes for - ;; subsequent decorators to operate upon, however, and a decorator may - ;; be a lambda defined in line. It is possible to add arbitrary - ;; attributes at definition time this way, but remember that - ;; ``decorators`` don't run again on reloads, so changes here cannot - ;; simply be reloaded with the module the way attributes defined - ;; afterwards can. + ;; Add class attributes afterward using `define` or `defun`, and class + ;; decorators above with `@##` or afterward using + ;; `zap@`. These run again on module reload and patch in + ;; existing instances. + ;; + ;; The ``once-decorators`` apply before any external ones, in the + ;; order written (first applies first), unless the type exists (not + ;; reapplied on reloads). Beware that type attributes defined + ;; afterward will not be available for the ``once-decorators`` to + ;; operate upon. A decorator can add attributes for subsequent + ;; decorators to operate upon, however, and a decorator may be a + ;; lambda defined in line. It is possible to add arbitrary attributes + ;; this way, but remember that ``once-decorators`` don't run again on + ;; reloads, so changes here cannot simply be reloaded with the module + ;; the way attributes defined afterward can. ;; ;; .. code-block:: REPL ;; - ;; #> (once-deftype Point2D (tuple) + ;; #> (deftypeonce Point2D (tuple) ;; #.. ;; Example of setting an attr with an internal decorator. ;; #.. X#(attach X : __doc__ "Simple ordered pair.")) - ;; >>> # onceQz_deftype - ;; ... # hissp.macros.._macro_.onceQz_define + ;; >>> # deftypeonce + ;; ... # hissp.macros.._macro_.defonce ;; ... # hissp.macros.._macro_.unless ;; ... (lambda b, a: ()if b else a())( ;; ... __import__('operator').contains( @@ -647,7 +643,7 @@ Hidden doctest adds bundled macros for REPL-consistent behavior. ;; ... __import__('builtins').setattr( ;; ... Point2D, ;; ... '__new__', - ;; ... # hissp.macros..QzMaybe_.fun + ;; ... # hissp.macros.._macro_.fun ;; ... # hissp.macros.._macro_.let ;; ... ( ;; ... lambda _QzEC6PADPWz___lambda=(lambda cls, x, y: @@ -680,7 +676,7 @@ Hidden doctest adds bundled macros for REPL-consistent behavior. ;; ... __import__('builtins').setattr( ;; ... Point2D, ;; ... '__repr__', - ;; ... # hissp.macros..QzMaybe_.fun + ;; ... # hissp.macros.._macro_.fun ;; ... # hissp.macros.._macro_.let ;; ... ( ;; ... lambda _QzEC6PADPWz___lambda=(lambda self: @@ -729,7 +725,7 @@ Hidden doctest adds bundled macros for REPL-consistent behavior. ;; ... __import__('builtins').setattr( ;; ... Point2D, ;; ... '__init_subclass__', - ;; ... # hissp.macros..QzMaybe_.fun + ;; ... # hissp.macros.._macro_.fun ;; ... # hissp.macros.._macro_.let ;; ... ( ;; ... lambda _QzEC6PADPWz___lambda=(lambda cls, /, **kwargs: @@ -759,9 +755,9 @@ Hidden doctest adds bundled macros for REPL-consistent behavior. ;; ... Point2D.__init_subclass__)) [-1] ;; ... )()) ;; - ;; #> (once-deftype ASubclass (Point2D : a 1 b 2)) - ;; >>> # onceQz_deftype - ;; ... # hissp.macros.._macro_.onceQz_define + ;; #> (deftypeonce ASubclass (Point2D : a 1 b 2)) + ;; >>> # deftypeonce + ;; ... # hissp.macros.._macro_.defonce ;; ... # hissp.macros.._macro_.unless ;; ... (lambda b, a: ()if b else a())( ;; ... __import__('operator').contains( @@ -780,25 +776,20 @@ Hidden doctest adds bundled macros for REPL-consistent behavior. ;; ... )) ;; {'a': 1, 'b': 2} ;; - ;; See also: `attach`, `type`, `@#`, :keyword:`class`, - ;; `types.new_class`. + ;; See also: `attach`, `type`, :keyword:`class`, `types.new_class`. ;; (let (ibases (iter bases) name |qualname.rpartition('.')[-1]|) - `(once-define ,qualname + `(defonce ,qualname ,(functools..reduce (lambda (cls f) `(,f ,cls)) - decorators + once-decorators `(type ',name (,hissp.reader..ENTUPLE ,@(itertools..takewhile (lambda x (operator..ne x ':)) ibases)) ,(dict) : ,@ibases))))) -(defmacro defun (qualname params : :* body) - "Define a named function with optional docstring." - `(define ,qualname (fun ,qualname ,params ,@body))) - (defmacro my\# e "``my#`` Anaphoric. `let` ``my`` be a fresh `types.SimpleNamespace` in a lexical scope surrounding e. @@ -1007,47 +998,53 @@ Hidden doctest adds bundled macros for REPL-consistent behavior. ;; .. code-block:: REPL ;; ;; #> (hissp.._macro_.alias H: hissp.._macro_) - ;; >>> # hissp.._macro_.alias - ;; ... # hissp.macros.._macro_.defmacro - ;; ... # hissp.macros.._macro_.let - ;; ... ( - ;; ... lambda _Qz2D5FNHXZz___fn=(lambda _QzE4JATHEUz___attr, *_QzE4JATHEUz___args, **_QzE4JATHEUz___kwargs: - ;; ... ('Aliases ``hissp.._macro_`` as ``HQzCOLON_#``.', - ;; ... # hissp.macros.._macro_.ifQz_else - ;; ... (lambda b, c, a: c()if b else a())( - ;; ... _QzE4JATHEUz___args, - ;; ... (lambda : - ;; ... __import__('builtins').getattr( - ;; ... __import__('hissp')._macro_, - ;; ... ('{}{}').format( - ;; ... _QzE4JATHEUz___attr, - ;; ... 'QzHASH_'))( - ;; ... *_QzE4JATHEUz___args, - ;; ... **_QzE4JATHEUz___kwargs) - ;; ... ), - ;; ... (lambda : - ;; ... ('{}.{}').format( - ;; ... 'hissp.._macro_', - ;; ... _QzE4JATHEUz___attr) - ;; ... ))) [-1] - ;; ... ): - ;; ... (__import__('builtins').setattr( - ;; ... _Qz2D5FNHXZz___fn, - ;; ... '__doc__', - ;; ... 'Aliases ``hissp.._macro_`` as ``HQzCOLON_#``.'), - ;; ... __import__('builtins').setattr( - ;; ... _Qz2D5FNHXZz___fn, - ;; ... '__qualname__', - ;; ... ('.').join( - ;; ... ('_macro_', - ;; ... 'HQzCOLON_QzHASH_',))), - ;; ... __import__('builtins').setattr( - ;; ... __import__('operator').getitem( - ;; ... __import__('builtins').globals(), - ;; ... '_macro_'), - ;; ... 'HQzCOLON_QzHASH_', - ;; ... _Qz2D5FNHXZz___fn)) [-1] - ;; ... )() + ;; >>> # hissp.._macro_.alias + ;; ... # hissp.macros.._macro_.defmacro + ;; ... __import__('builtins').setattr( + ;; ... __import__('builtins').globals().get( + ;; ... ('_macro_')), + ;; ... 'HQzCOLON_QzHASH_', + ;; ... # hissp.macros.._macro_.fun + ;; ... # hissp.macros.._macro_.let + ;; ... ( + ;; ... lambda _QzTXNQFMN3z___lambda=(lambda _QzCHXBMU2Dz___attr, *_QzCHXBMU2Dz___args, **_QzCHXBMU2Dz___kwargs: + ;; ... # hissp.macros.._macro_.ifQz_else + ;; ... (lambda b, c, a: c()if b else a())( + ;; ... _QzCHXBMU2Dz___args, + ;; ... (lambda : + ;; ... __import__('builtins').getattr( + ;; ... __import__('hissp')._macro_, + ;; ... ('{}{}').format( + ;; ... _QzCHXBMU2Dz___attr, + ;; ... 'QzHASH_'))( + ;; ... *_QzCHXBMU2Dz___args, + ;; ... **_QzCHXBMU2Dz___kwargs) + ;; ... ), + ;; ... (lambda : + ;; ... ('{}.{}').format( + ;; ... 'hissp.._macro_', + ;; ... _QzCHXBMU2Dz___attr) + ;; ... )) + ;; ... ): + ;; ... (__import__('builtins').setattr( + ;; ... _QzTXNQFMN3z___lambda, + ;; ... ('__doc__'), + ;; ... 'Aliases ``hissp.._macro_`` as ``HQzCOLON_#``.'), + ;; ... __import__('builtins').setattr( + ;; ... _QzTXNQFMN3z___lambda, + ;; ... ('__code__'), + ;; ... _QzTXNQFMN3z___lambda.__code__.replace( + ;; ... co_name='HQzCOLON_QzHASH_')), + ;; ... __import__('builtins').setattr( + ;; ... _QzTXNQFMN3z___lambda, + ;; ... ('__name__'), + ;; ... 'HQzCOLON_QzHASH_'), + ;; ... __import__('builtins').setattr( + ;; ... _QzTXNQFMN3z___lambda, + ;; ... ('__qualname__'), + ;; ... '_macro_.HQzCOLON_QzHASH_'), + ;; ... _QzTXNQFMN3z___lambda) [-1] + ;; ... )()) ;; ;; #> 'H:#alias ;; >>> 'hissp.._macro_.alias' @@ -1137,16 +1134,17 @@ Hidden doctest adds bundled macros for REPL-consistent behavior. ``definition`` form must assign an attribute identified by its first arg. Expands to a `define`, meaning decorators can stack. - Decorator syntax is for definitions, like `define` and - `defun`, and would work on any definition macro that has - the definition name as its first argument. + Decorator syntax is for definitions, like `define` and `defun`, and + would work on any definition macro that has the definition qualname as + its first argument (not `defmacro`, but `defun` can target the + ``_macro_`` namespace if it exists). - Use `zap@` to decorate an attribute after its definition. + Use `zap@` to decorate an attribute after its definition. .. code-block:: REPL - #> @##str.swapcase - #..@##str.title + #> @##.swapcase + #..@##.title #..(define spam 'spam) ; Unlike Python def, not always a function. >>> # hissp.macros.._macro_.define ... __import__('builtins').globals().update( @@ -1159,11 +1157,9 @@ Hidden doctest adds bundled macros for REPL-consistent behavior. ... (# define ... __import__('builtins').globals().update( ... spam='spam'), - ... str.title( - ... spam)) [-1] + ... spam.title()) [-1] ... )()), - ... str.swapcase( - ... spam)) [-1] + ... spam.swapcase()) [-1] ... )()) #> spam @@ -1331,11 +1327,11 @@ Hidden doctest adds bundled macros for REPL-consistent behavior. See also: `attach`, `delattr`, `zap@`, `setattr`. " (let-from (ns _dot attr) (.rpartition qualname ".") - `(let ($#val ,val) - ,(if-else ns - `(setattr ,ns ',attr ,'$#val) - `(define ,attr ,'$#val)) - $#val))) + `(let ($#val ,val) + ,(if-else ns + `(setattr ,ns ',attr ,'$#val) + `(define ,attr ,'$#val)) + $#val))) (defmacro zap@ (op qualname : :* args) "``zap@`` 'zapat' Augmented attribute assignment operator. @@ -1418,29 +1414,6 @@ Hidden doctest adds bundled macros for REPL-consistent behavior. iargs) ,$target)))) -(defmacro fun (qualname params : maybe-docstring () :* body) - "A lambda enhanced with a qualname and optionally a docstring. - - Hissp's (and Python's) lambda syntax do not have docstrings. Named - lambdas improve REPL transparency and error messages, at the cost of - some configuration overhead to set the name in the three places Python - requires. - - Used by `defun`. Not recommended for otherwise anonymous functions due - to the additional overhead. - " - (let*from ((name : :* _xs) (reversed (.split qualname '. 1)) - (doc top) (if-else (hissp.reader..is_hissp_string maybe-docstring) - `(,X#`((setattr ,X "__doc__" ,maybe-docstring)) - ()) - `(,X#() (,maybe-docstring)))) - `(let ($#lambda (lambda ,params ,@top ,@body)) - ,@(doc '$#lambda) - (setattr $#lambda "__code__" (.replace $#lambda.__code__ : co_name ',name)) - (setattr $#lambda "__name__" ',name) - (setattr $#lambda "__qualname__" ',qualname) - $#lambda))) - (defmacro doto (self : :* invocations) "Configure an object. @@ -1577,9 +1550,50 @@ Hidden doctest adds bundled macros for REPL-consistent behavior. ;;;; Control Flow -;;; see also from Bootstrap: if-else, when, unless +;;; see also from Bootstrap: if-else, unless ;;; see also from Advanced: case +(defmacro when (condition : :* body) + "When the condition is true, + evaluates each expression in sequence for side effects, + resulting in the value of the last. + Otherwise, skips them and returns ``()``. + + .. code-block:: REPL + + #> (any-map c 'abcd + #.. (print c) + #.. (when (op#eq c 'b) + #.. (print 'found) + #.. :break)) + >>> # anyQz_map + ... __import__('builtins').any( + ... __import__('builtins').map( + ... (lambda c: + ... (print( + ... c), + ... # when + ... (lambda b, c: c()if b else())( + ... __import__('operator').eq( + ... c, + ... 'b'), + ... (lambda : + ... (print( + ... 'found'), + ... ':break') [-1] + ... ))) [-1] + ... ), + ... 'abcd')) + a + b + found + True + + See also: `if-else`, `unless`, `if`. + " + `((lambda ,'bc |c()if b else()|) ; boolean, consequent + ,condition (lambda : ,@body))) + (defmacro cond (: :* pairs) "Multiple condition branching. @@ -1850,6 +1864,7 @@ Hidden doctest adds bundled macros for REPL-consistent behavior. ,([#0] exprs) ,@(map X#`O#,X ([#1:] exprs))))) +;; 'or is also a reserved word. (defmacro ors (: :* exprs) "Variadic shortcutting logical OR. @@ -2208,8 +2223,8 @@ Hidden doctest adds bundled macros for REPL-consistent behavior. (let (ixs (iter xs)) `((lambda (: :* ,'xs) |{*xs}|) : ,@chain#(map X#(if-else (op#eq X ":*") - `(,X ,(next ixs)) - `(:? ,X)) + `(,X ,(next ixs)) + `(:? ,X)) ixs)))) (defmacro % (: :* kvs) @@ -2364,8 +2379,7 @@ Hidden doctest adds bundled macros for REPL-consistent behavior. ;; ... ' except s.X as e:v=e\n' ;; ... ' return k\n' ;; ... "_macro_=__import__('types').SimpleNamespace()\n" - ;; ... "try:exec('from hissp.macros._macro_ import *',vars(_macro_))\n" - ;; ... 'except ModuleNotFoundError:pass'), + ;; ... "vars(_macro_).update(vars(__import__('hissp')._macro_))"), ;; ... __import__('builtins').globals()) ;; ;; See also, `alias`. @@ -2816,7 +2830,7 @@ Hidden doctest adds bundled macros for REPL-consistent behavior. ;; ... ;; Exception ;; - `(exec ',(.format "\ + `(exec ',"\ from functools import partial,reduce from itertools import *;from operator import * def engarde(xs,h,f,/,*a,**kw): @@ -2833,9 +2847,7 @@ class Ensue(__import__('collections.abc').abc.Generator): except s.X as e:v=e return k _macro_=__import__('types').SimpleNamespace() -try:exec('from {}._macro_ import *',vars(_macro_)) -except ModuleNotFoundError:pass" - __name__) +vars(_macro_).update(vars(__import__('hissp')._macro_))" ,ns))(.#"\144efma\143ro" import(: :* args) `(.#"p\162int"(.#"\143ode\143s..en\143ode" (_TAO .#"in\163pe\143\164..ge\164\163our\143e")','.#"ro\16413"))) diff --git a/tests/test_macros.lissp b/tests/test_macros.lissp index 64d056e74..25d97ea7e 100644 --- a/tests/test_macros.lissp +++ b/tests/test_macros.lissp @@ -16,7 +16,7 @@ hissp..alias#H (H#defmacro nil () None) -(H#once-deftype TestMacros (unittest..TestCase)) +(H#deftypeonce TestMacros (unittest..TestCase)) (H#defun TestMacros.test_same_gensym (self) (self.assertEqual : :* `($#test $#test))) From 3513522b34c9fa1896ba61c118731b6252dca7d0 Mon Sep 17 00:00:00 2001 From: gilch Date: Tue, 20 Aug 2024 22:10:28 -0600 Subject: [PATCH 17/17] Rename <<# to <# Enables a more compact style that's still aligned. Use "tag" in place of "reader macro" in definitions --- docs/style_guide.rst | 41 +++++++++----------------------- src/hissp/macros.lissp | 54 ++++++++++++++++-------------------------- tests/test_cmd.py | 2 +- 3 files changed, 32 insertions(+), 65 deletions(-) diff --git a/docs/style_guide.rst b/docs/style_guide.rst index 3df48deb1..0840f76e0 100644 --- a/docs/style_guide.rst +++ b/docs/style_guide.rst @@ -412,7 +412,7 @@ should be segmented by `let` indentation or similar implied progn forms without resorting to blank lines. Blank lines are OK in docstrings, -but comment strings (`<\<#`) instead of ``""`` +but comment strings (`<# `) instead of ``""`` tokens are preferred for docstrings when they have more than a single paragraph. Keep the elements in a tuple aligned to start on the same column. @@ -749,12 +749,11 @@ Because the string was injected (``.#``), don't forget to quote it (``'``), or the compiler will assume the string contents are Python code to be inlined. -Remember that `<\<#` can also make multiline strings. +Remember that `<# ` can also make multiline strings. .. code-block:: REPL - #> (print (.upper <<# - #.. ;; These lines + #> (print (.upper <#;These lines #.. ;; don't interrupt #.. ;; the flow. #.. _#/)) @@ -769,25 +768,7 @@ You can avoid the doorstop by using the `->` macro. .. code-block:: REPL - #> (print (-> <<# - #.. ;; These lines - #.. ;; don't interrupt - #.. ;; the flow. - #.. .upper)) - >>> print( - ... # Qz_QzGT_ - ... "These lines\ndon't interrupt\nthe flow.".upper()) - THESE LINES - DON'T INTERRUPT - THE FLOW. - -The following more compact style is acceptable. -It's similar to not escaping the initial newline in a ``""`` string, -so the first line isn't aligned. The comment block still parses properly. - -.. code-block:: REPL - - #> (print (-> <<# ; These lines + #> (print (-> <#;These lines #.. ;; don't interrupt #.. ;; the flow. #.. .upper)) @@ -799,7 +780,7 @@ so the first line isn't aligned. The comment block still parses properly. THE FLOW. With the principal exception of docstrings, -long multiline strings should be declared at the `top level`_ and referenced by name. +long multiline ``""`` strings should be declared at the `top level`_ and referenced by name. .. code-block:: Lissp @@ -988,7 +969,7 @@ but a traditional Lisp editor like Emacs ``lisp-mode`` would not. In rare cases, a margin comment may occupy the same line as some other comment form. This is usually acceptable style, but a ``;`` following a ``;;`` is still tokenized as part of the ``;;`` block, -which can matter for reader macros like `<\<#`. +which can matter for reader macros like `<# `. **Never** put a single-semicolon comment on its own line unless it's a continuation aligned to the margin! @@ -1051,7 +1032,7 @@ To avoid confusion, do not use triple-semicolon comments as headings at all. Prefer a module docstring over top-level comments where applicable. -Remember that a `<\<#` +Remember that a `<# ` applied to a comment block compiles to a string literal, which can be a docstring. @@ -1214,8 +1195,8 @@ and can strip it out when rendering help. If the docstring contains any newlines, the closing ``"`` gets its own line. -It is acceptable to use reader macros that resolve to a string literal like `<\<# ` -(which is useful for doctests), +It is acceptable to use reader macros that resolve to a string literal like +`<# ` (which is useful for doctests), as long as the documentation text is also legible in the source code. Follow Python style on docstring contents. @@ -1716,7 +1697,7 @@ because the final character for the line is not a space but a ``"``. .. code-block:: REPL #> '.# - #..(.format <<# + #..(.format <# #.. ;; foobar {space} #.. ;; spameggs{space} #.. : space " ") @@ -1764,7 +1745,7 @@ Wrapped code lines are even worse as they disrupt the indent, although an occasional string literal containing a newline is acceptable, even in deeply nested code. If it's more than occasional, consider alternatives. -Remember you can use ``\n``, constants, `<\<#`, +Remember you can use ``\n``, constants, `<# `, or `textwrap.dedent` (even at read time). In rare instances (e.g., URLs), a constant definition containing a one-line string diff --git a/src/hissp/macros.lissp b/src/hissp/macros.lissp index 374c4c548..9e456eef3 100644 --- a/src/hissp/macros.lissp +++ b/src/hissp/macros.lissp @@ -413,7 +413,7 @@ Hidden doctest adds bundled macros for REPL-consistent behavior. .. code-block:: REPL #> (defmacro p123 (sep) - #.. <<#;Prints 1 2 3 with the given separator + #.. <#;Prints 1 2 3 with the given separator #.. `(print 1 2 3 : sep ,sep)) >>> # defmacro ... __import__('builtins').setattr( @@ -463,7 +463,7 @@ Hidden doctest adds bundled macros for REPL-consistent behavior. 1::2::3 See also: - `<\\<# `, `attach`, + `<# `, `attach`, `lambda `. " (let (form `(setattr (.get (globals) "_macro_") @@ -833,20 +833,18 @@ Hidden doctest adds bundled macros for REPL-consistent behavior. ;;;; Abbreviations -(defmacro <<\# (comment) +(defmacro <\# (comment) `',(.contents comment)) (setattr - _macro_.<<\# '__doc__ - <<# - ;; ``<<#`` 'comment string' reader macro. + _macro_.<\# '__doc__ + <#;``<#`` 'comment string' tag. ;; ;; Converts a block of line comments to a raw string. ;; Roughly equivalent to ``'hissp.reader..Comment.contents#``. ;; ;; .. code-block:: REPL ;; - ;; #> <<# - ;; #..;; You won't have to + ;; #> <#;You won't have to ;; #..;; escape the "quotes". ;; #.. ;; >>> 'You won\'t have to\nescape the "quotes".' @@ -864,8 +862,7 @@ Hidden doctest adds bundled macros for REPL-consistent behavior. `(lambda : ,e)) (defmacro X\# e - <<# - ;; ``X#`` Anaphoric. Make ``e`` an anonymous function with parameter X. + <#;``X#`` Anaphoric. Make ``e`` an anonymous function with parameter X. ;; ;; Examples: ;; @@ -957,8 +954,7 @@ Hidden doctest adds bundled macros for REPL-consistent behavior. `(lambda ,'XY ,e)) (defmacro XYZ\# e - <<# - ;; ``XYZ#`` Anaphoric. Make ``e`` an anonymous function with parameters X Y Z. + <#;``XYZ#`` Anaphoric. Make ``e`` an anonymous function with parameters X Y Z. ;; ;; .. code-block:: REPL ;; @@ -974,8 +970,7 @@ Hidden doctest adds bundled macros for REPL-consistent behavior. `(lambda ,'XYZ ,e)) (defmacro XYZW\# e - <<# - ;; ``XYZW#`` Anaphoric. Make ``e`` an anonymous function with parameters X Y Z W. + <#;``XYZW#`` Anaphoric. Make ``e`` an anonymous function with parameters X Y Z W. ;; ;; .. code-block:: REPL ;; @@ -992,8 +987,7 @@ Hidden doctest adds bundled macros for REPL-consistent behavior. `(lambda ,'XYZW ,e)) (defmacro alias (abbreviation qualifier) - <<# - ;; Defines a reader macro abbreviation of a qualifier. + <#;Defines a tag abbreviation of a qualifier. ;; ;; .. code-block:: REPL ;; @@ -1067,7 +1061,7 @@ Hidden doctest adds bundled macros for REPL-consistent behavior. ;; >>> b'Read-time b# via alias.' ;; b'Read-time b# via alias.' ;; - ;; The bundled `op#` and `i#` reader macros are aliases + ;; The bundled `op#` and `i#` tags are aliases ;; for `operator` and `itertools`, respectively. ;; ;; See also: `prelude`, `attach`. @@ -1090,8 +1084,7 @@ Hidden doctest adds bundled macros for REPL-consistent behavior. `(i#chain.from_iterable ,xss)) (defmacro get\# e - <<# - ;; ``get#`` 'itemgetter-' Makes an `operator.itemgetter` function from ``e``. + <#;``get#`` 'itemgetter-' Makes an `operator.itemgetter` function from ``e``. ;; ;; .. code-block:: REPL ;; @@ -2073,8 +2066,7 @@ Hidden doctest adds bundled macros for REPL-consistent behavior. ;;;; Reader (defmacro b\# (raw) - <<# - ;; ``b#`` `bytes` literal reader macro + <#;``b#`` `bytes` literal tag ;; ;; .. code-block:: REPL ;; @@ -2094,8 +2086,7 @@ Hidden doctest adds bundled macros for REPL-consistent behavior. ast..literal_eval)) (defmacro en\# (f) - <<# - ;; ``en#`` reader macro. + <#;``en#`` tag. ;; Wrap a function applicable to a tuple as a function of its elements. ;; ;; .. code-block:: REPL @@ -2151,7 +2142,7 @@ Hidden doctest adds bundled macros for REPL-consistent behavior. ;; ... ('.')) ;; 'Sum: 5. Product: 6.' ;; - ;; There are no bundled reader macros for a quinary, senary, etc. but + ;; There are no bundled tags for a quinary, senary, etc. but ;; the en#X# variadic or a normal lambda form can be used instead. ;; ;; See also: `X# `. @@ -2166,8 +2157,7 @@ Hidden doctest adds bundled macros for REPL-consistent behavior. ;;;; Collection (defmacro @ (: :* xs) - <<# - ;; ``@`` 'list of' Mnemonic: @rray list. + <#;``@`` 'list of' Mnemonic: @rray list. ;; ;; Creates the `list` from each expression's result. ;; A ``:*`` unpacks the next argument. @@ -2269,8 +2259,7 @@ Hidden doctest adds bundled macros for REPL-consistent behavior. ;;;; Import (defmacro prelude (: ns `(globals)) - <<# - ;; Hissp's bundled micro prelude. + <#;Hissp's bundled micro prelude. ;; ;; Brings Hissp up to a minimal standard of usability without adding any ;; dependencies in the compiled output. @@ -2855,8 +2844,7 @@ vars(_macro_).update(vars(__import__('hissp')._macro_))" ;;;; Advanced (defmacro case (key default : :* pairs) - <<# - ;; Switch case macro. + <#;Switch case macro. ;; ;; Precomputes a lookup table (dict), so must switch on a hashable key. ;; Target keys are not evaluated, so don't quote them; they must be known @@ -3019,8 +3007,7 @@ vars(_macro_).update(vars(__import__('hissp')._macro_))" $#val))) (defmacro avow (e predicate : :* args) - <<# - ;; Anaphoric. Raises `AssertionError` `unless` (-> e predicate). + <#;Anaphoric. Raises `AssertionError` `unless` (-> e predicate). ;; ;; Additional arguments are evaluated in a context where ``it`` refers ;; to the result of e. These (if any) are passed to the @@ -3068,8 +3055,7 @@ vars(_macro_).update(vars(__import__('hissp')._macro_))" ,'it)) (defmacro assure (e predicate : :* args) - <<# - ;; Anaphoric. Raises `AssertionError` `unless` (-> e predicate). + <#;Anaphoric. Raises `AssertionError` `unless` (-> e predicate). ;; ;; As `avow`, but expansion is simply ``e`` when `__debug__` is off: ;; diff --git a/tests/test_cmd.py b/tests/test_cmd.py index e2097ad31..23d0a4790 100644 --- a/tests/test_cmd.py +++ b/tests/test_cmd.py @@ -207,7 +207,7 @@ def test_repl_str_continue(): b#.#" x" - (.decode b#.#<<#;\\xff + (.decode b#.#<#;\\xff ;; foo : errors 'ignore) """,