{Begin SubSec CLISP Operation}
{Title CLISP Operation}
{Text

{index *BEGIN* CLISP operation}

CLISP is a part of the basic Interlisp system.  Without any special preparations, the user can include CLISP constructs in programs, or type them in directly for evaluation (in {fn EVAL} or {fn APPLY} format), then, when the "error" occurrs, and DWIM is called, it will destructively transform the CLISP to the equivalent Interlisp expression and evaluate the Interlisp expression.  CLISP transformations, like all DWIM corrections, are undoable.  User approval is not requested, and no message is printed.  Note that this entire discussion also applies to CLISP transformation initiated by calls to DWIM from {index DWIMIFY FN}{fn DWIMIFY}.


However, if a CLISP construct contains an error, an appropriate diagnostic is generated, and the form is left unchanged.  For example, if the user writes {lisp (LIST X+Y*)}, the error diagnostic {lisp MISSING OPERAND AT X+Y* IN (LIST X+Y*)}{index MISSING OPERAND (DWIM error message)} would be generated.  Similarly, if the user writes {lisp (LAST+EL X)}, CLISP knows that {lisp ((IPLUS LAST EL) X)} is not a valid Interlisp expression, so the error diagnostic {lisp MISSING OPERATOR IN (LAST+EL X)}{index MISSING OPERATOR (CLISP error message)} is generated.  (For example, the user might have meant to say {lisp (LAST+EL*X)}.)  Note that if {lisp LAST+EL} were the name of a defined function, CLISP would never see this form.


Since the bad CLISP transformation might not be CLISP at all, for example, it might be a misspelling of a user function or variable, DWIM holds all CLISP error messages until after trying other corrections.  If one of these succeeds, the CLISP message is discarded.  Otherwise, if all fail, the message is printed (but no change is made).    For example, suppose the user types {lisp (R/PLACA X Y)}.  CLISP generates a diagnostic, since {lisp ((IQUOTIENT R PLACA) X Y)} is obviously not right.  However, since {lisp R/PLACA} spelling corrects to {lisp /RPLACA}, this diagnostic is never printed.

Note:  CLISP error messages are not printed on type-in.  For example, typing {lisp X+*Y} will just produce a {lisp U.B.A. X+*Y} message.


If a CLISP infix construct is well formed from a syntactic standpoint, but one or both of its operands are atomic and not bound, it is possible that either the operand is misspelled, e.g., the user wrote {lisp X+YY} for {lisp X+Y}, or that a CLISP transformation operation was not intended at all, but that the entire expression is a misspelling.  For the purpose of {fn DWIMIFY}ing, "not bound" means no top level value, not on list of bound variables built up by {fn DWIMIFY} during its analysis of the expression, and not on {index NOFIXVARSLST Var}{var NOFIXVARSLST}, i.e., not previously seen.


For example, if the user has a variable named {lisp LAST-EL}, and writes {lisp (LIST LAST-ELL)}.  Therefore, CLISP computes, but does not actually perform, the indicated infix transformation.  DWIM then continues, and if it is able to make another correction, does so, and ignores the CLISP interpretation.  For example, with {lisp LAST-ELL}, the transformation {lisp LAST-ELL -> LAST-EL} would be found.


If no other transformation is found, and DWIM is about to interpret a construct as CLISP for which one of the operands is not bound, DWIM will ask the user whether CLISP was intended, in this case by printing {index TREAT AS CLISP ? (Printed by DWIM)}{lisp LAST-ELL TREAT AS CLISP ?}.

Note:  If more than one infix operator was involved in the CLISP construct, e.g., {lisp X+Y+Z}, or the operation was an assignment to a variable already noticed, or {index TREATASCLISPFLG Var}{var TREATASCLISPFLG} is {lisp T} (initially {lisp NIL}), the user will simply be informed of the correction, e.g., {lisp X+Y+Z TREATED AS CLISP}.{index TREATED AS CLISP (Printed by DWIM)}  Otherwise, even if DWIM was enabled in {index TRUSTING  (DWIM mode)}{lisp TRUSTING} mode, the user will be asked to approve the correction.


The same sort of procedure is followed with 8 and 9 errors.  For example, suppose the user writes {lisp FOO8*X} where {lisp FOO8} is not bound.  The CLISP transformation is noted, and DWIM proceeds.  It next asks the user to approve {lisp FOO8*X -> FOO ( *X}.  For example, this would make sense if the user has (or plans to define) a function named {lisp *X}.  If he refuses, the user is asked whether {lisp FOO8*X} is to be treated as CLISP.  Similarly, if {lisp FOO8} were the name of a variable, and the user writes {lisp FOOO8*X}, he will first be asked to approve {lisp FOOO8*X -> FOOO ( XX}, and if he refuses, then be offered the {lisp FOOO8 -> FOO8} correction.  The 8-9 transformation is tried before spelling correction since it is empirically more likely that an unbound atom or undefined function containing an 8 or a 9 is a parenthesis error, rather than a spelling error.


CLISP also contains provision for correcting misspellings of infix operators (other than single characters), {lisp IF} words, and i.s. operators.  This is implemented in such a way that the user who does not misspell them is not penalized.  For example, if the user writes {lisp IF N=0 THEN 1 ELSSE N*(FACT N-1)} CLISP does {it not} operate by checking each word to see if it is a misspelling of {lisp IF}, {lisp THEN}, {lisp ELSE}, or {lisp ELSEIF}, since this would seriously degrade CLISP's performance on {it all} {lisp IF} statements.  Instead, CLISP assumes that all of the {lisp IF} words are spelled correctly, and transforms the expression to {lisp (COND ((ZEROP N) 1 ELSSE N*(FACT N-1)))}.  Later, after DWIM cannot find any other interpretation for {lisp ELSSE}, and using the fact that this atom originally appeared in an IF statement, DWIM attempts spelling correction, using {lisp (IF THEN ELSE ELSEIF)} for a spelling list.  When this is successful, DWIM "fails" all the way back to the original
{lisp IF} statement, changes {lisp ELSSE} to {lisp ELSE}, and starts over.  Misspellings of {lisp AND}, {lisp OR}, {lisp LT}, {lisp GT}, etc. are handled similarly.


CLISP also contains many Do-What-I-Mean features besides spelling corrections.  For example, the form {lisp (LIST +X Y)} would generate a {lisp MISSING OPERATOR} error.  However, {lisp (LIST -X Y)} makes sense, if the minus is unary, so DWIM offers this interpretation to the user.  Another common error, especially for new users, is to write {lisp (LIST X*FOO(Y))} or {lisp (LIST X*FOO Y)}, where {lisp FOO} is the name of a function, instead of {lisp (LIST X*(FOO Y))}.  Therefore, whenever an operand that is not bound is also the name of a function (or corrects to one), the above interpretations are offered.

{index *END* CLISP operation}

}{End SubSec CLISP Operation}



{Begin SubSec CLISP Translations}
{Title CLISP Translations}
{Text

{index *PRIMARY* Translations in CLISP}


The translation of CLISP character operators and the CLISP word {lisp IF} are handled by {it replacing} the CLISP expression with the corresponding Interlisp expression, and discarding the original CLISP.  This is done because (1) the CLISP expression is easily recomputable (by {fn CLISPIFY}) and (2) the Interlisp expressions are simple and straightforward.  Another reason for discarding the original CLISP is that it may contain errors that were corrected in the course of translation (e.g., {lisp FOO←FOOO:1}, {lisp N*8FOO X)}, etc.).  If the original CLISP were retained, either the user would have to go back and fix these errors by hand, thereby negating the advantage of having DWIM perform these corrections, or else DWIM would have to keep correcting these errors over and over.


Note that {fn CLISPIFY} is sufficiently fast that it is practical for the user to configure his Interlisp system so that all expressions are automatically {fn CLISPIFY}ed immediately before they are presented to him.  For example, he can define an edit macro to use in place of {lisp P} which calls {fn CLISPIFY} on the current expression before printing it.  Similarly, he can inform {fn PRETTYPRINT} to call {fn CLISPIFY} on each expression before printing it, etc.


Where (1) or (2) are not the case, e.g., with iterative statements, pattern matches, record expressions, etc. the original CLISP {it is} retained (or a slightly modified version thereof), and the translation is stored elsewhere (by the function {fn CLISPTRAN}, {PageRef Fn CLISPTRAN}), usually in the hash array {index CLISPARRAY Var}{var CLISPARRAY}.  The interpreter automatically checks this array when given a form {fn CAR} of which is not a function.  Similarly, the compiler performs a {index GETHASH FN}{fn GETHASH} when given a form it does not recognize to see if it has a translation, which is then compiled instead of the form.  Whenever the user {it changes} a CLISP expresson by editing it, the editor automatically deletes its translation (if one exists), so that the next time it is evaluated or dwimified, the expression will be retranslated (if the value of {var CLISPRETRANFLG}{index CLISPRETRANFLG Var} is {lisp T}, {fn DWIMIFY} will also (re)translate any expressions which have translations stored remotely, see {PageRef Var CLISPRETRANFLG}).  The function {fn PPT}{index PPT FN} and the edit commands {index PPT EditCom}{editcom PPT} and {index CLISP: EditCom}{editcom CLISP:} are available for examining translations ({PageRef EditCom CLISP:}).


{Begin comment flushed}
broken in Intermezzo release, quietly dropped
If {index PRETTYTRANFLG Var}{var PRETTYTRANFLG} is {lisp T}, {fn PRETTYPRINT} will print the translations instead of the corresponding CLISP expression (see {PageRef Var PRETTYTRANFLG}).  This can be used for exporting programs to systems that do not provide CLISP, and to examine translations for debugging purposes.
{End comment flushed}


{index CLISP (as CAR of form)}

The user can also indicate that he wants the original CLISP retained by embedding it in an expression of the form {lisp (CLISP . {arg CLISP-EXPRESSION})}, e.g., {lisp (CLISP X:5:3)} or {lisp (CLISP <A B C ! D>)}.  In such cases, the translation will be stored remotely as described above.  Furthermore, such expressions will be treated as CLISP even if infix and prefix transformations have been disabled by setting {var CLISPFLG} to {lisp NIL} ({PageRef Var CLISPFLG}).  In other words, the user can instruct the system to interpret as CLISP infix or prefix constructs only those expressions that are specifically flagged as such.  The user can also include CLISP declarations{index CLISP declarations} by writing {lisp (CLISP {arg DECLARATIONS} . {arg FORM})}, e.g., {lisp (CLISP (CLISP: FLOATING) ... )}.  These declarations will be used in place of any CLISP declarations in the function definition.  This feature provides a way of including CLISP declarations in macro definitions.

{note info about CLISP%  moved to Stuff.CLISPsp}

Note:  CLISP translations can also be used to supply an interpretation for function objects, as well as forms, either for function objects that are used openly, i.e., appearing as {fn CAR} of form, function objects that are explicitly {fn APPLY}ed, as with arguments to mapping functions, or function objects contained in function definition cells.  In all cases, if {fn CAR} of the object is not {lisp LAMBDA} or {lisp NLAMBDA}, the interpreter and compiler will check {var CLISPARRAY}.





}{End SubSec CLISP Translations}