internal/runner_cli チュートリアル

このページでは、internal/runner_cli の共有ヘルパーを使って cli/ に適合性ランナーを書く方法を、メンテナ向けに説明します。共通オプションの構文解析、コーパスファイルの収集と読み込み、診断の報告、JSON 要約の出力、終了コードの選択を扱います。このパッケージは Luna-Flow/floating の内部パッケージであり、例は公開モジュールに対してはコンパイルされません。

クイックスタート

モジュール内部で、ヘルパーとフロントエンドをインポートします。

import {
  "Luna-Flow/floating/internal/runner_cli",
  "Luna-Flow/floating/frontend/gda_expr",
}

最小限のランナー(run は引数ベクトル全体を受け取り、先頭はプログラム名です):

///|
pub fn run(arguments : Array[String]) -> Int {
  let common = match @runner_cli.parse_common_options(arguments) {
    Ok(value) => value
    Err(message) => {
      println(message)
      return 2
    }
  }
  let files = match @runner_cli.collect_files(common.remaining(), ".decTest") {
    Ok(value) => value
    Err(message) => {
      println(message)
      return 2
    }
  }
  let documents = []
  for path in files {
    guard @runner_cli.read_source(path) is Ok(text) else {
      println("cannot read file: " + path)
      return 2
    }
    match @gda_expr.parse_dectest(path, text) {
      Ok(document) => documents.push(document)
      Err(diagnostics) => {
        let first = diagnostics[0]
        println(
          @runner_cli.format_diagnostic_at(
            first.span().source(),
            first.span().line(),
            first.message(),
          ),
        )
        return 2
      }
    }
  }
  let summary = @gda_expr.execute_documents(
    documents,
    options=@gda_expr.RunOptions::new(
      shard_count=common.shard_count(),
      shard_index=common.shard_index(),
    ),
  )
  if common.json() {
    println(
      @runner_cli.json_stringify(
        @runner_cli.json_object([
          ("totalCases", @runner_cli.json_int(summary.total_cases())),
          ("failedCases", @runner_cli.json_int(summary.failed_cases())),
        ]),
      ),
    )
  }
  if summary.success() { 0 } else { 1 }
}

日常的なタスク

終了コードの規約に従う

cli/ のすべてのランナーは同じコードを使い、tools/*.py はそれに依存しています。

コード意味
0実行されたすべてのケースが合格した(strict モードではさらに、サポート外のものが何もなかった)
1少なくとも 1 つのケースが失敗した、または strict モードでサポートされないケースが見つかった
2使用法エラー、読み取れないファイル、または構文解析の診断

ランナー固有のオプションを追加する

parse_common_options は、認識しないすべての引数を順序どおりに remaining() に残します。その配列から独自のオプションを解析し、残りをパスとして扱ってください。ランナーがシャード分割できない場合は allow_shard=false を渡します。その場合シャードオプションは remaining() に残るので、パーサはそれらを未知のオプションとして拒否すべきです。

出力を機械可読に保つ

--json が指定された場合は、1 回の呼び出しにつきちょうど 1 つの JSON オブジェクトを出力します。キーの順序が列挙した順になるよう json_object で構築し、件数が整数として出力されるよう json_int を使ってください。

さらに進んで

  • cli/ の 4 つのランナーが完全な例です:gda_expr_cli、itl_expr_cli、mpfr_expr_cli、testfloat_expr_cli。
  • native のディスパッチャは sh tools/run_moon_clean_exec.sh run --release --target native src/cli -- --help でビルドします。
  • ヘルパーのテストは、モジュールを含むワークスペースから実行します:moon test -p Luna-Flow/floating/internal/runner_cli。

よくある落とし穴

  • プログラム名。 parse_common_options は arguments[0] を読み飛ばします。プログラム名を除いたスライスではなく完全なベクトルを渡してください。そうしないと最初の実引数が失われます。
  • ディレクトリは再帰的に探索されません。 collect_files はディレクトリの直下のエントリだけを列挙します。
  • 一致しないファイルは黙って除外されます。 接尾辞を持たないファイル引数は報告されずに無視されます。
  • 実質的に native 専用。 ファイルアクセスは moonbitlang/x/fs を介して行われるため、ランナーは native ターゲットでビルド・実行されます。

次のステップ