# 画面設計書 11-フォールバックREPL

## 概要

本ドキュメントは、Julia処理系に組み込まれたフォールバックREPL（Read-Eval-Print Loop）画面の設計仕様を定義する。フォールバックREPLは、標準のREPLモジュール（`REPL.jl`）の読み込みに失敗した場合、またはダム端末（dumb terminal）環境で動作する際に使用される、最小限の対話的プロンプト環境である。

### 本画面の処理概要

フォールバックREPLは、Julia標準のREPL機能が利用できない状況でもユーザがJulia式を入力・評価できるよう設計された簡易対話環境である。行編集、タブ補完、履歴検索、構文ハイライトといった高度な機能は一切持たず、最小限のRead-Eval-Printループのみを提供する。

**業務上の目的・背景**：Juliaは通常、`REPL.jl`標準ライブラリを読み込んでリッチな対話環境を提供する。しかし、システムイメージの破損、LOAD_PATHの設定誤り、stdlibの欠損、またはダム端末からのアクセスといった異常・制約下では`REPL.jl`の読み込みに失敗する場合がある。フォールバックREPLは、そのような場合でもJuliaプロセスが最低限の対話機能を維持し、デバッグやリカバリ操作を行えるようにするためのセーフティネットである。また、環境変数`JULIA_FALLBACK_REPL=true`を設定することで強制的にフォールバックREPLを使用することも可能であり、開発・テスト用途にも利用される。

**画面へのアクセス方法**：以下のいずれかの条件でフォールバックREPLが起動する。
- `REPL.jl`モジュールの`require_stdlib`による読み込みが失敗した場合（自動フォールバック）
- 端末がダム端末（`TERM=dumb`）として認識された場合
- 環境変数`JULIA_FALLBACK_REPL`が`true`に設定されている場合（強制起動）
- `pkgimage.mk`によるパッケージイメージビルド時（`JULIA_FALLBACK_REPL=true`が設定される）

**主要な操作・処理内容**：
1. プロンプト（`julia> `）を表示し、ユーザからの入力を待機する
2. 入力された行を`parse_input_line()`で構文解析し、不完全な式の場合は追加行を読み込む
3. 完全な式が得られたら`eval_user_input()`で`Main`モジュールのコンテキストでevalを実行する
4. 評価結果を`display()`で表示し、`ans`変数に格納する
5. エラー発生時は`display_error()`でエラーメッセージとスタックトレースを表示する
6. EOFまたはCtrl+Dで終了する

**画面遷移**：
- 遷移元：起動バナー画面（REPL読込失敗時またはダム端末の場合）
- 遷移先：プロセス終了（EOF / Ctrl+D）

**権限による表示制御**：権限やロールによる表示制御は存在しない。フォールバックREPLはプロセスの実行ユーザ権限で動作し、すべての操作が同一権限で行われる。

## 関連機能

| 機能No | 機能名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 58 | eval | 主機能 | eval_user_input()によるJulia式の評価。行編集・補完なしの最小限eval-printループ |
| 36 | テキスト出力 | 主機能 | print("julia> ")による簡易プロンプト表示とflush(stdout)による即時出力 |
| 55 | 式オブジェクト（Expr） | 補助機能 | parse_input_line()による入力のAST構築。:toplevelノードの逐次評価 |
| 37 | ファイルI/O | 補助機能 | stdinからのread/readlineによる入力取得。File/IOStream判定による一括・逐次読み込み切り替え |
| 64 | エラー表示 | 補助機能 | display_errorによるエラーメッセージ表示。current_exceptions()でエラー情報を取得 |
| 62 | 例外機構 | 補助機能 | try/catchによるREPLループ内のエラーハンドリング。エラー発生時もREPLを継続 |
| 88 | パーサー | 補助機能 | parse_input_line()内でのJuliaSyntaxによる構文解析 |
| 38 | 標準入出力 | 補助機能 | stdin/stdout/stderrの直接使用による入出力処理 |

## 画面種別

対話型プロンプト（REPL: Read-Eval-Print Loop）

## URL/ルーティング

該当なし。フォールバックREPLはターミナルベースの対話環境であり、URL/ルーティングの概念は適用されない。起動は`base/client.jl`内の`run_main_repl()`関数から`run_fallback_repl(interactive)`が呼び出されることで開始される。

## 入出力項目

| 項目名 | 入力/出力 | データ型 | 説明 | 必須 |
|--------|----------|---------|------|------|
| Julia式（テキスト入力） | 入力 | String | ユーザがプロンプトに入力するJulia式。複数行にまたがる場合は式が完全になるまで追加行が読み込まれる | - |
| stdin（ファイル入力） | 入力 | File/IOStream/TTY | 標準入力。TTYの場合は対話モード、File/IOStreamの場合は一括読み込みモードで動作 | 必須 |
| プロンプト文字列 | 出力 | String | `"julia> "`固定文字列。対話モード時のみ表示 | - |
| 評価結果 | 出力 | Any | Julia式の評価結果。`display()`関数を介してstdoutに表示。結果は`Base.MainInclude.ans`に格納 | - |
| エラーメッセージ | 出力 | ExceptionStack | 評価エラー発生時のエラーメッセージとスタックトレース。stderrに出力 | - |

## 表示項目

| 表示項目 | 表示条件 | 表示形式 | 説明 |
|---------|---------|---------|------|
| プロンプト（`julia> `） | interactive==trueの場合のみ | プレーンテキスト | 入力待ちを示す固定文字列。`print("julia> ")`で出力後、`flush(stdout)`で即時表示 |
| 評価結果 | 評価結果がnothingでない場合 | `display(value)`による表示 | カラー対応時は`answer_color()`で色付け。`invokelatest(display, value)`で表示 |
| エラーメッセージ | 評価時にエラーが発生した場合 | `"ERROR: "` + エラー詳細 + スタックトレース | `printstyled`による赤色太字の"ERROR:"プレフィックス付き。stderrに出力 |
| REPL未使用警告 | REPL読み込み失敗かつquiet==falseの場合 | `@warn`マクロ出力 | `"REPL provider not available: using basic fallback"`メッセージとLOAD_PATH情報 |

## イベント仕様

### 1-プロンプト表示・入力待機

対話モード（`interactive==true`）の場合、`print("julia> ")`でプロンプト文字列を表示し、`flush(stdout)`でバッファをフラッシュした後、stdinからの入力を待機する。非対話モード（File/IOStream入力）の場合は、プロンプト表示を行わず`read(input, String)`で入力全体を一括読み込みする。

### 2-入力解析（パース）

入力された行を`parse_input_line(line; mod=Main)`で構文解析する。結果が`:incomplete`式の場合は追加の行を`readline(input, keep=true)`で読み込み、連結して再度パースを試みる。式が完全になるか、EOFに達するまでこのループを繰り返す。一括読み込みモードでは、`Meta.parseall`で全入力を一度にパースし、`:toplevel`ノードの場合は各文（stmt）を順次評価する。

### 3-式評価（Eval）

完全な式が得られると`eval_user_input(stderr, ex, true)`が呼び出される。内部では以下の処理が行われる：
1. `__repl_entry_client_lower(Main, ast)`で式をMainモジュールのコンテキストでlower（中間表現への変換）
2. `__repl_entry_client_eval(Main, ast)`で`Core.eval(Main, ast)`を実行
3. 結果を`Base.MainInclude.ans`に格納
4. 結果がnothingでなければ`invokelatest(display, value)`で表示

### 4-エラーハンドリング

評価中にエラーが発生した場合：
1. `current_exceptions()`でエラースタックを取得
2. `scrub_repl_backtrace()`でREPL関連のフレームを除去
3. `display_error(errio, lasterr)`でstderrにエラー表示
4. 非致命的エラーの場合は`Base.MainInclude.err`に格納し、REPLループを継続
5. `errcount > 2`の場合は致命的エラーとしてループを中断

### 5-割り込み処理（InterruptException）

Ctrl+Cによる`InterruptException`が発生した場合、`catch`ブロックで捕捉し、改行2つ（`"\n\n"`）を出力してプロンプトに復帰する。REPLループは中断されない。

### 6-終了処理

stdinからEOFを検出した場合（`eof(input)`がtrueを返した場合）、ループを終了する。対話モードではCtrl+Dの入力がEOFとして扱われる。

## データベース更新仕様

該当なし。フォールバックREPLはデータベースへのアクセスを行わない。

## メッセージ仕様

| メッセージID | 種別 | メッセージ内容 | 表示条件 | 出力先 |
|-------------|------|---------------|---------|--------|
| M-01 | 警告 | `"REPL provider not available: using basic fallback"` | REPL.jl読み込み失敗かつinteractive==trueかつquiet==false | stderr（@warnマクロ） |
| M-02 | エラー | `"ERROR: "` + エラー詳細 | Julia式の評価でエラー発生時 | stderr |
| M-03 | エラー | `"SYSTEM: display_error(errio, lasterr) caused an error"` | display_error自体がエラーを起こした場合（errcount > 0） | stderr（@errorマクロ） |
| M-04 | エラー | `"It is likely that something important is broken, and Julia will not be able to continue normally"` | errcount > 2の場合（連続エラー） | stderr（@errorマクロ） |
| M-05 | 情報 | `"Evaluation succeeded, but an error occurred while displaying the value"` | 評価は成功したがdisplayでエラー発生時 | stderr（@errorマクロ） |

## 例外処理

| 例外状況 | 処理内容 | 影響 |
|---------|---------|------|
| Julia式の構文エラー | `parse_input_line()`が`:error`式を返し、`eval_user_input()`内で評価時にエラー表示 | エラーメッセージ表示後、プロンプトに復帰 |
| Julia式の評価エラー | `try/catch`で捕捉、`scrub_repl_backtrace()`でバックトレース整理後`display_error()`で表示 | エラーメッセージ表示後、プロンプトに復帰。`err`変数にエラー情報を格納 |
| display関数のエラー | 評価結果の表示中にエラーが発生した場合、`@error`でログ出力後`rethrow()` | エラーが上位のcatchブロックで捕捉され、再表示を試みる |
| display_error自体のエラー | `errcount`をインクリメントし、再度エラー表示を試みる | errcount > 2で致命的エラーとしてREPLループを中断 |
| InterruptException（Ctrl+C） | 改行2つを出力してプロンプトに復帰 | REPLループは継続 |
| EOF（Ctrl+D） | `eof(input)`チェックでループ終了 | プロセス終了に向かう |
| stdin読み込みエラー | 一括読み込みモードでのIOエラーは通常のエラーハンドリングに委譲 | エラーメッセージ表示 |

## 備考

- フォールバックREPLは`base/client.jl`内に実装されており、Juliaのブートストラップイメージ（sysimage）に含まれるため、外部ライブラリへの依存なく常に利用可能である
- プロンプト文字列は`"julia> "`で固定されており、標準REPLのようなモジュール名表示やカスタマイズは不可能である
- 複数行入力のサポートは`:incomplete`式の検出による自動継続行で実現されているが、行編集（カーソル移動、削除等）の機能はない
- `JULIA_FALLBACK_REPL`環境変数による強制起動は、パッケージイメージビルド（`pkgimage.mk`）やプリコンパイル処理（`generate_precompile.jl`）でも使用される
- File/IOStream入力の場合は`read(input, String)`で全体を一括読み込みし、`:toplevel`ノードの各文を順次評価する非対話モードで動作する
- `ans`変数（最後の評価結果）と`err`変数（最後のエラー）は`Base.MainInclude`モジュールを通じて`Main`にエクスポートされる

---

## コードリーディングガイド

本画面を理解するために参照すべきファイルと、推奨する読み解き順序を以下に示す。

### 推奨読解順序

#### Step 1: データ構造を理解する

フォールバックREPLで扱われる主要なデータ構造は、Julia式（Expr）とエラースタック（ExceptionStack）である。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | meta.jl | `base/meta.jl` | `parseall`関数（414行目）の戻り値であるExpr型を理解する。`:toplevel`ヘッドを持つ式ノードと`:incomplete`、`:error`ヘッドの意味を把握する |
| 1-2 | errorshow.jl | `base/errorshow.jl` | `show_exception_stack`関数（1104行目）で使用される`ExceptionStack`型の構造を理解する。各要素は`(exception, backtrace)`のNamedTupleである |
| 1-3 | client.jl | `base/client.jl` | `MainInclude`ベアモジュール（537-566行目）で定義される`ans`変数と`err`変数の役割を理解する |

**読解のコツ**: Juliaの式オブジェクト（Expr）は`.head`と`.args`フィールドを持つ木構造であり、`Meta.isexpr(ex, :toplevel)`のようなパターンマッチでヘッドを判定する。`:incomplete`は入力が不完全であることを示す特別なヘッドである。

#### Step 2: エントリーポイントを理解する

処理の起点となる`_start()`から`run_fallback_repl()`に至る呼び出しチェーンを追う。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | client.jl | `base/client.jl` | `_start()`関数（575行目）がJuliaプロセスの最初のエントリーポイント。`exec_options()`の戻り値（repl_was_requested）に基づき`repl_main()`を呼び出す |
| 2-2 | client.jl | `base/client.jl` | `repl_main()`関数（615行目）でバナー表示設定やquiet/history_fileオプションを解析し、`run_main_repl()`を呼び出す |
| 2-3 | client.jl | `base/client.jl` | `run_main_repl()`関数（515行目）で`JULIA_FALLBACK_REPL`環境変数の確認とREPLモジュールの読み込みを試み、失敗時に`run_fallback_repl(interactive)`を呼び出す |

**主要処理フロー**:
1. **575行目**: `_start()` - Julia起動のメインエントリーポイント
2. **585行目**: `exec_options(JLOptions())` - コマンドラインオプション処理。戻り値`repl_was_requested`でREPL起動判定
3. **596行目**: `repl_main(ARGS)` - REPLメイン処理への分岐
4. **615-627行目**: `repl_main()` - バナー/quiet/history_fileオプション解析後、`run_main_repl()`呼び出し
5. **516行目**: `JULIA_FALLBACK_REPL`環境変数チェック
6. **519-522行目**: `load_InteractiveUtils()`と`load_REPL()`によるREPLモジュール読み込み試行
7. **525-531行目**: REPL読み込み成功なら`run_std_repl()`、失敗なら`run_fallback_repl()`を呼び出し

#### Step 3: フォールバックREPLのメインループを理解する

`run_fallback_repl()`関数の内部処理を詳細に把握する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | client.jl | `base/client.jl` | `run_fallback_repl()`関数（442-482行目）。stdinの型判定（File/IOStream vs TTY）による処理分岐、対話ループの実装を読む |

**主要処理フロー**:
- **443行目**: `let input = stdin` - stdinをローカル変数にバインド
- **444行目**: `if isa(input, File) || isa(input, IOStream)` - ファイル入力の場合は一括読み込みモード
- **446行目**: `parse_input_line(read(input, String); mod=Main)` - 全入力を一括パース
- **447-456行目**: `:toplevel`式の場合は各文を順次`eval_user_input()`、それ以外は単一式として評価
- **458行目**: `while true` - 対話モードのメインループ開始
- **459-462行目**: プロンプト表示（`print("julia> ")`と`flush(stdout)`）
- **463行目**: `eof(input) && break` - EOF検出でループ終了
- **465-473行目**: 行読み込みと不完全式の継続読み込みループ
- **474行目**: `eval_user_input(stderr, ex, true)` - 式評価
- **475-476行目**: InterruptException処理

#### Step 4: 式評価とエラーハンドリングを理解する

`eval_user_input()`関数の内部処理を把握する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | client.jl | `base/client.jl` | `eval_user_input()`関数（127-174行目）。エラーカウントによる段階的エラーハンドリング、`invokelatest`の使用理由を理解する |
| 4-2 | client.jl | `base/client.jl` | `display_error()`関数（108-121行目）。エラーメッセージの書式化とスタックトレース表示を理解する |
| 4-3 | client.jl | `base/client.jl` | `scrub_repl_backtrace()`関数（92-102行目）。`__repl_entry`プレフィックスによるフレームフィルタリングの仕組みを理解する |

**主要処理フロー**:
- **131行目**: `while true` - エラーリトライループ（通常1回で抜ける）
- **136-141行目**: 前回エラーがある場合のエラー表示処理
- **143行目**: `__repl_entry_client_lower(Main, ast)` - 式のlowering
- **144行目**: `__repl_entry_client_eval(Main, ast)` - Core.evalによる式評価
- **145行目**: `setglobal!(Base.MainInclude, :ans, value)` - 結果をans変数に格納
- **146-156行目**: 結果表示（nothing以外の場合）
- **159-170行目**: catchブロック - errcount管理と致命的エラー判定

#### Step 5: 入力パース処理を理解する

`parse_input_line()`と関連するパーサー機能を把握する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 5-1 | client.jl | `base/client.jl` | `parse_input_line()`関数（192-203行目）と`_parse_input_line_core()`関数（176-190行目）。depwarn制御とNullLoggerの使用を理解する |
| 5-2 | client.jl | `base/client.jl` | `incomplete_tag()`関数（217-232行目）と`fl_incomplete_tag()`関数（208-215行目）。不完全式の種類判定ロジックを理解する |
| 5-3 | meta.jl | `base/meta.jl` | `parseall()`関数（414-417行目）。JuliaSyntaxベースのパーサー呼び出しを理解する |

**主要処理フロー**:
- **192行目**: `parse_input_line()` - エントリーポイント。depwarn制御付き
- **177行目**: `Meta.parseall(s; filename, _parse=...)` - 実際のパース処理
- **178-189行目**: `:toplevel`式のエラーチェック。末尾が`:error`/`:incomplete`の場合はエラー式のみ返却

### プログラム呼び出し階層図

```
_start()                                    [base/client.jl:575]
    |
    +-- exec_options(JLOptions())            [base/client.jl:234]
    |       |
    |       +-- load_julia_startup()         [base/client.jl:381]
    |
    +-- repl_main(ARGS)                      [base/client.jl:615]
            |
            +-- run_main_repl()              [base/client.jl:515]
                    |
                    +-- load_InteractiveUtils()  [base/client.jl:413]
                    +-- load_REPL()              [base/client.jl:429]
                    |
                    +-- run_fallback_repl(interactive)  [base/client.jl:442]
                            |
                            +-- parse_input_line()     [base/client.jl:192]
                            |       |
                            |       +-- _parse_input_line_core()  [base/client.jl:176]
                            |               |
                            |               +-- Meta.parseall()   [base/meta.jl:414]
                            |
                            +-- eval_user_input()      [base/client.jl:127]
                                    |
                                    +-- __repl_entry_client_lower()  [base/client.jl:124]
                                    +-- __repl_entry_client_eval()   [base/client.jl:125]
                                    +-- display()                    [Base]
                                    +-- scrub_repl_backtrace()       [base/client.jl:92]
                                    +-- display_error()              [base/client.jl:108]
                                            |
                                            +-- show_exception_stack()  [base/errorshow.jl:1104]
```

### データフロー図

```
[入力]                     [処理]                           [出力]

stdin (TTY)          +---> parse_input_line()               stdout
  |                  |         |                              ^
  | readline()       |         | Expr / :incomplete           | display(value)
  v                  |         v                              |
line (String) -------+    eval_user_input()                   |
  |                           |                               |
  | (不完全時)                 +-- Core.eval(Main, ast)        |
  | 追加行読込                 |       |                       |
  +---(ループ)                 |       v                       |
                              |   value (Any) -----> ans -----+
                              |
                              +-- (エラー時)
                                      |
                                      v                    stderr
                              scrub_repl_backtrace()         ^
                                      |                      |
                                      v                      |
                              display_error() ---------------+
                                      |
                                      v
                                  err (ExceptionStack)
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| client.jl | `base/client.jl` | ソース | フォールバックREPLのメイン実装。`run_fallback_repl()`、`eval_user_input()`、`parse_input_line()`、`display_error()`等の全主要関数を含む |
| meta.jl | `base/meta.jl` | ソース | `Meta.parseall()`関数によるJulia式の構文解析。`parse_input_line()`から呼び出される |
| errorshow.jl | `base/errorshow.jl` | ソース | `show_exception_stack()`関数によるエラースタックの表示。`display_error()`から呼び出される |
| options.jl | `base/options.jl` | ソース | `JLOptions`構造体と`colored_text()`関数。カラー出力の有無判定に使用 |
| environment-variables.md | `doc/src/manual/environment-variables.md` | ドキュメント | `JULIA_FALLBACK_REPL`環境変数の公式ドキュメント |
| pkgimage.mk | `pkgimage.mk` | 設定 | パッケージイメージビルド時に`JULIA_FALLBACK_REPL=true`を設定 |
| generate_precompile.jl | `contrib/generate_precompile.jl` | ソース | プリコンパイル処理で`JULIA_FALLBACK_REPL=true`を使用 |
