As of release 0.11, OpenMCL addresses the fact that foreign type, constant, record, field, and function nams are case-sensitive and provides mechanisms to refer to these names via lisp symbols.
Previous versions of OpenMCL have tried to ignore that fact, under the belief that case conflicts were rare and that many users (and implementors) would prefer not to deal with case-related issues. The fact that some information in the interface databases was incomplete or inaccessable because of this policy made it clearer that the policy was untenable. I can't claim that the approach described here is aesthetically pleasing, but I can honestly say that it's less unpleasant than other approaches that I'd thought of. I'd be interested to hear alternate proposals.
The issues described here have to do with how lisp symbols
are used to denote foreign functions, constants, types,
records, and fields. It doesn't affect how other lisp
objects are sometimes used to denote foreign objects.
For instance, the first argument to the EXTERNAL-CALL
macros is now and has always been a case-sensitive string.
The primary way of referring to foreign constant and function names in OpenMCL is via the #$ and #_ reader macros. These reader macro functions each read a symbol into the "OS" package, look up its constant or function definition in the interface database, and assign the value of the constant to the symbol or install a macroexpansion function on the symbol.
In order to observe case-sensitivity, the reader-macros now
read the symbol with (READTABLE-CASE :PRESERVE)
in effect.
This means that it's necessary to type the foreign constant or function name in correct case, but it isn't necessary to use any special escaping constructs when writing the variable name. For instance:
... (#_read fd buf n) ; refers to foreign symbol "read" (#_READ fd buf n) ; refers to foreign symbol "READ", which may ; not exist ... #$o_rdonly ; Probably doesn't exist #$O_RDONLY ; Exists on most platforms ...
Constructs like RLET
expect a foreign type or
record name to be denoted by a symbol (typically a keyword);
RREF
(and PREF
) expect an "accessor"
form, typically a keyword formed by concatenating a foreign
type or record name with a sequence of one or more foreign
field names, separated by dots. These names are interned
by the reader as other lisp symbols are, with an arbitrary
value of READTABLE-CASE
in effect (typically
:UPCASE
.) It seems like it would be very tedious
to force users to manually escape (via vertical bar or backslash
syntax) all lowercase characters in symbols used to specify
foreign type, record, and field names (especially given that
many traditional POSIX structure, type, and field names are
entirely lowercase.)
The approach taken by OpenMCL is to allow the symbols (keywords)
used to denote foreign type, record, and field names to contain
angle brackets (<
and >
). Such
symbols are translated to foreign names via the following set
of conventions:
All instances of < and > in the symbol's pname are balanced and don't nest.
Any alphabetic characters in the symbol's pname that aren't
enclosed in angle brackets are treated as lower-case, regardless
of the value of READTABLE-CASE
and regardless of
the case in which they were written.
Alphabetic characters that appear within angle brackets are mapped to upper-case, again regardless of how they were written or interned.
There may be many ways of "escaping" (with angle brackets) sequences of upper-case and non-lower-case characters in a symbol used to denote a foreign name. When translating in the other direction, OpenMCL always escapes the longest sequence that starts with an upper-case character and doesn't contain a lower-case character. It's often preferable to use this canonical form of a foreign type name.
The accessor forms used by PREF
/RREF
should be viewed as a series of foreign type/record and field
names; upper-case sequences in the component names should
be escaped with angle brackets, but those sequences shouldn't
span components. (More simply, the separating dots shouldn't
be enclosed, even if both surrounding characters need to be.)
Older POSIX code tends to use lower-case exclusively for type, record, and field names; there are only a few cases in the OpenMCL sources where mixed-case names need to be escaped.
Examples:
;;; Allocate a record of type "window". (rlet ((w :window)) ...) ;;; Allocate a record of type "Window", which is probably a different type (rlet ((w :<w>indow)) ...) ;;; This is equivalent to the last example (rlet ((w :<w>INDOW)))