source: branches/0.23.x/abcl/doc/lisp-ffi.markdown

Last change on this file was 12560, checked in by Mark Evenson, 14 years ago

More work on standalone documentation.

File size: 4.2 KB
Line 
1Lisp FFI
2========
3
4    Mark Evenson
5    Created:  15-FEB-2010
6    Modified: 18-MAR-2010
7
8FFI stands for "Foreign Function Interface", which is the way the
9contemporary Lisp world refers to methods of "calling out" from Lisp
10into "foreign" langauges and envrionments.  This document describes
11the various ways that one interacts with Lisp world of Abcl from Java,
12considering the hosted Lisp as the "Foreign Function" that needs to be
13"Interfaced".
14
15# Lisp FFI
16
17## Calling Lisp from Java
18
19Note: As the entire ABCL Lisp system resides in the org.armedbear.lisp
20package the following code snippets do not show the relevant import
21statements in the interest of brevity.
22
23Per JVM, there can only ever be a single Lisp interpreter.  This is
24started by calling the static method `Interpreter.createInstance()`.
25
26    Interpreter interpreter = Interpreter.createInstance();
27
28If this method has already been invoked in the lifetime of the current
29Java process it will return null, so if you are writing Java whose
30lifecycle is a bit out of your control (like in a Java servlet), a
31safer invocation pattern might be:
32
33    Interpreter interpreter = Interpreter.getInstance();
34    if (interpreter == null) {
35      interpreter = Interpreter.createInstance();
36    }
37
38The Lisp `EVAL` primitive may be simply passed strings for evaluation,
39as follows
40   
41    String line = "(load \"file.lisp\")";
42    LispObject result = interpreter.eval(line);
43
44Notice that all possible return values from an arbitrary Lisp
45computation are collapsed into a single return value.  Doing useful
46further computation on the `LispObject` depends on knowing what the
47result of the computation might be, usually involves some amount
48of instanceof introspection, and forms a whole topic to itself
49(c.f. [Introspecting a LispObject](#introspecting)). 
50
51Using `EVAL` involves the Lisp interpreter.  Lisp functions may be
52directly invoked by Java method calls as follows.  One simply locates
53the package containing the symbol, then obtains a reference to the
54symbol, and then invokes the `execute()` method with the desired
55parameters.
56
57    interpreter.eval("(defun foo (msg) (format nil \"You told me '~A'~%\" msg))");
58    Package pkg = Packages.findPackage("CL-USER");
59    Symbol foo = pkg.findAccessibleSymbol("FOO");
60    Function fooFunction = (Function)foo.getSymbolFunction();
61    JavaObject parameter = new JavaObject("Lisp is fun!");
62    LispObject result = fooFunction.execute(parameter);
63    // How to get the "naked string value"?
64    System.out.prinln("The result was " + result.writeToString());
65
66If one is calling an primitive function in the CL package the syntax
67becomes considerably simpler if we can locate the instance of
68definition in the ABCL source, we can invoke the symbol directly.  To
69tell if a `LispObject` contains a reference to a symbol.
70
71    boolean nullp(LispObject object) {
72      LispObject result = Primitives.NULL.execute(object);
73      if (result == NIL) {
74        return false;
75      }
76      return true;
77   }
78
79<a name="interpreting"/>
80## Introspecting a LispObject
81
82We present various patterns for introspecting an an arbitrary
83`LispObject` which can represent the result of every Lisp evaluation
84into semantics that Java can meaniningfully deal with.
85
86### LispObject as boolean
87
88If the LispObject a generalized boolean values, one can use
89`getBooleanValue()` to convert to Java:
90
91     LispObject object = Symbol.NIL;
92     boolean javaValue = object.getBooleanValue();
93
94Although since in Lisp, any value other than NIL means "true", the
95use of Java equality it quite a bit easier and more optimal:
96
97    boolean javaValue = (object != Symbol.NIL);
98
99### LispObject is a list
100
101If LispObject is a list, it will have the type `Cons`.  One can then use
102the `copyToArray[]` to make things a bit more suitable for Java
103iteration.
104
105    LispObject result = interpreter.eval("'(1 2 4 5)");
106    if (result instanceof Cons) {
107      LispObject array[] = ((Cons)result.copyToArray());
108      ...
109    }
110   
111A more Lispy way to iterated down a list is to use the `cdr()` access
112function just as like one would traverse a list in Lisp:;
113
114    LispObject result = interpreter.eval("'(1 2 4 5)");
115    while (result != Symbol.NIL) {
116      doSomething(result.car());
117      result = result.cdr();
118    }
119
Note: See TracBrowser for help on using the repository browser.