mie コマンド仕様 v1
本書は mie CLI の起動形態と各サブコマンドの仕様を定める。言語の意味論は language-spec.md、組込関数群は prelude.md を参照。分量の大きい 3 つのモードは別冊に分離した — REPL は repl.md、LSP サーバは lsp.md、整形 (mie fmt) は format.md。本書中の §N は本書内の節を指し、別冊内の節は「repl.md「動作モード」」のように書名+節名で参照する。
1. 起動ディスパッチ
mie [SUBCOMMAND | <path>] [ARGS...]
第 1 引数によって起動モードが決まる。
| 第 1 引数 | モード | 節 |
|---|---|---|
なし (または --strict のみ) | REPL | repl.md |
lsp | LSP サーバ | lsp.md |
build | バイナリビルド | §4 |
check | 静的検査のみ | §6 |
test | テスト実行 | §7 |
fmt | ソース整形 | format.md |
lint | スタイル検査 | §9 |
doc | リファレンス生成 | §10 |
add | 依存追加 | §11 |
get | 依存取得 | §11 |
update | 依存更新 | §11 |
remove | 依存削除 | §11 |
eval | 標準入力評価 | §5.6 |
| それ以外 | ファイル実行 | §5 |
サブコマンド名 (lsp / build / check / test / fmt / lint / doc / add / get / update / remove / eval) は予約。同名の .mie ファイルを実行したい場合は ./lsp のようにディレクトリ付きで指定する。
1.1 終了コード
ファイル実行モード・eval モード・build モード・check モードの終了コード:
| code | 意味 |
|---|---|
0 | 成功 |
1 | 構文エラー / 評価エラー / ビルドエラー |
2 | I/O エラー / 引数不正 / 必須ツール不在 |
REPL と LSP サーバは正常終了時 0。
1.2 ソース系サブコマンドの住み分け
check / fmt / lint はいずれも評価せずソースを扱うが、責務が異なる。
| ツール | 対象 | 動作 | 不変条件 |
|---|---|---|---|
check (§6) | 正しさ(構文 + 静的エラー、到達可能グラフ全体) | 検出のみ | — |
fmt (format.md) | 具体構文の正規形 | -w で書き換え | 抽象構文木を保存 |
lint (§9) | スタイル/品質(パース可能前提、保守的) | 検出、--fix で書き換え | --fix は抽象構文を変えうる |
checkとlintはどちらも評価せず診断するが、checkは「正しさ」(エラーの有無、モジュールグラフ単位)、lintは「書き方」(エラーではないスタイル問題、ファイル単位で import 解決なし)。fmtとlint --fixはどちらもソースを書き換えるが、不変条件が違う。fmtは抽象構文木を保存する正規化のみ(具体構文の見た目を正す。例: 1 引数f(x)→f x)。lint --fixは抽象構文を変える正規化まで踏み込む(例: 制御構造if(c, t, e)→if c {t} {e}。評価結果は同じだが適用の段数=抽象構文が変わる)。よってfmtは制御構造のタプル形を保ち、並置化はlint --fixが担う。
2. REPL
REPL (mie を引数なし、または --strict のみで起動) の仕様は repl.md に分離した。
3. LSP サーバ (mie lsp)
LSP サーバ (mie lsp) の仕様は lsp.md に分離した。
4. ビルド (mie build)
エントリ .mie とその import 依存を go:embed で同梱した単体 Go バイナリを生成する。生成バイナリはホストに mie 処理系をインストールしなくても動く。
4.1 構文
mie build [-o <output>] [--target <os>/<arch>]... [--strict] <entry.mie>
引数の並びは フラグ → エントリ の順。Go の flag パッケージの規約に従い、positional 引数 (エントリ) より後ろのフラグは解釈されない。
4.2 オプション
| フラグ | 既定値 | 意味 |
|---|---|---|
-o <output> | エントリの basename から .mie を除いたもの | 出力ファイル名のベース |
--target <os>/<arch> | ホストの GOOS/GOARCH | ビルドターゲット。複数指定可 |
--strict | off | ビルド前に strict 型検査 (§4.9) を適用する |
4.3 出力名
- ターゲットが 1 個:
<output>をそのまま使う。 - ターゲットが複数:
<output>-<os>-<arch>の形に展開。 - ターゲット OS が
windowsの場合は.exeを付与。
4.4 対応ターゲット
go build がサポートする任意の GOOS/GOARCH ペア。検証済みの組合せ:
darwin/arm64darwin/amd64linux/amd64linux/arm64windows/amd64
4.5 import の静的解決
ビルドはまず entry を起点に 静的検査 (static-analysis.md §1) を行う。構文エラー (動的 import を含む) や import 先不在があればビルドを中止し exit code 1。検査を通過した場合のみ、@import "<path>" のリテラルパスを再帰収集して embed する。embed ルート (相対 slash パスの 0 点) は、プロジェクトに package.mie (packages.md) があれば その manifest dir、無ければ エントリの所属ディレクトリ。
- 構文エラー / import 先不在 → 静的エラーで 停止 (ファイル実行 §5・
mie check§6 と同一規則)。 - embed ルートより外 (
../...) に出る相対 import は エラー で停止する (embed FS の制約)。 pkg:依存 (third-party、packages.md) は lockfile で解決したグラフを別名前空間pkg/<source>@<version>/...に embed する。path dep は embed ルート相対の元位置に embed し、embed ルート外 (../...) を指す path dep は embed 不可として エラー で停止する (git dep 化を案内)。path dep は commit 固定が無いため embed 時に再現性警告を stderr に出す。std:モジュールは従来どおり host コンパイル同梱 (embed FS とは独立)。
4.6 ホスト要件
- ホストに
goツールチェーン (Go 1.26+) が必要。exec.LookPath("go")で確認し、無ければ「go toolchain not found in PATH」を stderr に出して exit code2。 - 内部で
go mod tidyおよびgo build -ldflags="-s -w"を実行する。 - 生成バイナリ自体の実行には Go ツールチェーンは不要。
4.7 mie リポジトリの位置解決
生成プロジェクトは replace github.com/bluegreenhq/mie => <path> で本体ソースを参照する。<path> は次の順で決定する:
- 環境変数
MIE_REPOの値 (絶対化) os.Executable()の親から最大 6 階層上向きにgo.modを含むディレクトリを探索os.Getwd()から最大 6 階層上向きにgo.modを含むディレクトリを探索
いずれも見つからなければエラーで exit code 2。
4.8 進捗出力
go mod tidy / go build の stdout/stderr はそのまま stderr に流す。
4.9 strict 型検査 (--strict)
mie build --strict は、§4.5 の構文層 静的検査 (static-analysis.md §1) の通過後・go build の起動前に、entry を起点とした strict 型検査 (static-analysis.md §3) を走らせる。型エラーが 1 件でもあれば診断を stderr に出してビルドを中止し exit code 1 で停止する (バイナリは生成しない)。検査がクリーンなときのみ通常どおりビルドを続行する。
- strict 規則はファイル実行
mie <path> --strict(§5.5) と同じ (static-analysis.md §3 の 6 規則)。 - 実効 strict はファイル単位。entry ファイルが header
#{mie strict}/#[mie strict](language-spec.md §13.1) を宣言していれば--strict無しでもその entry は strict として検査される。実効 strict = 「CLI--strict」OR「entry header のstrict属性」。 - フラグ無し・header に strict 無しの
mie buildは従来どおり構文層検査のみで、型検査は行わない (通常モードのmie <path>と揃う。実行時照合が backstop、§6.2)。
5. ファイル実行 (mie <path> [args...])
<path> を .mie ソースとして読み込み、評価する。<path> より後ろのトークンは プログラム起動引数としてそのまま実行プログラムへ渡り、std:env の args() (std/env.md §3) で取得できる。
mie app.mie list --json hello # args() は ["list", "--json", "hello"]
mie 自身のフラグ (--strict、§5.5) は位置を問わず entry に渡る前に取り除かれるため args() には現れない。その帰結として、プログラムへ literal --strict を引数として渡すことはできない。
5.1 ヘッダ要件
ファイル先頭の #{mie} ヘッダは省略できる (省略時は #{mie} 明示と同一意味、language-spec.md §1.1 / §13.1)。#[mie] ヘッダ (ライブラリ形) は省略不可。先頭の空行・行コメント・shebang #!... は許容される。
5.2 標準入出力
- 標準入力:
input(prompt)(prelude.md §1) の読み取り元。 - 標準出力:
print(s)の出力先。 - 標準エラー: パース/評価エラーメッセージの出力先(トップレベルに達した
?の失敗 bail 診断を含む、language-spec.md §16.7)。
5.3 import の解決
@import "<rel>" は caller ファイルのディレクトリ を起点に絶対化される。同じファイルを複数回 import してもパースは 1 度だけ (*module.Manager の Cache による)。循環 import は呼び出し位置のエラーで停止する (詳細は language-spec.md の import 章を参照)。
ファイル実行モードでは OS の filepath.Abs ベースの解決が使われ、ファイルシステム外への参照 (絶対パスなど) も許される。embed バイナリ (§4) では FS ルートからの slash 相対パスに限定される (runtime.Config.EmbedMode)。
std:fs の各関数 (read / write / readdir ほか、std/fs.md) は @import "std:fs" で取得するが、データファイルの読み書きはソースの @import "x.mie" とは 解決系統が別 で、embed バイナリ内でも常にホスト FS の cwd 相対で動く (embed FS にはアクセスしない)。std:fs モジュール自体は embed バイナリにも常に含まれる。
5.4 終了コード
| 状況 | code |
|---|---|
| 正常終了 | 0 |
| パース・評価エラー | 1 |
| ファイル読み取り失敗 | 2 |
トップレベルに達した未処理失敗(? の失敗 bail、language-spec.md §16.7)は評価エラーとして 1。診断は stderr(§5.2)に出す。
5.5 strict 型検査 (--strict)
mie <path> --strict は、評価の 前に strict 型検査 (static-analysis.md §3) を走らせ、型エラーが 1 件でもあれば診断を stderr に出して 評価せず exit code 1 で停止する。型検査がクリーンなら通常どおり評価する。フラグは path の前後どちらに置いてもよい (mie --strict <path> / mie <path> --strict)。
- strict モードは static-analysis.md §2 の健全・漸進検査に「名前付き関数の結果型に明示 Any を禁止 (省略は許容)」「名前付き関数のパラメータ型必須化」「宣言結果型を契約とした越境照合」を上乗せする (static-analysis.md §3)。
- 実効 strict はファイル単位で決まる。entry ファイルが header
#{mie strict}/#[mie strict](language-spec.md §13.1) を宣言していれば、--strictを付けなくてもそのファイルは strict として検査される。実効 strict = 「CLI--strict」OR「entry header のstrict属性」。 - フラグ無し・header に strict 無しの
mie <path>は従来どおり型検査せず実行する (実行時照合が backstop)。 - 終了コードは §5.4 と同じ (型エラーは構文/評価エラーと同じ
1)。
5.6 標準入力からの評価 (mie eval)
mie eval は標準入力から読み込んだソース全量を .mie プログラムとして評価する。エディタの選択範囲など、ファイルに無いソース断片を実行する用途を想定する。
- 入力: 標準入力全量がソース。パス引数は取らない。
- ヘッダ: ファイル実行 (§5.1) と同じく
#{mie}は省略可。 - 標準出力:
print(s)の出力先。標準エラー: パース/評価エラーの出力先。 input(): 標準入力はソースとして消費されるため、input(prompt)は即座に EOF(空)を受け取る。- import の解決:
@import "<rel>"は 実行時カレントディレクトリ を起点に絶対化される(§5.3 と同じ OS filepath ベース)。エラー位置のファイルラベルは<stdin>と表示する。 - 終了コード: ファイル実行 (§5.4) と同一。
| 状況 | code |
|---|---|
| 正常終了 | 0 |
| パース・評価エラー | 1 |
| 標準入力の読み取り失敗 | 2 |
eval は 評価する 点で、評価せずソースを扱う check / fmt / lint (§1.2) とは別系統である。
6. 静的検査 (mie check)
指定した各 .mie を起点 (entry) に、評価せず 静的検査 (static-analysis.md §1) のみを実行する。entry とそこから到達可能なモジュールグラフ全体を構文検査し、結果に応じた終了コードを返す。CI や保存時フックでの利用を想定する。
6.1 構文
mie check [--strict] <path>...
引数は .mie ファイルまたはディレクトリを 1 個以上。ディレクトリは配下の .mie を再帰収集する (fmt / lint と同じパス展開、§4)。収集した各ファイルをそれぞれ entry として検査する。1 件の検査単位は到達可能なモジュールグラフ全体であり、lint の「ファイル単位・import 解決なし」とは異なる (§4)。
6.2 検査内容
ファイル実行 (§5) の開始前に走るものと同一の検査 (同じ internal/analyze)。検出対象は static-analysis.md §1 を参照。
mie check は構文・import 解決層 (§6.2 前段) に加えて、健全な静的型検査 (static-analysis.md §2) を行う。検出するのは「実行すれば確実に型不一致 panic になる」ことが静的に確定する箇所だけで (誤検出を出さない)、確定しない箇所は素通しする (漸進的型付け)。深いケース (関数結果の越境推論・演算子レベル・未定義型参照の静的化など) は将来段階。型検査は mie check と LSP 診断でのみ走り、通常モードの mie <path> / mie build には適用しない (実行時照合が backstop)。
6.3 strict 型検査 (--strict)
mie check --strict <path>... は、§6.2 の健全・漸進検査に strict 規則 (static-analysis.md §3) を上乗せして検査する。越境・契約まわりで追加検出するのは次の 3 点:
- 名前付き関数の結果型に明示 Any を禁止 (省略は許容): 名前に束縛された関数 (body 非空) の結果型を宣言する場合 (束縛注釈
add: {Int, Int | Int} := …/内部名注釈{self: {Int, Int | Int} | …}/body 末尾アスクリプション{x, y | x + y: Int}のいずれか。language-spec.md §17.3)、その結果型をAnyにすると型エラー。結果型注釈を省略した場合は許容しAny扱いとする (素通し)。 - 名前付き関数のパラメータ型必須化: 名前に束縛された関数 (body 非空) の各パラメータ型が、インライン注釈・宣言関数型の対応位置 (非
Any)・推論可能なデフォルトのいずれでも確定しなければ型エラー。インラインx: Anyは動的型へのオプトインとして充足する (型変数の無い mie で真に多相な関数を書く唯一の手段)。bare パラメータと関数型注釈位置のAnyは充足とみなさない (static-analysis.md §3)。 - 宣言結果型を契約とした越境照合: 完全適用
f(args)の結果型を宣言から確定し、x: T := f(args)等の照合に用いる。
加えて、分岐の収束系診断 (static-analysis.md §3 規則 (4)-(6)) も strict で報告する: if/@match の分岐結果型が確実に割れる場合、closed variant の @match の被覆漏れ (非網羅)、および到達しえないアーム・冗長な catch-all (不要 default)。
strict は mie <path> --strict (§5.5) と同じ規則。実効 strict もファイル単位で、entry が header #{mie strict} / #[mie strict] を宣言していれば --strict 無しでもその entry は strict として検査される (実効 strict = 「CLI --strict」OR「entry header の strict 属性」)。複数 entry のときは entry ごとに独立に判定する。診断・終了コードの形式は §6.1 / §6.2 と同じ (型エラーは exit 1)。LSP は mie lsp --strict (lsp.md「起動」)、ビルドは mie build --strict (§4.9) で strict 診断に対応する。
import 解決規則はファイル実行 (§5.3) と同じ (caller ディレクトリ基準、OS filepath ベース)。各 entry は独立に検査するため、複数 entry が同じモジュールを import する場合そのモジュールは複数回検査される (診断は冪等)。
6.3 出力と終了コード
- 全 entry の検査がクリーンな場合は 何も出力せず exit code
0。 - 静的エラーがある場合は各診断を
<file>:<line>:<col>: <msg>形式で stderr に出す。 - 複数 entry のときは全 entry を検査し、終了コードはそれらの最大値を返す (いずれかに静的エラーがあれば
1、いずれかの読み取りに失敗すれば2)。
| 状況 | code |
|---|---|
| 静的エラーなし | 0 |
| 静的エラーあり | 1 |
読み取り失敗 / 引数不正 / .mie 不在 | 2 |
7. テスト (mie test)
mie のテストを mie 自身で書く。*_test.mie 内に test "name" {block} を並べ、assert 名前空間でアサーションする。CI やローカル開発での回帰検査を想定する。
test / assert は mie test 専用の魔法束縛ではなく、@import で取得する通常のライブラリ (std:test / std:assert) である。mie test はそれらで組んだテストを収集・実行する専用ランナーであり、REPL・playground・mie run からも同じ API を使える。
7.1 構文
mie test [path...]
pathは 0 個以上。各pathはファイルまたはディレクトリ。- ディレクトリは配下を再帰し、ファイル名が
_test.mieで終わるものを収集する。 - ファイルはそのまま対象にする (名前が
_test.mieで終わらなくてよい)。 - 引数省略時は cwd を対象ディレクトリとする。
- 収集されたファイルはパス昇順で評価する。
7.2 テストライブラリ (std:test / std:assert)
テストの語彙は 2 つの標準ライブラリモジュールとして提供する。ambient 束縛ではないため、@import すれば REPL・playground・mie run を含む任意の文脈で使える。
std:assert — アサーション (状態なし)
equal / not_equal / ok / fail を持つ純粋な名前空間。失敗時に panic (object.Error) を投げるだけで std:test に依存しない。test の外で失敗した場合は通常どおりトップレベルまで伝播する。
assert := @import "std:assert" assert.equal(1 + 1, 2)
| 形 | pass 条件 | 失敗メッセージ例 |
|---|---|---|
assert.equal(actual, expected) | actual == expected (language-spec.md §9.1。ユーザー定義 == スロットも尊重) | assert.equal: expected 3, got 4 |
assert.not_equal(a, b) | a == b が偽 | assert.not_equal: expected values to differ, both 3 |
assert.ok(cond) | cond が true (Bool、language-spec.md §9.3) | assert.ok: expected true, got false |
assert.fail(message) | (常に失敗) | message |
両辺・実値の表示は各値の Inspect を用いる。
std:test — テストの構築と実行 (collect-then-run)
test は receiver を持ち回らない純関数で、テストを構築するだけ (実行しない)。実行・集計は run が担う。
[test, run] := @import "std:test" assert := @import "std:assert" run [ test "add" { assert.equal(1 + 1, 2) } test "less" { assert.ok ("a" < "b") } ]
| 形 | 返り値 | 意味 |
|---|---|---|
test("name", {block}) / test "name" {block} | Trial | name (String) のテストを 1 件構築する。block は必須スロット 0 個の本体付きオブジェクト ({body} 形)。実行はしない |
suite("name", [trials]) | Trial | 子 Trial をまとめたグループを構築する (ネスト可)。実行時に名前は 親/子 でプレフィックスする |
run([trials]) | Report | Trial 列を記述順に実行し、集計した Report を返す。出力はしない |
run の合否は各 Trial の block を呼んだ結果で決まる: panic (object.Error) なら FAIL (メッセージと位置を記録)、それ以外は PASS。1 件が失敗しても残りは継続実行する (合否境界は run にある)。group Trial は子を再帰実行する。
Report は集計値で、少なくとも次を持つ:
{
passed := Int
failed := Int
failures := [{ name := String, message := String, pos := String |}]
|}
出力・整形は行わない (printer / reporter は将来課題)。mie test は返った Report を §7.5 の形式で整形出力する。REPL では run の返り値をそのまま参照・表示すればよい。
7.3 収集 (mie test の top-level Trial 収集)
mie test は各対象ファイルについて次を行う:
- 静的検査 (§6 / static-analysis.md §1) を通す。
test/suite(std:test) とassert(std:assert) をファイルスコープに供給して評価する (ゼロボイラープレート維持。REPL・playground・mie runはこの供給を受けず@importで明示取得する — 同一意味論・入口 2 つ)。- ファイルの top-level が返す値のうち Trial であるものを記述順に収集する。
#{mie}ブレース形式のファイル (テストファイルの通常形) では top-level の bare な式文 (test "name" {block}/suite …) が対象。#[mie]ブラケット形式や|区切りを使うファイルでは file-root の位置スロット (language-spec.md §1.4) も同じ枠で拾う。名前束縛 (t := …) の値は収集対象にしない (ヘルパ・import は束縛として共有する)。 - 収集した Trial 列を
runで実行し、返った Report を §7.5 形式で整形出力し、終了コードを立てる。
したがって _test.mie は従来どおり top-level に test "name" {block} を並べるだけでよい。名前束縛 (ヘルパ定義・@import した被テストコード) は従来どおり共有する。
7.4 分離 (isolation)
- 各テストファイルは fresh な root 環境 で評価する (
mie <file>1 回相当)。ファイル間で状態は共有しない。 - ファイル評価はまず全 top-level 文を評価して Trial (thunk) を構築し、そのあと
runが各 Trial のblockを実行する。したがって top-level の副作用はテスト body より前に一度だけ起こり、各テストは共有 top-level 束縛 (ヘルパ定義・@importした被テストコード) を参照する。テスト間の自動状態リセットは行わないため、共有された mutable 状態を変更すると後続テストに影響しうる。 - 被テストコードは
@import "<rel>"で取り込む (§5.3 と同じ caller ディレクトリ基準の解決)。被テストコード側も必要なら@import "std:assert"してアサートヘルパを共有できる。
7.5 出力と終了コード
mie test は run の返した Report をもとに、各ファイルについてファイル名見出しを出し、テストごとに PASS / FAIL 行 (FAIL は失敗メッセージと位置を続ける) を出力。最後に集計行 <P> passed, <F> failed を出す。出力例:
foo_test.mie PASS add は和を返す FAIL add は0で恒等 assert.equal: expected 5, got 6 (foo_test.mie:8:3) 3 passed, 1 failed
| 状況 | code |
|---|---|
| 全テスト pass (対象 0 件を含む) | 0 |
| 1 件でも FAIL / 構文・評価エラー | 1 |
| I/O エラー / 引数不正 | 2 |
8. 整形 (mie fmt)
整形 (mie fmt) の仕様は format.md に分離した。
9. スタイル検査 (mie lint)
パースは通るが書き方として問題のあるパターンを検出する。構文エラー (= 静的検査 mie check §6 の領域) とは別レイヤで、スタイル/品質に絞った保守的な (誤検出を避ける) 検査を行う。
9.1 構文
mie lint [--fix] [path...]
path はファイルまたはディレクトリ (ディレクトリは配下を再帰して .mie を収集)。引数省略時は cwd を対象とする。収集ファイルはパス昇順で処理する。
--fix は自動修正可能なルールを修正してファイルを上書きする (現状の対象は control-juxtaposition)。修正の際ソースは整形され (mie fmt 相当 + 制御構造の並置化)、内容が変わる場合のみ書き込む。--fix 指定時は診断を出力しない。
9.2 ルール
| ルール | 検出内容 |
|---|---|
unused | 値が一度も読み出されないローカル束縛。immutable 宣言 name :=、mutable local name = (auto-vivify)、分割束縛 a, b := / = / [a, b] := の各名が対象。代入先 (書き込み) は使用に数えないため write-only な mutable local も検出する。さらに body 内で一度も参照されない inner-name ({self | …} の self、§4.2) も対象 (inner-name は body 専用の自己参照で名前による外部参照が無いため、ローカル束縛と同じく安全に判定できる)。ただし型注釈付き inner-name ({self: T | …}) は名前未参照でも自身の型を表明する用途があるため対象外。破棄子 _ は対象外。オブジェクトのスロット (関数引数を含む) は対象外 (下記) |
self-assign | 自分自身への代入 (x = x / a.b = a.b) で効果が無い |
control-juxtaposition | 制御構造 (if / when / while) がタプル形 if(c, t, e) で書かれている。並置形 if c {t} {e} が推奨 (--fix で自動変換) |
non-tail-recur | @loop 関数 (language-spec.md §16.9) の反復ドライバ (lexically 内側の inner-name 自己再帰) で、self 呼び出しが末尾位置になく TCO (language-spec.md §16.10) が効かない。深い反復で呼び出しスタックを消費する (溢れうる)。@loop は「これはループ (定数スタックで回るべき)」という意図の宣言なので、その駆動再帰が非末尾なら書き方の問題として報告する |
検出は保守的で、検出漏れ (false negative) は許容し誤検出 (false positive) を避ける。unused はシャドウイング等の曖昧なケースでは報告しない。
non-tail-recur を @loop に限る理由: 非末尾の自己再帰は一般には正常であり (fact / fib・木の再帰・分割統治・アキュムレータなしのリスト構築)、それらに警告するのは誤検出になる。@loop 注釈だけが「この関数はループ=定数スタックで回るべき」という意図を静的に宣言するため、その反復ドライバの非末尾 self 呼び出しに限れば高信号・低誤検出で報告できる (language-spec.md §16.10 の末尾位置判定を再利用する)。@loop を使わない一般の再帰は対象外 (Scala @tailrec が注釈付き関数のみを検査するのと同じく、意図の signal がある箇所だけを見る)。
unused がオブジェクトのスロットを対象としない理由: スロット (関数引数を含む) は、束縛元のオブジェクトが関数として呼ばれて body 内で参照されるだけでなく、obj.slot で外部から参照され得る。そして mie は型情報を静的に持たないため、ある .slot 参照がどのオブジェクトのどのスロットを指すかを mie lint は静的に特定できない。とりわけ次のパターンでは、スロットの参照がそのファイルの外 (別ファイル) に現れる:
- ファクトリ関数が構築して return するオブジェクト のメソッド/フィールド (importer が
account.deposit等で参照) - 引数として他の関数に渡すレコード (呼び出し先が
.fieldを読む) @type/@enumで宣言される 型のフィールド名
これらはファイル内に .slot が現れないため、スロットを未使用検出の対象に含めると誤検出になる。name := / name = / 分割束縛といった ローカル束縛は名前で外部参照されない ので安全に判定できるが、スロットは外部 API になり得る点が本質的に異なる。この区別はエスケープ解析や型情報なしには厳密化できないため、unused はスロットを一律に対象外とする (検出漏れを許容し誤検出を避ける保守的方針)。
9.3 出力と終了コード
検出は <file>:<line>:<col>: <msg> (<rule>) 形式で stdout に出す。
| 状況 | code |
|---|---|
| 検出なし | 0 |
| 検出あり / 構文エラー | 1 |
| I/O エラー / 引数不正 | 2 |
構文エラーのあるファイルは lint せず、診断を stderr に出して exit code 1 に寄与する。
--fix 指定時は診断を出力せず、修正対象を並置形へ書き換えてファイルを上書きする。修正成功 (変更なしを含む) は 0、構文エラーのあるファイルは整形せずスキップして 1、I/O エラーは 2。
10. リファレンス生成 (mie doc)
mie doc は prelude・std・言語構文の doc コメント(実装内 //| / #|)からユーザ向けリファレンス Markdown を docs/reference/ に生成する。ソース (internal/prelude 等の Go 実装、および言語構文の doc コメント) が真実源であり、docs/reference/ はそこから機械的に生成される派生物である。ライブラリ項目には、処理系の静的型表 (LSP hover と同じ出所) から型シグネチャ (mie 型表記) を合成し、形と同じコードブロックの 2 行目に束縛注釈と同じ「名前: 型」の形 (例 range: {Int, Int | Range}) で併記する。型表から確定しない項目 (型名の値束縛・each のように戻り型を静的に固定できないメソッドなど) は形と意味だけを出す。
10.1 構文
mie doc [--check]
引数を取らない (対象は常にリポジトリ全体の doc コメント)。
10.2 動作
mie doc— prelude・std 各モジュール・言語構文の doc コメントを収集し、ライブラリ項目に静的型表から型シグネチャを join した上で、docs/reference/{prelude.md, std/*.md, syntax.md}を生成して上書きする。mie doc --check— 同じ生成処理を行い、結果が現在のdocs/reference/の内容と一致するか検査する。差分があれば非ゼロ終了 (CI で「生成物が最新か」を検査する用途)。
10.3 doctest
doc コメント中の >>> で始まる例は doctest として抽出され、go test 実行時に実際に評価してその出力が期待値と一致するか検証される。ドキュメント中の例が実装と乖離することを防ぐ。
10.4 出力と終了コード
| 状況 | code |
|---|---|
生成 (--check 無し) 成功 | 0 |
--check で差分なし | 0 |
--check で差分あり | 1 |
| I/O エラー | 2 |
11. パッケージ管理 (add / get / update / remove)
third-party パッケージ (packages.md) の依存を、マニフェスト (package.mie) と lockfile (package-lock.mie) を介して管理する。取得元は git source とローカル path dep。別名解決・キャッシュ・推移依存・複数共存の意味論は packages.md、pkg: 解決の言語側は language-spec.md §13.4 を参照。
各コマンドは cwd を起点に上方探索で最も近いマニフェストを対象とする。マニフェストが無い場合は §11.5 のエラー。
add / remove はマニフェストの deps / entry を読み、正規形 (2 スペースインデント・末尾カンマなし) で書き戻す。deps 内に書いたコメントは保持されない。
11.1 mie add
mie add <host/path@tag> [--as <alias>]
<host/path@tag>の git source をキャッシュ (§12MIE_CACHE) へ取得し、tag→ commit を解決して lockfile に固定する。マニフェストdepsにalias := "<host/path@tag>"を追記する。--as <alias>省略時、alias はpathの末尾要素の-を_に正規化したもの (例github.com/u/mie-http→mie_http)。alias は mie の識別子 (スロット名) になるためハイフンを含めず、正規化しても有効な識別子にならない場合 (先頭が数字など) は取得せずエラーで--as <alias>を要求する。短い別名にしたい場合も--as httpを使う。- 既存の同名 alias があればその pin を更新する (version の差し替え)。
- path dep の追加は
mie addでは扱わず、マニフェストを直接編集する (取得を伴わないため)。
11.2 mie get
mie get
- 引数なし。マニフェストと lockfile を読み、未取得の依存をキャッシュへ復元する。lockfile があれば commit を信頼し tag の再解決はしない。CI・新規 clone 後の初期化に使う。
- lockfile が無い場合はマニフェストから tag → commit を解決して取得し、lockfile を生成する。
11.3 mie update
mie update [alias]
- マニフェストに記載された tag を再解決 (tag → 現在の commit) し、lockfile を書き換える。
alias指定でその 1 件、省略で全 git 依存。 - バージョンを上げるのは
tagの変更 (mie add <...@新tag>またはマニフェスト編集) であり、updateは記載済み tag の commit 固定を最新化するもの (semver range の自動引き上げは持たない)。
11.4 mie remove
mie remove <alias>
- マニフェスト
depsから<alias>を削除し、どの依存からも参照されなくなった実体を lockfile から除く。キャッシュ実体は他プロジェクトと共有のため削除しない。
11.5 出力と終了コード
| 状況 | code |
|---|---|
| 成功 | 0 |
| 取得・解決失敗 (不正な tag / リポジトリ到達不可 / マニフェスト不正) / 対象 alias 不在 | 1 |
引数不正 / マニフェスト読み取り失敗 / git 不在 | 2 |
git ツールチェーンは exec.LookPath("git") で確認し、無ければ exit code 2。
12. 環境変数
| 変数 | 影響先 | 意味 |
|---|---|---|
MIE_REPO | mie build / mie lsp | mie 本体ソースの絶対パス。設定すれば自動検出 (build §4.7 / lsp の定義ジャンプ lsp.md「定義ジャンプ」) より優先 |
MIE_CACHE | add / get / update / ファイル実行・build の pkg: 解決 | third-party パッケージのグローバルキャッシュ。未設定時の既定は XDG の $XDG_CACHE_HOME/mie (既定 ~/.cache/mie) (packages.md) |
13. 意図的に残す制約
go install github.com/bluegreenhq/mie/cmd/mie@latestでインストールしたバイナリからmie buildを使うには現状MIE_REPOが必要 (本体ソースの自動配置は未対応)。- Universal Binary (
darwin/arm64+darwin/amd64のlipo結合) は非対応 — 別ターゲットとして個別バイナリを並べるのみ。 - バイナリサイズ最適化は
-ldflags="-s -w"のみ。UPX 等の圧縮は行わない。 - LSP は semantic tokens・go-to-definition・references・hover (型情報)・補完 (ドットメンバ)・整形 (全文フォーマット)・コードアクション (lint 自動修正)・シンボル一覧 (アウトライン)・リネーム・インレイヒント (推論型)・出現ハイライト・診断 (静的検査 Error + lint Warning、publishDiagnostics) を提供 (各機能は lsp.md)。hover は prelude 組込名・ユーザ定義識別子に加え、型メソッド (
list.each等) とユーザ定義オブジェクトのメンバも対象とする (lsp.md「hover」)。補完はドット (.) を trigger に、レシーバの slot・型メソッド・std メンバ・universal method を返す (lsp.md「補完」)。 mie fmtは AST 再構成方式のため、行内の任意改行位置やスロットの positional/named 混在順といった意味に影響しない見た目は正規形へ寄せる (原文どおりには保たない)。mie lintのルールはunused/self-assign/control-juxtapositionの 3 つ。スコープ厳密解析は行わず、全体走査による保守的判定に留める (control-juxtapositionも構文上の callee 名のみで判定し、シャドーイングは見ない)。- third-party パッケージの取得元は git と ローカル path dep のみ (packages.md)。中央レジストリ・HTTPS tarball 直取得・semver range の自動解決は非対応 (exact pin + 複数共存)。
mie add等のパッケージ管理コマンドはgitツールチェーンを必要とする。