Skip to content

Commit

Permalink
Remove synexpand and friends
Browse files Browse the repository at this point in the history
^*#, ^# - ^^^^#
  • Loading branch information
gilch committed Jan 13, 2024
1 parent b4fed74 commit 61a5cac
Showing 1 changed file with 5 additions and 233 deletions.
238 changes: 5 additions & 233 deletions src/hissp/macros.lissp
Original file line number Diff line number Diff line change
Expand Up @@ -759,7 +759,7 @@ Hidden doctest adds bundled macros for REPL-consistent behavior.
;;
;; See also:
;; `en#<enQzHASH_>`, `O#<OQzHASH_>`, `XY#<XYQzHASH_>`, `getattr`,
;; `operator.attrgetter`, `lambda`, `^#<QzHAT_QzHASH_>`.
;; `operator.attrgetter`, `lambda`.
;;
`(lambda ,'X ,e))

Expand All @@ -777,7 +777,7 @@ Hidden doctest adds bundled macros for REPL-consistent behavior.
... 'abcd')
'dcba'

See also: `X#<XQzHASH_>`, `XYZ#<XYZQzHASH_>`, `^^#<QzHAT_QzHAT_QzHASH_>`.
See also: `X#<XQzHASH_>`, `XYZ#<XYZQzHASH_>`.
"
`(lambda ,'XY ,e))

Expand All @@ -794,8 +794,7 @@ Hidden doctest adds bundled macros for REPL-consistent behavior.
;; ... Z=__import__('math').tau)
;; True
;;
;; See also: `XY#<XYQzHASH_>`, `XYZW#<XYZWQzHASH_>`,
;; `^^^#<QzHAT_QzHAT_QzHAT_QzHASH_>`.
;; See also: `XY#<XYQzHASH_>`, `XYZW#<XYZWQzHASH_>`.
;;
`(lambda ,'XYZ ,e))

Expand All @@ -814,7 +813,6 @@ Hidden doctest adds bundled macros for REPL-consistent behavior.
;; 'Hello'
;;
;; See also: `XYZ#<XYZQzHASH_>`, `en#<enQzHASH_>`, `X#<XQzHASH_>`.
;; `^^^^#<QzHAT_QzHAT_QzHAT_QzHAT_QzHASH_>`.
;;
`(lambda ,'XYZW ,e))

Expand Down Expand Up @@ -939,8 +937,8 @@ Hidden doctest adds bundled macros for REPL-consistent behavior.
;; ... QzPLUS_=(1)))
;; 1
;;
;; See also: `operator.getitem`, `[#<QzLSQB_QzHASH_>`,
;; `set!<setQzBANG_>`, `^*#<QzHAT_QzSTAR_QzHASH_>`.
;; See also:
;; `operator.getitem`, `[#<QzLSQB_QzHASH_>`, `set!<setQzBANG_>`.
;;
`(op#itemgetter ,e))

Expand Down Expand Up @@ -2585,232 +2583,6 @@ except ModuleNotFoundError:pass"
"``nil#`` evaluates as ``x or ()``. Adapter for 'nil punning'."
`(ors ,x ()))

(defmacro ^*\# e
"``^*#`` 'synexpand' concatenative mini-language expressions

Walks e expanding any mini-language syntax found.

The mini-language supports higher-order function manipulation
including composition, partial application, and point-free data flow.

A mini-language expression is a tuple beginning with an element
containing at least one ``^`` or ``:`` character that is not the first
character (to avoid detecting all control words). The remainder form
the initial stack.

The first element must read to a `str` (typically a symbol, control
word, or injected string literal), is demunged, and is split into
terms on magic characters.

Syntax expansion builds an expression from the stack of expressions
operated on by the mini-language terms. The result is the stack
spliced into a `prog1` (or the element itself if only one remains).

The
`^#<QzHAT_QzHASH_>`,
`^^#<QzHAT_QzHAT_QzHASH_>`,
`^^^#<QzHAT_QzHAT_QzHAT_QzHASH_>`, and
`^^^^#<QzHAT_QzHAT_QzHAT_QzHAT_QzHASH_>` macros apply to terms and
wrap a ``^*#`` expression in a lambda of arity 1-4 (respectively)
using their parameters as the initial stack.

The terms are applied right-to-left, like function calls.
Magic characters are

``,`` -data (Suffix)
Interprets callable term as data.
``^`` -depth (Suffix)
Increases arity of a term. Assume depth 1 otherwise. Can be repeated.
Write after -data.
``/`` DROP (term)
Removes expression (at depth).
``&`` PICK (term)
Copies expression (at depth) and pushes.
``@`` ROLL (term, default depth 2)
Pops expression (at depth) and pushes.
``>`` MARK (term, default depth 0)
Inserts a sentinel object for PACK (at depth).
``<`` PACK (term)
Pops to the first MARK (if any) and pushes as tuple.
With depth, looks tuple up on the next expression.
Used for invocations.
``*`` SPLAT (term)
Splices an iterable (in-place, at depth).
``:`` NOP (no depth)
Has no effect. A separator when no other magic applies.

They can be escaped with a backtick (:literal:`\\``).

Other terms are either callables or data, and read as Lissp.

Callables (default depth 1) pop args to their depth and push their
result. Combine with a datum for partial application.

.. code-block:: REPL

#> (define decrement ^#sub^@1)
>>> # define
... __import__('builtins').globals().update(
... decrement=(lambda _QzX7FS3TFJz_x:
... # hissp.macros.._macro_.QzHAT_QzSTAR_QzHASH_
... sub(
... _QzX7FS3TFJz_x,
... (1))))

#> (decrement 5)
>>> decrement(
... (5))
4

Data terms just push themselves on the stack (default depth 0).

.. code-block:: REPL

#> ^*#(<`@,1:2:3)
>>> # QzAT_
... (lambda *xs:[*xs])(
... (1),
... (2),
... (3))
[1, 2, 3]

Increasing the depth of data to 1 implies a lookup on the next
expression. 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 _QzX7FS3TFJz_x:
... # hissp.macros.._macro_.QzHAT_QzSTAR_QzHASH_
... __import__('operator').attrgetter(
... '__class__.__name__')(
... __import__('operator').getitem(
... _QzX7FS3TFJz_x,
... 'spam')))(
... dict(
... spam='eggs'))
'str'

Terms are categorized as callable or data at read time. Literals are
always data, but a term that reads as a `tuple` or `str` type may be
ambiguous, in which case it's presumed callable, unless it ends with a
``,``.

.. code-block:: REPL

#> (define prod ^#reduce^mul,)
>>> # define
... __import__('builtins').globals().update(
... prod=(lambda _QzX7FS3TFJz_x:
... # hissp.macros.._macro_.QzHAT_QzSTAR_QzHASH_
... reduce(
... mul,
... _QzX7FS3TFJz_x)))

#> (en#prod 1 2 3)
>>> (lambda *_Qz6RFWTTVXz_xs:
... prod(
... _Qz6RFWTTVXz_xs))(
... (1),
... (2),
... (3))
6

#> (define geomean ^#pow^prod@truediv^1:len&)
>>> # define
... __import__('builtins').globals().update(
... geomean=(lambda _QzX7FS3TFJz_x:
... # hissp.macros.._macro_.QzHAT_QzSTAR_QzHASH_
... pow(
... prod(
... _QzX7FS3TFJz_x),
... truediv(
... (1),
... len(
... _QzX7FS3TFJz_x)))))

#> (geomean '(1 10))
>>> geomean(
... ((1),
... (10),))
3.1622776601683795

"
(if-else (ands e (op#is_ tuple (type e)))
(let-from (sym : :* args) e
(if-else (ands (op#is_ str (type sym))
(re..search ".[:^]" (hissp..demunge sym)))
(._rewrite _macro_
(re..findall <<#;([/&@<>*:]|(?:[^,^`/&@<>*:]|`[,^/&@<>*:])+)(,?\^*)
(hissp..demunge sym))
: :* (map X#(.^*\# _macro_ X) args))
`(,@(map X#(.^*\# _macro_ X) e))))
e))

(defmacro _rewrite (program : :* exprs)
(if-else (not program)
(case (len exprs) `(prog1 ,@exprs)
(1) (get#0 exprs))
my#
(let-from (cmd suffix) (.pop program)
(attach my
: reader (hissp..reader.Lissp : ns (.get hissp.compiler..NS))
is? XY#(op#is_ X (type Y))
str? X#(my.is? str X)
startswith? XY#(ands (my.str? X) (.startswith X Y))
literal? X#(ors (op#eq () X) (not (op#contains (# tuple str) (type X))))
quotation? X#(ands (my.is? tuple X) (op#eq 'quote (get#0 X)))
control-word? X#(my.startswith? X ":")
module-handle? X#(ands (my.str? X) (.endswith X "."))
method? X#(my.startswith? X ".")
exprs (list exprs)
arity (.count suffix "^")
mark (getattr unittest.mock..sentinel "hissp.>"))
(attach my
: iexprs (iter my.exprs)
obj (next (.reads my.reader (.replace cmd "`" "")))
arity+1 (op#add 1 my.arity))
(set@ my.result
(case cmd (@ (if-else (ors (my.literal? my.obj)
(.startswith suffix ",")
(hissp.reader..is_lissp_string my.obj)
(my.control-word? my.obj)
(my.module-handle? my.obj)
(my.quotation? my.obj))
(if-else my.arity `(op#getitem ,(next my.iexprs) ,my.obj) my.obj)
(if-else (ors my.arity (not (my.method? my.obj)))
`(,my.obj ,@(i#islice my.iexprs my.arity+1))
`((op#attrgetter ',([#1:] my.obj))
,(next my.iexprs)))))
|/| (progn (.pop my.exprs my.arity) ())
|&| (@ (op#getitem my.exprs my.arity))
|@| (@ (.pop my.exprs my.arity+1))
|>| nil#(.insert my.exprs my.arity my.mark)
|<| (@ (let (x (tuple (i#takewhile X#(op#ne X my.mark) my.iexprs)))
(if-else suffix
`(op#getitem ,(next my.iexprs) x)
x)))
|*| (@ :* (i#islice my.iexprs my.arity) :* (next my.iexprs))
: ()))
(set@ my.result
(._rewrite _macro_ program : :* my.result :* my.iexprs))
my.result)))

.#`(progn ,@(map X#(let (args (get#(slice X) `($#x $#y $#z $#w))
name (.format "{}#" (op#mul X "^")))
`(defmacro ,(hissp..munge name) (,'terms)
',(.format "``{}`` 'synexpand-{X}'.

Creates a lambda of arity {X} containing a `^*#<QzHAT_QzSTAR_QzHASH_>`
(synexpand) applied with terms to a tuple of the parameters.
"
name : X X)
`(lambda ,',args
(^*\# (,,'terms ,@',args)))))
(range 1 5)))

(defmacro _spy (expr file)
`(let ($#e ,expr)
(print (pprint..pformat ',expr : sort_dicts 0)
Expand Down

0 comments on commit 61a5cac

Please sign in to comment.