Python Tutor の C# 版。C# のコードを1行ずつ実行し、変数・スタックフレーム・ヒープ上のオブジェクト・参照の矢印を可視化して、初心者がプログラムの動きを「目で見て」理解できるようにする教育用ツールです。
すべてブラウザ内で完結します(サーバー不要・静的サイトとして配布可能)。
npm install
npm run dev # 開発サーバー (http://localhost:5173)
npm test # 意味論テスト(88件)
npm run build # 本番ビルド(dist/ に静的ファイルを出力)- 左のエディタに C# コードを書き「▶ 実行して可視化」(
Ctrl/⌘ + Enter) ◀ 前へ / 次へ ▶・スライダー・←→キー・自動再生でステップを前後に移動- コードの行をクリックするとその行を実行するステップへジャンプ
- スライダー上のタイムラインマーカー(緑=出力 / 紫=メソッド呼び出し / 赤=例外)をクリックしてイベントへ直行
- 参照の ● やヒープのオブジェクトにマウスを載せると、関係する矢印と実体が強調表示され、「どの変数がどれを指しているか」が一目で分かる
- 各ステップで「解説」パネルが何が起きたかを日本語で説明(参照の共有・struct のコピーも明示)
Console.ReadLine()は画面下の「標準入力」欄から1行ずつ読み取り- ヘッダーの「サンプル」から14個の教材プログラムを読み込み可能
| 表示 | 意味 |
|---|---|
| 赤い ▶ | 次に実行する行 |
| 緑の ▶ | 直前に実行した行 |
| ティール色のチップ | 値型(int / double / bool / char / struct)— 変数の箱に値が直接入る |
| ● → 矢印 | 参照型(配列 / List / Dictionary / クラス)— ヒープ上の実体を指す |
| 「共有」バッジ | ref / out 引数で呼び出し元と同じ変数を共有している |
| 「実行中」バッジ | スタックの最上段(現在実行中のフレーム) |
※ string は C# では参照型ですが、不変であるため表示の分かりやすさを優先して値のように表示しています(凡例にも明記)。
- エントリポイント: トップレベル文 /
class Program { static void Main() }/namespace内の Main(どれでも可) - 型:
intlongdouble(float/decimalは double として扱う)boolcharstringvarobject、配列・ジャグ配列、List<T>、Dictionary<K,V> - 制御構文:
if/elseforwhiledo-whileforeachswitch(フォールスルー禁止も検査)breakcontinuereturn - 式: 算術・比較・論理・ビット演算、
++/--、複合代入、三項演算子、????=?.、文字列補間$"{x:F2}"、複合書式"{0}"、キャスト、is/as - メソッド: トップレベル関数・クラスメソッド、オーバーロード、デフォルト引数、
ref/out(out var含む)、再帰 - クラス / struct: フィールド、コンストラクタ(
: base(...)連鎖)、自動プロパティ、式形式プロパティ / メソッド、静的メンバー・const、オブジェクト初期化子・コレクション初期化子 - 継承:
virtual/override(object のToString含む)、base.、アップ/ダウンキャスト - 例外:
try/catch/finally、throw、組み込み例外の階層(Exception←DivideByZeroExceptionなど)、ユーザー定義例外 - 標準ライブラリ(抜粋):
Console.WriteLine/Write/ReadLine、Math.*(Roundは偶数丸め)、string の主要メソッド、int.Parse/TryParse、Convert.*、Array.Sort/Reverse/IndexOf、string.Join/IsNullOrEmpty
未対応(使うと日本語エラーで案内します): LINQ、ラムダ式・デリゲート、interface、enum、abstract、async/await、ユーザー定義ジェネリック、多次元配列 [,]、null許容型 int?、パターンマッチング、本体付きプロパティアクセサ、入れ子クラス など
Visual Studio や Web からのコピペをそのまま動かせるよう、次を吸収します。
namespace(ブロック / ファイルスコープ)・usingディレクティブ・internalなどの修飾子- 属性
[STAThread]や#region/#pragmaなどのプリプロセッサ指令は読み飛ばし Console.ReadKey()/Console.Clear()は何もしない扱い(エラーにしない)String/Int32/Booleanなどの .NET 型名エイリアス、string.Format、Environment.NewLine- 全角スペースは C# の仕様どおり空白として受理。全角記号(
;など)や曲がった引用符(“ ”)は直し方つきの日本語エラーで案内 staticを忘れたMain、小文字のmain、クラス定義だけの貼り付けにも、始め方をエラーメッセージで案内
「本物の C# で動かしたら結果が違う」を避けるため、以下を vitest の意味論テスト(88件)で検証しています。
- 整数除算の切り捨て(
7 / 2 == 3、-7 / 2 == -3)と0除算のDivideByZeroException intの 32bit ラップ(int.MaxValue + 1 == int.MinValue、Math.imulによる乗算)structは代入・引数渡し・returnでコピー、classは参照共有(structメソッドのthis書き戻しも再現)ref/outは変数スロットの共有として実装(トレース上でエイリアス検出可能)boolの出力はTrue/False、doubleは最短ラウンドトリップ表記(2.0→"2"、1/0.0→"∞")Math.Round(2.5) == 2(偶数丸め)、Convert.ToInt32も同様foreach中のコレクション変更でInvalidOperationException- 未代入ローカル変数の使用・型不一致の代入などは「C# ではコンパイルエラー」として実行時に日本語で報告
Listの要素(struct)への直接フィールド代入はエラー(C# のコンパイルエラーを再現)
既知の簡略化: long は JS の安全整数範囲で扱う(64bitラップなし)/文字列の並び替え・比較は序数ベース/書式指定はカルチャ非依存の簡易実装/非virtualメソッドの隠蔽(new)は動的解決になる、など。
コード文字列
→ lexer.ts 字句解析(エディタのハイライトにも共用)
→ parser.ts 再帰下降構文解析 → AST
→ interpreter.ts ツリーウォーク実行
各文の実行前にスナップショットを記録(Python Tutor 方式)
→ trace(自己完結なステップ配列: 行番号・スタック・ヒープ・累積stdout)
→ React UI がトレースを前後に再生するだけ(逆方向ステップが自由)
| パス | 役割 |
|---|---|
src/interpreter/ |
字句解析・構文解析・実行エンジン・組み込みAPI・トレース型 |
src/interpreter/semantics.test.ts |
C# 意味論の回帰テスト |
src/explain/explain.ts |
ステップ間の差分から日本語の解説文を生成 |
src/examples/ |
教材サンプル14本(全て自動テストで実行可能性を担保) |
src/ui/ |
エディタ・コードビュー・状態キャンバス・操作パネル |
実行トレースは1ステップごとに完全な状態を持つため、UI は単なる「再生機」です。ステップ上限(既定1500)とヒープ上限で無限ループ・メモリ暴走から保護しています。
- UI・トレース形式の設計は Python Tutor(Philip Guo 氏)のアイデアに基づきます
- 依存ライブラリ: React / Tailwind CSS / shadcn+ui(Radix UI・lucide-react ほか)(開発時: Vite / TypeScript / vitest)

