From c0df3f918798e798cc95072cbd74b6e20922d629 Mon Sep 17 00:00:00 2001 From: gilch Date: Wed, 24 May 2023 21:12:28 -0600 Subject: [PATCH 01/11] Add depth to MARK ] --- src/hissp/macros.lissp | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/src/hissp/macros.lissp b/src/hissp/macros.lissp index 41d70378..4d739eae 100644 --- a/src/hissp/macros.lissp +++ b/src/hissp/macros.lissp @@ -2017,6 +2017,9 @@ except ModuleNotFoundError:pass" Expressions are often terse enough to be used one-off inline. + The mini-language supports higher-order function manipulation + including composition, partial application, and point-free data flow. + The language is applied right-to-left, like function calls. Magic characters are @@ -2028,21 +2031,24 @@ except ModuleNotFoundError:pass" Copies (at depth) and pushes. ``@`` ROLL (default depth 2) Pops (at depth) and pushes. - ``]`` MARK (no depth) - Pushes a sentinel gensym for PACK. - Callables are data when there's a mark. + ``]`` MARK (default depth 0) + Inserts a sentinel gensym for PACK (at depth). + Callables are quoted between ``[]``. ``[`` PACK (no depth) - Pops to MARK and pushes as tuple. + Pops to the first sentinel and pushes as tuple. ``*`` SPLAT - Pops (at depth) and pushes its elements. + Pops (at depth) and pushes elements. ``:`` NOP (no depth) No effect. Used as a separator when no other magic applies. They can be escaped with a backtick (:literal:`\``). Other elements are either callables or data, and read as Lissp. - Data elements just put themselves on the stack. + Data elements just push themselves on the stack (depth 0). Callables pop args to their depth and push their result. + These are categorized at read time. Literals are always data, but + elements that read as `tuple` or `str` types are sometimes ambiguous, + in which case they are assumed callable, unless between ``[]``. .. code-block:: REPL @@ -2213,7 +2219,9 @@ except ModuleNotFoundError:pass" `(.append ,'$#stack (tuple (iter ,'$#stack.pop ','$#\])))) .#"]" (progn (.append marks "]") - `(.append ,'$#stack ','$#\])) + `(.insert ,'$#stack + (op#sub (len ,'$#stack) ,(len Y)) + ','$#\])) .#"*" `(.extend ,'$#stack (reversed (tuple (.pop ,'$#stack ,(op#sub -1 (len Y)))))) From 82e3f2e027583ea2a276aae448d853e6665930c2 Mon Sep 17 00:00:00 2001 From: gilch Date: Fri, 26 May 2023 08:51:37 -0600 Subject: [PATCH 02/11] Use # instead of @ tuple str are hashable --- src/hissp/macros.lissp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hissp/macros.lissp b/src/hissp/macros.lissp index 4d739eae..86abd5db 100644 --- a/src/hissp/macros.lissp +++ b/src/hissp/macros.lissp @@ -2201,7 +2201,7 @@ except ModuleNotFoundError:pass" XY#(case X (let (obj (next (.reads reader (.replace X "`" "")))) `(.append ,'$#stack ,(if-else (|| marks - (not (op#contains (@ tuple str) + (not (op#contains (# tuple str) (type obj))) (hissp.reader..is_lissp_string obj) (&& (op#is_ str (type obj)) From 14ea7a34c525f7bdd2bade7983d3944343da3d80 Mon Sep 17 00:00:00 2001 From: gilch Date: Sat, 27 May 2023 09:07:18 -0600 Subject: [PATCH 03/11] Remove examples in ^# docstring They'll be changing too rapidly. I'll add examples later. --- src/hissp/macros.lissp | 143 +---------------------------------------- 1 file changed, 1 insertion(+), 142 deletions(-) diff --git a/src/hissp/macros.lissp b/src/hissp/macros.lissp index 86abd5db..9c846bf5 100644 --- a/src/hissp/macros.lissp +++ b/src/hissp/macros.lissp @@ -2048,148 +2048,7 @@ except ModuleNotFoundError:pass" Callables pop args to their depth and push their result. These are categorized at read time. Literals are always data, but elements that read as `tuple` or `str` types are sometimes ambiguous, - in which case they are assumed callable, unless between ``[]``. - - .. code-block:: REPL - - #> (define average ^#truediv^sum@len&) - >>> # define - ... __import__('builtins').globals().update( - ... average=(lambda *_QzNo73_args: - ... # hissp.macros.._macro_.let - ... (lambda _QzNo73_stack=__import__('builtins').list( - ... _QzNo73_args):( - ... _QzNo73_stack.reverse(), - ... _QzNo73_stack.append( - ... (lambda X,Y:X[-1-Y])( - ... _QzNo73_stack, - ... (0))), - ... _QzNo73_stack.append( - ... len( - ... _QzNo73_stack.pop())), - ... _QzNo73_stack.append( - ... _QzNo73_stack.pop( - ... (-2))), - ... _QzNo73_stack.append( - ... sum( - ... _QzNo73_stack.pop())), - ... _QzNo73_stack.append( - ... truediv( - ... _QzNo73_stack.pop(), - ... _QzNo73_stack.pop())), - ... _QzNo73_stack.pop())[-1])())) - - #> (define geomean ^#pow^reduce^*[mul]@truediv^1:len&) - >>> # define - ... __import__('builtins').globals().update( - ... geomean=(lambda *_QzNo73_args: - ... # hissp.macros.._macro_.let - ... (lambda _QzNo73_stack=__import__('builtins').list( - ... _QzNo73_args):( - ... _QzNo73_stack.reverse(), - ... _QzNo73_stack.append( - ... (lambda X,Y:X[-1-Y])( - ... _QzNo73_stack, - ... (0))), - ... _QzNo73_stack.append( - ... len( - ... _QzNo73_stack.pop())), - ... (), - ... _QzNo73_stack.append( - ... (1)), - ... _QzNo73_stack.append( - ... truediv( - ... _QzNo73_stack.pop(), - ... _QzNo73_stack.pop())), - ... _QzNo73_stack.append( - ... _QzNo73_stack.pop( - ... (-2))), - ... _QzNo73_stack.append( - ... '_QzNo73_QzRSQB_'), - ... _QzNo73_stack.append( - ... mul), - ... _QzNo73_stack.append( - ... __import__('builtins').tuple( - ... __import__('builtins').iter( - ... _QzNo73_stack.pop, - ... '_QzNo73_QzRSQB_'))), - ... _QzNo73_stack.extend( - ... __import__('builtins').reversed( - ... __import__('builtins').tuple( - ... _QzNo73_stack.pop( - ... (-1))))), - ... _QzNo73_stack.append( - ... reduce( - ... _QzNo73_stack.pop(), - ... _QzNo73_stack.pop())), - ... _QzNo73_stack.append( - ... pow( - ... _QzNo73_stack.pop(), - ... _QzNo73_stack.pop())), - ... _QzNo73_stack.pop())[-1])())) - - #> (geomean '(1 10)) - >>> geomean( - ... ((1), - ... (10),)) - 3.1622776601683795 - - #> (average '(.1 10)) - >>> average( - ... ((0.1), - ... (10),)) - 5.05 - - #> (geomean '(.1 10)) - >>> geomean( - ... ((0.1), - ... (10),)) - 1.0 - - #> (en#average 4 5 6) - >>> (lambda *_QzNo60_xs: - ... average( - ... _QzNo60_xs))( - ... (4), - ... (5), - ... (6)) - 5.0 - - #> (define decrement ^#sub^@1) - >>> # define - ... __import__('builtins').globals().update( - ... decrement=(lambda *_QzNo73_args: - ... # hissp.macros.._macro_.let - ... (lambda _QzNo73_stack=__import__('builtins').list( - ... _QzNo73_args):( - ... _QzNo73_stack.reverse(), - ... _QzNo73_stack.append( - ... (1)), - ... _QzNo73_stack.append( - ... _QzNo73_stack.pop( - ... (-2))), - ... _QzNo73_stack.append( - ... sub( - ... _QzNo73_stack.pop(), - ... _QzNo73_stack.pop())), - ... _QzNo73_stack.pop())[-1])())) - - #> (^#decrement:decrement 5) - >>> (lambda *_QzNo73_args: - ... # hissp.macros.._macro_.let - ... (lambda _QzNo73_stack=__import__('builtins').list( - ... _QzNo73_args):( - ... _QzNo73_stack.reverse(), - ... _QzNo73_stack.append( - ... decrement( - ... _QzNo73_stack.pop())), - ... (), - ... _QzNo73_stack.append( - ... decrement( - ... _QzNo73_stack.pop())), - ... _QzNo73_stack.pop())[-1])())( - ... (5)) - 3 + in which case they are assumed callable. " (let (reader (hissp..reader.Lissp : ns (.get hissp.compiler..NS)) From dae5ff808bba250805defaa00f994f0642cda244 Mon Sep 17 00:00:00 2001 From: gilch Date: Sat, 27 May 2023 09:08:00 -0600 Subject: [PATCH 04/11] Don't disable functions between [] --- src/hissp/macros.lissp | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) diff --git a/src/hissp/macros.lissp b/src/hissp/macros.lissp index 9c846bf5..2d246b5b 100644 --- a/src/hissp/macros.lissp +++ b/src/hissp/macros.lissp @@ -2033,7 +2033,6 @@ except ModuleNotFoundError:pass" Pops (at depth) and pushes. ``]`` MARK (default depth 0) Inserts a sentinel gensym for PACK (at depth). - Callables are quoted between ``[]``. ``[`` PACK (no depth) Pops to the first sentinel and pushes as tuple. ``*`` SPLAT @@ -2051,16 +2050,14 @@ except ModuleNotFoundError:pass" in which case they are assumed callable. " - (let (reader (hissp..reader.Lissp : ns (.get hissp.compiler..NS)) - marks (list)) + (let (reader (hissp..reader.Lissp : ns (.get hissp.compiler..NS))) `(lambda (: :* $#args) (let ($#stack (list $#args)) (.reverse $#stack) ,@(i#starmap XY#(case X (let (obj (next (.reads reader (.replace X "`" "")))) `(.append ,'$#stack - ,(if-else (|| marks - (not (op#contains (# tuple str) + ,(if-else (|| (not (op#contains (# tuple str) (type obj))) (hissp.reader..is_lissp_string obj) (&& (op#is_ str (type obj)) @@ -2074,13 +2071,10 @@ except ModuleNotFoundError:pass" .#"/" `(.pop ,'$#stack ,(op#sub -1 (len Y))) .#"&" `(.append ,'$#stack (,'XY#.#"X[-1-Y]" ,'$#stack ,(len Y))) .#"@" `(.append ,'$#stack (.pop ,'$#stack ,(op#sub -2 (len Y)))) - .#"[" (progn (.pop marks) - `(.append ,'$#stack - (tuple (iter ,'$#stack.pop ','$#\])))) - .#"]" (progn (.append marks "]") - `(.insert ,'$#stack - (op#sub (len ,'$#stack) ,(len Y)) - ','$#\])) + .#"[" `(.append ,'$#stack (tuple (iter ,'$#stack.pop ','$#\]))) + .#"]" `(.insert ,'$#stack + (op#sub (len ,'$#stack) ,(len Y)) + ','$#\]) .#"*" `(.extend ,'$#stack (reversed (tuple (.pop ,'$#stack ,(op#sub -1 (len Y)))))) From e70061afed552b2ae8140c10bd27f6cae0d39fa3 Mon Sep 17 00:00:00 2001 From: gilch Date: Sat, 27 May 2023 11:01:50 -0600 Subject: [PATCH 05/11] Add literal-with-depth lookups --- src/hissp/macros.lissp | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/src/hissp/macros.lissp b/src/hissp/macros.lissp index 2d246b5b..d7be75c8 100644 --- a/src/hissp/macros.lissp +++ b/src/hissp/macros.lissp @@ -2043,7 +2043,16 @@ except ModuleNotFoundError:pass" They can be escaped with a backtick (:literal:`\``). Other elements are either callables or data, and read as Lissp. - Data elements just push themselves on the stack (depth 0). + Data elements just push themselves on the stack (default depth 0). + + #> (^#2) + 2 + + Increasing the depth to 1 implies a lookup on the next element. + + #> (^#:'foo^ (% 'foo 2)) + 2 + Callables pop args to their depth and push their result. These are categorized at read time. Literals are always data, but elements that read as `tuple` or `str` types are sometimes ambiguous, @@ -2065,7 +2074,9 @@ except ModuleNotFoundError:pass" (.endswith obj "."))) (&& (op#is_ tuple (type obj)) (op#eq 'quote (get#0 obj)))) - obj + (if-else Y + `(op#getitem (.pop ,'$#stack) ,obj) + obj) `(,obj ,@(XY#.#"X*(Y+1)" `((.pop ,'$#stack)) (len Y)))))) .#"/" `(.pop ,'$#stack ,(op#sub -1 (len Y))) @@ -2079,7 +2090,7 @@ except ModuleNotFoundError:pass" (reversed (tuple (.pop ,'$#stack ,(op#sub -1 (len Y)))))) : ()) - (reversed (re..findall "([/&@*:[\]]|(?:[^^`/&@*:[\]]|`[/&@*:[\]])+)(\^*)" + (reversed (re..findall "([/&@[\]*:]|(?:[^^`/&@[\]*:]|`[/&@[\]*:])+)(\^*)" (hissp..demunge s)))) (.pop $#stack))))) From 75a8bf0d0a79ca65be72e711036f32aa54ffc73a Mon Sep 17 00:00:00 2001 From: gilch Date: Sat, 27 May 2023 13:04:06 -0600 Subject: [PATCH 06/11] Add PACK-with-depth lookups --- src/hissp/macros.lissp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/hissp/macros.lissp b/src/hissp/macros.lissp index d7be75c8..52973dbe 100644 --- a/src/hissp/macros.lissp +++ b/src/hissp/macros.lissp @@ -2033,8 +2033,9 @@ except ModuleNotFoundError:pass" Pops (at depth) and pushes. ``]`` MARK (default depth 0) Inserts a sentinel gensym for PACK (at depth). - ``[`` PACK (no depth) + ``[`` PACK Pops to the first sentinel and pushes as tuple. + With depth, looks tuple up on the next element. ``*`` SPLAT Pops (at depth) and pushes elements. ``:`` NOP (no depth) @@ -2082,7 +2083,10 @@ except ModuleNotFoundError:pass" .#"/" `(.pop ,'$#stack ,(op#sub -1 (len Y))) .#"&" `(.append ,'$#stack (,'XY#.#"X[-1-Y]" ,'$#stack ,(len Y))) .#"@" `(.append ,'$#stack (.pop ,'$#stack ,(op#sub -2 (len Y)))) - .#"[" `(.append ,'$#stack (tuple (iter ,'$#stack.pop ','$#\]))) + .#"[" `(.append ,'$#stack + (-<>> (tuple (iter ,'$#stack.pop ','$#\])) + ,@(when Y `(op#itemgetter + (:<> (,'$#stack.pop)))))) .#"]" `(.insert ,'$#stack (op#sub (len ,'$#stack) ,(len Y)) ','$#\]) From 35bf630e3ad4103c1b175884272e50ddcc622f6c Mon Sep 17 00:00:00 2001 From: gilch Date: Sat, 27 May 2023 13:40:44 -0600 Subject: [PATCH 07/11] Factor out predicates --- src/hissp/macros.lissp | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/src/hissp/macros.lissp b/src/hissp/macros.lissp index 52973dbe..ab4cd9c0 100644 --- a/src/hissp/macros.lissp +++ b/src/hissp/macros.lissp @@ -2060,21 +2060,22 @@ except ModuleNotFoundError:pass" in which case they are assumed callable. " - (let (reader (hissp..reader.Lissp : ns (.get hissp.compiler..NS))) + (let (reader (hissp..reader.Lissp : ns (.get hissp.compiler..NS)) + literal? X#(not (op#contains (# tuple str) (type X))) + control-word? X#(&& (op#is_ (type X) str) (.startswith X ":")) + module-handle? X#(&& (op#is_ (type X) str) (.endswith X ".")) + quotation? X#(&& (op#is_ (type X) tuple) (op#eq 'quote (get#0 X)))) `(lambda (: :* $#args) (let ($#stack (list $#args)) (.reverse $#stack) ,@(i#starmap XY#(case X (let (obj (next (.reads reader (.replace X "`" "")))) `(.append ,'$#stack - ,(if-else (|| (not (op#contains (# tuple str) - (type obj))) + ,(if-else (|| (literal? obj) (hissp.reader..is_lissp_string obj) - (&& (op#is_ str (type obj)) - (|| (.startswith obj ":") - (.endswith obj "."))) - (&& (op#is_ tuple (type obj)) - (op#eq 'quote (get#0 obj)))) + (control-word? obj) + (module-handle? obj) + (quotation? obj)) (if-else Y `(op#getitem (.pop ,'$#stack) ,obj) obj) From efc53a418e59f3f5fa5c8d6a8c70c21f5090dc8a Mon Sep 17 00:00:00 2001 From: gilch Date: Sat, 27 May 2023 15:01:36 -0600 Subject: [PATCH 08/11] Add attribute lookups --- src/hissp/macros.lissp | 25 ++++++++++++++++++------- 1 file changed, 18 insertions(+), 7 deletions(-) diff --git a/src/hissp/macros.lissp b/src/hissp/macros.lissp index ab4cd9c0..0f5cd608 100644 --- a/src/hissp/macros.lissp +++ b/src/hissp/macros.lissp @@ -2054,17 +2054,22 @@ except ModuleNotFoundError:pass" #> (^#:'foo^ (% 'foo 2)) 2 - Callables pop args to their depth and push their result. - These are categorized at read time. Literals are always data, but - elements that read as `tuple` or `str` types are sometimes ambiguous, - in which case they are assumed callable. + Callables (default depth 1) pop args to their depth and push their + result. These are categorized at read time. Literals are always data, + but elements that read as `tuple` or `str` types are sometimes + ambiguous, in which case they are assumed callable. + Methods at depth one are converted to attribute lookups. + + #> (^#.__class__.__name__ :x) + 'str' " (let (reader (hissp..reader.Lissp : ns (.get hissp.compiler..NS)) literal? X#(not (op#contains (# tuple str) (type X))) control-word? X#(&& (op#is_ (type X) str) (.startswith X ":")) module-handle? X#(&& (op#is_ (type X) str) (.endswith X ".")) - quotation? X#(&& (op#is_ (type X) tuple) (op#eq 'quote (get#0 X)))) + quotation? X#(&& (op#is_ (type X) tuple) (op#eq 'quote (get#0 X))) + method? X#(&& (op#is_ (type X) str) (.startswith X "."))) `(lambda (: :* $#args) (let ($#stack (list $#args)) (.reverse $#stack) @@ -2079,8 +2084,14 @@ except ModuleNotFoundError:pass" (if-else Y `(op#getitem (.pop ,'$#stack) ,obj) obj) - `(,obj ,@(XY#.#"X*(Y+1)" `((.pop ,'$#stack)) - (len Y)))))) + (if-else (method? obj) + (if-else Y + `(,obj ,@(XY#.#"X*Y" `((.pop ,'$#stack)) + (len Y))) + `((op#attrgetter ',.#"obj[1:]") + (.pop ,'$#stack))) + `(,obj ,@(XY#.#"X*(Y+1)" `((.pop ,'$#stack)) + (len Y))))))) .#"/" `(.pop ,'$#stack ,(op#sub -1 (len Y))) .#"&" `(.append ,'$#stack (,'XY#.#"X[-1-Y]" ,'$#stack ,(len Y))) .#"@" `(.append ,'$#stack (.pop ,'$#stack ,(op#sub -2 (len Y)))) From d613fa6f65960000d586abfbec39de8d20baca59 Mon Sep 17 00:00:00 2001 From: gilch Date: Sat, 27 May 2023 16:22:47 -0600 Subject: [PATCH 09/11] Add % -kwargs --- src/hissp/macros.lissp | 46 +++++++++++++++++++++++++----------------- 1 file changed, 27 insertions(+), 19 deletions(-) diff --git a/src/hissp/macros.lissp b/src/hissp/macros.lissp index 0f5cd608..0190e025 100644 --- a/src/hissp/macros.lissp +++ b/src/hissp/macros.lissp @@ -2023,8 +2023,10 @@ except ModuleNotFoundError:pass" The language is applied right-to-left, like function calls. Magic characters are - ``^`` DEPTH - Suffix to increase arity. Assume depth 1 otherwise. + ``%`` -kwargs + Suffix interprets top element as **kwargs. Write before any ``^``. + ``^`` -depth + Suffix increases arity. Assume depth 1 otherwise. Can be repeated. ``/`` DROP Pops (at depth) and discards. ``&`` PICK @@ -2069,7 +2071,9 @@ except ModuleNotFoundError:pass" control-word? X#(&& (op#is_ (type X) str) (.startswith X ":")) module-handle? X#(&& (op#is_ (type X) str) (.endswith X ".")) quotation? X#(&& (op#is_ (type X) tuple) (op#eq 'quote (get#0 X))) - method? X#(&& (op#is_ (type X) str) (.startswith X "."))) + method? X#(&& (op#is_ (type X) str) (.startswith X ".")) + kwargs? X#(.startswith X "%") + depth X#(.count X "^")) `(lambda (: :* $#args) (let ($#stack (list $#args)) (.reverse $#stack) @@ -2081,33 +2085,37 @@ except ModuleNotFoundError:pass" (control-word? obj) (module-handle? obj) (quotation? obj)) - (if-else Y + (if-else (depth Y) `(op#getitem (.pop ,'$#stack) ,obj) obj) - (if-else (method? obj) - (if-else Y - `(,obj ,@(XY#.#"X*Y" `((.pop ,'$#stack)) - (len Y))) - `((op#attrgetter ',.#"obj[1:]") - (.pop ,'$#stack))) - `(,obj ,@(XY#.#"X*(Y+1)" `((.pop ,'$#stack)) - (len Y))))))) - .#"/" `(.pop ,'$#stack ,(op#sub -1 (len Y))) - .#"&" `(.append ,'$#stack (,'XY#.#"X[-1-Y]" ,'$#stack ,(len Y))) - .#"@" `(.append ,'$#stack (.pop ,'$#stack ,(op#sub -2 (len Y)))) + (if-else (|| (depth Y) (not (method? obj))) + `(,obj ,@(XYZW#.#"(X+1-Y-Z)*W" + (depth Y) + (method? obj) + (kwargs? Y) + `((.pop ,'$#stack + ,(op#sub -1 (kwargs? Y))))) + : ,@(when (kwargs? Y) + `(:** (dict (.pop ,'$#stack))))) + `((op#attrgetter ',.#"obj[1:]") + (.pop ,'$#stack)))))) + .#"/" `(.pop ,'$#stack ,(op#sub -1 (depth Y))) + .#"&" `(.append ,'$#stack (,'XY#.#"X[-1-Y]" ,'$#stack ,(depth Y))) + .#"@" `(.append ,'$#stack (.pop ,'$#stack ,(op#sub -2 (depth Y)))) .#"[" `(.append ,'$#stack (-<>> (tuple (iter ,'$#stack.pop ','$#\])) ,@(when Y `(op#itemgetter (:<> (,'$#stack.pop)))))) .#"]" `(.insert ,'$#stack - (op#sub (len ,'$#stack) ,(len Y)) + (op#sub (len ,'$#stack) ,(depth Y)) ','$#\]) .#"*" `(.extend ,'$#stack (reversed (tuple (.pop ,'$#stack - ,(op#sub -1 (len Y)))))) + ,(op#sub -1 (depth Y)))))) : ()) - (reversed (re..findall "([/&@[\]*:]|(?:[^^`/&@[\]*:]|`[/&@[\]*:])+)(\^*)" - (hissp..demunge s)))) + (reversed (re..findall + "([/&@[\]*:]|(?:[^%^`/&@[\]*:]|`[%^/&@[\]*:])+)(%?\^*)" + (hissp..demunge s)))) (.pop $#stack))))) (defmacro _spy (expr file) From 65469a64d1b456c8cd59197c0e598d8ec01fc192 Mon Sep 17 00:00:00 2001 From: gilch Date: Sat, 27 May 2023 18:08:40 -0600 Subject: [PATCH 10/11] Add , -data --- src/hissp/macros.lissp | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/hissp/macros.lissp b/src/hissp/macros.lissp index 0190e025..bfe2beae 100644 --- a/src/hissp/macros.lissp +++ b/src/hissp/macros.lissp @@ -2023,6 +2023,8 @@ except ModuleNotFoundError:pass" The language is applied right-to-left, like function calls. Magic characters are + ``,`` -data + Suffix interprets callable as data. Write before any ``^``. ``%`` -kwargs Suffix interprets top element as **kwargs. Write before any ``^``. ``^`` -depth @@ -2058,13 +2060,14 @@ except ModuleNotFoundError:pass" Callables (default depth 1) pop args to their depth and push their result. These are categorized at read time. Literals are always data, - but elements that read as `tuple` or `str` types are sometimes - ambiguous, in which case they are assumed callable. + but an element that reads as `tuple` or `str` type may be ambiguous, + in which case they are presumed callable, unless it ends with a ``,``. Methods at depth one are converted to attribute lookups. #> (^#.__class__.__name__ :x) 'str' + " (let (reader (hissp..reader.Lissp : ns (.get hissp.compiler..NS)) literal? X#(not (op#contains (# tuple str) (type X))) @@ -2081,6 +2084,7 @@ except ModuleNotFoundError:pass" XY#(case X (let (obj (next (.reads reader (.replace X "`" "")))) `(.append ,'$#stack ,(if-else (|| (literal? obj) + (.startswith Y ",") (hissp.reader..is_lissp_string obj) (control-word? obj) (module-handle? obj) @@ -2114,7 +2118,7 @@ except ModuleNotFoundError:pass" ,(op#sub -1 (depth Y)))))) : ()) (reversed (re..findall - "([/&@[\]*:]|(?:[^%^`/&@[\]*:]|`[%^/&@[\]*:])+)(%?\^*)" + "([/&@[\]*:]|(?:[^,%^`/&@[\]*:]|`[,%^/&@[\]*:])+)(%?,?\^*)" (hissp..demunge s)))) (.pop $#stack))))) From 3ce5f7800d76a22af95e036386aabba4e74a37da Mon Sep 17 00:00:00 2001 From: gilch Date: Sat, 27 May 2023 21:05:59 -0600 Subject: [PATCH 11/11] Fill in ^# docstring again --- src/hissp/macros.lissp | 165 +++++++++++++++++++++++++++++++++++++---- 1 file changed, 149 insertions(+), 16 deletions(-) diff --git a/src/hissp/macros.lissp b/src/hissp/macros.lissp index bfe2beae..61024bf6 100644 --- a/src/hissp/macros.lissp +++ b/src/hissp/macros.lissp @@ -2015,8 +2015,6 @@ except ModuleNotFoundError:pass" Builds a function whose arguments are pushed to a stack, operates on the stack according to the program, and finally pops its result. - Expressions are often terse enough to be used one-off inline. - The mini-language supports higher-order function manipulation including composition, partial application, and point-free data flow. @@ -2024,11 +2022,12 @@ except ModuleNotFoundError:pass" Magic characters are ``,`` -data - Suffix interprets callable as data. Write before any ``^``. + Suffix interprets callable as data. ``%`` -kwargs - Suffix interprets top element as **kwargs. Write before any ``^``. + Suffix interprets top element as ``**kwargs``. ``^`` -depth Suffix increases arity. Assume depth 1 otherwise. Can be repeated. + Write after other suffixes. ``/`` DROP Pops (at depth) and discards. ``&`` PICK @@ -2050,23 +2049,157 @@ except ModuleNotFoundError:pass" Other elements are either callables or data, and read as Lissp. Data elements just push themselves on the stack (default depth 0). - #> (^#2) - 2 - - Increasing the depth to 1 implies a lookup on the next element. + .. code-block:: REPL - #> (^#:'foo^ (% 'foo 2)) - 2 + #> (^#:2) + >>> (lambda *_QzNo73_args: + ... # hissp.macros.._macro_.let + ... (lambda _QzNo73_stack=__import__('builtins').list( + ... _QzNo73_args):( + ... _QzNo73_stack.reverse(), + ... _QzNo73_stack.append( + ... (2)), + ... (), + ... _QzNo73_stack.pop())[-1])())() + 2 Callables (default depth 1) pop args to their depth and push their - result. These are categorized at read time. Literals are always data, - but an element that reads as `tuple` or `str` type may be ambiguous, - in which case they are presumed callable, unless it ends with a ``,``. + result. Combine with a datum for partial application. - Methods at depth one are converted to attribute lookups. + .. code-block:: REPL - #> (^#.__class__.__name__ :x) - 'str' + #> (define decrement ^#sub^@1) + >>> # define + ... __import__('builtins').globals().update( + ... decrement=(lambda *_QzNo73_args: + ... # hissp.macros.._macro_.let + ... (lambda _QzNo73_stack=__import__('builtins').list( + ... _QzNo73_args):( + ... _QzNo73_stack.reverse(), + ... _QzNo73_stack.append( + ... (1)), + ... _QzNo73_stack.append( + ... _QzNo73_stack.pop( + ... (-2))), + ... _QzNo73_stack.append( + ... sub( + ... _QzNo73_stack.pop( + ... (-1)), + ... _QzNo73_stack.pop( + ... (-1)))), + ... _QzNo73_stack.pop())[-1])())) + + #> (decrement 5) + >>> decrement( + ... (5)) + 4 + + Increasing the depth of data to 1 implies a lookup on the next + element. Methods always need a self, so they can be converted to + attribute lookups at the default depth of 1. Combine them to drill + into complex data structures. + + .. code-block:: REPL + + #> (^#.__class__.__name__:'spam^ (dict : spam 'eggs)) + >>> (lambda *_QzNo73_args: + ... # hissp.macros.._macro_.let + ... (lambda _QzNo73_stack=__import__('builtins').list( + ... _QzNo73_args):( + ... _QzNo73_stack.reverse(), + ... _QzNo73_stack.append( + ... __import__('operator').getitem( + ... _QzNo73_stack.pop(), + ... 'spam')), + ... (), + ... _QzNo73_stack.append( + ... __import__('operator').attrgetter( + ... '__class__.__name__')( + ... _QzNo73_stack.pop())), + ... _QzNo73_stack.pop())[-1])())( + ... dict( + ... spam='eggs')) + 'str' + + The callable or data type is determined at read time. Literals are + always data. but an element that reads as `tuple` or `str` type may be + ambiguous, in which case they are presumed callable, unless it ends + with a ``,``. + + .. code-block:: REPL + + #> (define prod ^#reduce^mul,) + >>> # define + ... __import__('builtins').globals().update( + ... prod=(lambda *_QzNo73_args: + ... # hissp.macros.._macro_.let + ... (lambda _QzNo73_stack=__import__('builtins').list( + ... _QzNo73_args):( + ... _QzNo73_stack.reverse(), + ... _QzNo73_stack.append( + ... mul), + ... _QzNo73_stack.append( + ... reduce( + ... _QzNo73_stack.pop( + ... (-1)), + ... _QzNo73_stack.pop( + ... (-1)))), + ... _QzNo73_stack.pop())[-1])())) + + #> (en#prod 1 2 3) + >>> (lambda *_QzNo60_xs: + ... prod( + ... _QzNo60_xs))( + ... (1), + ... (2), + ... (3)) + 6 + + #> (define geomean ^#pow^prod@truediv^1:len&) + >>> # define + ... __import__('builtins').globals().update( + ... geomean=(lambda *_QzNo73_args: + ... # hissp.macros.._macro_.let + ... (lambda _QzNo73_stack=__import__('builtins').list( + ... _QzNo73_args):( + ... _QzNo73_stack.reverse(), + ... _QzNo73_stack.append( + ... (lambda X,Y:X[-1-Y])( + ... _QzNo73_stack, + ... (0))), + ... _QzNo73_stack.append( + ... len( + ... _QzNo73_stack.pop( + ... (-1)))), + ... (), + ... _QzNo73_stack.append( + ... (1)), + ... _QzNo73_stack.append( + ... truediv( + ... _QzNo73_stack.pop( + ... (-1)), + ... _QzNo73_stack.pop( + ... (-1)))), + ... _QzNo73_stack.append( + ... _QzNo73_stack.pop( + ... (-2))), + ... _QzNo73_stack.append( + ... prod( + ... _QzNo73_stack.pop( + ... (-1)))), + ... _QzNo73_stack.append( + ... pow( + ... _QzNo73_stack.pop( + ... (-1)), + ... _QzNo73_stack.pop( + ... (-1)))), + ... _QzNo73_stack.pop())[-1])())) + + #> (geomean '(1 10)) + >>> geomean( + ... ((1), + ... (10),)) + 3.1622776601683795 " (let (reader (hissp..reader.Lissp : ns (.get hissp.compiler..NS))