make(<class>)
is not implemented.
slot-initialized?()
, applicable-method?()
and
sorted-applicable-methods()
are not implemented.
class
and each-subclass
slot allocation are not
supported.
keyword
clause to "define class
" for
defining initargs (e.g. keyword foo:, ...) are parsed but ignored.
aref
, element
, and
singleton
is supposed to
look up the name in the context of the operation. Instead, we always
look it up in the Dylan
library.
for
'' macro is supposed to evaluate the types
interleaved with
the init expressions, but it does not. In fact, in some cases, it
will evaluate the type expression each time though the loop.
define sealed domain
'' are not
detected.
d2c -gMndT {-tdirectory} {-Ldirectory}* {-Dfeature}* {-Ufeature*} lid-file
d2c compilation is driven by a LID (Library Interchange Description) file describing the library contents and various compilation options. It serves a similar purpose to a make file (but we use make too.) See the description of the LID file format below.
In operation, d2c reads and processes the dylan files, generating .c and .s files and a temporary .mak makefile. It then runs gmake on this makefile.
d2c recognizes these switches:
#if
conditional compilation. Features may
also be specified in the LID file by the
"Features:
" option.
A LID file is composed of entries of the form
"keyword: value", similar to mail
headers and to the Dylan file header format. Currently d2c expects the list of
source files to appear as the "main body" of the LID file, after the header and
a blank line. In the Harlequin LID format, there is a "Files:
"
entry which is used instead, and which we do not yet support.
d2c recognizes these LID entries:
Library:
dylan-library-name
define library
" somewhere in the source for this library.
Unit-prefix:
c_legal_identifier_fragment
-
").
Unique-ID-base:
decimal-integer
Executable:
result-file-name
Entry-Point:
dylan-module:
dylan-variable
Extensions:Main
by using the Extensions
module in
your main module and then specifying:
"Entry-Point:
mymodule:%main
"
in the LID file. The %Main
function parses the arguments and then
calls Main
.
Linker-options:
various "ld" flags
-lm
" so that it can use the math library. This
dependency is automatically propagated to users of the library.
Features:
{feature | ~
feature}*
~
", then the rest of the token is interpreted as a feature
to remove. Otherwise, the token is added as a feature.
//
as a
comment-to-end-of-line sequence (equivalent to whitespace.)
Here is a sample LID file:
rcs-header: $Header: /afs/cs.cmu.edu/project/gwydion-9/dylan/docs/htdocs/RCS/d2c.html,v 1.3 97/06/04 19:50:59 ram Exp Locker: ram $ library: my-program unit-prefix: myprog unique-id-base: 30000 executable: mp entry-point: main:%main myprog-exports.dylan myprog.dylan
%main
, see
Entry-Point:
.
define library
" and "define module
" forms
for a library must be in a
separate file which is the first file specified in the LID file. This file
should specify "Module: Dylan-User
" in its header.
*standard-output*
on process exit, so you may need to add
explicit calls to force-output
.
random-gaussian()
and
random-exponential()
.
Dig currently only compiles on HP/Ux and Win32, and is probably not useful on the latter. Feel free to get it working on other platforms. dig is not strictly necessary in any case, but it does sugarcoat some of the naming issues.
print
print
" to
provide a meaningful description of the object. (The choice of
which "print
" to use depends upon the setting of *warning-output*
.)
Because DIG calls a function within your program, the program must be
running before Dylan values may be printed.
find
break
interactive
prompt
set prompt
" command. Bad things will happen.)
quit
gdb
print
" command instead of DIG's.
print
" and "break
"
commands may be noticeably slower than you expect. Since translations
are cached, it will get faster as you go along.
-g
" switch to D2C.
Dylan
" library is to be found.
The gnu assembler must be used in conjunction with the generated code from gcc. If you somehow end up running the HP/UX "as" with gcc, it will produce many errors about STAB entries, etc.
The actual C code comes in three pieces, or entries, with each entry being a separate C function. At a call site, the compiler can either know exactly what function is being called or it might not have a clue (e.g. inside map where it calls the passed in function). So to keep from having to pay the penalty of runtime checking everything all the time instead of just when necessary, we generate multiple entry points for each function.
The main entry is the entry that is used when the compiler can determine that everything is fine. It doesn't have to check any argument types or figure out what values correspond to what keywords.
The general entry is the entry that is used in a random call where the compiler can't tell anything. It checks the argument types, decodes the keywords, and then calls the main entry.
The generic entry is like the general entry, except that it is only used when the method was invoked via some generic function. The generic function dispatch stuff already guarantees that they argument types are okay, so it only has to decode the keywords before calling the main entry.
'As a special case to deal with the Dylan' => "
BLANK
"
'!
' => "D
"
'%
' => "PCT
"
'$
' => "C
"
'&
' => "AND
"
'*
' => "V
"
'+
' => "PLUS
"
'-
' => "_
"
'/
' => "SLASH
"
'<
' => "LESS
"
'=
' => "EQUAL
"
'>
' => "GREATER
"
'?
' => "QUERY
"
'^
' => "RAISE
"
'_
' => "X_
"
'|
' => "OR
"
'~
' => "NOT
"
otherwise => "Xhex code"
<class>
naming
convention, the brackets are stripped off of the variable name, and
CLS_
is prefixed to the name. So <list>
becomes CLS_list
instead of LESSlistGREATER
.
_METH
_DISCRIM
_GENERAL
_GENERIC
_MAIN
_INT_
local method name
_INT_method
method
form inside the named method.
_DEFER
_INIT
_SETTER
_GETTER
_TYPE
_VAR
_MAKER
LINE_542
UNKNOWN
_542
_VAR
names are guaranteed never to have this uniquifier suffix.
As you might infer from the preceding, some suffixes can be combined, but
except for _INT_
not to an arbitrary depth. Some examples:
dylanZdylan_visceraZCLS_type /* <type> */ /* general-entry for maker for <type-error> */ dylanZdylan_visceraZCLS_type_error_MAKER_GENERAL /* signal{<condition>} internal search */ dylanZdylan_visceraZsignal_METH_INT_search_MAIN dylanZdylan_visceraZVdebuggerV_VAR /* *debugger* */For local variables, we simply add "
L_
" to the front of the name.
This may result in a non-unique name. In which case, a uniquifier is
appended to the end; see the "some name_542
" rule
above.
known dylan type c type <integer> long <single-float> float <double-float> double <extended-float> long double <raw-pointer> void * no data word heapptr_t <object> descriptor_t
An immediate representation is one where the actual data is directly there. As opposed to a pointer representation where the actual data lives in the heap and is referenced via a pointer.
The general representation is the fully general representation that can be used to represent any Dylan object. It consists of a heap pointer and a data word. (i.e. descriptor_t) The heap pointer representation is used to represent anything that doesn't need the data word. (i.e. heapptr_t)
"Boxed" and "unboxed" are somewhat vague terms that one will often hear on the 'net. Unboxed data is the raw data, the good stuff, with no overhead. The drawback is that if you don't know the type of the raw data (is it an integer, a character, or a float?), it's just a bunch of bits. Boxing means to add meta-data (the type of the data) so that the data can be interpreted unambiguously. The d2c immediate representation is an unboxed representation, while the d2c general representation is a boxed representation. Depending on the situation, the heap pointer representation might be considered either boxed or unboxed.
inline
movable
Plus is an example of a movable function:
2 + 2
is always 4
no matter
when. movable
implies flushable
; see below.
flushable
functional
==
) is defined in terms of the
slot values, not the pointer identity of the heap representation of the object.
Actually, currently you have to define a functional-==
method that
checks to see if two instances of a functional class are the same yourself. So
you could intentionally get it wrong, and then strange things would happen.
But the idea is that the instances will be ==
iff the object-class
for them both is the same and all slots are ==
. Functional
classes may have subclasses, but be sure to define functional-==
methods accordingly.
d2c performs the following optimizations:
common sub-expression elimination (CSE), optimistic type inferencing, compile time method selection, inlining, code motion.See also compile time constants.
==
, the literal
#"foo"
in the String-extensions library is ==
to the
literal #"foo"
in the Streams library, and so cannot go in either
library's unitprefix-heap.s. Currently symbols are the
only object with this property.
If the type expression isn't an obvious compile-time constant, then d2c gains no useful information from it, but is required to go to extra work to implement a run-time check. For this reason, your code will compile much better if you only use type expressions which d2c can recognize as being constant. The notion of compile time constant lies at the heart of many of d2c's optimizations.
To start with, some terminology:
<unknown-ctype>
, which
frustrates any attempt at further type inference.
If we can figure out a ct-value equivalent to an expression parse, we say that expression is ct-evaluable. An expression is ct-evaluable if any of the following holds:
Some definitions are ct-evaluable, and some are not:
For function calls to most functions with built-in support, simply knowing that the arguments and the function are ct-evaluable is enough to make the function call ct-evaluable. These functions include:
type-union, false-or, subclass, direct-instance, negative,
abs, \+, \-, \*, ash, \^, logior, logxor, logand, lognot
limited(<integer>)
and
limited(<collection>)
are also ct-evaluable if
their arguments are ct-evaluable.
However, two functions are different. In addition to requiring that the arguments and the function are ct-evaluable, they impose additional constraints:
singleton(
obj)
is ct-evaluable only if obj is an
eql-ct-value.
one-of(
obj1, obj2, ...)
is ct-evaluable only if every arg is an eql-ct-value.
The most common way to construct a type which is not ct-evaluable is to create a singleton of a non-class type. For instance, although
type-union(<foo>, <bar>)is ct-evaluable,
singleton(type-union(<foo>, <bar>))is not.