chore: Phase 25.1 完了 - LoopForm v2/Stage1 CLI/環境変数削減 + Phase 26-D からの変更

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>
This commit is contained in:
nyash-codex
2025-11-21 06:25:17 +09:00
parent baf028a94f
commit f9d100ce01
366 changed files with 14322 additions and 5236 deletions

View File

@ -137,4 +137,4 @@ impl Display for AddBox {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
self.fmt_box(f)
}
}
}

View File

@ -76,4 +76,4 @@ impl CompareBox {
let right_str = right.to_string_box();
BoolBox::new(left_str.value >= right_str.value)
}
}
}

View File

@ -124,4 +124,4 @@ impl Display for DivideBox {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
self.fmt_box(f)
}
}
}

View File

@ -13,19 +13,19 @@
// Individual arithmetic operation implementations
mod add_box;
mod subtract_box;
mod multiply_box;
mod compare_box;
mod divide_box;
mod modulo_box;
mod compare_box;
mod multiply_box;
mod subtract_box;
// Re-export all arithmetic box types
pub use add_box::AddBox;
pub use subtract_box::SubtractBox;
pub use multiply_box::MultiplyBox;
pub use compare_box::CompareBox;
pub use divide_box::DivideBox;
pub use modulo_box::ModuloBox;
pub use compare_box::CompareBox;
pub use multiply_box::MultiplyBox;
pub use subtract_box::SubtractBox;
// Re-export for convenience - common pattern in arithmetic operations
pub use crate::box_trait::{BoolBox, IntegerBox, NyashBox, StringBox};
@ -125,4 +125,4 @@ mod tests {
assert_eq!(CompareBox::greater(&left, &right).value, false);
assert_eq!(CompareBox::equals(&left, &right).value, false);
}
}
}

View File

@ -115,4 +115,4 @@ impl Display for MultiplyBox {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
self.fmt_box(f)
}
}
}

View File

@ -116,4 +116,4 @@ impl Display for SubtractBox {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
self.fmt_box(f)
}
}
}

View File

@ -42,11 +42,11 @@ impl ArrayBox {
None => {
let strict = std::env::var("HAKO_OOB_STRICT")
.ok()
.map(|v| matches!(v.as_str(), "1"|"true"|"on"))
.map(|v| matches!(v.as_str(), "1" | "true" | "on"))
.unwrap_or(false)
|| std::env::var("NYASH_OOB_STRICT")
.ok()
.map(|v| matches!(v.as_str(), "1"|"true"|"on"))
.map(|v| matches!(v.as_str(), "1" | "true" | "on"))
.unwrap_or(false);
if strict {
Box::new(StringBox::new("[array/empty/pop] empty array"))
@ -92,11 +92,11 @@ impl ArrayBox {
None => {
let strict = std::env::var("HAKO_OOB_STRICT")
.ok()
.map(|v| matches!(v.as_str(), "1"|"true"|"on"))
.map(|v| matches!(v.as_str(), "1" | "true" | "on"))
.unwrap_or(false)
|| std::env::var("NYASH_OOB_STRICT")
.ok()
.map(|v| matches!(v.as_str(), "1"|"true"|"on"))
.map(|v| matches!(v.as_str(), "1" | "true" | "on"))
.unwrap_or(false);
if strict {
// Mark OOB occurrence for runner policies (GateC strict fail, etc.)
@ -127,11 +127,11 @@ impl ArrayBox {
} else {
let strict = std::env::var("HAKO_OOB_STRICT")
.ok()
.map(|v| matches!(v.as_str(), "1"|"true"|"on"))
.map(|v| matches!(v.as_str(), "1" | "true" | "on"))
.unwrap_or(false)
|| std::env::var("NYASH_OOB_STRICT")
.ok()
.map(|v| matches!(v.as_str(), "1"|"true"|"on"))
.map(|v| matches!(v.as_str(), "1" | "true" | "on"))
.unwrap_or(false);
if strict {
crate::runtime::observe::mark_oob();

View File

@ -2,7 +2,7 @@
//!
//! Implements the core BoolBox type for true/false values.
use crate::box_trait::{NyashBox, BoxCore, BoxBase, StringBox};
use crate::box_trait::{BoxBase, BoxCore, NyashBox, StringBox};
use std::any::Any;
use std::fmt::{Debug, Display};
@ -83,4 +83,4 @@ impl Display for BoolBox {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
self.fmt_box(f)
}
}
}

View File

@ -2,7 +2,7 @@
//!
//! Implements the ErrorBox type for representing error information.
use crate::box_trait::{NyashBox, BoxCore, BoxBase, StringBox, BoolBox};
use crate::box_trait::{BoolBox, BoxBase, BoxCore, NyashBox, StringBox};
use std::any::Any;
use std::fmt::{Debug, Display};
@ -79,4 +79,4 @@ impl Display for ErrorBox {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
self.fmt_box(f)
}
}
}

View File

@ -9,4 +9,4 @@
)]
// Re-export the new FileBox implementation for backward compatibility
pub use crate::boxes::file::FileBox;
pub use crate::boxes::file::FileBox;

View File

@ -2,7 +2,7 @@
//!
//! Implements the core IntegerBox type for 64-bit signed integers.
use crate::box_trait::{NyashBox, BoxCore, BoxBase, StringBox, BoolBox};
use crate::box_trait::{BoolBox, BoxBase, BoxCore, NyashBox, StringBox};
use std::any::Any;
use std::fmt::{Debug, Display};
@ -79,4 +79,4 @@ impl Display for IntegerBox {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
self.fmt_box(f)
}
}
}

View File

@ -4,17 +4,17 @@
//! fundamental data types in Nyash: String, Integer, Boolean, Void, File, and Error.
// Individual basic box implementations
mod string_box;
mod integer_box;
mod bool_box;
mod void_box;
mod file_box;
mod error_box;
mod file_box;
mod integer_box;
mod string_box;
mod void_box;
// Re-export all basic box types
pub use string_box::StringBox;
pub use integer_box::IntegerBox;
pub use bool_box::BoolBox;
pub use void_box::VoidBox;
pub use error_box::ErrorBox;
pub use file_box::FileBox;
pub use error_box::ErrorBox;
pub use integer_box::IntegerBox;
pub use string_box::StringBox;
pub use void_box::VoidBox;

View File

@ -2,7 +2,7 @@
//!
//! Implements the core StringBox type with all string manipulation methods.
use crate::box_trait::{NyashBox, BoxCore, BoxBase};
use crate::box_trait::{BoxBase, BoxCore, NyashBox};
use crate::boxes::ArrayBox;
use std::any::Any;
use std::fmt::{Debug, Display};

View File

@ -2,7 +2,7 @@
//!
//! Implements the core VoidBox type representing empty or null results.
use crate::box_trait::{NyashBox, BoxCore, BoxBase, StringBox, BoolBox};
use crate::box_trait::{BoolBox, BoxBase, BoxCore, NyashBox, StringBox};
use std::any::Any;
use std::fmt::{Debug, Display};
@ -75,4 +75,4 @@ impl Display for VoidBox {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
self.fmt_box(f)
}
}
}

View File

@ -99,9 +99,9 @@
* - call stackは直近100件まで自動保持
*/
use crate::box_factory::RuntimeError;
use crate::box_trait::{BoolBox, BoxBase, BoxCore, NyashBox, StringBox, VoidBox};
use crate::instance_v2::InstanceBox;
use crate::box_factory::RuntimeError;
use chrono::Local;
use std::any::Any;
use std::collections::HashMap;

View File

@ -33,8 +33,8 @@
* - `run()`はブロッキング動作(アプリ終了まで制御を返さない)
*/
use crate::box_trait::{BoolBox, BoxBase, BoxCore, NyashBox, StringBox};
use crate::box_factory::RuntimeError;
use crate::box_trait::{BoolBox, BoxBase, BoxCore, NyashBox, StringBox};
use eframe::{self, egui, epaint::Vec2};
use std::any::Any;
use std::sync::{Arc, RwLock};

View File

@ -1,8 +1,8 @@
//! Thin FileBox shim that delegates to a selected provider.
//! Not wired into the registry yet (safe placeholder).
use super::provider::{FileCaps, FileIo, FileResult};
use std::sync::Arc;
use super::provider::{FileIo, FileCaps, FileResult};
#[allow(dead_code)]
pub struct FileBoxShim {
@ -16,9 +16,16 @@ impl FileBoxShim {
let caps = provider.caps();
Self { provider, caps }
}
pub fn open(&self, path: &str) -> FileResult<()> { self.provider.open(path) }
pub fn read(&self) -> FileResult<String> { self.provider.read() }
pub fn close(&self) -> FileResult<()> { self.provider.close() }
pub fn caps(&self) -> FileCaps { self.caps }
pub fn open(&self, path: &str) -> FileResult<()> {
self.provider.open(path)
}
pub fn read(&self) -> FileResult<String> {
self.provider.read()
}
pub fn close(&self) -> FileResult<()> {
self.provider.close()
}
pub fn caps(&self) -> FileCaps {
self.caps
}
}

View File

@ -3,10 +3,12 @@
//! Provides ProviderFactory implementation for the builtin FileBox (core-ro).
//! This is auto-registered when feature "builtin-filebox" is enabled.
use std::sync::Arc;
use crate::boxes::file::provider::FileIo;
use crate::boxes::file::core_ro::CoreRoFileIo;
use crate::runner::modes::common_util::provider_registry::{ProviderFactory, register_provider_factory};
use crate::boxes::file::provider::FileIo;
use crate::runner::modes::common_util::provider_registry::{
register_provider_factory, ProviderFactory,
};
use std::sync::Arc;
/// Builtin FileBox factory (static registration)
pub struct BuiltinFileBoxFactory;

View File

@ -3,10 +3,10 @@
// 参考: 既存Boxの設計思想
// SSOT provider design (ring0/1) — modules are currently placeholders
pub mod provider; // trait FileIo / FileCaps / FileError
pub mod core_ro; // Core readonly provider
pub mod box_shim; // Thin delegating shim
pub mod builtin_factory; // Builtin FileBox ProviderFactory
pub mod box_shim; // Thin delegating shim
pub mod builtin_factory;
pub mod core_ro; // Core readonly provider
pub mod provider; // trait FileIo / FileCaps / FileError // Builtin FileBox ProviderFactory
use crate::box_trait::{BoolBox, BoxBase, BoxCore, NyashBox, StringBox};
use crate::runtime::provider_lock;
@ -64,7 +64,8 @@ impl FileBox {
.ok_or("FileBox provider not initialized")?
.clone();
provider.open(path)
provider
.open(path)
.map_err(|e| format!("Failed to open: {}", e))?;
Ok(FileBox {
@ -76,8 +77,7 @@ impl FileBox {
pub fn read_to_string(&self) -> Result<String, String> {
if let Some(ref provider) = self.provider {
provider.read()
.map_err(|e| format!("Read failed: {}", e))
provider.read().map_err(|e| format!("Read failed: {}", e))
} else {
Err("No provider available".to_string())
}
@ -85,7 +85,8 @@ impl FileBox {
pub fn write_all(&self, _buf: &[u8]) -> Result<(), String> {
// Fail-Fast by capability: consult provider caps
let caps = self.provider
let caps = self
.provider
.as_ref()
.map(|p| p.caps())
.or_else(|| provider_lock::get_filebox_caps())
@ -107,15 +108,20 @@ impl FileBox {
/// ファイルに内容を書き込む
pub fn write(&self, _content: Box<dyn NyashBox>) -> Box<dyn NyashBox> {
let caps = self.provider
let caps = self
.provider
.as_ref()
.map(|p| p.caps())
.or_else(|| provider_lock::get_filebox_caps())
.unwrap_or_else(|| provider::FileCaps::read_only());
if !caps.write {
return Box::new(StringBox::new("Error: write unsupported by provider (read-only)"));
return Box::new(StringBox::new(
"Error: write unsupported by provider (read-only)",
));
}
Box::new(StringBox::new("Error: write supported but not implemented in this build"))
Box::new(StringBox::new(
"Error: write supported but not implemented in this build",
))
}
/// ファイルが存在するかチェック
@ -126,28 +132,38 @@ impl FileBox {
/// ファイルを削除
pub fn delete(&self) -> Box<dyn NyashBox> {
let caps = self.provider
let caps = self
.provider
.as_ref()
.map(|p| p.caps())
.or_else(|| provider_lock::get_filebox_caps())
.unwrap_or_else(|| provider::FileCaps::read_only());
if !caps.write {
return Box::new(StringBox::new("Error: delete unsupported by provider (read-only)"));
return Box::new(StringBox::new(
"Error: delete unsupported by provider (read-only)",
));
}
Box::new(StringBox::new("Error: delete supported but not implemented in this build"))
Box::new(StringBox::new(
"Error: delete supported but not implemented in this build",
))
}
/// ファイルをコピー
pub fn copy(&self, _dest: &str) -> Box<dyn NyashBox> {
let caps = self.provider
let caps = self
.provider
.as_ref()
.map(|p| p.caps())
.or_else(|| provider_lock::get_filebox_caps())
.unwrap_or_else(|| provider::FileCaps::read_only());
if !caps.write {
return Box::new(StringBox::new("Error: copy unsupported by provider (read-only)"));
return Box::new(StringBox::new(
"Error: copy unsupported by provider (read-only)",
));
}
Box::new(StringBox::new("Error: copy supported but not implemented in this build"))
Box::new(StringBox::new(
"Error: copy supported but not implemented in this build",
))
}
}

View File

@ -12,7 +12,12 @@ pub struct FileCaps {
}
impl FileCaps {
pub const fn read_only() -> Self { Self { read: true, write: false } }
pub const fn read_only() -> Self {
Self {
read: true,
write: false,
}
}
}
/// Unified error type (thin placeholder for now)
@ -40,9 +45,10 @@ pub trait FileIo: Send + Sync {
pub fn normalize_newlines(s: &str) -> String {
let mut out = String::with_capacity(s.len());
for b in s.as_bytes() {
if *b == b'\r' { continue; }
if *b == b'\r' {
continue;
}
out.push(*b as char);
}
out
}

View File

@ -279,7 +279,11 @@ impl HTTPResponseBox {
}
/// ステータスコード・メッセージ設定
pub fn set_status(&self, code: Box<dyn NyashBox>, message: Box<dyn NyashBox>) -> Box<dyn NyashBox> {
pub fn set_status(
&self,
code: Box<dyn NyashBox>,
message: Box<dyn NyashBox>,
) -> Box<dyn NyashBox> {
let code_val = code.to_string_box().value.parse::<i32>().unwrap_or(200);
let message_val = message.to_string_box().value;
*self.status_code.lock().unwrap() = code_val;
@ -288,7 +292,11 @@ impl HTTPResponseBox {
}
/// ヘッダー設定
pub fn set_header(&self, name: Box<dyn NyashBox>, value: Box<dyn NyashBox>) -> Box<dyn NyashBox> {
pub fn set_header(
&self,
name: Box<dyn NyashBox>,
value: Box<dyn NyashBox>,
) -> Box<dyn NyashBox> {
let name_str = name.to_string_box().value;
let value_str = value.to_string_box().value;
self.headers.lock().unwrap().insert(name_str, value_str);
@ -326,7 +334,10 @@ impl HTTPResponseBox {
let version = self.http_version.lock().unwrap().clone();
let status_code = *self.status_code.lock().unwrap();
let status_message = self.status_message.lock().unwrap().clone();
response.push_str(&format!("{} {} {}\r\n", version, status_code, status_message));
response.push_str(&format!(
"{} {} {}\r\n",
version, status_code, status_message
));
// Headers
for (name, value) in self.headers.lock().unwrap().iter() {
@ -335,7 +346,8 @@ impl HTTPResponseBox {
// Content-Length if not already set
let body_len = { self.body.lock().unwrap().len() };
let need_len = { !self.headers.lock().unwrap().contains_key("content-length") && body_len > 0 };
let need_len =
{ !self.headers.lock().unwrap().contains_key("content-length") && body_len > 0 };
if need_len {
response.push_str(&format!("Content-Length: {}\r\n", body_len));
}
@ -367,10 +379,11 @@ impl HTTPResponseBox {
let response = HTTPResponseBox::new();
*response.status_code.lock().unwrap() = 200;
*response.status_message.lock().unwrap() = "OK".to_string();
response.headers.lock().unwrap().insert(
"Content-Type".to_string(),
"application/json".to_string(),
);
response
.headers
.lock()
.unwrap()
.insert("Content-Type".to_string(), "application/json".to_string());
*response.body.lock().unwrap() = content.to_string_box().value;
response
}
@ -384,7 +397,8 @@ impl HTTPResponseBox {
"Content-Type".to_string(),
"text/html; charset=utf-8".to_string(),
);
*response.body.lock().unwrap() = "<html><body><h1>404 - Not Found</h1></body></html>".to_string();
*response.body.lock().unwrap() =
"<html><body><h1>404 - Not Found</h1></body></html>".to_string();
response
}
}

View File

@ -161,7 +161,10 @@ impl MapBox {
}
value.clone_box()
}
None => Box::new(StringBox::new(&format!("[map/missing] Key not found: {}", key_str))),
None => Box::new(StringBox::new(&format!(
"[map/missing] Key not found: {}",
key_str
))),
}
}
@ -202,7 +205,10 @@ impl MapBox {
.unwrap()
.values()
.map(|v| {
if v.as_any().downcast_ref::<crate::instance_v2::InstanceBox>().is_some() {
if v.as_any()
.downcast_ref::<crate::instance_v2::InstanceBox>()
.is_some()
{
v.share_box()
} else {
v.clone_box()

View File

@ -16,28 +16,48 @@ pub struct MissingBox {
impl MissingBox {
pub fn new() -> Self {
Self { base: BoxBase::new() }
Self {
base: BoxBase::new(),
}
}
pub fn is_missing(&self) -> bool { true }
pub fn is_missing(&self) -> bool {
true
}
}
impl BoxCore for MissingBox {
fn box_id(&self) -> u64 { self.base.id }
fn parent_type_id(&self) -> Option<std::any::TypeId> { self.base.parent_type_id }
fn box_id(&self) -> u64 {
self.base.id
}
fn parent_type_id(&self) -> Option<std::any::TypeId> {
self.base.parent_type_id
}
fn fmt_box(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
// 開発時の可視性向上のための文字列表現。prod では基本的に表面化させない想定。
write!(f, "(missing)")
}
fn as_any(&self) -> &dyn Any { self }
fn as_any_mut(&mut self) -> &mut dyn Any { self }
fn as_any(&self) -> &dyn Any {
self
}
fn as_any_mut(&mut self) -> &mut dyn Any {
self
}
}
impl NyashBox for MissingBox {
fn type_name(&self) -> &'static str { "MissingBox" }
fn to_string_box(&self) -> StringBox { StringBox::new("(missing)") }
fn clone_box(&self) -> Box<dyn NyashBox> { Box::new(self.clone()) }
fn share_box(&self) -> Box<dyn NyashBox> { self.clone_box() }
fn type_name(&self) -> &'static str {
"MissingBox"
}
fn to_string_box(&self) -> StringBox {
StringBox::new("(missing)")
}
fn clone_box(&self) -> Box<dyn NyashBox> {
Box::new(self.clone())
}
fn share_box(&self) -> Box<dyn NyashBox> {
self.clone_box()
}
fn equals(&self, other: &dyn NyashBox) -> BoolBox {
// 欠損どうしは論理同値とみなすが、通常の等価比較は境界で禁止される想定。
BoolBox::new(other.as_any().downcast_ref::<MissingBox>().is_some())
@ -45,6 +65,7 @@ impl NyashBox for MissingBox {
}
impl Display for MissingBox {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { self.fmt_box(f) }
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
self.fmt_box(f)
}
}

View File

@ -145,8 +145,8 @@ pub use egui_box::EguiBox;
#[cfg(target_arch = "wasm32")]
pub use web::{WebCanvasBox, WebConsoleBox, WebDisplayBox};
pub mod null_box;
pub mod missing_box;
pub mod null_box;
// High-priority Box types
pub mod array;
@ -168,8 +168,8 @@ pub mod intent_box;
pub mod p2p_box;
// null関数も再エクスポート
pub use null_box::{null, NullBox};
pub use missing_box::MissingBox;
pub use null_box::{null, NullBox};
// High-priority Box types re-export
pub use array::ArrayBox;