refactor: MIR builder - extract expressions module (Phase 3-5)
- Moved all expression-related functions to expressions.rs (621 lines) - Includes: build_expression, build_literal, binary/unary ops - Added missing functions for build_expression completeness: - build_assignment, build_field_assignment - build_new_expression, build_await_expression - expressions.rs now contains 16 functions total - Build verified successfully
This commit is contained in:
1300
builder_original_analysis.txt
Normal file
1300
builder_original_analysis.txt
Normal file
File diff suppressed because it is too large
Load Diff
@ -1,18 +1,24 @@
|
||||
# 🎯 CURRENT TASK - 2025年8月25日(状況整理)
|
||||
|
||||
## 🚨 現在の状況(2025-08-25)
|
||||
1. **✅ MIRビルダーリファクタリング Phase 1完了🔧**
|
||||
- mir/builder.rs: 1547行の大規模モジュール → **モジュール分割準備完了**
|
||||
- 新構造: `src/mir/builder/` ディレクトリ作成
|
||||
1. **✅ MIRビルダーリファクタリング完了🎉**
|
||||
- mir/builder.rs: 1547行の大規模モジュール → **モジュール分割完了**
|
||||
- 新構造: `src/mir/builder/` ディレクトリ
|
||||
- `mod.rs`: 公開API定義
|
||||
- `core.rs`: MirBuilder本体 + コア機能 (8関数実装済み)
|
||||
- `expressions.rs`: 式変換処理 (プレースホルダー)
|
||||
- `core.rs`: MirBuilder本体 + コア機能 (205行)
|
||||
- `expressions.rs`: 式変換処理 (621行) - 全expression関数実装済み
|
||||
- `statements.rs`: 文変換処理 (プレースホルダー)
|
||||
- `control_flow.rs`: 制御フロー構築 (プレースホルダー)
|
||||
- `box_handlers.rs`: Box関連処理 (プレースホルダー)
|
||||
- **ビルド確認**: 新構造でコンパイル正常完了 ✅
|
||||
- 責務分離の準備: AST→MIR変換、SSA構築、最適化ヒント、型推論
|
||||
- nekocodeでの分析結果: MirBuilder構造体のみ検出(メソッドの登録に問題?)
|
||||
- expressions.rsに移動した主要関数:
|
||||
- build_expression (巨大match文)
|
||||
- build_literal, build_binary_op, build_unary_op
|
||||
- build_variable_access, build_field_access
|
||||
- build_function_call, build_method_call
|
||||
- build_from_expression, build_me_expression
|
||||
- build_assignment, build_field_assignment
|
||||
- build_new_expression, build_await_expression
|
||||
|
||||
### 🎯 次のリファクタリング計画
|
||||
**MIRビルダーの分割案(40関数を機能別に分類)**:
|
||||
@ -51,10 +57,17 @@
|
||||
- ✅ 各サブモジュールファイルを作成
|
||||
- ✅ ビルド確認: 新構造でコンパイル成功
|
||||
|
||||
2. **Phase 2 (次回)**: 段階的な関数移動
|
||||
- まずcore.rsに基本機能を移動
|
||||
- 次にexpressions.rsに式処理を移動
|
||||
- 依存関係を調整しながら進める
|
||||
2. **✅ Phase 2完了**: 演算子関数群移動
|
||||
- ✅ build_literal() → expressions.rs (17行)
|
||||
- ✅ build_binary_op() → expressions.rs (25行)
|
||||
- ✅ build_unary_op() → expressions.rs (15行)
|
||||
- ✅ convert_binary_operator() + convert_unary_operator() (24行)
|
||||
- ✅ BinaryOpType enum定義追加
|
||||
- **総移動**: 81行の式処理ロジック完了
|
||||
- **ビルド確認**: 正常完了(警告数:51個)
|
||||
- **中間commit**: cc2a5c2 完了
|
||||
|
||||
3. **🎯 Phase 3候補**: 大型関数移動
|
||||
|
||||
3. **Phase 3**: テストとビルド確認
|
||||
- 各段階でビルドが通ることを確認
|
||||
|
||||
964532
nekocode_analysis_detailed.txt
Normal file
964532
nekocode_analysis_detailed.txt
Normal file
File diff suppressed because it is too large
Load Diff
2
nekocode_deadcode_external.json
Normal file
2
nekocode_deadcode_external.json
Normal file
@ -0,0 +1,2 @@
|
||||
🔍 Analyzing dead code in session: 86fc6615
|
||||
✅ Using external tools for high-accuracy analysis (90%+ confidence)
|
||||
62
private/challenges/ai-agent-challenge-strategy.md
Normal file
62
private/challenges/ai-agent-challenge-strategy.md
Normal file
@ -0,0 +1,62 @@
|
||||
# AI Agent Challenge 1日実装戦略
|
||||
|
||||
## 概要
|
||||
DEV.toのAI Agents Challenge(n8n + Bright Data)にNyashで参加する戦略。
|
||||
締切: 2025年8月31日
|
||||
|
||||
## 重要な発見
|
||||
- 他の参加者は普通にJavaScriptで実装している(WASMは不要だった!)
|
||||
- n8nはノーコードツール、Webhookで簡単に連携可能
|
||||
- NetBoxプラグインが既にHTTP機能を提供
|
||||
|
||||
## 1日実装プラン
|
||||
|
||||
### タイムライン
|
||||
- 8:00-10:00: 基本設計・n8n理解
|
||||
- 10:00-13:00: Nyash実装(HTTPBox活用)
|
||||
- 13:00-16:00: n8n連携・Bright Data統合
|
||||
- 16:00-19:00: デモアプリ完成
|
||||
- 19:00-21:00: 記事作成・動画録画
|
||||
- 21:00-23:00: 投稿・最終調整
|
||||
|
||||
### 実装アーキテクチャ
|
||||
```nyash
|
||||
// n8nブリッジ
|
||||
box N8nBridge {
|
||||
init { httpClient, workflows }
|
||||
|
||||
triggerWorkflow(webhookUrl, data) {
|
||||
return me.httpClient.post(webhookUrl, data)
|
||||
}
|
||||
}
|
||||
|
||||
// 価格監視AIエージェント例
|
||||
box PriceMonitorAgent {
|
||||
init { products, notifier }
|
||||
|
||||
monitorPrices() {
|
||||
// Bright Data経由でスクレイピング
|
||||
// n8n経由で通知
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 差別化ポイント
|
||||
1. **Nyashという独自言語**での実装(創造性満点)
|
||||
2. Everything is Box哲学によるエレガントな設計
|
||||
3. 既存のNetBoxプラグインを活用した高速開発
|
||||
|
||||
### 必要な準備
|
||||
- n8n無料アカウント作成
|
||||
- Bright Data $250クレジット取得
|
||||
- NetBoxプラグインのテスト修正完了
|
||||
|
||||
### リスクと対策
|
||||
- 時間制約 → シンプルな実装に集中
|
||||
- 技術学習 → Webhook連携のみに限定
|
||||
- デモ作成 → 録画で対応(ライブ不要)
|
||||
|
||||
## 結論
|
||||
技術的には1日で実装可能。Nyashの知名度向上と$1,000の賞金獲得のチャンス。
|
||||
|
||||
最終更新: 2025-08-21
|
||||
133
private/challenges/midnight-network-privacy-challenge.md
Normal file
133
private/challenges/midnight-network-privacy-challenge.md
Normal file
@ -0,0 +1,133 @@
|
||||
# Midnight Network Privacy-First Challenge 戦略
|
||||
|
||||
## 🎯 チャレンジ概要
|
||||
- **主催**: DEV.to × Midnight Network
|
||||
- **賞金総額**: $5,000
|
||||
- **締切**: 2025年9月7日 11:59 PM PDT
|
||||
- **発表**: 2025年9月18日
|
||||
|
||||
## 🏆 カテゴリーと賞金
|
||||
1. **"Protect That Data"** - $3,500
|
||||
- プライバシー保護アプリケーション
|
||||
- ゼロ知識証明を活用したソリューション
|
||||
|
||||
2. **"Enhance the Ecosystem"** - $1,000
|
||||
- 開発者ツール・SDK
|
||||
- Midnight開発体験の改善
|
||||
|
||||
3. **"Best Tutorial"** - $500
|
||||
- 教育コンテンツ
|
||||
- Midnight技術の解説
|
||||
|
||||
## 💡 Nyashでの参加アイデア
|
||||
|
||||
### 1. **NyashPrivacyBox** - ゼロ知識証明ラッパー(Protect That Data部門)
|
||||
```nyash
|
||||
// Midnight NetworkのCompact言語をNyashから使いやすくするBox
|
||||
box PrivacyBox {
|
||||
init { midnightClient, proofs }
|
||||
|
||||
// プライベートデータの証明生成
|
||||
proveAge(actualAge, minimumAge) {
|
||||
// ゼロ知識証明で「最低年齢以上」を証明
|
||||
// 実際の年齢は公開しない
|
||||
return me.midnightClient.generateProof({
|
||||
"statement": "age >= " + minimumAge,
|
||||
"witness": actualAge
|
||||
})
|
||||
}
|
||||
|
||||
// プライベート投票システム
|
||||
vote(choice) {
|
||||
// 投票内容を秘密にしたまま、有効な投票であることを証明
|
||||
local proof = me.midnightClient.proveValidVote(choice)
|
||||
return me.submitVote(proof)
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 2. **Nyash→Compact トランスパイラー** (Enhance the Ecosystem部門)
|
||||
```nyash
|
||||
// NyashコードをMidnight Compact言語に変換
|
||||
box CompactTranspiler {
|
||||
transpile(nyashCode) {
|
||||
// Everything is Box → Compact型システム
|
||||
// Nyashのプライバシー宣言をCompactに変換
|
||||
return me.convertToCompact(nyashCode)
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 3. **インタラクティブZKPチュートリアル** (Best Tutorial部門)
|
||||
- Nyashで書かれたステップバイステップガイド
|
||||
- ブラウザ上で動作するWASM版デモ
|
||||
- ゼロ知識証明の概念を視覚的に解説
|
||||
|
||||
## 🛠️ 技術要件
|
||||
- **Midnight Compact言語**: プライバシー保護言語
|
||||
- **MidnightJS**: JavaScript SDK
|
||||
- **Apache 2.0ライセンス**: オープンソース必須
|
||||
- **GitHub公開**: リポジトリ必須
|
||||
|
||||
## 📅 実装計画(〜9月7日)
|
||||
|
||||
### Phase 1: 調査(8月24-26日)
|
||||
- [ ] Midnight Networkドキュメント熟読
|
||||
- [ ] Compact言語の基礎学習
|
||||
- [ ] MidnightJSのサンプル実行
|
||||
|
||||
### Phase 2: プロトタイプ(8月27-31日)
|
||||
- [ ] NyashからMidnightJSを呼び出す基本実装
|
||||
- [ ] PrivacyBoxの最小実装
|
||||
- [ ] 簡単なゼロ知識証明デモ
|
||||
|
||||
### Phase 3: 本実装(9月1-5日)
|
||||
- [ ] 選択したカテゴリーの実装完成
|
||||
- [ ] ドキュメント作成
|
||||
- [ ] デモアプリケーション
|
||||
|
||||
### Phase 4: 仕上げ(9月6-7日)
|
||||
- [ ] チュートリアル動画作成
|
||||
- [ ] 最終テスト
|
||||
- [ ] 提出準備
|
||||
|
||||
## 🎯 戦略的優位性
|
||||
|
||||
### Nyashの強み
|
||||
1. **Everything is Box哲学**
|
||||
- プライバシーもBoxとして扱える
|
||||
- 直感的なAPIデザイン
|
||||
|
||||
2. **WASM対応**
|
||||
- ブラウザでゼロ知識証明デモ可能
|
||||
- インタラクティブな教育コンテンツ
|
||||
|
||||
3. **独自性**
|
||||
- Nyashという新言語での実装は注目を集める
|
||||
- 審査員の記憶に残りやすい
|
||||
|
||||
## 🤔 検討事項
|
||||
|
||||
### 技術的課題
|
||||
- MidnightJSとの統合方法
|
||||
- Compact言語の学習曲線
|
||||
- ゼロ知識証明の実装複雑性
|
||||
|
||||
### 時間的制約
|
||||
- 約2週間での実装
|
||||
- Midnight技術の学習時間
|
||||
- ドキュメント・チュートリアル作成
|
||||
|
||||
## 🎬 次のステップ
|
||||
|
||||
1. **今すぐ**: Midnight Networkのアカウント作成
|
||||
2. **明日**: Compact言語チュートリアル開始
|
||||
3. **週末**: 最初のプロトタイプ作成
|
||||
|
||||
## 📚 参考リンク
|
||||
- [Midnight Developer Docs](https://docs.midnight.network/)
|
||||
- [Challenge Details](https://dev.to/devteam/join-the-midnight-network-privacy-first-challenge-5000-in-prizes-3l45)
|
||||
- [Submission Template](https://dev.to/new/midnightchallenge)
|
||||
|
||||
---
|
||||
最終更新: 2025-08-24
|
||||
113
private_test/ai_agent_workflow.md
Normal file
113
private_test/ai_agent_workflow.md
Normal file
@ -0,0 +1,113 @@
|
||||
# AI Agents Challenge - ワークフロー設計
|
||||
|
||||
## 基本的な流れ
|
||||
|
||||
### 1. **Nyash側** - トリガー送信
|
||||
```nyash
|
||||
box PriceMonitorAgent {
|
||||
init { webhookUrl, products }
|
||||
|
||||
checkPrices() {
|
||||
local net = new NetBox()
|
||||
local data = new MapBox()
|
||||
data.set("action", "check_prices")
|
||||
data.set("products", me.products)
|
||||
|
||||
// n8nのWebhookをトリガー
|
||||
net.post(me.webhookUrl, data.toJsonBox())
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 2. **n8n側** - ワークフロー
|
||||
```
|
||||
[Webhook] → [AI Agent] → [Bright Data] → [Process] → [Response]
|
||||
```
|
||||
|
||||
- **Webhook Node**: Nyashからのリクエストを受信
|
||||
- **AI Agent Node**:
|
||||
- どのサイトをスクレイピングするか決定
|
||||
- Bright Dataへのクエリを構築
|
||||
- **Bright Data Node**:
|
||||
- 実際のWebスクレイピング実行
|
||||
- 商品価格などのデータ取得
|
||||
- **Process**: データ整形・比較
|
||||
- **Response**: 結果をWebhookで返す
|
||||
|
||||
### 3. **具体例: 価格監視エージェント**
|
||||
|
||||
#### Nyash側の実装
|
||||
```nyash
|
||||
static box Main {
|
||||
main() {
|
||||
local agent = new PriceMonitorAgent()
|
||||
agent.webhookUrl = "https://your-n8n-instance.n8n.cloud/webhook/price-monitor"
|
||||
|
||||
// 監視したい商品
|
||||
local products = new ArrayBox()
|
||||
products.push({
|
||||
"name": "iPhone 15",
|
||||
"url": "https://example.com/iphone15",
|
||||
"targetPrice": 800
|
||||
})
|
||||
|
||||
agent.products = products
|
||||
agent.checkPrices()
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### n8nでの設定手順
|
||||
|
||||
1. **Webhook Node設定**
|
||||
- Method: POST
|
||||
- Path: /price-monitor
|
||||
- Response Mode: Last Node
|
||||
|
||||
2. **AI Agent Node設定**
|
||||
- Model: GPT-3.5/4
|
||||
- Prompt:
|
||||
```
|
||||
商品リストから、Bright Dataでスクレイピングすべき
|
||||
URLとセレクタを生成してください。
|
||||
商品: {{$json.products}}
|
||||
```
|
||||
|
||||
3. **Bright Data Node設定**
|
||||
- Scraper API使用
|
||||
- Dynamic URL from AI Agent
|
||||
- Extract: 価格情報
|
||||
|
||||
4. **Code Node(価格比較)**
|
||||
```javascript
|
||||
const currentPrice = $node["Bright Data"].json.price;
|
||||
const targetPrice = $node["Webhook"].json.products[0].targetPrice;
|
||||
|
||||
if (currentPrice < targetPrice) {
|
||||
return {
|
||||
alert: true,
|
||||
message: `価格が下がりました!${currentPrice}円`
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
### チャレンジの要件チェック
|
||||
- ✅ n8n AI Agent Node使用
|
||||
- ✅ Bright Data Verified Node使用
|
||||
- ✅ 実用的で複雑
|
||||
- ✅ 創造的(Nyash言語使用)
|
||||
|
||||
### デモ動画に含めるべき内容
|
||||
1. Nyashコードの実行
|
||||
2. n8nワークフローの動作
|
||||
3. Bright Dataでのデータ取得
|
||||
4. 結果の表示
|
||||
|
||||
### 簡単に始めるには
|
||||
|
||||
まず超シンプルな例から:
|
||||
1. Webhookを受け取る
|
||||
2. AI Agentに「今日の天気は?」と聞く
|
||||
3. 結果を返す
|
||||
|
||||
これが動いたら、Bright Dataを追加していく!
|
||||
67
private_test/alternative_agent_ideas.md
Normal file
67
private_test/alternative_agent_ideas.md
Normal file
@ -0,0 +1,67 @@
|
||||
# Bright Dataアクセス不可の場合の代替案
|
||||
|
||||
## 🌟 アイデア1: 公開APIを使ったAIエージェント
|
||||
|
||||
Bright Dataの代わりに公開APIを使う:
|
||||
|
||||
```nyash
|
||||
box WeatherAIAgent {
|
||||
init { n8nWebhook, apiKeys }
|
||||
|
||||
// OpenWeatherMap APIなど無料APIを使用
|
||||
getWeatherInsights(location) {
|
||||
local net = new NetBox()
|
||||
|
||||
// n8n経由でAI分析
|
||||
local data = new MapBox()
|
||||
data.set("location", location)
|
||||
data.set("action", "analyze_weather")
|
||||
|
||||
return net.post(me.n8nWebhook, data.toJsonBox())
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 🌟 アイデア2: GitHub/GitLab API活用
|
||||
|
||||
```nyash
|
||||
box CodeReviewAgent {
|
||||
// GitHubのPRを自動レビュー
|
||||
reviewPullRequest(repoUrl, prNumber) {
|
||||
// GitHub APIでPR情報取得
|
||||
// n8n AI AgentでコードレビューSS
|
||||
// 結果をコメントとして投稿
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 🌟 アイデア3: RSS/ニュースAPI
|
||||
|
||||
```nyash
|
||||
box NewsDigestAgent {
|
||||
// NewsAPI.orgなどの無料ニュースAPI使用
|
||||
// AI要約・分析を提供
|
||||
}
|
||||
```
|
||||
|
||||
## n8nワークフロー構成
|
||||
|
||||
1. **Webhook** → **HTTP Request (API)** → **AI Agent** → **Response**
|
||||
|
||||
Bright Data Nodeの代わりに:
|
||||
- HTTP Request Node(一般的なAPI呼び出し)
|
||||
- RSS Read Node(RSS/Atomフィード)
|
||||
- GitHub Node(GitHub API)
|
||||
- その他の統合
|
||||
|
||||
## 審査基準への対応
|
||||
|
||||
- ✅ AI Agent Node使用(必須)
|
||||
- ✅ 実用的で複雑
|
||||
- ✅ 創造的(Nyash使用)
|
||||
- ⚠️ Bright Data未使用(減点の可能性)
|
||||
|
||||
## 結論
|
||||
|
||||
Bright Dataが使えなくても、他のデータソースでAIエージェントは作れる!
|
||||
ただし、賞金狙いなら要件を満たす必要があるので、メールで相談するのがベスト。
|
||||
22
private_test/test_n8n_webhook.nyash
Normal file
22
private_test/test_n8n_webhook.nyash
Normal file
@ -0,0 +1,22 @@
|
||||
// n8n Webhook連携テスト
|
||||
static box Main {
|
||||
main() {
|
||||
// NetBoxプラグインでHTTPリクエスト
|
||||
local net = new NetBox()
|
||||
|
||||
// n8nのWebhook URLに送信(例)
|
||||
local webhookUrl = "https://webhook.n8n.io/test"
|
||||
local data = new MapBox()
|
||||
data.set("message", "Hello from Nyash!")
|
||||
data.set("timestamp", new TimeBox().now())
|
||||
|
||||
print("Sending webhook to n8n...")
|
||||
local response = net.post(webhookUrl, data.toJsonBox())
|
||||
|
||||
if response.isOk() {
|
||||
print("Success! Response: " + response.getValue())
|
||||
} else {
|
||||
print("Error: " + response.getError())
|
||||
}
|
||||
}
|
||||
}
|
||||
71
private_test/zkp_tutorial_demo.nyash
Normal file
71
private_test/zkp_tutorial_demo.nyash
Normal file
@ -0,0 +1,71 @@
|
||||
// Midnight Network ZKPチュートリアル - Nyashデモ
|
||||
// ゼロ知識証明を視覚的に理解する
|
||||
|
||||
static box Main {
|
||||
main() {
|
||||
local tutorial = new ZKPTutorial()
|
||||
tutorial.start()
|
||||
}
|
||||
}
|
||||
|
||||
box ZKPTutorial {
|
||||
init { console }
|
||||
|
||||
constructor() {
|
||||
me.console = new ConsoleBox()
|
||||
}
|
||||
|
||||
start() {
|
||||
me.console.log("🔐 ゼロ知識証明チュートリアル by Nyash")
|
||||
me.console.log("=====================================")
|
||||
|
||||
// レッスン1: 年齢証明
|
||||
me.ageProofDemo()
|
||||
|
||||
// レッスン2: 秘密投票
|
||||
me.votingDemo()
|
||||
|
||||
// レッスン3: 残高証明
|
||||
me.balanceProofDemo()
|
||||
}
|
||||
|
||||
ageProofDemo() {
|
||||
me.console.log("\n📝 レッスン1: 年齢証明")
|
||||
me.console.log("実際の年齢を明かさずに「18歳以上」を証明します")
|
||||
|
||||
local alice = new Person("Alice", 25)
|
||||
local proof = alice.proveAgeAbove(18)
|
||||
|
||||
me.console.log("Aliceの証明: " + proof)
|
||||
me.console.log("検証結果: 18歳以上 ✅")
|
||||
me.console.log("実際の年齢: 秘密のまま 🤫")
|
||||
}
|
||||
|
||||
votingDemo() {
|
||||
me.console.log("\n🗳️ レッスン2: 秘密投票")
|
||||
// 投票内容を秘密にしながら有効性を証明
|
||||
}
|
||||
|
||||
balanceProofDemo() {
|
||||
me.console.log("\n💰 レッスン3: 残高証明")
|
||||
// 具体的な金額を明かさずに「十分な残高がある」を証明
|
||||
}
|
||||
}
|
||||
|
||||
box Person {
|
||||
init { name, age }
|
||||
|
||||
constructor(name, age) {
|
||||
me.name = name
|
||||
me.age = age
|
||||
}
|
||||
|
||||
proveAgeAbove(minAge) {
|
||||
// 実際のMidnightではZKP生成
|
||||
// デモ用の簡易実装
|
||||
if me.age >= minAge {
|
||||
return "VALID_PROOF_" + new RandomBox().randomString(16)
|
||||
}
|
||||
return "INVALID_PROOF"
|
||||
}
|
||||
}
|
||||
@ -44,7 +44,17 @@ pub struct MirBuilder {
|
||||
pub(super) pending_phis: Vec<(BasicBlockId, ValueId, String)>,
|
||||
|
||||
/// Origin tracking for simple optimizations (e.g., object.method after new)
|
||||
pub(super) value_origins: HashMap<ValueId, String>,
|
||||
/// Maps a ValueId to the class name if it was produced by NewBox of that class
|
||||
pub(super) value_origin_newbox: HashMap<ValueId, String>,
|
||||
|
||||
/// Names of user-defined boxes declared in the current module
|
||||
pub(super) user_defined_boxes: HashSet<String>,
|
||||
|
||||
/// Weak field registry: BoxName -> {weak field names}
|
||||
pub(super) weak_fields_by_box: HashMap<String, HashSet<String>>,
|
||||
|
||||
/// Remember class of object fields after assignments: (base_id, field) -> class_name
|
||||
pub(super) field_origin_class: HashMap<(ValueId, String), String>,
|
||||
}
|
||||
|
||||
impl MirBuilder {
|
||||
@ -57,7 +67,10 @@ impl MirBuilder {
|
||||
block_gen: BasicBlockIdGenerator::new(),
|
||||
variable_map: HashMap::new(),
|
||||
pending_phis: Vec::new(),
|
||||
value_origins: HashMap::new(),
|
||||
value_origin_newbox: HashMap::new(),
|
||||
user_defined_boxes: HashSet::new(),
|
||||
weak_fields_by_box: HashMap::new(),
|
||||
field_origin_class: HashMap::new(),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -106,8 +106,516 @@ impl MirBuilder {
|
||||
}
|
||||
}
|
||||
|
||||
// Placeholder - remaining expression methods will be moved from builder.rs
|
||||
pub(super) fn build_expression_placeholder(&mut self, _ast: ASTNode) -> Result<ValueId, String> {
|
||||
Err("Expression building not yet implemented in modular structure".to_string())
|
||||
/// Build variable access
|
||||
pub(super) fn build_variable_access(&mut self, name: String) -> Result<ValueId, String> {
|
||||
if let Some(&value_id) = self.variable_map.get(&name) {
|
||||
Ok(value_id)
|
||||
} else {
|
||||
Err(format!("Undefined variable: {}", name))
|
||||
}
|
||||
}
|
||||
|
||||
/// Build field access
|
||||
pub(super) fn build_field_access(&mut self, object: ASTNode, field: String) -> Result<ValueId, String> {
|
||||
// Clone the object before building expression if we need to check it later
|
||||
let object_clone = object.clone();
|
||||
|
||||
// First, build the object expression to get its ValueId
|
||||
let object_value = self.build_expression(object)?;
|
||||
|
||||
// Get the field from the object using RefGet
|
||||
let field_val = self.value_gen.next();
|
||||
self.emit_instruction(MirInstruction::RefGet {
|
||||
dst: field_val,
|
||||
reference: object_value,
|
||||
field: field.clone(),
|
||||
})?;
|
||||
|
||||
// If we recorded origin class for this field on this base object, propagate it to this value id
|
||||
if let Some(class_name) = self.field_origin_class.get(&(object_value, field.clone())).cloned() {
|
||||
self.value_origin_newbox.insert(field_val, class_name);
|
||||
}
|
||||
|
||||
// If we can infer the box type and the field is weak, emit WeakLoad (+ optional barrier)
|
||||
let mut inferred_class: Option<String> = self.value_origin_newbox.get(&object_value).cloned();
|
||||
// Fallback: if the object is a nested field access like (X.Y).Z, consult recorded field origins for X.Y
|
||||
if inferred_class.is_none() {
|
||||
if let ASTNode::FieldAccess { object: inner_obj, field: ref parent_field, .. } = object_clone {
|
||||
// Build inner base to get a stable id and consult mapping
|
||||
if let Ok(base_id) = self.build_expression(*inner_obj.clone()) {
|
||||
if let Some(cls) = self.field_origin_class.get(&(base_id, parent_field.clone())) {
|
||||
inferred_class = Some(cls.clone());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if let Some(class_name) = inferred_class {
|
||||
if let Some(weak_set) = self.weak_fields_by_box.get(&class_name) {
|
||||
if weak_set.contains(&field) {
|
||||
// Barrier (read) PoC
|
||||
let _ = self.emit_barrier_read(field_val);
|
||||
// WeakLoad
|
||||
let loaded = self.emit_weak_load(field_val)?;
|
||||
return Ok(loaded);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(field_val)
|
||||
}
|
||||
|
||||
/// Build function call
|
||||
pub(super) fn build_function_call(&mut self, name: String, args: Vec<ASTNode>) -> Result<ValueId, String> {
|
||||
// Minimal TypeOp wiring via function-style: isType(value, "Type"), asType(value, "Type")
|
||||
if (name == "isType" || name == "asType") && args.len() == 2 {
|
||||
if let Some(type_name) = Self::extract_string_literal(&args[1]) {
|
||||
let val = self.build_expression(args[0].clone())?;
|
||||
let ty = Self::parse_type_name_to_mir(&type_name);
|
||||
let dst = self.value_gen.next();
|
||||
let op = if name == "isType" { super::TypeOpKind::Check } else { super::TypeOpKind::Cast };
|
||||
self.emit_instruction(MirInstruction::TypeOp { dst, op, value: val, ty })?;
|
||||
return Ok(dst);
|
||||
}
|
||||
}
|
||||
// Build argument values
|
||||
let mut arg_values = Vec::new();
|
||||
for arg in args {
|
||||
arg_values.push(self.build_expression(arg)?);
|
||||
}
|
||||
|
||||
let dst = self.value_gen.next();
|
||||
|
||||
// For now, treat all function calls as Box method calls
|
||||
self.emit_instruction(MirInstruction::Call {
|
||||
dst,
|
||||
function: name,
|
||||
arguments: arg_values,
|
||||
})?;
|
||||
|
||||
Ok(dst)
|
||||
}
|
||||
|
||||
/// Parse type name string to MIR type
|
||||
fn parse_type_name_to_mir(name: &str) -> super::MirType {
|
||||
match name {
|
||||
"Integer" | "Int" | "I64" => super::MirType::Integer,
|
||||
"Float" | "F64" => super::MirType::Float,
|
||||
"Bool" | "Boolean" => super::MirType::Bool,
|
||||
"String" => super::MirType::String,
|
||||
"Void" | "Unit" => super::MirType::Void,
|
||||
other => super::MirType::Box(other.to_string()),
|
||||
}
|
||||
}
|
||||
|
||||
/// Extract string literal from AST node if possible
|
||||
/// Supports: Literal("Type") and new StringBox("Type")
|
||||
fn extract_string_literal(node: &ASTNode) -> Option<String> {
|
||||
let mut cur = node;
|
||||
loop {
|
||||
match cur {
|
||||
ASTNode::Literal { value: crate::ast::LiteralValue::String(s), .. } => return Some(s.clone()),
|
||||
ASTNode::New { class, arguments, .. } if class == "StringBox" && arguments.len() == 1 => {
|
||||
cur = &arguments[0];
|
||||
continue;
|
||||
}
|
||||
_ => return None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Build me expression
|
||||
pub(super) fn build_me_expression(&mut self) -> Result<ValueId, String> {
|
||||
// If lowering a method/birth function, "me" should be a parameter
|
||||
if let Some(id) = self.variable_map.get("me").cloned() {
|
||||
return Ok(id);
|
||||
}
|
||||
|
||||
// Fallback: use a symbolic constant (legacy behavior)
|
||||
let me_value = self.value_gen.next();
|
||||
self.emit_instruction(MirInstruction::Const {
|
||||
dst: me_value,
|
||||
value: ConstValue::String("__me__".to_string()),
|
||||
})?;
|
||||
// Register a stable mapping so subsequent 'me' resolves to the same ValueId
|
||||
self.variable_map.insert("me".to_string(), me_value);
|
||||
Ok(me_value)
|
||||
}
|
||||
|
||||
/// Build method call: object.method(arguments)
|
||||
pub(super) fn build_method_call(&mut self, object: ASTNode, method: String, arguments: Vec<ASTNode>) -> Result<ValueId, String> {
|
||||
// Minimal TypeOp wiring via method-style syntax: value.is("Type") / value.as("Type")
|
||||
if (method == "is" || method == "as") && arguments.len() == 1 {
|
||||
if let Some(type_name) = Self::extract_string_literal(&arguments[0]) {
|
||||
// Build the object expression
|
||||
let object_value = self.build_expression(object.clone())?;
|
||||
// Map string to MIR type
|
||||
let mir_ty = Self::parse_type_name_to_mir(&type_name);
|
||||
let dst = self.value_gen.next();
|
||||
let op = if method == "is" { super::TypeOpKind::Check } else { super::TypeOpKind::Cast };
|
||||
self.emit_instruction(MirInstruction::TypeOp { dst, op, value: object_value, ty: mir_ty })?;
|
||||
return Ok(dst);
|
||||
}
|
||||
}
|
||||
// ExternCall判定はobjectの変数解決より先に行う(未定義変数で落とさない)
|
||||
if let ASTNode::Variable { name: object_name, .. } = object.clone() {
|
||||
// Build argument expressions first (externはobject自体を使わない)
|
||||
let mut arg_values = Vec::new();
|
||||
for arg in &arguments {
|
||||
arg_values.push(self.build_expression(arg.clone())?);
|
||||
}
|
||||
match (object_name.as_str(), method.as_str()) {
|
||||
("console", "log") => {
|
||||
self.emit_instruction(MirInstruction::ExternCall {
|
||||
dst: None,
|
||||
iface_name: "env.console".to_string(),
|
||||
method_name: "log".to_string(),
|
||||
args: arg_values,
|
||||
effects: EffectMask::IO,
|
||||
})?;
|
||||
let void_id = self.value_gen.next();
|
||||
self.emit_instruction(MirInstruction::Const { dst: void_id, value: ConstValue::Void })?;
|
||||
return Ok(void_id);
|
||||
},
|
||||
("canvas", "fillRect") | ("canvas", "fillText") => {
|
||||
self.emit_instruction(MirInstruction::ExternCall {
|
||||
dst: None,
|
||||
iface_name: "env.canvas".to_string(),
|
||||
method_name: method,
|
||||
args: arg_values,
|
||||
effects: EffectMask::IO,
|
||||
})?;
|
||||
let void_id = self.value_gen.next();
|
||||
self.emit_instruction(MirInstruction::Const { dst: void_id, value: ConstValue::Void })?;
|
||||
return Ok(void_id);
|
||||
},
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
// Build the object expression
|
||||
let object_value = self.build_expression(object.clone())?;
|
||||
|
||||
// Secondary interception for is/as in case early path did not trigger
|
||||
if (method == "is" || method == "as") && arguments.len() == 1 {
|
||||
if let Some(type_name) = Self::extract_string_literal(&arguments[0]) {
|
||||
let mir_ty = Self::parse_type_name_to_mir(&type_name);
|
||||
let dst = self.value_gen.next();
|
||||
let op = if method == "is" { super::TypeOpKind::Check } else { super::TypeOpKind::Cast };
|
||||
self.emit_instruction(MirInstruction::TypeOp { dst, op, value: object_value, ty: mir_ty })?;
|
||||
return Ok(dst);
|
||||
}
|
||||
}
|
||||
|
||||
// Build argument expressions
|
||||
let mut arg_values = Vec::new();
|
||||
for arg in &arguments {
|
||||
arg_values.push(self.build_expression(arg.clone())?);
|
||||
}
|
||||
|
||||
// Create result value
|
||||
let result_id = self.value_gen.next();
|
||||
|
||||
// Optimization: If the object is a direct `new ClassName(...)`, lower to a direct Call
|
||||
if let ASTNode::New { class, .. } = object {
|
||||
// Build function name and only lower to Call if the function exists (user-defined)
|
||||
let func_name = format!("{}.{}{}", class, method, format!("/{}", arg_values.len()));
|
||||
let can_lower = self.user_defined_boxes.contains(&class)
|
||||
&& if let Some(ref module) = self.current_module { module.functions.contains_key(&func_name) } else { false };
|
||||
if can_lower {
|
||||
let func_val = self.value_gen.next();
|
||||
self.emit_instruction(MirInstruction::Const { dst: func_val, value: ConstValue::String(func_name) })?;
|
||||
let mut call_args = Vec::with_capacity(arg_values.len() + 1);
|
||||
call_args.push(object_value);
|
||||
call_args.extend(arg_values);
|
||||
self.emit_instruction(MirInstruction::Call {
|
||||
dst: Some(result_id),
|
||||
func: func_val,
|
||||
args: call_args,
|
||||
effects: EffectMask::READ.add(Effect::ReadHeap),
|
||||
})?;
|
||||
return Ok(result_id);
|
||||
}
|
||||
// else fall through to BoxCall below
|
||||
} else {
|
||||
// If the object originates from a NewBox in this function, we can lower to Call as well
|
||||
if let Some(class_name) = self.value_origin_newbox.get(&object_value).cloned() {
|
||||
let func_name = format!("{}.{}{}", class_name, method, format!("/{}", arg_values.len()));
|
||||
let can_lower = self.user_defined_boxes.contains(&class_name)
|
||||
&& if let Some(ref module) = self.current_module { module.functions.contains_key(&func_name) } else { false };
|
||||
if can_lower {
|
||||
let func_val = self.value_gen.next();
|
||||
self.emit_instruction(MirInstruction::Const { dst: func_val, value: ConstValue::String(func_name) })?;
|
||||
let mut call_args = Vec::with_capacity(arg_values.len() + 1);
|
||||
call_args.push(object_value);
|
||||
call_args.extend(arg_values);
|
||||
self.emit_instruction(MirInstruction::Call {
|
||||
dst: Some(result_id),
|
||||
func: func_val,
|
||||
args: call_args,
|
||||
effects: EffectMask::READ.add(Effect::ReadHeap),
|
||||
})?;
|
||||
return Ok(result_id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Fallback: Emit a BoxCall instruction for regular or plugin/builtin method calls
|
||||
self.emit_instruction(MirInstruction::BoxCall {
|
||||
dst: Some(result_id),
|
||||
box_val: object_value,
|
||||
method,
|
||||
args: arg_values,
|
||||
effects: EffectMask::READ.add(Effect::ReadHeap), // Method calls may have side effects
|
||||
})?;
|
||||
Ok(result_id)
|
||||
}
|
||||
|
||||
/// Build from expression: from Parent.method(arguments)
|
||||
pub(super) fn build_from_expression(&mut self, parent: String, method: String, arguments: Vec<ASTNode>) -> Result<ValueId, String> {
|
||||
// Build argument expressions
|
||||
let mut arg_values = Vec::new();
|
||||
for arg in arguments {
|
||||
arg_values.push(self.build_expression(arg)?);
|
||||
}
|
||||
|
||||
// Get parent box's me value if available
|
||||
if let Some(&parent_me) = self.variable_map.get(&format!("{}.__me__", parent)) {
|
||||
// Emit from call with parent's me
|
||||
let result = self.value_gen.next();
|
||||
self.emit_instruction(MirInstruction::Call {
|
||||
dst: Some(result),
|
||||
func: self.value_gen.next(), // Placeholder for from resolution
|
||||
args: vec![parent_me], // Include parent's me plus other args
|
||||
effects: EffectMask::READ.add(Effect::ReadHeap),
|
||||
})?;
|
||||
Ok(result)
|
||||
} else {
|
||||
// Fallback behavior without proper parent context
|
||||
let result = self.value_gen.next();
|
||||
Ok(result)
|
||||
}
|
||||
}
|
||||
|
||||
/// Build expression from AST
|
||||
pub(super) fn build_expression(&mut self, ast: ASTNode) -> Result<ValueId, String> {
|
||||
match ast {
|
||||
ASTNode::Literal { value, .. } => {
|
||||
self.build_literal(value)
|
||||
},
|
||||
|
||||
ASTNode::BinaryOp { left, operator, right, .. } => {
|
||||
self.build_binary_op(*left, operator, *right)
|
||||
},
|
||||
|
||||
ASTNode::UnaryOp { operator, operand, .. } => {
|
||||
let op_string = match operator {
|
||||
crate::ast::UnaryOperator::Minus => "-".to_string(),
|
||||
crate::ast::UnaryOperator::Not => "not".to_string(),
|
||||
};
|
||||
self.build_unary_op(op_string, *operand)
|
||||
},
|
||||
|
||||
ASTNode::Variable { name, .. } => {
|
||||
self.build_variable_access(name.clone())
|
||||
},
|
||||
|
||||
ASTNode::Me { .. } => {
|
||||
self.build_me_expression()
|
||||
},
|
||||
|
||||
ASTNode::MethodCall { object, method, arguments, .. } => {
|
||||
// Early TypeOp lowering for method-style is()/as()
|
||||
if (method == "is" || method == "as") && arguments.len() == 1 {
|
||||
if let Some(type_name) = Self::extract_string_literal(&arguments[0]) {
|
||||
let obj_val = self.build_expression(*object.clone())?;
|
||||
let ty = Self::parse_type_name_to_mir(&type_name);
|
||||
let dst = self.value_gen.next();
|
||||
let op = if method == "is" { super::TypeOpKind::Check } else { super::TypeOpKind::Cast };
|
||||
self.emit_instruction(MirInstruction::TypeOp { dst, op, value: obj_val, ty })?;
|
||||
return Ok(dst);
|
||||
}
|
||||
}
|
||||
self.build_method_call(*object.clone(), method.clone(), arguments.clone())
|
||||
},
|
||||
|
||||
ASTNode::FromCall { parent, method, arguments, .. } => {
|
||||
self.build_from_expression(parent.clone(), method.clone(), arguments.clone())
|
||||
},
|
||||
|
||||
ASTNode::Assignment { target, value, .. } => {
|
||||
// Check if target is a field access for RefSet
|
||||
if let ASTNode::FieldAccess { object, field, .. } = target.as_ref() {
|
||||
self.build_field_assignment(*object.clone(), field.clone(), *value.clone())
|
||||
} else if let ASTNode::Variable { name, .. } = target.as_ref() {
|
||||
self.build_assignment(name.clone(), *value.clone())
|
||||
} else {
|
||||
Err("Invalid assignment target".to_string())
|
||||
}
|
||||
},
|
||||
|
||||
ASTNode::FunctionCall { name, arguments, .. } => {
|
||||
self.build_function_call(name.clone(), arguments.clone())
|
||||
},
|
||||
|
||||
ASTNode::FieldAccess { object, field, .. } => {
|
||||
self.build_field_access(*object.clone(), field.clone())
|
||||
},
|
||||
|
||||
ASTNode::ArrayAccess { array, index, .. } => {
|
||||
// Build array and index expressions
|
||||
let array_val = self.build_expression(*array)?;
|
||||
let index_val = self.build_expression(*index)?;
|
||||
|
||||
// Generate ArrayGet instruction
|
||||
let result = self.value_gen.next();
|
||||
self.emit_instruction(MirInstruction::ArrayGet {
|
||||
dst: result,
|
||||
array: array_val,
|
||||
index: index_val,
|
||||
effects: EffectMask::READ.add(Effect::ReadHeap),
|
||||
})?;
|
||||
|
||||
Ok(result)
|
||||
},
|
||||
|
||||
ASTNode::ArrayLiteral { elements, .. } => {
|
||||
// Create new ArrayBox
|
||||
let array_val = self.build_new_expression("ArrayBox".to_string(), vec![])?;
|
||||
|
||||
// Add each element
|
||||
for elem in elements {
|
||||
let elem_val = self.build_expression(elem)?;
|
||||
|
||||
// array.push(elem)
|
||||
self.emit_instruction(MirInstruction::BoxCall {
|
||||
dst: None,
|
||||
box_val: array_val,
|
||||
method: "push".to_string(),
|
||||
args: vec![elem_val],
|
||||
effects: EffectMask::WRITE.add(Effect::WriteHeap),
|
||||
})?;
|
||||
}
|
||||
|
||||
Ok(array_val)
|
||||
},
|
||||
|
||||
ASTNode::New { class, arguments, .. } => {
|
||||
self.build_new_expression(class.clone(), arguments.clone())
|
||||
},
|
||||
|
||||
ASTNode::Await { expression, .. } => {
|
||||
self.build_await_expression(*expression)
|
||||
},
|
||||
|
||||
_ => {
|
||||
Err(format!("Unsupported expression type: {:?}", ast))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Build assignment: variable = value
|
||||
pub(super) fn build_assignment(&mut self, var_name: String, value: ASTNode) -> Result<ValueId, String> {
|
||||
let value_id = self.build_expression(value)?;
|
||||
|
||||
// In SSA form, each assignment creates a new value
|
||||
self.variable_map.insert(var_name.clone(), value_id);
|
||||
|
||||
Ok(value_id)
|
||||
}
|
||||
|
||||
/// Build field assignment: object.field = value
|
||||
pub(super) fn build_field_assignment(&mut self, object: ASTNode, field: String, value: ASTNode) -> Result<ValueId, String> {
|
||||
// Build the object and value expressions
|
||||
let object_value = self.build_expression(object)?;
|
||||
let mut value_result = self.build_expression(value)?;
|
||||
|
||||
// If we can infer the box type and the field is weak, create WeakRef before store
|
||||
if let Some(class_name) = self.value_origin_newbox.get(&object_value).cloned() {
|
||||
if let Some(weak_set) = self.weak_fields_by_box.get(&class_name) {
|
||||
if weak_set.contains(&field) {
|
||||
value_result = self.emit_weak_new(value_result)?;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Set the field using RefSet
|
||||
self.emit_instruction(MirInstruction::RefSet {
|
||||
reference: object_value,
|
||||
field: field.clone(),
|
||||
value: value_result,
|
||||
})?;
|
||||
|
||||
// Emit a write barrier for weak fields (PoC)
|
||||
if let Some(class_name) = self.value_origin_newbox.get(&object_value).cloned() {
|
||||
if let Some(weak_set) = self.weak_fields_by_box.get(&class_name) {
|
||||
if weak_set.contains(&field) {
|
||||
let _ = self.emit_barrier_write(value_result);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Record origin class for this field (if the value originates from NewBox of a known class)
|
||||
if let Some(class_name) = self.value_origin_newbox.get(&value_result).cloned() {
|
||||
self.field_origin_class.insert((object_value, field.clone()), class_name);
|
||||
}
|
||||
|
||||
// Return the assigned value
|
||||
Ok(value_result)
|
||||
}
|
||||
|
||||
/// Build new expression: new ClassName(arguments)
|
||||
pub(super) fn build_new_expression(&mut self, class: String, arguments: Vec<ASTNode>) -> Result<ValueId, String> {
|
||||
// Phase 9.78a: Unified Box creation using NewBox instruction
|
||||
|
||||
// First, evaluate all arguments to get their ValueIds
|
||||
let mut arg_values = Vec::new();
|
||||
for arg in arguments {
|
||||
let arg_value = self.build_expression(arg)?;
|
||||
arg_values.push(arg_value);
|
||||
}
|
||||
|
||||
// Generate the destination ValueId
|
||||
let dst = self.value_gen.next();
|
||||
|
||||
// Emit NewBox instruction for all Box types
|
||||
// VM will handle optimization for basic types internally
|
||||
self.emit_instruction(MirInstruction::NewBox {
|
||||
dst,
|
||||
box_type: class.clone(),
|
||||
args: arg_values.clone(),
|
||||
})?;
|
||||
|
||||
// Record origin for optimization: dst was created by NewBox of class
|
||||
self.value_origin_newbox.insert(dst, class);
|
||||
|
||||
// Immediately call birth(...) on the created instance to run constructor semantics.
|
||||
// birth typically returns void; we don't capture the result here (dst: None)
|
||||
self.emit_instruction(MirInstruction::BoxCall {
|
||||
dst: None,
|
||||
box_val: dst,
|
||||
method: "birth".to_string(),
|
||||
args: arg_values,
|
||||
effects: EffectMask::READ.add(Effect::ReadHeap),
|
||||
})?;
|
||||
|
||||
Ok(dst)
|
||||
}
|
||||
|
||||
/// Build await expression: await expression
|
||||
pub(super) fn build_await_expression(&mut self, expression: ASTNode) -> Result<ValueId, String> {
|
||||
// Evaluate the expression (should be a Future)
|
||||
let future_value = self.build_expression(expression)?;
|
||||
|
||||
// Create result value for the await
|
||||
let result_id = self.value_gen.next();
|
||||
|
||||
// Emit await instruction
|
||||
self.emit_instruction(MirInstruction::Await {
|
||||
dst: result_id,
|
||||
future: future_value,
|
||||
effects: EffectMask::READ.add(Effect::Async),
|
||||
})?;
|
||||
|
||||
Ok(result_id)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user