xyo-rust は、Scratch の .sb3 プロジェクトを Rust で読み込み、構文解析し、LLVM IR を生成して JIT で動かす実験的なランタイム / コンパイラ基盤です。
いまの主眼は SB3 ローダー・パーサー・IR 生成 / JIT 実行経路の検証 にあります。Scratch VM と同等の完全実行を目指す段階ではなく、まずは「Scratch プロジェクトをどこまで静的に扱えるか」を試すための土台が実装されています。
Scratch は MIT メディアラボが開発したビジュアルプログラミング環境です。.sb3 ファイルは ZIP アーカイブで、内部の project.json にすべてのブロック・スプライト・変数などのメタデータが JSON 形式で格納されています。
xyo-rust はこの project.json を Rust の型として読み込み、hat block(「緑の旗が押されたとき」など)を起点にスクリプトを解析して LLVM IR を生成し、JIT で動かします。
.sb3 ファイル
│
▼
[SB3 ロード] src/sb3.rs
ZIP を展開し project.json を取り出す
│
▼
[デシリアライズ] src/types/
project.json → ScratchProject (Rust 構造体)
│
▼
[パース] src/parser/
hat block → Thread (スレッド)
各ブロック → Stmt / Expr (AST)
│
▼
[IR 生成 + JIT 実行] src/compiler/
Thread → LLVM 関数
最適化パス (O3) を適用
JIT で各スレッドを実行し、状態を標準出力へ表示
│
▼
実行結果 (標準出力)
| 機能 | コマンド | 状態 |
|---|---|---|
project.json を取り出して表示する |
json |
✅ |
| ブロック数・使用 opcode を確認する | stats |
✅ |
| hat block からスレッドを抽出する | run |
✅ |
| 動き系命令・演算子を LLVM IR へ変換し、JIT で実行する | run |
🚧 一部 |
| JSON パースエラー時の位置情報・コンテキスト表示 | — | ✅ |
| 完全な Scratch 互換実行 | — | ❌ |
- Scratch opcode の網羅的な IR 実装(現状は動き系 + 演算子のみ)
- Scratch VM 相当のイベントランタイムの完成
- 生成した IR から実行可能ファイルへつなぐフロー
- 互換性検証とリグレッションテストの拡充
runサブコマンドの未実装命令に対する安全なフォールバック
| ツール | バージョン | 確認コマンド |
|---|---|---|
| Rust | stable | rustc --version |
| LLVM | 21.1.x | llvm-config --version |
llvm-config |
PATH 上にあること | which llvm-config |
clang |
PATH 上にあること | which clang |
inkwell を使っているため、LLVM のメジャー・マイナー差異には注意が必要です。作業前に llvm-config --version が 21.1.x を返すことを確認してください。
git clone https://github.com/pnsk-lab/xyo-rust.git
cd xyo-rust
cargo build --releasecargo build は build.rs を通じて bitcodes/ 配下の C コードも再生成します。ビルドが成功すると target/release/xyo が生成されます。
cargo testcargo run -- --help生成される実行ファイル名は xyo です。開発中は cargo run -- ... で試せます。
cargo run -- stats <path-to-project.sb3>出力例:
File: my_project.sb3
Loading Time: 2.345ms
Block Number: 42
Using Op Codes: ["event_whenflagclicked", "motion_movesteps", "operator_add"]
cargo run -- json <path-to-project.sb3>.sb3 に含まれる project.json をそのまま表示します。jq などと組み合わせてフィルタリングできます。
cargo run -- json my_project.sb3 | jq '[.targets[].blocks[].opcode] | unique | sort'cargo run -- run <path-to-project.sb3>run は現状もっとも実験的なコマンドです。動き系命令と演算子のみを含むシンプルなプロジェクトから試すことを推奨します。成功時は各スレッドの実行後状態が標準出力に表示されます。
JitSpriteState { sprite_x: 100.0, sprite_y: 0.0, sprite_rotate: 0.0 }
このリポジトリには現在、配布用の .sb3 サンプルは含まれていません。Scratch エディタでプロジェクトを作成し、「ファイル」→「コンピューターに保存する」 で .sb3 を書き出して入力に使ってください。
run で最後まで通したい場合は、動き系ブロック(「〇歩動かす」「x座標を〇にする」)と演算子のみを使ったシンプルなプロジェクトから始めると確認しやすいです。
xyo-rust/
├── src/
│ ├── main.rs CLI エントリポイントとエラー出力
│ ├── cli.rs サブコマンド定義 (clap)
│ ├── sb3.rs .sb3 / project.json の読み込みと詳細エラー整形
│ ├── types/ Scratch JSON 構造を受ける型定義
│ ├── parser/ Scratch ブロック列を Stmt / Expr に変換
│ └── compiler/ LLVM IR 生成
├── tests/ CLI テスト
├── bitcodes/ C ソースと生成済み bitcode / IR
├── docs/ Markdown ソースと Taiga サイト生成ファイル
├── build.rs ビルドスクリプト (C → bitcode)
└── Cargo.toml プロジェクト設定
| ワークフロー | トリガー | 内容 |
|---|---|---|
ci.yml |
push / pull_request / workflow_dispatch |
Ubuntu 上で cargo test を回す通常 CI |
build.yml |
GitHub Release 用の tag push | Rust バイナリのマルチプラットフォームビルド |
pages.yml |
ドキュメント更新時の push | ドキュメントを GitHub Pages へデプロイ |
bitcodes/ には LLVM bitcode と LLVM IR の生成元 C コードがあります。bitcodes/c/ 配下のトップレベル .c ファイルが cargo build 時にまとめて再生成され、対応する出力が bitcodes/bc/ と bitcodes/ll/ に書き出されます。Git には生成物を含めません。
現在は dtoa.c、atod.c、to_lower.c が対象です。to_lower.c は、XYO_ICU_ROOT で指定した ICU source tree、または bitcodes/c/lib/icu-prebuilt の include/ を使って bitcode / IR を生成します。日常運用では、同じ ICU から生成した prebuilt static archive をネイティブ動作確認に使うルートを正式扱いにしています。ICU ソースごと to_lower.bc に埋め込む重い自己完結ビルドは、XYO_EMBED_ICU_BITCODE=1 を付けたときだけ有効です。
セットアップ全体を流すには次を使います。
CLANG=clang-23 \
CLANGXX=clang++-23 \
./setup.shsetup.sh は prebuilt ICU 構築、cargo build --release、to_lower.ll の native check までを順に実行します。
通常の cargo build を軽く保つため、build.rs はデフォルトでは ICU ソース全体の bitcode 化を行いません。自己完結な to_lower.bc を試したいときだけ、次のように明示 opt-in します。
XYO_EMBED_ICU_BITCODE=1 cargo build --releaseICU source tree が既定位置に無い場合は、XYO_ICU_ROOT=/path/to/icu を付けて setup.sh や cargo build を実行できます。prebuilt archive の配置先を変えたい場合は XYO_ICU_PREBUILT_DIR=/path/to/prebuilt を使います。
ローカルで再生成するには次を使います。
./bitcodes/build.sh古い出力を消して作り直す場合は --clean、全部強制再生成する場合は --force を付けます。
to_lower.ll をネイティブ実行で確認したい場合は、事前に構築した ICU の static archive を使って次を実行できます。
まず vendored ICU から prebuilt archive だけを作る場合は次を使います。
CLANG=clang-23 \
CLANGXX=clang++-23 \
./tools/build_icu_prebuilt.sh生成先は bitcodes/c/lib/icu-prebuilt です。--clean を付けると configure 結果から作り直します。
XYO_ICU_PREBUILT_DIR=/path/to/icu \
CLANG=clang-23 \
CLANGXX=clang++-23 \
./tools/check_to_lower_native.shこのスクリプトは tools/to_lower_harness.c を使って bitcodes/ll/to_lower.ll をネイティブリンクし、"", "0", "false", "FALSE", "true" などの基本ケースを確認します。
XYO_ICU_PREBUILT_DIR を省略した場合は bitcodes/c/lib/icu-prebuilt を自動で見に行きます。既存の XYO_ICU_NATIVE_LIB_DIR も後方互換として使えます。
詳細は ドキュメントサイト を参照してください。
| ページ | 内容 |
|---|---|
| セットアップ | LLVM インストール・ビルド手順・最初のコマンド |
| CLI | サブコマンドの詳細・出力例・エラーの読み方 |
| 対応ブロック一覧 | opcode ごとのパーサー / IR 対応状況 |
| アーキテクチャ | パイプラインの詳細・モジュール設計 |
MIT