LispKit is a framework for building Lisp-based extension and scripting languages for macOS applications. LispKit is fully written in the programming language Swift. LispKit implements a core language based on the R7RS (small) Scheme standard. It is extensible, allowing the inclusion of new native libraries written in Swift, of new libraries written in Scheme, as well as custom modifications of the core environment consisting of a compiler, a virtual machine as well as the core libraries.
So far, performance was not a priority in the development of LispKit. The LispKit compiler does not perform many code optimizations and the performance of the system is below state of the art Lisp and Scheme implementations.
The NumericalScheme demo showcases how to create a derived LispKit interpreter that inherits everything from LispKit (without code duplication) and defines a new native as well as Scheme-based library.
LispPad implements a simple, lightweight, integrated development environment for LispKit on macOS with a Cocoa-based UI. A simpler command-line tool with similar functionality is provided by the LispKit framework itself (see below).
LispKit provides support for the following core features, many of which are based on R7RS:
- Modules based on R7RS libraries
- Hygienic macros based on
syntax-rules
- First-class environments
call/cc
,dynamic-wind
and exceptions- Dynamically-scoped parameters
- Multiple return values
- Delayed execution via promises and streams
- Support for the full numerical tower consisting of arbitrary size integers, rationals, real numbers, and inexact complex numbers.
- Unicode strings and characters
- Vectors and bytevectors
- Text and binary ports
- R7RS-compliant records
- R6RS-compliant hashtables
- R6RS-compliant enumerations
- All R7RS (small) libraries:
(scheme base)
,(scheme case-lambda)
,(scheme char)
,(scheme complex)
,(scheme cxr)
,(scheme eval)
,(scheme file)
,(scheme inexact)
,(scheme lazy)
,(scheme load)
,(scheme process-context)
,(scheme read)
,(scheme repl)
,(scheme time)
,(scheme write)
,(scheme r5rs)
- Some R7RS (large) libraries from Scheme Red and Scheme Tangerine editions:
(scheme box)
,(scheme charset)
,(scheme comparator)
,(scheme generator)
,(scheme hash-table)
,(scheme ideque)
,(scheme list)
,(scheme mapping)
,(scheme rlist)
,(scheme set)
,(scheme sort)
,(scheme stream)
,(scheme text)
,(scheme vector)
- LispKit-specific libraries:
(lispkit base)
,(lispkit core)
,(lispkit control)
,(lispkit system)
,(lispkit box)
,(lispkit math)
,(lispkit list)
,(lispkit hashtable)
,(lispkit dynamic)
,(lispkit type)
,(lispkit vector)
,(lispkit gvector)
,(lispkit record)
,(lispkit bytevector)
,(lispkit char)
,(lispkit char-set)
,(lispkit string)
,(lispkit port)
,(lispkit date-time)
,(lispkit draw)
,(lispkit draw turtle)
,(lispkit datatype)
,(lispkit object)
,(lispkit enum)
,(lispkit regexp)
,(lispkit stream)
,(lispkit graph)
,(lispkit match)
,(lispkit iteration)
,(lispkit log)
,(lispkit set)
,(lispkit stack)
,(lispkit queue)
,(lispkit heap)
,(lispkit disjoint-set)
,(lispkit wt-tree)
,(lispkit comparator)
,(lispkit logic)
,(lispkit clos)
,(lispkit test)
,(lispkit prettify)
,(lispkit csv)
,(lispkit markdown)
,(lispkit json)
, and(lispkit pdf)
.
LispKit is incompatible or incomplete with respect to the following R7RS features:
- Lists are immutable. Mutable cons-cells are supported in a way similar to Racket
- Datum comments introduced via
#;
do not always work as in other Scheme dialects.
The following SRFI libraries have been ported to LispKit and are included in the framework:
- SRFI 1: List Library
- SRFI 2: AND-LET* - an AND with local bindings, a guarded LET* special form
- SRFI 8: receive - Binding to multiple values
- SRFI 11: Syntax for receiving multiple values
- SRFI 14: Character-set library
- SRFI 16: Syntax for procedures of variable arity
- SRFI 17: Generalized set!
- SRFI 19: Time Data Types and Procedures
- SRFI 23: Error reporting mechanism
- SRFI 26: Notation for Specializing Parameters without Currying
- SRFI 27: Sources of Random Bits
- SRFI 28: Basic Format Strings
- SRFI 31: A special form rec for recursive evaluation
- SRFI 33: Integer Bitwise-operation Library
- SRFI 34: Exception Handling for Programs
- SRFI 35: Conditions
- SRFI 39: Parameter objects
- SRFI 41: Streams
- SRFI 46: Basic Syntax-rules Extensions
- SRFI 48: Intermediate Format Strings
- SRFI 51: Handling rest list
- SRFI 55: require-extension
- SRFI 63: Homogeneous and Heterogeneous Arrays
- SRFI 64: A Scheme API for test suites
- SRFI 69: Basic hash tables
- SRFI 87:
=>
in case clauses - SRFI 95: Sorting and Merging
- SRFI 98: An interface to access environment variables
- SRFI 101: Purely Functional Random-Access Pairs and Lists
- SRFI 111: Boxes
- SRFI 112: Environment inquiry
- SRFI 113: Sets and bags
- SRFI 121: Generators
- SRFI 125: Intermediate hash tables
- SRFI 128: Comparators
- SRFI 129: Titlecase procedures
- SRFI 132: Sort Libraries
- SRFI 133: Vector Library
- SRFI 134: Immutable Deques
- SRFI 135: Immutable Texts
- SRFI 137: Minimal Unique Types
- SRFI 142: Bitwise Operations
- SRFI 145: Assumptions
- SRFI 146: Mappings
- SRFI 151: Bitwise Operations
- SRFI 152: String Library
- SRFI 158: Generators and Accumulators
- SRFI 161: Unifiable Boxes
- SRFI 165: The Environment Monad
- SRFI 167: Ordered Key Value Store
- SRFI 173: Hooks
- SRFI 174: POSIX Timespecs
- SRFI 175: ASCII Character Library
- SRFI 177: Portable keyword arguments
The project defines three different targets:
- LispKit: the core interpreter framework, including all support files
- LispKitTools: a framework for tools supporting LispKit; e.g. a read-eval-print framework
- LispKitRepl: a command-line tool implementing a read-eval-print loop
From an architectural perspective, LispKit consists of:
- a compiler translating LispKit expressions into bytecode,
- a virtual machine for interpreting the generated bytecode. The virtual machine is stack-based, handles tail calls and continuations, and provides a garbage collector.
- a large range of libraries, all packaged together with the framework.
Details can be found in the LispKit Wiki.
This project also includes a command-line tool, called the LispKit Shell, for executing LispKit applications in the terminal. It can be used to try out and experiment with the LispKit framework. The command-line tool can also be used interactively as a read-eval-print loop. The read-eval-print loop parses the entered LispKit expression, compiles it to bytecode, executes it, and displays the result.
First, clone the LispKit repository via git
. The following command will create a directory swift-lispkit
.
> git clone https://github.com/objecthub/swift-lispkit.git
Cloning into 'swift-lispkit'...
remote: Enumerating objects: 14, done.
remote: Counting objects: 100% (14/14), done.
remote: Compressing objects: 100% (12/12), done.
remote: Total 5300 (delta 1), reused 14 (delta 1), pack-reused 5286
Receiving objects: 100% (5300/5300), 1.76 MiB | 132.00 KiB/s, done.
Resolving deltas: 100% (3724/3724), done.
Next, switch to Xcode and build the LispKit command-line tool via scheme LispKitRepl
:
> open LispKit.xcodeproj
A debug binary can be built in the following way:
> cd swift-lispkit
> swift build -Xswiftc "-D" -Xswiftc "SPM"
Fetching https://github.com/objecthub/swift-numberkit.git
Fetching https://github.com/objecthub/swift-commandlinekit.git
Fetching https://github.com/objecthub/swift-markdownkit.git
Completed resolution in 6.47s
Cloning https://github.com/objecthub/swift-numberkit.git
Resolving https://github.com/objecthub/swift-numberkit.git at 2.3.2
Cloning https://github.com/objecthub/swift-markdownkit.git
Resolving https://github.com/objecthub/swift-markdownkit.git at 0.2.0
Cloning https://github.com/objecthub/swift-commandlinekit.git
Resolving https://github.com/objecthub/swift-commandlinekit.git at 0.3.1
[124/124] Linking LispKitRepl
The debug binary can be run by invoking .build/debug/LispKitRepl -d LispKit
assuming that directory ~/Documents/LispKit
contains a copy of the
resources directory
needed to run the command-line tool.
A release binary can be built like this:
> cd swift-lispkit
> swift build -c release -Xswiftc "-D" -Xswiftc "SPM"
Fetching https://github.com/objecthub/swift-numberkit.git
Fetching https://github.com/objecthub/swift-commandlinekit.git
Fetching https://github.com/objecthub/swift-markdownkit.git
Completed resolution in 4.02s
Cloning https://github.com/objecthub/swift-numberkit.git
Resolving https://github.com/objecthub/swift-numberkit.git at 2.3.2
Cloning https://github.com/objecthub/swift-markdownkit.git
Resolving https://github.com/objecthub/swift-markdownkit.git at 0.2.0
Cloning https://github.com/objecthub/swift-commandlinekit.git
Resolving https://github.com/objecthub/swift-commandlinekit.git at 0.3.1
[6/6] Linking LispKitRepl
The release binary can be run by invoking .build/release/LispKitRepl -r Sources/LispKit/Resources
in the directory swift-lispkit
(in which the binary was build above).
Assuming that directory ~/Documents/LispKit
contains a copy of the
resources directory, it is also
possible to run the release binary by invoking .build/release/LispKitRepl -d LispKit
.
The following technologies are needed to build the components of the LispKit framework. For building the command-line tool, all that is needed is the Swift Package Manager. For compiling the framework and trying the command-line tool directly in Xcode, the Swift Package Manager is not needed.