[armedbear-cvs] r13335 - in trunk/abcl/doc: . manual

mevenson at common-lisp.net mevenson at common-lisp.net
Thu Jun 16 14:56:44 UTC 2011


Author: mevenson
Date: Thu Jun 16 07:56:43 2011
New Revision: 13335

Log:
Fold freestanding documentation into the Manual.

Deleted:
   trunk/abcl/doc/lisp-ffi.markdown
Modified:
   trunk/abcl/doc/manual/abcl.tex

Modified: trunk/abcl/doc/manual/abcl.tex
==============================================================================
--- trunk/abcl/doc/manual/abcl.tex	Wed Jun 15 22:53:00 2011	(r13334)
+++ trunk/abcl/doc/manual/abcl.tex	Thu Jun 16 07:56:43 2011	(r13335)
@@ -77,6 +77,141 @@
   Function.execute(args [...]) 
 \end{itemize}
 
+\subsubsection{Lisp FFI}
+
+FFI stands for "Foreign Function Interface", which is the way the
+contemporary Lisp world refers to methods of "calling out" from Lisp
+into "foreign" langauges and envrionments.  This document describes
+the various ways that one interacts with Lisp world of Abcl from Java,
+considering the hosted Lisp as the "Foreign Function" that needs to be
+"Interfaced".
+
+
+\subsubsubsection{Calling Lisp from Java}
+
+Note: As the entire ABCL Lisp system resides in the org.armedbear.lisp
+package the following code snippets do not show the relevant import
+statements in the interest of brevity.
+
+Per JVM, there can only ever be a single Lisp interpreter.  This is
+started by calling the static method `Interpreter.createInstance()`.
+
+\begin{code}{java}
+Interpreter interpreter = Interpreter.createInstance();
+\end{code}
+
+If this method has already been invoked in the lifetime of the current
+Java process it will return null, so if you are writing Java whose
+lifecycle is a bit out of your control (like in a Java servlet), a
+safer invocation pattern might be:
+
+\begin{code}{java}
+Interpreter interpreter = Interpreter.getInstance();
+if (interpreter == null) {
+  interpreter = Interpreter.createInstance();
+}
+\end{code}
+
+
+
+The Lisp `EVAL` primitive may be simply passed strings for evaluation,
+as follows
+
+\begin{code}{java}   
+String line = "(load \"file.lisp\")";
+LispObject result = interpreter.eval(line);
+\end{code}
+
+
+Notice that all possible return values from an arbitrary Lisp
+computation are collapsed into a single return value.  Doing useful
+further computation on the `LispObject` depends on knowing what the
+result of the computation might be, usually involves some amount
+of instanceof introspection, and forms a whole topic to itself
+(c.f. [Introspecting a LispObject](#introspecting)).  
+
+Using `EVAL` involves the Lisp interpreter.  Lisp functions may be
+directly invoked by Java method calls as follows.  One simply locates
+the package containing the symbol, then obtains a reference to the
+symbol, and then invokes the `execute()` method with the desired
+parameters.
+
+\begin{code}{java}   
+    interpreter.eval("(defun foo (msg) (format nil \"You told me '~A'~%\" msg))");
+    Package pkg = Packages.findPackage("CL-USER");
+    Symbol foo = pkg.findAccessibleSymbol("FOO"); 
+    Function fooFunction = (Function)foo.getSymbolFunction();
+    JavaObject parameter = new JavaObject("Lisp is fun!");
+    LispObject result = fooFunction.execute(parameter);
+    // How to get the "naked string value"?
+    System.out.prinln("The result was " + result.writeToString()); 
+\end{code}
+
+If one is calling an primitive function in the CL package the syntax
+becomes considerably simpler if we can locate the instance of
+definition in the ABCL source, we can invoke the symbol directly.  To
+tell if a `LispObject` contains a reference to a symbol.
+
+\begin{code}{java}   
+    boolean nullp(LispObject object) {
+      LispObject result = Primitives.NULL.execute(object);
+      if (result == NIL) {
+        return false;
+      }
+      return true;
+   }
+
+\end{code}
+
+/subsubsubsection{Introspecting a LispObject}
+
+We present various patterns for introspecting an an arbitrary
+`LispObject` which can represent the result of every Lisp evaluation
+into semantics that Java can meaniningfully deal with.
+
+/subsubsubsubsection{LispObject as \java{boolean}}
+
+If the LispObject a generalized boolean values, one can use
+\java{getBooleanValue()} to convert to Java:
+
+\begin{code}{java}
+     LispObject object = Symbol.NIL;
+     boolean javaValue = object.getBooleanValue();
+\end{code}
+
+Although since in Lisp, any value other than NIL means "true", the
+use of Java equality it quite a bit easier and more optimal:
+
+\begin{code}{java}
+    boolean javaValue = (object != Symbol.NIL);
+\end{code}
+
+/subsubsubsubsection{LispObject is a list}
+
+If LispObject is a list, it will have the type `Cons`.  One can then use
+the `copyToArray[]` to make things a bit more suitable for Java
+iteration.
+
+\begin{code}{java}
+    LispObject result = interpreter.eval("'(1 2 4 5)");
+    if (result instanceof Cons) {
+      LispObject array[] = ((Cons)result.copyToArray());
+      ...
+    }
+\end{code}
+    
+A more Lispy way to iterated down a list is to use the `cdr()` access
+function just as like one would traverse a list in Lisp:;
+
+\begin{code}{java}
+    LispObject result = interpreter.eval("'(1 2 4 5)");
+    while (result != Symbol.NIL) {
+      doSomething(result.car());
+      result = result.cdr();
+    }
+\end{code}
+
+
 \subsection{JAVA}
 
 % include autogen docs for the JAVA package.




More information about the armedbear-cvs mailing list