


The Kawa Scheme system, by Per Bothner
**************************************

Kawa is a Scheme environment, written in java, and that compiles Scheme
code into Java byte-codes.

This documents version 1.0, updated 16 September 1996.

R. Alexander Milowski <alex@copsol.com> wrote the first Kawa releases.
Per Bothner <bothner@cygnus.com> extensively re-wrote Kawa, and
released version 0.3 and up.  For now, send bug reports to
bothner@cygnus.com.

Features
========

Kawa is a full Scheme implementation.  It implements almost all of R4RS
(for exceptions *note Restrictions::.), plus some extensions.  It
provide `define-syntax' from the R4RS appendex, and multiple values
(from the draft R5RS).

It is completely written in Java.  Scheme functions and files are
automatically compiled into Java byte-codes, providing reasonable
speed.  (However, Kawa is not an optimizing compiler, and does not
perform major transformations on the code.)

Kawa provides the usual read-eval-print loop, as well as batch modes.

Kawa is written in an object-oriented style.

Building and installing Kawa
============================

Before installing Kawa, you must have Java working on your system.

You can compile Kawa from the source distribution.  Alternatively, you
can install the pre-compiled binary distribution.

Getting and running Java
------------------------

You will need a working Java system.  The discussion below assumes you
are using the Java Developer's Kit (JDK) JDK 1.0.x from JavaSoft (Sun).
You can download free copies of JDK 1.0.2 for Sparc/Solaris,
x86/Solaris, MS-Windows 95/NT, and MacOS; see
`http://java.sun.com:80/java.sun.com/products/JDK/1.0.2/index.html'.

The program 'java' is the Java interpreter.  The program 'javac' is the
Java compiler, and is needed if you want to compile the source release
yourself.  Both programs must both be in your `PATH'.

You also need to set `CLASSPATH' so it includes both the current
directory, and the standard Java library.  After you have installed
Kawa, the `CLASSPATH' needs to include wherever you installed Kawa.

If you have the JDK in directory `$JDK', and you are using a
Bourne-shell compatible shell (/bin/sh, ksh, bash, or other) you can
set both variables thus:
     PATH=$JDK/bin:$PATH
     CLASSPATH=.:$JDK/lib/classes.zip
     export PATH CLASSPATH

Installing and using the binary distribution
--------------------------------------------

The binary release includes only the binary compiled `.class' versions
of the same `.java' source files in the source release.  It does not
include any documentation, so you probably want the source release in
addition to the binary release.  The purpose of the binary release is
just to save you time and trouble compiling the sources.

The binary release comes as a gzip-compressed tar file named
`kawa-1.0-compiled.tar.gz'.

You need to decide where you want to put the Kawa `.class' files.
Assuming it is `/usr/local/java' (the default), you can do:
     gunzip -c <kawa-1.0-compiled.tar.gz|(cd /usr/local/java; tar xf -)

Then, before you can actually run Kawa, you need to set `CLASSPATH' so
it includes the Kawa files.  For example:
     export CLASSPATH=.:/usr/local/java:$JDK/lib/classes.zip

Then to run Kawa do:
     java kawa

Installing and using the source distribution
--------------------------------------------

The Kawa release normally comes as a gzip-compressed tar file named
`kawa-1.0.tar.gz'.

In your build directory do:
     tar xzf kawa-1.0.tar.gz
     cd kawa-1.0

Then you must configure the sources.  This you can do the same way you
configure most other GNU software.  Normally you can just run the
configure script with no arguments:

     ./configure

This will specify that a later `make install' will install the compiled
`.class' files into `/usr/local/java'.  If you want them to be
installed someplace else, such as `$PREFIX/java', then specify that
when you run configure:
     ./configure -- prefix $PREFIX

Thus you need to compile all the .java source files.  Just run make:
     make

You can now test the system by running Kawa in place:
     java kawa

or you can install the compiled files:
     make install

This will install your classes into `$PREFIX/java' (and its
sub-directories).  Here `$PREFIX' is the directory you specified to
configure with the `--prefix' option, or `/usr/local' if you did not
specify a `--prefix' option.

To use the installed files, you need to set `CLASSPATH' so that
`$PREFIX/java' is on the path:
     export CLASSPATH=.:$PREFIX/java:$JDK/lib/classes.zip

How to start up and run Kawa
============================

To run Kawa, you must start a Java interpreter.  This depends on the
Java interpreter.  For JavaSoft's JDK, you must have the Java
interpreter in your `PATH'.  You must also make sure that the
`kawa.class' file, the rest of the Kawa packages, and the standard Java
packages can be found by searching CLASSPATH.  *Note Running Java::.

Then you do:
     java kawa

You will then get the `kawa>' prompt, which means you are in the Kawa
read-eval-print-loop.  If you type a Scheme expression, Kawa will
evaluate it.  Kawa will then print the result (if there is a non-"void"
result).

To exit Kawa, type the end-of-file character (normally ctrl/D), or call
the `exit' procedure (with 0 or 1 integer arguments).

You can pass various flags to Kawa, for example:
     java kawa -e '(display (+ 12 4))(newline)'
This causes Kawa to print `16', and then exit.

`-c EXPR'
     Kawa evaluates EXPR, which contains one or more Scheme expressions.

`-e EXPR'
     Same as `-c EXPR'.

`-f FILENAME'
     Kawa reads and evaluates expressions from the file named by
     FILENAME.  If FILENAME is `-', standard input is read (with no
     prompting).

`-s'
`--'
     The global variable `command-line-arguments' is set to the
     remaining arguments (if any), and an interactive read-eval-print
     loop is started.

If there are further command-line arguments after the options have been
processed, then the first remaining argument names a file that is read
and evaluated.  If there is no such argument, then Kawa enters an
interactive read-eval-print loop, but only if none of the `-c', `-e',
`-f', `-s', or `--' options were specified.

 - Variable: command-line-arguments
     The remaining arguments (following any switches processed by Kawa
     itself) are assigned to the global variable
     `command-line-arguments', which is a vector of strings.

Features of R4RS not implemented
================================

The file Compliance.html specifies which functions and syntax have been
implemented so far.

Of the "numeric tower", only integers and double-precision floats are
implemented.  There is partial bignum support, but many operations are
only available for 32-bit (or sometimes 64-bit) fixnums.  Integral
function do not necessarily work on inexact (floating-point) integers.
(The whole idea of "inexact integer" in R4RS seems rather pointless ...)

Also, call-with-current-continuation is only "upwards" (?).  I.e. once
a continuation has been exited, it cannot be invoked.  These restricted
continuations can be used to implement catch/throw (such as the
examples in R4RS), but not co-routines or backtracking.

Kawa does not do general tail-call elimination.  However, if the
compiler can prove that the procedure being called is the current
function, then the tail call will be replaced by a jump.  This means
the procedure must be defined using a letrec, not a define (because the
compiler does not know if someone might re-define a global definition),
and there must be no assignments (using `set!') to the procedure
binding.

Extensions
==========

 - Function: exit [CODE]
     Exits the Kawa interpreter, and ends the Java session.  The
     integer value CODE is returned to the operating system.  If CODE
     is not specified, zero is returned, indicating normal (non-error)
     termination.

 - Macro: when CONDITION FORM...
     If CONDITION is true, evaluate each FORM in order, returning the
     value of the last one.

 - Macro: unless CONDITION FORM...
     If CONDITION is false, evaluate each FORM in order, returning the
     value of the last one.

 - Function: vector-append ARG...
     Creates a new vector, containing the elements from all the ARGs
     appended together.   Each ARG may be a vector or a list.

 - Function: call-with-input-string STRING PROC
     Create an input port that gets its data from STRING, call PROC
     with that port as its one argument, and return the result from the
     call of PROC

 - Function: call-with-output-string PROC
     Create an output port that writes its data to a STRING, and call
     PROC with that port as its one argument.  Return a string
     consisting of the data written to the port.

Compiling Scheme code to byte-codes
===================================

All Scheme functions and source files are invisibly compiled into
internal Java byte-codes.  A traditional evaluator is only used for
top-level directly entered expressions *outside* a lambda.  (It would
have been simpler to also byte-compile top-level expressions by
surrounding them by a dummy lambda.  However, this would create a new
Class object in the Java VM for every top-level expression.  This is
undesirable unless you have a VM that can garbage collect Class objects.
Sun's VM currently does not, but that is planned for JDK 1.1.)

To save speed when loading large Scheme source files, you probably want
to pre-compile them and save them on your local disk.  There are two
ways to do this.

You can compile a Scheme source file to a single archive file.  You do
this using the `compile-file' function.  The result is a single file
that you can move around `load' just like the `.scm' source file.  You
just specify the name of the archive file to the `load' procedure.
Currently, the archive is a "zip" archive and has extension ".zip"; a
future release will probably use "Java Archive" (jar) files, once
support from that has been released from JavaSoft.  The advantage of
compiling to an archive is that it is simple and transparent.  A
disadvantage is that it causes the Java "verifier" to be run when
functions are loaded from it, which takes a little extra time.

Alternatively, you can compile a Scheme source file to a collection of
`.class' files using the stand-alone `kawac' application.  You then use
the standard Java class loading mechanism to load the code.  The Java
"verifier" does not need to get run, which makes loading a little
faster.  The compiled class files do have to be installed be installed
somewhere in the `CLASSPATH'.

Compiling Scheme to an archive file
-----------------------------------

To byte-compile a file `foo.scm' do:
     (compile-file "foo.scm" "foo")

This will create `foo.zip', which contains byte-compiled "j-code" that
implements `foo.scm'.

You can later do:
     (load "foo")

This will load `foo.zip', which should have the same effect as loading
`foo.scm', except you will get the byte-compiled versions.

Compiling Scheme to a set of .class files
-----------------------------------------

The `kawac' will compile a `.scm' source file into one or more `.class'
files.

You run it as follows:
     java kawac infile [-d outdirectory] [prefix [topname]]

Here:
INFILE
     The Scheme source file we want to compile.

`-D' OUTDIRECTORY
     The directory under which the resulting `.class' files will be.
     The default is the current directory.

PREFIX
     A string to prepend to the generated class names.  The default is
     the empty string.

TOPNAME
     The name of the "top" class - i.e. the one that contains the code
     for the top-level expressions and definitions.  The default is
     generated from the INFILE and PREFIX.

When you actually want to load the classes, the OUTDIRECTORY must be in
your `CLASSPATH'.  You can use the standard `load' function to load the
code, by specifying the top-level class, either as a file name
(relative to OUTDIRECTORY) or a class name.  E.g. if you did:
     java kawac foosrc.scm -d /usr/local/java my.lib. foo
you can use either:
     (load "my.lib.foo")
or:
     (load "my/lib/foo.class")

Writing new "primitive" Scheme functions in Java
================================================

Scheme types in Java
--------------------

All Scheme values are implemented by sub-classes of `java.lang.Object'.

Scheme symbols are implemented by `kawa.lang.Symbol'.  Use the `make'
static method to create a new (interned) symbol.

Scheme integers are implemented by `kawa.math.IntNum'.  Use the make
static function to create a new IntNum from an int or a long.  Use the
intValue or longValue methods to get the int or long value of an
IntNum.  There is partial support for bignums.

A Scheme "flonum" is implemented by `kawa.math.DFloNum'.

A Scheme pair is implemented by `kawa.lang.Pair'.

A Scheme vector is implemented by `kawa.lang.Vector'.

Scheme characters are implemented using `kawa.lang.Char'.

Scheme strings are *currently* implemented using
`java.lang.StringBuffer'.  This will probably be changed to use a new
sub-class of `kawa.lang.Sequence'.

Scheme procedures are all sub-classes of `kawa.lang.Procedure'.
Normally each function (lambda expression) in the source code is
compiled to a separate sub-class of `Procedure'.  The "action" of a
`Procedure' is invoked by using one of the `apply*' methods:  `apply0',
`apply1', `apply2', `apply3', `apply4', or `applyN'.  Various sub-class
of `Procedure' provide defaults for the various `apply*' methods.  For
example, a `Procedure2' is used by 2-argument procedures.  The
`Procedure2' class provides implementations of all the `apply*' methods
*except* `apply2', which must be provided by any class that extends
`Procedure2'.

A function that does some initialization and makes definitions should
probably be written as a `ModuleBody'.  A `ModuleBody' is a sub-class
of `Procedure0'.  It must therefore define an `apply0' method;  that is
where you can put definitions.  A `ModuleBody' can be loaded using the
Scheme `load' procedure.

You can define new bindings in the top-level environment using the
`define_global' method in `kawa.lang.Interpreter'.  For example:
        Interpreter.define_global (Symbol.make ("pi"),
                                   new DFloNum (java.lang.Math.PI));

The various Kawa classes may be shuffled around some in the future.  It
is quite likely they will not remain in the package `kawa.lang', so you
should probably use `import' statements rather than fully-qualified
class names to refer to Kawa classes.

License
=======

This software is copyrighted by Copernican Solutions Incorporated, R.
Alexander Milowski, Cygnus Support, and other parties.  The following
terms apply to all files associated with the software unless explicitly
disclaimed in individual files.

The authors hereby grant permission to use, copy, modify, distribute,
and license this software and its documentation for any purpose,
provided that existing copyright notices are retained in all copies and
that this notice is included verbatim in any distributions. No written
agreement, license, or royalty fee is required for any of the
authorized uses.  Modifications to this software may be copyrighted by
their authors and need not follow the licensing terms described here,
provided that the new terms are clearly indicated on the first page of
each file where they apply.

IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY
FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY
DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.

THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES,
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND
NON-INFRINGEMENT.  THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, AND
THE AUTHORS AND DISTRIBUTORS HAVE NO OBLIGATION TO PROVIDE MAINTENANCE,
SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.

