Copyright (c) 1994, 1995, 1996, 1997 Carnegie Mellon University All rights reserved. Refer to the end of this document for precise terms of use.
The Gwydion Project would like to thank those on the net that have contributed code patches and bug reports for Mindy:
Adam Alpern, Steve Strassman, Scott Collins, Ed Gamble, Bruno Haible, John Shen, Galen Hunt, Richard Lynch, Dan Ratner, Court Demas, Miles Bader, Kelly Murray, Nick Thompson, Brent Benson, Brian Rogoff, Alain Rogister, Mark Chu-Carroll, Enrico Colombini, Dave Dyer, Jonathan Bachrach, Michael Binz, Jonathan Sobel, Eric Kidd, John Shen, Carl Gay, Patrick Premont, Eric Gouriou, Kim Barrett
Special thanks for major efforts to Roger Critchlow, Patrick Beard, Gary Palter, and Jim Studt for enhancements to Mindy.
Mindy is an implementation of a language that is very much like the language described in the DylanTM Reference Manual (DRM). Mindy was named for "Mindy Is Not Dylan Yet", and it still is and will probably always remain a Dylan subset, primarily because mindycomp doesnt do enough semantic analysis to implement macros or to implement the precise semantics of Dylan naming. Now that the d2c Dylan-to-C compiler is available (see web documentation), debugged Dylan applications will normally be compiled for better performance. Mindy remains useful because:
Mindy was developed by the Gwydion Project at Carnegie Mellon University for our own internal use as a development tool while we work on our real high-performance Dylan implementation. We have decided to make Mindy available for other people who want to learn about Dylan. However, the amount of effort that we can put into maintaining Mindy is strictly limited.
Mindy will never be an industrial-strength implementation, and nobody should depend on it for real work. We will make future releases from time to time as we add new features and fix bugs, but this is strictly a sideshow for us. We would appreciate receiving bug reports (especially those accompanied by code patches) and suggestions for improvements, but we may not fix every bug reported in a timely manner, or fix it at all.
Mindy comprises two C programs, a compiler that produces byte-codes and a byte-code interpreter. Instructions for compiling and installing Mindy can be found in the file INSTALL at the top level of the Mindy release. Instructions for obtaining the different versions of Mindy can be found in the file README at the top level of the Mindy release.
Well, the first program anyone should endeavor to write in a new language is, of course, Hello World. Type this into a file called hw-exports.dylan:
Module: dylan-user
define library hello-world
use Dylan;
end library;
define module hello-world
use dylan;
use cheap-io;
use extensions;
end module;
And put this in hw.dylan:
module: Hello-World
// This is the canonical ``hello, world'' demo.
define method main (argv0 :: <byte-string>, #rest noise)
puts("Hello, World.\n");
end;
To compile your program invoke $INSTALL/bin/mindycomp, for example:
% $INSTALL/bin/mindycomp -lhello-world hw-exports.dylan
% $INSTALL/bin/mindycomp -lhello-world hw.dylan
This produces files named hw.dbc and hw-exports.dbc. The .dbc stands for "Dylan Byte Code". To run the program, say:
% $INSTALL/bin/mindy -f hw-exports.dbc -f hw.dbc
It should print "Hello, World." to standard output and then exit.
Note that even the minimal Dylan program has at least two files. This is because in order to do anything much at all, you must access additional libraries, and the only way to set up your namespace is to define your own library and module. But the only way to place code in a module is to use the Module: file header, so two files are required.
Note also that a blank line is required after the Module: file header.
After loading your program, Mindy invokes the generic function main from the Extensions module of the Dylan library. Your program must define a method for main, or Mindy will signal a no applicable methods error and put you in the debugger. For more information on the main function, see section The Extensions Module.
It can be useful to load code into Mindy with no main method. Once you land in the debugger, you can call any function manually. This provides a way to test any library.
No matter how many files there are, you just compile them each independently, and then run Mindy with multiple -f switches:
% mindy -f foo.dbc -f bar.dbc -f baz.dbc
Mindy loads the files specified with the -f switches in the order you specify the files on the command line. This becomes important when you define your own modules (see section Using Libraries and Modules).
If you typically load several .dbc files as part of a single program, you can combine them into one file for convenience. The mechanism for combining .dbc files is the UnixTM cat utility:
% cat foo.dbc bar.dbc baz.dbc > big.dbc
% mindy -f big.dbc
Under Microsoft Windows, many implementations of cat will corrupt .dbc files because they perform newline translation. For this reason, under MS-Windows, we recommend using dbclink:
% dbclink big.dbc cat foo.dbc bar.dbc baz.dbc
% mindy -f big.dbc
If Mindy encounters an unrecoverable error, or if Mindy is exited via the debugger quit command, Mindy exits with a return code of 1. If the Dylan program ends with a call to exit() and a return code is specified (see section Exiting Applications), Mindy exits with that return code. Otherwise, the return code is 0.
Mindycomp recognizes the following command line switches:
Mindy recognizes the following command line switches:
Mindy recognizes the following environment variables:
If there are any syntax errors in your program, mindycomp will report them to stderr while compiling. For example, if you had left off the closing parenthesis in the call to puts in the above example, mindycomp would have reported:
hw.dylan:4: parse error at or before `;'
Because the line introduction, hw.dylan:4:, has the same format that the C compiler uses, gnu-emacs's compile package can parse the error messages from mindycomp.
Mindycomp's error recovery is not the best in the world. Often, it has to completely punt, telling you only about the first few errors it found. You have to fix what it reports and try again.
A hint to getting slightly tighter error recovery is to end all method and class definitions with "end method;" or "end class;". For example, if you forget an end token for a statement inside a method definition, the mindycomp parser goes all the way to the end of the file and then reports a syntax error at the EOF position. You do not get any more clues. If you use "end method;", then the parser can recover at the end of the method containing the bad syntax and reports the syntax error there. This gives you a lot tighter recovery and more information in this situation.
Much more common than syntax errors are runtime errors. And given the simplistic model of compilation mindycomp uses, most semantic errors are not detected until runtime. When Mindy hits a runtime error that is not handled via the condition system, it drops you into a debugger. From this debugger you can look at variables, examine the stack, and invoke functions. For example, if you had assumed that puts would be named something more reasonable, like put-string, you would have gotten the following when you tried to run your Hello World program:
% mindy -f hw.dbc
Warning: the following variables are undefined:
in library Dylan-user:
in module Dylan-user:
put-string[hw.dylan, line 9]
thread [0] D main
fp 0x1003009c: invoke-debugger({<simple-error> 0x101a24c9})
mindy>
Typing help at the mindy> prompt will list the various commands you can use. See the document debug.ps for more information.
Mindycomp issues warnings at compile time when:
Mindy issues warnings at runtime when:
Mindy does not gracefully handle stack overflows. If Mindy gets a stack overflow, it will die with some kind of signal, like SIGSEG (segmentation fault). If this happens, you probably have an infinite recursion in your program.
Sometimes mindycomp or Mindy will get an internal error. When this happens, it will print a message to stderr and then abort. This results in the process dying due to some kind of signal. On the pmax, this signal is SIGILL, or Illegal Instruction. When this happens, send gwydion-bugs@cs.cmu.edu a piece of mail containing the error message and information on what it was you did that triggered the problem.
The Dylan language is still changing slightly. Mindy implements most of the Dylan Reference Manual, as well as some features we would like to see in Dylan. In addition to those extensions described in the document Gwydion Extensions, Mindy diverges from the DRM as described below:
Additions:
(var1, var2, ...) = expr1 THEN expr2
Deficiencies:
if (foo)
end if;
Mindy has full support for modules and libraries. Mindy provides two built-in libraries, Dylan and Dylan-user. The Dylan library contains the Dylan language implementation and the following exported modules:
This module contains the Dylan language implementation and exports all the built-in Dylan definitions.
This module exports useful extensions to the Dylan language (see section The Extensions Module).
Ultimately, there will be several, more logically separate libraries that extend Dylan or provide an
application framework for users. For now, we put any commonly used utilities in the Extensions
module.
This module exports an interface to operating system calls and special, low-level functionality (see section The System Module).
This module exports reflective operations for examining classes, functions, and so on.
This module exports an interface to most standard C system calls that operate on file descriptors.
This module exports some basic, unextendable input and output functionality.
This module exports an interface to threads, locks, and objects that behave similarly to cthreads.h
condition variables.
The Dylan-user library is the default library in which mindycomp compiles user code. Mindy provides this library for user convenience when whipping up play code or small applications for which the programmer does not want to bother to create a library. You cannot redefine the Dylan-user library. This library contains one module, Dylan-user, and you cannot redefine this module.
The Dylan language requires every library to contain a Dylan-user module, and this module must use the Dylan module from the Dylan library regardless of any user specifications. This module provides a starting point in every library where users can begin to define modules; without an initial module in the library, you would be unable to write any code, including module definitions. Each Dylan-user module in Mindy also automatically uses the modules from the Dylan library described above. You cannot redefine the Dylan-user module, so if your code requires module other than those described above, then you must define your own library and module.
Mindy comes bundled with several other libraries. Documentation for these libraries can be found in $INSTALL/doc/libraries.
To compile code into a particular library use the -l switch to mindycomp:
% mindycomp -lmy-lib foo.dylan
If there is no -l switch, then mindycomp compiles the code into the Dylan-user library. When loading a .dbc file into Mindy that was compiled into a particular library, one of the following conditions must be satisfied to avoid errors:
While loading a file, if Mindy processes a library definition that uses an undefined library, then Mindy stops loading the current file, searches for the undefined library, and loads it. After loading the undefined library, Mindy continues loading the current file and processing the original library definition. Mindy searches for the undefined library in the directories listed in the DYLANPATH environment variable. If DYLANPATH is undefined, then Mindy uses the path:
.:$DYLANDIR/lib/dylan
If DYLANDIR is also undefined, then the fallback default is /usr/local/lib/dylan on Unix and c:\dylan\lib\dylan on Windows. This default can be changed by recompiling Mindy, see the build instructions.
In each directory, Mindy first looks for the file <library>-lib.dbc, where <library> is the name of the undefined library, and if this file does not exist, then Mindy looks for <library>.dbc.
Mindy loads the Dylan library when it first sees a reference to it. A reference to the Dylan library occurs when loading a file compiled to be in the Dylan library, or when loading a file with a library definition that uses the Dylan library. Mindy loads the Dylan library by looking for the file dylan.dbc on DYLANPATH.
To make a single compiled file for a library which has multiple source files, compile all the files that constitute the library with the -l switch set to the library's name. Then cat all the resulting .dbc files together (see section Multiple Files), making sure the file that defines the library is first. Then install the combined .dbc file in one of the directories in your DYLANPATH.
To compile code into a particular module, use the module: file header. Whenever a source file lacks a module: file header, mindycomp issues a compiler warning and compiles the code into the Dylan-user module. This is the Dylan-user module of the library specified with the -l switch, and if there was no -l switch, it is the Dylan-user module of the Dylan-user library. If a file contains no file headers, it still must contain a leading blank line to conform to Dylan syntax.
When loading a .dbc file into Mindy that was compiled into a particular module, one of the following conditions must be satisfied to avoid errors:
Ultimately, there will be several, more logically separate libraries that extend Dylan or provide an application framework for users. For now, we put any commonly used utilities in the Extensions module. Extensions which are likely to be supported in future Gwydion compilers are documented in the document Gwydion Extensions; here we document those extensions whose future is not so certain.
The Extensions module exports the following generally useful functionality:
main [Generic Function]
load [Function]
load-library [Function]
The Extensions module exports the following functionality for controlling the exiting of applications:
on-exit [Function]
The Extensions module exports the following weak-pointer functionality:
<weak-pointer> [Class]
weak-pointer-object [Function]
The Extensions module exports the following debugger customization:
*debug-output* [Variable]
In addition to those extensions described in the document Gwydion Extensions, the System module exports the following:
*print-GC-messages* [Variable]
collect-garbage [Function]
getcwd [Function]
The Mindy Introspection module exports reflective operations for examining classes, functions, and types. (See also the document Gwydion Extensions)
The Introspection module exports the following for class objects, slot descriptions, and fetching and modifying the slot values of general objects:
abstract? [Function]
<slot-descriptor> [Class]
slot-descriptors [Function]
slot-name [Function]
slot-allocation [Function]
slot-type [Function]
slot-getter [Function]
slot-setter [Function]
slot-value [Function]
slot-value-setter [Function]
init-keyword [Function]
keyword-required? [Function]
A cleaner interface to most of these functions is available from the Streams library (see the document The Streams Library). You probably do not need to use the File-descriptor module, unless you need an obscure file mode.
The File-descriptor module exports the following functions and constants:
fd-exec [Function]
fd-open [Function]
fd-close [Function]
fd-read [Function]
fd-write [Function]
fd-input-available? [Function]
fd-sync-output [Function]
fd-seek [Function]
fd-error-string [Function]
EFBIG [Constant]
The Cheap-io module exports some basic, unextendable I/O functionality. Mindy uses the Cheap-io functions internally. The Gwydion Project also provides the Streams, Print, and Format libraries (see The Streams Library, The Print Library, and The Format Library, respectively). It is an error to use both Cheap-IO functions and Streams/Print/Format functions on a single stream. (For example, if you are using the Streams library *standard-input*, do not also use the Cheap-io input functions) For this reason, if any library that you load into Mindy uses the Debugger-format library, the debugger will use format from the Format library. Also, look at the document Gwydion Extensions for Cheap-IO functionality also supported in other Gwydion compilers.
prin1 [Function]
puts [Function]
putc [Function]
getc [Function]
fflush [Function]
This module is in the Dylan library and exports an interface to <thread>s, <lock>s, and <event>s (objects on which threads can wait until a signalling thread indicates the events have occurred).
The Threads module exports the following classes and functions:
<thread> [Class]
spawn-thread [Function]
kill-thread [Function]
current-thread [Function]
<lock> [Abstract Class]
<multilock> [Sealed Class]
<semaphore> [Sealed Class]
locked? [Function]
grab-lock [Generic Function]
grab-lock [G.F. Method]
grab-lock [G.F. Method]
grab-lock [G.F. Method]
release-lock [Generic Function]
release-lock [G.F. Method]
release-lock [G.F. Method]
<event> [Class]
wait-for-event [Generic Function]
signal-event [Function]
broadcast-event [Function]
The following code shows how to use locks and events to isolate access to a queue:
// This example shows two routines, get-queue and release-queue. Code
// that accesses the queue should call get-queue before doing so and call
// release-queue when done. Any code failing to isolate access to the
// queue in this way has undefined behavior and is incorrectly written.
//
// This variable is #t if and only if the queue is generally available.
//
define variable queue-available? = #t;
// This constant holds an event object used to signal when the queue
// becomes generally available again.
//
define constant queue-available = make(<event>);
// This constant holds a lock object used to isolate access to
// queue-available? for testing and setting purposes.
//
define constant queue-lock = make(<lock>);
// When this function returns, the caller has exclusive access to the
// queue. If necessary, this function waits for the queue to become
// available, but it does not busy loop. This function returns #f as
// a meaningless return value.
//
define method get-queue ()
grab-lock(queue-lock);
while (~ queue-available?)
wait-for-event(queue-available, queue-lock);
grab-lock(queue-lock);
end;
queue-available? := #f;
lock-release(queue-lock);
#f;
end;
// This function releases the queue and signals that it is released so
// that someone waiting on the queue will be woken up. This function
// returns #f as a meaningless return value.
//
define method release-queue ()
grab-lock(queue-lock);
queue-available? := #t;
release-lock(queue-lock);
signal-event(queue-available);
#f;
end;
The following example shows how to use a lock to isolate queue access in a different way than the previous example:
// This constant holds an event object used to signal when an element
// exists in the queue.
//
define constant something-available = make(<event>);
// This constant holds a lock that is held whenever a thread is accessing
// queue.
//
define constant lock = make(<lock>);
// This constant holds a queue object.
//
define constant queue = make(<deque>);
// This function returns an element from queue. If no element is
// immediately available, then this function blocks until it can return
// an element. This function assumes only one or two other threads are
// ever waiting for the queue, and it assumes pop is a fast high-level
// operation.
//
define method get-something()
grab-lock(lock);
while (empty?(queue))
wait-for-event(something-available, lock);
grab-lock(lock);
end;
let result = pop(queue);
lock-release(lock);
result;
end;
// This function adds thing to queue. It assumes only one or two other
// threads are ever waiting for the queue, and it assumes push is a fast
// high-level operation.
//
define method put-something(thing)
grab-lock(lock);
push(queue, thing);
release-lock(lock);
signal-event(something-available);
end;
The error method specialized on <byte-string> applies the format function to the arguments passed to error. See section The Extensions Module for the details of format from the Cheap-io module of the Dylan library. See the document The Format Library for the details of format from the Format library.
Rest arguments in Mindy are <sequence>s. You cannot use any functions on the rest argument that assumes the collection is an instance of any class more specific than <sequence>; for example, you cannot use the head or tail functions because they operate on instances of <pair>.
Mindys <character> implementation is equivalent to unicode characters. The <byte-character> class exported from the Extensions module of the Dylan library is a subclass of <character>.
Copyright (c) 1994, 1995, 1996, 1997 Carnegie Mellon University All rights reserved.
Use and copying of this software and preparation of derivative works based on this software are permitted, including commercial use, provided that the following conditions are observed:
This software is made available as is. Neither the authors nor Carnegie Mellon University make any warranty about the software, its performance, or its conformity to any specification.
Bug reports, questions, comments, and suggestions should be sent by E-mail to the Internet address gwydion-bugs@cs.cmu.edu.
Copyright 1994, 1995, 1996, 1997 Carnegie Mellon University. All rights reserved.