mirror of
https://github.com/PDP-10/its.git
synced 2026-01-13 23:36:30 +00:00
128 lines
6.6 KiB
Plaintext
Executable File
128 lines
6.6 KiB
Plaintext
Executable File
Date: 25 November 1980 12:52-EST
|
||
From: Robert W. Kerns <RWK at MIT-MC>
|
||
Subject: Feature double creature
|
||
To: KMP at MIT-MC
|
||
cc: LISP-FORUM at MIT-MC, "(FILE [LISP;SHARPC DOC])" at MIT-MC
|
||
|
||
Well, I suppose I should at this time (I've been postponing it) propose my
|
||
FEATURE-SET proposal.
|
||
|
||
First off, a couple notes about KMP's proposal:
|
||
|
||
1) I think the need for a canonical way of determining which dialect the code
|
||
is running under is clear.
|
||
|
||
2) I don't see any reason for it to be a STATUS mumble rather than a variable.
|
||
|
||
3) The issue is separate from issues of sharp-sign conditionalization and
|
||
feature-testing. Sharp-sign conditionalization does not want to depend on what
|
||
features are PRESENT AT READ TIME, but rather WHAT FEATURES ARE PRESENT AT
|
||
TIME-OF-USE. This last is the motivation for my proposal.
|
||
|
||
Some of you have seen this before. I've long intended to bring this out as
|
||
an alternate mode for the existing MACLISP SHARPM package, but haven't had the
|
||
time for integrating my code into the current version. But since it turns out
|
||
I need it for cross-compilation in NIL, I've just fixed it up.
|
||
|
||
1) A single LISP environment often has need of reading forms intended for
|
||
different LISP environments. For example, a compiler may be doing READ for
|
||
forms which may be EVAL'ed in its environment, or which may be EVAL'd in some
|
||
other LISP with possibly different features (probably not the COMPLR feature!)
|
||
with or without compilation. I.e. the line #-FOO in a source file usually
|
||
refers to a feature FOO in the LISP that the compiled file will run in. (I'll
|
||
get into exceptions to this later). The LISP where it will eventually matter
|
||
whether the FOO feature exists I will call the TARGET LISP. The target LISP
|
||
may or may not be the same LISP that is doing the READ that see's the #+FOO.
|
||
|
||
2) It is not really enough to say that because a feature is not on a list of
|
||
features somewhere that a feature is not present. Sometimes this is because
|
||
whoever told the compiler what features exist simply did not know all about the
|
||
target environment (I.e. I'm compiling this file for use with the RWK-HACKS
|
||
feature). Sometimes you know that a feature is NOT present, like FRANZ in the
|
||
MACLISP compiler. The obvious solution is to maintain TWO LISTS, of KNOWN
|
||
FEATURES and NON-FEATURES. What do you do if a feature is not known? Two
|
||
options are to signal an error, and to ask the user. I prefer the later.
|
||
|
||
3) It is not enough to have simply ONE set of features. When doing a LOAD in
|
||
a COMPLR, for example, one generally intends for that code to be evaluated in
|
||
the compiler, so the LOCAL LISP is the target, and the LOCAL FEATURES should be
|
||
brought to bear. When reading for compilation, COMPILATION-TARGET-FEATURES
|
||
should be what is used (by default) for FEATUREP.
|
||
|
||
So! I define the following goodies:
|
||
|
||
[This stuff is available by loading ((LISP) SHARPCONDITIONALS) either on top of
|
||
or instead of ((LISP) SHARPM)]
|
||
|
||
defun DEF-FEATURE-SET target features &optional nofeatures (query-mode ':QUERY)
|
||
Defines a feature-set for a target environment named <target>, with
|
||
the supplied features and non-features. If <query-mode> is :QUERY, the
|
||
user will be asked each time. If <query-mode> is :ERROR, an error is
|
||
signaled. If <query-mode> is T, FEATUREP of things unknown returns T, while
|
||
if it is (), it returns ().
|
||
|
||
[This query-mode stuff is merely to satisfy any namby-pambies out there who
|
||
don't like this winning stuff for one reason or another. If nobody dislikes
|
||
this stuff, maybe it should be flushed as being excess hair.]
|
||
|
||
defvar TARGET-FEATURES default LOCAL-FEATURES
|
||
The default feature-set for FEATUREP and the sharp-sign macro. This should
|
||
be bound around calls to READ when the result of the READ will be understood
|
||
in some other environment, such as compilers.
|
||
|
||
defun FEATUREP feature &optional (feature-set TARGET-FEATURES) (featurep T)
|
||
Returns T if <feature> is known to be a feature in <feature-set>.
|
||
<feature-set> is a symbol which has been defined to be a feature-set by
|
||
DEF-FEATURE-SET. If it the feature is not known to be either a feature or
|
||
not a feature, action is taken according to the query-mode of the feature
|
||
set. (see DEF-FEATURE-SET)
|
||
|
||
featurep is a purely internal flag which if () turns FEATURP into NOFEATUREP.
|
||
|
||
defun NOFEATUREP feature &optional (feature-set TARGET-FEATURES)
|
||
like FEATUREP, except returns T if known NOT to be a feature.
|
||
|
||
FEATUREP will take not only a feature name, but a generalized FEATURE-SPEC. A
|
||
feature-spec is a feature name, or (OR f1 f2 ... fn), meaning T iff f1, f2, ...
|
||
OR fn satisfy the FEATUREP test, (NOT f) [meaning the same as (nofeature f)],
|
||
(AND f1 f2 ... fn) meaning T iff f1, f2, ... AND fn satisfy the featurep test.
|
||
In addition to these familiar operators can be used any name of a FEATURE-SET.
|
||
I.e. (FEATUREP (AND (LOCAL-FEATURES F1) F2)) returns T iff F1 is a feature in
|
||
LOCAL-FEATURES and F2 is a feature in whatever feature set is the value of
|
||
TARGET-FEATURES. This may have some limited application in conjunction with #+
|
||
and #-, but should not be used wantonly.
|
||
|
||
#+ and #- are followed by a feature-spec and another form. #+ calls FEATUREP,
|
||
and #- calls NOFEATUREP on the feature-spec, and if () is returned, the next
|
||
form is gobbled and thrown away. Note that it is gobbled via a recursive READ,
|
||
so if it contains illegal syntax or #.'s, an error may result. Note that
|
||
using #- and #+ inside forms conditionalized with #- and #+ can quickly result
|
||
in unreadable and unmaintainable code.
|
||
|
||
A few functions for manipulating FEATURE-SETs:
|
||
|
||
defun COPY-FEATURE-SET old new
|
||
This function makes a new feature-set having the same known features,
|
||
non-features, and query mode as the old. It is probably the right way
|
||
to create new feature sets for related environments.
|
||
|
||
defun SET-FEATURE feature &optional (feature-set-name TARGET-FEATURES)
|
||
This function makes <feature> be a feature in the feature-set named by
|
||
<feature-set-name>. (FEATUREP <feature> <feature-set-name>) will thereafter
|
||
return T.
|
||
|
||
defun SET-NOFEATURE feature &optional (feature-set-name TARGET-FEATURES)
|
||
This function makes <feature> be a non-feature in the feature-set named by
|
||
<feature-set-name>. (NOFEATUREP <feature> <feature-set-name>) will
|
||
thereafter return T.
|
||
|
||
defun SET-FEATURE-UNKNOWN feature &optional (feature-set-name TARGET-FEATURES)
|
||
This function makes <feature> be unknown in the feature set. Depending on
|
||
the query-mode, FEATUREP and NOFEATUREP may query, give an error, or assume
|
||
the default values thereafter.
|
||
|
||
defun SET-FEATURE-SET-QUERY-MODE feature-set-name mode
|
||
sets the feature-set query-mode to <mode>. <mode> can be one of :QUERY,
|
||
:ERROR, T, or (), as described above.
|
||
|