pyvm: split op handlers into ops_core/ops_box/ops_ctrl; add ops_flow + intrinsic; delegate vm.py without behavior change
net-plugin: modularize constants (consts.rs) and sockets (sockets.rs); remove legacy commented socket code; fix unused imports mir: move instruction unit tests to tests/mir_instruction_unit.rs (file lean-up); no semantic changes runner/pyvm: ensure using pre-strip; misc docs updates Build: cargo build ok; legacy cfg warnings remain as before
This commit is contained in:
49
docs/guides/core-principles.md
Normal file
49
docs/guides/core-principles.md
Normal file
@ -0,0 +1,49 @@
|
||||
# Nyash Core Principles — Minimal Syntax, Zero Runtime, Visual Flow
|
||||
|
||||
Status: design-only during freeze (no implementation changes)
|
||||
|
||||
Core (one page summary)
|
||||
- Minimal syntax: `{ … }` + `->` + `|args|` or `_` for flow; guard chains as the canonical first-match form. No new `match` construct; normalize instead.
|
||||
- Zero-runtime lowering: always desugar to `let/if/call/ret/phi`. No new opcodes, no implicit closures.
|
||||
- Capture policy: capture by reference by default; mutation requires `mut` on the captured binding. Captures remain within the defining scope.
|
||||
- ASI/format: treat `->` as a low-precedence line-continue. Formatter aligns arrows vertically.
|
||||
|
||||
Before/After (normalize view)
|
||||
- Each example documents Ny → normalized Ny → MIR intent (design-only):
|
||||
1) Flow serial: `{read} -> { |x| validate(x) } -> { |x| save(x) }`
|
||||
2) Guard chain: `guard c1 -> {A}; guard c2 -> {B}; else -> {C}`
|
||||
3) If horizontal: `if cond -> {A} else -> {B}`
|
||||
4) Range pattern: `guard ch in '0'..'9' -> { ... }`
|
||||
5) Digit helper: `acc = acc*10 + ch.toDigitOrNull()` (null-guarded)
|
||||
|
||||
nyfmt alignment (visual flow)
|
||||
```
|
||||
{ fetch() }
|
||||
-> { validate(_) }
|
||||
-> { save(_) }
|
||||
```
|
||||
|
||||
Domain demos (≤20 lines each)
|
||||
- ETL pipeline: `read -> validate -> normalize -> save`
|
||||
- Text/number parse: `guard ch in '0'..'9' -> { acc = acc*10 + ch.toDigitOrNull() }`
|
||||
- Mini state machine: guard-first horizontal description with `else` fallback
|
||||
|
||||
Observability (spec hooks; design-only)
|
||||
- `NYASH_SCOPE_TRACE=1|json`: enter/exit + captures (JSONL: `sid`, `caps`, `ret`).
|
||||
- `NYASH_FLOW_TRACE=1`: desugared steps like `t0=B0(); t1=B1(t0);`.
|
||||
|
||||
Runtime/API additions (docs-only at freeze)
|
||||
- `StringBox/Utf8Cursor`: `toDigitOrNull(base=10)`, `toIntOrNull()` — compile to simple comparisons/arithmetic.
|
||||
- Guard sugar: Range (`'0'..'9'`) and CharClass (`Digit`, `AZ`, `az`, `Alnum`, `Space`) — compile to bound checks.
|
||||
|
||||
Acceptance & guardrails (freeze)
|
||||
- “No new grammar beyond sugar” and “no new VM opcodes” as hard rules during freeze.
|
||||
- Golden texts (Ny → MIR fragments) to lock compatibility where practical.
|
||||
- Lint proposals are documentation-only: single-use scope, long `->` chains, duplicated side effects.
|
||||
|
||||
Related docs
|
||||
- proposals/scope-reuse.md — local scope reuse blocks (MVP)
|
||||
- design/flow-blocks.md — arrow flow + anonymous blocks
|
||||
- reference/language/match-guards.md — guard chains + range/charclass sugar
|
||||
- reference/language/strings.md — UTF‑8 first; proposed digit helpers
|
||||
|
||||
88
docs/guides/exception-handling.md
Normal file
88
docs/guides/exception-handling.md
Normal file
@ -0,0 +1,88 @@
|
||||
Exception Handling — Postfix catch / cleanup (Stage‑3)
|
||||
|
||||
Summary
|
||||
- Nyash adopts a flatter, postfix-first exception style:
|
||||
- try is deprecated. Use postfix `catch` and `cleanup` instead.
|
||||
- `catch` = handle exceptions from the immediately preceding expression/call.
|
||||
- `cleanup` = always-run finalization (formerly finally), regardless of success or failure.
|
||||
- This matches the language’s scope unification and keeps blocks shallow and readable.
|
||||
|
||||
Status
|
||||
- Phase 1: normalization sugar(既存)
|
||||
- `NYASH_CATCH_NEW=1` でコア正規化パスが有効化。
|
||||
- 後置フォームは内部 `TryCatch` AST に変換され、既存経路で降下。
|
||||
- 実行時コストはゼロ(意味論不変)。
|
||||
- Phase 2(実装済み・Stage‑3ゲート)
|
||||
- パーサが式レベルの後置 `catch/cleanup` を直接受理。
|
||||
- ゲート: `NYASH_PARSER_STAGE3=1`
|
||||
- 糖衣正規化はそのまま併存(関数糖衣専用)。キーワード直受理と二重適用はしない設計。
|
||||
|
||||
Syntax (postfix)
|
||||
- Expression-level postfix handlers (Stage‑3):
|
||||
- `expr catch(Type e) { /* handle */ }`
|
||||
- `expr catch { /* handle (no variable) */ }`
|
||||
- `expr cleanup { /* always-run */ }`
|
||||
- Combine: `expr catch(Type e){...} cleanup{...}`
|
||||
- Method/function calls are just expressions, so postfix applies:
|
||||
- `call(arg1, arg2) catch(Error e) { log(e) }`
|
||||
- `obj.method(x) cleanup { obj.release() }`
|
||||
|
||||
Precedence and chaining
|
||||
- Postfix `catch`/`cleanup` binds to the immediately preceding expression (call/chain result), not to the whole statement.
|
||||
- For long chains, we recommend parentheses to make intent explicit:
|
||||
- `(obj.m1().m2()) catch { ... }`
|
||||
- `f(a, b) catch { ... } cleanup { ... }`
|
||||
- Parser rule (Stage‑3): postfix attaches once at the end of a call/chain and stops further chaining on that expression.
|
||||
|
||||
Diagram (conceptual)
|
||||
```
|
||||
// before (parse)
|
||||
obj.m1().m2() catch { H } cleanup { C }
|
||||
|
||||
// precedence (binding)
|
||||
obj.m1().[ m2() ↖ binds to this call ] catch { H } cleanup { C }
|
||||
|
||||
// normalization (conceptual AST)
|
||||
TryCatch {
|
||||
try: [ obj.m1().m2() ],
|
||||
catch: [ (type:Any, var:None) -> H ],
|
||||
finally: [ C ]
|
||||
}
|
||||
```
|
||||
|
||||
Normalization (Phase 1)
|
||||
- With `NYASH_CATCH_NEW=1`, postfix sugar is transformed into legacy `TryCatch` AST:
|
||||
- `EXPR catch(T e){B}` → `TryCatch { try_body:[EXPR], catch:[(T,e,B)], finally:None }`
|
||||
- `EXPR cleanup {B}` → `TryCatch { try_body:[EXPR], catch:[], finally:Some(B) }`
|
||||
- Multiple `catch` are ordered top-to-bottom; first matching type handles the error.
|
||||
- Combined `catch ... cleanup ...` expands to a single `TryCatch` with both blocks.
|
||||
- Lowering uses the existing builder (`cf_try_catch`) which already supports cleanup semantics.
|
||||
|
||||
Semantics
|
||||
- catch handles exceptions from the immediately preceding expression only.
|
||||
- cleanup is always executed regardless of success/failure (formerly finally).
|
||||
- Multiple catch blocks match by type in order; the first match is taken.
|
||||
- In loops, `break/continue` cooperate with cleanup: cleanup is run before leaving the scope.
|
||||
|
||||
Migration notes
|
||||
- try is deprecated: prefer postfix `catch/cleanup`.
|
||||
- Member-level handlers (computed/once/birth_once/method) keep allowing postfix `catch/cleanup` (Stage‑3), unchanged.
|
||||
- Parser acceptance of postfix at expression level will land in Phase 2; until then use the gate for normalization.
|
||||
|
||||
Examples
|
||||
```
|
||||
// Postfix catch on a call
|
||||
do_work() catch(Error e) { env.console.log("error: " + e) }
|
||||
|
||||
// Always-run cleanup
|
||||
open_file(path) cleanup { env.console.log("closed") }
|
||||
|
||||
// Combined
|
||||
connect(url)
|
||||
catch(NetworkError e) { env.console.warn(e) }
|
||||
cleanup { env.console.log("done") }
|
||||
|
||||
// Stage‑3 parser gate quick smoke (direct acceptance)
|
||||
// NYASH_PARSER_STAGE3=1 ./target/release/nyash --backend vm \
|
||||
// apps/tests/macro/exception/expr_postfix_direct.nyash
|
||||
```
|
||||
46
docs/guides/language-core-and-sugar.md
Normal file
46
docs/guides/language-core-and-sugar.md
Normal file
@ -0,0 +1,46 @@
|
||||
# Nyash: Core Minimal + Strong Sugar
|
||||
|
||||
> 最小のコア言語に、強力な糖衣構文を重ねて「書きやすさ」と「0コスト正規化」を両立する方針です。
|
||||
|
||||
## Core(最小)
|
||||
- 制御: `if`, `loop(condition) { … }`, `break`, `continue`(単一入口・先頭条件)
|
||||
- 式: `const/binop/compare/branch/jump/ret/phi`、`call/boxcall`
|
||||
- 単項: `-x`, `!x` / `not x`(真偽は i64 0/1 へ正規化)
|
||||
- 例外: `try/catch/cleanup`(postfix 版は正規化で TryCatch に降下)
|
||||
|
||||
設計上の非採用
|
||||
- do‑while: 不採用(先頭条件原則)。代替は糖衣で表現→先頭条件へ正規化。
|
||||
|
||||
### 演算子とループの方針(要約)
|
||||
- 単項 not(`!`)は採用(既存の `not` と同義)。
|
||||
- do‑while は非採用(明確性と正規化単純性を優先)。
|
||||
- ループは LoopForm 正規化に合わせて糖衣→正規形に落とす(break/continue を含む)。
|
||||
|
||||
## Sugar(強く・美しく・0コスト)
|
||||
- repeat N { … }
|
||||
- 正規化: `i=0; while(i<N){ …; i=i+1 }`(`loop`に降下)
|
||||
- until cond { … }
|
||||
- 正規化: `while(!cond){ … }`(`!` は Compare(Eq,0) へ)
|
||||
- for i in A..B { … }
|
||||
- 正規化: 範囲生成なしでカウンタ while へ
|
||||
- foreach x in arr { … }
|
||||
- 正規化: `i=0; while(i < arr.size()){ x=arr.get(i); …; i=i+1 }`
|
||||
- 文字列補間: `"hello ${name}"` → `"hello " + name`
|
||||
- 三項: `cond ? a : b` → `if/else + PHI`
|
||||
- 論理代入: `a ||= b` / `a &&= b` → `if(!a) a=b` / `if(a) a=b`
|
||||
|
||||
いずれも「意味論を変えずに」`loop/if` へ降下します。MIR/LLVM/Cranelift の下層は常にコア形にのみ対応すればよく、認知負荷を小さく保てます。
|
||||
|
||||
## 実装ガイド(Rust/PyVM共通)
|
||||
- Parser は糖衣の表層を受理し、Normalize(前段)で 0コストに正規化→ MIR 降下。
|
||||
- PyVM は正規化後の MIR を実行(P0 機能のみ実装)。
|
||||
- LLVM は PHI/SSA 衛生を守る。空PHIは不可、PHIはブロック先頭。
|
||||
|
||||
## Profiles(実行プロファイル・方針)
|
||||
- dev: 糖衣ON/デバッグON(作業向け)
|
||||
- lite: 糖衣OFF/静音(軽量)
|
||||
- ci: 糖衣ON/strict/静音(最小スモークのみ)
|
||||
|
||||
将来の拡張
|
||||
- 文字列補間/複数行/安全アクセスなどの糖衣は、常に正規化→コア形(if/loop)へ降下していきます。
|
||||
- 例外の後処理は `cleanup` に統一し、`defer` 的表現は糖衣→`cleanup` へ。
|
||||
@ -1,39 +1,31 @@
|
||||
# ScopeBox(コンパイル時メタ)設計ガイド
|
||||
ScopeBox and MIR Scope Hints (Dev/CI option)
|
||||
|
||||
目的
|
||||
- スコープ境界・defer・capabilities を“箱(Box)”のメタとして表現しつつ、最終的な実行物ではゼロコストにする。
|
||||
- LoopForm(ループのみキャリア整形)と責務分離し、If/Match は合流点正規化(join変数+単一PHI群)に限定する。
|
||||
Overview
|
||||
- ScopeBox is an optional, compile-time-only wrapper that makes lexical scopes explicit in the AST for diagnostics and macro visibility. It is a no-op for execution: MIR lowering treats ScopeBox like a normal block and semantics are unchanged.
|
||||
|
||||
基本方針
|
||||
- ScopeBox は“消える箱”。AST/マクロ段階で Block に属性を付与し、MIR ではヒントとして解釈、IR では完全に剥がす。
|
||||
- ループを伴わないスコープを LoopForm に持ち込まない(0回ループ化はしない)。
|
||||
How to enable
|
||||
- Inject ScopeBox wrappers during core normalization by setting:
|
||||
- `NYASH_SCOPEBOX_ENABLE=1`
|
||||
- Injection points:
|
||||
- If.then / If.else bodies
|
||||
- Loop.body
|
||||
- Bare blocks are represented by `Program { statements }` and already get ScopeEnter/ScopeLeave hints.
|
||||
|
||||
属性とヒント(MVP)
|
||||
- AST(マクロ内部表現)
|
||||
- Block.attrs.scope: { id, name, caps?: {io,net,env}, defer?: [Call…], diag?: {...} }
|
||||
- 備考: 現段階では属性はマクロ内で保持するだけ。MIR 降下時にヒントへ写すのが目標。
|
||||
- MIR(ヒントのみ/構造不変)
|
||||
- hint.scope_enter(id) / hint.scope_leave(id)
|
||||
- hint.defer(list) ・・・ 静的展開(cleanup合流)に用いる
|
||||
- hint.join_result(var) ・・・ If/Match の合流結果を明示
|
||||
- hint.loop_carrier(vars...) ・・・ ループヘッダで同一PHI群に導く
|
||||
- hint.no_empty_phi(検証)
|
||||
- IR(Release)
|
||||
- すべての hint は生成前に剥離。追加命令は一切残らない。
|
||||
MIR Scope Hints (unified env)
|
||||
- Configure hint output with a single env using a pipe-style syntax:
|
||||
- `NYASH_MIR_HINTS="<target>|<filters>..."`
|
||||
- Targets:
|
||||
- `trace` or `stderr`: print human-friendly hints to stderr
|
||||
- `jsonl=<path>` or a file path: append one JSON object per line
|
||||
- Filters:
|
||||
- `all` (default), `scope`, `join`, `loop`, `phi`
|
||||
- Examples:
|
||||
- `NYASH_MIR_HINTS="trace|all"`
|
||||
- `NYASH_MIR_HINTS="jsonl=tmp/hints.jsonl|scope|join"`
|
||||
- `NYASH_MIR_HINTS="tmp/hints.jsonl|loop"`
|
||||
- Back-compat:
|
||||
- `NYASH_MIR_TRACE_HINTS=1` is still accepted (equivalent to `trace|all`).
|
||||
|
||||
パイプライン
|
||||
1) Parse → Macro(If/Match 正規化、Scope 属性付与)
|
||||
2) LoopForm(while/for/foreach のみ、キャリア整形)
|
||||
3) Resolve → MIR Lower(ヒント埋め、defer静的展開)
|
||||
4) 検証(PHI先頭/空PHI無し)→ ヒント剥離 → Backend
|
||||
|
||||
受け入れ基準(Release)
|
||||
- IR に scope/hint 名が一切出現しない。
|
||||
- LoopForm ケースはヘッダ先頭に PHI がまとまり、空PHI無し。
|
||||
- If/Match 式は join 変数 1 個で収束(空PHI無し)。
|
||||
|
||||
今後の予定(短期)
|
||||
- マクロ: @scope/@defer 記法のスキャフォールド → AST 属性付与(挙動は現状どおり、構造変更無し)。
|
||||
- MIR: hint.* の型と注入ポイント定義(降下部のスケルトン、既定は no-op)。
|
||||
- スモーク: IR に scope/hint 名が残らないこと、PHI 健全性が保たれることを確認。
|
||||
Zero-cost policy
|
||||
- ScopeBox is removed implicitly during MIR lowering (treated as a block). ScopeEnter/ScopeLeave hints are observational only. Execution and IR are unchanged.
|
||||
|
||||
|
||||
26
docs/guides/testing-matrix.md
Normal file
26
docs/guides/testing-matrix.md
Normal file
@ -0,0 +1,26 @@
|
||||
# Testing Matrix — Mapping Specs to Tests
|
||||
|
||||
Purpose
|
||||
- Map invariants/constraints to the concrete tests (smokes/goldens/unit) that verify them.
|
||||
|
||||
Categories
|
||||
- PHI hygiene (LLVM)
|
||||
- ir_phi_empty_check.sh — no empty PHIs
|
||||
- ir_phi_hygiene_if_phi_ret.sh — PHIs at block head with if/ret pattern
|
||||
- MIR hints (VM)
|
||||
- hints_trace_smoke.sh — basic scope enter/leave
|
||||
- hints_join_result_* — join diagnostics for 2/3 vars
|
||||
- hints_scope_trycatch_smoke.sh — try/catch scopes
|
||||
- Match normalization (VM/goldens)
|
||||
- match_literal_basic / literal_three_arms output smokes
|
||||
- match_guard_literal_or / type_basic_min goldens
|
||||
- Exceptions (VM)
|
||||
- expr_postfix_catch_cleanup_output_smoke.sh — postfix direct parser
|
||||
- loop_postfix_catch_cleanup_output_smoke.sh — combined with loops
|
||||
- LoopForm break/continue (VM)
|
||||
- loopform_continue_break_output_smoke.sh — basic continue/break
|
||||
- loop_nested_if_ctrl_output_smoke.sh — nested if inside loop
|
||||
- loop_nested_block_break_output_smoke.sh — nested bare block with break
|
||||
|
||||
Maintenance
|
||||
- When adding an invariant or lifting a constraint, update this matrix and link the tests.
|
||||
@ -29,7 +29,7 @@ Backward compat (deprecated)
|
||||
MacroCtx (MVP)
|
||||
- Rust側に最小の `MacroCtx` と `MacroCaps` を用意(将来のAPI統合のため)。
|
||||
- フィールド/メソッド(MVP):
|
||||
- `MacroCtx::from_env()` → 環境からcapabilitiesを組み立て
|
||||
- `MacroCtx::from_env()` → 環境からcapabilitiesを組み立て(親プロセス)
|
||||
- `ctx.gensym(prefix)` → 衛生識別子生成
|
||||
- `ctx.report(level, message)` → 開発用レポート(標準エラー)
|
||||
- `ctx.get_env(key)` → 環境取得(`NYASH_MACRO_CAP_ENV=1` のときのみ)
|
||||
@ -88,6 +88,8 @@ CLI プロファイル(推奨)
|
||||
|
||||
Notes
|
||||
- Built-in child route (stdin JSON -> stdout JSON) remains available when `NYASH_MACRO_BOX_CHILD_RUNNER=0`.
|
||||
- Internal child can receive ctx via env: `NYASH_MACRO_CTX_JSON='{"caps":{"io":false,"net":false,"env":true}}'`
|
||||
- CLI からも指定可能: `--macro-ctx-json '{"caps":{"io":false,"net":false,"env":true}}'`
|
||||
- Strict mode: `NYASH_MACRO_STRICT=1` (default) fails build on macro child error/timeout; set `0` to fallback to identity.
|
||||
- Timeout: `NYASH_NY_COMPILER_TIMEOUT_MS` (default `2000`).
|
||||
|
||||
|
||||
Reference in New Issue
Block a user