rontolisp:wasm-export
(rontolisp:wasm-export 'name :as "alias" :params '(type...) :param-names '(name...) :returns type :async t)
WebAssembly コアモジュールへコンパイルする際に、トップレベルの defun を
ホストから呼び出し可能にし、その引数と戻り値の WASM 境界型を宣言します。これは
通常の関数ではなくコンパイル時のディレクティブです。インタプリタおよび
JVM バックエンドでは、名前付きシンボルをそのまま返す no-op となるため、同じ
ソースがすべてのバックエンドで動作します。詳細は
WebAssembly へのコンパイル を参照してください。JVM
版の双子は rontolisp:jvm-export で、同じ宣言が
コンパイルされたクラス上に型付きで Java から呼び出し可能なメソッドを生成
します。
引数
- エクスポートするトップレベル
defunを指すクォートされたシンボル。defun名と同じように現在のパッケージで解決されます。 :as— WASM エクスポート名の文字列 (例:"factorial"、JavaScript 向け API の camelCase 名など)。デフォルトは (パッケージ修飾子を除いた) 素の Lisp 名 (fact) です。:params— 各引数に対応する境界型指定子のリスト。省略、nil、'()の場合は 引数なしを意味します。:param-names— コンポーネントモデルのシグネチャにおける引数名を、:paramsの各要素に 1 つずつ、シンボルまたは文字列で指定します。それぞれコンポーネント モデルのラベル (lower-kebab-case の語) でなければなりません。デフォルトはp0、p1、... です。これはホストやバインディングジェネレータがコンポーネントの型で 目にする名前であり、したがって--emit-witが印字する名前でもあります。--component以外では無視されます (コア WASM の引数に 名前はありません)。またrontolisp:wit-exportで WIT world を実装している プログラムでは、これを宣言せず world から得ます。:returns— 戻り値の境界型指定子。省略、nil、'()、:voidの場合は void の 戻り値 (Lisp の戻り値は破棄される) を宣言します。:async—tの場合、--componentでエクスポートを非同期のコンポーネント モデル関数としてリフトします。これにより内部の I/O (print、rontolisp:fetchなど) がトラップせず動作します。デフォルトはnil(同期・純粋計算のリフト) です。意味を持つのは--componentのみで、Preview 1 /--no-wasiのコア エクスポートは無視し、--no-gc --componentは拒否します。
型指定子と境界表現は次のとおりです。
| Designator | WIT type | WASM boundary | Notes |
|---|---|---|---|
:s8 :s16 :s32 | s8 s16 s32 | i32 | :int は :s32 の恒久的な別名 |
:u8 :u16 :u32 | u8 u16 u32 | i32 | |
:s64 :u64 | s64 u64 | i64 | :long は :s64 の恒久的な別名。2^63 以上の :u64 値はトラップする (どのバックエンドも計算に使う符号付き 64 ビット整数に正確な表現を持たないため) |
:float | f64 | f64 | rontolisp に単精度浮動小数点数はないため、f32 は境界型ではない |
:bool | bool | i32 | 0 が nil、非ゼロの値はすべて t |
:string | string | (ptr, len) | 線形メモリ上の UTF-8 バイト列 |
:s-expr | string | (ptr, len) | 線形メモリ上の S 式テキスト (関数以外の任意の値)。対応する WIT 型はない |
:bytes | — | (ptr, len) argument / (ptr, cap) -> len result | (unsigned-byte 8) ベクタを生のバイト列として運ぶ。どちらの方向にも UTF-8 変換なし。GC コアモジュール形状専用 |
:bytes の結果は呼び出し側バッファ方式 (read(2) の形) です: エクスポートの
コアシグネチャの末尾にホストが渡す (ptr, cap) ペアが加わり — cap バイトは
エクスポートされた __ronto_alloc で確保します — ラッパーはそこへ最大 cap
バイトをコピーし、単一の i32 結果はベクタの全長です。バッファが小さすぎた
場合は切り詰めではなくリトライになります。
境界は値を正確に運ぶか、さもなければトラップします。 宣言した型が表現できない
値 — :u32 で返した負数、:u8 で返した 300、:s32 で返した 32 ビット範囲外の
値 — は、静かに折り返されて届くのではなく呼び出しを停止させます。マスクは一切行い
ません。これは wasmtime と、より厳格なバインディング生成系 (jco など) とで
コンポーネントの挙動を一致させることにもつながります。
表現可能な範囲は、どのバックエンドでも宣言した型そのものの範囲です。デフォルト
(GC) バックエンドでは着信する整数は正確な整数として届きます (fixnum に収まれば
そのまま、超えればボックス化された 64 ビット整数)。3000000000 という :u32
引数は正確な整数 3000000000 として Lisp コードに届きます。Lisp コード内の
整数演算は任意の大きさで正確です (:u32 引数 1073741823 に
対する (+ x 1) は正確に 1073741824 を返します)。宣言した型で表せない結果
だけが境界でトラップします。非 GC バックエンド (--no-gc) では整数を i64 で
計算し、同じように渡ります。
制限事項
--componentでは、エクスポートは WAVE 構文 (wasmtime run --invoke 'name(args)') で呼び出せる型付き コンポーネントモデルエクスポートになります: 固定幅整数族全体 (:longを 含む) と:float/:bool/void に加えて、:stringと:s-exprは コンポーネントモデルのstringとして渡ります (--no-gcに:s-exprは ありません)。同期 (デフォルト) のエクスポートは純粋計算で なければならず、内部の I/O はトラップします。印字や fetch を行うエクスポート には:async tを宣言してください。--no-gc --componentでは:asyncは 拒否されますが、印字はそのまま動作します (プログラムが印字するときだけ 配線される、組み込みの WASI 0.3 stdout マイクロアダプタを通じて。印字する プログラムのすべてのエクスポートは自動的にasyncリフトされます)。 エクスポート名は lower-kebab-case である必要があります (そうでない場合は:asで改名します)。また--emit-witを追加すると、コンポーネントの WIT world (すべてのエクスポートの型付きシグネチャ入り) が.wasmの隣に書き出されます。 コンポーネントモデル関数エクスポート とコンパクトなコンポーネント出力 を参照してください。インタプリタおよび JVM では名前付きシンボルを返すだけです。- エクスポートできるのはトップレベルの
defunのみで、宣言した引数の数はその アリティと一致しなければなりません。また関数値を引数や戻り値とする関数は対象外 です。 --component以外では、エクスポートされる関数は純粋計算です。入力・時刻・ ファイルアクセス (関数内でもトップレベルフォームでも) はサポートされません。--no-wasiではそれぞれに定義された答えがあり、素のトラップにはなりません — 出力は破棄、getenvとファイル検索は「無い」と答え、時計はホストが__ronto_set_timeで書き込んだ時刻を報告し (設定されるまではシグナル)、rontolisp:random-bytesは捕捉可能なエラーをシグナル、randomは組み込みの 生成器で動作し、トラップするのは標準入力だけです。 No-WASI(リアクター)モード を参照してください。もう 1 つ例外があります:--no-gcではprint/princ/terpriが、プログラムが印字する場合にのみ追加される単一のfd_writeインポートを通じて動作します (印字を参照)。- 非 GC バックエンド (
--no-gc) は:int/:long/:float/:bool/:stringを サポートしますが、cons/リーダ/プリンタのランタイムを必要とする:s-exprと、 配列を必要とする:bytesはサポートしません。 :bytesは GC コアモジュール (Preview 1 /--no-wasi) の境界型です:--componentは拒否し (list<u8>リフトは未対応)、対応する WIT 型は ありません。