# PBS Dynamic Semantics Specification

Status: Draft v1 (Temporary)  
Applies to: runtime-observable behavior of PBS core programs

## 1. Purpose

This document defines the normative dynamic semantics of PBS core.

Its purpose is to make runtime behavior convergent across implementations by fixing:

- execution ordering,
- runtime evaluation of expressions and statements,
- abrupt completion and propagation behavior,
- runtime behavior of effect surfaces such as `optional` and `result`,
- the execution boundary between ordinary PBS code, callbacks, contract calls, and host-backed calls.

## 2. Scope

This document defines:

- the observable execution model of PBS core,
- evaluation order for expressions, statements, and blocks,
- runtime branch selection for `if` and `switch`,
- runtime application behavior for `apply`, call sugar, methods, contracts, callbacks, and host-backed call surfaces,
- runtime behavior of `optional`, `result<E>`, `else`, `!`, and `handle`,
- abrupt completion (`return`, `break`, `continue`) and trap propagation,
- determinism requirements that affect execution behavior.

This document does not define:

- static typing or overload resolution rules,
- GC algorithm internals,
- exact IR shape or lowering passes,
- diagnostics catalog wording,
- the full PBX binary format.

## 3. Authority and Precedence

Normative precedence:

1. Runtime authority (`docs/specs/hardware/topics/chapter-2.md`, `chapter-3.md`, `chapter-9.md`, `chapter-12.md`, `chapter-16.md`)
2. Bytecode authority (`docs/specs/bytecode/ISA_CORE.md`)
3. `3. Core Syntax Specification.md`
4. `4. Static Semantics Specification.md`
5. This document

If a rule here conflicts with higher authority, it is invalid.

## 4. Normative Inputs

This document depends on, at minimum:

- `1. Language Charter.md`
- `3. Core Syntax Specification.md`
- `4. Static Semantics Specification.md`
- `5. Manifest, Stdlib, and SDK Resolution Specification.md`
- `6.2. Host ABI Binding and Loader Resolution Specification.md`

This document integrates the following accepted decisions:

- `discussion/lessons/DSC-0007-pbs-learn-to-discussion-lessons-migration/LSN-0020-pbs-runtime-values-identity-memory-boundaries-legacy.md`
- `discussion/lessons/DSC-0007-pbs-learn-to-discussion-lessons-migration/LSN-0022-pbs-globals-lifecycle-and-published-entrypoint-legacy.md`

## 5. Already-Settled Inputs

The following inputs are already fixed elsewhere and must not be contradicted here:

- PBS prioritizes determinism and compatibility over ergonomics when the two conflict.
- `FRAME_SYNC`-based execution semantics remain preserved.
- No non-deterministic async execution model is part of PBS v1.
- Function application is defined on the canonical `apply` surface, with call sugar desugaring to `apply`.
- `optional T` function fallthrough yields `none`.
- `result<E>` function fallthrough is a compile-time error.
- `ok(...)` and `err(...)` are special result-flow forms rather than ordinary first-class runtime constructors.
- Lifecycle bootstrap is one-shot and fail-fast.
- `[Frame]` denotes the logical userland frame root, not the physical published entrypoint by itself.

## 6. Execution Baseline

PBS execution is single-threaded per program instance in v1.

User-visible execution is deterministic and does not expose concurrent interleaving.

User-visible sequencing is defined by:

- evaluation order,
- branch selection,
- abrupt completion,
- result propagation,
- trap propagation,
- and host-call boundaries.

VM-internal frame layout, temporary storage, and lowering steps are not observable unless they change one of the semantic effects above.

`FRAME_SYNC` is the only normative safepoint in PBS v1.

## 6.1 Lifecycle bootstrap

Executable PBS programs have a logical bootstrap sequence before ordinary frame execution.

Normative order:

1. materialize globals for each file according to dependency order,
2. execute that file's `[Init]`, if present,
3. compose those steps into one synthetic module init per module,
4. execute project init, if present,
5. then invoke the userland callable marked with `[Frame]`.

Lifecycle bootstrap is one-shot:

- no automatic retry occurs after boot failure,
- failure during module init aborts boot,
- failure during project init aborts boot.

## 6.2 Logical frame root and physical wrapper

PBS distinguishes the logical frame root from the physical published entrypoint:

- the userland callable marked with `[Frame]` is the logical frame root,
- the compiler-published synthetic wrapper is the physical executable root,
- the wrapper owns final `FRAME_RET`,
- and the wrapper invokes the logical frame root after bootstrap is complete.

Nominal manifest metadata does not participate in this runtime boot choice.

## 7. Evaluation Order and Single Evaluation

### 7.1 Default rule

The default evaluation rule is strict left-to-right unless a construct explicitly states otherwise.

### 7.2 Call evaluation

For application:

1. form the call target,
2. evaluate any receiver or callable artifact needed for target formation exactly once,
3. evaluate arguments in source order from left to right,
4. invoke the resolved target,
5. produce one of:
   - normal return,
   - explicit `result<E>` propagation,
   - or `trap`.

This rule applies to canonical `apply` and to direct-call sugar that desugars to `apply`.

`apply` chains are parsed right-associatively, but their observable evaluation still follows the left-to-right rule above.

### 7.3 Exactly-once guarantees

The following expressions are evaluated exactly once where they appear:

- `if` condition,
- `switch` selector,
- the left operand of `opt else fallback`,
- the payload expression of `some(expr)`,
- the operand of `expr!`,
- the operand of `handle expr { ... }`,
- the context expression of `bind(context, fn_name)`,
- call receivers, callees, and argument expressions as required by the call rule above.

## 8. Blocks and Abrupt Completion

Statements in a block execute in source order.

Only the final unsemicoloned expression in a block contributes to the block result.

Abrupt completion terminates the current construct immediately and prevents later sibling evaluation.

At minimum, the following are abrupt-completion forms:

- `return`,
- `break`,
- `continue`,
- `!` on an error path,
- `trap`.

## 9. `optional`

### 9.1 Runtime model

`optional` has exactly two runtime states:

- `some(payload)`
- `none`

`none` is the canonical absence of payload.

### 9.2 Construction

`some(expr)` evaluates `expr` eagerly and exactly once before forming the `some(payload)` carrier.

### 9.3 Extraction

`opt else fallback`:

1. evaluates the left operand exactly once,
2. yields the extracted payload if that operand evaluates to `some(payload)`,
3. otherwise evaluates `fallback` and yields its value.

`else` is extraction with fallback, not error handling.

### 9.4 Trap behavior

`optional` is trap-free by itself.

Any trap associated with `some(expr)` or `opt else fallback` arises only from evaluating the relevant subexpressions.

## 10. `result<E>`

### 10.1 Runtime role

`result<E>` is the runtime carrier for success-or-modeled-failure at function boundaries and in expressions whose static type is `result<E> P`.

Expected, recoverable failures belong to `result<E>`, not to `trap`.

### 10.2 `!`

`expr!`:

1. evaluates `expr` exactly once,
2. yields the extracted success payload if `expr` succeeds,
3. performs immediate enclosing-function return with the same `err(...)` if `expr` yields error.

`!` does not:

- remap errors,
- intercept traps,
- or continue ordinary evaluation after the propagated error path is chosen.

### 10.3 `handle`

`handle expr { ... }`:

1. evaluates `expr` exactly once,
2. yields the extracted success payload directly if `expr` succeeds,
3. selects exactly one matching arm if `expr` yields error,
4. executes that arm,
5. requires the arm to terminate with either `ok(payload)` or `err(E2.case)`.

`ok(payload)` in a `handle` arm recovers locally and makes the `handle` expression yield `payload`.

`err(E2.case)` in a `handle` arm performs immediate enclosing-function return with `err(E2.case)`.

For the remap-only case, a short form such as `E1.case -> E2.case` is sugar for an arm block that returns `err(E2.case)`.

`handle` may execute user-defined logic inside an arm, but it remains specific to modeled `result` errors.

`handle` does not intercept or convert traps.

## 11. `apply`, Call Sugar, and `bind`

### 11.1 Canonical role of `apply`

`apply` is the canonical universal call surface in PBS v1.

The same observable call model applies to:

- top-level functions,
- struct methods,
- service methods,
- contract calls,
- callback calls,
- host-backed calls.

Callable-specific dispatch may differ internally, but it does not change the user-visible sequencing model defined in this document.

### 11.2 Effect boundaries

`apply` does not introduce implicit effect composition.

If a callable returns:

- `optional<P>`, extraction remains explicit through `else`,
- `result<E> P`, propagation or processing remains explicit through `!` or `handle`.

### 11.3 `bind`

`bind(context, fn_name)` is the explicit callback-formation mechanism in PBS v1.

It:

- evaluates `context` exactly once,
- captures the same struct context identity without copying it,
- attaches that context to the resolved top-level function target,
- produces a callback value whose invocation behaves as if the target function were called with the captured context as its first argument.

At the language-semantics level, `bind` is trap-free.

Incompatible binding shape remains a compile-time matter rather than a runtime failure mode.

Retention and storage consequences of `bind` belong to `Memory and Lifetime Specification.md`.

## 12. Branch Selection

### 12.1 `if`

`if` evaluates its condition exactly once.

If the condition is `true`, only the selected `then` branch executes.
If the condition is `false`, only the selected `else` branch executes.

The non-selected branch is not evaluated, even partially.

### 12.2 `switch`

`switch` evaluates its selector exactly once and executes exactly one selected arm.

The non-selected arms are not evaluated.

`switch` is restricted to statically discriminable selector categories in v1:

- literal-comparable scalar values,
- enum values,
- canonical `str` values,
- and any other selector category admitted elsewhere by explicit specification.

`switch` does not accept:

- `result`,
- `error`,
- structs,
- string object/reference types distinct from canonical `str`,
- heap-backed selector categories.

Matching is exact and deterministic:

- enum selectors match by canonical enum-case identity,
- scalar selectors match by the exact equality rule for that scalar category,
- `str` selectors match by canonical static string identity.

`switch` does not perform structural matching, guard evaluation, or user-defined equality dispatch.

## 13. Trap, Determinism, and Host Interaction

### 13.1 Trap boundary

`trap` is reserved for failures that are:

- outside the ordinary userland contract,
- not suitably representable as the declared `result<E>` surface,
- caused by runtime or host invariant failure,
- or severe enough that ordinary userland recovery is not part of the v1 language model.

PBS v1 does not define `try/catch` for traps.

Traps are not part of ordinary recoverable control flow.

Any trap aborts the current PBS program execution rather than returning control to ordinary userland flow.

Control then transfers to runtime or firmware crash handling outside the ordinary language model.

### 13.2 Host interaction

Host calls must not introduce user-visible reordering of already-defined PBS evaluation order.

Expected operational failures of host-backed surfaces should be modeled through their declared contract rather than through ad hoc trap usage.

Cross-boundary host/userland interaction remains stack-value-based as defined by the host-boundary decision track; direct host-memory manipulation is not part of PBS userland semantics.

## 14. TODO

The following items remain editorial or cross-spec integration tasks rather than open semantic agenda questions:

- the final wording split between this document and `16. Runtime Execution and Initialization Specification.md` for crash handoff after trap,
- the final wording split between this document and `10. Memory and Lifetime Specification.md` for retention/allocation facts that arise during ordinary execution,
- conformance-oriented example coverage once `13. Conformance Test Specification.md` is expanded.

## 15. Non-Goals

- Reopening grammar or static typing unless current text is impossible to execute normatively.
- Defining exact GC collection strategy.
- Designing future async, actor, or scheduler models.
- Specifying backend optimization policy.

## 16. Exit Criteria

This document is ready to move beyond temporary draft status only when:

1. every runtime-observable core construct has deterministic evaluation wording,
2. trap versus status-value behavior is explicit for every effect-bearing construct,
3. host-call interaction rules are stated without relying on informal prose elsewhere,
4. the document can drive runtime conformance tests without decision backfill,
5. the remaining TODO items are reduced to editorial integration rather than semantic uncertainty.
