Next: Break hooks, Previous: Hook functions, Up: Hook functions
In the previous section, we have seen how to extend mixguile
's
functionality through the use of user defined functions. Frequently,
you'll write new functions that improve in some way the workings of a
built-in mixvm
command, following this pattern:
We call the functions executed in step (a) pre-hooks, and those of
step post-hooks of the given command. mixguile
lets you
specify pre- and post-hooks for any mixvm
command using the
mix-add-pre-hook
and mix-add-post-hook
functions, which
take as arguments a symbol naming the command and a function to be
executed before (resp. after) the command. In other words,
mixguile
will execute for you steps (a) and (c) above whenever
you eval (b). The hook functions must take a single argument, which is a
string list of the command's arguments. As an example, let us define the
following hooks for the next
command:
(define next-pre-hook (lambda (arglist) (mix-slog #f))) (define next-post-hook (lambda (arglist) (display "Stopped at line ") (display (mix-src-line-no)) (display ": ") (display (mix-src-line)) (newline) (mix-slog #t)))
In these functions, we are using the function mix-slog
to turn
off the informational messages produced by the virtual machine, since we
are providing our own ones in the post hook function. To install these
hooks, we would write:
(mix-add-pre-hook 'next next-pre-hook) (mix-add-post-hook 'next next-post-hook)
Assuming we have put the above expressions in mixguile
's
initialisation file, we would obtain the following results when
evaluating mix-next
:
guile> (mix-next) MIXAL HELLO WORLD Stopped at line 6: HLT guile>
As a second, more elaborated, example, let's define hooks which print
the address and contents of a cell being modified using smem
. The
hook functions could be something like this:
(define smem-pre-hook (lambda (arglist) (if (eq? (length arglist) 2) (begin (display "Changing address ") (display (car arglist)) (newline) (display "Old contents: ") (display (mix-cell (string->number (car arglist)))) (newline)) (error "Wrong arguments" arglist)))) (define smem-post-hook (lambda (arglist) (if (eq? (length arglist) 2) (begin (display "New contents: ") (display (mix-cell (string->number (car arglist)))) (newline)))))
and we can install them using
(mix-add-pre-hook 'smem smem-pre-hook) (mix-add-post-hook 'smem smem-post-hook)
Aferwards, a sample execution of mix-smem
would look like this:
guile> (mix-smem 2000 100) Changing address 2000 Old contents: 0 New contents: 100 guile>
You can add any number of hooks to a given command. They will be
executed in the same order as they are registered. You can also define
global post (pre) hooks, which will be called before (after) any
mixvm
command is executed. Global hook functions must admit two
arguments, namely, a string naming the invoked command and a string list
of its arguments, and they are installed using the Scheme functions
mix-add-global-pre-hook
and mix-add-global-post-hook
. A
simple example of global hook would be:
guile> (define pre-hook (lambda (cmd args) (display cmd) (display " invoked with arguments ") (display args) (newline))) guile> (mix-add-global-pre-hook pre-hook) ok guile> (mix-pmem 120 125) pmem invoked with arguments (120-125) 0120: + 00 00 00 00 00 (0000000000) 0121: + 00 00 00 00 00 (0000000000) 0122: + 00 00 00 00 00 (0000000000) 0123: + 00 00 00 00 00 (0000000000) 0124: + 00 00 00 00 00 (0000000000) 0125: + 00 00 00 00 00 (0000000000) guile>
Note that if you invoke mixvm
commands within a global hook, its
associated command hooks will be run. Thus, if you have installed both
the next
hooks described earlier and the global hook above,
executing mix-next
will yield the following result:
guile> (mix-next 5) next invoked with arguments (5) slog invoked with arguments (off) MIXAL HELLO WORLD Stopped at line 7: MSG ALF "MIXAL" slog invoked with arguments (on) guile>
Adventurous readers may see the above global hook as the beginning of a command log utility or a macro recorder that saves your commands for replay.