beowulf.bootstrap
Lisp as defined in Chapter 1 (pages 1-14) of the Lisp 1.5 Programmer's Manual
; that is to say, a very simple Lisp language, which should, I believe, be sufficient in conjunction with the functions provided by beowulf.host
, be sufficient to bootstrap the full Lisp 1.5 interpreter..
The convention is adopted that functions in this file with names in ALLUPPERCASE are Lisp 1.5 functions (although written in Clojure) and that therefore all arguments must be numbers, symbols or beowulf.cons_cell.ConsCell
objects.
APPLY
(APPLY function args environment depth)
Apply this function
to these arguments
in this environment
and return the result.
For bootstrapping, at least, a version of APPLY written in Clojure. All args are assumed to be symbols or beowulf.cons-cell/ConsCell
objects. See page 13 of the Lisp 1.5 Programmers Manual.
EVAL
(EVAL expr)
(EVAL expr env depth)
Evaluate this expr
and return the result. If environment
is not passed, it defaults to the current value of the global object list. The depth
argument is part of the tracing system and should not be set by user code.
All args are assumed to be numbers, symbols or beowulf.cons-cell/ConsCell
objects. However, if called with just a single arg, expr
, I’ll assume it’s being called from the Clojure REPL and will coerce the expr
to ConsCell
.
PROG
(PROG program env depth)
The accursed PROG
feature. See page 71 of the manual.
Lisp 1.5 introduced PROG
, and most Lisps have been stuck with it ever since. It introduces imperative programming into what should be a pure functional language, and consequently it’s going to be a pig to implement.
Broadly, PROG
is a variadic pseudo function called as a FEXPR
(or possibly an FSUBR
, although I’m not presently sure that would even work.)
The arguments, which are unevaluated, are a list of forms, the first of which is expected tp be a list of symbols which will be treated as names of variables within the program, and the rest of which (the ‘program body’) are either lists or symbols. Lists are treated as Lisp expressions which may be evaulated in turn. Symbols are treated as targets for the GO
statement.
GO: A GO
statement takes the form of (GO target)
, where target
should be one of the symbols which occur at top level among that particular invocation of PROG
s arguments. A GO
statement may occur at top level in a PROG, or in a clause of a COND
statement in a PROG
, but not in a function called from the PROG
statement. When a GO
statement is evaluated, execution should transfer immediately to the expression which is the argument list immediately following the symbol which is its target.
If the target is not found, an error with the code A6
should be thrown.
RETURN: A RETURN
statement takes the form (RETURN value)
, where value
is any value. Following the evaluation of a RETURN
statement, the PROG
should immediately exit without executing any further expressions, returning the value.
SET and SETQ: In addition to the above, if a SET
or SETQ
expression is encountered in any expression within the PROG
body, it should affect not the global object list but instead only the local variables of the program.
COND: In strict mode, when in normal execution, a COND
statement none of whose clauses match should not return NIL
but should throw an error with the code A3
… except that inside a PROG
body, it should not do so. sigh.
Flow of control: Apart from the exceptions specified above, expressions in the program body are evaluated sequentially. If execution reaches the end of the program body, NIL
is returned.
Got all that?
Good.
prog-eval
(prog-eval expr vars env depth)
Like EVAL
, q.v., except handling symbols, and expressions starting GO
, RETURN
, SET
and SETQ
specially.
try-resolve-subroutine
(try-resolve-subroutine subr args)
Attempt to resolve this subr
with these arg
.