feat(repl): Phase 288.1 session persistence + auto-display
実装内容: - AST Rewriter (~430行): 未宣言変数を __repl.get/set に変換 - ExternCall Bridge: VM で __repl.get/set ハンドラー実装 - Rc<RefCell<>> セッション共有: VM と REPL runner 間で永続化 - 式自動表示: pure expression の結果を自動出力 - _ 変数: 最後の表示値を保存(Void は除外) - .reset 実装: セッション変数の完全クリア - Fail-Fast: 未定義変数読み取りで明示的エラー + ヒント 変更ファイル (8ファイル, +592行): - src/runner/repl/ast_rewriter.rs (NEW, +430行) - src/runner/repl/repl_runner.rs (+84/-35行) - src/backend/mir_interpreter/handlers/externals.rs (+54行) - src/mir/builder/calls/build.rs (+41行) - src/backend/mir_interpreter/mod.rs (+12行) - src/runner/repl/repl_session.rs (+11/-9行) - src/runner/repl/mod.rs (+2行) - src/runner/mod.rs (+2/-1行) REPL専用設計(src/mir/builder/calls/build.rs の特別扱い理由): - __repl.get/set は REPL mode 専用の橋渡し機能 - try_build_repl_method_call() で早期検出・ExternCall 変換 - file mode では決して使用されない(VM で "outside REPL mode" エラー) - 将来的にも file mode への影響ゼロを保証 検証済み: - 変数永続化: x = 42; print(x) → 42 ✅ - 式自動表示: 1 + 1 → 2 ✅ - _ 変数: 10 * 2 → 20; _ → 20 ✅ - Fail-Fast: 未定義エラー + ヒント ✅ - 回帰テスト: 154/154 PASS ✅ 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
@ -117,6 +117,11 @@ impl MirBuilder {
|
||||
return Ok(result);
|
||||
}
|
||||
|
||||
// Phase 288.1: REPL session variable bridge: __repl.get/set → ExternCall
|
||||
if let Some(result) = self.try_build_repl_method_call(&object, &method, &arguments)? {
|
||||
return Ok(result);
|
||||
}
|
||||
|
||||
// 1. Static box method call: BoxName.method(args)
|
||||
if let Some(result) = self.try_build_static_receiver_method_call(&object, &method, &arguments)? {
|
||||
return Ok(result);
|
||||
@ -181,6 +186,42 @@ impl MirBuilder {
|
||||
self.try_build_mir_debug_call(method, arguments)
|
||||
}
|
||||
|
||||
/// Phase 288.1: REPL session variable bridge
|
||||
/// Transform __repl.get/set → ExternCall("__repl", "get/set", args)
|
||||
fn try_build_repl_method_call(
|
||||
&mut self,
|
||||
object: &ASTNode,
|
||||
method: &str,
|
||||
arguments: &[ASTNode],
|
||||
) -> Result<Option<ValueId>, String> {
|
||||
let ASTNode::Variable { name: obj_name, .. } = object else {
|
||||
return Ok(None);
|
||||
};
|
||||
if obj_name != "__repl" {
|
||||
return Ok(None);
|
||||
}
|
||||
|
||||
// Only handle get/set methods
|
||||
if method != "get" && method != "set" {
|
||||
return Err(format!("__repl.{} is not supported. Only __repl.get and __repl.set are allowed.", method));
|
||||
}
|
||||
|
||||
// Build argument values
|
||||
let arg_values = self.build_call_args(arguments)?;
|
||||
|
||||
// Emit ExternCall instruction
|
||||
let dst = self.next_value_id();
|
||||
self.emit_instruction(MirInstruction::ExternCall {
|
||||
dst: Some(dst),
|
||||
iface_name: "__repl".to_string(),
|
||||
method_name: method.to_string(),
|
||||
args: arg_values,
|
||||
effects: EffectMask::PURE, // get/set are pure from MIR perspective
|
||||
})?;
|
||||
|
||||
Ok(Some(dst))
|
||||
}
|
||||
|
||||
fn try_build_static_receiver_method_call(
|
||||
&mut self,
|
||||
object: &ASTNode,
|
||||
|
||||
Reference in New Issue
Block a user