## LLVM Call Instruction Modularization - Moved MirInstruction::Call lowering to separate instructions/call.rs - Follows the principle of one MIR instruction per file - Call implementation was already complete, just needed modularization ## Phase 21 Documentation - Moved all Phase 21 content to private/papers/paper-f-self-parsing-db/ - Preserved AI evaluations from Gemini and Codex - Academic paper potential confirmed by both AIs - Self-parsing AST database approach validated ## Next Steps - Continue monitoring ChatGPT5's LLVM improvements - Consider creating separate nyash-llvm-compiler crate when LLVM layer is stable - This will reduce build times by isolating LLVM dependencies 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
7.1 KiB
7.1 KiB
Phase 21: Nyash自己解析アプローチ - AST直接保存
📋 概要
Nyashの最大の強み「自分自身をパースできる」を活かした究極にシンプルなアプローチ。 外部パーサー不要、複雑な変換層不要。NyashのASTをそのままデータベースに保存する。
🎯 核心的なアイデア
// Nyashは自分自身を解析できる!
NyashParser.parse(sourceCode) → AST → Database → NyashPrinter.print(AST) → sourceCode
重要な気づき:
- Nyashにはすでにパーサーがある
- ASTから元のソースを生成する機能もある
- だから、ASTをDBに保存すれば完全可逆!
🏗️ シンプルな実装
データベース構造
-- ASTノードをそのまま保存
CREATE TABLE ast_nodes (
id INTEGER PRIMARY KEY,
node_type TEXT, -- "Box", "Method", "Field", "Statement"等
node_data JSON, -- ASTノードの完全な情報
parent_id INTEGER,
position INTEGER, -- 親ノード内での位置
source_file TEXT, -- 元のファイルパス
metadata JSON, -- 後から追加する解析情報
FOREIGN KEY (parent_id) REFERENCES ast_nodes(id)
);
-- インデックス
CREATE INDEX idx_node_type ON ast_nodes(node_type);
CREATE INDEX idx_parent ON ast_nodes(parent_id);
CREATE INDEX idx_source ON ast_nodes(source_file);
基本実装
box NyashCodeDB {
parser: NyashParser
printer: NyashPrinter
db: SQLiteBox
birth() {
me.parser = new NyashParser()
me.printer = new NyashPrinter()
me.db = new SQLiteBox("code.db")
}
// ファイルをDBに保存
importFile(filePath) {
local source = FileBox.read(filePath)
local ast = me.parser.parse(source)
// ASTを再帰的にDBに保存
me.saveAST(ast, null, filePath)
}
// ASTノードを保存
saveAST(node, parentId, sourceFile) {
local nodeId = me.db.insert("ast_nodes", {
node_type: node.type,
node_data: node.toJSON(),
parent_id: parentId,
position: node.position,
source_file: sourceFile
})
// 子ノードも保存
for (i, child) in node.children.enumerate() {
child.position = i
me.saveAST(child, nodeId, sourceFile)
}
return nodeId
}
// DBからソースコードを復元
exportFile(filePath) {
local rootNodes = me.db.query(
"SELECT * FROM ast_nodes
WHERE source_file = ? AND parent_id IS NULL
ORDER BY position",
filePath
)
local source = ""
for node in rootNodes {
local ast = me.loadAST(node.id)
source += me.printer.print(ast) + "\n"
}
FileBox.write(filePath, source)
}
// ASTを再構築
loadAST(nodeId) {
local node = me.db.get("ast_nodes", nodeId)
local astNode = ASTNode.fromJSON(node.node_data)
// 子ノードも読み込む
local children = me.db.query(
"SELECT * FROM ast_nodes
WHERE parent_id = ?
ORDER BY position",
nodeId
)
for child in children {
astNode.addChild(me.loadAST(child.id))
}
return astNode
}
}
🚀 高度な機能
リファクタリング
box ASTRefactorer {
db: SQLiteBox
// 名前変更
renameBox(oldName, newName) {
// Box定義を見つける
local boxNodes = me.db.query(
"SELECT * FROM ast_nodes
WHERE node_type = 'Box'
AND json_extract(node_data, '$.name') = ?",
oldName
)
for node in boxNodes {
// AST上で名前を変更
local data = JSON.parse(node.node_data)
data.name = newName
me.db.update("ast_nodes", node.id, {
node_data: JSON.stringify(data)
})
}
// 使用箇所も更新
me.updateReferences(oldName, newName)
}
// メソッド移動
moveMethod(methodName, fromBox, toBox) {
// SQLで親ノードを変更するだけ!
local fromBoxId = me.findBoxNode(fromBox)
local toBoxId = me.findBoxNode(toBox)
me.db.execute(
"UPDATE ast_nodes
SET parent_id = ?
WHERE parent_id = ?
AND node_type = 'Method'
AND json_extract(node_data, '$.name') = ?",
[toBoxId, fromBoxId, methodName]
)
}
}
メタデータ解析(オンデマンド)
box MetadataEngine {
// 必要な時だけ解析
analyzeOnDemand(nodeId) {
local node = db.get("ast_nodes", nodeId)
if not node.metadata or me.isOutdated(node.metadata) {
local metadata = {
dependencies: me.findDependencies(node),
complexity: me.calculateComplexity(node),
lastAnalyzed: now()
}
db.update("ast_nodes", nodeId, {
metadata: JSON.stringify(metadata)
})
}
return JSON.parse(node.metadata)
}
// 依存関係を動的に検出
findDependencies(node) {
local deps = []
// "new XXXBox" パターンを検索
local matches = me.searchPattern(node, "NewBox")
for match in matches {
deps.push(match.boxType)
}
// "from XXX" パターンを検索
local inherits = me.searchPattern(node, "From")
for inherit in inherits {
deps.push(inherit.parentBox)
}
return deps
}
}
📊 利点
1. 実装の簡単さ
- パーサーはすでにある(Nyash自身)
- プリンターもすでにある
- 複雑な変換層不要
2. 100%の正確性
- Nyash公式パーサーを使うから完璧
- ASTは言語の完全な表現
- 情報の欠落なし
3. 柔軟性
- メタデータは後から追加
- 部分的な解析が可能
- 増分更新が簡単
4. 高速性
- ASTの一部だけ読み込み可能
- SQLの力でクエリが高速
- キャッシュも自然に実装
🎯 実装ステップ
Phase 1: 基本機能(1週間)
- AST保存・読み込み
- ファイル単位のインポート・エクスポート
- 基本的なクエリ
Phase 2: リファクタリング(1週間)
- 名前変更
- メソッド移動
- 依存関係追跡
Phase 3: 高度な機能(2週間)
- メタデータ解析
- インクリメンタル更新
- VSCode統合
🌟 まとめ
「Nyashの能力をフル活用する」
- 外部ツール不要
- 複雑な実装不要
- Nyashらしいシンプルさ
このアプローチなら、Phase 21は「NyashのASTをDBに入れるだけ」という 極めてシンプルな実装で、強力な機能を実現できる!
「なぜ複雑にする?Nyashにはすでに必要なものが全部ある」 - にゃ