Files
hakorune/docs/予定/nyash.link/builtin-stdlib-architecture.md
Moe Charm ef7a0de3b0 feat: Prepare for code modularization and cleanup
- Archive old documentation and test files to `docs/archive/` and `local_tests/`.
- Remove various temporary and old files from the project root.
- Add `nekocode-rust` analysis tool and its output files (`nekocode/`, `.nekocode_sessions/`, `analysis.json`).
- Minor updates to `apps/chip8_nyash/chip8_emulator.nyash` and `local_tests` files.

This commit cleans up the repository and sets the stage for further code modularization efforts, particularly in the `src/interpreter` and `src/parser` modules, based on recent analysis.
2025-08-16 01:30:39 +09:00

15 KiB
Raw Blame History

組み込みnyashstd名前空間アーキテクチャ設計

🏗️ 技術的実装アーキテクチャ

📊 現在のインタープリター構造分析

NyashInterpreter構造

pub struct NyashInterpreter {
    pub(super) shared: SharedState,           // 共有状態
    pub(super) local_vars: HashMap<String, SharedNyashBox>,
    pub(super) outbox_vars: HashMap<String, SharedNyashBox>,
    // その他の制御フロー状態...
}

設計判断SharedStateに組み込み

  • 理由: 標準ライブラリは不変・全インタープリターで共有可能
  • 利点: メモリ効率、パフォーマンス向上
  • 実装: SharedStateにbuiltin_stdlibフィールド追加

🌟 最適化されたアーキテクチャ設計

1. SharedState拡張

src/interpreter/core.rs

#[derive(Clone)]
pub struct SharedState {
    // 既存フィールド...
    pub global_vars: Arc<RwLock<HashMap<String, SharedNyashBox>>>,
    pub functions: Arc<RwLock<HashMap<String, Function>>>,
    pub box_definitions: Arc<RwLock<HashMap<String, Box<UserDefinedBoxDefinition>>>>,
    pub loop_counter: Arc<AtomicU64>,
    pub included_files: Arc<RwLock<HashSet<String>>>,
    
    // 🌟 新規追加: 組み込み標準ライブラリ
    pub builtin_stdlib: Arc<BuiltinStdlib>,
    pub using_imports: Arc<RwLock<HashMap<String, UsingContext>>>, // ファイル別インポート管理
}

#[derive(Debug, Clone)]
pub struct UsingContext {
    pub imported_namespaces: Vec<String>,  // ["nyashstd"] 
    pub file_id: String,                   // インポート元ファイル識別
}

2. BuiltinStdlib効率化設計

新ファイル: src/stdlib/builtin.rs

//! 🚀 高性能組み込み標準ライブラリ
//! 
//! 設計方針:
//! - Zero-allocation関数実行
//! - 高速名前解決
//! - 既存Box実装の最大活用

use crate::boxes::*;
use std::collections::HashMap;

/// 組み込み標準ライブラリのメイン構造体
#[derive(Debug)]
pub struct BuiltinStdlib {
    /// 高速アクセス用:フラットな関数マップ
    /// "string.upper" -> BuiltinFunction
    pub flat_functions: HashMap<String, BuiltinFunction>,
    
    /// IDE補完用階層構造
    /// "nyashstd" -> { "string" -> ["upper", "lower", ...] }
    pub hierarchical_map: HashMap<String, HashMap<String, Vec<String>>>,
}

/// 組み込み関数の実装
pub struct BuiltinFunction {
    pub namespace: &'static str,    // "nyashstd"
    pub box_name: &'static str,     // "string"  
    pub method_name: &'static str,  // "upper"
    pub implementation: BuiltinMethodImpl,
    pub arg_count: Option<usize>,   // None = 可変長
    pub description: &'static str,  // エラーメッセージ・ヘルプ用
}

/// 高性能関数実装
pub type BuiltinMethodImpl = fn(&[Box<dyn NyashBox>]) -> Result<Box<dyn NyashBox>, RuntimeError>;

impl BuiltinStdlib {
    /// 🚀 標準ライブラリ初期化起動時1回のみ
    pub fn new() -> Self {
        let mut stdlib = BuiltinStdlib {
            flat_functions: HashMap::new(),
            hierarchical_map: HashMap::new(),
        };
        
        // 標準関数登録
        stdlib.register_all_functions();
        
        stdlib
    }
    
    /// ⚡ 高速関数解決
    pub fn get_function(&self, qualified_name: &str) -> Option<&BuiltinFunction> {
        // "string.upper" で直接アクセス
        self.flat_functions.get(qualified_name)
    }
    
    /// 🔍 IDE補完用利用可能関数一覧取得
    pub fn get_available_methods(&self, namespace: &str, box_name: &str) -> Option<&Vec<String>> {
        self.hierarchical_map.get(namespace)?.get(box_name)
    }
    
    /// 📋 全名前空間取得IDE補完用
    pub fn get_all_namespaces(&self) -> Vec<&String> {
        self.hierarchical_map.keys().collect()
    }
}

3. 標準関数実装(高性能版)

文字列関数実装

impl BuiltinStdlib {
    fn register_all_functions(&mut self) {
        // === nyashstd.string.* ===
        self.register_function("string.upper", BuiltinFunction {
            namespace: "nyashstd",
            box_name: "string", 
            method_name: "upper",
            implementation: |args| {
                if args.len() != 1 {
                    return Err(RuntimeError::InvalidArguments(
                        "string.upper(str) takes exactly 1 argument".to_string()
                    ));
                }
                
                // 🚀 既存StringBox実装活用
                let input_str = args[0].to_string_box().value;
                let result = StringBox::new(&input_str.to_uppercase());
                Ok(Box::new(result))
            },
            arg_count: Some(1),
            description: "Convert string to uppercase",
        });
        
        self.register_function("string.lower", BuiltinFunction {
            namespace: "nyashstd",
            box_name: "string",
            method_name: "lower", 
            implementation: |args| {
                if args.len() != 1 {
                    return Err(RuntimeError::InvalidArguments(
                        "string.lower(str) takes exactly 1 argument".to_string()
                    ));
                }
                
                let input_str = args[0].to_string_box().value;
                let result = StringBox::new(&input_str.to_lowercase());
                Ok(Box::new(result))
            },
            arg_count: Some(1),
            description: "Convert string to lowercase",
        });
        
        self.register_function("string.split", BuiltinFunction {
            namespace: "nyashstd", 
            box_name: "string",
            method_name: "split",
            implementation: |args| {
                if args.len() != 2 {
                    return Err(RuntimeError::InvalidArguments(
                        "string.split(str, separator) takes exactly 2 arguments".to_string()
                    ));
                }
                
                // 🚀 既存StringBox.split()メソッド活用
                let string_box = StringBox::new(&args[0].to_string_box().value);
                let separator = &args[1].to_string_box().value;
                string_box.split(separator)
            },
            arg_count: Some(2),
            description: "Split string by separator into array",
        });
        
        // === nyashstd.math.* ===
        self.register_function("math.sin", BuiltinFunction {
            namespace: "nyashstd",
            box_name: "math",
            method_name: "sin",
            implementation: |args| {
                if args.len() != 1 {
                    return Err(RuntimeError::InvalidArguments(
                        "math.sin(x) takes exactly 1 argument".to_string()
                    ));
                }
                
                // 🚀 既存MathBox実装活用
                let math_box = MathBox::new();
                let x = args[0].to_integer_box().value as f64;
                let result = math_box.sin(x)?;
                Ok(result)
            },
            arg_count: Some(1),
            description: "Calculate sine of x (in radians)",
        });
        
        // 階層マップも同時構築
        self.build_hierarchical_map();
    }
    
    fn register_function(&mut self, qualified_name: &str, function: BuiltinFunction) {
        self.flat_functions.insert(qualified_name.to_string(), function);
    }
    
    fn build_hierarchical_map(&mut self) {
        for (qualified_name, function) in &self.flat_functions {
            let namespace_map = self.hierarchical_map
                .entry(function.namespace.to_string())
                .or_insert_with(HashMap::new);
                
            let method_list = namespace_map
                .entry(function.box_name.to_string())
                .or_insert_with(Vec::new);
                
            method_list.push(function.method_name.to_string());
        }
        
        // ソートして一貫性確保
        for namespace_map in self.hierarchical_map.values_mut() {
            for method_list in namespace_map.values_mut() {
                method_list.sort();
            }
        }
    }
}

4. インタープリター統合

NyashInterpreter拡張

impl NyashInterpreter {
    /// using文実行
    pub fn execute_using(&mut self, namespace_name: &str) -> Result<(), RuntimeError> {
        // 組み込み名前空間存在チェック
        if !self.shared.builtin_stdlib.hierarchical_map.contains_key(namespace_name) {
            return Err(RuntimeError::UndefinedNamespace(namespace_name.to_string()));
        }
        
        // 現在ファイルのusingコンテキスト更新
        let file_id = self.get_current_file_id();
        let mut using_imports = self.shared.using_imports.write().unwrap();
        
        let context = using_imports.entry(file_id.clone()).or_insert(UsingContext {
            imported_namespaces: Vec::new(),
            file_id: file_id.clone(),
        });
        
        if !context.imported_namespaces.contains(&namespace_name.to_string()) {
            context.imported_namespaces.push(namespace_name.to_string());
        }
        
        Ok(())
    }
    
    /// ⚡ 高速名前解決string.upper() → nyashstd.string.upper()
    pub fn resolve_qualified_call(&self, path: &[String]) -> Option<String> {
        if path.len() != 2 {
            return None; // Phase 0では2段階のみ対応
        }
        
        let box_name = &path[0];
        let method_name = &path[1];
        let file_id = self.get_current_file_id();
        
        // 現在ファイルのusingインポート確認
        if let Ok(using_imports) = self.shared.using_imports.read() {
            if let Some(context) = using_imports.get(&file_id) {
                for namespace in &context.imported_namespaces {
                    let qualified_name = format!("{}.{}", box_name, method_name);
                    
                    // 実際に関数が存在するかチェック
                    if self.shared.builtin_stdlib.get_function(&qualified_name).is_some() {
                        return Some(qualified_name);
                    }
                }
            }
        }
        
        None
    }
    
    /// 🚀 組み込み関数実行
    pub fn call_builtin_function(&self, qualified_name: &str, args: Vec<Box<dyn NyashBox>>) 
        -> Result<Box<dyn NyashBox>, RuntimeError> {
        
        if let Some(function) = self.shared.builtin_stdlib.get_function(qualified_name) {
            // 引数数チェック
            if let Some(expected_count) = function.arg_count {
                if args.len() != expected_count {
                    return Err(RuntimeError::InvalidArguments(
                        format!("{}.{}() takes exactly {} arguments, got {}", 
                            function.box_name, function.method_name, 
                            expected_count, args.len())
                    ));
                }
            }
            
            // 関数実行
            (function.implementation)(&args)
        } else {
            Err(RuntimeError::UndefinedMethod(qualified_name.to_string()))
        }
    }
}

5. 式実行統合

src/interpreter/expressions.rs修正

impl NyashInterpreter {
    pub fn execute_expression(&mut self, node: &ASTNode) -> Result<Box<dyn NyashBox>, RuntimeError> {
        match node {
            // 既存のケース...
            
            // メソッド呼び出し処理修正
            ASTNode::MethodCall { object, method, args, .. } => {
                // オブジェクトが単純な識別子かチェック
                if let ASTNode::Variable { name: box_name, .. } = object.as_ref() {
                    // using経由での短縮呼び出しチェック
                    let path = vec![box_name.clone(), method.clone()];
                    if let Some(qualified_name) = self.resolve_qualified_call(&path) {
                        // 引数評価
                        let evaluated_args = self.evaluate_arguments(args)?;
                        // 組み込み関数実行
                        return self.call_builtin_function(&qualified_name, evaluated_args);
                    }
                }
                
                // 既存のメソッド呼び出し処理
                // ...
            }
            
            // using文実行
            ASTNode::UsingStatement { namespace_name, .. } => {
                self.execute_using(namespace_name)?;
                Ok(Box::new(VoidBox::new()))
            }
            
            // 他の既存ケース...
        }
    }
}

📊 パフォーマンス特性

最適化ポイント

1. Zero-Allocation関数解決

// ❌ 遅い:毎回文字列生成
let qualified = format!("{}.{}", box_name, method_name);

// ✅ 高速:事前計算済みマップ
if let Some(func) = stdlib.flat_functions.get(&qualified_name) { ... }

2. 高速名前解決

// O(1)アクセスHashMap直接ルックアップ
// "string.upper" -> BuiltinFunction

3. 既存Box実装活用

// 既存の最適化済みStringBox.split()を直接使用
string_box.split(separator)  // 新規実装不要

🧪 テストカバレッジ

Phase 0必須テスト

基本機能テスト

# test_builtin_stdlib_basic.nyash
using nyashstd

# 文字列操作
assert(string.upper("hello") == "HELLO")
assert(string.lower("WORLD") == "world") 
assert(string.split("a,b,c", ",").length() == 3)

# 数学関数
assert(math.sin(0) == 0)
assert(math.cos(0) == 1)

# 配列操作
local arr = [1, 2, 3]
assert(array.length(arr) == 3)
assert(array.get(arr, 1) == 2)

エラーハンドリング

# test_builtin_stdlib_errors.nyash
using nyashstd

# 引数数エラー
try {
    string.upper("hello", "extra")  # 2引数でエラー
    assert(false, "Should have thrown error")
} catch e {
    assert(e.contains("takes exactly 1 argument"))
}

# 未定義名前空間
try {
    using nonexistent
    assert(false, "Should have thrown error")
} catch e {
    assert(e.contains("UndefinedNamespace"))
}

IDE補完サポート

// テスト:補完候補取得
let methods = stdlib.get_available_methods("nyashstd", "string");
assert!(methods.unwrap().contains(&"upper".to_string()));
assert!(methods.unwrap().contains(&"lower".to_string()));

🎯 実装順序

🚨 Critical即時実装

  1. BuiltinStdlib基盤 - src/stdlib/builtin.rs作成
  2. SharedState統合 - builtin_stdlibフィールド追加
  3. using文パーサー - ASTNode::UsingStatement

High今週中

  1. string関数4種 - upper, lower, split, join
  2. 基本テスト - using nyashstd動作確認
  3. エラーハンドリング - 適切なエラーメッセージ

📝 Medium来週

  1. math関数5種 - sin, cos, sqrt, floor, random
  2. array関数4種 - length, get, push, slice
  3. io関数3種 - print, println, debug

この高性能アーキテクチャで、複雑なファイル依存関係なしに即座に実用的なnamespace/usingが実現できるにゃ🚀