diff options
author | Kaz Kylheku <kaz@kylheku.com> | 2016-11-18 06:15:40 -0800 |
---|---|---|
committer | Kaz Kylheku <kaz@kylheku.com> | 2016-11-18 06:15:40 -0800 |
commit | 0bfa413c5c5c61d48e94a46e48e52fed46c5860a (patch) | |
tree | 04b37db4de76140529109fb2053b4f5cc62a17bd /txr.1 | |
parent | dc84927c791873508f473f1d5679550882f86e91 (diff) | |
download | txr-0bfa413c5c5c61d48e94a46e48e52fed46c5860a.tar.gz txr-0bfa413c5c5c61d48e94a46e48e52fed46c5860a.tar.bz2 txr-0bfa413c5c5c61d48e94a46e48e52fed46c5860a.zip |
Adding a tagbody macro to the language.
This is a "disciplined goto" feature of Common Lisp.
This uses a new sys:switch operator, which could
also be used for optimizing case and cond forms.
* eval.c (switch_s): New symbol variable.
(op_switch, expand_list_of_form_lists, expand_switch):
New static functions.
(do_expand): Hook in the expansion of the sys:switch
operator.
(eval_init): Initialize switch_s special variable to
sys:switch symbol. Register sys:switch special op.
* lisplib.c (tagbody_set_entries, tagbody_instantiate): New
static functions.
(lisplib_init): Register autoloading of tagbody module
via new functions.
* share/txr/stdlib/tagbody.tl: New file.
* txr.1: Documented.
Diffstat (limited to 'txr.1')
-rw-r--r-- | txr.1 | 166 |
1 files changed, 166 insertions, 0 deletions
@@ -14546,6 +14546,172 @@ arguments to which do not simply quote a symbol have no equivalent in .codn return-from . +.coNP Macros @ tagbody and @ go +.synb +.mets (tagbody >> { form | << label }*) +.mets (go << label ) +.syne +.desc +The +.code tagbody +macro provides a form of the "go to" control construct. The arguments of a +.code tagbody +form are a mixture of zero or more forms and +.IR "go labels" . +The latter consist of those arguments which are symbols, integers or +characters. Labels are not considered by +.code tagbody +and +.code go +to be forms, and are not subject to macro expansion or evaluation. + +The +.code go +macro is available inside +.codn tagbody . +It is erroneous for a +.code go +form to occurs outside of a +.codn tagbody . +This situation is diagnosed by global macro called +.codn go , +which unconditionally throws an error. + +In the absence of invocations of +.code go +or other control transfers, the +.code tagbody +macro evaluates each +.meta form +in left to right order. The go labels are ignored. +After the last +.meta form +is evaluated, the +.code tagbody +form terminates, and yields +.codn nil . + +Any +.meta form +itself, or else one of its sub-forms, may be the form +.cblk +.meti (go << label ) +.cble +where +.meta label +matches one of the go labels of a surrounding +.codn tagbody . +When this +.code go +form is evaluated, then the evaluation of +.meta form +is immediately abandoned, and control transfers to the specified +label. The forms are then evaluated in left-to-right order starting +with the form immediately after that label. If the label is not +followed by any forms, then the +.code tagbody +terminates. If +.meta label +doesn't match to any label in any surrounding +.codn tagbody , +the +.code go +form is erroneous. + +The abandonment of a +.meta form +by invocation of +.code go +is a dynamic transfer. All necessary unwinding inside +.meta form +takes place. + +The go labels are lexically scoped, but dynamically bound. Their scope +being lexical means that the labels are not visible to forms which are not +enclosed within the +.codn tagbody , +even if their evaluation is invoked from that +.codn tagbody . +The dynamic binding means that the labels of a +.code tagbody +form are established when it begins evaluating, and removed when +that form terminates. Once a label is removed, it is not available +to be the target of a +.code go +control transfer, even if that +.code go +form has the label in its lexical scope. Such an attempted transfer +is erroneous. + +It is permitted for +.code tagbody +forms to nest arbitrarily. The labels of an inner +.code tagbody +are not visible to an outer +.codn tagbody . +However, the reverse is true: a +.code go +form in an inner +.code tagbody +may branch to a label in an outer +.codn tagbody , +in which case the entire inner +.code tagbody +terminates. + +In cases where the same objects are used as labels +by an inner and outer +.codn tagbody , +the inner labels shadow the outer labels. + +.TP* "Dialect Note:" + +ANSI Common Lisp +.code tagbody +supports only symbols and integers as labels (which are called "go tags"); +characters are not supported. + +.TP* Examples: +.cblk + ;; print the numbers 1 to 10 + (let ((i 0)) + (tagbody + (go skip) ;; forward goto skips 0 + again + (prinl i) + skip + (when (<= (inc i) 10) + (go again)))) + + ;; Example of erroneous usage: by the time func is invoked + ;; by (call func) the tagbody has already terminated. The + ;; lambda body can still "see" the label, but it doesn't + ;; have a binding. + (let (func) + (tagbody + (set func (lambda () (go label))) + (go out) + label + (prinl 'never-reached) + out) + (call func)) + + ;; Example of unwinding when the unwind-protect + ;; form is abandoned by (go out). Output is: + ;; reached + ;; cleanup + ;; out + (tagbody + (unwind-protect + (progn + (prinl 'reached) + (go out) + (prinl 'notreached)) + (prinl 'cleanup)) + out + (prinl 'out)) +.cble + .SS* Evaluation .coNP Function @ eval |