Skip to content
Switch branches/tags

Latest commit


Git stats


Failed to load latest commit information.
Latest commit message
Commit time
        `___`         embeddable
        (O,O)             and
        \)  )          purely
      ---"-"---     functional!
   O t u s L i s p

 /Based on Aki Helin's Owl-Lisp/

Travis-CI project page Visit the project page Github build ol status

Otus Lisp, Version 2.2

Otus Lisp (Ol in short) is a purely functional dialect of Lisp.

It implements an extended subset of the R7RS Scheme, including but not limited to some SRFIs. It is tiny (< 64KB), embeddable and cross-platform. Provides a portable, high-level interface to call code written in another language.

You can use Ol on Linux, Windows, macOS, Android, BSD (and its descendants), webOS, Solaris and other operating systems based on various hardware architectures (intel, arm, ppc, mips, etc).

Also Ol is ported to the Web and can be used in Chrome, Firefox, Opera, Iceweasel, Epiphany, Luakit, SeaMonkey, Iceape, etc.

Source code available under tag "2.2" or at Releases page.


Otus Lisp is available under 2 licenses: MIT License and GNU (L)GPLv3 License.

Copyright (c) 2011-2014 Aki Helin
Copyright (c) 2014-2021 Yuriy Chumak


Join the online Join the chat at, additionally Freenode channel #otus-lisp is available.

Post bugs and issues at the issues page. If your architecture is not supported, post an issue too.


You can find Ol samples at:


You can use basic Ol functionality without any installation - just copy the ol (ol.exe for Windows) binary to any user-accessible path.

Basic functionality includes a rich set of features: lists, vectors and bytevectors, numbers math with unlimited accuracy, strings, associative arrays (named ff), i/o streams and files, lazy calculations, regular expressions, coroutines, etc.

Advanced functionality (i.e. OpenGL support) requires a complete installation of the Ol package:

  • You can use precompiled binaries and/or installation packages that can be found at the Releases announcement page.
  • or You can manually copy required libraries to your OL_HOME or current directory,

Some libraries can be installed using 'kiss' package manager. Usage instruction available at ol-packages repository.

Otus Lisp, Version 2.3 rc1

New Ol changes have been added to the Master branch:

  • the build command line has been changed. See the "BUILD" section.
  • fasl format updated:
    • fasl is fully 32/64 bit independent (32-bit machines can execute 64-bit fasl and vice versa),
    • numbers encoded as numbers, not as objects,
    • big endian numbers order changed to little-endian
    • introduced a new object type 63 - "constructor", constructors are automatically executed by olvm during fasl loading process
      • if no constructors are found, the vanilla behavior will be used
      • note: for example the library (owl math) contains a constructor (math-constructor) that recalculates a NaN value which is different under different fpu architectures.


  • 2.1. Identifiers
    • |\t\t| and |\x9;\x9;| are different in Ol, but the same in Scheme.
    • Ol is definitely case sensitive, but Sheme is configurable with #!fold-case and #!no-fold-case.
  • 4.1.5. Conditionals
    • Ol provides extended if in forms (if <condition> <then-clause> else <else1-clause>..<elseN-clause>) and (if <condition> then <then1-clause> <then2-clause> else <else1-clause>..<elseN-clause>), while Scheme is not.
  • 4.1.6. Assignments
    • No set! in Ol.
      • note: Ol is purely functional language.
  • 4.1.7. Inclusion
    • No include and include-ci in Ol.
      • note: Use ",load" instead.
  • 4.2.1. Conditionals
    • Result of the when expression is value returned by the last expression in Ol, but unspecified in Scheme.
    • Result of the unless expression is value returned by the last expression in Ol, but unspecified in Scheme.
  • 4.2.5. Delayed evaluation
    • No delay-force, promise? and make-promise in Ol.
      • note: But DELAY and FORCE exists, sure.
  • 4.2.7. Exception handling
    • No guard and raise in Ol.
  • 5.5. Record-type definitions
    • No define-record-type in Ol.
  • 6.1. Equivalence predicate eqv?
    • (eqv? +nan.0 +nan.0) is #true in Ol, but unspecified in Scheme. The same for +inf.0 and -inf.0.
  • 6.2.5. Syntax of numerical constants
    • NUMBERS WITHOUT PRECISION considered to be exact in Ol, but inexact in Scheme.
      • explanation: Inexactness can be disabled by compiler features or/and unsupported by platform. But we should expect the same behavior of the program independently of inexactness support (unless we use inexact numbers, sure).
  • 6.2.6. Numerical operations
    • Just Note: complex? is the same as number?, like in Scheme.
    • integer? for inexact numbers always returns #false in Ol, but can be #true in Scheme when (= number (round number)).
      • explanation: Inexactness is an inexactness - we may lose the fractional part and not to be noticed about. So let's be a little paranoid.
    • sqrt is included in base library profile while not included in Scheme
      • explanation: due to frequent use.
  • 6.4. Pairs and lists
    • memq and assq behavior with 'short' numbers (aka 'enumerations') as first argument is fully specified in Ol, but unspecified in Scheme.
      • note: those numbers processed by memq and assq as usual elements.
  • 6.6. Characters
    • CHARACTERS in Ol is a small numbers (aka 'enumerations'), but a characters in Scheme.
      • explanation: This is for a historical reason. Ol supports two types of numbers - 'small' numbers and 'long' numbers. 'Small' numbers are used as 'glyphs' (or 'runes' in other word) inside strings for better Unicode support. An additional 'character' type with requirements to use the char->integer and integer->char functions every time is too boring and slow. Thanks.
      • note: Ol supports full Unicode 12.1.0 (2020 Jun 13) character set.
      • note: If you want to print a character in the form of a letter (or a digit, etc.), use a function 'string', i.e. instead of (print #\λ) use (print (string #\λ)), otherwise you will get a number 955.
  • 6.8. Vectors
    • NEGATIVE indices of a vector is valid in Ol, but invalid in Scheme.
      • note: Negative indices of a vector can be used to access to the n-th element from the end of a vector. I mean "-1" is the last vector element, "-2" - before the last element, "-N" - N-th element from the end of a vector.
  • 6.11. Exceptions
    • No exceptions handling in Ol.
      • note: Yet.
  • Ol has builtin regular expressions while Scheme not.
    • note: you can use m/<pattern>/, s/<expression>/<new-expression>/ (with optional 'g' suffix) and c/<pattern>/ as functions to match, change and split the string.


Note: Since version 2.2.1, the build command line has been changed. The variable NAKED_VM is no longer supported. Instead, a new REPL build variable is provided.


You should have GCC 3.2+ (with gcc-multilib) or CLANG 3.5+ installed.

MacOS users should have xcode-tools installed.

Windows support requires MinGW installed (with GCC). Wine cross-compilation is also supported.

WebAssembly binary compilation requires Emscripten 1.37.40+.


$ make; make install
  • Note: use gmake for unix clients
  • Note: use make uninstall to completely uninstall Ol.



Build olvm (ol virtual machine):
$ cc src/olvm.c  -std=gnu99 -O2  -lm -ldl  -o vm
Build ol (with integrated REPL):
$ xxd --include repl >tmp/repl.c
$ echo '(display "unsigned char repl[] = {") (lfor-each (lambda (x) (for-each display (list x ","))) (file->bytestream "repl")) (display "0};")'| ./vm repl >tmp/repl.c
$ cc src/olvm.c tmp/repl.c  -DREPL=repl  -std=gnu99 -O2  -lm -ldl  -o ol

For some platforms, build can be done without using the xxd tool or vm itself.

$ ld -r -b binary -o repl.o repl
$ cc src/olvm.c -DREPL=_binary_repl_start  repl.o  -std=gnu99 -O2  -lm -ldl  -o ol
Build WebAssembly Binaries (in wasm form):
$ source {your-emsdk-path}/
$ make olvm.wasm

This should create olvm.wasm and olvm.js - web assembly ol representation. An example usage of Ol as a built-in web application you can check at the official project page.


Build olvm (ol virtual machine):
> set PATH=%PATH%;C:\MinGW\bin
> gcc.exe src\olvm.c -IC:\MinGW\include\ -LC:\MinGW\lib\ -std=gnu99 -O2  -lws2_32  -o ol
Build ol (with integrated REPL):
> set PATH=%PATH%;C:\MinGW\bin
> ld -r -b binary -o tmp/repl.o repl
> gcc.exe src\olvm.c tmp\repl.o -DREPL=repl -IC:\MinGW\include\ -LC:\MinGW\lib\ -std=gnu99 -O2  -lws2_32  -o ol


You should include "c" library instead of "dl":

Build only olvm (ol virtual machine):
$ cc src/olvm.c  -std=gnu99 -O2  -lc -lm  -o vm
Build ol (with integrated REPL):
$ ld -r -b binary -o tmp/repl.o repl
$ cc src/olvm.c tmp/repl.o  -std=gnu99 -O2  -lc -lm  -o ol -DREPL=_binary_repl_start


$ ndk-build

Open webOS:

Put toolchain/ bitbake recipe into any place of open webOs recipes folder (i.e. ./meta-oe/) and run "make ol" from root open webOs folder.

Upload ol executable from BUILD/work//ol//build to machine /bin.

Now you cat execute ol under webos command line or other way you would like.


You can check some sample lisp programs. For example:

"pacman" screenshot

"digital rain" screenshot

"newton" screenshot


If you want to enable/disable some olvm features you can use -Dxxx or -Dxxx=y gcc syntax. This is a list of currently accessible customizations:

Variable Value Meaning
REPL undefined Which source code binary data is a REPL
OLVM_NOMAIN 1|0, default 0 Disable 'main' function, make olvm embed
OLVM_FFI 1|0, default 1 Enable FFI support
OLVM_CALLABLES 1|0, default 1 Enable FFI callbacks support
OLVM_INEXACTS 1|0, default 1 Enable inexact math support
OLVM_BUILTIN_FMATH 1|0, default 1 Enable builtin vm floating-point math
CAR_CHECK 1|0, default 1 Enable car arguments check
CDR_CHECK 1|0, default 1 Enable cdr arguments check

This variables are automatically set by the Makefile (like configure script). You can override those values, sure:

Variable Value Meaning
HAS_SOCKETS 1|0, default 1 Enable sockets support (bind, listen, socket, etc.)
HAS_DLOPEN 1|0, default 1 Enable dlopen/dlsym functions support
HAS_UNSAFES 1|0, default 1 Enable "unsafe" external and internal functions
HAS_SANDBOX 1|0, default 0 Enable internal sandbox support (depends on OS kernel)
HAS_STRFTIME 1|0, default 1 Enable strftime function support

Please note that external libraries (like opengl, sqlite, etc.) support require HAS_DLOPEN and OLVM_FFI enabled.

Additionally you can disable the following olvm features by setting the variables to 0 (-Dxxx=0):

Variable Meaning
SYSCALL_SYSINFO sysinfo() function usage
SYSCALL_PIPE pipe() function usage
SYSCALL_GETRLIMIT getrlimit() function usage
SYSCALL_GETRUSAGE getrusage() function usage


You can change the Otus Lisp language as a language (yes, you can) by editing the sources in lang/ and libraries/ subfolders. Additionally, you can change the virtual machine itself by editing the src/vm.scm and src/olvm.c source files.

To build the Otus Lisp language (not olvm) named REPL do:

$ make recompile

This will create a new (in successful way) REPL binary ./repl containing the compiled ol code.


Ol command line is: $ ol [[vm-options] [filename]] [arguments]]

  • if no filename given all options is ol options, not an olvm
  • if no filename given ol will use stdin as source
  • if you want to use stdin as source but must provide a filename and/or arguments, use "-"
  • if you want to break vm-options scanning and provide filename like option (i.e. '--version'), use "--" as 'end-of-option' flag

Current olvm command line options available:

  • '--version': print olvm version and exit

Ol can be executed interactively or in the unattended mode.

Interactive mode

$ ol
Welcome to Otus Lisp 2.2,
type ',help' to help, ',quit' to end session.
; now you in REPL and can play with in
> (+ 1 2 3)
; or let's make some factorial calculations?
> (let factorial ((n 17))
   (if (= n 0)
      (* n (factorial (- n 1)))))
; this ends interactive session
> ,quit
bye bye :/

Unattended mode

GNU/Linux, Unixes, *BSDs, macOS, ...

$ ol scriptname.ol                # text script
$ ol                # binary (compiled) script
$ echo '(print (+ 1 2 3))' | ol


> ol scriptname.ol
> ol
> echo (print (+ 1 2 3)) | ol


OL can execute precompiled scripts. You can compile your script using this code:

(define (main . args)
   (print "hello !")) ; anything you want to compile

(fasl-save main "")

where "" is your binary output file name. This code creates binary script that can be executed directly by ol or vm:

$ ./vm
hello !

$ ./ol
hello !


  • repl - the compiled ol binary interpreter/compiler
  • src/olvm.c - the ol virtual machine source code (in C)
  • includes/ol/ol.h - the common ol header (not required by compiler, just for use as embed)
  • includes/ol/vm.h - the ol virtual machine header (not required by compiler, just for use as embed)
  • extensions/ffi.c - FFI implementation
  • lang/*.scm - ol repl and compiler source codes (in Lisp)
  • libraries/**.scm - various OL libraries (in Lisp):
    • libraries/scheme/core.scm - r7rs core implementation
    • libraries/owl/*.scm - legacy basic libraries
    • libraries/lib/*.scm - some external native library mappings
    • etc.
  • tests/** - some basic automation tests (in Lisp and C)
  • tests/rosettacode/*.scm - additional automation tests (in Lisp) that described at the Rosetta Code programming chrestomathy site.


Register interpreter in the linux: start you script with

#!/usr/bin/env ol

Register interpreter in the ms windows:

assoc .ol=OLisp.File
ftype OLisp.File=ol "%1" %*
assoc .bl=OLisp.Binary.File
ftype OLisp.Binary.File=ol "%1" %*


Please refer to the embedding sample README.


Please refer to the project page or check the source codes - libraries/scheme/core.scm


Copyright (c) 2014 Aki Helin
Copyright (c) 2014 - 2021 Yuriy Chumak

Grew out of the Owl Lisp by Aki Helin:

Thanks to:

Packaging status Packaging status latest packaged version(s)