General Documentation 
 PS3
Revision: 1.20

Christian Queinnec
Université Paris 6 --- Pierre et Marie Curie
LIP6, 4 place Jussieu, 75252 Paris Cedex
France -- Email: Christian.Queinnec@lip6.fr

This document presents PS3I, the Persistent Server-Side Scheme Interpreter. PS3I is a nearly R4RS -compliant Scheme implementation, written in Java, multi-users, multi-threaded and aimed to run on (Web-)servers (as servlets). PS3I is pronounced ``psssssee'', has been written by Christian Queinnec and is available under Gnu General Public License .

1   History

In August 1996, I designed Jaja as a small runtime library, written in Java. This runtime was needed to run programs compiled by a Scheme to Java compiler obtained by retargetting a Scheme to C compiler described in [Que96a]. Slightly after, I expanded Jaja in order to also offer a Scheme interpreter written directly in Java (and not obtained through compilation since I wanted to teach the straight implementation of such an interpreter). This was the first public appearance of Jaja (whose name was coined by Emmanuel Chailloux : this name is a slang word for wine (usually not necessarily of a good quality)). Jaja could be used as a text-only interpreter and as an applet.

In August 1997, I added some new features: Jaja uses ``worlds'' to mean global environments. Multiple users may concurrently run a single (re-entrant) Jaja interpreter, without interference, within their own world. First, they ask for the creation of a world then, they send expressions to be evaluated in that world. The Jaja evaluation engine may be used via RMI so multiple users may also share a remote world. On the side of the language, I added some primitives for concurrency (fork and suicide, see [QD93]), for anomaly handling (monitor and diagnose see [Que96a]), dynamic variables (mainly to implement the dynamically-scoped functions that deal with the current input/output ports), a tower of macroexpanders (see [Que96b]), etc. All these things went in the distribution undocumented. On the back side, continuations only had a dynamic extent and Jaja still offers a very reduced tower of numbers.

During the year 1999, I was designing and programming an educational CDROM to teach the C programming language and I wanted to introduce the notion of ``path''. A path specifies which lectures notes and which exercises the student must read or perform. Since it was possible (and often suggested) to divert from the path (i.e., browse other pages, use a search engine or surf the web) I wanted to offer, in the navigation bar, a ``next'' button allowing the student to be reset on his/her path in just one click. When I realize that this ``next'' button was no more than a disguised invocation of the continuation of the path, I had a perfect solution. It allowed me to specify a path as a Scheme program and use the full power of the language. In other words, I was able to offer sophisticated paths not only sequential or conditional (a quizz may be viewed as a kind of conditional form) but also random or, freshly adapted or, history based paths, see [Que00b])

In February 1999, I then decide to write a new Scheme interpreter with non-restricted continuations in order to use continuations for a the next version of the CDROM [CQS00, Que00a]. This interpreter had to run as a servlet in the server hence its name of PS3I. I only reuse the code of the read function from Jaja and, inspired by SILK from Peter Norvig, I decided to make Scheme and Java more intimate. This turns to be an excellent idea as may be seen in the boot file. PS3I is the name of the new distribution and this report is the associated documentation.

2   How to get and run PS3I

The PS3I system is available via its home page . PS3I is available as a jar file containing source, compiled, javadoc and other documentation (such as the present one). PS3I requires other GPL packages to run, these are:

gnu.getopt 1.0.7 Aaron M. Renn Decode command line options
gnu.regexp 1.0.8 Wes Biggs Regular expression parser
log4j 0.9.0 Ceki Gülcü A configurable logger

Alternatively, you may download PS3I with these additional packages bundled in a single jar .

After download and since there is more than one way to use PS3I, please continue reading.

2.1   Textual mode

You may use PS3I as a text-only single-user interpreter that evaluates the expressions from its standard input stream and prints the results on its standard output stream. This interpreter stops when the input stream ends.

The PS3I system requires at least Java 1.2 to run (due to the immature nature of serialization as offered by Java 1.1). You may start a textual version of PS3I with one of the two next commands (see appendix A for options). While tested under Unix, it should probably be invoked similarly under DOS.
java -cp ps3i+.jar fr.lip6.qnc.ps3i.TopLevel 
java -jar ps3i+.jar 

If you use the raw ps3i.jar, it is required that the additional packages are available, for instance, in your CLASSPATH environment variable. This will look (in bash) as (where /JavaStuff is where you downloaded these additional package):
export CLASSPATH=${CLASSPATH}:/JavaStuff/gnu.regexp-1.0.8/classes
export CLASSPATH=${CLASSPATH}:/JavaStuff/java-getopt-1.0.8.jar
export CLASSPATH=${CLASSPATH}:`pwd`/ps3i-latest.jar
java fr.lip6.qnc.ps3i.TopLevel 

Without the right command options, you only have a bare interpreter that only knows of special forms and some rare technical functions.


? cons
*** PS3I Anomaly[fr.lip6.qnc.ps3i.EvaluationAnomaly](UnboundVariable)
Culprits:
[0]  cons

? ((lambda (x) x) 1)
= 1 

With the right options (see Section A), you may have access to the full R4RS language including concurrent features (see Section 3). If you evaluate a command that forks threads, final values will be printed as soon as they are obtained by the toplevel. The toplevel will restart a new iteration when all threads of the preceding iteration are finished. For instance:
PS3I? (* 2 (fork 3 4))
PS3I= 6
PS3I= 8
PS3I?    

The interpreter ends when there is nothing left to read (CTRL D, on Unix, may help there).

2.2   GUI mode

A second way to use the PS3I system is to use it from an applet.

This part will be completed. I initially thought of adapting the applet of Jaja but prefer to devote time to the servlet mode.

2.3   Servlet mode

The PS3I system may also be run in a servlet. Some servlets along which the PS3I and the LAML servlets, are provided in the PS3I distribution. These servlets comply with the servlet 2.2 specification , they were tested with Tomcat 3.0.

The LAML servlet serves pages written in Scheme. They are recognized since they are stored as files with the .laml extension.

The PS3I servlet offers a web-based interactive Scheme interpreter.

More on servlets in Section 5.

3   PS3I Features

PS3I is a regular Scheme interpreter, nearly fully R4RS compliant (nearly since I did not take care to verify). It offers non-restricted continuations (it is written in Java with explicit continuations i.e., in CPS style). PS3I is a pure interpreter that does not compile expressions before evaluating them therefore it is not very fast. Another major source of inefficiency comes from the binding with Java which uses a lot the Java reflection facilities.

There are at least two kind of predefined procedures in the Scheme programming language. Some procedures such as map or display may be entirely written in Scheme, others are written directly in the language used for the implementation of the interpreter. This may occur for various reasons: some primitives are the predicates, constructors or accessors of some particular data types (for instance vector?, vector, vector-ref, vector-set!), other primitives must be hard-coded to be not completely unefficient (this is the case for arithmetic functions for instance), yet others manage second-class entities (dynamic environments for instance).

I decided to write only a few primitives in Java. The read function is able to convert characters into S-expressions, it has to know about symbols, pairs, vectors etc. For bootstrap reasons, you must be able to read the Scheme definitions of the functions you miss so read is written in Java (and in fact, this is the only piece of code I reused from Jaja).

This attitude finally yields a very tiny Scheme interpreter where most of the initial library is defined in Scheme (the predefined primitive environment only contains current-output-port, current-input-port, dynamic, dynamic-bind, thread+offspring-get, thread+offspring-put, current-world, load, eval, expand, diagnose, apply, call/cc and some other arithmetic functions). This approach is reminiscent of the MetaVLisp project led by Emmanuel Saint-James circa 1986.

3.1   PS3I primitives types

All Java values are legal first-class PS3I values. Conversely, as in Silk, Scheme values should be, as much as possible, represented by Java values. Table 1 shows how Scheme values are mapped onto Java values.


() null
symbol fr.lip6.qnc.ps3i.Symbol
pair fr.lip6.qnc.ps3i.Pair
integer java.lang.Integer
real java.lang.Double
boolean java.lang.Boolean
string java.lang.String or java.lang.StringBuffer
vector java.lang.Object[]
procedure fr.lip6.qnc.ps3i.Invokable
continuation fr.lip6.qnc.ps3i.Continuable
output port java.io.Writer
input port fr.lip6.qnc.ps3i.SexprReadable

Table 1 : PS3I values wrt Java classes/interfaces


Note that, in Table 1, strings have two alternate representations (Silk chose char[] instead). This is not a problem since most Java methods may equally take String or StringBuffer as arguments. It also allows to turn implicitly quoted strings (such as "foo") into String whereas constructed strings (via make-string for instance) are instance of StringBuffer. These strings do have a lot more properties and capabilities than pure Scheme strings but this not forbidden by R4RS.

Note also that the interpreter uses interfaces for functions and continuations, this allow the user to create new classes implementing these interfaces whose instances are recognized as regular functions or continuations.

When started, PS3I may be told to read some boot files where it finds missing features. Currently the boot file (the fr/lip6/qnc/ps3i/ps3i.scm file) contains 216 functions including a traditional macro-expander. Among these functions are functions that simply name a Java method. A new syntax, #@kind:name@ or #@kind:name(name,name...)@, has been invented to name Java entities and to make direct use of them. The value of such an expression is something you may invoke from Scheme (technically this is an instance of the Invokable interface). The kind may be one of instanceof, send, new, newArray, field, method, staticMethod (case is insensitive for this parameter). The kind parameter specifies what type of invokable function will be returned: a predicate, a method invoker, a constructor, an accessor (a reader or a writer depending on the arity), a method or a static method.

Here is an excerpt from the standard boot file:
(set! boolean? #@instanceof:java.lang.Boolean@)
(set! cons     #@new:fr.lip6.qnc.ps3i.Pair@)
(set! car      #@method:fr.lip6.qnc.ps3i.Pair.getCar@)
(set! eq?      #@staticMethod:fr.lip6.qnc.ps3i.Function.eq@)
(set! eof-object?
      ((lambda (eof)
         (lambda (x) (eq? x eof)) )
       (#@field:fr.lip6.qnc.ps3i.SexprReadable.EOF@) ) ) 

The first definitions are simple. The eq? predicate is defined as a particular PS3I method because I don't know of any standard method in Java that corresponds to the == operator. The eq method just wraps this Java test. The last definition extracts, from an interface, a constant that signifies the end of a file.

When a method is overloaded, you may name the classes of the arguments in order to precise which method you want. For instance, since there are more than one method named write in the java.io.Writer class, the boot file contains:
(set! display 
      (lambda (o . port)
        ((lambda (port) 
           (#@method:java.io.Writer.write(java.lang.String)@
            port (if (null? o) 
                     "()"
                     (#@method:java.lang.Object.toString()@ o) ) ) )
         (if (pair? port) (car port) (current-output-port)) ) ) ) 

Currently, among primitive functions written in Java are integer->char, char->integer, make-string, open-input-file, open-output-file, eq?, =, <, +, -, *, /, modulo, remainder.

All other functions are defined in Scheme in the boot file. Half of them use the #@...@ syntax.

3.1.1   The #@...@ syntax

Here is the complete description of the #@...@ syntax. This syntax is equivalent to a symbol whose value is the intended Java object. The first word (before the colon) is case-insensitive; it specifies the type of the intended Java object. This word may only be one of instanceof, new, newArray, field, method, staticMethod or send.

After the colon are the parameters naming the intended Java object. Most often this is a fully qualified class or method name. The relevant class will be automatically loaded on the fly. If the name is ambiguous in case of overloaded methods for instance, then the fully qualified names of the class of the arguments are required for disambiguation. Any ambiguity in the #@...@ syntax yields a read error that is, these syntaxes are resolved at read-time (and not at run-time).

field fully qualified (static or not) field name
instanceof fully qualified class name
new fully qualified class name fully qualified argument class names
newArray fully qualified class name
method fully qualified method name fully qualified argument class names
staticMethod fully qualified static method name fully qualified argument class names
send method name

The #@field:...@ syntax names a (possibly static) field of a class. If the field is static then its value is a nullary accessor function that returns the value of the specified static field. If the field is not static then its value is a unary accessor function that takes an instance and returns the value of the specified field.

The #@instanceof:...@ syntax names a unary predicate that recognizes whether its argument belongs to the specified class.

The #@new:...@ syntax names a constructor function that will create one instance of the specified class. The generated constructor has the arity of the specified constructor. If the constructor is overloaded then it is necessary to disambiguate it otherwise a read-time error will be raised.

The #@newArray:...@ syntax names a constructor of an array of the specified class. The generated constructor is unary and takes the size of the array to create as argument.

The #@method:...@ syntax names a non static method from a fully qualified class. The generated function has the arity of the specified method plus one. It takes as first argument the instance that will act as the receiver and as next arguments the arguments of the method. If the method is overloaded then it is necessary to disambiguate it otherwise a read-time error will be raised.

Pay attention to the following Java peculiarity. Say A is a class with a method m and B is a subclass of A overriding m. Suppose b to be an instance of B then what is the meaning of the following expression ?
(#@method:A.m@ b
This form will in fact apply B.m since the reflection API does not allow to directly invoke a precise method on an instance. The m message is sent to b which in turn invokes the most specialized method that is B.m.

The #@staticMethod:...@ syntax names a static method from a fully qualified class. The generated function has the arity of the specified static method. If the static method is overloaded then it is necessary to disambiguate it otherwise a read-time error will be raised.

The #@send:...@ syntax takes a message name as second parameter. It generates a function that will send the specified message to a Java object with the other arguments as arguments. The precise (non static) method to invoke is looked up at run-time (this will raise an exception if no such method is found) according to the actual classes of the arguments.

Here is an example:
(set! substring
      (lambda (s start end)
        (if (#@instanceof:java.lang.String@ s)
            (#@send:substring@ s start end)
            (if (#@instanceof:java.lang.StringBuffer@ s)
                (#@send:substring@ s start end)
                (if (#@instanceof:fr.lip6.qnc.ps3i.ConcatenatedString@ o)
                    (#@send:substring@ s start end)
                    (error (quote substring) "Not a string" s) ) ) ) ) )

Disambiguation is problematic. Consider for instance a method foo(int) from a foo(Integer) method. The reflection layer confuses them.

3.1.2   The Silk syntax

Silk introduced another very good idea described in [AHN00] that of using the Java dot in Scheme names. Scheme symbols with a dot are interpreted specially. A slightly different version was adopted in PS3I and was first implemented by Arnaud Thiefaine and Benoit Blancard.

3.2   Hints about the implementation

PS3I also introduces some important interfaces that helps interfacing Scheme and Java (see also the javadoc generated documentation in the doc subdirectory). The main interfaces are: Other interfaces are more related to the evaluation process and the Scheme entities that contribute to it. These interfaces allow to change many aspects of the implementation while not touching the implementation of the interpretation process.

3.3   How to use PS3I as a component

If you want to put PS3I to work as a component, here is the basic theory.

  1. At the beginning, you have nothing but an intepreter that only knows of special forms and some rare functions.

  2. You create a World: a BaseWorld or a HandyWorld, the latter is easier but the former allows much more precise handling. You may create more than one World: they are normally separate (except if you do weird things such as sharing global environments). Worlds are serializable hence possibly persistent.

    A World represents a global environment.

  3. You create an Evaluation in that World with the createEvaluation method. An Evaluation is not serializable: it only contains some threads (paused or awaked) to evaluate some programs. These threads are created as you add S-expressions to evaluate, files to load, streams to evaluate to the Evaluation. You may create more than one Evaluation in one World.

    An Evaluation represents a bunch of transient activities (Java threads) that should run together. Many different Evaluations may run concurrently in a same World.

  4. You create an EvaluationListener to listen to the previous Evaluation. You may attach more than one listener to a given Evaluation. An Evaluation is listened to by an EvaluationListener that will be notified of any resulting value, uncaught exception or exhaustion of threads (i.e., when no more threads are running in the Evaluation).

  5. You finally run the Evaluation and get the results via the EvaluationListener. This will run the accumulated threads stored in the Evaluation.

    I will use a pool of threads soon to lessen the cost of threads creation.
The basic theory is complex due to the conjunct presence of continuations, concurrency and toplevel. You may alternatively use a HandyWorld that offers methods with reasonable defaults that allow you to easily evaluate expressions in a World without taking care of EvaluationListeners listening to Evaluations.

4   The PS3I language

PS3I roughly offers R4RS as well as some supplementary features.

4.1   Additional special forms

4.2   Additional functions

Some primitive non-R4RS functions exist as well.

4.3   File inclusion

A curious syntax exists that is processed at read-time. When the read function reads something like #`url` then this token is replaced by the content of the url. This syntax is convenient to share included files.

Some R4RS primitives do not exist in all contexts. For instance, reading and printing depend on the presence of standard input/output ports which are initially set up in the dynamic environment. These ports may be absent in some contexts (in the LAML servlet for instance). An input port should be a SexprReadable stream, an output port is a simple Writer stream and printing is done with the toString method.

Some functions such as load take an URL that may be relative. A configurable way to decode that relative URL exists. To be described.

5   Servlets

You need to configure your servlet container to accept the PS3I servlets and this depends on your servlet container.

I just tell how to do it with Tomcat 3.0. First download Tomcat 3.0 and install it. In the directory served by Tomcat, you will find a WEB-INF directory that contains a web.xml file and a lib subdirectory. Place the ps3i.jar file in that lib subdirectory then edit the web.xml file. There are two things to specify:
  1. introduce the servlets and their properties file,
  2. tell which pathnames trigger them.
For Tomcat 3.0, these lines have to be inserted in the web.xml file in between the <web-app> tags.


  <servlet>
    <servlet-name>LamlPage</servlet-name>
    <servlet-class>fr.lip6.qnc.ps3i.servlet.LAMLServlet</servlet-class>
    <description>Scheme Server Pages</description> 
    <init-param>
      <param-name>config.file</param-name>
      <param-value><!-- tell where is the properties file --></param-value>
      <description>The configuration for Laml pages</description>
    </init-param>
  </servlet>

  <servlet>
    <servlet-name>PS3IServlet</servlet-name>
    <servlet-class>fr.lip6.qnc.ps3i.servlet.PS3IServlet</servlet-class>
    <description>Web Interactive Scheme Interpreter</description> 
    <init-param>
      <param-name>config.file</param-name>
      <param-value><!-- tell where is the properties file --></param-value>
      <description>The configuration for the PS3I interpreter</description>
    </init-param>
  </servlet>

  <servlet-mapping>
    <servlet-name>LamlPage</servlet-name>
    <url-pattern>*.laml</url-pattern>
  </servlet-mapping>
  <servlet-mapping>
    <servlet-name>PS3IServlet</servlet-name>
    <url-pattern>/ps3i/*</url-pattern>
  </servlet-mapping> 

Starts the servlet container and check these servlets with the following URLs:


http://127.0.0.1:8080/ps3i/
http://127.0.0.1:8080/fr/lip6/qnc/ps3i/servlet/demo/demo.laml 

Adapt those URLs to the machine (127.0.0.1) where you run your servlet container and to the port the servlet container is listening to (8080).

5.1   The LAML servlet

The LAML servlet (standing for Lisp Abstracted Markup Language [Nør99] a concept invented by Kurt Nørmark ) serves files whose suffix is .laml. These files are written in Scheme and generates HTML. They are the equivalent of Java Server PagesTM except for the language which is Scheme and the evaluation mode which is interpretation.

All LAML pages are evaluated in a fresh World. This World pre-loads the R4RS environment plus the laml.scm utilities that nearly defines all the basic usual HTML tags. Look at this file if you want to add your own tags. The World specified by the way the servlet is configured is only built once afterthat it is made immutable and cloned for every served page.

Here is a small example of a LAML file where you see the overall style. HTML tags are produced via functions taking texts maybe preceded by some options (a keyword (that is, a symbol whose name ends with a colon) followed by a value). Texts may be any Java values that may be turned into a String.
(let ((the-title "Hello LAML"))
  (html
   (head (title the-title))
   (body bgcolor: 'beige
         (h1 the-title)
         "Hello. "
         (p align: 'center
            (a href: "http://videoc.lip6.fr/"
               "See the VideoC Project." ) ) ) ) ) 

Similarly to JSP, some predefined Scheme global variables are preset. These are resp. request, response, page, world, session, config, out and application to access the current request (and its parameters filled in by a form for instance), response (to set some additional headers for instance), the current servlet generating the page, the PS3I current world, the session object (to store information relative to the user), the servlet configuration object, the output stream and the servlet context object.

LAML pages are interpreted rather than compiled to Java as JSP are. It is therefore easier to tune up LAML pages since they are reloaded at every change (their expanded Scheme code is cached to improve speed).

5.2   The XML servlet

This servlet serves files with an .xml extension as if they were written in Scheme. This is based on the fact that an XML file has the structure of an S-expression with merrily-named parentheses. First the file is read as an S-expression, then that S-expression is evaluated and yield an HTML string that it sent back to the HTTP client. Pretty simple, is not it ?

The XML servlet first creates an immutable World according to the way it is configured. This immutable World is made immutable then cloned for every served pages. This World should contain the libraries that are required to process the S-expressions.

An XML paragraph starting with an <tag> and ending with the appropriate tag is read as an S-expression whose car is the symbol tag. If there are some attributes in a tag, the name of the attribute is converted into a keyword (a symbol with a trailing colon) followed by the value of the attribute. Here follows an example of a conversion.


<start a="12 3">
  <in><foo>bar</foo>
      <foo a="blah" b="blah">foo</foo></in>
</start> 

This xml snippet is converted into the rather compact S-expression:


(start a: "12 3"
 (in (foo "bar")
     (foo a: "blah" b: "blah") ) ) 

5.3   The PS3I servlet

This servlet provides the PS3I interpreter as a servlet. It analyses URLs and evaluates an expression or resumes a continuation as told. Suppose that this servlet is triggered by the /ps3i path then the two following URLs are possible: Parameters may be set in line (if they are not too long) in the URL (submitted via the GET method) as follows:
http://localhost:8080/ps3i/eval?expression=(list+1+2) 
They may be more conveniently sent (via the POST method) from a form (use a LAML page for that).

For any evaluation request, a fresh World is created with the R4RS environment. For a resumption request, the world of the creator of the continuation is re-used therefore it is possible to share information through the global environment of the current World (or in the continuation itself). It is possible to use the continuation more than once even in parallel, see [Que00b] for more theoretical considerations.

A demonstration is present in the distribution, just ask for the /ps3i url.

5.4   A Commented Example

The following example uses LAML pages as well as the PS3I servlet. It may be obtained with the following URL (details may change across distributions):
http://127.0.0.1:19991/fr/lip6/qnc/ps3i/servlet/intro.laml 

When connecting to the PS3I servlet, the first screen may be seen on Figure 1. You have to wait a little for the predefined libraries to be loaded.



Figure 1 : First screen


Just hit the ``eval'' button to start the evaluation. The evaluation is a regular factorial except that
  1. it requests the number on which to apply the factorial function,
  2. the factorial of 1 is defined to be read from the user,
  3. a trace is produced before and after evaluation.
You should then get Figure 2.



Figure 2 : Second screen


Suppose you want to know the factorial of 7, you just type that number and resume the evaluation with the ``resume'' button. You should obtain a third screen similar to the one in Figure 3.



Figure 3 : Third screen


Note now the accumulated printing produced by the trace. It is now time to tell PS3I what is the value of (fact 1). Just for fun, 2 is typed and the ``resume'' button is hit. This yields to Figure 4.



Figure 4 : Fourth screen


The final result is 10080. Note the accumulated printing produced by the final trace.

So far, this example is simple but since PS3I uses full continuations you may use the ``back'' button of your browser and return to Figure 3, change your answer and watch for the new answer. Furthermore if you use the old Mosaic browser or MS IExplorer, you may clone the final window, perform ``back'' on it, and ``back, back'' on the cloned window then, with a really quick mouse move, click ``resume'' on the two windows: you now have two concurrent requests in the server. Therefore your browser is a new special form (alike fork) that creates concurrency. Of course the ``stop'' button is kind of analog to the suicide function. In both cases, concurrency and task creation/destruction is a consequence of the features of your browser. Never thought of a browser as a concurrency operator !?

I also defend that these uses of continuations form very good examples of what continuations are. Moreover, the second example is the only interesting case I have been looking for years of a continuation which is invoked more than once in an understandable way (by me and by students).

To have full continuations on the server-side is really desirable for several reasons.
  1. to have continuations gives a default behavior to the server when users come back and resumes old computations,
  2. to have a fork special form along with continuations allow to protect the code from the weird effects of browser-induced concurrency or multiple returns,
  3. to have first-class continuations allows the programmer to reason at the right level and write whatever behavior is thought useful. It is possible to always accept the last answer to a question and kill the threads that depend on previous answers. It is possible to only accept the first answer and ignore any other answer. These behaviors may be appropriately wrapped inside macros.

6   Conclusions

PS3I is not fast but offers full continuations, persistent global environments, servlet support, Scheme server pages, etc. See the demos bundled with PS3I!

Références

[AHN00]
Kenneth R Anderson, Timothy J Hickey, and Peter Norvig. Silk -- a playful blend of scheme and java. In Matthias Felleisen, editor, Proceedings of the Workshop on Scheme and Functional Programming, number Rice University COMP TR00-368, pages 13--22, Montréal (Canada), September 2000.

[CQS00]
Claire Cazes, Christian Queinnec, and Chantal Steinberg. Enseignement du langage C à l'aide d'un cédérom et d'un site -- Mise en oeuvre et observation. Troyes (France), Atelier TICE, October 2000.

[MQ97]
Luc Moreau and Christian Queinnec. Design and semantics of quantum: a language to control resource consumption in distributed computing. In Usenix Conference on Domain Specific Language, DSL'97, pages 183--197, Santa-Barbara (California, USA), October 1997.

[Nør99]
Kurt Nørmark. Using lisp as a markup language -- the laml approach. In European Lisp User Group Meeting, Amsterdam, Holland, 1999.

[QD93]
Christian Queinnec and David De Roure. Design of a concurrent and distributed language. In Robert H Halstead Jr and Takayasu Ito, editors, Parallel Symbolic Computing: Languages, Systems, and Applications, (US/Japan Workshop Proceedings), volume Lecture Notes in Computer Science 748, pages 234--259, Boston (Massachussetts USA), October 1993.

[Que96a]
Christian Queinnec. Lisp in Small Pieces. Cambridge University Press, 1996.

[Que96b]
Christian Queinnec. Macroexpansion reflective tower. In Gregor Kiczales, editor, Proceedings of the Reflection'96 Conference, pages 93--104, San Francisco (California, USA), April 1996.

[Que00a]
Christian Queinnec. Enseignement du langage C à l'aide d'un cédérom et d'un site -- Architecture logicielle. In Colloque international -- Technologie de l'Information et de la Communication dans les Enseignements d'ingénieurs et dans l'industrie -- TICE 2000, pages 93--102, Troyes (France), October 2000. CNED.

[Que00b]
Christian Queinnec. The influence of browsers on evaluators or, continuations to program web servers. In ICFP '2000 -- International Conference on Functional Programming, pages 23--33, Montreal (Canada), September 2000.

A   Textual command options

When the PS3I interpreter is run in textual mode, several command options are available to customize its behavior. Options are processed with the gnu.getopt package from Aaron M. Renn that is, options may appear anywhere, they will be handled first.

The textual version of PS3I creates a single World where all successive expressions are evaluated.

There are a number of other options to trace evaluation, they will probably disappear as they stand currently. Options are processed from left to right.

Non option command arguments are considered as URLs that should be loaded initially by the interpreter from left to right. For instance, if you don't like the default boot file (fr/lip6/qnc/ps3i/ps3i.scm that defines most of Scheme R4RS features), you may load your own by telling:


java fr.lip6.qnc.ps3i.TopLevel file:my/boot/file.scm 

A.1   Examples

Some examples are in order (I'll vary the way java is started with -cp or -jar). The following command starts a bare PS3I:


java -cp ps3i-latest.jar fr.lip6.qnc.ps3i.TopLevel 

Pay attention to the fact that the bare interpreter knows nearly no primitives (see Section 4) and only has a definition of expand that behaves as the identity (this variable will be patched at boot-time with a more interesting definition).

The next command starts a sort-of R4RS PS3I:


java -jar ps3i.jar -t PS3I.textual -r PS3I.properties 

B   Customization

The PS3I system may be customized with a Configuration. This file may define the prompts, the boot files, the banners and the error messages. These messages may be tailored for different language. See the PS3I.properties file at the root of ps3i.jar. If you translate it into another language, send me your translation so I can add it to a future release.

The PS3I system has been written to be highly customizable. You may define of course new functions in Scheme on the fly, you may invoke Java methods from any class (this will load the class if needed), you will even (soon) adjoin new special forms on the fly!

Here is the beginning of the ps3i.properties file:
01 PS3I.search.path.0=disk <%user.dir%><%file.separator%>
02 PS3I.textual.prelude.0=file:fr/lip6/qnc/ps3i/ps3i.scm
03 PS3I.textual.prelude.1=file:fr/lip6/qnc/ps3i/nought.scm
04 toplevel.promptin=PS3I? 
05 toplevel.promptout=PS3I= 
06 toplevel.bannerin=PS3I: The Persistent Server-Side Scheme Interpreter
07 toplevel.bannerout=;;;  end of PS3I
08 # Customized error messages:
09 UnboundVariable=The variable {0} has no value 

Suppose that the name of the World is PS3I then properties prefixed with a ``PS3I.'' prefix will customize the interpreter.

Line 1, the PS3I.search.path properties customize where to search relatives pathnames. See the documentation of the Configuration package for details. Here it says that relative filenames should be searched in the user's HOME directory.

Lines 2-3 specifies the files to be pre-loaded in the current World.

Lines 4-7 specifies the prompts and banners of the intepreter.

Line 9 shows how one error message may be customized. There are a number of error messages!



 


Ce document a été traduit de LATEX par HEVEA.