Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adding an at or as command. #70

Closed
2 of 7 tasks
okamsn opened this issue Apr 19, 2021 · 1 comment · Fixed by #87
Closed
2 of 7 tasks

Adding an at or as command. #70

okamsn opened this issue Apr 19, 2021 · 1 comment · Fixed by #87
Labels
enhancement New feature or request

Comments

@okamsn
Copy link
Owner

okamsn commented Apr 19, 2021

This command affects those which accumulate values or which would exit a loop.

This is based on the Iterate's in clause:

(iter outer (for i below (array-dimension ar 0))
             (iter (for j below (array-dimension ar 1))
                   (in outer (collect (aref ar i j)))))

In Loopy, we would want this to look something like

(loopy-iter outer
            (for list i (number-sequence 0 (array-dimension ar 0)))
            (loopy (list j (number-sequence 0 (array-dimension ar 1)))
                   (as outer (collect (aref ar i j)))))

The current way of achieving the above is to use the sub-loop command:

(loopy (list i (number-sequence 0 (array-dimension ar 0)))
       (sub-loop (list j (number-sequence 0 (array-dimension ar 1)))
                 (collect (aref ar i j))))

This works well for accumulation commands, because sub-loop cannot have their
own return values. However, sub-loops also have a generated name, which affects
commands which exit the loop, like leave and return.

An easy way to deal with this situation is to have at set loopy--loop-name
in a let-binding. However, this doesn't help with accumulation commands,
which have no reference to the loop they are in. Therefore, we need a way to
pass instructions back up to higher levels in the parsing process and to
identify which loop the instructions belong to.

One way to identify the loop to which an instruction belongs is to change
instructions from cons pairs to proper lists of at least 3 elements. This
third element would be a symbol identifying the loop. Lists with no third
symbol would be understood to belong to the current loop. In this scheme, the
at command would be able to add the third element itself, without us needing
to change any of the existing command parsers.

Such an approach would not work with a loopy macro inside in a do command,
but that can be an acceptable limitation now that we have loopy-iter. It
might also be worth adding a loopy loop command, which could allow for special
macro arguments in sub-loops.

TODO List

  • Change instruction format to a proper list. Tedious, but not difficult.
    The tests should quickly capture any problems caused by this.

  • Change the cl-tagbody tags to be based on the loop name. Maybe
    introduce let-bound variables to store these tags.

    • Along with above, add a leave-from command.
  • Add an at command.

    • Sets loopy--loop-name and loopy--in-sub-level.
    • Adds the loop name as the third element in instructions.
    • Can take multiple expressions.
    • Maybe if first argument not symbol, default to loop name nil?
  • Maybe add a loopy loop command?

  • Maybe change in from an alias of list to an alias of at, to be
    consistent with Iterate?

  • Changes needed for parsing

    • There might be some for how loopy-iter processes instructions.

    • loopy-iter calls macroexpand-all on its arguments, which won't work if
      we're wrapping a loopy-iter call with an at command.

      • We might need to check of any wrapping of loopy-iter or loopy in the
        tree, operate on it, and then return to the top-level and expand any
        macros.

Examples

;; => (1 2 3)
(loopy outer
       (list i '((1 2 3) (4 5 6)))
       (sub-loop (list j i)
                 (at outer
                     (if (= j 4)
                         (leave)
                       (collect j)))))

;; Same as above, due to `sub-loop' not having return values.
(loopy outer
       (list i '((1 2 3) (4 5 6)))
       (sub-loop (list j i)
                 (if (= j 4)
                     (at outer (leave))
                   (collect j))))

;; => (1 2 3)
(loopy-iter outer
            (for list i '((1 2 3) (4 5 6)))
            (loopy-iter (for list j i)
                        (at outer
                            (if (= j 4)
                                (leave)
                              (collect j)))))
@okamsn
Copy link
Owner Author

okamsn commented Aug 30, 2021

We're now working on this in the at-cmd branch. Depending on how
macroexpand-all works with variables let-bound during this expansion, this
might be simpler to implement than previously thought.

In this change, it makes sense to remove the current form of the sub-loop
command, since it was a work-around to not having an at command. Instead, it
should be a call to the loopy macro, which the macro will now to expand while
processing commands.

That would behave differently than arguments to the do command, which are
inserted literally into the loop body.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

Successfully merging a pull request may close this issue.

1 participant