# nyash.linkシステム実装計画 ## 🎯 実装戦略 ### 📊 現状確認 - ✅ **include**: 限定的使用(text_adventure例のみ)→廃止OK - ✅ **using**: 未実装→完全新規作成 - ✅ **namespace**: 設計完了→実装のみ - ✅ **Gemini推奨**: 技術的妥当性確認済み ## 📋 段階的実装ロードマップ ### 🚀 **Phase 1: 基盤構築(1-2週間)** #### 1.1 トークナイザー拡張 ```rust // src/tokenizer.rs pub enum TokenType { // 既存... USING, // using キーワード NAMESPACE, // namespace キーワード AS, // as キーワード(将来のエイリアス用) } // キーワード認識追加 fn tokenize_identifier(input: &str) -> TokenType { match input { // 既存... "using" => TokenType::USING, "namespace" => TokenType::NAMESPACE, "as" => TokenType::AS, _ => TokenType::IDENTIFIER(input.to_string()), } } ``` #### 1.2 AST拡張 ```rust // src/ast.rs pub enum ASTNode { // 既存... UsingStatement { module_path: Vec, // ["nyashstd"] or ["mylib"] alias: Option, // using mylib as lib span: Span, }, NamespaceDeclaration { name: String, body: Vec, span: Span, }, QualifiedCall { path: Vec, // ["nyashstd", "string", "upper"] args: Vec, span: Span, }, } ``` #### 1.3 パーサー基本実装 ```rust // src/parser/statements.rs impl NyashParser { pub fn parse_using(&mut self) -> Result { self.advance(); // consume 'using' let module_path = self.parse_module_path()?; // using mylib → ["mylib"] // using nyashstd.string → ["nyashstd", "string"] Ok(ASTNode::UsingStatement { module_path, alias: None, // Phase 1では未サポート span: self.current_span(), }) } fn parse_module_path(&mut self) -> Result, ParseError> { let mut path = vec![]; // 最初の識別子 if let TokenType::IDENTIFIER(name) = &self.current_token().token_type { path.push(name.clone()); self.advance(); } else { return Err(ParseError::ExpectedIdentifier); } // ドット区切りで追加パス(将来拡張) // using nyashstd.string のような構文 Ok(path) } } ``` ### ⚡ **Phase 2: nyash.link基盤(2-3週間)** #### 2.1 nyash.linkパーサー ```rust // 新ファイル: src/link_file.rs use serde::{Deserialize, Serialize}; use std::collections::HashMap; #[derive(Debug, Deserialize, Serialize)] pub struct NyashLink { pub project: Option, pub dependencies: HashMap, pub search_paths: Option>, pub build: Option, } #[derive(Debug, Deserialize, Serialize)] pub struct ProjectInfo { pub name: String, pub version: String, pub description: Option, } #[derive(Debug, Deserialize, Serialize)] #[serde(untagged)] pub enum Dependency { Path { path: String }, Stdlib { stdlib: bool }, Registry { version: String, registry: String }, } #[derive(Debug, Deserialize, Serialize)] pub struct BuildConfig { pub entry_point: Option, } impl NyashLink { pub fn from_file(path: &Path) -> Result { let content = std::fs::read_to_string(path)?; let link: NyashLink = toml::from_str(&content)?; Ok(link) } pub fn resolve_dependency(&self, name: &str) -> Option { if let Some(dep) = self.dependencies.get(name) { match dep { Dependency::Path { path } => Some(PathBuf::from(path)), Dependency::Stdlib { .. } => { // 標準ライブラリパス解決ロジック self.resolve_stdlib_path(name) } _ => None, // Phase 2では未サポート } } else { None } } } ``` #### 2.2 依存関係解決エンジン ```rust // 新ファイル: src/module_resolver.rs pub struct ModuleResolver { nyash_link: NyashLink, loaded_modules: HashMap>, loading_stack: Vec, // 循環依存検出用 } impl ModuleResolver { pub fn new(link_path: &Path) -> Result { let nyash_link = NyashLink::from_file(link_path)?; Ok(ModuleResolver { nyash_link, loaded_modules: HashMap::new(), loading_stack: Vec::new(), }) } pub fn resolve_using(&mut self, module_name: &str) -> Result, ResolverError> { // 既にロード済みかチェック if let Some(module) = self.loaded_modules.get(module_name) { return Ok(module.clone()); } // 循環依存チェック if self.loading_stack.contains(&module_name.to_string()) { return Err(ResolverError::CircularDependency( self.loading_stack.clone() )); } // ファイルパス解決 let file_path = self.hako_link.resolve_dependency(module_name) .ok_or(ResolverError::ModuleNotFound(module_name.to_string()))?; // 再帰的読み込み防止 self.loading_stack.push(module_name.to_string()); // ファイル読み込み・パース let content = std::fs::read_to_string(&file_path)?; let ast = NyashParser::parse_from_string(&content)?; // モジュール作成 let module = Arc::new(ParsedModule { name: module_name.to_string(), file_path, ast, exports: self.extract_exports(&ast)?, }); // キャッシュに保存 self.loaded_modules.insert(module_name.to_string(), module.clone()); self.loading_stack.pop(); Ok(module) } } ``` ### 📈 **Phase 3: 名前空間システム(3-4週間)** #### 3.1 namespace解析 ```rust impl NyashParser { pub fn parse_namespace(&mut self) -> Result { self.advance(); // consume 'namespace' let name = self.expect_identifier()?; self.expect_token(TokenType::LBRACE)?; let mut body = vec![]; while !self.check_token(&TokenType::RBRACE) { body.push(self.parse_statement()?); } self.expect_token(TokenType::RBRACE)?; Ok(ASTNode::NamespaceDeclaration { name, body, span: self.current_span(), }) } } ``` #### 3.2 名前空間レジストリ ```rust // 新ファイル: src/namespace_registry.rs pub struct NamespaceRegistry { namespaces: HashMap, using_imports: HashMap>, // ファイル別インポート } pub struct Namespace { pub name: String, pub static_boxes: HashMap, } pub struct StaticBox { pub name: String, pub static_methods: HashMap, } impl NamespaceRegistry { pub fn register_namespace(&mut self, name: String, namespace: Namespace) { self.namespaces.insert(name, namespace); } pub fn add_using_import(&mut self, file_id: String, namespace_name: String) { self.using_imports .entry(file_id) .or_insert_with(Vec::new) .push(namespace_name); } pub fn resolve_call(&self, file_id: &str, path: &[String]) -> Option { // 例: string.upper() → nyashstd.string.upper() if path.len() == 2 { let box_name = &path[0]; let method_name = &path[1]; // usingでインポートされた名前空間を検索 if let Some(imports) = self.using_imports.get(file_id) { for namespace_name in imports { if let Some(namespace) = self.namespaces.get(namespace_name) { if let Some(static_box) = namespace.static_boxes.get(box_name) { if let Some(method) = static_box.static_methods.get(method_name) { return Some(method.clone()); } } } } } } None } } ``` ### 🎯 **Phase 4: インタープリター統合(4-5週間)** #### 4.1 using文実行 ```rust // src/interpreter/core.rs impl NyashInterpreter { pub fn execute_using(&mut self, module_path: &[String]) -> Result<(), RuntimeError> { let module_name = module_path.join("."); // モジュール解決・読み込み let module = self.module_resolver.resolve_using(&module_name)?; // 名前空間登録 if let Some(namespace) = self.extract_namespace_from_module(&module) { self.namespace_registry.register_namespace(module_name.clone(), namespace); self.namespace_registry.add_using_import( self.current_file_id.clone(), module_name ); } Ok(()) } fn extract_namespace_from_module(&self, module: &ParsedModule) -> Option { // ASTからnamespace宣言を探して解析 for node in &module.ast { if let ASTNode::NamespaceDeclaration { name, body, .. } = node { return Some(self.build_namespace_from_body(name, body)); } } None } } ``` #### 4.2 qualified call実行 ```rust impl NyashInterpreter { pub fn execute_qualified_call(&mut self, path: &[String], args: &[ASTNode]) -> Result, RuntimeError> { // 名前解決 if let Some(method_sig) = self.namespace_registry.resolve_call( &self.current_file_id, path ) { // 引数評価 let evaluated_args = self.evaluate_args(args)?; // メソッド実行(既存のBox呼び出しシステム活用) return self.call_static_method(&method_sig, evaluated_args); } // 完全修飾名として試行 if path.len() >= 3 { // nyashstd.string.upper() の場合 let namespace_name = &path[0]; let box_name = &path[1]; let method_name = &path[2]; if let Some(namespace) = self.namespace_registry.namespaces.get(namespace_name) { if let Some(static_box) = namespace.static_boxes.get(box_name) { if let Some(method) = static_box.static_methods.get(method_name) { let evaluated_args = self.evaluate_args(args)?; return self.call_static_method(method, evaluated_args); } } } } Err(RuntimeError::UndefinedMethod(path.join("."))) } } ``` ## 🧪 テスト戦略 ### Phase 1テスト ```nyash # test_basic_using.hako # 基本using文テスト # ファイル: mylib.hako static function hello() { return "Hello from mylib!" } # ファイル: main.hako using mylib local result = mylib.hello() assert(result == "Hello from mylib!") ``` ### Phase 2テスト ```nyash # test_nyash_link.hako # nyash.linkファイル連携テスト # nyash.link内容: # [dependencies] # mylib = { path = "./mylib.hako" } using mylib local result = mylib.process("data") assert(result == "processed: data") ``` ### Phase 3テスト ```nyash # test_namespace.hako # 名前空間システムテスト # nyashstd.hako: # namespace nyashstd { # static box string { # static upper(str) { ... } # } # } using nyashstd local result = string.upper("hello") assert(result == "HELLO") # 完全修飾名 local result2 = nyashstd.string.upper("world") assert(result2 == "WORLD") ``` ## 📊 実装マイルストーン ### ✅ 完了条件 #### Phase 1 - [ ] USING/NAMESPACE トークン認識 - [ ] using文AST構築 - [ ] 基本パーサーテスト通過 #### Phase 2 - [ ] nyash.linkファイル読み込み - [ ] 依存関係解決 - [ ] モジュールキャッシュ機能 #### Phase 3 - [ ] namespace宣言解析 - [ ] 名前空間レジストリ動作 - [ ] 静的メソッド解決 #### Phase 4 - [ ] インタープリター統合 - [ ] qualified call実行 - [ ] 全テストケース通過 ## 🔮 将来拡張 ### Phase 5: 高度機能 - エイリアス(`using mylib as lib`) - 選択インポート(`using nyashstd.string`) - 動的モジュール読み込み ### Phase 6: 標準ライブラリ - nyashstd.hako完全実装 - string/math/io/http モジュール - ドキュメント生成 ### Phase 7: エコシステム - パッケージレジストリ設計 - CLI ツール(nyash init/install) - IDE Language Server連携 --- **🎯 この実装計画でnyash.linkシステムを段階的に完成させるにゃ!**