Files
hakorune/docs/reference/language/EBNF.md
nyash-codex 4b6b75932c chore(phase152-b): Static method 宣言整理(箱化モジュール化)
- MainDetectionHelper で main() 検出ロジックを箱化
- Legacy "static method main" と Modern "static box Main { main() }" の両パターン対応
- stage1_run_min.hako を modern 形式に統一
- ドキュメント更新(quickstart 等で static box スタイルに統一)
- パーサ新構文追加なし(仕様統一性保持)
- 後方互換性維持(Stage-B ヘルパーで legacy もサポート)
- テスト結果: 全スモーク PASS

Phase 152-B: Static Method 宣言の整理(Stage-3 仕様統一)

実装パターン: 箱化モジュール化(Phase 133/134 継承)

修正ファイル:
- lang/src/compiler/entry/compiler_stageb.hako: MainDetectionHelper (+103 lines)
- lang/src/compiler/entry/compiler.hako: Legacy Stage-A コメント (+3 lines)
- apps/tests/stage1_run_min.hako: Modern syntax に統一 (-1 line)
- docs/development/selfhosting/quickstart.md: サンプルコード更新
- CURRENT_TASK.md: Phase 152-B 完了記録

MainDetectionHelper 設計:
- findMainBody(): Entry point
- tryLegacyPattern(): "static method main" detection
- tryModernPattern(): "static box Main { main() }" detection
- findPattern(): Pattern search helper
- extractBodyFromPosition(): Brace matching extraction

利点:
 明確な責任分離(各パターン検出が独立モジュール)
 テスタビリティ(各メソッド個別テスト可能)
 拡張性(新パターン追加時は新メソッド追加のみ)
 後方互換性(Legacy パターン削除は tryLegacyPattern 削除のみ)

テスト結果:
- stage1_run_min.hako: RC 0
- Selfhost depth-1: RC 0
- 全スモーク: 30/31 PASS (1 timeout は無関係)
2025-12-04 13:54:45 +09:00

148 lines
7.7 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Nyash Grammar (Stage2 EBNF)
Status: Fixed for Phase 15 Stage2. Parser implementations (Rust/Python/Nyash selfhost) should conform to this subset.
program := stmt* EOF
stmt := 'return' expr
| 'local' IDENT '=' expr
| 'if' expr block ('else' block)?
| 'loop' '('? expr ')' ? block
| expr ; expression statement
block := '{' stmt* '}'
expr := logic
logic := compare (('&&' | '||') compare)*
compare := sum (( '==' | '!=' | '<' | '>' | '<=' | '>=' ) sum)?
sum := term (('+' | '-') term)*
term := unary (('*' | '/') unary)*
unary := ('-' | '!' | 'not') unary | factor
factor := INT
| STRING
| IDENT call_tail*
| '(' expr ')'
| '(' assignment_expr ')' ; Stage3: grouped assignment as expression
| 'new' IDENT '(' args? ')'
| '[' args? ']' ; Array literal (Stage1 sugar, gated)
| '{' map_entries? '}' ; Map literal (Stage2 sugar, gated)
| match_expr ; Pattern matching (replaces legacy peek)
match_expr := 'match' expr '{' match_arm+ default_arm? '}'
match_arm := pattern guard? '=>' (expr | block) ','?
default_arm:= '_' '=>' (expr | block) ','?
pattern := '_'
| STRING | INT | 'true' | 'false' | 'null'
| IDENT '(' IDENT? ')' ; Type pattern e.g., StringBox(s)
| '[' (IDENT (',' '..' IDENT)? )? ']'
| '{' ( (STRING|IDENT) ':' IDENT (',' '..')? )? '}'
| pattern '|' pattern ; OR pattern (same arm)
guard := 'if' expr
map_entries := (STRING | IDENT) ':' expr (',' (STRING | IDENT) ':' expr)* [',']
call_tail := '.' IDENT '(' args? ')' ; method
| '(' args? ')' ; function call
args := expr (',' expr)*
; Stage3: grouped assignment expression
; `(x = expr)` だけを式として認める。値と型は右辺 expr と同じ。
assignment_expr := IDENT '=' expr
Notes
- ASI: Newline is the primary statement separator. Do not insert a semicolon between a closed block and a following 'else'.
- Semicolon (optional): When `NYASH_PARSER_ALLOW_SEMICOLON=1` is set, `;` is accepted as an additional statement separator (equivalent to newline). It is not allowed between `}` and a following `else`.
- Dowhile: not supported by design. Prefer a singleentry, precondition loop normalized via sugar (e.g., `repeat N {}` / `until cond {}`) to a `loop` with clear break conditions.
- Short-circuit: '&&' and '||' must not evaluate the RHS when not needed.
- Unary minus has higher precedence than '*' and '/'.
- IDENT names consist of [A-Za-z_][A-Za-z0-9_]*
- Array literal is enabled when syntax sugar is on (NYASH_SYNTAX_SUGAR_LEVEL=basic|full) or when NYASH_ENABLE_ARRAY_LITERAL=1 is set.
- Map literal is enabled when syntax sugar is on (NYASH_SYNTAX_SUGAR_LEVEL=basic|full) or when NYASH_ENABLE_MAP_LITERAL=1 is set.
- Identifier keys (`{name: v}`) are Stage3 and require either NYASH_SYNTAX_SUGAR_LEVEL=full or NYASH_ENABLE_MAP_IDENT_KEY=1.
- Pattern matching: `match` replaces legacy `peek`. MVP supports wildcard `_`, literals, simple type patterns, fixed/variadic array heads `[hd, ..tl]`, simple map key extract `{ "k": v, .. }`, OR patterns, and guards `if`.
## Box Members (Phase15, env gate: NYASH_ENABLE_UNIFIED_MEMBERS; default ON)
This section adds a minimal grammar for Box members (a unified member model) without changing JSON v0/MIR. Parsing is controlled by env `NYASH_ENABLE_UNIFIED_MEMBERS` (default ON; set `0/false/off` to disable).
```
box_decl := 'box' IDENT '{' member* '}'
member := stored
| computed
| once_decl
| birth_once_decl
| method_decl
| block_as_role ; nyash-mode (block-first) equivalent
stored := IDENT ':' TYPE ( '=' expr )?
; stored property (read/write). No handlers supported.
computed := IDENT ':' TYPE ( '=>' expr | block ) handler_tail?
; computed property (readonly). Recomputes on each read.
once_decl := 'once' IDENT ':' TYPE ( '=>' expr | block ) handler_tail?
; lazy once. First read computes and caches; later reads return cached value.
birth_once_decl:= 'birth_once' IDENT ':' TYPE ( '=>' expr | block ) handler_tail?
; eager once. Computed during construction (before user birth), in declaration order.
method_decl := IDENT '(' params? ')' ( ':' TYPE )? block handler_tail?
; nyash-mode (block-first) variant — gated with NYASH_ENABLE_UNIFIED_MEMBERS=1
block_as_role := block 'as' ( 'once' | 'birth_once' )? IDENT ':' TYPE
handler_tail := ( catch_block )? ( cleanup_block )?
catch_block := 'catch' ( '(' ( IDENT IDENT | IDENT )? ')' )? block
cleanup_block := 'cleanup' block
; Stage3 (Phase 1 via normalization gate NYASH_CATCH_NEW=1)
; Postfix handlers for expressions and calls
postfix_catch := primary_expr 'catch' ( '(' ( IDENT IDENT | IDENT )? ')' )? block
postfix_cleanup := primary_expr 'cleanup' block
```
Semantics (summary)
- stored: O(1) slot read; write via assignment. Initializer (if present) evaluates at construction once.
- computed: readonly; each read evaluates the block; assignment is an error unless a setter is explicitly defined.
- once: first read evaluates the block and caches the value; subsequent reads return the cached value. On exception without a `catch`, the property becomes poisoned and rethrows on later reads (no retries).
- birth_once: evaluated before the user `birth` body, in declaration order; exceptions without a `catch` abort construction; cycles between `birth_once` members are an error.
- handlers: `catch/cleanup` are permitted for computed/once/birth_once/method blocks (Stage3), not for stored.
Lowering (no JSON v0 change)
- stored → slot
- computed → synthesize `__get_name():T { try body; catch; finally }`; reads of `obj.name` become `obj.__get_name()`
- once → add `__name: Option<T>` and emit `__get_name()` with firstread initialization; on uncaught exception mark poisoned and rethrow on subsequent reads
- 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
## Stage3 (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)?`
- MVP policy: single `catch` per `try`
- `(Type var)` or `(var)` or `()` are accepted for the catch parameter。
- Blockpostfix catch/cleanupPhase 15.5
- `block_catch := '{' stmt* '}' ('catch' '(' (IDENT IDENT | IDENT | ε) ')' block)? ('cleanup' block)?`
- Applies to standalone block statements. Do not attach to `if/else/loop` structural blocks (wrap with a standalone block when needed).
- Gate: `NYASH_BLOCK_CATCH=1` (or `NYASH_PARSER_STAGE3=1`).
- throw
- `throw_stmt := 'throw' expr`
- Methodlevel postfix catch/cleanupPhase 15.6, gated
- `method_decl := 'method' IDENT '(' params? ')' block ('catch' '(' (IDENT IDENT | IDENT | ε) ')' block)? ('cleanup' block)?`
- Gate: `NYASH_METHOD_CATCH=1`(または `NYASH_PARSER_STAGE3=1` と同梱)
- Memberlevel postfix catch/cleanupPhase 15.6, gated
- Applies to computed/once/birth_once in the unified member model: see “Box Members”.
- Gate: `NYASH_PARSER_STAGE3=1` (shared). Stored members do not accept handlers.
These constructs remain experimental; behaviour may degrade to noop in some backends until runtime support lands, as tracked in CURRENT_TASK.md.