ひとことで言うと
Fluxa-WebCPは「C++コンパイラ」ではありません。 競技プログラミングで実際に書かれる範囲のC++を、ASTノード1個ずつ実行し、その途中状態をまるごと観測できるようにした、教育・デバッグのための実行基盤です。
オンラインジャッジは「AC / WA」という結果しか返しません。Wandboxやコンパイラエクスプローラは最終的な標準出力を見せてくれます。けれど、そのどれもが「dp配列が1行ずつ埋まっていく様子」や「再帰dfsの中でコールスタックがどう積まれているか」を見せてはくれません。
Fluxa-WebCPは、まさにそこを埋めるために作りました。
どんな意識で作ったか — 3つの約束
このプロジェクトは、機能の足し算ではなく 3つの設計上の約束 を軸に組み立てています。妥協できる便利機能ではなく、これが守られているからこそ価値がある、という核です。
1. 「1ステップ」は1行ではなく、1ノード
普通のデバッガは「1行ずつ」進みます。Fluxa-WebCPは 構文木のノード単位 で止まれます。
a[i] = f(j) + g(k);
この1行の途中 — f(j)を評価し終えて、まだg(k)を呼ぶ前 — で立ち止まり、両方の部分式を独立して覗けます。「式のどこで値が壊れたのか」を、行ではなく式の構造そのもので追えるということです。
2. 未定義動作を、絶対に起こさない
C++最大の地雷は「未定義動作(UB)」です。配列の範囲外アクセス、未初期化変数の読み取り、nullポインタ参照、ゼロ除算 — 本物のコンパイラなら「たまたま動く」か「謎のクラッシュ」になります。学習者にとってこれは最悪です。
Fluxa-WebCPでは、これら全てが 明示的で、回復可能な実行時エラー になります。スタックトレース付きで、「何が・どこで・なぜ」起きたかをはっきり伝えます。
Runtime Error: index 10 out of range for array of size 5
at dfs:23
at main:41
インタプリタ自身は決して例外を投げません。 ユーザープログラムのエラーは「クラッシュ」ではなく「観測可能な状態」として扱われます。
3. 状態は「プロセス」ではなく「データ」
実行中の全状態 — コールスタック、グローバル変数、生きている全配列、入力カーソル — は、ただの JSONシリアライズ可能なプレーンオブジェクト です。
JSON.stringify(session.state); // これがそのまま動く
だから、スナップショットを保存できる。2つの状態を差分できる。Web Workerの向こうに送れる。タイムトラベルデバッグのバックエンドにもできる。状態がデータであることが、応用の自由度をそのまま決めています。
どんな課題を解決するのか
| ありがちな悩み | Fluxa-WebCPの答え |
|---|---|
| 「DPの遷移、どこで間違えた?」 | 配列が埋まる過程を1セルずつ観測 |
| 「再帰が何回呼ばれてる?」 | コールスタックを各フレームごと可視化 |
| 「セグフォの原因が分からない」 | 範囲外アクセスを行番号付きエラーで明示 |
| 「初心者にC++をどう教える?」 | UBで黙って壊れない、安全な学習環境 |
| 「実行状態をUIに繋ぎたい」 | 状態がJSON。差分も永続化も自由 |
競プロ初心者がつまずく「なぜか分からないバグ」のほとんどは、実行の途中が見えないことに原因があります。Fluxa-WebCPは、その「見えなさ」そのものを解決対象にしています。
何ができるのか
サポートする言語機能
競プロで「実際に頻出する表面記法」を、意味論・デバッグ表示・テストまで揃えて再現しています。
- 型 —
int/long long(内部64bit BigInt)、double、bool、char、string、固定長配列、vector<T>、map<K,V>、pair、tuple、ポインタT*、参照T& - 制御構文 —
if/else、for、範囲for(配列・vector・map・string)、while、break/continue - 関数 — 値渡し・参照渡し・ポインタ渡し、再帰、グローバル変数、限定的な関数テンプレート(型推論+明示テンプレート実引数)
- 入出力 —
cin/cout/cerr/endl、fixed/setprecision、競プロ定番のsync_with_stdio系はno-opとして受理 - 標準ライブラリ風 —
sort(greater<>()降順対応)、reverse、fill、abs/max/min/swap、make_pair/make_tuple/get<I>、vectorの各メソッド、mapのm[key]自動挿入
あえて「やらない」こと
中途半端に黙って受理するのではなく、非対応機能はコンパイルエラーとしてはっきり拒否します。
new/deleteなどの動的メモリ、ユーザー定義struct/class、関数ポインタ、static_cast、参照戻り値 — これらが必要なら「本物のコンパイラを使ってください」と明示的に伝えます。
サブセットであることを隠さない。これも設計上の誠実さです。
ひとつのエンジン、4つの顔
同じコアが、用途を変えるだけで全く別のツールになります。
| 使い方 | 何になるか |
|---|---|
run() |
CLIのコードランナー |
stepInto() / breakpoint |
フル機能のステップデバッガ |
| UBを安全なエラー化 | C++初学者向けの教材エンジン |
| 状態の差分・永続化 | タイムトラベルデバッグUIのバックエンド |
import { Compiler } from "fluxa-webcp";
const result = new Compiler().compile(source);
if (result.kind === "error") { /* GCC/Clang形式の診断 */ }
const session = result.session;
session.provideInput("5\n");
// 1ノードずつ進めて、その都度 状態を覗く
while (session.state.status === "paused") {
session.stepInto();
const info = session.debugInfo();
console.log(`line ${info.currentLine}`, info.localVars.at(-1));
}
debugInfo() ひとつで、コールスタック・スコープ階層・全配列・入力カーソル・「今まさに評価中のソース範囲」が一気に取れます。
技術的な裏側
- 言語 — TypeScript(v5)。
any/unknownを原則禁止し、Valueのunion型を明示的にnarrowingする設計 - 依存 — ランタイム依存ゼロ。ESM / CJS 両方のバンドルと
.d.tsを同梱 - アーキテクチャ —
parser→runtime→interpreter→debuggerの一方向依存。循環依存は禁止。1ファイル800行以内を厳守し、肥大化したら「行数ではなく責務」で分割 - エラー診断 — コンパイルエラーは
main.cpp:7:14: error: ...のGCC/Clang形式。実行時エラーはleaf-firstのスタックトレース付き。整形はdiagnostics.tsに一元化 - 標準ライブラリ — evaluatorへの直書きを避け、
stdlib/のメタデータ+ハンドラ方式に集約。テンプレートも「既知名分岐」ではなく一般のtemplate-idとして受理してから解決 - テスト — Vitestで機能領域ごとに分割(
01-basics〜10-pointers-and-references)。新機能は専用テストとセットで着地
安全装置
| 制限 | 既定値 | 挙動 |
|---|---|---|
| 再帰の深さ | 10,000フレーム | グレースフルな実行時エラー |
| 実行ステップ数 | 10,000,000 | UIから調整可、クラッシュさせない |
どちらも「異常終了」ではなく「観測できるエラー」として扱われます。
プレイグラウンド
Next.js製のプレイグラウンドが付属します。Monaco Editor、ガター上のブレークポイント、ライブな変数/コールスタックパネル、ステップ実行コントロール — エンジンの観測能力を、そのままブラウザUIに繋いだものです。
「コードを書く → 止める → 中身が全部見える」を、インストールなしで体験できます。
なぜ作ったか
競プロを学ぶとき、いちばん欲しかったのは「実行の途中を見せてくれる道具」でした。結果だけ返すジャッジでも、最終出力だけ見せるオンラインコンパイラでもなく、自分の書いた配列が、再帰が、いまどうなっているのかを動かしながら見たい。
それを安全に、UBに怯えず、状態をデータとして自由に扱える形で実現したのがFluxa-WebCPです。「C++全部」ではなく「競プロで本当に書く範囲」に絞り切ったからこそ、ここまで深く観測可能にできました。
結果ではなく、過程を。コンパイルではなく、観測を。
MIT License
