Specifying Object Names#
Because naming conventions differ between C and Dylan, Melange attempts to translate the names specified in C declarations into a form more appropriate to Dylan. This involves
Adding angle brackets around type names.
Adding dollar signs at the beginning of constant names.
Translating (non-initial) underlines into hyphens.
Adding
struct-name$
prefixes to slot accessors.
In many cases, this default behavior will be precisely what you want. However, Melange provides mechanisms for specifying different translations for some or all of the declarations.
Mapping functions#
The translations described above are provided by calls
to a built-in “name mapping function” named
“minimal-name-mapping-with-structure-prefix”. You may specify
other mapping functions via a name-mapper:
option. Our
example interface might then look like this:
define interface
#include "gc.h",
name-mapper: c-to-dylan;
end interface;
Function |
Result |
---|---|
minimal-name-mapping-with-structure-prefix |
Provides the translations described above. |
minimal-name-mapping |
Same as above, but excludes |
c-to-dylan |
Like |
identity-name-mapping |
Does no translation. |
New name-mapping functions can be implemented within melange by
defining methods on the map-name
generic function which
accepts the following parameters:
mapper
a
<symbol>
which is typically specialized by a singleton to select a specific name mapper method.category
a
<symbol>
which will always be one of:#"type"
,#"constant"
,#"variable"
, or#"function"
.prefix
a
<string>
which is typically prepended to the result string.name
a
<string>
which supplies the original C name.sequence-of-classes
a sequence of simple names for the classes which logically “contain” the given object. For example, if we were processing the declaration
struct str {int size; char *chars;}
, one of the calls to the mapping function would have with name bound to “size” and classes bound to#["str"]
.
It must return a <string>
which will be used as the
Dylan name for the declaration.
Mapping functions may call hyphenate-case-breaks
which
performs the same “CaseBased separation” as is done by
c-to-dylan
. The trivial identity-name-mapping
described
above might be implemented by:
define method map-name
(mapper == #"identity-name-mapping", category, prefix, name, classes)
=> (result :: <string>)
name;
end method map-name;
You may specify different name mappers to be applied to the slots of “container types”. This capability is described in a later section.
Prefixes#
As noted above, the name mapping function is passed a
prefix
argument. By default, it is an empty string, but
users may specify a different value by adding a prefix:
option to the interface definition. For example, we might
expand the previous example to:
define interface
#include "gc.h",
name-mapper: c-to-dylan,
prefix: "gc-";
end interface;
This would cause Melange to tack gc-
onto the
beginning of every translated symbol. Because the system
knows about the “standard” Dylan naming conventions, it can do
this intelligently. You would, therefore, get names like
<gc-bool>
, gc-time-to-gc
, and gc-scavenge
.
Note that the interpretation of the prefix
is entirely
up to the name mapping routine. Identity-name-mapping, for
example, completely ignores the prefix. All of the other
standard mapping functions prepend it to the name before
adding brackets or dollar signs, but after performing all
other transformations.
Facilities for adding “localized” prefixes to slot accessors, enumeration literals, etc. will be described in later sections.
Explicit Renaming#
Although the automatic name mapping described above is
sufficient for most objects named within a header file, there
are cases in which you might wish to explicitly control the
name of one or more specific objects. You can do this through
a rename:
option. This options specifies a list of
translations between raw C names and Dylan identifiers. For
example, we might have:
define interface
#include "gc.h",
name-mapper: c-to-dylan,
prefix: "gc-"
rename: {"struct obj" => <C-Object>, "collect_garbage" => GC};
end interface;
Note that the “target” of the renaming is an ordinary
Dylan variable and is therefore case-insensitive. However, the
source is an “alien name”, which is (like all C code) case
sensitive. Alien names should refer to an object, function, or
type in exactly the same way you would refer to them in C. We
therefore say struct obj
instead of simply obj
, and might
also say enum foo
or union bar
. Alien names are actually
parsed according to the standard lexical conventions of C, so
you may use arbitrary spacing and even include comments if you
really wish.
Note that rename:
options supply names for new objects
(and types) that are being imported into Dylan. You cannot,
therefore, simply rename bool
to <Boolean>
to make
it equivalent to the existing type – this would simply result
in a name conflict. For these purposes, you would instead use
the equate
and map
operations, which will be described
later. (In fact, if the C declaration had defined a type name
boolean
, you might have to explicitly rename it to something
else in order to avoid name conflicts with the existing type.
Of course, in the above example, the gc-
prefix would be
sufficient to make the name unique.)
Anonymous Types#
The alien names described above can also be used to
refer to C’s so-called “anonymous types”. You can therefore
refer to char *
, int [23]
, or even int (*) (char *foo)
(i.e. a pointer to function which takes a string and returns
an integer) [At present, function types are not fully
supported. You should not depend upon them to work as
expected.]. The ability to refer to anonymous types is
useful because it allows you to use the rename
option to
provide explicit names for such types. Normally Melange would
simply generate a an arbitrary “anonymous” identifier for the
type. Without knowing the name of this type, you could not
define new operations upon it. However, by saying, for
example, rename: {"char *" => <char-ptr>}
, you can
provide a convenient handle to use in defining new
operations.