[Openmcl-devel] Using OpenMCL as a shell scripting interpreter

Gary Byers gb at clozure.com
Tue Mar 30 21:15:35 PST 2004

On Tue, 30 Mar 2004, Stonewall Ballard wrote:

> My next task is to figure out how to pass command-line arguments into
> the script. openmcl itself seems rather unhappy with extra arguments. I
> guess I need to add a switch that takes the rest of the args and binds
> them to *argv* or somesuch.
> Gary, is that likely to be difficult, or interfere with anything else?

There's a not-quite-mature notion of an "application object" - an object
of type CCL::APPLICATION that's the value of CCL:*APPLICATION* - that's
supposed to define application-specific behavior (how command-line args
are parsed, how errors are reported, etc.)  The default value of
which is a subclass of CCL::APPLICATION.

A method called CCL::PARSE-APPLICATION-ARGUMENTS processes the actual
args (with anything that has to be handled by the kernel removed) and
tries to "normalize" them, in terms of the actual arguments that the
application class recognizes/supports.  CCL::PARSE-APPLICATION-ARGUMENTS
returns 3 values:

 1) A keyword indicating the type of syntax error (duplicate/unknown
options, missing arguments) that occurred, or NIL.
 2) An alist of normalized option keywords and their associated values
 3) A list of arguments that weren't associated with any option.

The return values from CCL::PARSE-APPLICATION-ARGUMENTS are provided
as arguments to the method CCL::PROCESS-APPLICATION-ARGUMENTS.  The
CCL::PROCESS-APPLICATION-ARGUMENTS signals an error if any non-option
args were present (this is the source of the unhappiness.)

handles --help and --version, on the theory that these might be common
to many different classes of application.

Even though I think that some of the implementation/organization of this
stuff could stand a lot of improvement, I think that this is mostly
the right idea: an application that's intended to process shell scripts
is probably different in many ways from one that's intended to enter
a REPL and interact with a user.

? (specializer-direct-methods (find-class 'lisp-development-system))

yields 4 entries that an instance of SCRIPTING-APPLICATION might want
to implement differently:

(defclass scripting-application (application)
  ((command-line-arguments ...))  ; kind of awkward to initialize this way

(defmethod process-application-arguments ((app scripting-application)
                                          error-flag alist others))

(defmethod toplevel-function ((app scripting-application) &optional init-file)
  "return a function of 0 or 1 arguments that's called when a saved image
   starts up.  If the concept of an init file is meaningful, the
   init-file argument may be non-NULL.")

(defmethod application-init-file ((app scripting-application))
   "return a pathname or NIL.")

(defmethod application-error ((app scripting-application) condition frame-ptr)
  "handle an error or other condition.  FRAME-PTR is a stack-frame pointer
   that some internal functions use to identify the function in which the
   error occurred and to provide context for backtrace.")

After defining the class and these methods, the canonical way of making
a new kind of application is via SAVE-APPLICATION:

? (save-application "scripting.image" :application-class 'scripting-application)

That image should behave more like a SCRIPTING-APPLICATION and less like
a LISP-DEVELOPMENT-SYSTEM when it starts up, at least in the ways described
above.  (I -think- that those are the most important/significant ways.)

More information about the Openmcl-devel mailing list