Because the DSL expresses traversals in a natural way in relation to the cursor, it often allows the implementation of tree algorithms to be simple enough that, even as a casual user, you might consider extending Symex to support features you might need. As an illustration, imagine that you are editing some Lisp code. You often find that you need to transform something like this:
(a (b (c (d e))))
… to this:
(a (b (c (d e))))
To perform the above transformation, intuitively, you might say, “go up into the expression, then go forward, then add a newline there, and then keep repeating the same thing until we reach the end.” Indeed, using the Symex modal UI, you can manually implement this, for this particular example, as kl>kl>kl>kl>
.
But you’d like a general command to do this that works in every case, no matter how deep or shallow the expression may be.
You could write a Symex command to do that, using the linguistic forms we learned about.
(symex-define-command my-cascade () (interactive) (symex-eval (symex-traversal (repeat (try (move up) (move forward) (lambda (_computation _result) (newline-and-indent 1)))))))
The important part is within symex-traversal
, and if you squint just a bit, you’ll see that it’s exactly the intuitive algorithm we came up with just now! repeat
, as the name implies, repeats the contained traversal until it fails. try
attempts a sequence of traversals in order, stopping when anything doesn’t work. A move is a single step in any direction. And you can provide any ELisp code (in this case, to add a newline with proper indentation) by entering a lambda
(See Lambdas for more on the unused arguments here). Now just compare that with our intuitive algorithm, reproduced here:
“go up into the expression, then go forward, then add a newline there, and then keep repeating the same thing until we reach the end.”
For the logistical aspects of this implementation, recall that you define a Symex program using symex-traversal
and evaluate it using symex-eval
. Symex commands often need to do some standard things like fix indentation after execution, or set some metadata that may help Emacs treat your command as you expect. Using symex-define-command
instead of defun
takes care of these things for you, but it’s not required. Finally, interactive
is Emacs’s standard way of making the command executable by you via M-x
.