cli の設計

設計目標

適合性の実行は、多数の native プロセスを並列に起動する Python ツールによって駆動されます。--backend スイッチを持つ単一の実行ファイルにすることで、ビルドは単純(MoonBit パッケージ 1 つ、リンク 1 回)に保たれ、各バックエンドは独自のオプション構文を維持できます。ディスパッチャの役割は、ランナーを選び、その戻り値をプロセスの終了ステータスに変換することだけです。

数学的背景

ランナーのもの以外にはありません。唯一の契約は機能的なものです。終了ステータスはランナーの戻り値であり、ランナーの出力はその引数と読み込むファイルにのみ依存します(internal/runner_cli の設計を参照)。

設計上の判断

3 つの層

コーパスの解析と実行は純粋な frontend/* パッケージに、引数処理、ファイルアクセス、出力は cli/*_expr_cli ランナー(それぞれ run(arguments) -> Int を持つライブラリ)にあります。プロセス境界(@env.args()、@sys.exit)は cli にのみ存在します。ランナーがライブラリであるため、その使用経路はプロセスを起動せずに単体テストでき、フロントエンドはすべてのターゲットで利用可能なままです。

プログラム名を転送する

ディスパッチャは --backend とその値を取り除き、[program, rest…] を転送します。どのランナーも要素 0 をスキップするため、ランナーはディスパッチャから呼ばれても、テストから呼ばれても、(原理的には)単独の実行ファイルとして呼ばれても同じように動作します。

1 つのバイナリをバックエンドごとにコピー

tools/conformance_cli.py は src/cli をバックエンド固有のターゲットディレクトリにビルドし、<backend>-conformance.exe にコピーします。したがって異なるバックエンドの並列ビルドが _build ディレクトリやロックを共有することはなく、ツールは常に、何を実行するかが名前からわかる実行ファイルを呼び出します。

ディスパッチャのヘルプが優先

--help はバックエンドが決まる前、引数の走査中に処理されるため、常にディスパッチャの使い方を表示して 0 で終了します。これにより --help はどんな組み合わせでも安全に呼び出せます。ランナーのオプションはそれぞれのページで説明されています。

正しさ/不変条件

  • 1 回の呼び出しで呼ばれるランナーはちょうど 1 つです。ただし引数が無効な場合(終了コード 2)や --help が指定された場合(終了コード 0)は 1 つも呼ばれません。
  • 終了ステータスはランナーの戻り値 0、1、2 のいずれかに等しくなります。
  • --backend、その値、--help/-h 以外の引数は、変更されず順序どおりにランナーに渡されます。

却下した代替案

  • 4 つの実行ファイル。 同一の main 関数を持つ 4 つのパッケージと 4 回のリンクが必要になり、動作上の利点はありません。
  • サブコマンド(floating-conformance gda …)。 位置引数によるバックエンド指定はランナーのパスと衝突します。明示的なオプションなら曖昧さがありません。
  • ランナーからの終了コード。 ランナー内で exit を呼ぶと、ライブラリとしてテストできなくなります。

境界

  • native ターゲットのみ(ファイルアクセスは moonbitlang/x/fs、終了は moonbitlang/x/sys 経由)。
  • コーパスのダウンロード、計画、並列化、集計は行いません。それらは tools/conformance.py と tools/run_*_interpreter.py スクリプトにあります。
  • 公開 MoonBit API はありません。