almide-repl

Almide の対話的実行環境。almide(引数なし)で起動する。v0.19.0 で追加。

アーキテクチャ

WASM JIT ではなく、毎回 .almd ソースを動的生成 → コンパイル → cargo incremental build → 実行 という戦略をとる。Rust の incremental compilation が十分高速なため、REPL としての応答速度は実用的。

ユーザー入力
    ↓
入力分類 (TopLevel / Body / Expr)
    ↓
セッション状態に追記
    ↓
.almd ソース全体を再生成
    ↓
try_compile (quiet mode)
    ↓
cargo build (incremental)
    ↓
生成バイナリを実行 → stdout をキャプチャ → 表示

入力分類

ユーザーの入力を 3 種類に分類し、生成ソース内の配置場所を決める。

種別マッチパターン生成ソースでの配置
TopLevelfn , effect fn , type , mod type , import トップレベル宣言
Bodylet , var , for , 代入文(ident = expr)main() 関数のボディ
Expr上記以外すべてlet __r = <expr> として評価し結果を表示

セッション状態

Session 構造体が 2 つのベクタで状態を保持:

毎回の eval で、これらを結合して完全な .almd ソースを生成する。

ソース生成

eval のたびに以下のソースが動的生成される:

import io                    // io は auto-import ではないため明示必要

// --- top (蓄積された宣言) ---
fn double(x: Int) -> Int = x * 2
type Color = | Red | Blue

// --- main ---
effect fn main() -> Unit =   // 戻り型 -> Unit は省略不可
  // --- body (蓄積された文) ---
  let x = 10
  var y = 20
  // --- 今回の入力(Expr の場合) ---
  let __r = double(x)
  io.print("${__r}\n")       // Debug format ({:?}) に post-replace

式の表示

io.print("${__r}\n") で生成された Rust コードを、{:?}(Debug format)に post-replace する。これにより List や Option などの Display 未実装の型も統一的に表示できる。

String interpolation は format!("{}", val)(Display)を使うため、Vec<T> 等は直接は表示できない。{:?} への書き換えがこの制約を回避している。

RcCow の Debug 透過化

Almide はミュータブルコレクションに RcCow<T>(Copy-on-Write 参照カウント)を使う。デフォルトの #[derive(Debug)] だと RcCow([1, 2, 3]) と表示されてしまう。

手動 impl Debug で内部値に委譲することで、REPL では [1, 2, 3] と表示される。

コンパイル

コンパイラ内部の知見

コマンド

コマンド動作
:q, :quit終了
:h, :helpヘルプ表示
:history評価履歴の表示
:clearセッション状態のリセット

押さえどころ(カード化候補)

関連

Graph