typelisp 0.2.0

A statically typed Lisp with an interpreter and a compiler to native executables (LLVM)
docs.rs failed to build typelisp-0.2.0
Please check the build logs for more information.
See Builds for ideas on how to fix a failed build, or Metadata for how to configure docs.rs builds.
If you believe this is docs.rs' fault, open an issue.

TypeLisp

English | 日本語 | 简体中文 | 繁體中文 | 한국어 | Español | Português (Brasil) | Deutsch | Français | Русский | العربية | Italiano | हिन्दी | Türkçe | Tiếng Việt | Bahasa Indonesia | Polski | ภาษาไทย | Українська | Nederlands | Svenska

TypeLisp は静的型付きの Lisp です。 文法などは主にCommon Lispを参考にしています。

特徴

関数定義

関数を定義するときには、引数の型と戻り値の型を指定します。 具体的には、以下のようになります。

(defun fun-name ((arg1 type1) (arg2 type2) ...) return-type
    body ...)

メソッド

(defstruct Point (x i32) (y i32))

(defmethod show ((p Point)) ()
  (println "Point: (x ~d y ~d)" p::x p::y))

(show (Point::new 1 2))

例

factorial

(defun factorial ((n int)) int
  (if (<= n 1)
    1
    (* n (factorial (- n 1))) ))

(let ((num (factorial 10)))
  (println "10! = ~d" num) )

wc

(defun is-whitespace ((b int)) bool
  (case b
    ((#x20 #x09 #x0a #x0b #x0c #x0d) true)
    (else false)))

(defun main () ()
  (let ((args (command-line-args)))
    (when (< (len args) 2)
      (println "usage: wc file")
      (exit 0))

    (let ((path (get args 1))
          (char-count 0)
          (word-count 0)
          (line-count 0)
          (in-word false))
      (match (open-binary-input path)
        ((ok file)
         (progn
           (loop (match (read-byte file)
                   ((some b)
                    (progn
                      (incf char-count)
                      (when (= b #x0a)
                        (incf line-count))
                      (if in-word
                        (when (is-whitespace b)
                          (setf in-word false))
                        (unless (is-whitespace b)
                          (setf in-word true)
                          (incf word-count)))))
                   ((none) (break))))
           (close file)
           (println "~10d ~10d ~10d ~a" line-count word-count char-count path)))
        ((err e)
         (progn
           (println "wc: ~a" (message e))
           (exit 1)))))))

(main)

Trait

(deftrait Animal ()
  (name ((self Self)) string)
  (sound ((self Self)) string)
  (speak ((self Self)) string
    (format false "~a says ~a" (name self) (sound self))))

(defstruct Dog (nick string))
(defstruct Cat (nick string))

(impl Animal Dog
  (name ((self Self)) string self::nick)
  (sound ((self Self)) string "Woof"))

(impl Animal Cat
  (name ((self Self)) string self::nick)
  (sound ((self Self)) string "Meow"))

(defun main () ()
  (let ((animals (the Vector<:dyn Animal> (Vector::new))))
    (push animals (Dog::new "Pochi"))
    (push animals (Cat::new "Tama"))
    (doiter (a (iter animals))
      (println "~a" (speak a)))))

(main)

そのほかの例

examples/ にあるプログラムは、ファイル名を指定して実行できます。上の wc と Trait の例も examples/wc.typl と examples/animals.typl にあります。

typl examples/fizzbuzz.typl
typl examples/wc.typl README_JP.md
ファイル 内容
bst.typl 二分探索木(defenum と match)
factorial.typl 階乗(63 ビットを超えると自動で多倍長になる)
fibonacci.typl フィボナッチ数列(ループ)
fizzbuzz.typl FizzBuzz
game_of_life.typl ライフゲーム
maze_bfs.typl 迷路の最短経路(幅優先探索)
primes.typl エラトステネスの篩

examples/projects/ には、複数のファイルに分かれたプログラムがあります。 src/main.typl を指定して実行します(例: typl examples/projects/todo-cli/src/main.typl)。

プロジェクト 内容
echo-server 接続ごとにタスクを起動するエコーサーバ
expr-eval 四則演算の対話計算機(字句解析、構文解析、評価)
http HTTP/1.1 のサーバとクライアント(TLS 対応)
mini-lisp 小さな Lisp の REPL
shape-canvas 文字のキャンバスに図形を描く(:dyn とエラー型)
todo-cli ToDo を管理するコマンドラインツール

インストール

macOS(Intel / Apple Silicon)では、ビルド済みの typl と typl-lsp を次のコマンドで インストールできます。

curl -fsSL https://raw.githubusercontent.com/JunSuzukiJapan/typelisp/main/install.sh | sh

~/.typelisp/bin に入るので、表示に従って PATH に追加してください。typl -c で実行ファイルを 作るには Xcode Command Line Tools(xcode-select --install)が必要です。ビルド済みの typl は Apple Silicon では macOS 26 以降、Intel では macOS 15 以降で動きます。Apple Silicon で macOS 26 より 前の macOS では、起動時に警告が 1 行出ます。そのまま使えますが、typl が実行中にコンパイルした コードの中で panic・throw・unwind-protect を使うと、異常終了することがあります。

インストール先は環境変数 TYPELISP_HOME で、バージョンは TYPELISP_VERSION で指定できます (指定しなければ最新のリリース)。

curl -fsSL https://raw.githubusercontent.com/JunSuzukiJapan/typelisp/main/install.sh | TYPELISP_VERSION=0.2.0 sh

アンインストールするときは、typl が書き出したライブラリを削除してから、インストール先を 削除します。

typl --remove-lib --all
rm -rf ~/.typelisp

ソースからビルドする場合は、次の「ビルド」を参照してください。

ビルド

必要なもの

  • Rust(cargo)
  • LLVM 22
  • macOS では Xcode Command Line Tools、Linux では C コンパイラ(どちらもリンクに使います)

macOS では、LLVM 22 は Homebrew で入れられます。

brew install llvm@22

Linux では、ディストリビューションのパッケージで LLVM 22 の開発用ファイルを入れます。 Ubuntu 24.04、Debian 13、Fedora 44 でビルドとテストを確かめています。

  • Ubuntu / Debian:apt.llvm.org のリポジトリを追加して llvm-22-dev と libpolly-22-dev を入れます。ほかに build-essential、pkg-config、zlib1g-dev、 libzstd-dev、libxml2-dev が要ります。
  • Fedora:llvm-devel、llvm-static、gcc、gcc-c++、zlib-devel、libzstd-devel、 libxml2-devel、libffi-devel を入れます。

初回の設定

クローンした後に一度だけ、次のスクリプトを実行します。

scripts/setup-cargo-env.sh

このスクリプトは LLVM 22 の場所を調べ(macOS では brew --prefix llvm@22、Linux では llvm-config-22 か、LLVM 22 の llvm-config)、.cargo/config.toml を生成します。 このファイルはマシンごとに内容が違うので、Git の管理対象外です。macOS では、ビルドに使う最低 OS バージョン(MACOSX_DEPLOYMENT_TARGET)も書き込みます。Rust のツールチェーンを更新したときは、 もう一度実行してください。

スクリプトが最低 OS バージョンを読み取れなかった場合は、その旨を表示して止まります。そのときは 値を自分で指定します。

scripts/setup-cargo-env.sh --deployment-target 15.0

設定ファイルを生成したくない場合は、cargo のコマンドを scripts/with-llvm-env.sh 経由で実行します。 こちらは実行のたびに同じ値を環境変数に設定します。

scripts/with-llvm-env.sh cargo build

Homebrew を使わない場合は、LLVM_SYS_221_PREFIX に LLVM 22 のインストール先を設定してください。 macOS の最低 OS バージョン(MACOSX_DEPLOYMENT_TARGET)は、設定しなくてもビルドできます。設定 しなければ、Rust の標準ライブラリが対象とするバージョンを使います。

ビルドする

cargo build            # デバッグビルド(target/debug/)
cargo build --release  # リリースビルド(target/release/)

次の2つの実行ファイルができます。

実行ファイル 役割
typl 処理系本体(使い方は次の「実行方法」)
typl-lsp 言語サーバ(エディタ連携用)

cargo install でインストールする

typl と typl-lsp を ~/.cargo/bin に入れるには、クローンしたリポジトリで次を実行します。

cargo install --locked --path .

cargo install --path は、「初回の設定」で生成した .cargo/config.toml を読みます。設定ファイルを 生成していない場合は、scripts/with-llvm-env.sh cargo install --locked --path . を実行します。 Homebrew を使わない場合は、LLVM_SYS_221_PREFIX を設定してから cargo install --locked --path . を 実行します。

インストールした typl は、コンパイルに使う静的ライブラリを中に持っているので、インストール後に リポジトリを移動・削除しても -c や compile-file が使えます(次の「ファイルをコンパイルする」を 参照)。

実行方法

typl の起動のしかたは次の3通りです。以下の例では、typl にパスが通っているものとします (install.sh や cargo install で入れて PATH を通した場合、またはビルドした target/debug/・target/release/ にパスを通した場合)。

インタラクティブモード(REPL)

引数を付けずに起動すると、インタラクティブモード(REPL)になります。式を1つ入力するたびに、 その場で評価して結果を表示します。:quit または :exit で終了します。

typl

ファイルを実行する

ファイル名だけを指定すると、そのファイルを実行します。ファイル名より後ろに書いた引数は、 プログラムに渡されます((command-line-args) で受け取れます)。

typl foo.typl
typl foo.typl a b c

ファイルをコンパイルする

-c または --compile を指定すると、そのファイルをコンパイルして実行ファイルを作ります。 -o を省くと、ファイル名から .typl を除いた名前の実行ファイル(この例では foo)ができます。

typl -c foo.typl
typl --compile foo.typl -o bar

コンパイルして作る実行ファイルには、静的ライブラリ libtypelisp_front.a をリンクします。 リリースビルドの typl(cargo install で入れたものを含む)は、このライブラリを中に持って いて、初めてコンパイルするときに ~/.typelisp/lib/<ビルドID>/ に書き出します。2回目からは 書き出したものを使います。書き出す場所は環境変数 TYPELISP_HOME で変えられます(TYPELISP_HOME を設定すると $TYPELISP_HOME/lib/<ビルドID>/ になります)。ビルドIDはライブラリの中身から 決まるので、別の版の typl を入れると、次のコンパイルで新しいディレクトリに書き出されます。

書き出したライブラリは、次のコマンドで削除できます。

typl --remove-lib           # この typl が書き出したものを削除する
typl --remove-lib --others  # 別の版の typl が書き出したものを削除する
typl --remove-lib --all     # すべての版のものを削除する

typl をアンインストールする前には typl --remove-lib を、入れ直した後には typl --remove-lib --others を実行すると、使われないライブラリが残りません。削除したものは、 typl が次にコンパイルするときに書き出し直します。削除するのは lib/ の下のビルドIDの ディレクトリだけで、それ以外のファイルには触れません。

デバッグビルドの typl は、ビルドしたリポジトリの target/debug/ にあるものを使い、何も 書き出しません。

別の場所に置いたライブラリを使うには、--lib-dir でそのフォルダを指定します。

cp target/debug/libtypelisp_front.a ~/lib/typelisp/
typl --lib-dir ~/lib/typelisp -c foo.typl

libtypelisp_front.a は、そのファイルと同時にビルドした typl でしか使えません。typl を ビルドし直したら、コピーも取り直してください。

その他のオプション

typl --help        # オプションの一覧を表示する
typl --version     # バージョンを表示する
typl --remove-lib  # 書き出したライブラリを削除する(--others / --all も使える)

文書

日本語の文書の一覧は docs/ja/README.md にあります。

チュートリアル

ガイド

リファレンス

エディタ連携

ライセンス

typelisp は、次の2つのライセンスのどちらかを選んで利用できます。

どちらを選んだ場合も、LICENSE-EXCEPTION の例外が加わります。typl -c や compile-file で作った実行ファイルには typelisp の一部が含まれますが、その部分については typelisp の著作権表示やライセンス文を添えずに配布できます。

typelisp への貢献は、特に断りのない限り、上と同じ条件(2つのライセンスのどちらか、および例外)で 提供されたものとして扱います。