// Deterministic activation/continuation transition core. The imperative
// dispatcher shell performs every effect described here and returns the
// ticketed result as a DispatchEvent. This module stores semantic data only:
// no host callback, evaluator frame, or Ref-backed result slot crosses a guest
// activation boundary.

///|
priv suberror InvalidDispatchTransition {
  InvalidDispatchTransition(String)
}

///|
priv struct DispatchTicket {
  value : String
}

///|
fn DispatchTicket::DispatchTicket(value~ : String) -> DispatchTicket {
  { value, }
}

///|
#warnings("-unused_field")
priv struct DispatchStatementCursor {
  ctx : ExecContext
  stmts : Array[@ast.Stmt]
  env : Environment
  index : Int
  last_value : Value
  production : Bool
}

///|
#warnings("-unused_value")
fn DispatchStatementCursor::DispatchStatementCursor(
  ctx~ : ExecContext,
  stmts~ : Array[@ast.Stmt],
  env~ : Environment,
  index? : Int = 0,
  last_value? : Value = Undefined,
  production? : Bool = false,
) -> DispatchStatementCursor {
  { ctx, stmts: stmts.copy(), env, index, last_value, production }
}

///|
#warnings("-unused_field")
priv struct DispatchStatementStep {
  ctx : ExecContext
  stmt : @ast.Stmt
  env : Environment
  index : Int
}

///|
#warnings("-unused_field")
priv struct DispatchStatementResume {
  cursor : DispatchStatementCursor
  updates_last_value : Bool
}

///|
#warnings("-unused_value")
fn DispatchStatementResume::DispatchStatementResume(
  cursor~ : DispatchStatementCursor,
  updates_last_value~ : Bool,
) -> DispatchStatementResume {
  { cursor, updates_last_value }
}

///|
#warnings("-unused_field")
priv struct DispatchCatchResume {
  parameter : @ast.Pattern?
  body : DispatchStatementCursor
}

///|
#warnings("-unused_value")
fn DispatchCatchResume::DispatchCatchResume(
  parameter~ : @ast.Pattern?,
  body~ : DispatchStatementCursor,
) -> DispatchCatchResume {
  { parameter, body }
}

///|
#warnings("-unused_field")
priv struct DispatchCallRequest {
  callee : Value
  this_value : Value
  args : Array[Value]
  loc : @token.Loc
}

///|
#warnings("-unused_value")
fn DispatchCallRequest::DispatchCallRequest(
  callee~ : Value,
  this_value~ : Value,
  args~ : Array[Value],
  loc~ : @token.Loc,
) -> DispatchCallRequest {
  { callee, this_value, args: args.copy(), loc }
}

///|
#warnings("-unused_field")
priv struct DispatchConstructRequest {
  ctor : Value
  args : Array[Value]
  loc : @token.Loc
}

///|
fn DispatchConstructRequest::DispatchConstructRequest(
  ctor~ : Value,
  args~ : Array[Value],
  loc~ : @token.Loc,
) -> DispatchConstructRequest {
  { ctor, args: args.copy(), loc }
}

///|
#warnings("-unused_field")
priv struct DispatchConstructAssignResume {
  target : Value
  property : String
  loc : @token.Loc
  strict : Bool
}

///|
fn DispatchConstructAssignResume::DispatchConstructAssignResume(
  target~ : Value,
  property~ : String,
  loc~ : @token.Loc,
  strict~ : Bool,
) -> DispatchConstructAssignResume {
  { target, property, loc, strict }
}

///|
#warnings("-unused_constructor-unused_field")
priv enum DispatchActivationRequest {
  DispatchProgramActivation(DispatchStatementCursor)
  DispatchCallActivation(DispatchCallRequest)
  DispatchConstructActivation(DispatchConstructRequest)
}

///|
#warnings("-unused_field")
priv struct DispatchBinaryResume {
  op : @ast.BinOp
  left : Value
  loc : @token.Loc
}

///|
#warnings("-unused_value")
fn DispatchBinaryResume::DispatchBinaryResume(
  op~ : @ast.BinOp,
  left~ : Value,
  loc~ : @token.Loc,
) -> DispatchBinaryResume {
  { op, left, loc }
}

///|
#warnings("-unused_field")
priv struct DispatchBinaryRightCallResume {
  left_request : DispatchCallRequest
  right_request : DispatchCallRequest
  left_value : Value?
  op : @ast.BinOp
  loc : @token.Loc
  left_adapter : DispatchManagedUserFuncAdapterToken
  right_adapter : DispatchManagedUserFuncAdapterToken
}

///|
fn DispatchBinaryRightCallResume::DispatchBinaryRightCallResume(
  left_request~ : DispatchCallRequest,
  right_request~ : DispatchCallRequest,
  left_value~ : Value?,
  op~ : @ast.BinOp,
  loc~ : @token.Loc,
  left_adapter~ : DispatchManagedUserFuncAdapterToken,
  right_adapter~ : DispatchManagedUserFuncAdapterToken,
) -> DispatchBinaryRightCallResume {
  {
    left_request: DispatchCallRequest(
      callee=left_request.callee,
      this_value=left_request.this_value,
      args=left_request.args,
      loc=left_request.loc,
    ),
    right_request: DispatchCallRequest(
      callee=right_request.callee,
      this_value=right_request.this_value,
      args=right_request.args,
      loc=right_request.loc,
    ),
    left_value,
    op,
    loc,
    left_adapter,
    right_adapter,
  }
}

///|
#warnings("-unused_field")
priv struct DispatchPropertyGetResume {
  target : Value
  property_key : Value
  receiver : Value
  loc : @token.Loc
}

///|
#warnings("-unused_field")
priv struct DispatchMapMemberCallResume {
  receiver : Value
  loc : @token.Loc
}

///|
#warnings("-unused_value")
fn DispatchMapMemberCallResume::DispatchMapMemberCallResume(
  receiver~ : Value,
  loc~ : @token.Loc,
) -> DispatchMapMemberCallResume {
  { receiver, loc }
}

///|
#warnings("-unused_value")
fn DispatchPropertyGetResume::DispatchPropertyGetResume(
  target~ : Value,
  property_key~ : Value,
  receiver~ : Value,
  loc~ : @token.Loc,
) -> DispatchPropertyGetResume {
  { target, property_key, receiver, loc }
}

///|
#warnings("-unused_field")
priv struct DispatchProxyGetResume {
  target : Value
  property_key : Value
  receiver : Value
  loc : @token.Loc
}

///|
#warnings("-unused_value")
fn DispatchProxyGetResume::DispatchProxyGetResume(
  target~ : Value,
  property_key~ : Value,
  receiver~ : Value,
  loc~ : @token.Loc,
) -> DispatchProxyGetResume {
  { target, property_key, receiver, loc }
}

///|
// `post_trap.target` and `handler` are captured before handler.[[Get]]. The
// mutable Proxy slots must not be read again when this continuation resumes;
// `proxy` is retained only for runtime provenance identity.
#warnings("-unused_field")
priv struct DispatchProxyGetTrapLookupResume {
  proxy : Value
  handler : Value
  post_trap : DispatchProxyGetResume
}

///|
#warnings("-unused_value")
fn DispatchProxyGetTrapLookupResume::DispatchProxyGetTrapLookupResume(
  proxy~ : Value,
  handler~ : Value,
  post_trap~ : DispatchProxyGetResume,
) -> DispatchProxyGetTrapLookupResume {
  { proxy, handler, post_trap }
}

///|
#warnings("-unused_field")
priv struct DispatchParameterDefaultResume {
  params : Array[@ast.Param]
  next_index : Int
  effective_param_count : Int
  args : Array[Value]
  rest_param : String?
  is_arrow : Bool
  env : Environment
  ctx : ExecContext
  body : Array[@ast.Stmt]
}

///|
#warnings("-unused_value")
fn DispatchParameterDefaultResume::DispatchParameterDefaultResume(
  params~ : Array[@ast.Param],
  next_index~ : Int,
  effective_param_count~ : Int,
  args~ : Array[Value],
  rest_param~ : String?,
  is_arrow~ : Bool,
  env~ : Environment,
  ctx~ : ExecContext,
  body~ : Array[@ast.Stmt],
) -> DispatchParameterDefaultResume {
  {
    params: params.copy(),
    next_index,
    effective_param_count,
    args: args.copy(),
    rest_param,
    is_arrow,
    env,
    ctx,
    body: body.copy(),
  }
}

///|
#warnings("-unused_field")
priv struct DispatchNumericCallStart {
  parameter : DispatchParameterBindingToken
  retained_parameter : DispatchRetainedParameterBindingToken?
  recursive_callee : DispatchCalleeCaptureToken
  recipe : NumericRecursionExpressionRecipe
  return_recipe : NumericRecursionFunctionReturnRecipe
}

///|
#warnings("-unused_value")
fn DispatchNumericCallStart::DispatchNumericCallStart(
  parameter~ : DispatchParameterBindingToken,
  retained_parameter? : DispatchRetainedParameterBindingToken? = None,
  recursive_callee~ : DispatchCalleeCaptureToken,
  recipe~ : NumericRecursionExpressionRecipe,
  return_recipe? : NumericRecursionFunctionReturnRecipe = NumericRecursionDirectReturn,
) -> DispatchNumericCallStart {
  { parameter, retained_parameter, recursive_callee, recipe, return_recipe }
}

///|
#warnings("-unused_constructor")
priv enum DispatchNumericProtectedRegion {
  DispatchNumericTryBody
  DispatchNumericCatchBody
  DispatchNumericFinalizerBody
}

///|
#warnings("-unused_constructor")
priv enum DispatchNumericClosedStatementKind {
  DispatchNumericExpressionStatement
  DispatchNumericReturnStatement
  DispatchNumericThrowStatement
}

///|
#warnings("-unused_field")
priv struct DispatchNumericProtectedStatementStart {
  expression : DispatchNumericExpression
  completion : NumericRecursionRootCallCompletion
}

///|
#warnings("-unused_value")
fn DispatchNumericProtectedStatementStart::DispatchNumericProtectedStatementStart(
  expression~ : DispatchNumericExpression,
  completion~ : NumericRecursionRootCallCompletion,
) -> DispatchNumericProtectedStatementStart {
  { expression, completion }
}

///|
#warnings("-unused_field")
priv struct DispatchNumericProtectedStart {
  expression : DispatchNumericExpression
  recipe : NumericRecursionProtectedRootRecipe
  catch_binding : DispatchNumericCatchBindingToken
}

///|
#warnings("-unused_value")
fn DispatchNumericProtectedStart::DispatchNumericProtectedStart(
  expression~ : DispatchNumericExpression,
  recipe~ : NumericRecursionProtectedRootRecipe,
  catch_binding~ : DispatchNumericCatchBindingToken,
) -> DispatchNumericProtectedStart {
  { expression, recipe, catch_binding }
}

///|
#warnings("-unused_field")
priv struct DispatchNumericProtectedReturnStart {
  expression : DispatchNumericExpression
  finalizer : NumericRecursionClosedBodyRecipe
}

///|
#warnings("-unused_value")
fn DispatchNumericProtectedReturnStart::DispatchNumericProtectedReturnStart(
  expression~ : DispatchNumericExpression,
  finalizer~ : NumericRecursionClosedBodyRecipe,
) -> DispatchNumericProtectedReturnStart {
  { expression, finalizer }
}

///|
#warnings("-unused_field")
priv struct DispatchNumericCatchResume {
  token : DispatchNumericCatchBindingToken
  parameter : String?
  body : NumericRecursionClosedBodyRecipe
}

///|
#warnings("-unused_value")
fn DispatchNumericCatchResume::DispatchNumericCatchResume(
  token~ : DispatchNumericCatchBindingToken,
  parameter~ : String?,
  body~ : NumericRecursionClosedBodyRecipe,
) -> DispatchNumericCatchResume {
  { token, parameter, body }
}

///|
#warnings("-unused_field")
priv struct DispatchNumericProgramStart {
  declaration_count : Int
  expression : DispatchNumericExpression
  root_control : NumericRecursionRootControlRecipe
  catch_binding : DispatchNumericCatchBindingToken
}

///|
#warnings("-unused_value")
fn DispatchNumericProgramStart::DispatchNumericProgramStart(
  declaration_count~ : Int,
  expression~ : DispatchNumericExpression,
  root_control~ : NumericRecursionRootControlRecipe,
  catch_binding~ : DispatchNumericCatchBindingToken,
) -> DispatchNumericProgramStart {
  { declaration_count, expression, root_control, catch_binding }
}

///|
#warnings("-unused_value")
fn numeric_recursion_program_dispatch_start(
  plan : NumericRecursionPlan,
  capture : DispatchCalleeCaptureToken,
) -> DispatchNumericProgramStart {
  let declaration_count = match plan.peer {
    Some(_) => 2
    None => 1
  }
  DispatchNumericProgramStart(
    declaration_count~,
    expression=numeric_recursion_root_dispatch_expression(plan, capture),
    root_control=plan.root_control,
    catch_binding=DispatchNumericCatchBindingToken(id=capture.id),
  )
}

///|
#warnings("-unused_constructor-unused_field")
priv enum DispatchNumericStatementObservation {
  DispatchNumericObserveRootDeclaration(Int)
  DispatchNumericObserveRootExpressionStatement
  DispatchNumericObserveRootTryStatement
  DispatchNumericObserveFunctionTryStatement
  DispatchNumericObserveProtectedStatement(
    DispatchNumericProtectedRegion,
    DispatchNumericClosedStatementKind
  )
  DispatchNumericObserveIfStatement
  DispatchNumericObserveReturnStatement
}

///|
#warnings("-unused_field")
priv struct DispatchNumericRootDeclarationResume {
  next_index : Int
  remaining : Int
  expression : DispatchNumericExpression
  root_control : NumericRecursionRootControlRecipe
  catch_binding : DispatchNumericCatchBindingToken
}

///|
#warnings("-unused_value")
fn DispatchNumericRootDeclarationResume::DispatchNumericRootDeclarationResume(
  next_index~ : Int,
  remaining~ : Int,
  expression~ : DispatchNumericExpression,
  root_control~ : NumericRecursionRootControlRecipe,
  catch_binding~ : DispatchNumericCatchBindingToken,
) -> DispatchNumericRootDeclarationResume {
  { next_index, remaining, expression, root_control, catch_binding }
}

///|
#warnings("-unused_constructor-unused_field")
priv enum DispatchNumericStatementContinuation {
  DispatchAfterNumericRootDeclaration(DispatchNumericRootDeclarationResume)
  DispatchAfterNumericRootExpressionStatement(DispatchNumericExpression)
  DispatchAfterNumericRootTryStatement(DispatchNumericProtectedStart)
  DispatchAfterNumericFunctionTryStatement(DispatchNumericProtectedReturnStart)
  DispatchAfterNumericProtectedStatement(DispatchNumericProtectedStatementStart)
  DispatchAfterNumericCatchEntry(DispatchNumericCatchResume)
  DispatchAfterNumericIfStatement(DispatchNumericCallStart)
  DispatchAfterNumericReturnStatement(DispatchNumericExpression)
}

///|
#warnings("-unused_constructor-unused_field")
priv enum DispatchCallStart {
  DispatchCallBody(DispatchStatementCursor)
  DispatchCallParameters(DispatchParameterDefaultResume)
  DispatchNumericCall(DispatchNumericCallStart)
  DispatchConstructorCall(DispatchStatementCursor, Value)
}

///|
#warnings("-unused_constructor-unused_field")
priv enum DispatchEntryRejection {
  DispatchEntryGuestThrow(Error)
  DispatchEntryRuntimeAbrupt(Error)
}

///|
#warnings("-unused_field")
priv struct DispatchForLoopState {
  condition : @ast.Expr?
  update : @ast.Expr?
  body : @ast.Stmt
  outer_env : Environment
  for_env : Environment
  loop_vars : Array[String]
}

///|
#warnings("-unused_value")
fn DispatchForLoopState::DispatchForLoopState(
  condition~ : @ast.Expr?,
  update~ : @ast.Expr?,
  body~ : @ast.Stmt,
  outer_env~ : Environment,
  for_env~ : Environment,
  loop_vars~ : Array[String],
) -> DispatchForLoopState {
  { condition, update, body, outer_env, for_env, loop_vars: loop_vars.copy() }
}

///|
#warnings("-unused_constructor-unused_field")
priv enum DispatchLoopKind {
  DispatchWhileLoop(@ast.Expr, @ast.Stmt, Environment)
  DispatchDoWhileLoop(@ast.Stmt, @ast.Expr, Environment)
  DispatchForLoop(DispatchForLoopState)
}

///|
#warnings("-unused_field")
priv struct DispatchLoopResume {
  kind : DispatchLoopKind
  ctx : ExecContext
  label : String?
  completion : Value
  production : Bool
}

///|
#warnings("-unused_value")
fn DispatchLoopResume::DispatchLoopResume(
  kind~ : DispatchLoopKind,
  ctx~ : ExecContext,
  label~ : String?,
  completion~ : Value,
  production? : Bool = false,
) -> DispatchLoopResume {
  { kind, ctx, label, completion, production }
}

///|
fn snapshot_dispatch_statement_cursor(
  cursor : DispatchStatementCursor,
) -> DispatchStatementCursor {
  DispatchStatementCursor(
    ctx=cursor.ctx,
    stmts=cursor.stmts,
    env=cursor.env,
    index=cursor.index,
    last_value=cursor.last_value,
    production=cursor.production,
  )
}

///|
fn snapshot_dispatch_parameter_progress(
  progress : DispatchParameterDefaultResume,
) -> DispatchParameterDefaultResume {
  DispatchParameterDefaultResume(
    params=progress.params,
    next_index=progress.next_index,
    effective_param_count=progress.effective_param_count,
    args=progress.args,
    rest_param=progress.rest_param,
    is_arrow=progress.is_arrow,
    env=progress.env,
    ctx=progress.ctx,
    body=progress.body,
  )
}

///|
fn snapshot_dispatch_catch_resume(
  catch_state : DispatchCatchResume,
) -> DispatchCatchResume {
  DispatchCatchResume(
    parameter=catch_state.parameter,
    body=snapshot_dispatch_statement_cursor(catch_state.body),
  )
}

///|
fn snapshot_dispatch_loop_kind(kind : DispatchLoopKind) -> DispatchLoopKind {
  match kind {
    DispatchWhileLoop(condition, body, env) =>
      DispatchWhileLoop(condition, body, env)
    DispatchDoWhileLoop(body, condition, env) =>
      DispatchDoWhileLoop(body, condition, env)
    DispatchForLoop(for_state) =>
      DispatchForLoop(
        DispatchForLoopState(
          condition=for_state.condition,
          update=for_state.update,
          body=for_state.body,
          outer_env=for_state.outer_env,
          for_env=for_state.for_env,
          loop_vars=for_state.loop_vars,
        ),
      )
  }
}

///|
fn snapshot_dispatch_loop_resume(
  loop_state : DispatchLoopResume,
) -> DispatchLoopResume {
  DispatchLoopResume(
    kind=snapshot_dispatch_loop_kind(loop_state.kind),
    ctx=loop_state.ctx,
    label=loop_state.label,
    completion=loop_state.completion,
    production=loop_state.production,
  )
}

///|
fn snapshot_dispatch_numeric_call_start(
  start : DispatchNumericCallStart,
) -> DispatchNumericCallStart {
  DispatchNumericCallStart(
    parameter=start.parameter,
    retained_parameter=start.retained_parameter,
    recursive_callee=start.recursive_callee,
    recipe=start.recipe,
    return_recipe=start.return_recipe,
  )
}

///|
fn snapshot_dispatch_numeric_statement_continuation(
  continuation : DispatchNumericStatementContinuation,
) -> DispatchNumericStatementContinuation {
  match continuation {
    DispatchAfterNumericRootDeclaration(progress) =>
      DispatchAfterNumericRootDeclaration(
        DispatchNumericRootDeclarationResume(
          next_index=progress.next_index,
          remaining=progress.remaining,
          expression=snapshot_dispatch_numeric_expression(progress.expression),
          root_control=progress.root_control,
          catch_binding=progress.catch_binding,
        ),
      )
    DispatchAfterNumericRootExpressionStatement(expression) =>
      DispatchAfterNumericRootExpressionStatement(
        snapshot_dispatch_numeric_expression(expression),
      )
    DispatchAfterNumericRootTryStatement(start) =>
      DispatchAfterNumericRootTryStatement(
        DispatchNumericProtectedStart(
          expression=snapshot_dispatch_numeric_expression(start.expression),
          recipe=start.recipe,
          catch_binding=start.catch_binding,
        ),
      )
    DispatchAfterNumericFunctionTryStatement(start) =>
      DispatchAfterNumericFunctionTryStatement(
        DispatchNumericProtectedReturnStart(
          expression=snapshot_dispatch_numeric_expression(start.expression),
          finalizer=start.finalizer,
        ),
      )
    DispatchAfterNumericProtectedStatement(start) =>
      DispatchAfterNumericProtectedStatement(
        DispatchNumericProtectedStatementStart(
          expression=snapshot_dispatch_numeric_expression(start.expression),
          completion=start.completion,
        ),
      )
    DispatchAfterNumericCatchEntry(catch_state) =>
      DispatchAfterNumericCatchEntry(
        DispatchNumericCatchResume(
          token=catch_state.token,
          parameter=catch_state.parameter,
          body=catch_state.body,
        ),
      )
    DispatchAfterNumericIfStatement(start) =>
      DispatchAfterNumericIfStatement(
        snapshot_dispatch_numeric_call_start(start),
      )
    DispatchAfterNumericReturnStatement(expression) =>
      DispatchAfterNumericReturnStatement(
        snapshot_dispatch_numeric_expression(expression),
      )
  }
}

///|
fn snapshot_dispatch_continuation(
  continuation : DispatchContinuation,
) -> DispatchContinuation {
  match continuation {
    DispatchCompleteReturn => DispatchCompleteReturn
    DispatchCompleteThrow => DispatchCompleteThrow
    DispatchDeliverCallResult => DispatchDeliverCallResult
    DispatchApplyConstructProperty(property) =>
      DispatchApplyConstructProperty(property)
    DispatchAssignConstructResult(assign) =>
      DispatchAssignConstructResult(assign)
    DispatchApplyBinaryRight(binary) => DispatchApplyBinaryRight(binary)
    DispatchApplyPropertyBinaryRight(binary) =>
      DispatchApplyPropertyBinaryRight(binary)
    DispatchApplyNumericBinaryRight(binary) =>
      DispatchApplyNumericBinaryRight(binary)
    DispatchComposeBinaryRight(binary) =>
      DispatchComposeBinaryRight(
        DispatchBinaryRightCallResume(
          left_request=binary.left_request,
          right_request=binary.right_request,
          left_value=binary.left_value,
          op=binary.op,
          loc=binary.loc,
          left_adapter=binary.left_adapter,
          right_adapter=binary.right_adapter,
        ),
      )
    DispatchDeliverAccessorResult(accessor) =>
      DispatchDeliverAccessorResult(accessor)
    DispatchResolveProxyGetTrap(lookup) => DispatchResolveProxyGetTrap(lookup)
    DispatchCheckProxyGetResult(proxy) => DispatchCheckProxyGetResult(proxy)
    DispatchBindParameterDefault(progress) =>
      DispatchBindParameterDefault(
        snapshot_dispatch_parameter_progress(progress),
      )
    DispatchContinueNumericExpression(numeric) =>
      DispatchContinueNumericExpression(
        snapshot_dispatch_numeric_continuation(numeric),
      )
    DispatchContinueExpressionPlan(plan) =>
      DispatchContinueExpressionPlan(
        snapshot_dispatch_expression_plan_resume(plan),
      )
    DispatchContinueResultPipeline(cursor) =>
      DispatchContinueResultPipeline(
        snapshot_dispatch_result_pipeline_cursor(cursor),
      )
    DispatchContinueNumericStatement(numeric) =>
      DispatchContinueNumericStatement(
        snapshot_dispatch_numeric_statement_continuation(numeric),
      )
    DispatchContinueMap(map) => DispatchContinueMap(map)
    DispatchMapStartMemberCall(member_resume) =>
      DispatchMapStartMemberCall(member_resume)
  }
}

///|
#warnings("-unused_field")
priv struct DispatchActivationCleanup {
  id : Int
}

///|
#warnings("-unused_value")
fn DispatchActivationCleanup::DispatchActivationCleanup(
  id : Int,
) -> DispatchActivationCleanup {
  { id, }
}

///|
#warnings("-unused_field")
priv struct DispatchPropertyCleanup {
  id : Int
}

///|
#warnings("-unused_value")
fn DispatchPropertyCleanup::DispatchPropertyCleanup(
  id : Int,
) -> DispatchPropertyCleanup {
  { id, }
}

///|
#warnings("-unused_field")
priv struct DispatchRejectedEntryCleanup {
  id : Int
}

///|
#warnings("-unused_value")
fn DispatchRejectedEntryCleanup::DispatchRejectedEntryCleanup(
  id : Int,
) -> DispatchRejectedEntryCleanup {
  { id, }
}

///|
#warnings("-unused_constructor-unused_field")
priv enum DispatchCompletion {
  DispatchNormal(Value)
  DispatchReturn(Value)
  DispatchBreak(Value?, String?)
  DispatchContinue(Value?, String?)
  DispatchThrow(Error)
  DispatchRuntimeAbrupt(Error)
}

///|
#warnings("-unused_constructor")
priv enum DispatchActivationExitRule {
  DispatchRootExit
  DispatchFunctionExit
  DispatchConstructorExit(Value)
}

///|
#warnings("-unused_constructor")
priv enum DispatchContinuation {
  DispatchCompleteReturn
  DispatchCompleteThrow
  DispatchDeliverCallResult
  DispatchApplyConstructProperty(DispatchPropertyGetResume)
  DispatchAssignConstructResult(DispatchConstructAssignResume)
  DispatchApplyBinaryRight(DispatchBinaryResume)
  DispatchApplyPropertyBinaryRight(DispatchBinaryResume)
  DispatchApplyNumericBinaryRight(DispatchBinaryResume)
  DispatchComposeBinaryRight(DispatchBinaryRightCallResume)
  DispatchDeliverAccessorResult(DispatchPropertyGetResume)
  DispatchResolveProxyGetTrap(DispatchProxyGetTrapLookupResume)
  DispatchCheckProxyGetResult(DispatchProxyGetResume)
  DispatchBindParameterDefault(DispatchParameterDefaultResume)
  DispatchContinueNumericExpression(DispatchNumericExpressionContinuation)
  DispatchContinueExpressionPlan(DispatchExpressionPlanResume)
  DispatchContinueResultPipeline(DispatchResultPipelineCursor)
  DispatchContinueNumericStatement(DispatchNumericStatementContinuation)
  DispatchContinueMap(MapState)
  DispatchMapStartMemberCall(DispatchMapMemberCallResume)
}

///|
#warnings("-unused_constructor-unused_field")
priv enum DispatchWork {
  DispatchExecuteStatement(DispatchStatementStep)
  DispatchAdvanceParameters(DispatchParameterDefaultResume)
  DispatchAdvanceLoop(DispatchLoopResume)
  DispatchExecuteCatch(DispatchCatchResume, Error)
  DispatchNormalizeFunctionControl(DispatchCompletion)
  DispatchResumeContinuation(DispatchContinuation, Value)
}

///|
#warnings("-unused_constructor-unused_field")
priv enum DispatchProductionWork {
  DispatchExecuteStatement(DispatchStatementStep)
  DispatchAdvanceLoop(DispatchLoopResume)
  DispatchPropertyApplyBinaryRight(DispatchBinaryResume, Value)
  DispatchNumericObserveExpressionStep(DispatchNumericExpressionObservation)
  DispatchNumericObserveStatementStep(DispatchNumericStatementObservation)
  DispatchNumericReadParameter(DispatchParameterBindingToken)
  DispatchNumericReadRetainedParameter(DispatchRetainedParameterBindingToken)
  DispatchNumericEnterCatch(DispatchNumericCatchResume, Error)
  DispatchNumericReadCatchBinding(DispatchNumericCatchBindingToken)
  DispatchNumericCaptureTrustedCallee(DispatchCalleeCaptureToken)
  DispatchNumericStartCapturedCall(
    DispatchCalleeCaptureToken,
    Double,
    @token.Loc
  )
  DispatchNumericStartCapturedTwoArgumentCall(
    DispatchCalleeCaptureToken,
    Double,
    Double,
    @token.Loc
  )
  DispatchReceiverStartCall(DispatchCallRequest, DispatchContinuation)
  DispatchConstructStart(DispatchConstructRequest, DispatchContinuation)
  DispatchConstructAssignResult(DispatchConstructAssignResume, Value)
  DispatchNumericApplyBinaryRight(DispatchBinaryResume, Value)
  DispatchPropertyStart(DispatchPropertyGetResume, DispatchContinuation)
  DispatchPropertyExecute(DispatchPropertyGetResume)
  DispatchPropertyDeliverAccessorResult(DispatchPropertyGetResume, Value)
  DispatchPropertyResolveProxyGetTrap(DispatchProxyGetTrapLookupResume, Value)
  DispatchPropertyCheckProxyGetResult(DispatchProxyGetResume, Value)
  DispatchMapStart(MapState)
  DispatchMapResume(MapState, Value)
  DispatchMapStartMemberCall(DispatchMapMemberCallResume, Value)
  DispatchMapAbort(MapState, Error)
}

///|
#warnings("-unused_constructor")
priv enum DispatchSuspension {
  DispatchSuspendStatements(DispatchStatementCursor)
  DispatchSuspendParameters(DispatchParameterDefaultResume)
  DispatchSuspendContinue(DispatchContinuation, DispatchWork)
  DispatchSuspendContinueProduction(
    DispatchContinuation,
    DispatchProductionWork
  )
  DispatchSuspendCall(DispatchCallRequest, DispatchContinuation)
  DispatchSuspendConstruct(DispatchConstructRequest, DispatchContinuation)
  DispatchSuspendNumericExpression(
    DispatchNumericExpression,
    DispatchContinuation?
  )
  DispatchSuspendProtected(
    DispatchStatementCursor,
    DispatchCatchResume?,
    DispatchStatementCursor?
  )
  DispatchSuspendLoopIteration(DispatchLoopResume, DispatchStatementCursor)
  DispatchSuspendSwitch(Value, DispatchStatementCursor)
  DispatchSuspendLabel(String, DispatchStatementCursor)
  DispatchSuspendProperty(
    DispatchPropertyCleanup,
    DispatchPropertyGetResume,
    DispatchContinuation
  )
}

///|
#warnings("-unused_field")
priv enum DispatchEffect {
  DispatchEnterActivation(DispatchActivationRequest)
  DispatchRun(DispatchWork)
  DispatchRunProduction(DispatchProductionWork)
  DispatchReleaseActivation(DispatchActivationCleanup, DispatchCompletion)
  DispatchRestorePropertyScope(DispatchPropertyCleanup, DispatchCompletion)
  DispatchRollbackRejectedEntry(
    DispatchRejectedEntryCleanup,
    DispatchCompletion
  )
  DispatchNormalizeEscapedControl(DispatchCompletion)
}

///|
#warnings("-unused_constructor")
priv enum DispatchEffectResult {
  DispatchProgramAccepted(DispatchActivationCleanup)
  DispatchNumericProgramAccepted(
    DispatchActivationCleanup,
    DispatchNumericProgramStart
  )
  DispatchCallAccepted(DispatchActivationCleanup, DispatchCallStart)
  DispatchActivationRejected(
    DispatchRejectedEntryCleanup,
    DispatchEntryRejection
  )
  DispatchEscapedControlNormalized(Error)
  DispatchWorkCompleted(DispatchCompletion)
  DispatchWorkSuspended(DispatchSuspension)
  DispatchCleanupCompleted
}

///|
#warnings("-unused_constructor")
priv enum ActivationDispatchEvent {
  DispatchStart(DispatchActivationRequest)
  DispatchEffectCompleted(DispatchTicket, DispatchEffectResult)
}

///|
#warnings("-unused_constructor")
priv enum ActivationDispatchDecision {
  DispatchPerform(DispatchTicket, DispatchEffect)
  DispatchFinish(DispatchCompletion)
}

///|
priv enum DispatchFrame {
  DispatchContinuationFrame(DispatchContinuation)
  DispatchStatementFrame(DispatchStatementResume)
  DispatchLoopFrame(DispatchLoopResume)
  DispatchSwitchFrame(Value)
  DispatchLabelFrame(String)
  DispatchCatchFrame(DispatchCatchResume)
  DispatchFinallyFrame(DispatchStatementCursor)
  DispatchNumericCatchFrame(DispatchNumericCatchResume)
  DispatchNumericFinallyFrame(NumericRecursionClosedBodyRecipe)
  DispatchSavedCompletionFrame(DispatchCompletion)
  DispatchPropertyScopeFrame(DispatchPropertyCleanup)
  DispatchActivationFrame(DispatchActivationCleanup, DispatchActivationExitRule)
}

///|
priv enum DispatchFrameStack {
  DispatchFrameStackEmpty
  DispatchFrameStackNode(DispatchFrame, DispatchFrameStack)
}

///|
priv enum DispatchPendingActivation {
  DispatchPendingProgram(DispatchStatementCursor)
  DispatchPendingCall
  DispatchPendingConstruct
}

///|
priv enum DispatchPendingEffect {
  DispatchPendingActivationEntry(DispatchTicket, DispatchPendingActivation)
  DispatchPendingWork(DispatchTicket)
  DispatchPendingActivationRelease(DispatchTicket, DispatchCompletion)
  DispatchPendingPropertyRestore(DispatchTicket, DispatchCompletion)
  DispatchPendingRejectedRollback(DispatchTicket, DispatchCompletion)
  DispatchPendingControlNormalization(DispatchTicket, DispatchActivationCleanup)
}

///|
#warnings("-unused_field")
priv enum ActivationDispatchPhase {
  DispatchReady
  DispatchAwaiting(DispatchPendingEffect)
  DispatchFinishedPhase(DispatchCompletion)
}

///|
priv struct ActivationDispatchState {
  frames : DispatchFrameStack
  phase : ActivationDispatchPhase
  ticket_cursor : DispatchTicket
}

///|
priv enum DispatchCompletionResume {
  DispatchResumeCompletion(DispatchCompletion)
  DispatchResumeDecision(ActivationDispatchState, ActivationDispatchDecision)
}

///|
fn dispatch_resume_decision(
  result : (ActivationDispatchState, ActivationDispatchDecision),
) -> DispatchCompletionResume {
  let (state, decision) = result
  DispatchResumeDecision(state, decision)
}

///|
#warnings("-unused_value")
fn ActivationDispatchState::ActivationDispatchState() -> ActivationDispatchState {
  {
    frames: DispatchFrameStackEmpty,
    phase: DispatchReady,
    ticket_cursor: DispatchTicket(value="0"),
  }
}

///|
fn[T] invalid_dispatch_transition(
  message : String,
) -> T raise InvalidDispatchTransition {
  raise InvalidDispatchTransition(message)
}

///|
fn require_dispatch_ticket(
  expected : DispatchTicket,
  actual : DispatchTicket,
) -> Unit raise InvalidDispatchTransition {
  guard expected.value == actual.value else {
    invalid_dispatch_transition(
      "stale dispatch ticket: expected " +
      expected.value +
      ", received " +
      actual.value,
    )
  }
}

///|
fn push_dispatch_frame(
  state : ActivationDispatchState,
  frame : DispatchFrame,
) -> ActivationDispatchState {
  {
    frames: DispatchFrameStackNode(frame, state.frames),
    phase: state.phase,
    ticket_cursor: state.ticket_cursor,
  }
}

///|
fn with_dispatch_frames(
  state : ActivationDispatchState,
  frames : DispatchFrameStack,
) -> ActivationDispatchState {
  { frames, phase: state.phase, ticket_cursor: state.ticket_cursor }
}

///|
fn ready_dispatch_state(
  state : ActivationDispatchState,
) -> ActivationDispatchState {
  {
    frames: state.frames,
    phase: DispatchReady,
    ticket_cursor: state.ticket_cursor,
  }
}

///|
fn increment_dispatch_ticket_value(
  value : String,
) -> String raise InvalidDispatchTransition {
  let digits = value.to_array()
  guard !digits.is_empty() else {
    invalid_dispatch_transition("dispatch ticket must not be empty")
  }
  let mut index = digits.length() - 1
  while index >= 0 {
    match digits[index] {
      '0' => {
        digits[index] = '1'
        return String::from_array(digits)
      }
      '1' => {
        digits[index] = '2'
        return String::from_array(digits)
      }
      '2' => {
        digits[index] = '3'
        return String::from_array(digits)
      }
      '3' => {
        digits[index] = '4'
        return String::from_array(digits)
      }
      '4' => {
        digits[index] = '5'
        return String::from_array(digits)
      }
      '5' => {
        digits[index] = '6'
        return String::from_array(digits)
      }
      '6' => {
        digits[index] = '7'
        return String::from_array(digits)
      }
      '7' => {
        digits[index] = '8'
        return String::from_array(digits)
      }
      '8' => {
        digits[index] = '9'
        return String::from_array(digits)
      }
      '9' => digits[index] = '0'
      _ => invalid_dispatch_transition("dispatch ticket must be decimal")
    }
    index = index - 1
  }
  "1" + String::from_array(digits)
}

///|
fn issue_dispatch_ticket(
  cursor : DispatchTicket,
) -> (DispatchTicket, DispatchTicket) raise InvalidDispatchTransition {
  let next = DispatchTicket(value=increment_dispatch_ticket_value(cursor.value))
  (cursor, next)
}

///|
fn pending_dispatch_ticket(pending : DispatchPendingEffect) -> DispatchTicket {
  match pending {
    DispatchPendingActivationEntry(ticket, _) => ticket
    DispatchPendingWork(ticket) => ticket
    DispatchPendingActivationRelease(ticket, _) => ticket
    DispatchPendingPropertyRestore(ticket, _) => ticket
    DispatchPendingRejectedRollback(ticket, _) => ticket
    DispatchPendingControlNormalization(ticket, _) => ticket
  }
}

///|
fn schedule_dispatch_effect(
  state : ActivationDispatchState,
  effect : DispatchEffect,
) -> (ActivationDispatchState, ActivationDispatchDecision) raise InvalidDispatchTransition {
  guard state.phase is DispatchReady else {
    invalid_dispatch_transition("cannot schedule an effect outside Ready")
  }
  let (ticket, next_cursor) = issue_dispatch_ticket(state.ticket_cursor)
  let pending = match effect {
    DispatchEnterActivation(request) => {
      let activation = match request {
        DispatchProgramActivation(cursor) =>
          DispatchPendingProgram(snapshot_dispatch_statement_cursor(cursor))
        DispatchCallActivation(_) => DispatchPendingCall
        DispatchConstructActivation(_) => DispatchPendingConstruct
      }
      DispatchPendingActivationEntry(ticket, activation)
    }
    DispatchRun(_) | DispatchRunProduction(_) => DispatchPendingWork(ticket)
    DispatchReleaseActivation(_, completion) =>
      DispatchPendingActivationRelease(ticket, completion)
    DispatchRestorePropertyScope(_, completion) =>
      DispatchPendingPropertyRestore(ticket, completion)
    DispatchRollbackRejectedEntry(_, completion) =>
      DispatchPendingRejectedRollback(ticket, completion)
    DispatchNormalizeEscapedControl(_) =>
      invalid_dispatch_transition(
        "escaped control requires its ownership-preserving scheduler",
      )
  }
  let next : ActivationDispatchState = {
    frames: state.frames,
    phase: DispatchAwaiting(pending),
    ticket_cursor: next_cursor,
  }
  (next, DispatchPerform(ticket, effect))
}

///|
fn schedule_dispatch_production_work(
  state : ActivationDispatchState,
  work : DispatchProductionWork,
) -> (ActivationDispatchState, ActivationDispatchDecision) raise InvalidDispatchTransition {
  schedule_dispatch_effect(state, DispatchRunProduction(work))
}

///|
fn schedule_dispatch_control_normalization(
  state : ActivationDispatchState,
  cleanup : DispatchActivationCleanup,
  completion : DispatchCompletion,
) -> (ActivationDispatchState, ActivationDispatchDecision) raise InvalidDispatchTransition {
  guard state.phase is DispatchReady else {
    invalid_dispatch_transition(
      "cannot schedule control normalization outside Ready",
    )
  }
  let (ticket, next_cursor) = issue_dispatch_ticket(state.ticket_cursor)
  let next : ActivationDispatchState = {
    frames: state.frames,
    phase: DispatchAwaiting(
      DispatchPendingControlNormalization(ticket, cleanup),
    ),
    ticket_cursor: next_cursor,
  }
  (next, DispatchPerform(ticket, DispatchNormalizeEscapedControl(completion)))
}

///|
fn normalize_activation_completion(
  rule : DispatchActivationExitRule,
  completion : DispatchCompletion,
) -> DispatchCompletion {
  match (rule, completion) {
    (DispatchFunctionExit, DispatchNormal(_)) => DispatchNormal(Undefined)
    (DispatchFunctionExit, DispatchReturn(value)) => DispatchNormal(value)
    (DispatchConstructorExit(receiver), DispatchNormal(_)) =>
      DispatchNormal(receiver)
    (DispatchConstructorExit(receiver), DispatchReturn(value)) =>
      if is_object_like_for_constructor_return(value) {
        DispatchNormal(value)
      } else {
        DispatchNormal(receiver)
      }
    (_, other) => other
  }
}

///|
fn dispatch_completion_value(value : Value?, fallback : Value) -> Value {
  match value {
    Some(found) => found
    None => fallback
  }
}

///|
fn dispatch_loop_label_matches(
  control_label : String?,
  loop_label : String?,
) -> Bool {
  match control_label {
    None => true
    Some(target) =>
      match loop_label {
        Some(found) => found == target
        None => false
      }
  }
}

///|
fn begin_dispatch_statements(
  state : ActivationDispatchState,
  cursor : DispatchStatementCursor,
) -> (ActivationDispatchState, ActivationDispatchDecision) raise InvalidDispatchTransition {
  guard state.phase is DispatchReady else {
    invalid_dispatch_transition("statement dispatch requires Ready")
  }
  guard cursor.index >= 0 && cursor.index <= cursor.stmts.length() else {
    invalid_dispatch_transition(
      "statement cursor is outside its statement list",
    )
  }
  if cursor.index == cursor.stmts.length() {
    return route_dispatch_completion(state, DispatchNormal(cursor.last_value))
  }
  let statement = cursor.stmts[cursor.index]
  let next_cursor : DispatchStatementCursor = {
    ..cursor,
    index: cursor.index + 1,
  }
  let statement_resume = DispatchStatementResume(
    cursor=next_cursor,
    updates_last_value=!is_declaration_stmt(statement),
  )
  let step : DispatchStatementStep = {
    ctx: cursor.ctx,
    stmt: statement,
    env: cursor.env,
    index: cursor.index,
  }
  let with_frame = push_dispatch_frame(
    state,
    DispatchStatementFrame(statement_resume),
  )
  if cursor.production {
    schedule_dispatch_production_work(
      with_frame,
      DispatchExecuteStatement(step),
    )
  } else {
    schedule_dispatch_effect(
      with_frame,
      DispatchRun(DispatchExecuteStatement(step)),
    )
  }
}

///|
fn begin_dispatch_numeric_statement_observation(
  state : ActivationDispatchState,
  observation : DispatchNumericStatementObservation,
  continuation : DispatchNumericStatementContinuation,
) -> (ActivationDispatchState, ActivationDispatchDecision) raise InvalidDispatchTransition {
  guard state.phase is DispatchReady else {
    invalid_dispatch_transition("numeric statement observation requires Ready")
  }
  schedule_dispatch_production_work(
    push_dispatch_frame(
      state,
      DispatchContinuationFrame(
        DispatchContinueNumericStatement(
          snapshot_dispatch_numeric_statement_continuation(continuation),
        ),
      ),
    ),
    DispatchNumericObserveStatementStep(observation),
  )
}

///|
fn begin_dispatch_numeric_protected_statement(
  state : ActivationDispatchState,
  region : DispatchNumericProtectedRegion,
  expression : DispatchNumericExpression,
  completion : NumericRecursionRootCallCompletion,
) -> (ActivationDispatchState, ActivationDispatchDecision) raise InvalidDispatchTransition {
  let kind = match completion {
    NumericRecursionRootCallValue => DispatchNumericExpressionStatement
    NumericRecursionRootCallThrow => DispatchNumericThrowStatement
  }
  begin_dispatch_numeric_statement_observation(
    state,
    DispatchNumericObserveProtectedStatement(region, kind),
    DispatchAfterNumericProtectedStatement(
      DispatchNumericProtectedStatementStart(expression~, completion~),
    ),
  )
}

///|
fn begin_dispatch_numeric_closed_body(
  state : ActivationDispatchState,
  region : DispatchNumericProtectedRegion,
  body : NumericRecursionClosedBodyRecipe,
  catch_binding : DispatchNumericCatchBindingToken?,
) -> (ActivationDispatchState, ActivationDispatchDecision) raise InvalidDispatchTransition {
  match body {
    NumericRecursionClosedBodyEmpty =>
      route_dispatch_completion(state, DispatchNormal(Undefined))
    NumericRecursionClosedNumberValue(value) =>
      begin_dispatch_numeric_protected_statement(
        state,
        region,
        DispatchNumericNumber(value),
        NumericRecursionRootCallValue,
      )
    NumericRecursionClosedNumberThrow(value) =>
      begin_dispatch_numeric_protected_statement(
        state,
        region,
        DispatchNumericNumber(value),
        NumericRecursionRootCallThrow,
      )
    NumericRecursionClosedBindingValue => {
      guard catch_binding is Some(token) else {
        return invalid_dispatch_transition(
          "numeric binding body requires a catch capability",
        )
      }
      begin_dispatch_numeric_protected_statement(
        state,
        region,
        DispatchNumericCatchBinding(token),
        NumericRecursionRootCallValue,
      )
    }
    NumericRecursionClosedBindingThrow => {
      guard catch_binding is Some(token) else {
        return invalid_dispatch_transition(
          "numeric binding body requires a catch capability",
        )
      }
      begin_dispatch_numeric_protected_statement(
        state,
        region,
        DispatchNumericCatchBinding(token),
        NumericRecursionRootCallThrow,
      )
    }
  }
}

///|
fn begin_dispatch_numeric_protected_root(
  state : ActivationDispatchState,
  start : DispatchNumericProtectedStart,
) -> (ActivationDispatchState, ActivationDispatchDecision) raise InvalidDispatchTransition {
  let with_finalizer = match start.recipe.finalizer_recipe {
    NumericRecursionNoFinalizer => state
    NumericRecursionFinalizer(body) =>
      push_dispatch_frame(state, DispatchNumericFinallyFrame(body))
  }
  let with_handler = match start.recipe.catch_recipe {
    NumericRecursionNoCatch => with_finalizer
    NumericRecursionCatch(parameter, body) =>
      push_dispatch_frame(
        with_finalizer,
        DispatchNumericCatchFrame(
          DispatchNumericCatchResume(
            token=start.catch_binding,
            parameter~,
            body~,
          ),
        ),
      )
  }
  begin_dispatch_numeric_protected_statement(
    with_handler,
    DispatchNumericTryBody,
    start.expression,
    start.recipe.try_completion,
  )
}

///|
fn begin_dispatch_numeric_program(
  state : ActivationDispatchState,
  start : DispatchNumericProgramStart,
) -> (ActivationDispatchState, ActivationDispatchDecision) raise InvalidDispatchTransition {
  guard start.declaration_count > 0 else {
    invalid_dispatch_transition(
      "numeric root requires at least one declaration observation",
    )
  }
  begin_dispatch_numeric_statement_observation(
    state,
    DispatchNumericObserveRootDeclaration(0),
    DispatchAfterNumericRootDeclaration(
      DispatchNumericRootDeclarationResume(
        next_index=1,
        remaining=start.declaration_count - 1,
        expression=snapshot_dispatch_numeric_expression(start.expression),
        root_control=start.root_control,
        catch_binding=start.catch_binding,
      ),
    ),
  )
}

///|
fn resume_dispatch_numeric_statement(
  state : ActivationDispatchState,
  continuation : DispatchNumericStatementContinuation,
  value : Value,
) -> (ActivationDispatchState, ActivationDispatchDecision) raise InvalidDispatchTransition {
  guard state.phase is DispatchReady else {
    invalid_dispatch_transition("numeric statement resume requires Ready")
  }
  guard value is Undefined else {
    invalid_dispatch_transition(
      "numeric statement observation returned a non-sentinel value",
    )
  }
  match continuation {
    DispatchAfterNumericRootDeclaration(progress) => {
      guard progress.next_index > 0 && progress.remaining >= 0 else {
        invalid_dispatch_transition(
          "numeric root declaration progress is invalid",
        )
      }
      if progress.remaining > 0 {
        begin_dispatch_numeric_statement_observation(
          state,
          DispatchNumericObserveRootDeclaration(progress.next_index),
          DispatchAfterNumericRootDeclaration(
            DispatchNumericRootDeclarationResume(
              next_index=progress.next_index + 1,
              remaining=progress.remaining - 1,
              expression=progress.expression,
              root_control=progress.root_control,
              catch_binding=progress.catch_binding,
            ),
          ),
        )
      } else {
        match progress.root_control {
          NumericRecursionDirectRoot =>
            begin_dispatch_numeric_statement_observation(
              state,
              DispatchNumericObserveRootExpressionStatement,
              DispatchAfterNumericRootExpressionStatement(progress.expression),
            )
          NumericRecursionProtectedRoot(recipe) =>
            begin_dispatch_numeric_statement_observation(
              state,
              DispatchNumericObserveRootTryStatement,
              DispatchAfterNumericRootTryStatement(
                DispatchNumericProtectedStart(
                  expression=progress.expression,
                  recipe~,
                  catch_binding=progress.catch_binding,
                ),
              ),
            )
        }
      }
    }
    DispatchAfterNumericRootExpressionStatement(expression) =>
      begin_dispatch_numeric_expression(state, expression)
    DispatchAfterNumericRootTryStatement(start) =>
      begin_dispatch_numeric_protected_root(state, start)
    DispatchAfterNumericFunctionTryStatement(start) =>
      begin_dispatch_numeric_statement_observation(
        push_dispatch_frame(state, DispatchNumericFinallyFrame(start.finalizer)),
        DispatchNumericObserveProtectedStatement(
          DispatchNumericTryBody,
          DispatchNumericReturnStatement,
        ),
        DispatchAfterNumericReturnStatement(start.expression),
      )
    DispatchAfterNumericProtectedStatement(start) => {
      let waiting = match start.completion {
        NumericRecursionRootCallValue => state
        NumericRecursionRootCallThrow =>
          push_dispatch_frame(
            state,
            DispatchContinuationFrame(DispatchCompleteThrow),
          )
      }
      begin_dispatch_numeric_expression(waiting, start.expression)
    }
    DispatchAfterNumericCatchEntry(catch_state) => {
      let binding = match catch_state.parameter {
        Some(_) => Some(catch_state.token)
        None => None
      }
      begin_dispatch_numeric_closed_body(
        state,
        DispatchNumericCatchBody,
        catch_state.body,
        binding,
      )
    }
    DispatchAfterNumericIfStatement(start) => {
      let waiting_condition = push_dispatch_frame(
        state,
        DispatchContinuationFrame(
          DispatchContinueNumericExpression(
            DispatchAfterNumericBaseCondition(start),
          ),
        ),
      )
      begin_dispatch_numeric_expression(
        waiting_condition,
        numeric_recursion_base_condition_dispatch_expression(
          start.recipe,
          start.parameter,
        ),
      )
    }
    DispatchAfterNumericReturnStatement(expression) =>
      begin_dispatch_numeric_expression(
        push_dispatch_frame(
          state,
          DispatchContinuationFrame(DispatchCompleteReturn),
        ),
        expression,
      )
  }
}

///|
fn route_dispatch_completion(
  state : ActivationDispatchState,
  completion : DispatchCompletion,
) -> (ActivationDispatchState, ActivationDispatchDecision) raise InvalidDispatchTransition {
  guard state.phase is DispatchReady else {
    invalid_dispatch_transition("completion routing requires Ready")
  }
  let mut frames = state.frames
  let mut routed = completion
  // The routing loop decreases a weighted explicit-work measure. Ordinary
  // frames weigh one; finally frames weigh two because entering an empty
  // finalizer replaces that frame with one saved-completion frame. Every
  // internal iteration strictly decreases that weight. Branches that add
  // further semantic work return a decision to the outer dispatcher.
  while true {
    match frames {
      DispatchFrameStackEmpty => {
        let finished : ActivationDispatchState = {
          frames,
          phase: DispatchFinishedPhase(routed),
          ticket_cursor: state.ticket_cursor,
        }
        return (finished, DispatchFinish(routed))
      }
      DispatchFrameStackNode(frame, rest) => {
        frames = rest
        let popped = with_dispatch_frames(state, frames)
        match frame {
          DispatchContinuationFrame(continuation) =>
            match (continuation, routed) {
              (DispatchCompleteReturn, DispatchNormal(value)) =>
                routed = DispatchReturn(value)
              (DispatchCompleteThrow, DispatchNormal(value)) =>
                routed = DispatchThrow(JsException(value))
              (DispatchDeliverCallResult, DispatchNormal(_)) => ()
              (DispatchContinueNumericExpression(numeric), DispatchNormal(value)
              ) =>
                match
                  resume_dispatch_numeric_expression_outcome(
                    popped, numeric, value,
                  ) {
                  DispatchResumeCompletion(next) => routed = next
                  DispatchResumeDecision(next_state, decision) =>
                    return (next_state, decision)
                }
              (DispatchContinueExpressionPlan(plan), DispatchNormal(value)) =>
                match resume_dispatch_expression_plan(popped, plan, value) {
                  DispatchResumeCompletion(next) => routed = next
                  DispatchResumeDecision(next_state, decision) =>
                    return (next_state, decision)
                }
              (DispatchContinueResultPipeline(cursor), DispatchNormal(value)) =>
                match dispatch_result_pipeline_transition(cursor, value) {
                  DispatchResultPipelineSuspend(request, next_cursor) =>
                    return suspend_dispatch_work(
                      popped,
                      DispatchSuspendCall(
                        request,
                        DispatchContinueResultPipeline(next_cursor),
                      ),
                    )
                  DispatchResultPipelineComplete(value) =>
                    routed = DispatchReturn(value)
                }
              (DispatchApplyNumericBinaryRight(binary), DispatchNormal(value)) =>
                return schedule_dispatch_production_work(
                  popped,
                  DispatchNumericApplyBinaryRight(binary, value),
                )
              (DispatchComposeBinaryRight(binary_call), DispatchNormal(value)) =>
                match binary_call.left_value {
                  None => {
                    guard dispatch_managed_user_func_adapter_token_matches(
                        binary_call.left_adapter,
                        binary_call.left_request.callee,
                      ) &&
                      dispatch_managed_user_func_adapter_token_matches(
                        binary_call.right_adapter,
                        binary_call.right_request.callee,
                      ) else {
                      invalid_dispatch_transition(
                        "binary-right call adapter token drifted",
                      )
                    }
                    return suspend_dispatch_work(
                      popped,
                      DispatchSuspendCall(
                        binary_call.right_request,
                        DispatchComposeBinaryRight(
                          DispatchBinaryRightCallResume(
                            left_request=binary_call.left_request,
                            right_request=binary_call.right_request,
                            left_value=Some(value),
                            op=binary_call.op,
                            loc=binary_call.loc,
                            left_adapter=binary_call.left_adapter,
                            right_adapter=binary_call.right_adapter,
                          ),
                        ),
                      ),
                    )
                  }
                  Some(left) => {
                    guard dispatch_managed_user_func_adapter_token_matches(
                      binary_call.right_adapter,
                      binary_call.right_request.callee,
                    ) else {
                      invalid_dispatch_transition(
                        "binary-right result adapter token drifted",
                      )
                    }
                    return schedule_dispatch_production_work(
                      popped,
                      DispatchNumericApplyBinaryRight(
                        DispatchBinaryResume(
                          op=binary_call.op,
                          left~,
                          loc=binary_call.loc,
                        ),
                        value,
                      ),
                    )
                  }
                }
              (DispatchApplyPropertyBinaryRight(binary), DispatchNormal(value)) =>
                return schedule_dispatch_production_work(
                  popped,
                  DispatchPropertyApplyBinaryRight(binary, value),
                )
              (DispatchDeliverAccessorResult(accessor), DispatchNormal(value)) =>
                return schedule_dispatch_production_work(
                  popped,
                  DispatchPropertyDeliverAccessorResult(accessor, value),
                )
              (DispatchApplyConstructProperty(property), DispatchNormal(value)) =>
                return schedule_dispatch_production_work(
                  popped,
                  DispatchPropertyStart(
                    DispatchPropertyGetResume(
                      target=value,
                      property_key=property.property_key,
                      receiver=value,
                      loc=property.loc,
                    ),
                    DispatchDeliverCallResult,
                  ),
                )
              (DispatchAssignConstructResult(assign), DispatchNormal(value)) =>
                return schedule_dispatch_production_work(
                  popped,
                  DispatchConstructAssignResult(assign, value),
                )
              (DispatchResolveProxyGetTrap(lookup), DispatchNormal(value)) =>
                return schedule_dispatch_production_work(
                  popped,
                  DispatchPropertyResolveProxyGetTrap(lookup, value),
                )
              (DispatchCheckProxyGetResult(work), DispatchNormal(value)) =>
                return schedule_dispatch_production_work(
                  popped,
                  DispatchPropertyCheckProxyGetResult(work, value),
                )
              (DispatchContinueNumericStatement(numeric), DispatchNormal(value)) =>
                match numeric {
                  DispatchAfterNumericCatchEntry(catch_state) =>
                    match (value, catch_state.body) {
                      (Undefined, NumericRecursionClosedBodyEmpty) =>
                        routed = DispatchNormal(Undefined)
                      _ =>
                        return resume_dispatch_numeric_statement(
                          popped, numeric, value,
                        )
                    }
                  _ =>
                    return resume_dispatch_numeric_statement(
                      popped, numeric, value,
                    )
                }
              (DispatchContinueMap(map), DispatchNormal(value)) =>
                return schedule_dispatch_production_work(
                  popped,
                  DispatchMapResume(map, value),
                )
              (
                DispatchContinueMap(map),
                DispatchThrow(error)
                | DispatchRuntimeAbrupt(error),
              ) =>
                return schedule_dispatch_production_work(
                  popped,
                  DispatchMapAbort(map, error),
                )
              (DispatchMapStartMemberCall(member_resume), DispatchNormal(value)) =>
                return schedule_dispatch_production_work(
                  popped,
                  DispatchMapStartMemberCall(member_resume, value),
                )
              (consumer, DispatchNormal(value)) =>
                return schedule_dispatch_effect(
                  popped,
                  DispatchRun(DispatchResumeContinuation(consumer, value)),
                )
              (_, abrupt) => routed = abrupt
            }
          DispatchStatementFrame(statement_resume) =>
            match routed {
              DispatchNormal(value) => {
                let cursor = if statement_resume.updates_last_value {
                  { ..statement_resume.cursor, last_value: value }
                } else {
                  statement_resume.cursor
                }
                if cursor.index == cursor.stmts.length() {
                  routed = DispatchNormal(cursor.last_value)
                } else {
                  return begin_dispatch_statements(popped, cursor)
                }
              }
              DispatchBreak(value, label) =>
                routed = DispatchBreak(
                  Some(
                    dispatch_completion_value(
                      value,
                      statement_resume.cursor.last_value,
                    ),
                  ),
                  label,
                )
              DispatchContinue(value, label) =>
                routed = DispatchContinue(
                  Some(
                    dispatch_completion_value(
                      value,
                      statement_resume.cursor.last_value,
                    ),
                  ),
                  label,
                )
              other => routed = other
            }
          DispatchLoopFrame(loop_state) =>
            match routed {
              DispatchNormal(value) => {
                let next_loop : DispatchLoopResume = {
                  ..loop_state,
                  completion: value,
                }
                if loop_state.production {
                  return schedule_dispatch_production_work(
                    popped,
                    DispatchAdvanceLoop(next_loop),
                  )
                } else {
                  return schedule_dispatch_effect(
                    popped,
                    DispatchRun(DispatchAdvanceLoop(next_loop)),
                  )
                }
              }
              DispatchContinue(value, label) =>
                if dispatch_loop_label_matches(label, loop_state.label) {
                  let next_loop : DispatchLoopResume = {
                    ..loop_state,
                    completion: dispatch_completion_value(
                      value,
                      loop_state.completion,
                    ),
                  }
                  if loop_state.production {
                    return schedule_dispatch_production_work(
                      popped,
                      DispatchAdvanceLoop(next_loop),
                    )
                  } else {
                    return schedule_dispatch_effect(
                      popped,
                      DispatchRun(DispatchAdvanceLoop(next_loop)),
                    )
                  }
                } else {
                  routed = DispatchContinue(value, label)
                }
              DispatchBreak(value, label) =>
                if dispatch_loop_label_matches(label, loop_state.label) {
                  routed = DispatchNormal(
                    dispatch_completion_value(value, loop_state.completion),
                  )
                } else {
                  routed = DispatchBreak(value, label)
                }
              other => routed = other
            }
          DispatchSwitchFrame(completion) =>
            match routed {
              DispatchBreak(value, None) =>
                routed = DispatchNormal(
                  dispatch_completion_value(value, completion),
                )
              other => routed = other
            }
          DispatchLabelFrame(expected) =>
            match routed {
              DispatchBreak(value, Some(actual)) if actual == expected =>
                routed = DispatchNormal(
                  dispatch_completion_value(value, Undefined),
                )
              other => routed = other
            }
          DispatchCatchFrame(catch_work) =>
            match routed {
              DispatchThrow(value) =>
                return schedule_dispatch_effect(
                  popped,
                  DispatchRun(DispatchExecuteCatch(catch_work, value)),
                )
              other => routed = other
            }
          DispatchNumericCatchFrame(catch_work) =>
            match routed {
              DispatchThrow(value) =>
                return schedule_dispatch_production_work(
                  push_dispatch_frame(
                    popped,
                    DispatchContinuationFrame(
                      DispatchContinueNumericStatement(
                        DispatchAfterNumericCatchEntry(catch_work),
                      ),
                    ),
                  ),
                  DispatchNumericEnterCatch(catch_work, value),
                )
              other => routed = other
            }
          DispatchFinallyFrame(finalizer_work) => {
            let waiting_finalizer = push_dispatch_frame(
              popped,
              DispatchSavedCompletionFrame(routed),
            )
            if finalizer_work.index == finalizer_work.stmts.length() {
              frames = waiting_finalizer.frames
              routed = DispatchNormal(finalizer_work.last_value)
            } else {
              return begin_dispatch_statements(
                waiting_finalizer, finalizer_work,
              )
            }
          }
          DispatchNumericFinallyFrame(finalizer_body) => {
            let waiting_finalizer = push_dispatch_frame(
              popped,
              DispatchSavedCompletionFrame(routed),
            )
            match finalizer_body {
              NumericRecursionClosedBodyEmpty => {
                frames = waiting_finalizer.frames
                routed = DispatchNormal(Undefined)
              }
              _ =>
                return begin_dispatch_numeric_closed_body(
                  waiting_finalizer,
                  DispatchNumericFinalizerBody,
                  finalizer_body,
                  None,
                )
            }
          }
          DispatchSavedCompletionFrame(saved) =>
            match routed {
              DispatchNormal(_) => routed = saved
              abrupt => routed = abrupt
            }
          DispatchPropertyScopeFrame(cleanup) =>
            return schedule_dispatch_effect(
              popped,
              DispatchRestorePropertyScope(cleanup, routed),
            )
          DispatchActivationFrame(cleanup, exit_rule) => {
            if exit_rule is DispatchFunctionExit {
              match routed {
                DispatchBreak(_, _) | DispatchContinue(_, _) =>
                  return schedule_dispatch_control_normalization(
                    popped, cleanup, routed,
                  )
                _ => ()
              }
            }
            let leaving = normalize_activation_completion(exit_rule, routed)
            return schedule_dispatch_effect(
              popped,
              DispatchReleaseActivation(cleanup, leaving),
            )
          }
        }
      }
    }
  }
  invalid_dispatch_transition("completion routing did not terminate")
}

///|
fn suspend_dispatch_work(
  state : ActivationDispatchState,
  suspension : DispatchSuspension,
) -> (ActivationDispatchState, ActivationDispatchDecision) raise InvalidDispatchTransition {
  match suspension {
    DispatchSuspendStatements(cursor) =>
      begin_dispatch_statements(
        state,
        snapshot_dispatch_statement_cursor(cursor),
      )
    DispatchSuspendParameters(progress) =>
      schedule_dispatch_effect(
        state,
        DispatchRun(
          DispatchAdvanceParameters(
            snapshot_dispatch_parameter_progress(progress),
          ),
        ),
      )
    DispatchSuspendContinue(continuation, work) =>
      schedule_dispatch_effect(
        push_dispatch_frame(
          state,
          DispatchContinuationFrame(
            snapshot_dispatch_continuation(continuation),
          ),
        ),
        DispatchRun(work),
      )
    DispatchSuspendContinueProduction(continuation, work) =>
      schedule_dispatch_production_work(
        push_dispatch_frame(
          state,
          DispatchContinuationFrame(
            snapshot_dispatch_continuation(continuation),
          ),
        ),
        work,
      )
    DispatchSuspendCall(request, continuation) =>
      schedule_dispatch_effect(
        push_dispatch_frame(
          state,
          DispatchContinuationFrame(
            snapshot_dispatch_continuation(continuation),
          ),
        ),
        DispatchEnterActivation(DispatchCallActivation(request)),
      )
    DispatchSuspendConstruct(request, continuation) =>
      schedule_dispatch_effect(
        push_dispatch_frame(
          state,
          DispatchContinuationFrame(
            snapshot_dispatch_continuation(continuation),
          ),
        ),
        DispatchEnterActivation(DispatchConstructActivation(request)),
      )
    DispatchSuspendNumericExpression(expression, outer_consumer) => {
      let with_outer_consumer = match outer_consumer {
        Some(continuation) =>
          push_dispatch_frame(
            state,
            DispatchContinuationFrame(
              snapshot_dispatch_continuation(continuation),
            ),
          )
        None => state
      }
      begin_dispatch_numeric_expression(with_outer_consumer, expression)
    }
    DispatchSuspendProtected(work, catch_work, finalizer_work) => {
      let with_finalizer = match finalizer_work {
        Some(cursor) =>
          push_dispatch_frame(
            state,
            DispatchFinallyFrame(snapshot_dispatch_statement_cursor(cursor)),
          )
        None => state
      }
      let with_handler = match catch_work {
        Some(catch_state) =>
          push_dispatch_frame(
            with_finalizer,
            DispatchCatchFrame(snapshot_dispatch_catch_resume(catch_state)),
          )
        None => with_finalizer
      }
      begin_dispatch_statements(
        with_handler,
        snapshot_dispatch_statement_cursor(work),
      )
    }
    DispatchSuspendLoopIteration(loop_state, body) =>
      begin_dispatch_statements(
        push_dispatch_frame(
          state,
          DispatchLoopFrame(snapshot_dispatch_loop_resume(loop_state)),
        ),
        snapshot_dispatch_statement_cursor(body),
      )
    DispatchSuspendSwitch(completion, body) =>
      begin_dispatch_statements(
        push_dispatch_frame(state, DispatchSwitchFrame(completion)),
        snapshot_dispatch_statement_cursor(body),
      )
    DispatchSuspendLabel(label, body) =>
      begin_dispatch_statements(
        push_dispatch_frame(state, DispatchLabelFrame(label)),
        snapshot_dispatch_statement_cursor(body),
      )
    DispatchSuspendProperty(cleanup, work, continuation) => {
      let with_consumer = push_dispatch_frame(
        state,
        DispatchContinuationFrame(snapshot_dispatch_continuation(continuation)),
      )
      let with_scope = push_dispatch_frame(
        with_consumer,
        DispatchPropertyScopeFrame(cleanup),
      )
      schedule_dispatch_effect(
        with_scope,
        DispatchRunProduction(DispatchPropertyExecute(work)),
      )
    }
  }
}

///|
fn complete_dispatch_effect(
  state : ActivationDispatchState,
  pending : DispatchPendingEffect,
  result : DispatchEffectResult,
) -> (ActivationDispatchState, ActivationDispatchDecision) raise InvalidDispatchTransition {
  let ready = ready_dispatch_state(state)
  match (pending, result) {
    (
      DispatchPendingActivationEntry(_, DispatchPendingProgram(work)),
      DispatchProgramAccepted(cleanup),
    ) => {
      let entered = push_dispatch_frame(
        ready,
        DispatchActivationFrame(cleanup, DispatchRootExit),
      )
      begin_dispatch_statements(entered, work)
    }
    (
      DispatchPendingActivationEntry(_, DispatchPendingProgram(_)),
      DispatchNumericProgramAccepted(cleanup, start),
    ) => {
      let entered = push_dispatch_frame(
        ready,
        DispatchActivationFrame(cleanup, DispatchRootExit),
      )
      begin_dispatch_numeric_program(entered, start)
    }
    (
      DispatchPendingActivationEntry(_, DispatchPendingCall),
      DispatchCallAccepted(cleanup, DispatchCallBody(work)),
    ) => {
      let entered = push_dispatch_frame(
        ready,
        DispatchActivationFrame(cleanup, DispatchFunctionExit),
      )
      begin_dispatch_statements(
        entered,
        snapshot_dispatch_statement_cursor(work),
      )
    }
    (
      DispatchPendingActivationEntry(_, DispatchPendingCall),
      DispatchCallAccepted(cleanup, DispatchCallParameters(progress)),
    ) => {
      let entered = push_dispatch_frame(
        ready,
        DispatchActivationFrame(cleanup, DispatchFunctionExit),
      )
      schedule_dispatch_effect(
        entered,
        DispatchRun(
          DispatchAdvanceParameters(
            snapshot_dispatch_parameter_progress(progress),
          ),
        ),
      )
    }
    (
      DispatchPendingActivationEntry(_, DispatchPendingCall),
      DispatchCallAccepted(cleanup, DispatchNumericCall(start)),
    ) => {
      let entered = push_dispatch_frame(
        ready,
        DispatchActivationFrame(cleanup, DispatchFunctionExit),
      )
      begin_dispatch_numeric_statement_observation(
        entered,
        DispatchNumericObserveIfStatement,
        DispatchAfterNumericIfStatement(start),
      )
    }
    (
      DispatchPendingActivationEntry(_, DispatchPendingConstruct),
      DispatchCallAccepted(cleanup, DispatchConstructorCall(work, receiver)),
    ) => {
      let entered = push_dispatch_frame(
        ready,
        DispatchActivationFrame(cleanup, DispatchConstructorExit(receiver)),
      )
      begin_dispatch_statements(
        entered,
        snapshot_dispatch_statement_cursor(work),
      )
    }
    (
      DispatchPendingActivationEntry(_, _),
      DispatchActivationRejected(cleanup, rejection),
    ) => {
      let rejected = match rejection {
        DispatchEntryGuestThrow(error) => DispatchThrow(error)
        DispatchEntryRuntimeAbrupt(error) => DispatchRuntimeAbrupt(error)
      }
      schedule_dispatch_effect(
        ready,
        DispatchRollbackRejectedEntry(cleanup, rejected),
      )
    }
    (DispatchPendingWork(_), DispatchWorkCompleted(completion)) =>
      route_dispatch_completion(ready, completion)
    (DispatchPendingWork(_), DispatchWorkSuspended(suspension)) =>
      suspend_dispatch_work(ready, suspension)
    (
      DispatchPendingControlNormalization(_, cleanup),
      DispatchEscapedControlNormalized(error),
    ) =>
      schedule_dispatch_effect(
        ready,
        DispatchReleaseActivation(cleanup, DispatchThrow(error)),
      )
    (DispatchPendingActivationRelease(_, completion), DispatchCleanupCompleted)
    | (DispatchPendingPropertyRestore(_, completion), DispatchCleanupCompleted)
    | (DispatchPendingRejectedRollback(_, completion), DispatchCleanupCompleted) =>
      route_dispatch_completion(ready, completion)
    _ =>
      invalid_dispatch_transition("effect result does not match pending effect")
  }
}

///|
#warnings("-unused_value")
fn reduce_activation_dispatch(
  state : ActivationDispatchState,
  event : ActivationDispatchEvent,
) -> (ActivationDispatchState, ActivationDispatchDecision) raise InvalidDispatchTransition {
  match (state.phase, event) {
    (DispatchReady, DispatchStart(request)) => {
      guard state.frames is DispatchFrameStackEmpty else {
        invalid_dispatch_transition("root start requires an empty frame stack")
      }
      schedule_dispatch_effect(state, DispatchEnterActivation(request))
    }
    (DispatchAwaiting(pending), DispatchEffectCompleted(ticket, result)) => {
      require_dispatch_ticket(pending_dispatch_ticket(pending), ticket)
      complete_dispatch_effect(state, pending, result)
    }
    (DispatchReady, DispatchEffectCompleted(_, _)) =>
      invalid_dispatch_transition("no dispatch effect is awaiting a result")
    (DispatchAwaiting(_), DispatchStart(_)) =>
      invalid_dispatch_transition("dispatch has already started")
    (DispatchFinishedPhase(_), _) =>
      invalid_dispatch_transition("dispatch is already finished")
  }
}