[armedbear-cvs] r12560 - in trunk/abcl/doc: . design/pathnames
Mark Evenson
mevenson at common-lisp.net
Thu Mar 18 10:15:54 UTC 2010
Author: mevenson
Date: Thu Mar 18 06:15:53 2010
New Revision: 12560
Log:
More work on standalone documentation.
Added:
trunk/abcl/doc/debugging-internals.markdown
trunk/abcl/doc/lisp-ffi.markdown
Removed:
trunk/abcl/doc/misc.markdown
Modified:
trunk/abcl/doc/design/pathnames/jar-pathnames.markdown
trunk/abcl/doc/slime.markdown
Added: trunk/abcl/doc/debugging-internals.markdown
==============================================================================
--- (empty file)
+++ trunk/abcl/doc/debugging-internals.markdown Thu Mar 18 06:15:53 2010
@@ -0,0 +1,5 @@
+Notes on debugging ABCL
+
+* Need to set *PRINT-CIRCLE* to T when examining the structures in
+ jvm.lisp.
+
Modified: trunk/abcl/doc/design/pathnames/jar-pathnames.markdown
==============================================================================
--- trunk/abcl/doc/design/pathnames/jar-pathnames.markdown (original)
+++ trunk/abcl/doc/design/pathnames/jar-pathnames.markdown Thu Mar 18 06:15:53 2010
@@ -1,45 +1,50 @@
JARs and JAR entries in ABCL
============================
-Mark Evenson
-Created: 09 JAN 2010
-Modified: 16 MAR 2010
+ Mark Evenson
+ Created: 09 JAN 2010
+ Modified: 16 MAR 2010
Notes towards sketching an implementation of "jar:" references to be
-contained in PATHNAMEs within ABCL.
+contained in Common Lisp `PATHNAMEs` within ABCL.
Goals
-----
-1. Use Common Lisp pathnames to refer to entries in a JAR file.
+1. Use Common Lisp pathnames to refer to entries in a jar file.
-2. Use 'jar:' schema as documented in java.net.JarURLConnection for
+2. Use `'jar:'` schema as documented in [`java.net.JarURLConnection`][jarURLConnection] for
namestring representation.
-An entry in a JAR file:
- #p"jar:file:baz.jar!/foo"
+ An entry in a JAR file:
+
+ #p"jar:file:baz.jar!/foo"
-A JAR file:
- #p"jar:file:baz.jar!/"
+ A JAR file:
+
+ #p"jar:file:baz.jar!/"
-A JAR file accessible via URL
- #p"jar:http://example.org/abcl.jar!/"
+ A JAR file accessible via URL
-An entry in a ABCL FASL in a URL accessible JAR file
- #p"jar:jar:http://example.org/abcl.jar!/foo.abcl!/foo-1.cls"
+ #p"jar:http://example.org/abcl.jar!/"
-3. MERGE-PATHNAMES working for JAR entries in the following use cases:
+ An entry in a ABCL FASL in a URL accessible JAR file
- (merge-pathnames "foo-1.cls" "jar:jar:file:baz.jar!/foo.abcl!/foo._")
- "jar:jar:file:baz.jar!/foo.abcl!/foo-1.cls"
+ #p"jar:jar:http://example.org/abcl.jar!/foo.abcl!/foo-1.cls"
+
+[jarUrlConnection]: http://java.sun.com/javase/6/docs/api/java/net/JarURLConnection.html
- (merge-pathnames "foo-1.cls" "jar:file:foo.abcl!/")
- "jar:file:foo.abcl!/foo-1.cls"
+3. `MERGE-PATHNAMES` working for jar entries in the following use cases:
-4. TRUENAME and PROBE-FILE working with "jar:"
+ (merge-pathnames "foo-1.cls" "jar:jar:file:baz.jar!/foo.abcl!/foo._")
+ ==> "jar:jar:file:baz.jar!/foo.abcl!/foo-1.cls"
-4.1 TRUENAME cannonicalizing the JAR reference.
+ (merge-pathnames "foo-1.cls" "jar:file:foo.abcl!/")
+ ==> "jar:file:foo.abcl!/foo-1.cls"
+
+4. TRUENAME and PROBE-FILE working with "jar:" with TRUENAME
+ cannonicalizing the JAR reference.
5. DIRECTORY working within JAR files (and within JAR in JAR).
@@ -100,163 +105,163 @@
An incomplete BNF of the syntax of JAR PATHNAME would be:
- JAR-PATHNAME ::= "jar:" URL "!/" [ ENTRY ]
+ JAR-PATHNAME ::= "jar:" URL "!/" [ ENTRY ]
+
+ URL ::= <URL parsable via java.net.URL.URL()>
+ | JAR-FILE-PATHNAME
- URL ::= <URL parsable via java.net.URL.URL()>
- | JAR-FILE-PATHNAME
-
- JAR-FILE-PATHNAME ::= "jar:" "file:" JAR-NAMESTRING "!/" [ ENTRY ]
+ JAR-FILE-PATHNAME ::= "jar:" "file:" JAR-NAMESTRING "!/" [ ENTRY ]
- JAR-NAMESTRING ::= ABSOLUTE-FILE-NAMESTRING
- | RELATIVE-FILE-NAMESTRING
+ JAR-NAMESTRING ::= ABSOLUTE-FILE-NAMESTRING
+ | RELATIVE-FILE-NAMESTRING
- ENTRY ::= [ DIRECTORY "/"]* FILE
+ ENTRY ::= [ DIRECTORY "/"]* FILE
### Notes
-1. ABSOLUTE-FILE-NAMESTRING and RELATIVE-FILE-NAMESTRING use the
+1. `ABSOLUTE-FILE-NAMESTRING` and `RELATIVE-FILE-NAMESTRING` use the
local filesystem conventions, meaning that on Windows this could
-contain '\' as the directory separator, while an ENTRY always uses '/'
+contain '\' as the directory separator, while an `ENTRY` always uses '/'
to separate directories within the jar proper.
Use Cases
---------
-// UC1 -- JAR
-pathname: {
- namestring: "jar:file:foo/baz.jar!/"
- device: (
- pathname: {
- device: "jar:file:"
- directory: (:RELATIVE "foo")
- name: "baz"
- type: "jar"
+ // UC1 -- JAR
+ pathname: {
+ namestring: "jar:file:foo/baz.jar!/"
+ device: (
+ pathname: {
+ device: "jar:file:"
+ directory: (:RELATIVE "foo")
+ name: "baz"
+ type: "jar"
+ }
+ )
}
- )
-}
-// UC2 -- JAR entry
-pathname: {
- namestring: "jar:file:baz.jar!/foo.abcl"
- device: ( pathname: {
- device: "jar:file:"
- name: "baz"
- type: "jar"
- })
- name: "foo"
- type: "abcl"
-}
-
-
-// UC3 -- JAR file in a JAR entry
-pathname: {
- namestring: "jar:jar:file:baz.jar!/foo.abcl!/"
- device: (
- pathname: {
- name: "baz"
- type: "jar"
- }
+ // UC2 -- JAR entry
pathname: {
+ namestring: "jar:file:baz.jar!/foo.abcl"
+ device: ( pathname: {
+ device: "jar:file:"
+ name: "baz"
+ type: "jar"
+ })
name: "foo"
type: "abcl"
- }
- )
-}
-
-// UC4 -- JAR entry in a JAR entry with directories
-pathname: {
- namestring: "jar:jar:file:a/baz.jar!/b/c/foo.abcl!/this/that/foo-20.cls"
- device: (
- pathname {
- directory: (:RELATIVE "a")
- name: "bar"
- type: "jar"
}
- pathname {
- directory: (:RELATIVE "b" "c")
- name: "foo"
- type: "abcl"
+
+
+ // UC3 -- JAR file in a JAR entry
+ pathname: {
+ namestring: "jar:jar:file:baz.jar!/foo.abcl!/"
+ device: (
+ pathname: {
+ name: "baz"
+ type: "jar"
+ }
+ pathname: {
+ name: "foo"
+ type: "abcl"
+ }
+ )
}
- )
- directory: (:RELATIVE "this" "that")
- name: "foo-20"
- type: "cls"
-}
-
-// UC5 -- JAR Entry in a JAR Entry
-pathname: {
- namestring: "jar:jar:file:a/foo/baz.jar!/c/d/foo.abcl!/a/b/bar-1.cls"
- device: (
+
+ // UC4 -- JAR entry in a JAR entry with directories
pathname: {
- directory: (:RELATIVE "a" "foo")
- name: "baz"
- type: "jar"
+ namestring: "jar:jar:file:a/baz.jar!/b/c/foo.abcl!/this/that/foo-20.cls"
+ device: (
+ pathname {
+ directory: (:RELATIVE "a")
+ name: "bar"
+ type: "jar"
+ }
+ pathname {
+ directory: (:RELATIVE "b" "c")
+ name: "foo"
+ type: "abcl"
+ }
+ )
+ directory: (:RELATIVE "this" "that")
+ name: "foo-20"
+ type: "cls"
}
+
+ // UC5 -- JAR Entry in a JAR Entry
pathname: {
- directory: (:RELATIVE "c" "d")
- name: "foo"
- type: "abcl"
+ namestring: "jar:jar:file:a/foo/baz.jar!/c/d/foo.abcl!/a/b/bar-1.cls"
+ device: (
+ pathname: {
+ directory: (:RELATIVE "a" "foo")
+ name: "baz"
+ type: "jar"
+ }
+ pathname: {
+ directory: (:RELATIVE "c" "d")
+ name: "foo"
+ type: "abcl"
+ }
+ )
+ directory: (:ABSOLUTE "a" "b")
+ name: "bar-1"
+ type: "cls"
}
- )
- directory: (:ABSOLUTE "a" "b")
- name: "bar-1"
- type: "cls"
-}
-
-// UC6 -- JAR entry in a http: accessible JAR file
-pathname: {
- namestring: "jar:http://example.org/abcl.jar!/org/armedbear/lisp/Version.class",
- device: (
- "http://example.org/abcl.jar"
+
+ // UC6 -- JAR entry in a http: accessible JAR file
pathname: {
- directory: (:RELATIVE "org" "armedbear" "lisp")
- name: "Version"
- type: "class"
- }
-}
-
-// UC7 -- JAR Entry in a JAR Entry in a URL accessible JAR FILE
-pathname: {
- namestring "jar:jar:http://example.org/abcl.jar!/foo.abcl!/foo-1.cls"
- device: (
- "http://example.org/abcl.jar"
- pathname: {
- name: "foo"
- type: "abcl"
- }
- )
- name: "foo-1"
- type: "cls"
-}
-
-// UC8 -- JAR in an absolute directory
-
-pathame: {
- namestring: "jar:file:/a/b/foo.jar!/"
- device: (
- pathname: {
- directory: (:ABSOLUTE "a" "b")
+ namestring: "jar:http://example.org/abcl.jar!/org/armedbear/lisp/Version.class",
+ device: (
+ "http://example.org/abcl.jar"
+ pathname: {
+ directory: (:RELATIVE "org" "armedbear" "lisp")
+ name: "Version"
+ type: "class"
+ }
+ }
+
+ // UC7 -- JAR Entry in a JAR Entry in a URL accessible JAR FILE
+ pathname: {
+ namestring "jar:jar:http://example.org/abcl.jar!/foo.abcl!/foo-1.cls"
+ device: (
+ "http://example.org/abcl.jar"
+ pathname: {
+ name: "foo"
+ type: "abcl"
+ }
+ )
+ name: "foo-1"
+ type: "cls"
+ }
+
+ // UC8 -- JAR in an absolute directory
+
+ pathame: {
+ namestring: "jar:file:/a/b/foo.jar!/"
+ device: (
+ pathname: {
+ directory: (:ABSOLUTE "a" "b")
+ name: "foo"
+ type: "jar"
+ }
+ )
+ }
+
+ // UC9 -- JAR in an relative directory with entry
+ pathname: {
+ namestring: "jar:file:a/b/foo.jar!/c/d/foo.lisp"
+ device: (
+ directory: (:RELATIVE "a" "b")
+ name: "foo"
+ type: "jar"
+ )
+ directory: (:ABSOLUTE "c" "d")
name: "foo"
- type: "jar"
- }
- )
-}
-
-// UC9 -- JAR in an relative directory with entry
-pathname: {
- namestring: "jar:file:a/b/foo.jar!/c/d/foo.lisp"
- device: (
- directory: (:RELATIVE "a" "b")
- name: "foo"
- type: "jar"
- )
- directory: (:ABSOLUTE "c" "d")
- name: "foo"
- type: "lisp
-}
+ type: "lisp
+ }
History
@@ -267,37 +272,37 @@
pathname, the device pathname contained the location of the jar.
In the analysis of the desire to treat jar pathnames as valid
-locations for LOAD, we determined that we needed a "double" pathname
+locations for `LOAD`, we determined that we needed a "double" pathname
so we could refer to the components of a packed FASL in jar. At first
we thought we could support such a syntax by having the device
pathname's device refer to the inner jar. But with in this use of
-PATHNAMEs linked by the DEVICE field, we found the problem that UNC
-path support uses the DEVICE field so JARs located on UNC mounts can't
-be referenced. via '\\'.
+`PATHNAME`s linked by the `DEVICE` field, we found the problem that UNC
+path support uses the `DEVICE` field so JARs located on UNC mounts can't
+be referenced. via '\\', i.e.
- i.e. jar:jar:file:\\server\share\a\b\foo.jar!/this\that!/foo.java
+ jar:jar:file:\\server\share\a\b\foo.jar!/this\that!/foo.java
would not have a valid representation.
-So instead of having DEVICE point to a PATHNAME, we decided that the
-DEVICE shall be a list of PATHNAMES, so we would have:
+So instead of having `DEVICE` point to a `PATHNAME`, we decided that the
+`DEVICE` shall be a list of `PATHNAME`, so we would have:
+
+ pathname: {
+ namestring: "jar:jar:file:\\server\share\foo.jar!/foo.abcl!/"
+ device: (
+ pathname: {
+ host: "server"
+ device: "share"
+ name: "foo"
+ type: "jar"
+ }
+ pathname: {
+ name: "foo"
+ type: "abcl"
+ }
+ }
-pathname: {
- namestring: "jar:jar:file:\\server\share\foo.jar!/foo.abcl!/"
- device: (
- pathname: {
- host: "server"
- device: "share"
- name: "foo"
- type: "jar"
- }
- pathname: {
- name: "foo"
- type: "abcl"
- }
-}
-
-Although there is a fair amount of special logic inside Pathname.java
-itself in the resulting implementation, the logic in Load.java seems
-to have been considerably simplified.
+Although there is a fair amount of special logic inside `Pathname.java`
+itself in the resulting implementation, the logic in `Load.java` seems
+to have been considerably simplified.
Added: trunk/abcl/doc/lisp-ffi.markdown
==============================================================================
--- (empty file)
+++ trunk/abcl/doc/lisp-ffi.markdown Thu Mar 18 06:15:53 2010
@@ -0,0 +1,119 @@
+Lisp FFI
+========
+
+ Mark Evenson
+ Created: 15-FEB-2010
+ Modified: 18-MAR-2010
+
+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".
+
+# Lisp FFI
+
+## 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()`.
+
+ Interpreter interpreter = Interpreter.createInstance();
+
+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:
+
+ Interpreter interpreter = Interpreter.getInstance();
+ if (interpreter == null) {
+ interpreter = Interpreter.createInstance();
+ }
+
+The Lisp `EVAL` primitive may be simply passed strings for evaluation,
+as follows
+
+ String line = "(load \"file.lisp\")";
+ LispObject result = interpreter.eval(line);
+
+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.
+
+ 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());
+
+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.
+
+ boolean nullp(LispObject object) {
+ LispObject result = Primitives.NULL.execute(object);
+ if (result == NIL) {
+ return false;
+ }
+ return true;
+ }
+
+<a name="interpreting"/>
+## 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.
+
+### LispObject as boolean
+
+If the LispObject a generalized boolean values, one can use
+`getBooleanValue()` to convert to Java:
+
+ LispObject object = Symbol.NIL;
+ boolean javaValue = object.getBooleanValue();
+
+Although since in Lisp, any value other than NIL means "true", the
+use of Java equality it quite a bit easier and more optimal:
+
+ boolean javaValue = (object != Symbol.NIL);
+
+### 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.
+
+ LispObject result = interpreter.eval("'(1 2 4 5)");
+ if (result instanceof Cons) {
+ LispObject array[] = ((Cons)result.copyToArray());
+ ...
+ }
+
+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:;
+
+ LispObject result = interpreter.eval("'(1 2 4 5)");
+ while (result != Symbol.NIL) {
+ doSomething(result.car());
+ result = result.cdr();
+ }
+
Modified: trunk/abcl/doc/slime.markdown
==============================================================================
--- trunk/abcl/doc/slime.markdown (original)
+++ trunk/abcl/doc/slime.markdown Thu Mar 18 06:15:53 2010
@@ -1,9 +1,9 @@
SLIME
=====
- Author: Mark Evenson
- Created: 16-MAR-2010
- Modified: 16-MAR-2010
+ Author: Mark Evenson
+ Created: 16-MAR-2010
+ Modified: 18-MAR-2010
SLIME is divided conceptually in two parts: the "swank" server process
which runs in the native Lisp and the "slime" client process running
@@ -24,12 +24,13 @@
One first locates the SLIME directory on the filesystem. In the code
that follows, the SLIME top level directory is assumed to be
-"~/work/slime", so adjust this value to your local value as you see
+`"~/work/slime"`, so adjust this value to your local value as you see
fit.
Then one configures Emacs with the proper initialization hooks by
adding code something like the following to "~/.emacs":
+ :::common-lisp
(add-to-list 'load-path "~/work/slime")
(setq slime-lisp-implementations
'((abcl ("~/work/abcl/abcl"))
@@ -39,28 +40,29 @@
(slime-setup '(slime-fancy slime-asdf slime-banner))
One further need to customize the setting of
-SLIME-LISP-IMPLEMENTATIONS to the location(s) of the Lisp(s) you wish to
+`SLIME-LISP-IMPLEMENTATIONS` to the location(s) of the Lisp(s) you wish to
invoke via SLIME. The value is list of lists of the form
(SYMBOL ("/path/to/lisp"))
where SYMBOL is a mnemonic for the Lisp implementation, and the string
-"/path/to/lisp" is the absolute path of the Lisp implementation that
+`"/path/to/lisp"` is the absolute path of the Lisp implementation that
SLIME will associate with this symbol. In the example above, I have
defined three implementations, the main abcl implementation, a version
that corresponds to the latest version from SVN invoked by
-"~/work/abcl.svn/abcl", and a version of SBCL.
+`"~/work/abcl.svn/abcl"`, and a version of SBCL.
-To start SLIME one simply issues M-x slime from Emacs. This will
+To start SLIME one simply issues `M-x slime` from Emacs. This will
start the first entry in the SLIME-LISP-IMPLEMENTATIONS list. If you
-wish to start a subsequent Lisp, prefix the invocation via M-u
-(i.e. M-u M-x slime). This will present an interactive chooser over
-all symbols contained in SLIME-LISP-IMPLEMENTATIONS.
+wish to start a subsequent Lisp, prefix the Emacs invocation with a
+negative argument (i.e. `C-- M-x slime`). This will present an
+interactive chooser over all symbols contained in
+`SLIME-LISP-IMPLEMENTATIONS`.
After you invoke SLIME, you'll see a buffer open up named
-*inferior-lisp* where the Lisp image is started up, the required swank
+`*inferior-lisp*` where the Lisp image is started up, the required swank
code is complied and then loaded, finally, you'll see the "flying
-letters" resolving itself to a "CL-USER>" prompt with an inspiration
+letters" resolving itself to a `"CL-USER>"` prompt with an inspiration
message in the minibuffer. Your initiation to SLIME has begun...
@@ -71,16 +73,16 @@
from a Lisp image. One merely needs to change *SLIME-DIRECTORY* to
point to the top directory of the server process.
-`
+ :::commmon-lisp
(defvar *slime-directory* #p"~/work/slime/") ;; Don't forget trailing slash
(load (merge-pathnames "swank-loader.lisp" *slime-directory*) :verbose t)
(swank-loader:init)
(swank:start-server "/tmp/swank.port") ;; remove if you don't want
;; swank to start listening for connections.
-`
+
When this code finishes executing, an integer representing the port on
-which the server starts will be written to '/tmp/swank.port' and also
-returned as the result of evaluating SWANK:START-SERVER. One may
-connect to this port via issuing M-x slime-connect in Emacs.
+which the server starts will be written to `'/tmp/swank.port'` and also
+returned as the result of evaluating `SWANK:START-SERVER`. One may
+connect to this port via issuing `M-x slime-connect` in Emacs.
More information about the armedbear-cvs
mailing list