The Kawa Scheme Language

The Kawa Scheme Language

How to start up and run Kawa

The easiest way to start up Kawa is to run the ‘kawa’ program. This finds your java interpreter, and sets up ‘CLASSPATH’ correctly. If you have installed Kawa such $PREFIX/bin is in your $PATH, just do:

kawa

However, ‘kawa’ only works if you have a Unix-like environment. On some platforms, ‘kawa’ is a program that uses the GNU ‘readline’ library to provide input line editing.

To run Kawa manually, you must start a Java Virtual Machine. How you do this depends on the Java implementation. For Sun's JDK s and some other implementations, you must have the Java evaluator (usually named java) in your PATH. You must also make sure that the kawa/repl.class file, the rest of the Kawa packages, and the standard Java packages can be found by searching CLASSPATH. See the section called “Getting and running Java”.

Then you do:

java kawa.repl

In either case, you will then get the ‘#|kawa:1|#’ 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).

Command-line arguments

You can pass various flags to Kawa, for example:

kawa -e '(display (+ 12 4))(newline)'

or:

java kawa.repl -e '(display (+ 12 4))(newline)'

Either causes Kawa to print ‘16’, and then exit.

At startup, Kawa executes an init file from the user's home directory. The init file is named .kawarc.scm on Unix-like systems (those for which the file separator is '/'), and kawarc.scm on other systems. This is done before the read-eval-print loop or before the first -f or -c argument. (It is not run for a -e command, to allow you to set options to override the defaults.)

If there are no command-line arguments following the options, then Kawa enters an interactive read-eval-print loop, but only if none of the ‘-c’, ‘-e’, ‘-f’, ‘-s’, ‘-C’, or ‘--’ options were specified.

If there are command-line arguments after processing options, then the first remaining argument names either a file that is read and evaluated, or a compiled class. In the former case, the whole file is read and compiled as a module before being loaded (unlike the -f flag which reads and evaluates the file command by command.) If the argument is the fully-qualited name of a class, then the class is loaded, an instance allocated, and its run method invoked. If the class was compiled from a Kawa Scheme module, then invoking run has the effect of evaluating the module body.

General options

-e expr

Kawa evaluates expr, which contains one or more Scheme expressions. Does not cause the ~/.kawarc.scm init file to be run.

-c expr

Same as ‘-e expr’, except that it does cause the ~/.kawarc.scm init file to be run.

-f filename-or-url

Kawa reads and evaluates expressions from the file named by filename-or-url. If the latter is ‘-’, standard input is read (with no prompting). Otherwise, it is equivalent to evaluating ‘(load "filename-or-url")’. The filename-or-url is interpreted as a URL if it is absolute - it starts with a "URI scheme" like http:.

-s
--

The remaining arguments (if any) are passed to ‘command-line-arguments’ and (the cdr of) (command-line), and an interactive read-eval-print loop is started. This uses the same "console" as where you started up Kawa; use ‘-w’ to get a new window.

--script filename-or-url
--scriptN filename-or-url

The global variable ‘command-line-arguments’ is set to the remaining arguments (if any). Kawa reads and evaluates expressions from the file named by filename-or-url. If script is followed by an integer N, then N lines are skipped first.

Skipping some initial lines is useful if you want to have a non-Kawa preamble before the actual Kawa code. One use for this is for Kawa shell scripts (see the section called “Running Command Scripts”).

-w

Creates a new top-level window, and runs an interactive read-eval-print in the new window. See the section called “Running a Command Interpreter in a new Window”. Same as -e (scheme-window #t). You can specify multiple ‘-w’ options, and also use ‘-s’.

--help

Prints out some help.

--version

Prints out the Kawa version number, and then exits.

--server portnum

Start a server listening from connections on the specified portnum. Each connection using the Telnet protocol causes a new read-eval-print-loop to started. This option allows you to connect using any Telnet client program to a remote "Kawa server".

Options for language selection

--scheme

Set the default language to Scheme. (This is the default unless you select another language, or you name a file with a known extension on the command-line.)

--r5rs
--r6rs
--r7rs

Provide better compatibility with the specified Scheme standards. (This is a work-in-progress.) For example --r6rs aims to disable Kawa extensions that conflict with R6RS. It does not aim to disable all extensions, only incompatible extensions. So far these extensions disable the colon operator and keyword literals. Selecting --r5rs makes symbols by default case-insensitive.

--elisp
--emacs
--emacs-lisp

Set the default language to Emacs Lisp. (The implementation is quite incomplete.)

--lisp
--clisp
--clisp
--commonlisp
--common-lisp

Set the default language to CommonLisp. (The implementation is very incomplete.)

--krl

Set the default language to KRL. See the section called “KRL - The Kawa Report Language for generating XML/HTML”.

--brl

Set the default language to KRL, in BRL-compatibility mode. See the section called “KRL - The Kawa Report Language for generating XML/HTML”.

--xquery

Set the default language to the draft XML Query language. See the Kawa-XQuery page for more information.

--xslt

Set the default language to XSLT (XML Stylesheet Language Transformations). (The implementation is very incomplete.) See the Kawa-XSLT page for more information.

--pedantic

Try to follow the approprate language specification to the letter, even in corner cases, and even if it means giving up some Kawa convenience features. This flags so far only affects the XQuery parser, but that will hopefully change.

Options for warnings and errors

--warn-undefined-variable

Emit a warning if the code references a variable which is neither in lexical scope nor in the compile-time dynamic (global) environment. This is useful for catching typos. (A define-variable form can be used to silence warnings. It declares to the compiler that a variable is to be resolved dynamically.) This defaults to on; to turn it off use the --no-warn-undefined-variable flag.

--warn-unknown-member

Emit a warning if the code references a named member (field or method) for which there is no match in the compile-time type of the receiver. This defaults to on; to turn it off use the --no-warn-unknown-member flag.

--warn-invoke-unknown-method

Emit a warning if the invoke function calls a named method for which there is no matching method in the compile-time type of the receiver. This defaults to the value of --warn-unknown-member, to turn it off use the --no-warn-invoke-unknown-method flag.

--warn-unused

Emit a warning if a variable is unused or code never executed. This defaults to on; to turn it off use the --no-warn-unused flag.

--warn-unreachable

Emit a warning if the code can never be executed. This defaults to on; to turn it off use the --no-warn-unreachable flag.

--warn-void-used

Emit a warning if an expression depends on an expression that is void (always has zero values), including call to void functions and method. Also warn if an expression depends on a conditional (if) that has no “else” clause. Examples include using the value of set-car! as an argument to a function, or to initialize a variable. This defaults to on; to turn it off use the --no-warn-void-used flag.

--warn-as-error

Treat a compilation warning as if it were an error and halt compilation.

An option can be followed by a value, as in --warn-invoke-unknown-method=no. For boolean options, the values yes, true, on, or 1 enable the option, while no, false, off, or 0 disable it. You can also negate an option by prefixing it with no-: The option --no-warn-unknown-member is the same as --warn-unknown-member=no.

These options can also be used in the module source, using module-compile-options or with-compile-options. (In that case they override the options on the command line.)

Options for setting variables

name=value

Set the global variable with the specified name to the given value. The type of the value is currently unspecified; the plan is for it to be like XQuery's untyped atomic which can be coerced as needed.

{namespace-uri}local-name=value

Set the global variable with the specified namespace uri and namespace-local name to the given value.

These options are processed when invoking the kawa application (i.e. the kawa.repl application). If you want a Kawa application compiled with --main to process these these assignments, call the process-command-line-assignments utility function.

Options for controlling output formatting

--output-format format
--format format

Change the default output format to that specified by format. See the section called “Named output formats” for more information and a list.

out:base=integer

The number base (radix) to use by default when printing rational numbers. Must be an integer between 2 and 36, and the default is of course 10. For example the option out:base=16 produces hexadecimal output. Equivalent to setting the *print-base* variable.

out:radix=no|yes

If true, prints an indicator of the radix used when printing rational numbers. The default is no. Equivalent to setting the *print-radix* variable.

out:doctype-system=system-identifier

If out:doctype-system is specified then a DOCTYPE declaration is written before writing a top-level XML element, using the specified system-identifier.

out:doctype-public=public-identifier

Ignored unless out:doctype-system is also specified, in which case the public-identifier is written as the public identifiers of the DOCTYPE declaration.

out:xml-indent=kind

Controls whether extra line breaks and indentation are added when printing XML. If kind is always or yes then newlines and appropriate indentation are added before and after each element. If kind is pretty then the pretty-printer is used to only add new lines when an element otherwise won't fit on a single line. If kind is no (the default) then no extra line breaks or indentation are added.

out:line-length=columns
out:right-margin=columns

Specifies the maximum number of number of columns in a line when the pretty-printer decides where to break a line. (The two options are equivalent.)

Options for compiling and optimizing

--target version

The version can be a JDK or Java specification version: 5, 6, or 7. The JDK versions 1.5 and 1.6 are equivalent to 5 or 6, respectively. Specify a JVM (classfile) version to target. This is useful if (for example) you use Java 6, but want to create .class files that can run on Java 5. In that case specify --target 5.

The following options control which calling conventions are used:

--full-tailcalls

Use a calling convention that supports proper tail recursion.

--no-full-tailcalls

Use a calling convention that does not support proper tail recursion. Self-tail-recursion (i.e. a recursive call to the current function) is still implemented correctly, assuming that the called function is known at compile time.

--no-inline

Disable inlining of known functions and methods. The generated code runs slower, but you can more reliably trace procedures. Normally Kawa will assume that a procedure fn declared using a (define (fn args) body) form is constant, assuming it isn't modified in the current module. However, it is possible some other module might modify the binding of fn. You can use the --no-inline to disable the assumption that fn is constant.

The default is currently --no-full-tailcalls because it is usually faster. It is also closer to the Java call model, so may be better for people primarily interested in using Kawa for scripting Java systems.

Both calling conventions can co-exist: Code compiled with --full-tailcalls can call code compiled with --no-full-tailcalls and vice versa.

These options can also be used in the module source, using module-compile-options or with-compile-options. (In that case they override the options on the command line.)

The options ‘-C’, ‘-d’, ‘-T’, ‘-P’, ‘--main’ ‘--applet’, and --servlet are used to compile a Scheme file; see the section called “Compiling to a set of .class files”. The options ‘--module-static’, --module-nonstatic, --no-module-static, and --module-static-run control how a module is mapped to a Java class; see the section called “How a module becomes a class”. The option ‘--connect portnum’ is only used by the ‘kawa’ front-end program.

Options for debugging

The following options are useful if you want to debug or understand how Kawa works.

--debug-dump-zip

Normally, when Kawa loads a source file, or evaluates a non-trivial expression, it generates new internal Java classes but does not write them out. This option asks it to write out generated classes in a ‘.zip’ archive whose name has the prefix ‘kawa-zip-dump-’.

--debug-print-expr

Kawa translates source language forms into an internal Expression data structure. This option causes that data structure to be written out in a readable format to the standard output.

--debug-print-final-expr

Similar to the previous option, but prints out the Expression after various transformations and optimizations have been done, and just before code generation.

--debug-error-prints-stack-trace

Prints a stack trace with any error found during compilation.

--debug-warning-prints-stack-trace

Prints a stack trace with any warning found during compilation.

Options for web servers

JDK 6 (or later) includes a complete web server library.

--http-auto-handler context-path appdir

Register a web application handler that uses files in the directory appdir to handle HTTP (web) requests containing the given context-path. That is it handles requests that start with http://localhost:portcontext-path. (This assumes the context-path starts with a /.) See the section called “Self-configuring web page scripts”.

--http-start port

Start the web server, listing on the specified port.

Options for the JVM

The kawa front-end can pass options to the java launcher, using -J or -D options. These must be given before any other arguments. For example:

kawa -J-Xms48m -Dkawa.command.name=foo foo.scm --

is equivalent to (ignoring classpath issues):

java -Xms48m -Dkawa.command.name=foo kawa.repl foo.scm --
-Jjvm-option

Passes the jvm-option to the java command, before the class-name (kawa.repl) and Kawa options.

-Dvariable-name=variable-value

Sets the JVM property variable-name to variable-value. Equivalent to -J-Dvariable-name=variable-value.

Running Command Scripts

If you write a Kawa application it is convenient to be able to execute it directly (from the command line or clicking an icon, say), without have to explicitly run kawa or java. On Unix-like systems the easiest way to do this is to write a small shell script that runs your Kawa application.

For modest-sized applications it is convenient if the shell script and the Kawa code can be in the same file. Unix-like systems support a mechanism where a script can specify a program that should execute it. The convention is that the first line of the file should start with the two characters ‘#!’ followed by the absolute path of the program that should process (interpret) the script.

(Windows has batch files, which are similar.)

This is convention works well for script languages that use ‘#’ to indicate the start of a comment, since the interpreter will automatically ignore the line specifying the interpreter filename. Scheme, however uses ‘#’ as a multi-purpose prefix, and Kawa specifically uses ‘#!’ as a prefix for various the section called “Special named constants” such as #!optional.

Kawa does recognize the three-character sequence ‘#!/’ at the beginning of a file as special, and ignores it. Here is an example:

#!/usr/local/bin/kawa
(format #t "The command-line was:~{ ~w~}~%" (command-line))

If you copy this text to a file named /home/me/bin/scm-echo, set the execute permission, and make sure it in your PATH, then you can execute it just by naming it on command line:

$ chmod +x /home/me/bin/scm-echo
$ PATH=/home/me/bin:$PATH
$ scm-env a b
The command-line was: "/home/me/bin/scm-echo" "a" "b"

The system kernel will automatically execute kawa, passing it the filename as an argument.

Note that the full path-name of the kawa interpreter must be hard-wired into the script. This means you may have to edit the script depending on where Kawa is installed on your system. Another possible problem is that the interpreter must be an actual program, not a shell script. Depending on how you configure and install Kawa, kawa can be a real program or a script. You can avoid both problems by the env program, available on most modern Unix-like systems:

#!/usr/bin/env kawa
(format #t "The command-line was:~{ ~w~}~%" (command-line))

This works the same way, but assumes kawa is in the command PATH.

Setting kawa options in the script

If you need to specify extra arguments to kawa, you can run arbitrary shell command inside Scheme block comments. Here is an example:

#!/bin/sh
#|
exec kawa out:base=16 out:radix=yes "$0" "$*"
|#
(format #t "The command-line is:~{ ~w~}.~%" (command-line))
(display "It has ")
(display (apply + (map string-length (command-line))))
(display " characters.")
(newline)

The trick is to hide the shell code from Kawa inside a #|...|# block-comment. The start of the block comment is a line starting with a #, so it is treated as a comment by the shell. You can then invoke kawa (or java directly) as you prefer, setting up class-path and jars as needed, and passing whatever arguments you want. (The shell replaces the "$0" by the name the script, and replaces the "$@" by the remaining arguments passed to the script.) You need to make sure the shell finishes before it reaches the end of the block comment or the Scheme code, which would confuse it. The example uses exec, which tells the shell to replace itself by kawa; an alternative is to use the shell exit command.

If you copy the above file to /tmp/sch-echo and make that file executate, you can run it directly:

$ /tmp/scm-echo "a b" "c d"
The command-line is: "/tmp/scm-echo" "a b c d".
It has #x14 characters.

When the Kawa reader sees the initial #/ it sets the command name to the file name, so it can be used by a future call to (command-name). If you want to override this you can use the -Dkawa.command.name=name option.

Using comments this way has the advantage that you have the option of running the script “manually” if you prefer:

$ kawa /tmp/scm-echo out:base=8 "x y"
The command-line is: "/tmp/scm-echo" "out:base=8" "x y".
It has 26 characters.

Other ways to pass options using meta-arg or –script

An argument consisting of just a \ (backslash) causes Kawa to read the second line looking for options. (Quotes and backslahes work like in the shell.) These replace the backslash in the command line.

This is a less verbose mechanism, but it requires an absolute path to kawa, due to shell limitations.

#!/usr/bin/bin/kawa \
  --scheme --full-tailcalls
(format #t "The command-line is:~{ ~w~}.~%" (command-line))

In this case the efective command line received by Kawa will be --scheme, --full-tailcalls, followed by the script filename, followed by other arguments specified when running the script.

The backslash used this way originated in scsh where it is called the meta-arg. (Unlike scsh, Kawa's #! is not a block comment, but a rest-of-line, though the backslash causes the following line to also be skipped.)

An alternative method is to use the --script2 option, which tells Kawa to execute the script after ignoring the initial two lines. For example:

#!/bin/sh
exec kawa --commonlisp out:base=16 --script2 "$0" "$@"
(setq xx 20) (display xx) (newline)

This slightly more compact than using block-comments as shown earlier, but it has the disadvantage that you can't explicitly use kawa or java to run the script unless you make sure to pass it the --script2 option.

Scripts for compiled code

If you compile your Kawa application to class files (or better: a jar file), you probably still want to write a small shell script to set things up. Here is one method:

#!/bin/sh
export CLASSPATH=/my/path
exec kawa -Dkawa.command.name="$0" foo "$@"

Using the kawa front-end is a convenience, since it automatically sets up the paths for the Kawa classes, and (if enabled) if provides readline support for the default input port.

Setting the kawa.command.name property to "$0" (the filename used to invoke the script) enables (command-line) to use the script name as the command name.

You can invoke java directly, which is necessary when running a jar file:

#!/bin/sh
exec java -cp /path/to/kawa -Dkawa.command.name="$0" foo.jar "$@"

(It is in principle possible to compile a Kawa application to “a native executable”, for example using gcj. However, this is no longer supported, as gcj is no longer being actively developed.)

Running a Command Interpreter in a new Window

An alternative interface runs the Java read-eval-print-loop inside a new window. This is in some ways nicer. One reason is that it provides better editing. (Mouse selection, arrow keys, and “standard” control keys should all work.)

You can also create new windows. They can either have different top-level environments or they can share environments. To try it, do:

java kawa.repl -w

Exiting Kawa

Kawa normally keeps running as long as there is an active read-eval-print loop still awaiting input or there is an unfinished other computation (such as requested by a ‘-e’ of ‘-f’ option).

To close a read-eval-print-loop, you can type the special literal #!eof at top level. This is recognized as end-of-file. Unfortunately, due to thread-related complications, just typing an end-of-file character (normally ctrl/D until Unix), will not work.

If the read-eval-print-loop is in a new window, you can select ‘Close’ from the ‘File’ menu.

To exit the entire Kawa session, call the exit procedure (with 0 or 1 integer arguments).

Compiling to byte-code or an executable

All Scheme functions and source files are invisibly compiled into internal Java byte-codes. (A traditional interpreter is used for macro-expansion. Kawa used to also interpret “simple” expressions in interactive mode, but always compiling makes things more consistent, and allows for better stack traces on errors.)

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 and 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. The advantage of compiling to an archive is that it is simple and transparent. A minor 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. 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 somewhere in the CLASSPATH.

You can also compile your Scheme program to native code using GCJ.

Compiling to a set of .class files

Invoking ‘kawa’ (or ‘java kawa.repl’) with the ‘-C’ flag will compile a ‘.scm’ source file into one or more ‘.class’ files:

kawa --main -C myprog.scm

You run it as follows:

kawa [-d outdirectory] [-P prefix] [-T topname] [--main | --applet | --servlet] -C infile ...

Note the ‘-C’ must come last, because ‘Kawa’ processes the arguments and options in order,

Here:

-C infile ...

The Scheme source files we want to compile.

-d outdirectory

The directory under which the resulting ‘.class’ files will be. The default is the current directory.

-P prefix

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

-T 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.

--main

Generate a main method so that the resulting "top" class can be used as a stand-alone application. See the section called “Compiling to a standalone application”.

--applet

The resulting class inherits from java.applet.Applet, and can be used as an applet. See the section called “Compiling to an applet”.

--servlet

The resulting class implements javax.servlet.http.HttpServlet, and can be used as an servlet in a servlet container like Tomcat.

When you actually want to load the classes, the outdirectory must be in your ‘CLASSPATH’. You can use the require syntax or the 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:

kawa -d /usr/local/share/java -P my.lib. -T foo -C foosrc.scm

you can use either:

(require my.lib.foo)

or:

(load "my.lib.foo")

Using require is preferred as it imports the definitions from my.lib.foo into the compile-time environment, while load only imports the definitions into run-time environment.

If you are compiling a Scheme source file (say ‘foosrc.scm’) that uses macros defined in some other file (say ‘macs.scm’), you need to make sure the definitions are visible to the compiler. One way to do that is with the ‘-f’:

kawa -f macs.scm -C foosrc.scm

Many of the options described earlier are relevant when compiling. Commonly used options include language selection, the --warn-xxx options, and --full-tailcalls.

Compiling to an archive file

compile-file source-file compiled-archive

Compile the source-file, producing a .zip archive compiled-file.

For example, to byte-compile a file ‘foo.scm’ do:

(compile-file "foo.scm" "foo")

This will create ‘foo.zip’, which contains byte-compiled JVM .class files. You can move this file around, without worrying about class paths. To load the compiled file, you can later load the named file, as in either (load "foo") or (load "foo.zip"). This should have the same effect as loading ‘foo.scm’, except you will get the faster byte-compiled versions.

Compiling using Ant

Many Java projects use Ant for building Java projects. Kawa includes a <kawac> Ant ask that simplifies compiling Kawa sources files to classes. See the build.xml in the Kawa source distribution for examples. See the kawac task documentation for details.

Compiling to a standalone application

A Java application is a Java class with a special method (whose name is main). The application can be invoked directly by naming it in the Java command. If you want to generate an application from a Scheme program, create a Scheme source file with the definitions you need, plus the top-level actions that you want the application to execute.

For example, assuming your Scheme file is MyProgram.scm, you have two ways at your disposal to compile this Scheme program to a standalone application:

  1. Compile in the regular way decribed in the previous section, but add the --main option.

    kawa --main -C MyProgram.scm
    

    The --main option will compile all Scheme programs received in arguments to standalone applications.

  2. Compile in the regular way decribed in the previous section, but add the main: #t module compile option to your module.

    ;; MyProgram.scm
    (module-name <myprogram>)
    (module-compile-options main: #t)
    
    kawa -C MyProgram.scm
    

    This way you can compile multiple Scheme programs at once, and still control which one(s) will compile to standalone application(s).

Both method will create a MyProgram.class which you can either load (as decribed in the previous section), or invoke as an application:

java MyProgram [args]

Your Scheme program can access the command-line arguments args by using the global variable ‘command-line-arguments’, or the R6RS function ‘command-line’.

If there is no explicit module-export in a module compiled with --main then no names are exported. (The default otherwise is for all names to be exported.)

Compiling to an applet

An applet is a Java class that inherits from java.applet.Applet. The applet can be downloaded and run in a Java-capable web-browser. To generate an applet from a Scheme program, write the Scheme program with appropriate definitions of the functions ‘init’, ‘start’, ‘stop’ and ‘destroy’. You must declare these as zero-argument functions with a <void> return-type.

Here is an example, based on the scribble applet in Flanagan's "Java Examples in a Nutshell" (O'Reilly, 1997):

(define-private last-x 0)
(define-private last-y 0)

(define (init) :: void
  (let ((applet (this)))
    (applet:addMouseListener
     (object (java.awt.event.MouseAdapter)
	     ((mousePressed e)
	      (set! last-x (e:getX))
	      (set! last-y (e:getY)))))
    (applet:addMouseMotionListener
     (object (java.awt.event.MouseMotionAdapter)
	     ((mouseDragged e)
	      (let ((g (applet:getGraphics))
		    (x (e:getX))
		    (y (e:getY)))
		(g:drawLine last-x last-y x y)
		(set! last-x x)
		(set! last-y y)))))))

(define (start) :: void (format #t "called start.~%~!"))
(define (stop) :: void (format #t "called stop.~%~!"))
(define (destroy) :: void (format #t "called destroy.~%~!"))

You compile the program with the ‘--applet’ flag in addition to the normal ‘-C’ flag:

java kawa.repl --applet -C scribble.scm

You can then create a ‘.jar’ archive containing your applet:

jar cf scribble.jar scribble*.class

Finally, you create an ‘.html’ page referencing your applet and its support jars:

<html><head><title>Scribble testapp</title></head>
<body><h1>Scribble testapp</h1>
You can scribble here:
<br>
<applet code="scribble.class" archive="scribble.jar, kawa-1.14.1.jar" width=200 height=200>
Sorry, Java is needed.</applet>
</body></html>

The problem with using Kawa to write applets is that the Kawa .jar file is quite big, and may take a while to download over a network connection. Some possible solutions:

  • Try to strip out of the Kawa .jar any classes your applet doesn't need.

  • Java 2 provides a mechanism to install a download extension.

  • Consider some alternative to applets, such as Java Web Start.

Compiling to a native executable

Using GCJ with Kawa is no longer supported, as GCJ is no longer being actively maintained.

You can compile your Scheme program to native code using GCJ, as long as you have built Kawa using GCJ.

First, you need to compile the Scheme code to a set of .class files; see the section called “Compiling to a set of .class files”.

kawa --main -C myprog.scm

Then to create an executable myprog do:

gckawa --main=myprog myprog*.class -o myprog

The gckawa is a simple shell script that calls gcj. The reason for the wildcard in myprog*.class is that sometimes Kawa will generate some helper classes in addition to myprog.class. The --main option tell gcj which class contains the main method it should use. The -o option names the resulting executable program. The -lkawa option tells the linker it should link with the kawa shared library, and the -L$PREFIX/bin option tells the linker where it can find that library.