This is a small interpreter of a subset of Scheme
in circa 900 lines of Java 8 and 11
(including a small arithmetic package
little_arith
in circa 100 lines).
It implements almost the same language as
- little-scheme-in-crystal
- little-scheme-in-cs
- little-scheme-in-dart
- little-scheme-in-go
- little-scheme-in-kotlin
- little-scheme-in-lisp
- little-scheme-in-php
- little-scheme-in-python
- little-scheme-in-ruby
- little-scheme-in-typescript
and their meta-circular interpreter, little-scheme.
As a Scheme implementation, it optimizes tail calls and handles first-class continuations properly.
$ make
rm -f little_arith/*.class little_scheme/*.class
javac -encoding utf-8 little_scheme/Main.java
jar cfm little-scheme.jar Manifest LICENSE little_arith/*.class little_scheme/*.
class
$ java -jar little-scheme.jar
> (+ 5 6)
11
> (cons 'a (cons 'b 'c))
(a b . c)
> (list
| 1
| 2
| 3
| )
(1 2 3)
>
Press EOF (e.g. Control-D) to exit the session.
> Goodbye
$
You can run it with a Scheme script.
Examples are found in
little-scheme;
download it at ..
and you can try the following:
$ java -jar little-scheme.jar ../little-scheme/examples/yin-yang-puzzle.scm |
> head
*
**
***
****
*****
******
*******
********
*********
^C$
$ java -jar little-scheme.jar ../little-scheme/examples/amb.scm
((1 A) (1 B) (1 C) (2 A) (2 B) (2 C) (3 A) (3 B) (3 C))
$ java -jar little-scheme.jar ../little-scheme/examples/nqueens.scm
((5 3 1 6 4 2) (4 1 5 2 6 3) (3 6 2 5 1 4) (2 4 6 1 3 5))
$ java -jar little-scheme.jar ../little-scheme/scm.scm \
> < ../little-scheme/examples/nqueens.scm
((5 3 1 6 4 2) (4 1 5 2 6 3) (3 6 2 5 1 4) (2 4 6 1 3 5))
$
Press INTR (e.g. Control-C) to terminate the yin-yang-puzzle.
Put a "-
" after the script in the command line to begin a session
after running the script.
$ java -jar little-scheme.jar ../little-scheme/examples/fib90.scm -
2880067194370816120
> (globals)
(globals error number? = < * - + apply call/cc symbol? eof-object? read newline
display list not null? pair? eq? cons cdr car fibonacci)
> (fibonacci 16)
987
> (fibonacci 1000)
43466557686937456435688527675040625802564660517371780402481729089536555417949051
89040387984007925516929592259308032263477520968962323987332247116164299644090653
3187938298969649928516003704476137795166849228875
>
Scheme Expression | Internal Representation |
---|---|
numbers 1 , 2.3 |
java.lang.Number |
#t |
java.lang.Boolean.TRUE |
#f |
java.lang.Boolean.FALSE |
strings "hello, world" |
java.lang.String |
symbols a , + |
little_scheme.Sym |
() |
null |
pairs (1 . 2) , (x y z) |
little_scheme.Cell |
closures (lambda (x) (+ x 1)) |
little_scheme.Closure |
built-in procedures car , cdr |
little_scheme.Intrinsic |
continuations | little_scheme.Continuation |
The implementation is similar to those of little-scheme-in-dart and little-scheme-in-cs.
-
v [variable reference]
-
(e0 e1...) [procedure call]
-
(
quote
e)
'
e [transformed into (quote
e) when read] -
(
if
e1 e2 e3)
(if
e1 e2) -
(
begin
e...) -
(
lambda
(v...) e...) -
(
set!
v e) -
(
define
v e)
For simplicity, this Scheme treats (define
v e) as an expression type.
(car lst) |
(display x) |
(+ n1 n2) |
(cdr lst) |
(newline ) |
(- n1 n2) |
(cons x y) |
(read ) |
(* n1 n2) |
(eq? x y) |
(eof-object? x) |
(< n1 n2) |
(pair? x) |
(symbol? x) |
(= n1 n2) |
(null? x) |
(call/cc fun) |
(number? x) |
(not x) |
(apply fun arg) |
(globals ) |
(list x ...) |
(error reason arg) |
-
(error
reason arg)
throws an exception with the message "Error:
reason:
arg". It is based on SRFI-23. -
(globals)
returns a list of keys of the global environment. It is not in the standard.
See GLOBAL_ENV
in little_scheme.LS
for the implementation of the procedures
except call/cc
and apply
.
call/cc
and apply
are implemented particularly at
applyFunction
in little_scheme.Eval
.
I hope this serves as a model of how to write a Scheme interpreter in Java 8 and later.