13 KiB
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
optionalandresult, - 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
ifandswitch, - runtime application behavior for
apply, call sugar, methods, contracts, callbacks, and host-backed call surfaces, - runtime behavior of
optional,result<E>,else,!, andhandle, - 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:
- Runtime authority (
docs/specs/hardware/topics/chapter-2.md,chapter-3.md,chapter-9.md,chapter-12.md,chapter-16.md) - Bytecode authority (
docs/specs/bytecode/ISA_CORE.md) 3. Core Syntax Specification.md4. Static Semantics Specification.md- 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.md3. Core Syntax Specification.md4. Static Semantics Specification.md5. Manifest, Stdlib, and SDK Resolution Specification.md6.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
applysurface, with call sugar desugaring toapply. optional Tfunction fallthrough yieldsnone.result<E>function fallthrough is a compile-time error.ok(...)anderr(...)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:
- materialize globals for each file according to dependency order,
- execute that file's
[Init], if present, - compose those steps into one synthetic module init per module,
- execute project init, if present,
- 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:
- form the call target,
- evaluate any receiver or callable artifact needed for target formation exactly once,
- evaluate arguments in source order from left to right,
- invoke the resolved target,
- 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:
ifcondition,switchselector,- 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:
- evaluates the left operand exactly once,
- yields the extracted payload if that operand evaluates to
some(payload), - otherwise evaluates
fallbackand 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!:
- evaluates
exprexactly once, - yields the extracted success payload if
exprsucceeds, - performs immediate enclosing-function return with the same
err(...)ifexpryields error.
! does not:
- remap errors,
- intercept traps,
- or continue ordinary evaluation after the propagated error path is chosen.
10.3 handle
handle expr { ... }:
- evaluates
exprexactly once, - yields the extracted success payload directly if
exprsucceeds, - selects exactly one matching arm if
expryields error, - executes that arm,
- requires the arm to terminate with either
ok(payload)orerr(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 throughelse,result<E> P, propagation or processing remains explicit through!orhandle.
11.3 bind
bind(context, fn_name) is the explicit callback-formation mechanism in PBS v1.
It:
- evaluates
contextexactly 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
strvalues, - 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,
strselectors 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.mdfor crash handoff after trap, - the final wording split between this document and
10. Memory and Lifetime Specification.mdfor retention/allocation facts that arise during ordinary execution, - conformance-oriented example coverage once
13. Conformance Test Specification.mdis 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:
- every runtime-observable core construct has deterministic evaluation wording,
- trap versus status-value behavior is explicit for every effect-bearing construct,
- host-call interaction rules are stated without relying on informal prose elsewhere,
- the document can drive runtime conformance tests without decision backfill,
- the remaining TODO items are reduced to editorial integration rather than semantic uncertainty.