JitterLisp

This is the manual for JitterLisp (for GNU Jitter version 0.7.312, last updated on 27 May 2024), an efficient Lisp system using a Jittery VM.

Copyright © 2017-2021 Luca Saiu
Updated in 2022 by Luca Saiu
Written by Luca Saiu.

Permission is granted to copy, distribute and/or modify this document under the terms of the GNU Free Documentation License, Version 1.3 or any later version published by the Free Software Foundation; with no Front-Cover texts and with the Back-Cover text being “You have freedom to copy and modify this manual, like GNU software.”.

A copy of the GNU Free Documentation License is distributed in electronic form along with the software in the file doc/COPYING.DOC, and available on the web at the URL https://www.gnu.org/licenses/fdl.html.

All the code examples contained in this manual are released into the public domain, up to the extent of the applicable law.

The author’s personal web site https://ageinghacker.net contains his contact information.

Table of Contents


1 Introduction

JitterLisp is a comparatively simple and efficient Lisp system, relying on a Jittery virtual machine for compiled code.


1.1 History

Jitter (see The GNU Jitter Manual) was borne out of an attempt to optimize the programming language GNU epsilon (see The GNU epsilon Manual), my main long-term project. Dissatisfied with the speedup provided by a simple direct-threaded virtual machine I started exploring more advanced techniques, and the experiment eventually grew into the current virtual machine generator. A sub-project, some might argue, that got out of hand.

Still, Jitter had seen no major application yet. It needed to be stressed to find bugs and embedded in a practical system for me to discover what was missing and fill the gaps. I wanted a real application. A real programming language. A Lisp.

And the sub-sub-project has now also gotten out of hand, again branching off in its own interesting direction.


1.2 Goals

JitterLisp lives somewhere near the boundary between the end of the domain of complex toys, and where simple real Lisp systems begin; as long as we keep seeing it as an example for Jitter either classification will do. As for concrete applications it can certainly be made practical: the Lisp library can be extended, and JitterLisp itself could become both embeddable and extensible in C without unreasonable effort. If in the future I bent the system in some of these directions, as I might well do, I guess the result would be useful; but writing yet another Lisp system was never my primary goal.

Even without the ambitious scope of Jitter I consider JitterLisp useful to show the level of performance within the reach of small, clean systems. JitterLisp gets many design decisions correct but is not perfect or exceptionally clever; still it appears more efficient than every mature “dynamic language” implementation, in some cases to a spectacular degree—due more to the faults of others than to any merit of mine.

I will not even try to hide my own personal goal for JitterLisp: being able to say that most language implementations are inexcusably bad, as in fact they are, with a real implementation to present as a comparison point and not just a proof of concept; and numbers.
And so here I stand, claiming my right to rub JitterLisp on everyone’s face. How good it feels.


1.3 Features and influences

Every time I had to choose whether to support a feature or to omit it for simplicity my decision relied on two criteria:

  • Can the feature be omitted while keeping the language realistic? JitterLisp should remain a Lisp, not more difficult to learn for a Lisper than another simple dialect nor too fundamentally different. JitterLisp must also be a reasonably practical system with the core features a programmer would expect, and not just an idealized prototype.
    It must be possible to compare the JitterLisp language with standard dialects, and find them similar in practice.
  • Is the feature critical for performance? If omitting the feature granted JitterLisp a performance advantage with respect to other Lisps at the cost of making JitterLisp very cumbersome to use, then not supporting it would make performance comparisons unfair. Where, on the other hand, a feature has no performance overhead (particularly when not in use), I can in good conscience leave it out and claim that an extended JitterLisp with the feature would still perform as well as the current system.
    The language must make comparisons between the JitterLisp implementation and other Lisp implementations possible, and fair.

In the end the relative weight associated to each of the two criteria can only be a judgment call and some grey areas will remain, no matter how I strive for fairness. In case some reader felt that I skewed the comparison to JitterLisp’s advantage by choosing to include or exclude some feature, I am open to discussion.

JitterLisp draws inspiration from both Common Lisp and Scheme, without being compatible with either. However a competent programmer should be able to write code running unchanged on top of JitterLisp, a Common Lisp system or a Scheme system, through a layer of simple macros.

Several design ideas originate from my own GNU epsilon.


1.3.1 Comparison with other Lisps

The JitterLisp language is first of all a Lisp dialect, and as such will feel familiar to any programmer already mastering any other Lisp.

JitterLisp is a lexically-scoped higher-order homoiconic1 Lisp/1 featuring closures, garbage collection, quasiquoting and Turing-complete macros.

Every syntactic form in JitterLisp is an expression, and nontrivial expressions will contain sub-expressions; JitterLisp has no “statements” as a distinct syntactic category, nor special forms which are only valid at the top level. Variables are mutable by default, and iteration and recursion are both supported. Tail calls incur no space overhead except in inter-calls between compiled and interpreted code.

Typing is dynamic. JitterLisp datatypes include the empty list object, symbols, characters, conses and procedures. Non-empty lists are cdr-nested conses. At the present time fixnums are the only numeric type.

Each procedure may be either interpreted or compiled, and procedures of different kinds are allowed to call each other with no restrictions and no difference in observable behavior apart from performance. Interpreted procedures can be compiled at run time without affecting their identity as objects.

[FIXME: quoting and quasiquoting are Lispy, not epsilonian]

[FIXME: compare with standard Lisp dialects]

[FIXME: Many of the superficial features of JitterLisp, particularly at the lexical level, come from Scheme]

[FIXME: define operating at the top level, like Common Lisp’s defun but differently from Scheme]


1.3.2 epsilonian features

JitterLisp is more “dynamic” and more reflective than typical Lisp dialects: any expression is allowed to define, remove or alter any non-constant global binding; the Abstract Syntax Tree returned by macroexpansion and contained within each closure is a recursive data structure describing an expression in a minimalistic core language which can be interpreted, compiled, analyzed, optimized or in general used like any other data structure, at run time, in the language itself.

Exposed ASTs and reflection make it possible and natural for the compiler to be implemented as an ordinary procedure, itself written in Lisp and running on top of the interpreter or compiled by itself at run time.

These distinctly epsilonian features, while important in making the internal implementation simpler and more elegant, are meant to be invisible to the casual user. In particular user macros operate on ordinary non-AST Lisp data structures, usually through Lisp quasiquoting, and will feel instantly familiar to any Common Lisp or Emacs Lisp programmer; the fact that the core Lisp forms are themselves predefined macros expanding to ASTs may be safely ignored in almost all programs as an implementation detail.

See Interaction example for a quick demo session introducing most of the non-traditional features likely to surprise a Lisp user.


1.3.3 Simplifications


1.3.3.1 Intentionally omitted features

[FIXME: no modules, packages or namespaces]

[FIXME: no values]

[FIXME: no continuations]

[FIXME: no exceptions]

[FIXME: no variadic procedures (but I do have variadic macros)]

[FIXME: no OO]


1.3.3.2 Desirable but not implemented features

[FIXME: no stack traces]

[FIXME: no type dispatching]

[FIXME: only a small library]


1.4 License

JitterLisp is free software, distributed under the GNU General Public License, version 3 or later. There is no warranty whatsoever.

This manual is free documentation, distributed under the GNU Free Documentation License, version 1.3 or later.


2 Using JitterLisp

JitterLisp is distributed along with GNU Jitter as an advanced example of its use, and must be compiled from the source code.

JitterLisp has no separate distribution or build system of its own, but is easy to build from the Jitter build directory. The build process follows the GNU conventions and supports cross-compilation.

Once compiled JitterLisp is quite friendly to use. It supports GNU-style command-line options and can work either interactively with a REPL, or by running Lisp code from text files.


2.1 Obtaining the software

JitterLisp is distributed as an example within Jitter, and can be obtained along with the Jitter source code. It is written in C and itself, and the virtual machine it relies on for compiled closures is generated by Jitter. The current web page for Jitter, containing a link to a publicly readable git repository, is on my web site at the URL https://www.gnu.org/software/jitter .

As of 2021 JitterLisp’s development takes place on the main git branch named master.

I welcome feedback. If you need to contact me or want to discuss about JitterLisp please see Contacting the author in The Jitter Manual.


2.2 Building JitterLisp

JitterLisp belongs to Jitter’s examples. The examples are not built by the default make target but are easy to generate by running

make examples

from the Jitter build directory, or by running the test suite as explained below.

The Jitter test suite includes many cases based on JitterLisp, as compiled JitterLisp procedures are a convenient and realistic way of stressing Jitter and testing its generated code. Running Jitter’s test suite with

make check

(see Running the test suite in The Jitter Manual) from its build directory is sufficient to build JitterLisp as a side effect, in all of the variants (see JitterLisp executables) supported by the Jitter configuration. I highly recommend running the test suite in any case before using Jitter.

See Working with the Jitter sources in The Jitter Manual for detailed building instructions. The build system follows the modern GNU style and in particular the common practices and suggestions from the GNU Coding Standards (see The GNU Coding Standards), which sets a few additional requirements such as GNU Autoconf and GNU Automake for “developers”—with the caveat that, at the present time before I release official stable tarballs, every user has to follow the developer instructions.

Even if the dependency is not mandatory I strongly recommend the Boehm-Demers garbage collector, packaged by every modern GNU/Linux distributions and also easy to install from sources. Other optional dependencies are the GNU Readline and GNU Libtextstyle libraries.
Both dependencies are automatically checked by Jitter’s configure script; if a library or its C headers are missing the corresponding functionality will be disabled, or some JitterLisp variants will not be built.

Jitter’s build system encourages a separate build directory and supports advanced features such as cross compilation, but is standard enough to just work with the usual command line

./bootstrap && ./configure && make

in most practical cases.


2.3 JitterLisp executables

According to the system characteristics as detected by Jitter’s configure script and to configure-time options supplied by the user the build system will compile different versions of JitterLisp, with the intent of testing and benchmarking Jitter.

These different compiled programs will exhibit different performance profiles, but still be equivalent in terms of Lisp functionality.

One JitterLisp executable is built for each combination of the following configuration items:

safety

a JitterLisp program may be safe and check for operand types before executing every operation, or unsafe and omit some checks. An unsafe Lisp will be more efficient, but subject to crashes in case of user error;

garbage collection

JitterLisp supports the Boehm-Demers garbage collector but can also allocate heap memory without ever freeing the space, either because the garbage collection library is not available or for performance testing. The two possible configuration values are called Boehm or litter, respectively.

dispatch

there are currently four dispatches supported by Jitter: switch-dispatching, direct threading, minimal threading and no threading (see Dispatches in The Jitter Manual), each with its own performance and portability profile. JitterLisp will run with any dispatch.

Unless some configuration choice has been disabled multiplying the number of choices for each of the three items gives a total of 16 combinations and therefore 16 different executables, recognizable by suffixes in their file name. The safety suffix may be empty or ‘--unsafe’, the garbage collection suffix ‘--boehm’ or empty, and the dispatch suffix one of ‘--switch’, ‘--direct-threading’, ‘--minimal-threading’ and ‘--no-threading’.
A good combination for general use will be safe-Boehm-no-threading, implemented in the file bin/jitterlisp--boehm--no-threading relative to Jitter’s build directory. A user measuring performance in a “lowest-overhead” context might want to try bin/jitterlisp--unsafe--no-threading, paying close attention to how much memory is used. The shell command

ls bin/jitterlisp*

will print the full list of available JitterLisp programs.

“Default” JitterLisp executables, with no dispatch suffix in their name are also built using the best dispatch available in the current configuration. In the example above bin/jitterlisp--boehm will have the same functionality as bin/jitterlisp--boehm--no-threading.

In the following examples I will arbitrarily refer to bin/jitterlisp--boehm as the executable to run. The executable name is easy to replace with another, in case that configuration is not available; every JitterLisp executable supports the same command-line interface. The current working directory is always irrelevant when invoking any JitterLisp executable without file arguments, which makes the bin/ component of the path name safe to freely adapt as well.


2.4 Installing JitterLisp

The Jitter build system does not support installing examples at the present time.

It would certainly be possible to directly use Libtool and install Jitter’s libraries and executables. However, as a simpler alternative, a user can configure Jitter to generate static libraries only by calling configure with the option --disable-shared, and then build the examples. Each JitterLisp executable will be one self-contained file with no external run-time dependencies, easy to copy by hand into some directory within PATH or to another convenient location.

If the Jitter libraries are statically linked and every dynamic library is correctly installed then the JitterLisp executables will not access any other file by default: the large Lisp initialization file and the GPL license text are in fact embedded as constants within the native compiled file image (see constant-strings).


2.5 Invoking JitterLisp

A user can either run JitterLisp interactively via a Read-Eval-Print Loop, or use it to execute Lisp programs from any number of text files.

An interactive run is the default: simply invoking a JitterLisp executable with no arguments, for example by typing

bin/jitterlisp--boehm

at the shell prompt will print a welcome banner and then wait for the user to type in Lisp forms; the system will evaluate one form, print its result unless the result is #<nothing>, and then go back to waiting for the next form.
User input supports the line-editing facilities of GNU Readline, as long as Jitter has been configured with Readline support. Lisp forms entered by the user are allowed to span multiple lines.
The user can exit by closing the input, typically by pressing C-d on an empty line on GNU and other Unix systems.

Any non-option argument on the command line is taken as the relative path name of one Lisp file to run; JitterLisp accepts an arbitrary number of file names on the command line, and executes them in the given order. JitterLisp will omit the banner and, by default, run non-interactively if it receives any file name, exiting without executing the REPL.
A single dash ‘-’ is a non-option argument and stands for the process standard input, from which the program will read Lisp forms. Like the path name for a Lisp file, a - argument will make JitterLisp default to non-interactive mode.

Lisp forms from input files or ‘-, in either interactive or non-interactive mode, will be evaluated without automatically printing each result, to avoid clutter in the output. Of course a Lisp program may still call I/O procedures (see Input and output) in order to print out information as desired, without such explicit output being suppressed.

A run-time error while executing a Lisp program given on the command line will cause JitterLisp to exit with failure, without processing any remaining Lisp file.

JitterLisp executables default to treating any command-line argument beginning with a dash (‘-’) as an option which affects the system behavior in one of the ways described in this section. The exceptions are arguments constituted by exactly a single dash, as explained above, or any arguments following an argument constituted by exactly two dashes (‘--’): those are interpreted as non-options.

Several JitterLisp options affect the software behavior in some way which can be negated by another option restoring the default. When both an option and its opposite are given, the last option on the command line prevails.

I call negative options the options whose only purpose is to negate the effect of other options, restoring the default behavior. Negative options are useful for canceling the effect of some option which is convenient to always pass and then occasionally override, for example as part of a shell alias or by quick interactive line editing of a complex shell command line.
The output of --help, described below, shows negative options marked as ‘(default)’.

JitterLisp supports the standard GNU command-line options:

--version

Print version information and legal notices for JitterLisp, then exit with success. Since JitterLisp is distributed along with Jitter and currently lacks a version number of its own, the output will actually reflect Jitter’s version.

-?, --help

Print a terse description of JitterLisp’s command-line interface including the options documented here, then exit with success.

--usage

Print a list of the options documented here with no explanation, then exit with success.

--

Stop option processing, and interpret any following argument in the command line as a non-option. This may be useful to execute Lisp files whose path name starts with a dash.

Checking JitterLisp’s version to obtain a version number and nothing more may be of some use in shell scripts:

--dump-version

Print JitterLisp’s version number and exit with success. The output is in a single line with no spaces, and does not contain JitterLisp’s name or any other information.

The following options affect JitterLisp’s interaction mode:

-q, --no-repl, --batch

Run in non-interactive mode, without a REPL, independently from non-option arguments.

--repl, --no-batch

Run in interactive mode even if non-option arguments are given; in this case start the REPL after executing the given Lisp files.

It may be useful to run JitterLisp for evaluating one or a few Lisp forms from the command line, possibly along with some Lisp program passed as a non-option argument:

-e sexprs, --eval=sexprs

Evaluate the given possibly empty sequence of forms, printing the final result (see Sequencing). Evaluation and printing takes place after running all the Lisp files from non-option arguments, and before executing the REPL (when in interactive mode).
This option does not by itself change JitterLisp’s mode to non-interactive.

Unfortunately the quoting rules for Bourne shells make Lisp quoting and quasiquoting (see Quoting and quasiquoting) somewhat inconvenient to use from the Unix command line:

bin/jitterlisp--boehm --no-repl --eval='(let ((a 42)) `(a is ,a))'
bin/jitterlisp--boehm --no-repl --eval="(let ((a 'b)) \`(a is ,a))"
bin/jitterlisp--boehm --no-repl --eval='(let ((a '\''b)) `(a is ,a))'
bin/jitterlisp--boehm --no-repl --eval=\'the-result-is-a-symbol

At least in simple cases a user should be able to work around such problems by defining a macro in a Lisp file, to be used in the --eval argument without requiring complex quoting in the command line. An alternative is avoiding the quoting prefix notation (see prefix-notation) altogether, writing for example (quote b) instead of 'b within single-quoted shell text.

Some options affect the way JitterLisp prints out information and let users deviate from the default behavior.

--no-omit-nothing

Print back #<nothing> when it occurs as the result of a user form (see Uniques), in interactive use or with --eval. The default is to omit it, as #<nothing> represents an “uninteresting” result from a form which is normally evaluated for its side effects.

--colorize

Print Lisp data using color and font variations to make different object types easier to distinguish at a glance. The current implementation, quite crude, relies on ANSI terminal escape sequences and uses a choice of colors suitable for a black or dark background.

The default is to always use the default terminal color and font, without emitting escape sequences.

-c, --compact-uninterned

Print uninterned symbols (see uninterned-symbols) in an alternative, more compact notation using a per-symbol index rather than a memory address. The index may theoretically wrap around after allocating a very high number of uninterned symbols.

--cross-disassembler

Use the cross-disassembler specified at Jitter configuration time (see Disassembly in The Jitter Manual) rather than the default native disassembler to print out native code for compiled closures (see disassembly).

The cross-disassembler is useful for running JitterLisp on an emulator for a foreign hardware architecture, using an objdump executable from cross-configured GNU binutils having a name different from the objdump program running on the host machine.

The default, reasonable for running JitterLisp without command-line options on the host architecture it was configured for, is using the native disassembler.

--free-routines

Normally, when compiling a closure (see Compilation) the JitterLisp system keeps two versions of the resulting VM routine in memory: one non-executable routine, and one executable routine. The executable routine is necessary for executing the closure code, and therefore will always remain in memory until garbage-collected—or for ever, in the case of littering JitterLisp programs. The non-executable routine, on the other hand, can be destroyed immediately at compilation time to save memory; its only purpose after compilation is debugging, using disassemble and disassemble-vm (see Compilation and see Disassembly in The Jitter Manual).

By default JitterLisp keeps non-executable routines in memory, and garbage-collects them along with executable routines. By specifying this option only executable routines are kept, which saves memory at the cost of making debugging output less friendly if not, according to the dispatch, completely useless.

--no-verbose-litter

A JitterLisp executable littering memory (see litter) will by default print a message to the standard error every time a new block of memory is allocated. Such warnings, although distracting, are useful to remind the user that the running program is allocating memory from a growing heap which will not be freed, and are therefore enabled by default.
Non-littering executables will accept and silently ignore verbose littering options.

This option suppresses litter-allocation messages.

--time[=time]

When this option is given with time unspecified or different from ‘no’ the REPL times interactive commands and prints a human-readable message specifying the elapsed time in seconds after each evaluation. Valid values for time are ‘no’, ‘yes’ and ‘verbose’. A time value of ‘verbose’ causes the timed command to be printed back along with the time, which is convenient when interactively running multiple commands on the same line, to be executed in sequence and timed independently.

The default is not printing timings, as with ‘no’, when the option is not given. Giving the option without specifying time is equivalent to setting time to ‘yes’.

Only commands executed by the REPL are timed: this excludes library initialization, code from Lisp files specified in the command line, and arguments from the --eval option.

--omit-nothing
--no-colorize
--no-compact-uninterned
--no-cross-disassembler
--no-free-routines
--verbose-litter
--no-time

These are the negative counterparts of the options above, restoring the respective default behaviors.

The last group of options is mostly meant for the development of JitterLisp itself with respect to debugging or benchmarking.

-v, --verbose

Print out debugging information about JitterLisp’s execution progress, including the full macroexpansion and evaluation of each library form executed at startup. The default it not to print such information.

This option may occasionally be useful to discover the approximate origin of a problem, such as which of several provided Lisp files caused an error.

--no-optimization-rewriting

Disable VM instruction rewriting (see Instruction rewriting in The Jitter Manual). This is only useful for debugging rewrite rules or benchmarking their effect, or theoretically for making compilation more efficient at the price of slower execution of compiled code.

Instruction rewriting is enabled by default.

--no-library

Do not run the default Lisp library at initialization, exposing only the language and library features implemented in C.

The predefined Lisp globals available when using this option will be limited to the ones marked as “core macro”, and “primitive wrapper” in the reference documentation (see Lisp reference), plus the associated primitives; in particular there will be no support for high-level macro definitions (see high-level-macros), AST optimization (see AST optimization) or compilation (see Compilation). A few globals documented as “macro” have actually two separate implementations, the first in C as a “core macro”, to be used at initialization for bootstrapping the system, and then a second, cleaner or more powerful redefinition as an ordinary “macro”, in Lisp. The option --no-library exposes the core macro implementation in this case, which may differ in subtle ways from the normally available definition, and in fact is allowed to contradict the specification in this manual.

This option is meant for debugging JitterLisp itself.

--no-verbose
--optimization-rewriting
--library

The negative versions of the options above.


2.6 Interaction example

This section will present the main features setting JitterLisp apart from other Lisp systems to readers already familiar with other Lisp dialects.

I believe that a sufficiently motivated beginner should be able to follow this section, possibly after first understanding the fundamentals of Lisp from the beginning of the reference part of this document (see Lisp reference). I am particularly interested in feedback from readers who cannot program yet or are only weak programmers but are making a serious attempt to learn by following this route; any beginner with useful feedback to provide, positive or negative, is welcome to contact me (see Contacting the author in The Jitter Manual).

??????????? [FIXME: Write this] [FIXME: it’s a stack machine]

[FIXME: + is a macro]

[FIXME: look at an interpreted closure]

[FIXME: macroexpand]

[FIXME: do some simple computation over ASTs]

[FIXME: optimize explicitly]

[FIXME: optimize retroactively]

[FIXME: These are just ideas. The variable x is unbound.]

(append '(a b c) '(1 (2 3) 4))
  ⇒ (a b c 1 (2 3) 4)


x
  error→ unbound variable x
'x
  ⇒ x
(macroexpand x)
  error→ unbound variable x

(macroexpand 'x)
  ⇒ [variable x]
(macroexpand ''x)
  ⇒ [literal x]
(macroexpand '''x)
  ⇒ [literal (quote x)]
(macroexpand ''''x)
  ⇒ [literal (quote (quote x))]

(define (twice n)
  (* n 2))
(twice 10)
  ⇒ 20
twice
  ⇒
  #<interpreted-closure () (#<u680>)
    [primitive #<primitive 2* 1-ary> [variable #<u680>]]>

(define-macro (when-zero discriminand . body)
  `(when (zero? ,discriminand) ,@body))

(macroexpand '(when-zero a b c))
  ⇒
  [if [call [variable zero?] [variable a]]
        [sequence [variable b]
                  [variable c]]
        [literal #<nothing>]]
(when-zero 42 (display 'foo) (newline))
  →
  [if [call [variable zero?] [literal 42]]
      [sequence [call [variable display] [literal foo]]
                [call [variable newline]]]
      [literal #<nothing>]]
  ⇒
  #<nothing>

;; For people familiar with Common Lisp:
(define-macro (defun operator formals . body-forms)
  `(define (,operator ,@formals)
     ,@body-forms))
(define-macro (defmacro operator formals . body-forms)
  `(define-macro (,operator . ,formals) ;; FIXME: why not (,operator ,@formals) ?
     ,@body-forms))
;; And then:
(defun successor (n)
  (+ n 1))
(defmacro when-zero (discriminand . body)
  `(when (zero? ,discriminand)
     ,@body))

(define my-even?
  (letrec ((my-even? (lambda (n)
                       (cond ((= n 0)  #t)
                             ((= n 1)  #f)
                             (else     (my-odd? (- n 1))))))
           (my-odd?  (lambda (n)
                       (cond ((= n 0)  #f)
                             ((= n 1)  #t)
                             (else     (my-even? (- n 1)))))))
    my-even?))
(lambda () (letrec ((f 1) (g 2)) f))
  ⇒
  #<interpreted-closure () ()
    [let #<u702> [literal #<undefined>]
      [let #<u703> [literal #<undefined>]
        [sequence [set! #<u702> [literal 1]]
                  [sequence [set! #<u703> [literal 2]]
                            [variable #<u702>]]]]]>
(macroexpand '(begin))
  ⇒ [literal #<nothing>]
(macroexpand '(begin (newline)))
  ⇒ [call [variable newline]]
(macroexpand '(newline))
  ⇒ [call [variable newline]]
(macroexpand '(begin (display 42) (newline)))
  ⇒
  [sequence [call [variable display] [literal 42]]
            [call [variable newline]]]
(macroexpand '(begin (display 42) (newline) (newline)))
  ⇒
  [sequence [call [variable display] [literal 42]]
            [sequence [call [variable newline]]
                      [call [variable newline]]]]


3 Lisp reference

[FIXME: Fill this.]

[FIXME: we will first define Lisp data structures, then show how some of them are mapped into expressions] [FIXME: see homoiconicity-footnote]


3.1 Lisp data

[FIXME: boxed and unboxed objects]

All Lisp data have an output notation, and some can be read from input via a read syntax as well. The two syntaxes, where both defined, are compatible.
For example the number 1234, the boolean #t and the symbol this-is-a-symbol are written back by the system (when they occur as results in the REPL, or in output) as 1234, #t and this-is-a-symbol, in the same syntax available to the user for data input. However some other objects such as procedures can be described in the output (for example ‘#<interpreted-closure () (x-1 x-0) [primitive #<primitive cons 2-ary> [variable x-1] [variable x-0]]>’), but have no corresponding read syntax to be directly input as immediates. Any object can still be built programmatically.

[FIXME: Out of convenience the written notation of an object does not necessarily convey all of the information about it; for example, the memory address where an object is stored does not appear, yet is important in the execution semantics in order to check whether two objects are the same. The output notation does express the presence of substructure sharing within a single Lisp object, currently without showing more detail: an ellipsis (‘...’) within a printed object stands for another boxed Lisp sub-object, it is not specified which, that has been already printed at least once as part of object being shown. This does not distinguish between Direct-Acyclic-Graph structures, where two pointers simply converge to the same address, and pointer cycles making circular or “infinite” structures. Shared structures have no read syntax but can be built programmatically.]

It is worth to stress how the language defined in the rest of this section describes Lisp data, and not necessarily valid Lisp expressions. For example foo denotes a symbol object, but simply typing foo at the first REPL prompt will cause an unbound-variable error—in such a case the symbol object foo will be macroexpanded into a variable named ‘foo’, even when no such variable exists. In the same way the read (and write) syntax (1 2 3) denotes a well-formed Lisp datum, but would macroexpand to a procedure call with 1 as the operator, immediately causing a failure on evaluation. See Quoting and quasiquoting for information about the quoting syntax for building expressions evaluating to literal Lisp objects.

[FIXME: Fill this.]

Every Lisp datum contains a value and a type. Given a datum it is always possible to check for its type at run time by means of some predefined procedure (see type-checking-procedures).

Since JitterLisp has, at least currently, no subtyping relation, each object belongs to exactly one of the following types. However some predefined procedures are provided to check whether an object belongs to one of several related data types; for example closure? will recognize either an interpreted closure or a compiled closure as a “closure”.

[FIXME: any two object are comparable by identity: see eq?.]

[FIXME: talk about macroexpansion]


3.1.1 Uniques

[FIXME: Fill this.] [FIXME: immutability]

A unique object important in practice is the empty list:

unique: ()

In read syntax it is acceptable to separate the open and closed parentheses with arbitrary whitespace or comments, in which last case the closed parentheses will be found on a separate line.

There exists exactly one empty list object, written as (). It is used, in particular, as the trailing part of the of every list spine: see lists.

A Boolean or canonical Boolean object represents a truth value, either false or true. There are exactly two Booleans:

unique: #f
unique: #t

The false object is written as #f; the true object is written as #t.

In practical use #f tends to be more important than #t, as JitterLisp conditionals and loops distinguish between the #f value and any other Lisp object which is taken as “true” for the purposes of tests. A Lisp object used as a Boolean in this extended sense is called a generalized Boolean. Of course generalized Booleans are not necessarily unique objects.

[FIXME: a few words about the following uniques]

unique, no read syntax: #<nothing>
unique, no read syntax: #<eof>
unique, no read syntax: #<undefined>

[FIXME: what they are used for]


3.1.2 Fixnums


3.1.3 Characters


3.1.4 Symbols


3.1.5 Conses

A cons is a pair object containing exactly two other Lisp objects, allowed to be conses in their turn or objects of any other types. Conses are mutable, in the sense that the two components of a cons can be changed at run time while keeping the identity of the cons object.

The first object contained in a cons is called its car, the second is called its cdr.

Syntax: If a and b are two Lisp objects, then (a . b) is a cons containing a as its car and b as its cdr.

Let S be any nonempty sequence of the characters “a” and “d”. Then the caSr of a cons is the car of the cSr of the cons, and its cdSr is the cdr of its cSr. For example the caddr of an object is the car of the cdr of its cdr. Such composed cons selector names are convenient to use when referring to nested components of a cons, and the JitterLisp library provides functionality to access them with any S of length 1, 2 and 3—therefore, for a level of nesting up to 4.

A list is either the empty list object or a cons whose cdr is another list. For example (), (#t . ()), (#f . (3 . ())) and ((1 . 2) . ()) are lists; (#t . #t) is not a list.

A sublist of a nonempty list is either its cdr or a sublist of its cdr. The elements of a nonempty list are the car of the list and the elements of its sublists. The empty list has no sublists and no elements.
For example the list (foo . (10 . (bar . ()))) has the three sublists (10 . (bar . ())), (bar . ()) and (), and the three elements foo, 10 and bar. Given a nonempty list its first element and its first sublist can always be found by taking, respectively, the car and the cdr of the list. Taking the car and cdr of the first sublist yields the second element and the second sublist of the original list, and so on.
It is easy to see how some composed cons selectors applied to a list identify specific sublists and elements: the list sublists will be its cdr, cddr, cdddr, cddddr, and so on; then taking the car of the list itself and its sublists yields the list elements: therefore the first, second, third and fourth element of a list will be respectively its car, cadr, caddr and cadddr.

The following notation makes lists much easier to write, as it suppresses every dot on the list spine and many parentheses; it can be used on many non-list conses as well:

Compact cons notation: Let a and b be two objects. When b is either the empty list () or a cons, the cons (a . b) can be written in the compact cons notation: in compact notation both the dot and the parentheses around b are omitted.

JitterLisp always adopts the compact cons notation in output, whenever applicable. Its use in input is optional.

For example (7) is a compact way of writing (7 . ()), (1 2) is a compact way of writing (1 . (2 . ())), ((a)) is a compact way of writing ((a . ()) . ()), and (10 a . #t) is a compact way of writing the non-list (10 . (a . #t)).

A further syntactic convenience is available for particular conses, which are also lists:

Prefix notation: Let q be the read syntax for a Lisp object. Then:

  • 'q is an alternative read syntax for (quote q);
  • `q is an alternative read syntax for (quasiquote q);
  • ,q is an alternative read syntax for (unquote q); and
  • ,@q is an alternative read syntax for (unquote-splicing q).

The prefix notation is recognized by the reader, but currently not emitted in output. Its use in input, again, is optional.

The prefix notation serves to express quoting and quasiquoting in a more convenient way: see Quoting and quasiquoting.

It is worth stressing that lists are not special at the language level and do not constitute a separate type: the name “list” is just a characterization of the shape of some objects, common in practice, which include the empty list object and some conses.


3.1.6 Boxes

Boxes have no read syntax.


3.1.7 Interpreted closures


3.1.8 Compiled closures

[FIXME: An interpreted closure can destructively change to a compiled closure (but not vice-versa) without changing its identity.]


3.1.9 Primitives


3.1.10 Abstract Syntax Trees

An Abstract Syntax Tree or AST is a recursive type representing code as a data structure. ASTs only support the core language forms which remain after macroexpanding away (see macroexpansion, see Macroexpanding) every macro use: Lisp code rewritten not to use any macro turns into an AST, which can be then interpreted or compiled, or even analyzed and transformed by other Lisp code.

JitterLisp in fact contains no executor for Lisp: there are only an AST interpreter, written in C, and an AST compiler written in Lisp and translating ASTs into code for the Jittery VM. It is thanks to the reflection capabilities provided by the AST data type that it is possible to write a self-compiler, and also a self-optimizer, in the language itself.

Even if ASTs have no read syntax the JitterLisp library provides facilities to conveniently inspect and build ASTs: see AST operations.

See Abstract Syntax Trees and their semantics for a complete description of the structure of Abstract Syntax Trees and their behavior.


3.1.11 Macros


3.1.12 Primitive macros


3.2 Abstract Syntax Trees and their semantics

JitterLisp code is executed by first translating user syntax into Abstract Syntax Trees, which are easy to interpret or compile. Far from being only an implementation device, JitterLisp ASTs are also exposed to the user who may execute them (see Code execution) and also work on them just as on any other Lisp data structure.

There is no read syntax allowing the user to directly enter an AST as a literal datum; however the library includes sufficient functionality to inspect or build ASTs (see AST operations). Such functionality is used extensively in macroexpansion and compilation.


3.2.1 AST syntax

ASTs define a minimalistic programming language, operating on Lisp data but otherwise not particularly similar to Lisp. The syntax given here is the output syntax used by the implementation for printing AST data, for example as the result of macroexpand (see Macroexpanding). This syntax is designed to be simple and unambiguous. In order to visually stand apart from user syntax it indicates grouping by brackets (‘[’, ‘]’) rather than parentheses.

A dot (‘.’) in the syntax below indicates the convention of writing a sequence of zero or more entities, represented in memory as a list, without the surrounding parentheses. For example a valid primitive following the syntax ‘[primitive operator . operands]’ will be [primitive + [literal 2] [variable x]], where [literal 2] and [variable x] are ASTs encoded as the two elements of a list within the AST for the primitive.

Every AST represents an expression. Each expression has exactly one of the following forms, named after the identifier immediately following the open bracket:

  • [literal value], a literal.

    The literal value may be any Lisp datum.

  • [variable name], a variable or variable reference.

    The variable name must be a symbol.

  • [primitive operator . operands], a primitive or primitive use.

    The primitive operator or primitive name must be a symbol which is the name of a primitive. The primitive operands must be a list of ASTs, having exactly as many elements as the arguments expected by the named primitive.

  • [let name bound-expression body], a let or block.

    The name or bound variable name in a block must be a symbol. A block bound-expression must be an AST. A block body must also be an AST.

  • [define name expression], a definition or global definition.

    The global definition name must be a symbol. The definition expression or defined expression must be an AST.

  • [set! name expression], an assignment.

    The assignment variable name must be a symbol. The assignment expression must be an AST.

  • [sequence expression-0 expression-1], a sequence.

    Each of the first expression or expression-0 and the second expression or expression-1 in a sequence must be an AST.

  • [if condition then-branch else-branch], a conditional.

    The conditional condition and its two branches must all be ASTs.

  • [while guard body], a while or loop.

    Each of the loop guard and body must be an AST.

  • [lambda formals body], a lambda or abstraction.

    The lambda or abstraction formals or formal arguments must be a list of symbols, all different from one another. The lambda body must be an AST.

  • [call operator . operands], a call or procedure call.

    The call (or procedure call) operator must be an AST. The call operands must be a list of ASTs.

The forms above specify the entirety of the AST syntax: every JitterLisp form, before being executed, is translated into an AST having one of the shapes described above, which in many cases will contain other ASTs; all the language power and complexity arise solely from the combination of those AST forms.
Conspicuously absent from the forms above is any form of syntactic abstraction such as macros: macros serve to automatically rewrite complex user syntax into a combination of simple ASTs, so that no use of a macro survives the expansion process.

It is important to notice that the syntactic constraints specified above, for example [if ] having exactly three subforms and the first component of [set! ] being a symbol, are verified at AST construction time: it is impossible to build a syntactically incorrect AST without immediately failing. In this sense only syntactically correct ASTs may be said to “exist”.


3.2.2 AST semantics

JitterLisp ASTs constitute an eager imperative call-by-value language based on named, lexically scoped variables and global state.

What follows is an attempt of describing the behavior of AST evaluation in a precise way without the burden of complicated notation.

The mathematically inclined reader will see immediately how the AST semantics would be easy to model in an operational style, with logic rules having multiple premises and one conclusion. Here I will content myself with rendering such rules into more accessible English.


3.2.2.1 Semantics preliminaries

JitterLisp, like most modern Lisp dialects with the (now partial) exception of Emacs Lisp, is lexically scoped. This means that a variable use refers to the innermost variable binding with the same name which syntactically contains the variable AST as a sub-AST. This reference may be different from the most recent binding in time still in force for the same variable—which is used in “dynamically scoped” languages, but not in JitterLisp.

An environment is a mapping from each variable name to its associated value. During the evaluation of an AST some environment is always implicitly in force, which dictates the current value of every variable.

Variable scopes can be nested, adding bindings to the local environment which are visible by variable references until the scope ends. An inner block or call may shadow a variable binding, by re-binding a variable with the same name to a possibly new value and thus making the original variable temporarily inaccessible, as long as the new environment re-binding the same variable is in force.

Some variables may be globally bound: the global binding for a variable records the default value of a variable to be used when a variable is not bound in the currently active environment.


3.2.2.2 Failure

JitterLisp treats failure or errors in a trivial way.

If evaluation fails at any point out of the REPL, then the error is fatal: the execution ends, and the JitterLisp program exits reporting failure.

If evaluation fails when evaluating a form entered at the REPL, then the error is equally unrecoverable, and the AST evaluation terminates reporting failure; however the REPL is not exited, and the user has the opportunity to try and execute other forms in a state altered by the changes which were executed with success before the error, starting again in an empty local environment.

JitterLisp currently provides no exception system, either at the AST level or as part of higher layers.
The error primitive (see Erroring out) provides a way to explicitly fail under program control, but it is not possible to recover from such a failure with any form similar to “catch” or “try” as they exist in other Lisp dialects or in other languages.


3.2.2.3 AST semantics in detail

An AST is evaluated in a given environment, which is empty at the top level.

Evaluating an AST will either fail or yield exactly one value, allowed to have any JitterLisp data type (see Lisp data), as the result. [FIXME: non-termination]

In the following, particularly within examples, I will use the following notation:


Evaluation notation: form, environmentresult [-| output]
form, environment error→

To mean, respectively, that a given form evaluated with a given environment either returns a result (possibly with an output side effect), or fails. An environment, as stated already, is a mapping from variables to values.

[FIXME: Update the evaluation notation and the description below: a form should return a new environment as the result, and possibly a new global environment as well.] [FIXME: distinguish environment extension from environment update. This is important for let versus set!, below.]

ASTs must be finite in size and non-circular2; however different parts of the same AST are allowed to share structure, as long as AST objects in memory form a DAG and not a cyclic graph.

  • [literal value]

    Evaluating a literal AST yields its value as the result, as contained within the AST and independently from its type, without any further processing, independently from the environment. The evaluation of a literal AST always terminates and never fails.

    • Examples: [literal #t], {} ⇒ #t
    • [literal (a . 42)], {} ⇒ (a . 42)
    • [literal a], {} ⇒ a
    • [literal a], {a = 42} ⇒ a
    • [literal [literal a]], {} ⇒ [literal a]
  • [variable name]

    If the named variable is bound in the current environment, then the result is its value in the environment; otherwise, if the variable is not bound in the environment but is bound globally, the result is its global value. If the variable is unbound both in the environment and globally then the form evaluation fails.

    • Examples: [variable a], {} ⇒ 4 if a is globally bound to 4
    • [variable a], {} error→ if a is globally unbound
    • [variable a], {a = 7} ⇒ 7 independently from global bindings
  • [primitive operator . operands]

    Evaluating a primitive begins by evaluating the operands, in a strict left-to-right order, to obtain the operand values as results. Then, unless evaluation has failed already on the operands, the result is the result of applying the primitive to the operand values, according to the primitive behavior. This primitive application may fail, for example if the operand values do not have the expected types, in which case the evaluation of the entire AST fails.

    • Examples: [primitive 1+ [literal 42]], {} ⇒ 43
    • [primitive negate [variable a]], {a = 7} ⇒ -7
    • [primitive 1+ [variable a]], {} error→ if a is globally unbound or bound to a non-number
    • [primitive 1+ [literal a]], {} error→
    • [primitive display [literal 42]], {} ⇒ #<nothing> -| 42
  • [let name bound-expression body]

    A block serves to introduce a local variable, whose binding is visible within the body.

    Evaluating a block starts with the evaluation of the bound expression in the current environment, whose result is the bound value. Then the block body is evaluated in an environment extended by binding the bound variable to the bound value: the result of this evaluation of the body is the result of evaluation of the block.

    If evaluating either the bound expression or the body fails, then the evaluation of the entire block fails.

    • Examples: [let a [literal 42] [primitive 1+ [variable a]]], {} ⇒ 43
    • [let a [primitive 1+ [literal 42]] [primitive negate [variable a]]], {} ⇒ -43
    • [let a [literal 42] [let a [literal #t] [variable a]]], {} ⇒ #t
  • [define name expression]

    A global definition serves to alter the global binding of a variable.

    In order to evaluate a global definition we first evaluate its expression in the current environment, obtaining the defined value. Then we alter the global binding for the named variable, setting it to the defined value. Only the global binding is ever altered by define, even if the variable happens to be bound locally at the time of the definition.

    A global definition fails if either the expression fails or the named variable has already been made constant (see constants).

    The result of a global definition AST is #<nothing>.

  • [set! name expression]

    An assignment destructively modifies the given environment, replacing the current value for the name variable with another. This altered binding is visible in the following code using the same environment.

    An assignment evaluation starts by evaluating the expression in the given environment, yielding the assigned value as result. Then, unless the expression evaluation failed, we alter a binding. If the named variable is locally bound, then the local environment is modified by changing the binding for the named variable to the assigned value; otherwise, if the named variable is globally bound, we set its global binding to the assigned value.

    Evaluating an assignment AST fails when evaluating the expression fails, or because the variable is unbound (both locally and globally) at the time of the assignment, or because the variable is locally unbound and globally bound as a constant.

    The result of an assignment AST is #<nothing>.

  • [sequence expression-0 expression-1]

    A sequence serves to evaluate two ASTs one after the other. The fact that the sub-ASTs of a sequence are exactly two is not a limitation, since by nesting sequences one inside the other, it is possible to evaluate any number of ASTs.

    Evaluation starts by evaluating the first expression in the given environment, ignoring its result. Then, in the same environment, the second expression is evaluated; its result will be the result of the sequence AST evaluation.

    Evaluating a sequence fails if evaluating either the first or the second expression fails.

  • [if condition then-branch else-branch]

    [FIXME: write]

  • [while guard body]

    [FIXME: write]

  • [lambda formals body]

    [FIXME: write]

  • [call operator . operands]

    [FIXME: write]


3.2.2.4 From ASTs to JitterLisp

At this point, in principle, it would be possible to describe how each individual JitterLisp form expands into ASTs.

Except in interesting or particularly subtle cases, I will avoid such pedantry.

In fact one of the justifications for having a core-based language like JitterLisp (and epsilon) is that once the core and the expansion mechanisms are specified in a sufficiently formal way, every language extension automatically inherits the mathematical precision of its definition; the source code of each macro can be, I argue, a rigorous enough specification.

Not more than a handful of macros called core macros are defined in C, and even those should present no particular difficulty. For example begin (see Sequencing) is a core macro, defined in jitterlisp-macros.c:

/* Return the expansion of the given list of forms as a sequence.
   This is what the primitive macro begin does and the same code is
   used whenever a form sequence is allowed, for example in a lambda
   body. */
static jitterlisp_object
jitterlisp_macroexpand_begin (jitterlisp_object forms,
                              jitterlisp_object env)
{
  /* Zero-form body. */
  if (JITTERLISP_IS_EMPTY_LIST (forms))
    return jitterlisp_ast_make_literal (JITTERLISP_NOTHING);

  /* Ill-formed body. */
  if (! JITTERLISP_IS_CONS (forms))
    jitterlisp_error_cloned ("begin: non-list body");

  /* At this point we have to look inside the cons. */
  jitterlisp_object first = JITTERLISP_EXP_C_A_CAR(forms);
  jitterlisp_object rest = JITTERLISP_EXP_C_A_CDR(forms);

  /* One-form body. */
  if (JITTERLISP_IS_EMPTY_LIST (rest))
    return jitterlisp_macroexpand (first, env);

  /* Multiple-form body. */
  return jitterlisp_ast_make_sequence
            (jitterlisp_macroexpand (first, env),
             jitterlisp_macroexpand_begin (rest, env));
}

The code shows that the sub-forms within a begin form are recursively expanded in right-nested sequence ASTs, and that there are special cases for a begin with zero or one sub-forms. It is easy to check that this is indeed the case, by observing the ASTs generated by macroexpand from begin forms at the REPL:

(macroexpand '(begin))
  ⇒
  [literal #<nothing>]
(macroexpand '(begin 42))
  ⇒
  [literal 42]
(macroexpand '(begin (display 42)))
  ⇒
  [call [variable display] [literal 42]]
(macroexpand '(begin (display 42) (newline)))
  ⇒
  [sequence
    [call [variable display] [literal 42]]
    [call [variable newline]]]
(macroexpand '(begin (display 42) (newline) (display 43) (newline)))
  ⇒
  [sequence
    [call [variable display] [literal 42]]
    [sequence
      [call [variable newline]]
      [sequence
        [call [variable display] [literal 43]]
        [call [variable newline]]]]]

The description above should be sufficient for a motivated reader, along with macroexpand and the informal description in the following, to follow the details of every macro definition in the implementation.


3.3 Mapping Lisp data to expressions

[FIXME: Fill this.] [FIXME: ASTs are validated at construction time: the implementation never needs to worry about whether an already existing AST is syntactically well-formed; this makes interpretation more efficient and other things simpler.]


3.4 Program structure

[FIXME: Write this]


3.4.1 Expressions

[FIXME: Fill this.]


3.4.2 Definitions

[FIXME: Fill this.]


3.4.3 Constants

[FIXME: primitive wrappers are global constants]


3.5 Lisp language forms

[FIXME: Write this.]

The distinction between language and library is not clear-cut in a system like JitterLisp with strong syntactic abstraction, where almost all of the language is implemented in itself. Here I present the linguistic features which are “fundamental” in a conceptual way, independently from the way they are implemented.

Users interested in distinguishing which individual feature is implemented in C rather than as a Lisp macro may check the tag (“macro” or “core macro”, and only occasionally in this chapter “primitive wrapper”) in the documentation of each item and then follow the sources, with the caveat that a few (important) forms are implemented more than once: first by a temporary definition in C, in order to run the library and initialize the global state; then, from the library itself, the feature is re-defined in Lisp in a more general or powerful way.

[FIXME: Write this]

[FIXME: lexical scoping]

[FIXME: left-to-right]

[FIXME: case sensitive]

[FIXME: metasyntactic conventions: the dot]

[FIXME: erroring out]

[FIXME: Write something]

[FIXME: There is a lot of redundancy, by design. It is desirable to use the most specific form available, for readability and occasionally also for efficiency’s sake.]

[FIXME: dot notation, again, like in AST syntax: here, however, we are speaking of user syntax with Lisp conses.]


3.5.1 Definition forms

macro: define defined-thing . forms
macro: define-constant defined-thing . forms
macro: define-non-optimized defined-thing . forms
macro: define-constant-non-optimized defined-thing . forms

[FIXME: Write this]

macro: define-macro (name . args-pattern) . forms

There is currently no syntactic support for local macros, such as Common Lisp’s macrolet.


3.5.2 Sequencing

[FIXME: sequencing is nice]

[FIXME: “implicit progn” or “implicit begin”: I do it in more cases than Common Lisp and Scheme]

macro: begin . forms

[FIXME: Write this]

macro: begin-from-first index . forms

[FIXME: Write this]

macro: begin1 form-1 . other-forms
macro: begin2 form-1 form-2 . other-forms
macro: begin3 form-1 form-2 form-3 . other-forms
macro: begin4 form-1 form-2 form-3 form-4 . other-forms

[FIXME: Write this]

macro: begin-from-last index . forms

[FIXME: Write this]

macro: begin-1 form-1 . other-forms
macro: begin-2 form-1 form-2 . other-forms
macro: begin-3 form-1 form-2 form-3 . other-forms
macro: begin-4 form-1 form-2 form-3 form-4 . other-forms

[FIXME: Write this]

begin-1 is only provided for symmetry, and is functionally equivalent to begin with the restriction of requiring at least one form.


3.5.3 Conditionals

A conditional form consists in evaluating some condition form and then decide which form to evaluate next according to the result of the condition.

core macro: if condition then-form . else-forms

[FIXME: Write this]

macro: when condition . forms

[FIXME: Write this]

macro: unless condition . forms

[FIXME: Write this]

core macro: cond . clauses

[FIXME: Write this]

macro: case discriminand . clauses

[FIXME: Write this]


3.5.4 Procedures

core macro: lambda formals . forms

3.5.5 Blocks

A block introduces a scope where some variables are locally bound.

Following a lexical scoping discipline a variable binding is visible in the syntactic region where it has been bound and in every callee, as long as it is not shadowed by an inner binding for the same variable.

macro: let bindings . forms
core macro: let* bindings . forms
macro: letrec bindings . forms
macro: let name bindings . forms

[FIXME: Write this]

The fourth variant, with name being a symbol, is listed here out of completeness but belongs with looping forms; see named let for its description.

macro: destructuring-bind pattern structure . forms

[FIXME: Write this. Common Lisp calls “template” what I call “pattern”.]


3.5.6 Assignment

An assignment operation destructively modifies an existing variable binding.

core macro: set! x . forms

Evaluate the forms forms left-to-right, then assign the result of the last one (or #<nothing> if no forms were given) to the innermost binding for the variable x.

Error out if x is not a symbol, if x is unbound, or if the binding for x is global and constant.

[FIXME: speak about constants]

Rationale: [FIXME: efficiency of compiled code]

primitive wrapper: make-constant! e

[FIXME: write. e must evaluate to a symbol, which is allowed to be also lexically bound; however only its global binding is affected. If called on a globally unbound symbol, it becomes impossible to ever assign or define it.]


3.5.7 Loops

A loop form consists in executing the same body forms potentially multiple times, in sequence.

core macro: while guard . forms

[FIXME: Write this]

macro: do clauses (guard . result-forms) . body-forms

[FIXME: Write this]

macro: dotimes (x count-form . result-forms) . body-forms
macro: dotimesdown (x count-form . result-forms) . body-forms

[FIXME: Write this]

macro: dolist (x list-form . result-forms) . body-forms

[FIXME: Write this]

macro: named-let name bindings . forms
macro: let name bindings . forms

[FIXME: Write this]

The other, simpler, syntax for let is described among block forms: see let.


3.5.8 Making macros

core macro: low-level-macro . forms

[FIXME: Write this. Speak of low-level-macro-args]

macro: macro (macro-name . pattern) . forms

[FIXME: Write this. This uses destructuring bind see destructuring-bind]

The macros above would suffice, along with define, for globally binding macros. However define-macro is provided as a more convenient syntax: see define-macro.


3.5.9 Quoting and quasiquoting

core macro: quote thing
macro: quasiquote template

[FIXME: link prefixes. Remind that ’ is usable]


3.6 Lisp library

[FIXME: Write this]

[FIXME: Every symbol documented here is a global constant, except for macros; rationale: it is convenient to be able to re-define macros in a backwards-compatible way, and macros are not critical to performance as macro calls are always replaced with AST combinations before evaluation]


3.6.1 Type checking


3.6.1.1 Actual type cheking

[FIXME: “Actual” is a terrible word to use here.]

[FIXME: Write. These return a canonical Boolean and never fail.]

primitive wrapper: fixnum? x
primitive wrapper: unique? x
primitive wrapper: boolean? x
primitive wrapper: character? x
primitive wrapper: null? x
primitive wrapper: eof? x
primitive wrapper: nothing? x
primitive wrapper: undefined? x
primitive wrapper: box? x
primitive wrapper: symbol? x
primitive wrapper: cons? x
primitive wrapper: primitive? x
primitive wrapper: macro? x
primitive wrapper: interpreted-closure? x
primitive wrapper: compiled-closure? x
primitive wrapper: ast? x
primitive wrapper: non-null? x
primitive wrapper: non-cons? x
primitive wrapper: non-symbol? x

3.6.1.2 Pseudo-type checking

procedure: number? x
procedure: closure? x
procedure: list? x
procedure: singleton? x
procedure: null-or-singleton? x
procedure: symbols? x
procedure: alist? x

3.6.2 Boolean operations

primitive wrapper: not x
macro: or . clauses
macro: lispy-or . clauses
macro: and . clauses
macro: lispy-and . clauses

[FIXME: lispy-and is provided just for symmetry with lispy-or, and is in fact an alias for and. The traditional Lisp definition for and introduces no inefficiencies in this case, differently from the traditional Lisp implementation of or.]

primitive wrapper: boolean-canonicalize x

3.6.3 Arithmetic

[FIXME: fixnum only for the time being]

primitive wrapper: negate x
primitive wrapper: 1+ x
primitive wrapper: 1- x
primitive wrapper: 2* x
primitive wrapper: 2/ x
primitive wrapper: 2quotient x
primitive wrapper: 2remainder x
primitive wrapper: primordial-+ x y
primitive wrapper: primordial-- x y
primitive wrapper: primordial-* x y
primitive wrapper: primordial-/ x y
primitive wrapper: quotient x y
primitive wrapper: remainder x y
procedure: *-by-sums-procedure x y
procedure: **-procedure b e
macro: + . args
macro: * . args
macro: *-by-sums . args
macro: ** . args
macro: - . args
macro: / . args
procedure: square x
procedure: even? x
procedure: odd? x
fixnum: fixnum-bit-no
fixnum: most-negative-fixnum
fixnum: most-positive-fixnum

3.6.4 Number comparison

[FIXME: fixnum only for the time being]

primitive wrapper: zero? x
primitive wrapper: non-zero? x
primitive wrapper: positive? x
primitive wrapper: non-positive? x
primitive wrapper: negative? x
primitive wrapper: non-negative? x
primitive wrapper: = x y
primitive wrapper: < x y
primitive wrapper: > x y
primitive wrapper: <= x y
primitive wrapper: >= x y
primitive wrapper: <> x y

3.6.5 Symbol handling

primitive wrapper: gensym
primitive wrapper: interned-symbols
primitive wrapper: symbol-global s
primitive wrapper: make-constant! s
primitive wrapper: constant? s
primitive wrapper: defined? s
primitive wrapper: undefine s

3.6.6 Box handling

primitive wrapper: box x
primitive wrapper: box-get b
primitive wrapper: box-set! b x

3.6.7 Cons handling

primitive wrapper: cons a b
primitive wrapper: car c
primitive wrapper: cdr c
procedure: caar c
procedure: cdar c
procedure: cadr c
procedure: cddr c
procedure: caaar c
procedure: cadar c
procedure: caadr c
procedure: caddr c
procedure: cdaar c
procedure: cddar c
procedure: cdadr c
procedure: cdddr c
procedure: caaaar c
procedure: caadar c
procedure: caaadr c
procedure: caaddr c
procedure: cadaar c
procedure: caddar c
procedure: cadadr c
procedure: cadddr c
procedure: cdaaar c
procedure: cdadar c
procedure: cdaadr c
procedure: cdaddr c
procedure: cddaar c
procedure: cdddar c
procedure: cddadr c
procedure: cddddr c
primitive wrapper: set-car! c x
primitive wrapper: set-cdr! c x
procedure: set-caar! c x
procedure: set-cdar! c x
procedure: set-cadr! c x
procedure: set-cddr! c x
procedure: set-caaar! c x
procedure: set-cadar! c x
procedure: set-caadr! c x
procedure: set-caddr! c x
procedure: set-cdaar! c x
procedure: set-cddar! c x
procedure: set-cdadr! c x
procedure: set-cdddr! c x
procedure: set-caaaar! c x
procedure: set-caadar! c x
procedure: set-caaadr! c x
procedure: set-caaddr! c x
procedure: set-cadaar! c x
procedure: set-caddar! c x
procedure: set-cadadr! c x
procedure: set-cadddr! c x
procedure: set-cdaaar! c x
procedure: set-cdadar! c x
procedure: set-cdaadr! c x
procedure: set-cdaddr! c x
procedure: set-cddaar! c x
procedure: set-cdddar! c x
procedure: set-cddadr! c x
procedure: set-cddddr! c x
procedure: car-or-nil c
procedure: cdr-or-nil c
macro: improper-list first-element . more-elements
macro: cons* first-element . more-elements
macro: circular-list first-element . more-elements

3.6.8 List handling

procedure: singleton
macro: list . elements
procedure: replicate n x
procedure: make-list n x
procedure: last-cons xs
procedure: last xs
procedure: all-but-last xs
procedure: all-but-last-reversed xs
procedure: length xs
procedure: reverse xs
procedure: reverse! xs
procedure: append-procedure xs ys
procedure: append-reversed xs ys
procedure: append!-procedure xs ys
macro: append . xss
macro: append! . xss
procedure: flatten xss
procedure: flatten! xss
procedure: flatten-reversed xss
procedure: flatten-reversed! xss
procedure: list-copy xs
procedure: nth-cons xs n
procedure: nth-cons-or-nil xs n
procedure: nth xs n
procedure: take xs n
procedure: take-reversed xs n
procedure: take! xs n
procedure: drop xs n
procedure: drop! xs n
procedure: zip xs n
procedure: zip-reversed xs n
procedure: unzip xs n
procedure: unzip-reversed xs n
procedure: map f xs
procedure: map-reversed f xs
procedure: map! f xs
procedure: fold-left f x xs
procedure: fold-right f xs y
procedure: fold-right! f xs y
procedure: exists? p xs
procedure: for-all? p xs
procedure: filter p xs
procedure: filter-reversed p xs
procedure: range a b
procedure: range-reversed a b
procedure: iota n
procedure: sort xs
procedure: list-has? xs x
procedure: list-without xs x
procedure: list-without! xs x
procedure: all-different?

[FIXME: quadratic]


3.6.9 Alist handling

procedure: assq key alist
procedure: rassq value alist
procedure: del-assq-1 key alist
procedure: del-assq key alist
procedure: del-assq-noncopying key alist
procedure: del-assq-list keys alist
procedure: del-assq-list-noncopying keys alist
procedure: alist-copy alist
procedure: alist-get key alist

3.6.10 Higher order

procedure: compose-procedure f g
procedure: compose-eta f g
macro: compose . fs
macro: compose-pipeline . fs
procedure: square-function f
procedure: square-function-eta f
procedure: iterate f n
procedure: iterate-eta f n
procedure: iterate-pre f n
procedure: iterate-post f n
macro: lambda-wrapper rator arity

3.6.11 Variadic utility

macro: define-left-nested-variadic-extension name original-name neutral
macro: define-right-nested-variadic-extension name original-name neutral
macro: define-associative-variadic-extension name original-name neutral

[FIXME: yes, the things that follow are really procedures]

procedure: variadic-left-deep rator neutral rands
procedure: variadic-right-deep rator neutral rands

3.6.12 Sets as lists

[FIXME: Performance caveat]

[FIXME: order caveat]

[FIXME: The word “set” as used here refers to a collection of objects in the mathematical sense, and has nothing to do with the action of “setting” as performed by set-thing! procedures.]

unique: set-empty
procedure: set-empty? s
procedure: set-singleton x
macro: set . elements
procedure: set-has? s x
procedure: set-with s x
procedure: set-without s x
procedure: set-unite-procedure s1 s2
procedure: set-intersect-procedure s1 s2
procedure: set-subtract-procedure s1 s2
macro: set-unite . sets
macro: set-intersect . sets
macro: set-subtract first-set . other-sets
procedure: list->set xs

[FIXME: No set->list is needed].


3.6.13 AST operations

[FIXME: if the argument is not an AST these all fail.]

primitive wrapper: ast-literal?
primitive wrapper: ast-variable?
primitive wrapper: ast-define?
primitive wrapper: ast-if?
primitive wrapper: ast-set!?
primitive wrapper: ast-while?
primitive wrapper: ast-primitive?
primitive wrapper: ast-call?
primitive wrapper: ast-lambda?
primitive wrapper: ast-let?
primitive wrapper: ast-sequence?

[FIXME: types: when we fail]

primitive wrapper: ast-literal value
primitive wrapper: ast-variable name
primitive wrapper: ast-define name body
primitive wrapper: ast-if condition then else
primitive wrapper: ast-set! name body
primitive wrapper: ast-while guard body
primitive wrapper: ast-primitive operator operands
primitive wrapper: ast-call operator operands
primitive wrapper: ast-lambda formals body
primitive wrapper: ast-let bound-name bound-form body
primitive wrapper: ast-sequence first second

[FIXME: these fail if the argument is not an AST or if it’s an AST of the wrong case] [FIXME: no destructive operations right now. They would be easy to add, even if using them in an unrestricted way might destroy compiler properties; anyway, it is already possible to destroy the same compiler implied properties, by violating other unenforced invariants]

primitive wrapper: ast-literal-value ast
primitive wrapper: ast-variable-name ast
primitive wrapper: ast-define-name ast
primitive wrapper: ast-define-body ast
primitive wrapper: ast-if-condition ast
primitive wrapper: ast-if-then ast
primitive wrapper: ast-if-else ast
primitive wrapper: ast-set!-name ast
primitive wrapper: ast-set!-body ast
primitive wrapper: ast-while-guard ast
primitive wrapper: ast-while-body ast
primitive wrapper: ast-primitive-operator ast
primitive wrapper: ast-primitive-operands ast
primitive wrapper: ast-call-operator ast
primitive wrapper: ast-call-operands ast
primitive wrapper: ast-lambda-formals ast
primitive wrapper: ast-lambda-body ast
primitive wrapper: ast-let-bound-name ast
primitive wrapper: ast-let-bound-form ast
primitive wrapper: ast-let-body ast
primitive wrapper: ast-sequence-first ast
primitive wrapper: ast-sequence-second ast

[FIXME: An example showing a constuction, check and field access for the same case, to highlight the lexical conventions.]


3.6.14 AST optimization

[FIXME: Fill this.]


3.6.15 Macroexpanding

[FIXME: There is currently no syntactic support for local macros, such as Common Lisp’s macrolet.]

primitive wrapper: primordial-macroexpand form env
macro: macroexpand form . optional-env

3.6.16 Code execution

primitive wrapper: apply operator operands
primitive wrapper: apply-primitive operator operands
primitive wrapper: primordial-eval form env
macro: eval form . optional-env

3.6.17 Compilation

[FIXME: Fill this.]


3.6.18 Input and output

JitterLisp provides very crude I/O functionalities. Files are not implemented, so input and output only use the standard input and standard output, respectively, or the terminal via ReadLine.


3.6.18.1 Character I/O

The following functionality provides a thin wrapper over C for reading or writing one character at a time.

primitive wrapper: character-read

Read a single character from the terminal and return it, or return #<eof> if the input ends.

The implementation is a thin wrapper over the getchar function from the C library.

primitive wrapper: character-display c

Print the single character c to the standard output. Error out if c is not a character object.

primitive wrapper: newline

Print a newline character to the standard output.

If newline were not already provided in the library it could be defined as:

(define-constant (newline)
  (character-display #\newline))

3.6.18.2 Lisp object I/O

primitive wrapper: read

Read one Lisp object in its input representation from the terminal, using the Readline functionality if enabled, and return it. Return #<eof> if the input ends before an object is entered.

The input may span several lines and include whitespace or even Lisp comments, but the read object must be exactly one.

Error out on syntax error, or if a second object starts after the first.

primitive wrapper: display thing

Emit the printed representation of thing to the standard output. No newline character or other terminator is added.


3.6.19 Debugging and profiling

primitive wrapper: print-locations

Print data location information, mapping runtime VM data structures into hardware machine resources. This is convenient for reading disassemblies.

primitive wrapper: print-defects

Print the names of all defective specialised instructions. Notice that the set of defective specialised instructions may be different from the set of replaced specialised instructions: when any call-related specialised instruction is defective then every call-related specialised instruction will be replaced.
The output is meant for the user.

primitive wrapper: print-defect-replacements

Print information about defective specialised instruction, listing the name of each replaced specialised instruction along with the specialised instruction replacing it. About the difference between defective specialised instruction and replaced specialised instruction see print-defects.
The output is meant for the user.

primitive wrapper: print-profile-specialized

Print cumulative profile information about the specialised VM instructions run up to this point. This just prints a warning if JitterLisp was not compiled with profiling instrumentation enabled, defining at least one of the CPP macros JITTERLISPVM_PROFILE_COUNT and JITTERLISPVM_PROFILE_SAMPLE; since profiling instrumentation incurs a performance penalty it is disabled by default.

primitive wrapper: print-profile-unspecialized

This primitive wrapper behaves exactly like print-profile-specialized, except that it prints information about unspecialised VM instructions.

primitive wrapper: reset-profile!

Reset profile information, changing the execution count for every instruction back to zero.


3.6.21 Unclassified (move)

procedure: identity x
primitive wrapper: eq? x y
primitive wrapper: not-eq? x y
primitive wrapper: error thing
primitive wrapper: gc

4 C API

[FIXME: Fill this.]


5 Internals

[FIXME: Fill this.]

[FIXME: it’s a stack machine: two stacks plus registers. Explain calling conventions. Explain closure representations. Explain tagging, possibly at the beginning]


Symbol and reserved syntax index

What follows is an alphabetical list of read syntax (see Lisp data) and predefined JitterLisp globals, without distinction between core definitions coming from the C code and library definitions from the library written in Lisp and executed at startup.

In the same sense the index glosses over the difference in type among globally defined variables: some may be procedures or primitive wrappers and other macros, from either the core or the library.

Most of the symbols named here are constant. Some, particularly macros, may not be.

Jump to:   -   ,   .   '   (   )   *   /   #   `   +   <   =   >   1   2  
A   B   C   D   E   F   G   I   L   M   N   O   P   Q   R   S   T   U   V   W   Z  
Index EntrySection

-
-Arithmetic

,
, (comma, prefix for unquote)Conses
, (comma, prefix for unquote)Quoting and quasiquoting
,@ (comma at, prefix for unquote-splicing)Conses
,@ (comma at, prefix for unquote-splicing)Quoting and quasiquoting

.
. (dot, cons syntax)Conses
. (dot), compact cons notationConses

'
' (apostrophe, prefix for quote)Conses
' (apostrophe, prefix for quote)Quoting and quasiquoting

(
( (open parenthesis, cons syntax)Conses
() (empty list object)Uniques

)
) (closed parenthesis, cons syntax)Conses

*
*Arithmetic
*-by-sumsArithmetic
*-by-sums-procedureArithmetic
**Arithmetic
**-procedureArithmetic

/
/Arithmetic

#
#<eof> (no read syntax)Uniques
#<nothing> (no read syntax)Uniques
#<nothing> (no read syntax)AST semantics in detail
#<nothing> (no read syntax)AST semantics in detail
#<undefined> (no read syntax)Uniques
#fUniques
#tUniques

`
` (backtick, prefix for quasiquote)Conses
` (backtick, prefix for quasiquote)Quoting and quasiquoting

+
+Arithmetic

<
<Number comparison
<=Number comparison
<>Number comparison

=
=Number comparison

>
>Number comparison
>=Number comparison

1
1-Arithmetic
1+Arithmetic

2
2*Arithmetic
2/Arithmetic
2quotientArithmetic
2remainderArithmetic

A
alist-copyAlist handling
alist-getAlist handling
alist?Pseudo-type checking
all-but-lastList handling
all-but-last-reversedList handling
all-different?List handling
andBoolean operations
apostrophe ('), prefix for quoteConses
apostrophe ('), prefix for quoteQuoting and quasiquoting
appendList handling
append-procedureList handling
append-reversedList handling
append!List handling
append!-procedureList handling
applyCode execution
apply-primitiveCode execution
assqAlist handling
ast-callAST operations
ast-call-operandsAST operations
ast-call-operatorAST operations
ast-call?AST operations
ast-defineAST operations
ast-define-bodyAST operations
ast-define-nameAST operations
ast-define?AST operations
ast-ifAST operations
ast-if-conditionAST operations
ast-if-elseAST operations
ast-if-thenAST operations
ast-if?AST operations
ast-lambdaAST operations
ast-lambda-bodyAST operations
ast-lambda-formalsAST operations
ast-lambda?AST operations
ast-letAST operations
ast-let-bodyAST operations
ast-let-bound-formAST operations
ast-let-bound-nameAST operations
ast-let?AST operations
ast-literalAST operations
ast-literal-valueAST operations
ast-literal?AST operations
ast-primitiveAST operations
ast-primitive-operandsAST operations
ast-primitive-operatorAST operations
ast-primitive?AST operations
ast-sequenceAST operations
ast-sequence-firstAST operations
ast-sequence-secondAST operations
ast-sequence?AST operations
ast-set!AST operations
ast-set!-bodyAST operations
ast-set!-nameAST operations
ast-set!?AST operations
ast-variableAST operations
ast-variable-nameAST operations
ast-variable?AST operations
ast-whileAST operations
ast-while-bodyAST operations
ast-while-guardAST operations
ast-while?AST operations
ast?Actual type checking

B
backtick (`), prefix for quasiquoteConses
backtick (`), prefix for quasiquoteQuoting and quasiquoting
beginFrom ASTs to JitterLisp
beginFrom ASTs to JitterLisp
beginSequencing
begin-1Sequencing
begin-2Sequencing
begin-3Sequencing
begin-4Sequencing
begin-from-firstSequencing
begin-from-lastSequencing
begin1Sequencing
begin2Sequencing
begin3Sequencing
begin4Sequencing
boolean-canonicalizeBoolean operations
boolean?Actual type checking
boxBox handling
box-getBox handling
box-set!Box handling
box?Actual type checking

C
caaaarCons handling
caaadrCons handling
caaarCons handling
caadarCons handling
caaddrCons handling
caadrCons handling
caarCons handling
cadaarCons handling
cadadrCons handling
cadarCons handling
caddarCons handling
cadddrCons handling
caddrCons handling
cadrCons handling
call/cc (non-existing form)Intentionally omitted features
carCons handling
car-or-nilCons handling
caseConditionals
catch (non-existing form)Intentionally omitted features
catch (non-existing form)Failure
cdaaarCons handling
cdaadrCons handling
cdaarCons handling
cdadarCons handling
cdaddrCons handling
cdadrCons handling
cdarCons handling
cddaarCons handling
cddadrCons handling
cddarCons handling
cdddarCons handling
cddddrCons handling
cdddrCons handling
cddrCons handling
cdrCons handling
cdr-or-nilCons handling
character-displayCharacter I/O
character-readCharacter I/O
character?Actual type checking
circular-listCons handling
closure?Pseudo-type checking
comma (,), prefix for unquoteConses
comma (,), prefix for unquoteQuoting and quasiquoting
comma at (,@), prefix for unquote-splicingConses
comma at (,@), prefix for unquote-splicingQuoting and quasiquoting
compiled-closure?Actual type checking
composeHigher order
compose-etaHigher order
compose-pipelineHigher order
compose-procedureHigher order
condConditionals
consCons handling
cons?Actual type checking
cons*Cons handling
constant?Symbol handling
copyingLegal notices

D
defineDefinition forms
defineMaking macros
define-associative-variadic-extensionVariadic utility
define-constantDefinition forms
define-constant-non-optimizedDefinition forms
define-left-nested-variadic-extensionVariadic utility
define-macroDefinition forms
define-macroMaking macros
define-non-optimizedDefinition forms
define-right-nested-variadic-extensionVariadic utility
defined?Symbol handling
del-assqAlist handling
del-assq-1Alist handling
del-assq-listAlist handling
del-assq-list-noncopyingAlist handling
del-assq-noncopyingAlist handling
destructuring-bindBlocks
displayLisp object I/O
doLoops
dolistLoops
dot (.), compact cons notationConses
dot (.), cons syntaxConses
dotimesLoops
dotimesdownLoops
dropList handling
drop!List handling

E
eof?Actual type checking
eq?Unclassified
errorFailure
errorUnclassified
evalCode execution
even?Arithmetic
exists?List handling

F
filterList handling
filter-reversedList handling
fixnum-bit-noArithmetic
fixnum?Actual type checking
flattenList handling
flatten-reversedList handling
flatten-reversed!List handling
flatten!List handling
fold-leftList handling
fold-rightList handling
fold-right!List handling
for-all?List handling

G
gcUnclassified
gensymSymbol handling

I
identityUnclassified
ifConditionals
improper-listCons handling
interned-symbolsSymbol handling
interpreted-closure?Actual type checking
iotaList handling
iterateHigher order
iterate-etaHigher order
iterate-postHigher order
iterate-preHigher order

L
lambdaProcedures
lambda-wrapperHigher order
lastList handling
last-consList handling
lengthList handling
letBlocks
let, namedBlocks
let, namedLoops
let*Blocks
letrecBlocks
lispy-andBoolean operations
lispy-orBoolean operations
lispy-orBoolean operations
listList handling
list->setSets as lists
list-copyList handling
list-has?List handling
list-withoutList handling
list-without!List handling
list?Pseudo-type checking
low-level-macroMaking macros
low-level-macro-argsMaking macros

M
macroMaking macros
macro?Actual type checking
macroexpandFrom ASTs to JitterLisp
macroexpandFrom ASTs to JitterLisp
macroexpandMacroexpanding
macrolet (non-existing form)Definition forms
macrolet (non-existing form)Macroexpanding
make-constant!Assignment
make-constant!Symbol handling
make-listList handling
mapList handling
map-reversedList handling
map!List handling
most-negative-fixnumArithmetic
most-positive-fixnumArithmetic

N
named letBlocks
named letLoops
named-letLoops
negateArithmetic
negative?Number comparison
newlineCharacter I/O
no-warrantyLegal notices
non-cons?Actual type checking
non-negative?Number comparison
non-null?Actual type checking
non-positive?Number comparison
non-symbol?Actual type checking
non-zero?Number comparison
notBoolean operations
not-eq?Unclassified
nothing?Actual type checking
nthList handling
nth-consList handling
nth-cons-or-nilList handling
null-or-singleton?Pseudo-type checking
null?Actual type checking
number?Pseudo-type checking

O
odd?Arithmetic
orBoolean operations

P
parentheses (()), empty list objectUniques
parenthesis, compact cons notationConses
parenthesis, cons syntaxConses
period (.), compact cons notationConses
period (.), cons syntaxConses
positive?Number comparison
primitive?Actual type checking
primordial--Arithmetic
primordial-*Arithmetic
primordial-/Arithmetic
primordial-+Arithmetic
primordial-evalCode execution
primordial-macroexpandMacroexpanding
print-defect-replacementsDebugging and profiling
print-defectsDebugging and profiling
print-locationsDebugging and profiling
print-profile-specializedDebugging and profiling
print-profile-unspecializedDebugging and profiling

Q
quasiquoteQuoting and quasiquoting
quasiquoteQuoting and quasiquoting
quoteQuoting and quasiquoting
quoteQuoting and quasiquoting
quotientArithmetic

R
rangeList handling
range-reversedList handling
rassqAlist handling
readLisp object I/O
remainderArithmetic
replicateList handling
reset-profile!Debugging and profiling
reverseList handling
reverse!List handling

S
setSets as lists
set->list (non-existing procedure)Sets as lists
set-caaaar!Cons handling
set-caaadr!Cons handling
set-caaar!Cons handling
set-caadar!Cons handling
set-caaddr!Cons handling
set-caadr!Cons handling
set-caar!Cons handling
set-cadaar!Cons handling
set-cadadr!Cons handling
set-cadar!Cons handling
set-caddar!Cons handling
set-cadddr!Cons handling
set-caddr!Cons handling
set-cadr!Cons handling
set-car!Cons handling
set-cdaaar!Cons handling
set-cdaadr!Cons handling
set-cdaar!Cons handling
set-cdadar!Cons handling
set-cdaddr!Cons handling
set-cdadr!Cons handling
set-cdar!Cons handling
set-cddaar!Cons handling
set-cddadr!Cons handling
set-cddar!Cons handling
set-cdddar!Cons handling
set-cddddr!Cons handling
set-cdddr!Cons handling
set-cddr!Cons handling
set-cdr!Cons handling
set-emptySets as lists
set-empty?Sets as lists
set-has?Sets as lists
set-intersectSets as lists
set-intersect-procedureSets as lists
set-singletonSets as lists
set-subtractSets as lists
set-subtract-procedureSets as lists
set-uniteSets as lists
set-unite-procedureSets as lists
set-withSets as lists
set-withoutSets as lists
set!Assignment
singletonList handling
singleton?Pseudo-type checking
sortList handling
squareArithmetic
square-functionHigher order
square-function-etaHigher order
symbol-globalSymbol handling
symbol?Actual type checking
symbols?Pseudo-type checking

T
takeList handling
take-reversedList handling
take!List handling
throw (non-existing form)Intentionally omitted features
throw (non-existing form)Failure

U
undefineSymbol handling
undefined?Actual type checking
unique?Actual type checking
unlessConditionals
unquoteQuoting and quasiquoting
unquoteQuoting and quasiquoting
unquote-splicingQuoting and quasiquoting
unquote-splicingQuoting and quasiquoting
unzipList handling
unzip-reversedList handling

V
values (non-existing form)Intentionally omitted features
variadic-left-deepVariadic utility
variadic-right-deepVariadic utility

W
whenConditionals
whileLoops

Z
zero?Number comparison
zipList handling
zip-reversedList handling


Concept index

Jump to:   -   .   /  
A   B   C   D   E   F   G   H   I   J   L   M   N   O   P   Q   R   S   T   U   V   W   Y  
Index EntrySection

-
--, command-line optionInvoking JitterLisp
--batch, command-line optionInvoking JitterLisp
--colorize, command-line optionInvoking JitterLisp
--compact-uninterned, command-line optionInvoking JitterLisp
--cross-disassembler, command-line optionInvoking JitterLisp
--disable-shared, Jitter configure optionInstalling JitterLisp
--dump-version, command-line optionInvoking JitterLisp
--eval, command-line optionInvoking JitterLisp
--free-routines, command-line optionInvoking JitterLisp
--help, command-line optionInvoking JitterLisp
--library, command-line optionInvoking JitterLisp
--no-batch, command-line optionInvoking JitterLisp
--no-colorize, command-line optionInvoking JitterLisp
--no-compact-uninterned, command-line optionInvoking JitterLisp
--no-cross-disassembler, command-line optionInvoking JitterLisp
--no-free-routines, command-line optionInvoking JitterLisp
--no-library, command-line optionInvoking JitterLisp
--no-omit-nothing, command-line optionInvoking JitterLisp
--no-optimization-rewriting, command-line optionInvoking JitterLisp
--no-repl, command-line optionInvoking JitterLisp
--no-time, command-line optionInvoking JitterLisp
--no-verbose-litter, command-line optionInvoking JitterLisp
--no-verbose, command-line optionInvoking JitterLisp
--omit-nothing, command-line optionInvoking JitterLisp
--optimization-rewriting, command-line optionInvoking JitterLisp
--repl, command-line optionInvoking JitterLisp
--time=time, command-line optionInvoking JitterLisp
--usage, command-line optionInvoking JitterLisp
--verbose-litter, command-line optionInvoking JitterLisp
--verbose, command-line optionInvoking JitterLisp
--version, command-line optionInvoking JitterLisp
-, command-line non-option argumentInvoking JitterLisp
-?, command-line optionInvoking JitterLisp
-c, command-line optionInvoking JitterLisp
-e, command-line optionInvoking JitterLisp
-r, command-line optionInvoking JitterLisp
-v, command-line optionInvoking JitterLisp

.
. AST meta-syntaxAST syntax

/
/1, LispComparison with other Lisps

A
Abstract Syntax Tree (AST)epsilonian features
Abstract Syntax Tree (AST)epsilonian features
Abstract Syntax Tree (AST)Abstract Syntax Trees
Abstract Syntax Tree (AST)Abstract Syntax Trees and their semantics
abstraction, AST semanticsAST semantics in detail
abstraction, AST syntaxAST syntax
abstraction, syntacticAST syntax
addressLisp data
alias, shellInvoking JitterLisp
ambitionInteraction example
ANSI terminal escape sequenceInvoking JitterLisp
architecture, hardwareInvoking JitterLisp
argument (formal), lambda, AST semanticsAST semantics in detail
argument (formal), lambda, AST syntaxAST syntax
assignmentAssignment
assignment, AST semanticsAST semantics in detail
assignment, AST syntaxAST syntax
AST output syntaxAST syntax
AST syntactic constraintAST syntax
AST syntax (output)AST syntax
author, contactingObtaining the software
AutoconfBuilding JitterLisp
AutomakeBuilding JitterLisp

B
beginnerInteraction example
blockBlocks
block, AST semanticsAST semantics in detail
block, AST syntaxAST syntax
body, block, AST semanticsAST semantics in detail
body, block, AST syntaxAST syntax
body, lambda, AST semanticsAST semantics in detail
body, lambda, AST syntaxAST syntax
body, while, AST semanticsAST semantics in detail
body, while, AST syntaxAST syntax
Boehm-Demers garbage collectorBuilding JitterLisp
Boehm-Demers garbage collectorJitterLisp executables
BooleanUniques
Boolean, canonicalUniques
Boolean, generalizedUniques
bound expression, block, AST semanticsAST semantics in detail
bound expression, block, AST syntaxAST syntax
bound value, blockAST semantics in detail
bound variable, block, AST semanticsAST semantics in detail
bound variable, block, AST syntaxAST syntax
boxBoxes
boxed, Lisp objectLisp data
branch, conditional, AST semanticsAST semantics in detail
branch, conditional, AST syntaxAST syntax
branch, gitObtaining the software
build directory (Jitter)Using JitterLisp
build directory (Jitter)Building JitterLisp
build directory (Jitter)Building JitterLisp
build directory (Jitter)Building JitterLisp
build directory (Jitter)JitterLisp executables
build systemUsing JitterLisp
build system, GNUBuilding JitterLisp

C
CObtaining the software
CInvoking JitterLisp
C-d, terminal input closingInvoking JitterLisp
C, macro defined inInvoking JitterLisp
C, macro defined inFrom ASTs to JitterLisp
caddrConses
call name, call, AST semanticsAST semantics in detail
call name, call, AST syntaxAST syntax
call-by-valueAST semantics
call-related VM instructionDebugging and profiling
call-related VM instructionDebugging and profiling
call, AST semanticsAST semantics in detail
call, AST syntaxAST syntax
canonical BooleanUniques
carConses
cdrComparison with other Lisps
cdrConses
characterComparison with other Lisps
characterCharacters
character-based input/outputCharacter I/O
check, make target (Jitter)Building JitterLisp
checking, typeType checking
circularityLisp data
circularity (forbidden), ASTAST semantics in detail
Coding Standards, GNUBuilding JitterLisp
colorInvoking JitterLisp
colorInvoking JitterLisp
colorInvoking JitterLisp
command lineJitterLisp executables
command lineInvoking JitterLisp
command line option (jitterlisp)Invoking JitterLisp
command-line optionsInvoking JitterLisp
common GNU options, command-lineInvoking JitterLisp
Common LispFeatures and influences
Common Lispepsilonian features
compact cons notationConses
compatibility, other Lisp dialects (none)Features and influences
compilationInvoking JitterLisp
compiled closureCompiled closures
compiled procedureComparison with other Lisps
compiled procedureComparison with other Lisps
compilerepsilonian features
compiler, self-Abstract Syntax Trees
complexity, syntaxAST syntax
composed selector, consConses
concept indexConcept index
condition, conditional, AST semanticsAST semantics in detail
condition, conditional, AST syntaxAST syntax
conditionalUniques
conditionalConditionals
conditional, AST semanticsAST semantics in detail
conditional, AST syntaxAST syntax
configuration item, JitterLispJitterLisp executables
configure script, JitterBuilding JitterLisp
configure script, JitterJitterLisp executables
configure script, JitterInstalling JitterLisp
consComparison with other Lisps
consConses
cons notation, compactConses
constantAssignment
contacting the authorObtaining the software
copying (software software)License
copying (software)Legal notices
core macroInvoking JitterLisp
core macroFrom ASTs to JitterLisp
criterion, for feature inclusionFeatures and influences
criterion, for feature inclusionFeatures and influences
criterion, for feature inclusionFeatures and influences
cross compilationUsing JitterLisp
cross compilationBuilding JitterLisp
cross compilingBuilding JitterLisp
cross-disassemblyInvoking JitterLisp
current working directoryJitterLisp executables
cycle (of pointers, within a Lisp object)Lisp data
cyclicity (forbidden), ASTAST semantics in detail

D
DAG, AST in memoryAST semantics in detail
DAG, output syntaxLisp data
data location, printDebugging and profiling
datatypeComparison with other Lisps
debugInvoking JitterLisp
default library, LispInvoking JitterLisp
default, command-line optionInvoking JitterLisp
defective specialised instruction, printDebugging and profiling
defective specialised instruction, print replacementsDebugging and profiling
defined value, global definitionAST semantics in detail
design criterionFeatures and influences
Directed Acyclic Graph, AST in memoryAST semantics in detail
Directed Acyclic Graph, output syntaxLisp data
directory, build (Jitter)Building JitterLisp
directory, current workingJitterLisp executables
disassemblyInvoking JitterLisp
disassemblyInvoking JitterLisp
disassembly, crossInvoking JitterLisp
disassembly, crossInvoking JitterLisp
disassembly, nativeInvoking JitterLisp
dispatch, JitterJitterLisp executables
distributionUsing JitterLisp
distributionUsing JitterLisp
distributionObtaining the software
distributionObtaining the software
dot (.), AST meta-syntaxAST syntax
downloadingObtaining the software
dynamic languageepsilonian features

E
eagerAST semantics
element, listConses
else branch, conditional, AST semanticsAST semantics in detail
else branch, conditional, AST syntaxAST syntax
empty listComparison with other Lisps
empty listUniques
emulatorInvoking JitterLisp
epsilonHistory
epsilonFeatures and influences
epsilonepsilonian features
errorFailure
error, at the REPLFailure
error, out of the REPLFailure
escape sequence, ANSI terminalInvoking JitterLisp
exceptions (non-existing feature)Failure
expresion-0, sequence, AST semanticsAST semantics in detail
expresion-0, sequence, AST syntaxAST syntax
expresion-1, sequence, AST semanticsAST semantics in detail
expresion-1, sequence, AST syntaxAST syntax
expressionComparison with other Lisps
expression, assignment, AST semanticsAST semantics in detail
expression, assignment, AST syntaxAST syntax
expression, ASTAST syntax
expression, global definition, AST semanticsAST semantics in detail
expression, global definition, AST syntaxAST syntax

F
failureFailure
failure, at the REPLFailure
failure, out of the REPLFailure
falseUniques
FDLLicense
featureFeatures and influences
featureComparison with other Lisps
featureComparison with other Lisps
featureComparison with other Lisps
featureComparison with other Lisps
featureComparison with other Lisps
feature inclusion criterionFeatures and influences
feature inclusion criterionFeatures and influences
feature inclusion criterionFeatures and influences
feedbackObtaining the software
file (JitterLisp code)Using JitterLisp
file name, non-option argumentInvoking JitterLisp
first expression, sequence, AST semanticsAST semantics in detail
first expression, sequence, AST syntaxAST syntax
fixnumComparison with other Lisps
fixnumFixnums
fontInvoking JitterLisp
fontInvoking JitterLisp
fontInvoking JitterLisp
form, languageLisp language forms
form, languageLisp language forms
form, top-level (absent in JitterLisp)Comparison with other Lisps
formal, lambda, AST semanticsAST semantics in detail
formal, lambda, AST syntaxAST syntax
free documentationLicense
Free Documentation LicenseLicense
free softwareLicense

G
garbage collectionComparison with other Lisps
garbage collector, Boehm-DemersBuilding JitterLisp
garbage collector, Boehm-DemersJitterLisp executables
General Public LicenseLicense
generalized BooleanUniques
gitObtaining the software
git branchObtaining the software
global definition, AST semanticsAST semantics in detail
global definition, AST syntaxAST syntax
global stateAST semantics
GNU AutoconfBuilding JitterLisp
GNU AutomakeBuilding JitterLisp
GNU binutilsInvoking JitterLisp
GNU build systemUsing JitterLisp
GNU build systemBuilding JitterLisp
GNU Coding StandardsBuilding JitterLisp
GNU conventions, build systemUsing JitterLisp
GNU epsilonHistory
GNU epsilonepsilonian features
GNU Free Documentation LicenseLicense
GNU General Public LicenseLicense
GNU General Public LicenseInstalling JitterLisp
GNU LibtextstyleBuilding JitterLisp
GNU LibtoolInstalling JitterLisp
GNU ReadlineBuilding JitterLisp
GNU ReadlineInvoking JitterLisp
GNU ReadlineInput and output
GNU, standard options, command-lineUsing JitterLisp
GNU, standard options, command-lineInvoking JitterLisp
GPLLicense
GPLInstalling JitterLisp
guard, while, AST semanticsAST semantics in detail
guard, while, AST syntaxAST syntax

H
Hans Boehm’s garbage collectorBuilding JitterLisp
Hans Boehm’s garbage collectorJitterLisp executables
hardware architecture, host (cross-compilation)Invoking JitterLisp
higher orderComparison with other Lisps
highlight, Lisp typeInvoking JitterLisp
historyHistory
homoiconicityComparison with other Lisps
homoiconicityLisp reference
host (cross-compilation)Invoking JitterLisp

I
I/OInvoking JitterLisp
I/OInput and output
identity, procedure across compilingComparison with other Lisps
if, AST syntaxAST syntax
imperativeAST semantics
index, for conceptsConcept index
index, for symbolsSymbol and reserved syntax index
influenceFeatures and influences
initialization file, JitterLispInstalling JitterLisp
initialization file, JitterLispInternals
inputInput and output
input, closingInvoking JitterLisp
input, standardInvoking JitterLisp
input/output, character-basedCharacter I/O
input/output, for Lisp objectsLisp object I/O
installing (by hand, for the time being)Installing JitterLisp
instruction, VM, rewritingInvoking JitterLisp
instruction, VM, specialisedDebugging and profiling
instruction, VM, specialisedDebugging and profiling
interaction (REPL)Using JitterLisp
interpreted closureInterpreted closures
interpreted procedureComparison with other Lisps
interpreted procedureComparison with other Lisps
invokingJitterLisp executables
invokingInvoking JitterLisp
iterationComparison with other Lisps

J
JitterHistory
JitterUsing JitterLisp
JitterBuilding JitterLisp
jitterlisp and related executables, invokingJitterLisp executables
jitterlisp and related executables, invokingInvoking JitterLisp

L
lambda, AST semanticsAST semantics in detail
lambda, AST syntaxAST syntax
language formLisp language forms
language formLisp language forms
learning LispInteraction example
let, AST semanticsAST semantics in detail
let, AST syntaxAST syntax
lexical scopingComparison with other Lisps
lexical scopingSemantics preliminaries
lexical scopingBlocks
library (native, non-Lisp)Installing JitterLisp
library file, JitterLispInstalling JitterLisp
library file, JitterLispInternals
library, default, LispInvoking JitterLisp
LibtextstyleBuilding JitterLisp
LibtoolInstalling JitterLisp
license, for JitterLispLicense
license, for this manualLicense
license, text in JitterLisp executablesInstalling JitterLisp
line editingInvoking JitterLisp
Lisp default libraryInvoking JitterLisp
Lisp object, input/outputLisp object I/O
Lisp/1Comparison with other Lisps
listComparison with other Lisps
listConses
list, emptyUniques
literal, AST semanticsAST semantics in detail
literal, AST syntaxAST syntax
litterJitterLisp executables
litterInvoking JitterLisp
local variableAST semantics in detail
location, printDebugging and profiling
logic rules, operational semantics (in the reader’s head)AST semantics
loopUniques
loopLoops
loop, AST semanticsAST semantics in detail
loop, AST syntaxAST syntax
Luca Saiu, contactingObtaining the software

M
macroFeatures and influences
macroComparison with other Lisps
macroepsilonian features
macroAST syntax
macro (type)Macros
macro, coreInvoking JitterLisp
macro, coreFrom ASTs to JitterLisp
macroexpansionepsilonian features
macroexpansionFrom ASTs to JitterLisp
macroexpansionFrom ASTs to JitterLisp
macroexpansionMacroexpanding
make check (Jitter)Building JitterLisp
manual, licenseLicense
master, git branchObtaining the software
message, litter allocationInvoking JitterLisp
message, litter allocationInvoking JitterLisp
minimalismAST syntax
mutability, variableComparison with other Lisps

N
name, assignment, AST semanticsAST semantics in detail
name, assignment, AST syntaxAST syntax
name, block, AST semanticsAST semantics in detail
name, block, AST syntaxAST syntax
name, global definition, AST semanticsAST semantics in detail
name, global definition, AST syntaxAST syntax
name, variable, AST semanticsAST semantics in detail
name, variable, AST syntaxAST syntax
negative option, command lineInvoking JitterLisp
no warrantyLicense
no warrantyLegal notices
no’, option argument for --time=timeInvoking JitterLisp
non-executable, Jittery routineInvoking JitterLisp
non-option argumentInvoking JitterLisp
notation, cons, compactConses
notation, prefixConses
numberComparison with other Lisps

O
objdumpInvoking JitterLisp
object, Lisp, input/outputLisp object I/O
obtainingObtaining the software
operand values, primitive, AST semanticsAST semantics in detail
operands, call, AST semanticsAST semantics in detail
operands, call, AST syntaxAST syntax
operands, primitive, AST semanticsAST semantics in detail
operands, primitive, AST syntaxAST syntax
operational semantics (in the reader’s head)AST semantics
operator, call, AST semanticsAST semantics in detail
operator, call, AST syntaxAST syntax
operator, primitive, AST semanticsAST semantics in detail
operator, primitive, AST syntaxAST syntax
optimizer, self-Abstract Syntax Trees
option, command line (jitterlisp)JitterLisp executables
option, command line (jitterlisp)Invoking JitterLisp
options, command-lineInvoking JitterLisp
order, higherComparison with other Lisps
outputInvoking JitterLisp
output syntax, consConses

P
path name, file, non-option argumentInvoking JitterLisp
patternBlocks
prefix notationConses
primitivePrimitives
primitive macroPrimitive macros
primitive name, primitive, AST semanticsAST semantics in detail
primitive name, primitive, AST syntaxAST syntax
primitive wrapperInvoking JitterLisp
primitive, AST semanticsAST semantics in detail
primitive, AST syntaxAST syntax
print replacements, defective specialised instructionsDebugging and profiling
print, defective specialised instructionsDebugging and profiling
print, locationDebugging and profiling
print, profile, specialisedDebugging and profiling
print, profile, unspecialisedDebugging and profiling
procedureComparison with other Lisps
procedureComparison with other Lisps
procedureComparison with other Lisps
procedure call, AST semanticsAST semantics in detail
procedure call, AST syntaxAST syntax
procedure, compiledComparison with other Lisps
procedure, interpretedComparison with other Lisps
profile, resetDebugging and profiling
profile, specialised, printDebugging and profiling
profile, unspecialised, printDebugging and profiling
programmer, non-Interaction example
promising beginnerInteraction example

Q
quasiquotingComparison with other Lisps
quasiquotingepsilonian features
quasiquotingQuoting and quasiquoting
quotingComparison with other Lisps
quotingQuoting and quasiquoting

R
read syntaxLisp data
read syntax, consConses
Read-Eval-Print LoopUsing JitterLisp
Read-Eval-Print LoopInvoking JitterLisp
ReadlineBuilding JitterLisp
ReadlineInvoking JitterLisp
ReadlineInput and output
ReadlineLisp object I/O
recursionComparison with other Lisps
reference, variable, AST syntaxAST syntax
reflectionepsilonian features
reflectionAbstract Syntax Trees
REPLUsing JitterLisp
REPLFrom ASTs to JitterLisp
replacement, defective specialised instructions, printingDebugging and profiling
reset, profileDebugging and profiling
rewritingInvoking JitterLisp
routine, executable, JitteryInvoking JitterLisp
routine, JitteryInvoking JitterLisp
routine, non-executable, JitteryInvoking JitterLisp

S
safe, JitterLisp configuration itemJitterLisp executables
Saiu, Luca, contactingObtaining the software
SchadenfreudeGoals
SchadenfreudeGoals
SchemeFeatures and influences
scopingAST semantics
scoping, lexicalComparison with other Lisps
scoping, lexicalSemantics preliminaries
scoping, lexicalBlocks
script, shellInvoking JitterLisp
second expression, sequence, AST semanticsAST semantics in detail
second expression, sequence, AST syntaxAST syntax
self-compilerAbstract Syntax Trees
self-optimizerAbstract Syntax Trees
sequence, AST semanticsAST semantics in detail
sequence, AST syntaxAST syntax
sequence, escape, ANSI terminalInvoking JitterLisp
sequencingSequencing
set!, AST semanticsAST semantics in detail
set!, AST syntaxAST syntax
shared libraryInstalling JitterLisp
sharingLisp data
shellInvoking JitterLisp
shell aliasInvoking JitterLisp
software, licenseLicense
sourceUsing JitterLisp
sourceObtaining the software
space overhead, tail callComparison with other Lisps
specialised, profile, printDebugging and profiling
spine, listConses
standard errorInvoking JitterLisp
standard GNU options, command-lineInvoking JitterLisp
standard inputInvoking JitterLisp
stateAST semantics
statement (absent in JitterLisp)Comparison with other Lisps
static libraryInstalling JitterLisp
static scopingComparison with other Lisps
static scopingSemantics preliminaries
static scopingBlocks
structure sharing, ASTAST semantics in detail
sub-expressionComparison with other Lisps
sub-projectHistory
sub-sub-projectHistory
sublistConses
substructure sharingLisp data
symbolComparison with other Lisps
symbolSymbols
symbol indexSymbol and reserved syntax index
syntactic abstractionAST syntax
syntactic complexityAST syntax
syntactic constraint, ASTAST syntax
syntaxLisp data
syntax (output), ASTsAST syntax
syntax, consConses

T
tail callComparison with other Lisps
tarball, stable release (not yet)Building JitterLisp
template (Common Lisp)Blocks
terminal escape sequence, ANSIInvoking JitterLisp
test suite, JitterBuilding JitterLisp
then branch, conditional, AST semanticsAST semantics in detail
then branch, conditional, AST syntaxAST syntax
top-level form (absent in JitterLisp)Comparison with other Lisps
trueUniques
typeComparison with other Lisps
type checkingType checking

U
unboxed, Lisp objectLisp data
uniqueUniques
unsafe, JitterLisp configuration itemJitterLisp executables
unspecialised, profile, printDebugging and profiling
usage (JitterLisp)Using JitterLisp

V
value, literal, AST semanticsAST semantics in detail
value, literal, AST syntaxAST syntax
variableComparison with other Lisps
variable name, assignment, AST semanticsAST semantics in detail
variable name, assignment, AST syntaxAST syntax
variable, AST semanticsAST semantics in detail
variable, AST syntaxAST syntax
variadic, procedure (absent in JitterLisp)Intentionally omitted features
verbose’, option argument for --time=timeInvoking JitterLisp
verbosityInvoking JitterLisp
VM instruction rewritingInvoking JitterLisp
VM instruction, specialisedDebugging and profiling
VM instruction, specialisedDebugging and profiling

W
warranty, lack thereofLicense
warranty, lack thereofLegal notices
while, AST semanticsAST semantics in detail
while, AST syntaxAST syntax
write syntaxLisp data

Y
yes’, option argument for --time=timeInvoking JitterLisp


Footnotes

(1)

[FIXME: justify; not as homoiconic as other Lisps appear, but still more than epsilon. I argue that any Lisp system aiming at decent performance must do something like that; the difference is that I expose this mechanism.]

(2)

At the time of writing this restriction is moot. It is in fact impossible in the current implementation to build a circular AST, for two reasons: first of all, ASTs are immutable from JitterLisp, with the currently existing primitives; second, letrec (see Blocks) relies on assignment to a variable when building circular closures, and the strict constraint-checking policy of ASTs along with call-by-value evaluation prevents a “temporary” value from being used inside an AST to be built and then replaced later.