prometeu-studio/docs/compiler/pbs/decisions/Dynamic Semantics - Branch Selection Decision.md
2026-03-24 13:42:37 +00:00

129 lines
3.8 KiB
Markdown

# Dynamic Semantics - Branch Selection Decision
Status: Accepted (Implemented)
Cycle: Initial branch-selection closure pass
## 1. Context
PBS v1 needs a closed runtime contract for `if` and `switch` before the dynamic semantics spec can be completed.
The remaining questions were:
- whether conditions and selectors are evaluated once,
- whether non-selected branches evaluate at all,
- which selector categories are admitted for `switch`,
- and whether branch selection itself may trap.
## 2. Decision
PBS v1 adopts the following branch-selection rules:
1. `if` evaluates its condition exactly once.
2. `switch` evaluates its selector exactly once.
3. Only the selected branch or arm executes.
4. Non-selected branches and arms perform no evaluation.
5. `if` and `switch` are trap-free by themselves; only selected subexpressions may trap.
6. `switch` is limited to statically discriminable selector categories.
7. `switch` does not accept `result`, `error`, structs, string objects, or heap-backed types as selectors in v1.
## 3. `if`
For:
```text
if cond { then_block } else { else_block }
```
the runtime behaves as follows:
1. evaluate `cond` exactly once,
2. if it yields `true`, execute only `then_block`,
3. if it yields `false`, execute only `else_block`.
The non-selected branch is not evaluated, even partially.
Any trap associated with `if` arises only from:
- evaluating `cond`,
- or executing the selected branch.
## 4. `switch`
### 4.1 Selector evaluation
For:
```text
switch selector { ... }
```
the runtime:
1. evaluates `selector` exactly once,
2. determines the matching arm using the canonical matching rule for the selector category,
3. executes exactly one selected arm.
No non-selected arm is evaluated.
### 4.2 Admitted selector categories
In v1, `switch` is restricted to selector categories with static, deterministic matching behavior.
These include:
- literal-comparable scalar values,
- enum values,
- `str` values with canonical static identity,
- and other compile-time-constant-compatible selector categories only if explicitly admitted elsewhere.
`switch` does not accept:
- `result` values,
- `error` values,
- structs,
- string object/reference types distinct from canonical `str`,
- or heap-backed selector categories.
Dynamic or structural matching belongs to a future `match`-style construct rather than to `switch`.
### 4.3 Matching rule
`switch` arm selection is exact and deterministic for the admitted selector type.
- Enum selectors match by canonical enum-case identity.
- Scalar selectors match by the exact equality rule already defined for that scalar category.
- `str` selectors match by canonical static string identity rather than by heap-object comparison.
`switch` does not perform structural matching, guard evaluation, or user-defined equality dispatch.
## 5. Invariants
- `if` and `switch` never evaluate more than one branch or arm.
- Branch selection is deterministic for the same selector value.
- `switch` remains a static discriminant-selection construct, not a result/error-processing construct.
- Error processing with logic belongs to `handle`, not to `switch`.
## 6. Explicit Non-Decisions
This decision record does not yet close:
- the final future design of `match`,
- whether additional scalar-like selector categories will be admitted later,
- the complete memory/cost wording associated with selector evaluation.
## 7. Spec Impact
This decision should feed at least:
- `docs/pbs/specs/9. Dynamic Semantics Specification.md`
- `docs/pbs/specs/4. Static Semantics Specification.md`
- `docs/pbs/specs/3. Core Syntax Specification.md`
## 8. Validation Notes
The intended split is:
- `if` and `switch` perform static, deterministic branch selection,
- `handle` processes modeled `result` errors,
- future dynamic or structural branching belongs to `match`, not to `switch`.