// Private, JavaScript-free execution-control state transitions.
// Public policy validation and runtime observation-point wiring are separate
// implementation slices.
///|
#warnings("-unused_constructor")
priv enum ExecutionControlFailure {
Interrupted
StackDepthLimit
ExecutionLimit
StaleActivationRelease
}
///|
priv suberror ExecutionControlError {
ExecutionControlError(ExecutionControlFailure)
}
///|
#warnings("-unused_constructor")
priv enum ExecutionControlConfigurationParameter {
StepBudget
StackDepth
}
///|
priv suberror ExecutionControlConfigurationError {
InvalidExecutionControlConfiguration(
ExecutionControlConfigurationParameter,
Int64
)
}
///|
const MAX_PORTABLE_EXECUTION_COUNT : Int64 = 2147483647L
///|
priv struct ExecutionControlConfiguration {
remaining_steps : Int64
maximum_active_depth : Int64
}
///|
fn validate_execution_control_limit(
parameter : ExecutionControlConfigurationParameter,
value : Int64,
) -> Int64 raise ExecutionControlConfigurationError {
guard value >= 0L && value <= MAX_PORTABLE_EXECUTION_COUNT else {
raise InvalidExecutionControlConfiguration(parameter, value)
}
value
}
///|
fn ExecutionControlConfiguration::ExecutionControlConfiguration(
remaining_steps~ : Int64,
maximum_active_depth~ : Int64,
) -> ExecutionControlConfiguration raise ExecutionControlConfigurationError {
{
remaining_steps: validate_execution_control_limit(
StepBudget,
remaining_steps,
),
maximum_active_depth: validate_execution_control_limit(
StackDepth,
maximum_active_depth,
),
}
}
///|
priv struct ExecutionControlState {
remaining_steps : Int64
maximum_active_depth : Int64
active_depth : Int64
}
///|
priv enum ExecutionControlEvent {
ObserveStep(Bool)
ObserveActivation(Bool)
ReleaseActivation
}
// Tail replacement is intentionally not an event in this slice. A future
// valid tail replacement must carry the retained `active_depth` forward and
// must not emit another `ObserveActivation` acquisition.
///|
priv enum ExecutionControlDecision {
StepObserved
ActivationObserved
ActivationReleased
Rejected(ExecutionControlFailure)
}
///|
// Pure execution-control transition core. Interruption visibility is supplied
// by the imperative shell; the reducer owns all precedence and counter
// arithmetic without mutating the caller's state.
fn reduce_execution_control(
state : ExecutionControlState,
event : ExecutionControlEvent,
) -> (ExecutionControlState, ExecutionControlDecision) {
match event {
ObserveStep(interrupted) =>
if interrupted {
(state, Rejected(Interrupted))
} else if state.remaining_steps == 0L {
(state, Rejected(ExecutionLimit))
} else {
(
{
remaining_steps: state.remaining_steps - 1L,
maximum_active_depth: state.maximum_active_depth,
active_depth: state.active_depth,
},
StepObserved,
)
}
ObserveActivation(interrupted) =>
if interrupted {
(state, Rejected(Interrupted))
} else if state.active_depth >= state.maximum_active_depth {
(state, Rejected(StackDepthLimit))
} else if state.remaining_steps == 0L {
(state, Rejected(ExecutionLimit))
} else {
(
{
remaining_steps: state.remaining_steps - 1L,
maximum_active_depth: state.maximum_active_depth,
active_depth: state.active_depth + 1L,
},
ActivationObserved,
)
}
ReleaseActivation =>
if state.active_depth == 0L {
(state, Rejected(StaleActivationRelease))
} else {
(
{
remaining_steps: state.remaining_steps,
maximum_active_depth: state.maximum_active_depth,
active_depth: state.active_depth - 1L,
},
ActivationReleased,
)
}
}
}
///|
// Per-Interpreter carrier for the active operation control. Keeping it in the
// internal Environment avoids public record-shape changes and module-global
// mutable state; it is not a globalThis property or persistent configuration.
const EXECUTION_CONTROL_BINDING = "[[ExecutionControl]]"
///|
const EXECUTION_CONTROL_ACTIVATION = "activation"
///|
const EXECUTION_CONTROL_RELEASE = "release"
///|
const STACK_DEPTH_LIMIT_MESSAGE = "Maximum call stack size exceeded"
///|
priv struct ExecutionInterruptionRequest {
requested : Ref[Bool]
}
///|
#warnings("-unused_value")
fn ExecutionInterruptionRequest::ExecutionInterruptionRequest() -> ExecutionInterruptionRequest {
{ requested: { val: false } }
}
///|
#warnings("-unused_value")
fn ExecutionInterruptionRequest::request(
self : ExecutionInterruptionRequest,
) -> Unit {
self.requested.val = true
}
///|
fn ExecutionInterruptionRequest::is_requested(
self : ExecutionInterruptionRequest,
) -> Bool {
self.requested.val
}
///|
priv struct ExecutionControl {
mut state : ExecutionControlState
interruption : ExecutionInterruptionRequest
}
///|
#warnings("-unused_value")
fn ExecutionControl::ExecutionControl(
remaining_steps~ : Int64,
maximum_active_depth~ : Int64,
interruption~ : ExecutionInterruptionRequest,
) -> ExecutionControl raise ExecutionControlConfigurationError {
let configuration = ExecutionControlConfiguration(
remaining_steps~,
maximum_active_depth~,
)
{
state: {
remaining_steps: configuration.remaining_steps,
maximum_active_depth: configuration.maximum_active_depth,
active_depth: 0L,
},
interruption,
}
}
///|
#warnings("-unused_value")
fn ExecutionControl::remaining_steps(self : ExecutionControl) -> Int64 {
self.state.remaining_steps
}
///|
#warnings("-unused_value")
fn ExecutionControl::active_depth(self : ExecutionControl) -> Int64 {
self.state.active_depth
}
///|
fn ExecutionControl::transition(
self : ExecutionControl,
event : ExecutionControlEvent,
) -> ExecutionControlDecision {
let (next_state, decision) = reduce_execution_control(self.state, event)
self.state = next_state
decision
}
///|
#warnings("-unused_value")
fn ExecutionControl::observe_step(
self : ExecutionControl,
) -> Result[Unit, ExecutionControlFailure] {
match self.transition(ObserveStep(self.interruption.is_requested())) {
StepObserved => Ok(())
Rejected(failure) => Err(failure)
_ => Err(ExecutionLimit)
}
}
///|
fn execution_control_observer(control : ExecutionControl) -> Value {
make_object(
Map([]),
Null,
Some(
NonConstructableCallable("[[execution-control-observer]]", fn(
args,
) raise {
match args {
[String_(operation)] if operation == EXECUTION_CONTROL_ACTIVATION =>
match control.observe_activation() {
Ok(_) => Undefined
Err(failure) => raise ExecutionControlError(failure)
}
[String_(operation)] if operation == EXECUTION_CONTROL_RELEASE =>
match control.release_activation() {
Ok(_) => Undefined
Err(failure) => raise ExecutionControlError(failure)
}
_ =>
match control.observe_step() {
Ok(_) => Undefined
Err(failure) => raise ExecutionControlError(failure)
}
}
}),
),
"Function",
Map([]),
true,
)
}
///|
fn restore_execution_control_binding(
global : Environment,
previous : Binding?,
) -> Unit {
match previous {
Some(binding) => global.bindings[EXECUTION_CONTROL_BINDING] = binding
None => {
let _ = global.bindings.remove(EXECUTION_CONTROL_BINDING)
}
}
}
///|
pub fn Interpreter::observe_execution_step(
self : Interpreter,
) -> Unit raise Error {
match self.global.bindings.get(EXECUTION_CONTROL_BINDING) {
Some(binding) =>
match binding.value {
Object(data) =>
match data.callable {
Some(NonConstructableCallable(_, observe)) => {
let _ = observe([])
}
_ => ()
}
_ => ()
}
None => ()
}
}
///|
fn Interpreter::observe_execution_activation(
self : Interpreter,
) -> Unit raise Error {
match self.global.bindings.get(EXECUTION_CONTROL_BINDING) {
Some(binding) =>
match binding.value {
Object(data) =>
match data.callable {
Some(NonConstructableCallable(_, observe)) => {
let _ = observe([String_(EXECUTION_CONTROL_ACTIVATION)])
}
_ => ()
}
_ => ()
}
None => ()
}
}
///|
// Release is an ownership-only lifecycle hook. Valid dispatcher ownership
// always releases an acquired unit; the reducer rejects a stale zero-depth
// release without mutating state.
fn Interpreter::release_execution_activation(self : Interpreter) -> Unit {
match self.global.bindings.get(EXECUTION_CONTROL_BINDING) {
Some(binding) =>
match binding.value {
Object(data) =>
match data.callable {
Some(NonConstructableCallable(_, observe)) =>
try {
let _ = observe([String_(EXECUTION_CONTROL_RELEASE)])
} catch {
_ => ()
}
_ => ()
}
_ => ()
}
None => ()
}
}
///|
#warnings("-unused_value")
// Saving and restoring a previous carrier guarantees scoped cleanup only. It
// does not authorize or define same-Engine re-entry through public operations.
fn[T] Interpreter::with_execution_control(
self : Interpreter,
control : ExecutionControl,
action : () -> T raise Error,
) -> T raise Error {
let previous = self.global.bindings.get(EXECUTION_CONTROL_BINDING)
self.global.bindings[EXECUTION_CONTROL_BINDING] = {
value: execution_control_observer(control),
kind: VarBinding,
initialized: true,
annex_b_hoisted: false,
is_parameter: false,
}
let result = action() catch {
error => {
restore_execution_control_binding(self.global, previous)
raise error
}
}
restore_execution_control_binding(self.global, previous)
result
}
///|
#warnings("-unused_value")
fn ExecutionControl::observe_activation(
self : ExecutionControl,
) -> Result[Unit, ExecutionControlFailure] {
match self.transition(ObserveActivation(self.interruption.is_requested())) {
ActivationObserved => Ok(())
Rejected(failure) => Err(failure)
_ => Err(ExecutionLimit)
}
}
///|
fn ExecutionControl::release_activation(
self : ExecutionControl,
) -> Result[Unit, ExecutionControlFailure] {
match self.transition(ReleaseActivation) {
ActivationReleased => Ok(())
Rejected(failure) => Err(failure)
_ => Err(StaleActivationRelease)
}
}
///|
// Adapt the deterministic depth policy to the policy-free lifecycle port. The
// shell owns cleanup ordering; this adapter only acquires depth at entry and
// releases it on rejected setup or final activation cleanup.
fn Interpreter::execution_control_activation_observation_port(
self : Interpreter,
) -> ActivationObservationPort {
ActivationObservationPort(
begin_entry=() => {
self.observe_execution_activation()
ActivationObservationAttemptHooks(
accepted=() => (),
// Setup rejection records the acquired attempt; the dispatcher
// releases it only after restoring the owned runtime state.
rejected=() => (),
released=() => self.release_execution_activation(),
)
},
denied=() => (),
)
}
///|
#warnings("-unused_value")
fn[T] ExecutionControl::with_activation(
self : ExecutionControl,
action : () -> T raise Error,
) -> Result[T, ExecutionControlFailure] raise Error {
match self.observe_activation() {
Err(failure) => Err(failure)
Ok(_) =>
try {
let result = action()
match self.release_activation() {
Ok(_) => Ok(result)
Err(failure) => Err(failure)
}
} catch {
error => {
let _ = self.release_activation()
raise error
}
}
}
}