Go to the first, previous, next, last section, table of contents.
Kawa has extensive features so you can work with Java objects and call Java methods,
All Scheme values are implemented by sub-classes of `java.lang.Object'.
Scheme symbols are implemented using java.lang.String
.
(Don't be confused by the fact the Scheme sybols are represented
using Java Strings, while Scheme strings are represented by
kawa.lang.Scheme
. It is just that the semantics of Java strings
match Scheme symbols, but do not match mutable Scheme strings.)
Interned symbols are presented as interned Strings.
(Note that with JDK 1.1 string literals are automatically interned.)
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.
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 implemented using kawa.lang.FString
.
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
.
Kawa provides a simple yet powerful "Foreign Function Interface", which allows you to call any (virtual or static) Java method as if it were a Scheme procedure.
These primitives require you to specify the parameter and return types.
Type specifications are currently required to be string literals
or one of the standard types (see section Standard Types).
A type specifier can be a fully-qualified Java class name
(for example <java.lang.StringBuffer>
). In that case,
the actual argument is cast at run time to the named class.
The specification <String>
is an exception:
It causes the toString
method of the actual
argument to be invoked.
A type specifier can also be one of the primitive Java types.
The numeric types <long>
, <int>
, <short>
,
<byte>
, <float>
, and <double>
are converted from the
corresponding Scheme number classes. Similarly, <char>
can be converted to and from Scheme characters. The type
boolean
matches any object, and the result is false
if and only if the actual argument is #f
.
The return type <void>
indicates that no value is returned.
The macros return procedure values, just like lambda
.
If the macros are used directly as the procedure of a procedure call,
then kawa can inline the correct bytecodes to call the specified methods.
(Note also that neither macro
checks that there really is a method that matches the specification.)
Otherwise, the Java reflection facility is used.
Some examples using these primitives are `vectors.scm' and `characters.scm' the directory `kawa/lib' in the Kawa sources.
The following macros evaluate to procedures that can be used to access or change the fields of objects or static fields. The compiler can inline each to a single bytecode instruction (not counting type conversion).
primitive-get-field
, but used to access static fields.
Returns a zero-argument function, which when called returns
the value of the static field.
primitive-set-field
, but used to modify static fields.
Returns a one-argument function, which when called sets the
value of the static field to the argument.
The following macros evaluate to procedures that can be used to manipulate primitive Java array objects. The compiler can inline each to a single bytecode instruction (not counting type conversion).
The "top" class created by kawa -C
(see section Compiling Scheme to a set of .class files)
extends the ModuleBody
class. It is actually fairly
easy to write a ModuleBody
by hand in Java, and you can
then use the Scheme load
procedure to cause arbitrary
actions. Here is an example.
(Note that the details are subject to change!)
package MyDev; import kawa.lang.*; class MyDevFunc extends Procedure2 { public Object apply2 (Object arg1, Object arg2) { ... stuff to control my device ...; } } public class MyDevice extends ModuleBody { public Object run (Environment env) throws WrongArguments, WrongType, GenericError, UnboundSymbol { ... initialize my device here ...; // Declare (handle-my-device x y) to call MyDevFunc.apply2 (x, y): env.define ("handle-my-device", new MyDevFunc ()); // Return the void value (i.e. no value). return Interpreter.voidObject; } }
If this text is in the file MyDev/MyDevice.java
, and you compile
it with javac
, you will get MyDev/MyDevice.class
and MyDev/MyDevFunc.class
. Assuming the current directory
is in your CLASSPATH
, you can now do the following in Kawa:
(load "MyDev/MyDevice.class")
or:
(load "MyDev.MyDevice")
This will cause the actions in MyDevice.run
to be executed.
The current environment is passed in as the parameter env
.
One of those actions is to define the procedure handle-my-device
.
The following methods are recommended if you need to evaluate a Scheme expression from a Java method. (Some details (such as the `throws' lists) may change.)
Interpreter.voidObject
if there is no expression.
Interpreter.voidObject
if there is no expression.
read
).
Evaluate it in the env environment, and return the result.
For the Environment
in most cases you could use
`Environment.current()'.
Go to the first, previous, next, last section, table of contents.