Phase 25.1 完了成果: - ✅ LoopForm v2 テスト・ドキュメント・コメント完備 - 4ケース(A/B/C/D)完全テストカバレッジ - 最小再現ケース作成(SSAバグ調査用) - SSOT文書作成(loopform_ssot.md) - 全ソースに [LoopForm] コメントタグ追加 - ✅ Stage-1 CLI デバッグ環境構築 - stage1_cli.hako 実装 - stage1_bridge.rs ブリッジ実装 - デバッグツール作成(stage1_debug.sh/stage1_minimal.sh) - アーキテクチャ改善提案文書 - ✅ 環境変数削減計画策定 - 25変数の完全調査・分類 - 6段階削減ロードマップ(25→5、80%削減) - 即時削除可能変数特定(NYASH_CONFIG/NYASH_DEBUG) Phase 26-D からの累積変更: - PHI実装改善(ExitPhiBuilder/HeaderPhiBuilder等) - MIRビルダーリファクタリング - 型伝播・最適化パス改善 - その他約300ファイルの累積変更 🎯 技術的成果: - SSAバグ根本原因特定(条件分岐内loop変数変更) - Region+next_iパターン適用完了(UsingCollectorBox等) - LoopFormパターン文書化・テスト化完了 - セルフホスティング基盤強化 Co-Authored-By: Claude <noreply@anthropic.com> Co-Authored-By: ChatGPT <noreply@openai.com> Co-Authored-By: Task Assistant <task@anthropic.com>
178 lines
4.9 KiB
Rust
178 lines
4.9 KiB
Rust
/*!
|
|
* External Call Handling
|
|
*
|
|
* Manages env.* methods and external interface calls
|
|
* Provides bridge to host environment functionality
|
|
*/
|
|
|
|
use crate::mir::{Effect, EffectMask};
|
|
|
|
/// Table-like spec for env.* methods
|
|
/// Returns (iface_name, method_name, effects, returns_value)
|
|
pub fn get_env_method_spec(
|
|
iface: &str,
|
|
method: &str,
|
|
) -> Option<(String, String, EffectMask, bool)> {
|
|
match (iface, method) {
|
|
// Future/async operations
|
|
("future", "delay") => Some((
|
|
"env.future".to_string(),
|
|
"delay".to_string(),
|
|
EffectMask::READ.add(Effect::Io),
|
|
true,
|
|
)),
|
|
("future", "spawn") => Some((
|
|
"env.future".to_string(),
|
|
"spawn".to_string(),
|
|
EffectMask::IO,
|
|
true,
|
|
)),
|
|
|
|
// Task management
|
|
("task", "currentToken") => Some((
|
|
"env.task".to_string(),
|
|
"currentToken".to_string(),
|
|
EffectMask::READ,
|
|
true,
|
|
)),
|
|
("task", "cancelCurrent") => Some((
|
|
"env.task".to_string(),
|
|
"cancelCurrent".to_string(),
|
|
EffectMask::IO,
|
|
false,
|
|
)),
|
|
|
|
// Console I/O
|
|
("console", "log") => Some((
|
|
"env.console".to_string(),
|
|
"log".to_string(),
|
|
EffectMask::IO,
|
|
false,
|
|
)),
|
|
("console", "readLine") => Some((
|
|
"env.console".to_string(),
|
|
"readLine".to_string(),
|
|
EffectMask::IO,
|
|
true,
|
|
)),
|
|
("console", "error") => Some((
|
|
"env.console".to_string(),
|
|
"error".to_string(),
|
|
EffectMask::IO,
|
|
false,
|
|
)),
|
|
|
|
// Canvas operations
|
|
("canvas", m) if matches!(m, "fillRect" | "fillText" | "clear") => Some((
|
|
"env.canvas".to_string(),
|
|
method.to_string(),
|
|
EffectMask::IO,
|
|
false,
|
|
)),
|
|
|
|
// File system
|
|
("fs", "readFile") => Some((
|
|
"env.fs".to_string(),
|
|
"readFile".to_string(),
|
|
EffectMask::IO,
|
|
true,
|
|
)),
|
|
("fs", "writeFile") => Some((
|
|
"env.fs".to_string(),
|
|
"writeFile".to_string(),
|
|
EffectMask::IO,
|
|
false,
|
|
)),
|
|
("fs", "exists") => Some((
|
|
"env.fs".to_string(),
|
|
"exists".to_string(),
|
|
EffectMask::READ,
|
|
true,
|
|
)),
|
|
|
|
// Network
|
|
("net", "fetch") => Some((
|
|
"env.net".to_string(),
|
|
"fetch".to_string(),
|
|
EffectMask::IO,
|
|
true,
|
|
)),
|
|
("net", "listen") => Some((
|
|
"env.net".to_string(),
|
|
"listen".to_string(),
|
|
EffectMask::IO,
|
|
true,
|
|
)),
|
|
|
|
// Process/system
|
|
("process", "exit") => Some((
|
|
"env.process".to_string(),
|
|
"exit".to_string(),
|
|
EffectMask::IO.add(Effect::Control),
|
|
false,
|
|
)),
|
|
("process", "argv") => Some((
|
|
"env.process".to_string(),
|
|
"argv".to_string(),
|
|
EffectMask::READ,
|
|
true,
|
|
)),
|
|
("process", "env") => Some((
|
|
"env.process".to_string(),
|
|
"env".to_string(),
|
|
EffectMask::READ,
|
|
true,
|
|
)),
|
|
|
|
// Direct env access
|
|
("env", "get") => Some(("env".to_string(), "get".to_string(), EffectMask::READ, true)),
|
|
("env", "set") => Some(("env".to_string(), "set".to_string(), EffectMask::IO, false)),
|
|
|
|
// Unknown
|
|
_ => None,
|
|
}
|
|
}
|
|
|
|
/// Parse external call name into interface and method
|
|
/// E.g., "nyash.builtin.print" -> ("nyash.builtin", "print")
|
|
pub fn parse_extern_name(name: &str) -> (String, String) {
|
|
let parts: Vec<&str> = name.rsplitn(2, '.').collect();
|
|
if parts.len() == 2 {
|
|
(parts[1].to_string(), parts[0].to_string())
|
|
} else {
|
|
("nyash".to_string(), name.to_string())
|
|
}
|
|
}
|
|
|
|
/// Check if a name refers to an environment interface
|
|
#[allow(dead_code)]
|
|
pub fn is_env_interface(name: &str) -> bool {
|
|
matches!(
|
|
name,
|
|
"env"
|
|
| "env.console"
|
|
| "env.fs"
|
|
| "env.net"
|
|
| "env.canvas"
|
|
| "env.task"
|
|
| "env.future"
|
|
| "env.process"
|
|
)
|
|
}
|
|
|
|
/// Determine effects for an external call
|
|
pub fn compute_extern_effects(iface: &str, method: &str) -> EffectMask {
|
|
match (iface, method) {
|
|
// Pure reads
|
|
(_, m) if m.starts_with("get") || m == "argv" || m == "env" => EffectMask::READ,
|
|
// Control flow changes
|
|
(_, "exit") | (_, "panic") | (_, "throw") => EffectMask::IO.add(Effect::Control),
|
|
// Memory allocation
|
|
(_, m) if m.starts_with("new") || m.starts_with("create") => {
|
|
EffectMask::IO.add(Effect::Alloc)
|
|
}
|
|
// Default to I/O
|
|
_ => EffectMask::IO,
|
|
}
|
|
}
|