mie REPL 仕様
本書は mie を引数なし(または --strict のみ)で起動したときの REPL の仕様を定める。起動ディスパッチ全体は mie-command.md、言語の意味論は language-spec.md、組込関数群は prelude.md を参照。
引数なしで起動。標準入力から 1 行ずつ式を読み、評価結果を表示する。
$ mie mie>
動作モード
stdin / stdout の両方が端末 (TTY) に接続されている場合は interactive モード (行編集 + ヒストリ + 複数行継続 + ライブ syntax highlight)、それ以外 (パイプ・リダイレクト・テスト) は batch モード (bufio.Scanner ベース) で動く。出力内容はどちらも同等。interactive モードの着色は入力中のソースをトークン単位で色付けし、行がパース可能なときは識別子の意味分類 (slot/local/inner/builtin/type, LSP と同一の highlight パッケージ由来) も反映する。環境変数 NO_COLOR が設定されている場合は着色しない。
プロンプト
| 状況 | プロンプト |
|---|---|
| 通常入力 | mie> |
| 文・式が途中 (継続) | ...> |
「途中」の判定は括弧/ブレース/角括弧のネスト深さで決定する。
interactive モードでは、構文的に閉じている行でも Shift+Enter / Alt+Enter で確定せず
任意位置に改行を挿入できる (continue プロンプト ...> に移る)。Shift+Enter は端末が
kitty keyboard protocol に対応している場合に有効で、Alt+Enter は対応有無に関わらず効く。
パーサモード
REPL では parser.SkipHeader() を有効化し、ファイル先頭の #{mie} / #[mie] ヘッダを要求しない。入力は平坦な文の列として解釈される。先頭にヘッダがあっても構文エラーにはせず、その構造効果 (language-spec.md §13.1 の slot-list / body 選択) を無視して読み飛ばし、以降を平坦に読む (ヘッダ有無で挙動は変わらない)。
SkipHeader は REPL のほか、文字列補間サブパース (language-spec.md §7.2.1) と、埋め込み self-host ソース (prelude / 標準ライブラリの .mie) のブートストラップ読み込みでも共用される。self-host ソースは #[mie] (ライブラリ mode) を宣言してツール (fmt / lint / LSP) にはモジュールとして見せつつ、ブートストラップ時はこの読み飛ばしにより平坦な文列として最外側 env に束縛される。
仮想ファイル名は <repl> で、エラーメッセージの Position 表記にもこの名前が現れる。
評価ループ
- 1 行入力を読む。空行は読み飛ばす。
- 継続が必要な場合は
...>を出してさらに読み、入力に結合する。 - パース。失敗時はエラーを表示してループ継続。
- 評価。
*object.Errorを返したらそれを表示して継続。 - 結果が
()(unit) でも束縛文 (x := ...) でもなければresult.Inspect()を出力。
env は REPL セッション全体で共有される (前の行で x := 10 した後、次の行で x を参照できる)。
終了
Ctrl+D (EOF) または Ctrl+C で終了する。interactive モードでは raw mode 解除を defer で保証する。
ブロッキング I/O (input) と Future
input 等のブロッキング I/O は呼び出し時点で Future を返す (prelude.md §1 / §9.4)。REPL での扱い:
!で待った場合 (例:input("name? ")!、x := input("name? ")!) は読み取り完了まで待ち、解決値 (Result(String)) を返す / 束縛する。!を当てずに評価した場合は結果のFutureをresult.Inspect()(未解決なら<future pending>) として表示する。値は束縛されない。最後まで必要な値はf!で明示的に待つこと (language-spec.md §13.3)。
interactive モードでは対話端末の行読み取りを直列化し、input の読み取りと次プロンプトの読み取りが同時に走らないようにする。これにより ! を付け忘れても REPL は固まらない。! を当てなかった input はその行の評価後に読み取りを完了させ (プロンプトを出して 1 行受け取り)、結果を破棄してから次プロンプトを出す。
strict 型検査 (--strict)
パスを伴わず --strict のみを与えて起動した場合 (mie --strict)、REPL は strict モード で動く。各入力行はパース成功後・評価前に strict 型検査 (static-analysis.md §3) を受け、型エラーが 1 件でもあればその診断を表示して その行を評価せず 次プロンプトに進む。型検査がクリーンな行は通常どおり評価する。
検査は「評価ループ」の 3 (パース) と 4 (評価) の間に挟まる。診断の文言・位置表記は mie-command.md §5.5 / §6 と同じ (<repl>:<line>:<col>: <msg>、interactive モードではエラー色で着色)。
検査は 1 行単位で行うため、前の行で束縛した名前の宣言結果型は当該行の検査からは参照できない。strict 規則のうち「名前付き関数のパラメータ型必須化」のような行内で完結する検査は効くが、行をまたぐ越境照合は対象外になる (健全側=誤検出は出さない)。
strict を有効にできるのは起動時のフラグのみで、セッション途中での切り替えはできない。REPL 入力は header を要求しない平坦な文列 (「パーサモード」) のため、header #{mie strict} (language-spec.md §13.1) による per-file strict は REPL には適用されない。mie --strict <path> (mie-command.md §5.5) のようにパスを伴う場合はファイル実行 (REPL ではない)。
実装構成 (self-host)
REPL のポリシー層 — 1 入力の「パース → (strict 検査) → 評価 → 表示判定」と、batch モードのループ本体 — は mie 自身で記述し (repl_core.mie、go:embed で処理系に同梱)、std/mie/repl.md の std:mie/repl の上で動く。コアは 2 層から成る:
handle_line— 1 入力をSessionで評価し、本書「評価ループ」3–5 の規則 (パースエラー表示・strict 診断・unit / 束縛文の非表示) を適用する。3 フロントエンドが共有する。run— プロンプト出力・継続入力 (needs_more) の結合・行読みを含む batch 用フルループ。
フロントエンドごとの分担:
| フロントエンド | ループ・行取得 | ポリシー層 |
|---|---|---|
| batch (パイプ・リダイレクト・テスト) | mie (run) | mie |
| interactive (端末) | Go — 行編集・履歴・複数行継続・ライブ着色 (reeflective/readline) | mie (handle_line) |
| web (ブラウザ REPL) | JS — 入力 UI・履歴 (repl.js) | mie (handle_line、wasm 経由) |
行編集と色付け (highlight) はフロントエンド責務であり、mie コアは装飾前の素のテキストだけを扱う。どのフロントエンドでも出力内容は同等 (「動作モード」)。