非常に小さな Lisp インタプリタ。Common Lisp か Scheme が有力。
- とりあえず Common Lisp のサブセットを実装。
- S式の構築部分だけ, 独立して使える。
C++17
variant
で数値は特別扱い- オブジェクト参照は
shared_ptr
で参照カウント方式 - リストは
vector
- 文字列は全部 Unicode (UTF-16).
行数:
Language | files | blank | comment | code |
---|---|---|---|---|
C++ | 17 | 363 | 275 | 1215 |
C/C++ Header | 6 | 225 | 234 | 507 |
Markdown | 1 | 33 | 0 | 91 |
make | 2 | 30 | 12 | 66 |
YAML | 2 | 5 | 1 | 32 |
Lisp | 2 | 5 | 4 | 12 |
SUM: | 30 | 661 | 526 | 1923 |
-
REPL Read-Eval-Print-Loop
- ✅ GNU Readline はライセンスが GPLv3 なので使えない。libedit-devel を利用
- ✅
repl()
,main()
-
Reader, Print -- ファイルからの読み込み
READ()
関数, S式の構築、画面への表示PRINT()
関数. 文法をユーザが拡張できるので, bison/flex は使えない。手書き。- ✅ Standard Macro Characters
- ✅ dotted pair notation
- reader macro
- Sharpsign (dispatching macro character)
<simple-vector>
- ✅ 単一行コメント
;
- 複数行コメント
#|
...|#
-
Environment
- ✅ 変数定義.
SETQ
- ✅ レキシカルスコープ.
LET
,LET*
.BLOCK
ではスコープ導入しない。 - ✅ ビルトイン関数の登録
- ✅ 変数定義.
-
Eval --
EVAL1()
が AST を評価.- ✅ 関数呼び出し.
- ✅ atom の評価
- ✅
lambda
式からクロージャをつくる - Function
FUNCALL
. 変数を評価して, クロージャの呼び出し. Lisp-2 - ✅ ユーザ関数の定義
DEFUN
- ✅ Special operator
IF
- macro
DO
-
✅ Tail Call Optimization (TCO). トランポリン trampoline で相互再帰もOK.
-
Files
-
✅ Quoting
QUOTE
-
Macros
- ✅ Backquote (
quasiquote
), Comma (unquote
),,@
(unquote-splicing
) - ✅ Function
MACROEXPAND-1
. - マクロの入れ子
- ✅ マクロの評価
- ✅ Backquote (
-
Try (Conditions)
tagbody
& 無条件ジャンプgo
-- 実装しない- ✅
block
&return-from
-- lexical non-local exit facility.StopIteration
例外を投げる catch
&throw
-- ほかのプログラミング言語の例外処理とは異なる。実装しないhandler-bind
orhandler-case
-- これが例外処理
-
構造体
-
若干のライブラリ
- ビルトイン関数
<string>
は<character>
の vector にしない.
- type
hash-table
.(make-hash-table)
- ビルトイン関数
Common Lisp は, クラス名に -
を含まなければ P
を, そうでなければ -P
を末尾に付ける。そうすると, null
と atom
には P
を付けないといかんのでは?
CL | Scheme | type | |
---|---|---|---|
boolean? | Scheme のみ | ||
null |
null? | null | == (eq x '()) |
SYMBOLP | symbol? | symbol | nil は真. |
atom |
atom | NIL は真. == (not (typep x 'cons)) | |
consp |
pair? | cons | nil は偽. == (not (typep x 'atom)) |
listp |
list? | list | '() は真. == (typep x '(or cons null)) |
NUMBERP | number? | number | |
integerp |
integer? | integer | |
rationalp |
rational | ||
floatp |
float | ||
complexp |
complex | ||
CHARACTERP | char? | character | |
STRINGP | string? | string | |
bit-vector-p | bit-vector | bit-vector means (vector bit) . |
|
VECTORP | vector? | vector | |
SIMPLE-VECTOR-P | simple-vector | ||
simple-string-p | simple-string | ||
simple-bit-vector-p | simple-bit-vector | ||
arrayp | array | ||
packagep | PACKAGE | 名前空間 | |
FUNCTIONP | procedure? | FUNCTION | マクロもクロージャも真 |
compiled-function-p | compiled-function | ||
STREAMP | port?, eof-object? | STREAM | Scheme: を介して入出力. EOF のときは EOFオブジェクトを返す. |
random-state-p | RANDOM-STATE | ||
readtablep | READTABLE | ||
hash-table-p | HASH-TABLE | ||
pathnamep | PATHNAME | ||
bytevector? |
The Make-A-Lisp Process ただ, MAL は Clojure に近く、Lisp らしい感じとは若干異なる。
そのほか興味深い:
Lisp を C言語にコンパイル。後は gcc でバイナリを作れる。
そのままではビルドに失敗する。__malloc_hook
undeclared. 組み込みの tinycc を dev
ブランチに切り替えてやれば動く。
出力されるCのソースは, それぞれの関数末尾で継続を返すスタイルになっている。
1,000行に満たないのに GC 付き。すごい。