feat(parser): Phase 285A1.4 & A1.5 - Weak field sugar + Parser hang fix
A1.4: Add sugar syntax `public weak parent` ≡ `public { weak parent }`
A1.5: Fix parser hang on unsupported `param: Type` syntax
Key changes:
- A1.4: Extend visibility parser to handle weak modifier (fields.rs)
- A1.5: Shared helper `parse_param_name_list()` with progress-zero detection
- A1.5: Fix 6 vulnerable parameter parsing loops (methods, constructors, functions)
- Tests: Sugar syntax (OK/NG), parser hang (timeout-based)
- Docs: lifecycle.md, EBNF.md, phase-285a1-boxification.md
Additional changes:
- weak() builtin implementation (handlers/weak.rs)
- Leak tracking improvements (leak_tracker.rs)
- Documentation updates (lifecycle, types, memory-finalization, etc.)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
@ -5,6 +5,10 @@
|
||||
Nyashの核心哲学「**Everything is Box**」に関する完全な設計ドキュメント集。
|
||||
言語設計の根幹から実装詳細まで、Boxシステムのすべてを網羅しています。
|
||||
|
||||
注(`init { ... }` について):
|
||||
- `init { a, b, c }` は legacy のフィールド宣言(slot)です(互換のために残っています)。
|
||||
- 新規コードでは、可能なら Unified Members(stored/computed/once/birth_once)での宣言を推奨します(SSOT: `docs/reference/language/EBNF.md` / ライフサイクルSSOT: `docs/reference/language/lifecycle.md`)。
|
||||
|
||||
## 📚 ドキュメント構成
|
||||
|
||||
### 🌟 コア哲学
|
||||
@ -51,4 +55,4 @@ Nyashの核心哲学「Everything is Box」の解説。なぜすべてをBoxに
|
||||
---
|
||||
|
||||
**最終更新**: 2025年8月19日 - boxes-system統合整理完了
|
||||
**Phase 9.75g-0成果**: プラグインシステムとの完全統合
|
||||
**Phase 9.75g-0成果**: プラグインシステムとの完全統合
|
||||
|
||||
@ -5,6 +5,8 @@
|
||||
Nyashは継承の代わりに「完全明示デリゲーション」を採用しています。
|
||||
これは「Everything is Box」哲学に基づく、より安全で明確な設計アプローチです。
|
||||
|
||||
注: `init { ... }` は legacy のフィールド宣言(slot)です(互換のために残っています)。新しい宣言モデル(Unified Members)は `docs/reference/language/EBNF.md` を参照してください。
|
||||
|
||||
## 🎯 なぜデリゲーションか
|
||||
|
||||
### 継承の問題点
|
||||
@ -387,4 +389,4 @@ box Proxy delegates * to target {
|
||||
関連ドキュメント:
|
||||
- [Everything is Box](everything-is-box.md)
|
||||
- [override/from構文詳細](../override-delegation-syntax.md)
|
||||
- [言語リファレンス](../language-reference.md)
|
||||
- [言語リファレンス](../language-reference.md)
|
||||
|
||||
@ -112,7 +112,7 @@ local result = "Hello" + 42.toString() // OK: "Hello42"
|
||||
|
||||
### 特殊Box型
|
||||
- **FutureBox** - 非同期処理
|
||||
- **WeakBox** - 弱参照
|
||||
- **WeakRef(WeakBox)** - 弱参照(観測は `weak_to_strong()`。言語SSOT: `docs/reference/language/lifecycle.md`)
|
||||
- **ExternBox** - 外部ライブラリ統合
|
||||
|
||||
## 🔄 Boxの生成と利用
|
||||
@ -130,6 +130,7 @@ local num = 42 // 自動的にIntegerBox
|
||||
|
||||
### ユーザー定義Box
|
||||
```nyash
|
||||
// 注: `init { ... }` は legacy のフィールド宣言(slot)です(互換のために残っています)。
|
||||
box Point {
|
||||
init { x, y }
|
||||
|
||||
@ -195,4 +196,4 @@ Everything is Box哲学により、Nyashは:
|
||||
関連ドキュメント:
|
||||
- [Box型カタログ](box-types-catalog.md)
|
||||
- [デリゲーションシステム](delegation-system.md)
|
||||
- [メモリ管理](memory-management.md)
|
||||
- [メモリ管理](memory-management.md)
|
||||
|
||||
@ -2,6 +2,8 @@
|
||||
|
||||
**最終更新: 2025年8月19日 - 統合仕様書**
|
||||
|
||||
注: 言語レベルの SSOT は `docs/reference/language/lifecycle.md`。本書は設計ノートであり、SSOT と矛盾する記述があれば SSOT を優先する。
|
||||
|
||||
## 📋 概要
|
||||
|
||||
Nyashは「Everything is Box」哲学のもと、統一的なメモリ管理と予測可能なリソース解放を実現しています。
|
||||
@ -72,20 +74,23 @@ box MyResource {
|
||||
|
||||
**重要**: `fini()`は「このオブジェクトをもう使わない」という宣言であり、物理的な即時破棄ではありません。
|
||||
|
||||
### 実行順序(確定仕様)
|
||||
### 実行順序(設計SSOTへの案内)
|
||||
|
||||
最終的な順序・禁止事項の SSOT は `docs/reference/language/lifecycle.md` に集約する。
|
||||
本セクションの箇条書きは “目標像/設計メモ” として読む。
|
||||
|
||||
#### 自動カスケード解放
|
||||
```nyash
|
||||
box Pipeline {
|
||||
init { r1, r2, r3, weak monitor }
|
||||
init { r1, r2, r3, monitor_weak }
|
||||
|
||||
fini() {
|
||||
// 1) ユーザー定義処理(柔軟な順序制御可能)
|
||||
me.r3.fini() // 依存関係でr3→r2の順
|
||||
me.r2.fini()
|
||||
|
||||
// 2) 自動カスケード: 残りのr1がinit宣言順で自動解放
|
||||
// 3) weakフィールドは対象外(lazy nil化)
|
||||
// 2) 自動カスケード: 残りのr1が自動解放(weak参照は対象外)
|
||||
// 3) weak参照は weak_to_strong() で観測し、失効時は null(=void/none)を返す
|
||||
}
|
||||
}
|
||||
```
|
||||
@ -94,7 +99,7 @@ box Pipeline {
|
||||
1. **finalized チェック** - 既に解放済みなら何もしない(idempotent)
|
||||
2. **再入防止** - `in_finalization`フラグで再帰呼び出し防止
|
||||
3. **ユーザー定義fini()実行** - カスタムクリーンアップ処理
|
||||
4. **自動カスケード** - `init`宣言順で未処理フィールドを解放
|
||||
4. **自動カスケード** - strong-owned フィールドを決定的順序で解放(weakはスキップ)
|
||||
5. **フィールドクリア** - 全フィールドを無効化
|
||||
6. **finalized設定** - 以後の使用を禁止
|
||||
|
||||
@ -102,25 +107,26 @@ box Pipeline {
|
||||
|
||||
```nyash
|
||||
box Node {
|
||||
init { id, weak next } // 'next'は弱参照
|
||||
init { id, next_weak } // 弱参照は値として保持する(`weak(x)`)
|
||||
}
|
||||
|
||||
local node1 = new Node("A", null)
|
||||
local node2 = new Node("B", node1) // node2はnode1への弱参照を持つ
|
||||
node1.next = node2 // node1はnode2への強参照を持つ
|
||||
local node2 = new Node("B", null)
|
||||
node2.next_weak = weak(node1)
|
||||
node1.next_weak = weak(node2)
|
||||
// 循環参照を回避し、安全に解放される
|
||||
```
|
||||
|
||||
#### weak参照の特性
|
||||
- **所有権なし**: オブジェクトの生存期間に影響しない
|
||||
- **自動nil化**: 参照先が解放されると自動的に`null`になる
|
||||
- **観測はweak_to_strong**: 参照先が Dead/Freed の場合、`weak_to_strong()` は `null` を返す
|
||||
- **fini()対象外**: 弱参照フィールドはfini()カスケードでスキップ
|
||||
|
||||
### 不変条件(重要)
|
||||
|
||||
- **weak参照**: `weak`フィールドに対して`fini()`を直接呼ぶことはできません
|
||||
- **finalized後禁止**: `fini()`呼び出し後は、そのオブジェクトの使用はすべて禁止
|
||||
- **カスケード順序**: `init`宣言順の**逆順**で実行、`weak`フィールドはスキップ
|
||||
- **カスケード順序**: strong-owned フィールドに対して決定的に実行し、`weak`フィールドはスキップ(順序のSSOTは `docs/reference/language/lifecycle.md`)。
|
||||
|
||||
## 🌟 実用例
|
||||
|
||||
@ -130,7 +136,7 @@ box FileHandler {
|
||||
init { file, buffer }
|
||||
|
||||
fini() {
|
||||
// オブジェクト削除時に自動呼び出し
|
||||
// 終了時に資源を解放(必要なら明示的に呼ぶ)
|
||||
if me.file != null {
|
||||
me.file.close()
|
||||
console.log("File closed automatically")
|
||||
@ -177,4 +183,4 @@ box PluginResource {
|
||||
**関連ドキュメント**:
|
||||
- [Box型リファレンス](box-reference.md)
|
||||
- [プラグインシステム](../plugin-system/)
|
||||
- [BID-FFI仕様](../plugin-system/ffi-abi-specification.md)
|
||||
- [BID-FFI仕様](../plugin-system/ffi-abi-specification.md)
|
||||
|
||||
@ -11,7 +11,7 @@
|
||||
|
||||
- `design-philosophy.md` - Nyashの設計哲学
|
||||
- `override-delegation-syntax.md` - オーバーライド・デリゲーション構文の詳細
|
||||
- `portability-contract.md` - 移植性に関する契約
|
||||
- `portability-contract.md` - 移植性に関する契約(アーカイブ。参照先: `docs/archive/core-language/portability-contract.md`)
|
||||
|
||||
## 📦 アーカイブ
|
||||
|
||||
|
||||
@ -1,295 +1,8 @@
|
||||
# 🤝 Nyash Portability Contract v0
|
||||
# Portability Contract v0 (Archived)
|
||||
|
||||
*ChatGPT5アドバイス・全バックエンド互換性保証仕様*
|
||||
This document has been archived. The canonical copy is:
|
||||
- `docs/archive/core-language/portability-contract.md`
|
||||
|
||||
## 🎯 目的
|
||||
|
||||
**「nyash --target= interp / vm / wasm / aot-rust / jit-cranelift」で同一プログラムが同一結果を保証**
|
||||
|
||||
全バックエンドでNyashプログラムが確実に動作し、最適化レベルに関係なく**決定的で予測可能な実行**を実現。
|
||||
|
||||
## 🔧 **Contract v0 仕様**
|
||||
|
||||
### 1️⃣ **決定的破棄(Deterministic Finalization)**
|
||||
|
||||
#### **強参照のみ伝播保証**
|
||||
```rust
|
||||
// ✅ 保証される動作
|
||||
box Parent {
|
||||
child_strong: ChildBox // 強参照→破棄連鎖
|
||||
}
|
||||
|
||||
parent.fini() // 必ずchild_strong.fini()も呼ばれる
|
||||
```
|
||||
|
||||
#### **破棄順序の決定性**
|
||||
```nyash
|
||||
// 破棄順序: 最新→最古(スタック順序)
|
||||
box Child from Parent {
|
||||
init { data }
|
||||
pack() {
|
||||
from Parent.pack() // 1. Parent初期化
|
||||
me.data = "child" // 2. Child初期化
|
||||
}
|
||||
// fini順序: 2→1(逆順破棄)
|
||||
}
|
||||
```
|
||||
|
||||
#### **例外安全性**
|
||||
```rust
|
||||
pub enum FinalizationGuarantee {
|
||||
AlwaysExecuted, // fini()は例外時も必ず実行
|
||||
NoDoubleDestroy, // 同一オブジェクトの二重破棄禁止
|
||||
OrderPreserved, // 初期化と逆順での破棄保証
|
||||
}
|
||||
```
|
||||
|
||||
### 2️⃣ **weak参照の非伝播+生存チェック**
|
||||
|
||||
#### **非伝播保証**
|
||||
```nyash
|
||||
box Parent {
|
||||
init { child_weak }
|
||||
|
||||
pack() {
|
||||
local child = new Child()
|
||||
me.child_weak = weak(child) // weak参照生成
|
||||
// child がfini()されても Parent は影響なし
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### **生存チェック必須**
|
||||
```mir
|
||||
// MIR レベルでの生存チェック
|
||||
%alive = weak_load %weak_ref
|
||||
br %alive -> %use_bb, %null_bb
|
||||
|
||||
%use_bb:
|
||||
// weak参照が有効な場合の処理
|
||||
%value = /* weak_refの値使用 */
|
||||
jmp %continue_bb
|
||||
|
||||
%null_bb:
|
||||
// weak参照が無効な場合の処理
|
||||
%value = const null
|
||||
jmp %continue_bb
|
||||
|
||||
%continue_bb:
|
||||
// 合流地点(Phi必須)
|
||||
%result = phi [%value from %use_bb, %value from %null_bb]
|
||||
```
|
||||
|
||||
#### **自動null化契約**
|
||||
```rust
|
||||
pub struct WeakContract {
|
||||
auto_nullification: true, // 参照先fini()時に自動null
|
||||
no_dangling_pointers: true, // ダングリングポインタ禁止
|
||||
thread_safe_access: true, // マルチスレッド安全アクセス
|
||||
}
|
||||
```
|
||||
|
||||
### 3️⃣ **Effect意味論(最適化可能性)**
|
||||
|
||||
#### **Effect分類契約**
|
||||
```rust
|
||||
pub enum EffectLevel {
|
||||
Pure, // 副作用なし→並び替え・除去・重複実行可能
|
||||
Mut, // メモリ変更→順序保証必要・並列化制限
|
||||
Io, // I/O操作→実行順序厳密保証・キャッシュ禁止
|
||||
Bus, // 分散通信→elision対象・ネットワーク最適化可能
|
||||
}
|
||||
```
|
||||
|
||||
#### **最適化契約**
|
||||
```mir
|
||||
// Pure関数→最適化可能
|
||||
%result1 = call @pure_function(%arg) effects=[PURE]
|
||||
%result2 = call @pure_function(%arg) effects=[PURE]
|
||||
// → 最適化: %result2 = copy %result1
|
||||
|
||||
// Mut操作→順序保証
|
||||
store %value1 -> %ptr effects=[MUT]
|
||||
store %value2 -> %ptr effects=[MUT]
|
||||
// → 順序維持必須
|
||||
|
||||
// Bus操作→elision対象
|
||||
send %bus, %message effects=[BUS]
|
||||
// → ネットワーク最適化・バッチ化可能
|
||||
```
|
||||
|
||||
### 4️⃣ **Bus-elision基盤契約**
|
||||
|
||||
#### **elision ON/OFF同一結果保証**
|
||||
```bash
|
||||
# 最適化ON→高速実行
|
||||
nyash --elide-bus --target wasm program.hako
|
||||
|
||||
# 最適化OFF→完全分散実行
|
||||
nyash --no-elide-bus --target vm program.hako
|
||||
|
||||
# 結果は必ず同一(契約保証)
|
||||
```
|
||||
|
||||
#### **Bus操作の意味保証**
|
||||
```mir
|
||||
// Bus送信の意味論
|
||||
send %bus, %message effects=[BUS] {
|
||||
// elision OFF: 実際のネットワーク送信
|
||||
// elision ON: ローカル最適化(結果同一)
|
||||
}
|
||||
|
||||
// Bus受信の意味論
|
||||
%msg = recv %bus effects=[BUS] {
|
||||
// elision OFF: ネットワーク受信待ち
|
||||
// elision ON: ローカル値返却(結果同一)
|
||||
}
|
||||
```
|
||||
|
||||
## 🧪 **Contract検証システム**
|
||||
|
||||
### **互換テストスイート**
|
||||
```rust
|
||||
// tests/portability_contract_tests.rs
|
||||
#[test]
|
||||
fn test_deterministic_finalization() {
|
||||
let program = "/* fini順序テスト */";
|
||||
|
||||
let interp_result = run_interpreter(program);
|
||||
let vm_result = run_vm(program);
|
||||
let wasm_result = run_wasm(program);
|
||||
|
||||
// 破棄順序・タイミングが全バックエンドで同一
|
||||
assert_eq!(interp_result.finalization_order, vm_result.finalization_order);
|
||||
assert_eq!(vm_result.finalization_order, wasm_result.finalization_order);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_weak_reference_semantics() {
|
||||
let program = "/* weak参照テスト */";
|
||||
|
||||
// 生存チェック・null化が全バックエンドで同一動作
|
||||
let results = run_all_backends(program);
|
||||
assert_all_equal(results.map(|r| r.weak_behavior));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_effect_optimization_equivalence() {
|
||||
let program = "/* Effect最適化テスト */";
|
||||
|
||||
// PURE関数の最適化結果が同一
|
||||
let optimized = run_with_optimization(program);
|
||||
let reference = run_without_optimization(program);
|
||||
assert_eq!(optimized.output, reference.output);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_bus_elision_equivalence() {
|
||||
let program = "/* Bus通信テスト */";
|
||||
|
||||
let elision_on = run_with_flag(program, "--elide-bus");
|
||||
let elision_off = run_with_flag(program, "--no-elide-bus");
|
||||
|
||||
// Bus最適化ON/OFFで結果同一
|
||||
assert_eq!(elision_on.output, elision_off.output);
|
||||
}
|
||||
```
|
||||
|
||||
### **Golden Dump検証**
|
||||
```bash
|
||||
#!/bin/bash
|
||||
# scripts/verify_portability_contract.sh
|
||||
|
||||
echo "🧪 Portability Contract v0 検証中..."
|
||||
|
||||
# 1. MIR出力一致検証
|
||||
nyash --dump-mir test.hako > golden.mir
|
||||
nyash --dump-mir test.hako > current.mir
|
||||
if ! diff golden.mir current.mir; then
|
||||
echo "❌ MIR回帰エラー検出"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# 2. 全バックエンド同一出力
|
||||
declare -a backends=("interp" "vm" "wasm")
|
||||
for backend in "${backends[@]}"; do
|
||||
nyash --target $backend test.hako > ${backend}.out
|
||||
done
|
||||
|
||||
# 出力一致確認
|
||||
if diff interp.out vm.out && diff vm.out wasm.out; then
|
||||
echo "✅ 全バックエンド出力一致"
|
||||
else
|
||||
echo "❌ バックエンド出力差異検出"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# 3. Bus-elision検証
|
||||
nyash --elide-bus test.hako > elision_on.out
|
||||
nyash --no-elide-bus test.hako > elision_off.out
|
||||
if diff elision_on.out elision_off.out; then
|
||||
echo "✅ Bus-elision同一結果"
|
||||
else
|
||||
echo "❌ Bus-elision結果差異"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "🎉 Portability Contract v0 検証完了"
|
||||
```
|
||||
|
||||
## 📊 **Contract適合レベル**
|
||||
|
||||
### **Tier-0: 基本互換性**
|
||||
- [ ] **決定的破棄**: fini()順序がバックエンド間で同一
|
||||
- [ ] **weak非伝播**: weak参照が親破棄に影響しない
|
||||
- [ ] **基本Effect**: PURE/MUT/IO の意味論統一
|
||||
- [ ] **出力一致**: 同一プログラム→同一標準出力
|
||||
|
||||
### **Tier-1: 最適化互換性**
|
||||
- [ ] **PURE最適化**: 純粋関数の除去・移動がバックエンド間で同等
|
||||
- [ ] **weak生存チェック**: 全バックエンドで同一タイミング
|
||||
- [ ] **Bus-elision**: ON/OFF切り替えで結果同一
|
||||
- [ ] **性能予測**: 最適化レベル差が定量的
|
||||
|
||||
### **Tier-2: 高度互換性**
|
||||
- [ ] **メモリレイアウト**: Box構造がバックエンド間で互換
|
||||
- [ ] **エラー処理**: 例外・パニックが同一動作
|
||||
- [ ] **並行性**: Future/awaitが同一意味論
|
||||
- [ ] **デバッグ**: スタックトレース・診断情報が同等
|
||||
|
||||
## ⚡ **実装優先順位**
|
||||
|
||||
### **Phase 8.4(今すぐ)**
|
||||
1. **Tier-0契約実装**: 基本互換性確保
|
||||
2. **Golden dump自動化**: CI/CDで回帰検出
|
||||
3. **Bus命令設計**: elision基盤構築
|
||||
|
||||
### **Phase 8.5(短期)**
|
||||
1. **Tier-1契約実装**: 最適化互換性
|
||||
2. **性能ベンチマーク**: 契約準拠性測定
|
||||
3. **エラー契約**: 例外処理統一
|
||||
|
||||
### **Phase 9+(中長期)**
|
||||
1. **Tier-2契約実装**: 高度互換性
|
||||
2. **形式検証**: 契約の数学的証明
|
||||
3. **認証システム**: 契約適合認定
|
||||
|
||||
---
|
||||
|
||||
## 🎯 **期待効果**
|
||||
|
||||
### **開発者体験**
|
||||
- **予測可能性**: どのバックエンドでも同一動作保証
|
||||
- **デバッグ容易性**: バックエンド切り替えで問題切り分け
|
||||
- **最適化信頼性**: 高速化しても結果不変保証
|
||||
|
||||
### **Nyash言語価値**
|
||||
- **差別化**: 「全バックエンド互換」言語として独自性
|
||||
- **信頼性**: エンタープライズ採用の技術的根拠
|
||||
- **拡張性**: 新バックエンド追加時の品質保証
|
||||
|
||||
---
|
||||
|
||||
*最終更新: 2025-08-14 - ChatGPT5アドバイス完全実装*
|
||||
|
||||
*「Everything is Box」×「全バックエンド互換」= Nyashの技術的優位性*
|
||||
Language SSOT:
|
||||
- `docs/reference/language/lifecycle.md`
|
||||
- `docs/reference/language/types.md`
|
||||
|
||||
@ -251,6 +251,7 @@ NYASH_CLI_VERBOSE=2 \
|
||||
| `NYASH_GC_METRICS=1` | OFF | Any | GC メトリクス (text) |
|
||||
| `NYASH_GC_METRICS_JSON=1` | OFF | Any | GC メトリクス (JSON) |
|
||||
| `NYASH_VM_TRACE=1` | OFF | Any | VM 実行トレース |
|
||||
| `NYASH_LEAK_LOG={1\|2}` | OFF | Any | Exit-time leak report (Phase 285)。`1`=summary counts, `2`=verbose (names/entries) |
|
||||
|
||||
---
|
||||
|
||||
|
||||
@ -72,13 +72,25 @@ This section adds a minimal grammar for Box members (a unified member model) wit
|
||||
```
|
||||
box_decl := 'box' IDENT '{' member* '}'
|
||||
|
||||
member := stored
|
||||
member := visibility_block
|
||||
| weak_stored
|
||||
| stored
|
||||
| computed
|
||||
| once_decl
|
||||
| birth_once_decl
|
||||
| method_decl
|
||||
| block_as_role ; nyash-mode (block-first) equivalent
|
||||
|
||||
visibility_block := ( 'public' | 'private' ) '{' member* '}'
|
||||
; member visibility grouping (Phase 285A1.3). `weak` is allowed inside.
|
||||
|
||||
weak_stored := 'weak' IDENT ( ':' TYPE )?
|
||||
; weak field declaration (Phase 285A1.2). Enforces WeakRef type at compile-time.
|
||||
|
||||
visibility_weak_sugar := ('public'|'private') 'weak' IDENT ( ':' TYPE )?
|
||||
; sugar syntax (Phase 285A1.4). Equivalent to visibility block form.
|
||||
; e.g., `public weak parent` ≡ `public { weak parent }`
|
||||
|
||||
stored := IDENT ':' TYPE ( '=' expr )?
|
||||
; stored property (read/write). No handlers supported.
|
||||
|
||||
@ -93,6 +105,10 @@ birth_once_decl:= 'birth_once' IDENT ':' TYPE ( '=>' expr | block ) handler_tail
|
||||
|
||||
method_decl := IDENT '(' params? ')' ( ':' TYPE )? block handler_tail?
|
||||
|
||||
params := IDENT (',' IDENT)*
|
||||
; parameter name list (Phase 285A1.5)
|
||||
; Note: Parameter type annotations (e.g., `name: Type`) are not supported.
|
||||
|
||||
; nyash-mode (block-first) variant — gated with NYASH_ENABLE_UNIFIED_MEMBERS=1
|
||||
block_as_role := block 'as' ( 'once' | 'birth_once' )? IDENT ':' TYPE
|
||||
|
||||
@ -101,7 +117,7 @@ catch_block := 'catch' ( '(' ( IDENT IDENT | IDENT )? ')' )? block
|
||||
cleanup_block := 'cleanup' block
|
||||
|
||||
; Stage‑3 (Phase 1 via normalization gate NYASH_CATCH_NEW=1)
|
||||
; Postfix handlers for expressions and calls
|
||||
; Postfix handlers for expressions and calls (cleanup may appear without catch)
|
||||
postfix_catch := primary_expr 'catch' ( '(' ( IDENT IDENT | IDENT )? ')' )? block
|
||||
postfix_cleanup := primary_expr 'cleanup' block
|
||||
```
|
||||
@ -120,12 +136,23 @@ Lowering (no JSON v0 change)
|
||||
- birth_once → add `__name: T` and insert initialization just before user `birth` in declaration order; handlers apply to each initializer
|
||||
- method → existing method forms; optional postfix handlers lower to try/catch/finally
|
||||
|
||||
## Legacy: `init { ... }` field list (compatibility)
|
||||
|
||||
Some docs and older code use an `init { a, b, c }` list inside a `box` body. This is a legacy compatibility form to declare stored slots.
|
||||
|
||||
Semantics (SSOT):
|
||||
- `init { a, b, c }` declares **untyped stored slots** named `a`, `b`, `c` (equivalent to writing `a` / `b` / `c` as stored members without type).
|
||||
- `init { weak x, weak y }` declares **weak fields** (equivalent to writing `weak x` / `weak y` as members).
|
||||
- It does not execute code. Initialization logic belongs in `birth(...) { ... }` and assignments.
|
||||
- **New code** should prefer the direct syntax: `weak field_name` (Phase 285A1.2) or the unified member model (`stored/computed/once/birth_once`).
|
||||
- Legacy `init { weak field }` syntax still works for backward compatibility but is superseded by `weak field`.
|
||||
|
||||
## Stage‑3 (Gated) Additions
|
||||
|
||||
Enabled when `NYASH_PARSER_STAGE3=1` for the Rust parser (and via `--stage3`/`NYASH_NY_COMPILER_STAGE3=1` for the selfhost parser):
|
||||
|
||||
- try/catch/cleanup
|
||||
- `try_stmt := 'try' block ('catch' '(' (IDENT IDENT | IDENT | ε) ')' block) ('cleanup' block)?`
|
||||
- `try_stmt := 'try' block ('catch' '(' (IDENT IDENT | IDENT | ε) ')' block)? ('cleanup' block)?`
|
||||
- MVP policy: single `catch` per `try`。
|
||||
- `(Type var)` or `(var)` or `()` are accepted for the catch parameter。
|
||||
|
||||
|
||||
@ -38,18 +38,18 @@ Rust製インタープリターによる高性能実行と、直感的な構文
|
||||
| `override` | 明示的オーバーライド | `override speak() { }` |
|
||||
| `break` | ループ脱出 | `break` |
|
||||
| `catch` | 例外処理 | `catch (e) { }`(式/呼び出しの後置も可・Stage‑3) |
|
||||
| `cleanup` | 最終処理(finally の後継) | `cleanup { }`(式/呼び出しの後置も可・Stage‑3) |
|
||||
| `cleanup` | 最終処理(finally の後継) | `cleanup { }`(式/呼び出しの後置・Stage‑3。`catch` があればその後に実行) |
|
||||
| `throw` | 例外発生 | `throw error` |
|
||||
| `nowait` | 非同期実行 | `nowait future = task()` |
|
||||
| `await` | 待機・結果取得 | `result = await future` |
|
||||
| `include` | ファイル取り込み | `include "math.hako"` |
|
||||
| `print` | 出力(デバッグ用) | `print("Hello")` |
|
||||
| `function`/`fn` | 関数定義 | `fn add(a,b) { }` |
|
||||
| `init` | 初期化ブロック | `init { field1, field2 }` |
|
||||
| `init` | (legacy/互換)フィールド宣言(slot) | `init { field1, field2 }` |
|
||||
| `pack` | 旧コンストラクタ(互換性) | `pack(param) { }` |
|
||||
| `outbox` | 所有権移転変数 | `outbox result = compute()` |
|
||||
| `global` | グローバル変数 | `global CONFIG = "dev"` |
|
||||
| `weak` | 弱参照修飾子 | `weak reference` |
|
||||
| `weak` | 弱参照(生成) | `weak(x)` |
|
||||
| `using` | 名前空間インポート | `using namespace` |
|
||||
|
||||
### **演算子・論理**
|
||||
@ -95,6 +95,16 @@ box ClassName {
|
||||
}
|
||||
```
|
||||
|
||||
注: `fini()` / strong・weak / スコープ終了 / GC の方針(cycle の扱い含む)の SSOT は `docs/reference/language/lifecycle.md`。
|
||||
|
||||
注(`init { ... }` について):
|
||||
- `init { a, b, c }` は **互換のために残っているフィールド宣言(slot)**です(コード実行の「初期化ブロック」ではありません)。
|
||||
- これは「untyped な stored slot を宣言する糖衣」として扱います(例: `a` / `b` / `c` の stored を追加する)。
|
||||
- `init { weak field }` は弱フィールド宣言です(Phase 285A1.2 の直接構文 `weak field` に統一されました)。
|
||||
- 新規コードでは、可能なら以下を推奨します:
|
||||
- **弱フィールド**: 直接構文 `weak field_name`(Phase 285A1.2)
|
||||
- **その他**: `docs/reference/language/EBNF.md` の Unified Members(stored/computed/once/birth_once)
|
||||
|
||||
#### **デリゲーションBox**
|
||||
```nyash
|
||||
box Child from Parent interface Comparable {
|
||||
@ -739,6 +749,8 @@ array.map(fn(x) { x * x })
|
||||
- Rust所有権システムによる完全なメモリ安全性
|
||||
- Arc<Mutex>によるスレッドセーフな共有状態管理
|
||||
- 自動参照カウント + 明示的デストラクタ(fini)
|
||||
- SSOT: `docs/reference/language/lifecycle.md`
|
||||
- GC(tracing/cycle collection)は意味論ではなく補助。OFFでも非循環は解放されるが、循環はリークしうる(仕様)。
|
||||
|
||||
### **6.2 実行効率**
|
||||
- 統一されたBox型システムによる最適化
|
||||
@ -783,7 +795,6 @@ static box Main {
|
||||
### **7.3 よくある間違いと対策**
|
||||
```nyash
|
||||
# ❌ よくある間違い
|
||||
public { field1 field2 } # 旧構文 → 使用不可
|
||||
x = 42 # 変数未宣言 → ランタイムエラー
|
||||
while condition { } # 非対応構文 → パーサーエラー
|
||||
this.field # thisは使用不可 → me.fieldを使用
|
||||
@ -794,6 +805,10 @@ field2 # 型なしフィールド
|
||||
local x = 42 # 事前宣言必須
|
||||
loop(condition) { } # 統一ループ構文
|
||||
me.field # self参照はmeのみ
|
||||
|
||||
# ✅ Weak field 構文(Phase 285A1.4対応)
|
||||
public weak parent # 糖衣構文(Phase 285A1.4)
|
||||
public { weak parent } # ブロック構文(Phase 285A1.3)- どちらも同義
|
||||
```
|
||||
|
||||
---
|
||||
@ -831,12 +846,12 @@ let [first, second, ...rest] = array
|
||||
方針
|
||||
- try は非推奨。postfix `catch` と `cleanup` を用いる。
|
||||
- `catch` は直前の式/呼び出しで発生した例外を処理。
|
||||
- `cleanup` は常に実行(finally の後継)。
|
||||
- `cleanup` は常に実行(finally の後継)。`catch` の有無に関係なく付与できる。
|
||||
|
||||
例(式レベルの postfix)
|
||||
```
|
||||
do_work() catch(Error e) { env.console.log(e) }
|
||||
open(path) cleanup { env.console.log("close") }
|
||||
do_work() cleanup { env.console.log("done") }
|
||||
open(path) catch(Error e) { env.console.log(e) } cleanup { env.console.log("close") }
|
||||
connect(url)
|
||||
catch(NetworkError e) { env.console.warn(e) }
|
||||
cleanup { env.console.log("done") }
|
||||
|
||||
@ -18,6 +18,7 @@ Imports and namespaces
|
||||
|
||||
Variables and scope
|
||||
- See: reference/language/variables-and-scope.md — Block-scoped locals, assignment resolution, and strong/weak reference guidance.
|
||||
- See: reference/language/lifecycle.md — Box lifetime, ownership (strong/weak), and finalization (`fini`) SSOT.
|
||||
|
||||
Type system (SSOT)
|
||||
- See: reference/language/types.md — runtime truthiness, `+`/compare/equality semantics, and the role/limits of MIR type facts.
|
||||
|
||||
@ -2,6 +2,8 @@
|
||||
|
||||
本書は Nyash 言語の「フィールド可視性」と「デリゲーション(from/override)」の設計をまとめた仕様草案です。実装は段階的に進めます。
|
||||
|
||||
注: `init { ... }` は legacy のフィールド宣言(slot)です。新しい宣言モデル(stored/computed/once/birth_once)は `docs/reference/language/EBNF.md` を参照してください。
|
||||
|
||||
## 1. フィールド可視性(Blocks)
|
||||
- 構文
|
||||
```nyash
|
||||
@ -61,4 +63,3 @@
|
||||
- BoxRef/Handle 仕様: `docs/reference/plugin-system/boxref-behavior.md`
|
||||
- nyash.toml v2.1–v2.2: `docs/reference/plugin-system/nyash-toml-v2_1-spec.md`
|
||||
- 実装箇所(予定): `src/parser/declarations/box_definition.rs`, `src/core/model.rs`, `src/interpreter/expressions/access.rs`, `src/mir/*`, `src/backend/vm.rs`
|
||||
|
||||
|
||||
@ -238,6 +238,18 @@ box Node {
|
||||
}
|
||||
```
|
||||
|
||||
**Legacy syntax** (still supported, Phase 285A1.2):
|
||||
- `init { weak parent }` — old syntax; superseded by direct `weak parent` declaration
|
||||
- Both syntaxes behave identically and populate the same weak_fields set
|
||||
- New code should use `weak field_name` directly for clarity
|
||||
|
||||
**Visibility blocks** (Phase 285A1.3):
|
||||
- `weak` is allowed inside visibility blocks: `public { weak parent }`
|
||||
|
||||
**Sugar syntax** (Phase 285A1.4):
|
||||
- `public weak parent` is equivalent to `public { weak parent }`
|
||||
- `private weak parent` is equivalent to `private { weak parent }`
|
||||
|
||||
## 5) Cycles and GC (language-level policy)
|
||||
|
||||
### Cycles
|
||||
|
||||
@ -42,6 +42,7 @@ Semicolons and ASI (Automatic Semicolon Insertion)
|
||||
Truthiness (boolean context)
|
||||
- SSOT: `reference/language/types.md`(runtime truthiness)
|
||||
- 実行上は `Bool/Integer/Float/String/Void` が中心。`BoxRef` は一部のコアBoxのみ許可され、その他は `TypeError`(Fail-Fast)。
|
||||
- `null` は `void` の別名(構文糖衣)。どちらも boolean context では `TypeError`。
|
||||
|
||||
Equality and Comparison
|
||||
- SSOT: `reference/language/types.md`(`==`/`!=` と `< <= > >=` の runtime 仕様)
|
||||
|
||||
@ -23,6 +23,19 @@ Terminology (SSOT):
|
||||
- **Runtime type**: what the VM executes on (`VMValue`).
|
||||
- **MIR type facts**: builder annotations (`MirType`, `value_types`, `value_origin_newbox`, `TypeCertainty`).
|
||||
|
||||
### Null vs Void (SSOT)
|
||||
|
||||
Nyash has two surface literals: `null` and `void`.
|
||||
|
||||
SSOT policy:
|
||||
- `null` is the source-level “none” literal used in APIs like `toIntOrNull()` and optional returns.
|
||||
- `void` is the “no value” literal (and is also the value produced by expressions/statements that do not yield a value).
|
||||
- At runtime, both are represented as the same “no value” concept (`Void`). Treat `null` as a syntax-level alias of `void` unless a backend explicitly documents a difference (differences are bugs).
|
||||
|
||||
Practical consequence:
|
||||
- `x == null` and `x == void` are equivalent checks.
|
||||
- `WeakRef.weak_to_strong()` returns `null` on failure (i.e., `void` / none).
|
||||
|
||||
---
|
||||
|
||||
## 2. Variables and Re-assignment
|
||||
@ -49,7 +62,7 @@ Runtime rule (SSOT) is implemented by `to_bool_vm` (`src/backend/abi_util.rs`):
|
||||
- `Integer` → `0` is false; non-zero is true
|
||||
- `Float` → `0.0` is false; non-zero is true
|
||||
- `String` → empty string is false; otherwise true
|
||||
- `Void` → **TypeError** (fail-fast)
|
||||
- `Void` (`null` / `void`) → **TypeError** (fail-fast)
|
||||
- `BoxRef`:
|
||||
- bridge boxes only:
|
||||
- `BoolBox` / `IntegerBox` / `StringBox` are unboxed and coerced like their primitive equivalents
|
||||
|
||||
@ -4,13 +4,15 @@ Status: Stable (Stage‑3 surface for `local`), default strong references.
|
||||
|
||||
This document defines the variable model used by Hakorune/Nyash and clarifies how locals interact with blocks, memory, and references across VMs (Rust VM, Hakorune VM, LLVM harness).
|
||||
|
||||
For the lifecycle/finalization SSOT, see: `docs/reference/language/lifecycle.md`.
|
||||
|
||||
## Local Variables
|
||||
|
||||
- Syntax: `local name = expr`
|
||||
- Scope: Block‑scoped. The variable is visible from its declaration to the end of the lexical block.
|
||||
- Redeclaration: Writing `local name = ...` inside a nested block creates a new shadowing binding. Writing `name = ...` without `local` updates the nearest existing binding in an enclosing scope.
|
||||
- Mutability: Locals are mutable unless future keywords specify otherwise (e.g., `const`).
|
||||
- Lifetime: The variable binding is dropped at block end; any referenced objects live as long as at least one strong reference exists elsewhere.
|
||||
- Lifetime: The variable binding is dropped at block end (`}`); object lifetime/finalization is defined separately in `docs/reference/language/lifecycle.md`.
|
||||
|
||||
Notes:
|
||||
- Stage‑3 gate: Parsing `local` requires Stage‑3 to be enabled (`NYASH_PARSER_STAGE3=1` or equivalent runner profile).
|
||||
@ -27,8 +29,8 @@ This matches intuitive block‑scoped semantics (Lua‑like), and differs from P
|
||||
|
||||
## Reference Semantics (Strong/Weak)
|
||||
|
||||
- Default: Locals hold strong references to boxes/collections. Implementation uses reference counting (strong = ownership) with internal synchronization.
|
||||
- Weak references: Use `WeakBox` to hold a non‑owning (weak) reference. Weak refs do not keep the object alive; they can be upgraded to strong at use sites. Intended for back‑pointers and cache‑like links to avoid cycles.
|
||||
- Default: Locals hold strong references to boxes/collections.
|
||||
- Weak references: Use `weak(x)` (and fields that store `WeakRef`) to hold a non‑owning reference. Weak refs do not keep the object alive; they can be upgraded at use sites (see SSOT: `docs/reference/language/lifecycle.md`).
|
||||
- Typical guidance:
|
||||
- Locals and return values: strong references.
|
||||
- Object fields that create cycles (child→parent): weak references.
|
||||
|
||||
@ -343,14 +343,16 @@ i32 filebox_read(u32 instance_id, i32 size, u8** result, size_t* result_len) {
|
||||
|
||||
3. **ライフサイクル保証**
|
||||
- `birth()` → 各メソッド呼び出し → `fini()` の順序を保証
|
||||
- `fini()`は必ず呼ばれる(GC時またはプログラム終了時)
|
||||
- 循環参照による`fini()`遅延に注意
|
||||
- `fini()` は論理的終了(use-after-fini禁止)。自動呼び出しは実行経路/所有形態に依存しうるため、必要な資源(fd/socket等)は明示 `fini()` / `shutdown_plugins_v2()` で確実に解放する
|
||||
- 循環参照や共有(複数スコープに跨る参照)では `fini()` タイミングが遅延/未観測になりうるため、weak/singleton/明示finiで設計する
|
||||
- SSOT: `docs/reference/language/lifecycle.md`
|
||||
|
||||
### Nyash側の実装
|
||||
```rust
|
||||
impl Drop for PluginBox {
|
||||
fn drop(&mut self) {
|
||||
// Boxが破棄される時、必ずfiniを呼ぶ
|
||||
// 破棄時の best-effort cleanup(実行経路/所有形態によりタイミングは変わりうる)。
|
||||
// 言語仕様としては `fini()` は明示的に呼ぶ/`shutdown_plugins_v2()` で閉じるのが推奨。
|
||||
let result = self.plugin.invoke(
|
||||
self.handle.type_id,
|
||||
FINI_METHOD_ID, // 最大値のmethod_id
|
||||
@ -434,4 +436,4 @@ HTTPServerBox = "http-plugin" # SocketBoxが使えない!
|
||||
|
||||
- [BID-FFI仕様](./ffi-abi-specification.md)
|
||||
- [Everything is Box哲学](./everything-is-box.md)
|
||||
- [実装タスク](../../../予定/native-plan/issues/phase_9_75g_0_chatgpt_enhanced_final.md)
|
||||
- [実装タスク](../../../予定/native-plan/issues/phase_9_75g_0_chatgpt_enhanced_final.md)
|
||||
|
||||
@ -6,13 +6,14 @@
|
||||
NyashのBoxには「ユーザー定義Box」「ビルトインBox」「プラグインBox」があります。いずれもRAII(取得した資源は所有者の寿命で解放)に従いますが、プラグインBoxは共有やシングルトン運用があるため、追加ルールがあります。
|
||||
|
||||
## 共通ライフサイクル(ユーザー/ビルトイン/プラグイン)
|
||||
- インスタンスの寿命が尽きると、強参照フィールド(public/private)に対し順に `fini()` が呼ばれ解放(weak はスキップ)
|
||||
- `local` 変数のスコープを抜けると、そのスコープで生成されたインスタンスは解放対象
|
||||
- 明示的に `fini()` が呼ばれた場合も同様に後処理を実施
|
||||
- `fini()` は論理的な終了(use-after-fini禁止)であり、外部資源(fd/socket/native handle など)を決定的に解放するための SSOT です。
|
||||
- `local` のスコープを抜けると、その binding は drop されます(= その binding が保持していた strong 参照が 1 つ減る)。
|
||||
- その時点で「最後の strong 参照」になれば物理的な解放が起きますが、タイミングは実装依存です。
|
||||
- 共有・循環参照がありうるため、スコープ終了“だけ”に `fini()` を期待しないでください。必要な資源は `fini()` / `cleanup` / `shutdown_plugins_v2()` で明示的に閉じます。
|
||||
|
||||
補足:
|
||||
- これらは Nyash のスコープトラッカにより実施されます
|
||||
- 解放順は生成の逆順(LIFO)で、カスケード `fini` を保証します
|
||||
- 言語レベルの SSOT は `docs/reference/language/lifecycle.md` を参照してください(スコープ/所有/weak/`fini`/GC)。
|
||||
- `fini()` の中で「strong-owned フィールドを順に `fini()`」するカスケード設計は有用ですが、最終的な順序や禁止事項は SSOT に従います。
|
||||
|
||||
## プラグインBoxの特則(シングルトン)
|
||||
- シングルトン(`nyash.toml`)
|
||||
@ -21,8 +22,8 @@ NyashのBoxには「ユーザー定義Box」「ビルトインBox」「プラグ
|
||||
- シャットダウン時(`shutdown_plugins_v2()` など)に一括 `fini()` されます
|
||||
|
||||
補足:
|
||||
- Nyashは参照カウントを採用しません。解放は「スコープ終了」または「明示的`fini`」のみで決まります(自己責任モデル)。
|
||||
- プラグインBoxも同じルールです。スコープ終了時に`fini`され、以後の利用はエラー(Use after fini)。
|
||||
- Nyashの実装は Box 値を参照(共有)として扱います。物理的な生存は strong 参照の有無に依存しうる一方、`fini()` は論理的な終了(use-after-fini禁止)です。
|
||||
- プラグインBoxも同じルールです。`fini` 後の利用はエラー(Use after fini)。
|
||||
- 長寿命が必要なケースは「シングルトン」で運用してください(個別のBoxに特例は設けない)。
|
||||
|
||||
### 例: `nyash.toml` 抜粋
|
||||
|
||||
@ -89,20 +89,21 @@ fn test_weak_reference_mir_stability() {
|
||||
let source = r#"
|
||||
box Parent { init { child_weak } }
|
||||
box Child { init { data } }
|
||||
|
||||
|
||||
static box Main {
|
||||
main() {
|
||||
local parent = new Parent()
|
||||
local child = new Child(42)
|
||||
parent.child_weak = weak(child)
|
||||
|
||||
if parent.child_weak.isAlive() {
|
||||
print(parent.child_weak.get().data)
|
||||
|
||||
local c = parent.child_weak.weak_to_strong()
|
||||
if c != null {
|
||||
print(c.data)
|
||||
}
|
||||
}
|
||||
}
|
||||
"#;
|
||||
|
||||
|
||||
verify_mir_golden("weak_reference", source);
|
||||
}
|
||||
```
|
||||
@ -404,4 +405,4 @@ fi
|
||||
|
||||
*最終更新: 2025-08-14 - ChatGPT5推奨3点セット完成*
|
||||
|
||||
*Golden Dump Testing = Nyash品質保証の技術的基盤*
|
||||
*Golden Dump Testing = Nyash品質保証の技術的基盤*
|
||||
|
||||
Reference in New Issue
Block a user