The Mock Lisp (MLisp) programming language provides access to all the Emacs extension facilities. This chapter describes how to use MLisp to extend Emacs by writing private functions or shareable libraries and subsystems.
The syntax of MLisp is based on certain dialects of the full Lisp language. This is a highly structured syntax with few built-in constructs. This simple syntax means that an efficient interpreter can be written, so that executing MLisp code does not use significant CPU overhead.
An MLisp program consists of an expression. Each expression may contain further expressions to be evaluated.
Expressions fall into two categories:
Examples:
(setq left-margin 9) (forward-word) (fetch-database-entry "MLisp-library" "process")
Examples:
24 "abc" left-margin
MLisp names in Emacs are held in two name-spaces: one for function names, and the other for variable names. A name in one name-space is not related to the same name in the other name-space. There is never any confusion about which name-space a particular name belongs in, as this information can always be deduced from the syntactic positioning of the name. Whenever you need to pass the name of a function to another function, you must pass it as a string.
A name can consist of an arbitrary sequence of any characters excluding the MLisp syntax characters (, ) and ;. Names may not start with a digit or a minus sign. Upper-case letters are always distinguished from lowercase letters.
Examples of names:
execute-mlisp-file ~TAGS-replace-string ^K-character the-quick-brown-fox-jumps-over-a-lazy-dog ANAMEWITHCAPITALLETTERS
Comments are introduced in MLisp using the ; character. The comment extends from the semicolon character to the end of the line. During MLisp compilation, all comments are removed.
Constants are represented in MLisp by either writing their value in the MLisp expressions, or by referencing one of the named constants provided by Emacs for special purposes. Named constants are located in the variable name-space along with other named variables. You cannot alter the value of a named constant.
You specify numeric constants using digit characters. An optional leading minus sign may be included to obtain negative values. Note, however, that you cannot specify a leading plus sign. Numeric constants are integers in the range 2,147,483,647 to -2,147,483,648. Overflow is not detected by the MLisp compiler, and merely results in wrap around.
Character constants are converted to their numeric equivalent during MLisp compilation; they are merely a convenient way of specifying the ASCII numeric value for a character.
Character constants are introduced and terminated with the single quote character, and can represent only one ASCII character. During MLisp compilation, the special sequences in Table 1 allow you to specify the control characters of the ASCII character set.
Table 1 MLisp Character Constants
Sequence | ASCII Character |
\n | Linefeed |
\b | Backspace |
\t | Tab |
\r | Return |
\e | Escape |
\' | Quote |
\\ | \ |
\xxx | Octal character xxx |
^X | Control X |
^? | Delete |
\x | character x |
It is best to use the \ sequences for the characters that are available using that mechanism, rather than using the equivalent ^ sequences because the \sequences are more meaningful.
String constants are enclosed in double quote characters and can be up to 800 characters in length. Any ASCII character can be included in the string. An escape mechanism is provided using a scheme similar to that for character constants. The codes are described in Table 2.
Table 2 MLisp String Constants
Sequence | ASCII character |
---|---|
\n | Linefeed |
\b | Backspace |
\t | Tab |
\r | Return |
\e | Escape |
\" | Double quotes |
\\ | \ |
\xxx | Octal character xxx |
\^X | Control X |
\^? | Delete |
\x | Character x |
\(key) | Key sequence for key |
Named key string constant escapes are particularly useful in MLisp expressions that bind keys. Figures ~~~Ref:numkeypadfig~~~,~~~Ref:editkeypadfig~~~ and ~~~Ref:funkeysfig~~~illustrate the escapes for the keys found on VT100-series terminals and terminals or workstations with LK201 keyboards.
Figure: VT100/LK201 Numeric Keypad Key EscapesFIGUREFILE: postscript:docs$src:emacspgnumkeypadfig.psFIGUREFILE: bookreader:docs$src:emacspgnumkeypadfig.fse
Figure: LK201 Editing Keypad Key EscapesFIGUREFILE: postscript:docs$src:emacspgeditkeypadfig.psFIGUREFILE: bookreader:docs$src:emacspgeditkeypadfig.fse
Figure: LK201 Top-Row Function Key EscapesFIGUREFILE: postscript:docs$src:emacspgfunkeysfig.psFIGUREFILE: bookreader:docs$src:emacspgfunkeysfig.fse
A variable is a name which is associated with a value, either a number, mark, string, window-ring or an array. Emacs uses many variables internally, and provides many others which allow the user to customise various Emacs features.
The easiest way to set a variable is to use the setq function. This function requires the name of the variable and the value to be assigned to the variable. Before the variable is set, the value being assigned may be checked so that you cannot set impossible values which might jeopardise other Emacs code. The variable to be set must already exist. You can set the value of a variable interactively using the ESC-x set command.
To fetch the value of a variable, simply reference it by name. You can also display the value of a single variable interactively with the ESC-x print command.
There are five different types of variable:
Numerics | which hold integer numbers in the range 2,147,483,647 to -2,147,483,648; |
Strings | which contain arbitrary length text; |
Markers | which contain a buffer name and positional information; |
Array | which contains up to a 10 dimension array of variables |
Window-rings | which contain a set of windows that make up a screen. |
You can also create arrays with up to 10 dimensions. A single array can contain elements of any of the basic types. Variable length system arrays conform to a convention where element zero contains the number of elements in the array excluding element zero.
When using variables in MLisp programs, the type of the variable is coerced to the type that a particular function expects. For example, if a variable holds a number and is supplied to a function expecting a string, the number is converted to a string when it is needed. When coercion takes place for markers, if a string is required, the value of the variable is the buffer name part; if a numeric is required, the position in the buffer is returned.
No coercion is available for window-rings. The only operation that can be performed on a window-ring is assignment.
There are five different classes of variable as described below:
System Variables
System variables are used to set up a specific option upon which Emacs acts. They either modify the way Emacs presents information, or they contain some specific information. Some examples of system variables include pop-up-windows, which tells Emacs to pop a window up when one is needed, and window-size which tells you the size, in lines, of the currently selected window.
Buffer-Specific Variables
Buffer-specific variables are used to contain information which is private to each buffer. The name of the variable is the same for each buffer, but when its value is fetched or set, a private copy for the currently selected buffer is used. If you attempt to fetch the value of a buffer-specific variable before you have set it, the variable is preset with a default value. Buffer specific variables are created using the declare-buffer-specific function, and their default value is set using setq-default (or ESC-x set-default).
Global Variables
Global variables are used to contain information to be accessed by functions executed at any time. Once created, these variables remain in existence until Emacs exits.
Named Constants
Named constants are used by Emacs to provide users with useful information. Each named constant has a name in the variable name-space and has a read-only value. If you attempt to alter the value of a named constant, Emacs issues an error message.
Local Variables
Local variables are used to contain local information in a block inside an MLisp program. The lifetime of these variables is only while the block in which they are declared is executing. Local variables are declared by nominating them immediately after the block introducer (after progn and function names). For example:
(progn a b c d ... )
The name scope for all variables is everywhere in Emacs, but the lifetime of the storage allocated to the variable depends on the class of variable. For example, once some MLisp has been compiled which declares a local variable, that variable's name is entered into the variable name-space and may be freely accessed. However, if you attempt to access the variable outside the block in which it is declared, no storage will have been allocated for it, and Emacs will issue an error message.
(declare-global name...)
Declares global variables and initialises their default value to zero.
(declare-buffer-specific name...)
Declares buffer-specific variables and initialises their default value to zero.
ESC-x set
Prompts for and sets the value of any variable interactively.
(setq name expression)
Sets the value of any variable in an MLisp program.
ESC-x set-default
Prompts for and sets the default value of a buffer-specific variable interactively.
(setq-default name expression)
Sets the default value of a buffer-specific variable in an MLisp program.
ESC-x print
Displays the current value of a variable in the Mini-buffer.
ESC-x print-default
Displays the default value of a buffer-specific variable in the Mini-buffer. If the variable is not buffer-specific, print-default functions the same way as the print command.
(use-variables-of-buffer buffer expression)
This function provides access to the buffer-specific variables of the buffer named buffer. When expression uses a buffer-specific variable, it will be the instance of the variable from buffer buffer, not from the current buffer. The following example inserts the file name of buffer fred into the current buffer joe:
(switch-to-buffer "joe") (use-variables-of-buffer "fred" (insert-string current-buffer-file-name) )
You create an array by using the array MLisp function, and assign the resulting structure to a variable. The target variable is then coerced into an array.
Once the array has been created, you can use all the functions defined below to manipulate the array contents.
You can finally free up the space allocated to array by assigning one of the basic types to the array variable.
(array low-bound high-bound...)
Creates an array with up to 10 dimensions. The array is initialised to integer zeroes in all elements.
(bounds-of-array array-name)
Analyses an array, and returns another array describing the bounds of the supplied array.
The output array is declared as (array 1 2 0 input-array-dimensions). Element [1,0] contains the number of dimensions of the array. Element [2,0]contains the total size of the array. Other elements contain the lower and upper bounds for each dimension of the array.
(fetch-array array index...)
Retrieves an element from the specified array.
(setq-array array index... value)
Assigns a value to an element of an array.
A function is the object through which Emacs runs programs written in MLisp. A function is defined, then compiled, and may then be run simply by nominating it using the ESC-x command, or by calling it in an MLisp program. MLisp functions may also have key sequences bound to them. In this way, key bindings may be altered in a way suitable for a given application.
Functions are defined using the MLisp defun function using either of the following syntaxes:
(defun (name local... expression...))
This defines a function called name with local variables locals. The function executes expressions each time it is called. The local variables are separated by white-space. Any arguments that need to be passed to the function must be accessed using the arg MLisp function. All the components except name are optional. The result of the function is the result of the last expression executed.
(defun name (arg...) local... expression...)
This defines a function with arguments. The arguments are entered into the variable name-space, and may have optional default expressions. The initialising expressions are executed just before the function in invoked. The result of the function is the value of the last expression executed in the expression list.
This section describes all the block structuring functions in MLisp. All the block structuring functions introduce a block which may contain local variable declarations. The value of most blocks is the value of the last expression executed in the block.
(progn local... expression...)
Introduces a basic block.
(save-excursion local... expression...)
Introduces a block, and saves the current environment for restoration after the last expression has been executed. The items saved are the current position of dot, the current buffer name, the current mark (if set), the last specified search string, and the visibility of the current buffer on the current screen.
(save-window-excursion local... expression...)
Introduces a block, and saves the current environment for restoration after the last expression in the block has been executed. The items saved are the screen state, the current buffer, the current position of dot, the current mark (if set) and the last search string.
After the expression has been executed, the windows that were visible on the screen when the command was started will be restored in the correct order with each window's dot in the correct location.
(save-restriction local... expression...)
Introduces a block, and saves the current environment for restoration after the last expression has been executed. The items saved are the current buffer, the current position of dot, the current mark (if set), the current narrowing, the last search string, and the visibility of the current buffer on the screen.
(error-occurred local... expression...)
Introduces a block, and evaluates expressions until an error occurs. If no error occurs, then the value of the block is 0, otherwise, the value of the block is 1. When an error occurs, the text of the error message is available in the system variable error-message, but is not displayed in the Mini-buffer.
This section describes the functions provided to control the flow of execution of MLisp statements.
(while test-expression expression...)
This function implements a pre-tested while loop statement. The test-expression is evaluated, and if non-zero, the expressions are executed. When the expressions have been executed, control returns to the test expression. The test expression is re-evaluated at each iteration. The result of the expression is the result of the test expression at exit.
(if test-expression true-expression false-expression)
This function implements an if-then-else statement common in most high level languages. test-expression is evaluated, and if non-zero, true-expression is evaluated, otherwise false-expression is evaluated.
A multi-way if statement can be constructed by repeating test-expression and true-expression in place of the false expression. The last test in the list must have a false-expression. For example, for the variable a, the following prints out the power of ten if a is less than 1000:
(message (if (< a 0) "a is too small" (< a 10) "Zero" (< a 100) "One" (< a 1000) "Two" "a is too large" ) )
Emacs has numerous operator functions specifically designed for use in MLisp programs.
There is no distinction between an operator function and an ordinary function as far as the syntax of calling the operators is concerned. They are called operator functions merely to distinguish them from functions whose values are of no interest to the caller.
The arithmetic operator functions are shown in Table 3.
Table 3 Arithmetic Operator Functions
+ | Addition |
-- | Subtraction |
/ | Division |
* | Multiplication |
! | Complimentation |
& | And |
| | Inclusive-or |
^ | Exclusive-or |
<< | Left shift |
>> | Right shift |
= | Equality |
!= | Non-equality |
< | Less than |
> | Greater than |
<= | Less than or equal |
>= | Greater than or equal |
c= | Character equal |
All of these functions can be used with one or more arguments. Arguments are used singly or in pairs to form a running total. The only unary operator is ! (complimentation).
The string operator functions include:
(concat expression...)
This function returns the concatenation of all of expressions as a single string. The expressions are coerced into strings before the concatenation takes place.
(substr str pos n)
This function returns the substring of str starting at character pos of length n. If pos is negative, the length of the string is added to it before it is used.
(length expression)
This function returns the string length of expression. If the expression yields a numeric or mark value, it is coerced into a string.
(region-to-string)
This function returns the region in the current buffer as a string value.
(case-string-capitalize string)
This function converts the first letter of each word in string to upper-case and all other letters to lowercase and returns the result as a string.
(case-string-invert string)
This function inverts the case of each letter in string and returns the result as a string.
(case-string-upper string)
This function changes the case of each letter in string to upper-case and returns the result as a string.
(case-string-lower string)
This function changes the case of each letter in string to lowercase and returns the result as a string.
The following list includes other useful operator functions:
(dot)
dot returns a marker for the current position of dot in the current buffer.
(mark)
mark returns a marker for the current position of the current buffer's mark if the mark is set. An error is generated if no mark is set.
(preceding-char)
preceding-char returns the numeric value of the character to the left of dot in the current buffer. If dot is located at the beginning of the buffer, 0 is returned.
(following-char)
following-char returns the numeric value of the character to the right of dot in the current buffer. If dot is located at the end of the buffer, 0 is returned.
Emacs contains a set of functions and variables which are primarily for use when programming in MLisp. Some of the functions actually check when they are called that they have not been executed interactively.
The following predicates are provided to test certain conditions in MLisp programs:
(eolp)
eolp returns true if dot is currently at the end of a line in the current buffer. Otherwise, it returns false.
(eobp)
eobp returns true if dot is at the end of the current buffer. Otherwise, it returns false.
(bolp)
bolp returns true if dot is currently at the beginning of a line in the current buffer. Otherwise, it returns false.
(bobp)
bobp returns true if dot is at the beginning of the current buffer. Otherwise, it returns false.
(dot-is-visible)
dot-is-visible returns true if the current location of dot is being displayed in a window on the screen. Otherwise, it returns false.
(interactive)
interactive returns true if the currently executing MLisp function was invoked either by using ESC-x, or as a result of a key binding. Otherwise, it returns false.
(is-bound name...)
is-bound returns true if all the specified variables currently bound to storage. Otherwise, it returns false.
Emacs has two argument systems: prefix arguments, which are always numerics; and post-fix arguments which may be numerics, strings, markers, arrays or window-rings. Prefix arguments are generally specified interactively from the keyboard using the ^U command, but may also be manipulated from within an MLisp program by using the following functions and variables:
(provide-prefix-argument prefix expression)
This function applies the numeric prefix argument prefix to the expression provided. The result of the function is the result of the execution of the expression. It is generally more efficient to use provide-prefix-argument to repeat a command many times than to use a while loop, or by repetition of the desired command. However, the command to be executed must interpret a prefix argument as a repetition count in order for this to work properly.
(prefix-argument-loop expression...)
prefix-argument-loop causes the expressions provided to be executed prefix argument number of times. If no prefix argument was provided to the MLisp function that calls prefix-argument-loop, the expressions will only be executed once. The result of the function is the result of the last expression in the expression list to be executed.
(return-prefix-argument expression)
This function sets up the prefix argument for the next function to be executed. The value of the function is the value of the expression returned as the prefix argument.
If you wish to provide a prefix argument for the next function to run after the current function has finished, return-prefix-argument must be the last expression to be executed.
(prefix-argument)
This variable contains the value of the prefix argument supplied to the current MLisp function. If no prefix argument was supplied, then its value is 1. Both positive and negative prefix arguments may be supplied.
prefix-argument-provided
This variable is true if an MLisp function has been called with a prefix argument, otherwise it is false. This variable is provided because there is no way to tell if a prefix argument has been provided by merely examining its value.
(arg num prompt)
This function causes the evaluation of the numth postfix argument provided to the function. If the required argument is an expression, then it will be re-evaluated every time arg accesses it. The left-most argument in a function call is argument number 1.
If the desired argument was not provided in the call, prompt is used as a terminal prompt string to read in the argument from the user. If prompt is omitted, this feature is disabled, and an error message is generated.
(nargs)
This function returns the number of arguments supplied to the called function. Arguments that are prompted for are not included in this count.
A number of functions exist to enable MLisp programmers to obtain input from the user. These functions generally take a string argument which is used as a prompt in the Mini-buffer. Specific functions may enable name completion.
The input functions are:
(expand-from-string-table prompt word-list-string)
This function provides access to the Emacs input expansion mechanism. The function has two parameters: the first is a prompt, the second is a string that contains a space-separated list of words from which the user can select a choice. The result of the function is the selected word. expand-from-string-table will only allow one of the words in the list to be returned. The following example, causes a Command: prompt to appear in the Mini-buffer; the user must then enter one of the four words from the supplied list:
(expand-from-string-table "Command: " "exit" "read" "write" "quit")
(get-tty-character)
This function waits for a single key to be pressed by the user. No prompt is available. The character that the user presses is returned as the value of the function. No keymaps are used to interpret the typed character.
(get-tty-command prompt)
get-tty-command issues the prompt in the Mini-buffer and then reads in a string. Function name completion is enabled during this operation, and the only valid input is an existing function name. The value of this function is a string containing the name of the function selected.
(get-tty-file prompt)
get-tty-file issues the prompt supplied in the Mini-buffer and then reads in a string. File name completion is enabled during this operation, although any string is valid when a Return is pressed. Multiple versions of the same file are ignored during completion. The value of this function is a string containing the name of the file selected.
(get-tty-string prompt)
This function issues the prompt in the Mini-buffer, then reads in a string from the user. This string is returned as the function's value.
(get-tty-variable prompt)
get-tty-variable issues the prompt in the Mini-buffer and then reads in the name of a variable. Variable name completion is enabled during this operation. The value of the function is a string containing the variable name selected.
(get-tty-buffer prompt)
This function issues the prompt and then obtains the name of a buffer using buffer name completion. The value of the function is a string containing the buffer name selected.
(process-keys keymap)
This function reads one key sequence from the keyboard by using the supplied keymap. The function selected by the key sequence is executed, and the result is returned as process-key's value.
Two functions exist for displaying text. Both functions display the text in the Mini-buffer, and can take any number of arguments. The arguments are coerced into strings and concatenated in the order in which they appear as arguments.
(message string...)
Displays the concatenated strings in the Mini-buffer the next time the screen is updated.
(error-message string...)
Displays the concatenated strings in the Mini-buffer and declares an error. No further statements of an MLisp program will be executed, and the keyboard processor will resume operation (unless error-message has been issued from inside an error-occurred function).
(sit-for length)
This function causes the display to be updated, and executes a pause for length tenths of a second. The pause may be interrupted by the user pressing a key.
This function is useful when displaying status information to the user. For example, if a function takes some time to execute, it may be helpful to indicate what the function is currently doing. An argument of zero to sit-for will update the screen, but will not pause Emacs processing.
Once you have written some MLisp, the code must be compiled before it can be executed. There are several ways to compile MLisp code:
When the file has been opened, all the MLisp expressions contained in the file are read in, compiled, and executed.
execute-mlisp-line can also be used from MLisp programs to dynamically compile and execute a string. When called non-interactively, a single string argument can be specified. This string is compiled and executed as above, and the result returned as the result of the execute-mlisp-line function.
A considerable number of the functions in Emacs reside in libraries. A library function is not accessible unless the library that contains it is loaded. A number of libraries are provided with Emacs, and can be loaded automatically or on request to make their functions available.
To load a library, use execute-mlisp-file. Emacs loads the library by first looking in your own directory for the library file (or a directory you specify), then in the Emacs directory, then in the MLisp-library database search-list. Once the library has been loaded, all the functions defined in the library are then available for use.
For example, if you load the AREA library, you can then use the delete-area function to delete an area of the screen. delete-area is defined in the AREA library.
In addition to making functions accessible to ESC-x, the library may bind some functions to key sequences. This is done by the library loading another file called LIBRARY-NAME.KEY, where LIBRARY-NAME is the name of the library being loaded.
Some libraries are loaded automatically in the course of executing certain functions. You will not normally notice this. For example, the PROCESS library is automatically loaded when you use the shell function for the first time. This facility is known as autoloading. Autoloading is used to make library functions available without you having to know how to load the library. Autoloading also saves space in Emacs by loading libraries only when you need them.
Autoloading works by simply calling execute-mlisp-file on the required library. Autoloading is set up using the autoload function. For example, if you have a function named box-it which is defined in the file BOXIT.ML, then the command:
(autoload "box-it" "boxit.ml")
will define the box-it function, but will not actually load the definition from BOXIT.ML until you execute the box-it function.
Emacs provides a powerful debugging facility to help you develop your MLisp programs. This section describes the supplied MLisp debugger and the tools that Emacs provides to support the development of new debuggers.
The DEBUG package is a powerful MLisp source-line debugger, providing the MLisp programmer with tracing, breakpointing, error trapping and stack-dumping facilities.
To start DEBUG, load the DEBUG library. Each time you want to enter DEBUG mode, use the ESC-^D command (or execute the ESC-x debug command). The debug function loads up the breakpoint, error and trace handlers, binds debug commands to keys and pops up the DEBUG windows. Source code and other information displayed by DEBUG will appear in these windows.
The following commands are available in the DEBUG window:
b (set breakpoint)
Sets a breakpoint on the specified function. When this function is executed after the breakpoint has been set, it will cause DEBUG to regain control, and DEBUG will display the decompiled source showing the call to the function.
B (remove breakpoint)
Clears the breakpoint flag for the specified function so that it will no longer cause a breakpoint when executed.
c (show calls)
Displays the current call stack in the DEBUG window.
. or KP5 (display current source)
Displays the current source line, in context, in the Debug window.
e (interrupt on error)
Causes DEBUG to trap error reports and display them and the function that generated them. Errors are not trapped by default.
E (kill error trapping)
Disables error-trapping.
g or KP, (go)
Continues the execution of a program without interference from DEBUG. The only way DEBUG will regain control is at a breakpoint or when an error is detected and error-trapping is enabled.
Use this function when you have finished examining execution at one point in your program, and you wish to continue the program.
h or ? or Help (help)
Displays help on DEBUG commands.
l (list breakpoints)
Lists in the DEBUG window all functions which have their breakpoint flag set.
o or KP0 (step over)
Executes the next MLisp expression and then stops in DEBUG afterwards. However, if the expression is a function call, DEBUG executes all of the expressions in the called function and any functions it calls.
p (print)
Prints the contents of a variable.
q (quit)
Exits DEBUG. The DEBUG windows are removed and all variables controlled by DEBUG are reset. Breakpoints remain intact, but will not cause DEBUG to be run. To restart debugging, use the ESC-^D command.
s (step)
Executes the next MLisp expression.
t (set trace mode)
Enables trace-mode. During trace-mode, every MLisp expression that is executed will be displayed in the DEBUG windows for debug-sit-for tenths of a second. Execution will continue until all MLisp expression have been executed.
T (Unset trace mode)
Unsets trace-mode.
v (View last expression)
Prints the value of the last executed expression.
DEBUG never displays debug information about any of the DEBUG functions or MLisp functions that are called while in the DEBUG window. This stops DEBUG from confusing you.
This section describes the components which can be used to build MLisp tracing and debugging packages.
Four facilities are provided with Emacs for debugging programs written in MLisp: breakpoints, error-trapping, tracing and stack-trace generation.
Each function within Emacs can have a breakpoint applied to it. If, during the course of executing functions, Emacs attempts to execute a function which has a breakpoint, it calls the breakpoint function specified in the breakpoint-hook variable.
Breakpoints are set for a function using the ESC-x breakpoint command. This command asks for the name of a function and the value to which the function's breakpoint flag should be set. The execution of a function causes a breakpoint if the function's breakpoint flag is set and if the variable breakpoint-hook contains the name of an Emacs function.
The breakpoint function is called just before the function that caused the breakpoint to occur is called.
decompile-current-line can be used to display the environment from which the breakpointing function was called.
If an error occurs during the execution of MLisp code, the normal action is to display the error message in the Mini-buffer, and to abort the execution of all macros and MLisp code.
However, if the variable error-hook contains the name of a function, then this function is called instead. This means that a debugger can gain control when an error occurs. Further, during the execution of the error function, the error message that should have been displayed is available to the debugger in the variable error-message.
Error trapping does not occur for errors that happen in an error-occurred block.
Tracing of MLisp programs is controlled with three variables:
· trace-into
· trace-mode
· trace-hook
When trace-mode is set, the function whose name is contained in trace-hook is called before each MLisp statement is executed. The decompiled form of the statement about to be executed is available using the decompile-current-line function.
On MLisp function calls, trace-into controls whether tracing continues into the called code. If trace-into is true, tracing continues into functions. Otherwise, tracing will be suspended until the inner function has completed execution.
The generation of an MLisp stack trace can be automatic when an error is detected, or can be generated by the user at any time from an MLisp function.
The variable stack-trace-on-error controls the generation of stack-traces when an error is detected. If set to true, when an error is generated, a buffer called Stack-trace is created, and the current MLisp stack is inserted into the buffer. No action is taken inside an error-occurred block. The first line of the stack trace contains the error message that caused the stack-trace to occur. The second and subsequent lines contain the decompiled expressions being executed when the error was detected. An end-of-stack marker is located at the end of the buffer.
The variable stack-maximum-depth limits the call depth of the running MLisp code.
For example, if the following function is executed with a parameter of 1:
(defun x (a) (if (> a 3) (error-message "Too deep") (x (+ a 1)) ) )
then the buffer Stack-trace would contain:
Message: Too deep Executing: (error-message "Too deep") (x (+ a 1)) (x (+ a 1)) (x (+ a 1)) (x 1) --- bottom of stack ---
The function dump-stack-trace can be used to generate a stack-trace at any time. The stack-trace will be located in buffer Stack-trace, which will be popped onto the screen. The stack-trace format is the same as that displayed for stack-traced errors, except that there will never be a Message: line.