Next: , Previous: Hook functions, Up: Hook functions


3.4.4.1 Command hooks

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:

  1. Prepare the command execution
  2. Execute the desired command
  3. Perform post execution operations

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.