// Executor-neutral function activation seam. Runtime owns observable function
// setup and completion normalization; executor packages supply only opaque code
// and private resumable frames. The neutral step surface returns neither a
// host-language continuation nor executor state. Until #631 migrates nested
// guest entry, individual executor steps may still cross the documented
// synchronous compatibility boundary; no stack-safety claim covers those
// operations.
///|
pub enum ExecutorActivationStep {
ExecutorActivationContinue
ExecutorActivationNormal(Value)
ExecutorActivationReturn(Value)
ExecutorActivationCall(ExecutorCallRequest)
ExecutorActivationConstruct(ExecutorConstructRequest)
ExecutorActivationPropertyGet(ExecutorPropertyGetRequest)
}
///|
// A closed child completion. Runtime owns the completion boundary so executor
// frames can choose whether an abrupt child result is recoverable without
// translating or copying the original error.
pub enum ExecutorActivationCompletion {
ExecutorActivationCompletionNormal(Value)
ExecutorActivationCompletionAbrupt(Error)
}
///|
priv enum ExecutorActivationRequestOutcome {
ExecutorActivationRequestChild
ExecutorActivationRequestValue(Value)
}
///|
pub fn executor_activation_completion_normal(
value : Value,
) -> ExecutorActivationCompletion {
ExecutorActivationCompletionNormal(value)
}
///|
pub fn executor_activation_completion_abrupt(
error : Error,
) -> ExecutorActivationCompletion {
ExecutorActivationCompletionAbrupt(error)
}
///|
// A closed ordinary-call request. Runtime owns the request fields and the
// coordinator is the only code that may inspect them; executors only create a
// request and later consume its one-shot result through their frame.
pub struct ExecutorCallRequest {
priv callee : Value
priv this_value : Value
priv args : Array[Value]
priv loc : @token.Loc
}
///|
fn ExecutorCallRequest::ExecutorCallRequest(
callee~ : Value,
this_value~ : Value,
args~ : Array[Value],
loc~ : @token.Loc,
) -> ExecutorCallRequest {
{ callee, this_value, args: args.copy(), loc }
}
///|
pub fn executor_activation_call(
callee : Value,
this_value : Value,
args : Array[Value],
loc : @token.Loc,
) -> ExecutorActivationStep {
ExecutorActivationCall(ExecutorCallRequest(callee~, this_value~, args~, loc~))
}
///|
// A closed static property-get request. Runtime owns property lookup and
// accessor admission; executors only provide the already-evaluated target and
// the static property name.
pub struct ExecutorPropertyGetRequest {
priv target : Value
priv property_name : String
priv loc : @token.Loc
}
///|
fn ExecutorPropertyGetRequest::ExecutorPropertyGetRequest(
target~ : Value,
property_name~ : String,
loc~ : @token.Loc,
) -> ExecutorPropertyGetRequest {
{ target, property_name, loc }
}
///|
pub fn executor_activation_property_get(
target : Value,
property_name : String,
loc : @token.Loc,
) -> ExecutorActivationStep {
ExecutorActivationPropertyGet(
ExecutorPropertyGetRequest(target~, property_name~, loc~),
)
}
///|
// A closed direct-construction request. Runtime retains ownership of
// constructability, prototype selection, instance allocation, new.target, and
// constructor completion; executors only provide already-evaluated operands.
pub struct ExecutorConstructRequest {
priv ctor : Value
priv args : Array[Value]
priv loc : @token.Loc
}
///|
fn ExecutorConstructRequest::ExecutorConstructRequest(
ctor~ : Value,
args~ : Array[Value],
loc~ : @token.Loc,
) -> ExecutorConstructRequest {
{ ctor, args: args.copy(), loc }
}
///|
pub fn executor_activation_construct(
ctor : Value,
args : Array[Value],
loc : @token.Loc,
) -> ExecutorActivationStep {
ExecutorActivationConstruct(ExecutorConstructRequest(ctor~, args~, loc~))
}
///|
pub fn executor_activation_continue() -> ExecutorActivationStep {
ExecutorActivationContinue
}
///|
pub fn executor_activation_normal(value : Value) -> ExecutorActivationStep {
ExecutorActivationNormal(value)
}
///|
pub fn executor_activation_return(value : Value) -> ExecutorActivationStep {
ExecutorActivationReturn(value)
}
///|
pub struct PreparedExecutorActivation {
ctx : ExecContext
env : Environment
args : Array[Value]
}
///|
fn PreparedExecutorActivation::PreparedExecutorActivation(
ctx~ : ExecContext,
env~ : Environment,
args~ : Array[Value],
) -> PreparedExecutorActivation {
{ ctx, env, args: args.copy() }
}
///|
pub fn PreparedExecutorActivation::context(
self : PreparedExecutorActivation,
) -> ExecContext {
self.ctx
}
///|
pub fn PreparedExecutorActivation::environment(
self : PreparedExecutorActivation,
) -> Environment {
self.env
}
///|
pub fn PreparedExecutorActivation::arguments(
self : PreparedExecutorActivation,
) -> ArrayView[Value] {
self.args.view()
}
///|
pub(open) trait ExecutorActivationFrame {
fn step(Self, Interpreter) -> ExecutorActivationStep raise Error
fn deliver_activation_completion(Self, ExecutorActivationCompletion) -> Unit raise Error
}
///|
pub(open) trait ExecutorCode {
fn start(Self, Interpreter, PreparedExecutorActivation) -> &ExecutorActivationFrame raise Error
}
///|
priv enum ExecutorCallableKind {
OrdinaryExecutorCallable
ArrowExecutorCallable
}
///|
// Runtime-owned metadata for a callable executor body. The code capability is
// mode-neutral and remains recoverable before entry so a managed dispatcher can
// start the private executor frame without invoking a final-value callback.
pub struct ExecutorCallableData {
priv name : String
priv params : Array[String]
priv closure : Environment
priv strict : Bool
priv code : &ExecutorCode
priv rest_param : String?
priv constructable : Bool
priv self_name : String?
priv define_arguments_object : Bool
priv kind : ExecutorCallableKind
priv activation_capability_summary : ExecutorActivationCapabilitySummary?
}
///|
pub fn ExecutorCallableData::name(self : ExecutorCallableData) -> String {
self.name
}
///|
pub fn ExecutorCallableData::length(self : ExecutorCallableData) -> Int {
self.params.length()
}
///|
pub fn ExecutorCallableData::is_constructable(
self : ExecutorCallableData,
) -> Bool {
self.constructable
}
///|
pub fn ExecutorCallableData::start_frame(
self : ExecutorCallableData,
interp : Interpreter,
prepared : PreparedExecutorActivation,
) -> &ExecutorActivationFrame raise Error {
self.code.start(interp, prepared)
}
///|
priv struct ExecutorActivationCleanup {
observation : ActivationObservationToken
cleared_realm : ClearedActiveCalleeRealmScope
active_realm : ActiveCalleeRealmValueScope
property_scope : ClearedActiveCalleeRealmScope?
saved_in_default : Bool
saved_param_default_conflicts : @set.Set[String]?
}
///|
priv enum ExecutorChildCompletion {
ExecutorChildCall(ExecutorCallableKind)
ExecutorChildConstruct(Value)
}
///|
priv enum ExecutorActivationStart {
ExecutorStartCall(ExecutorCallRequest)
ExecutorStartConstruct(ExecutorConstructRequest)
}
///|
priv struct ExecutorActivationStackEntry {
frame : &ExecutorActivationFrame
completion : ExecutorChildCompletion?
cleanup : ExecutorActivationCleanup?
graph_cursor : TreeExecutorGraphCursor?
}
///|
fn Interpreter::restore_executor_activation_resources(
self : Interpreter,
cleared_realm : ClearedActiveCalleeRealmScope,
active_realm : ActiveCalleeRealmValueScope,
saved_in_default : Bool,
saved_param_default_conflicts : @set.Set[String]?,
failure : Error?,
) -> Unit {
self.in_nonarrow_param_default_eval = saved_in_default
self.param_default_eval_var_conflicts = saved_param_default_conflicts
finish_active_callee_realm_value(self.realm_state, active_realm, failure~)
finish_cleared_active_callee_realm(self.realm_state, cleared_realm)
}
///|
fn Interpreter::finish_executor_activation(
self : Interpreter,
cleanup : ExecutorActivationCleanup,
failure : Error?,
) -> Unit raise Error {
self.restore_executor_activation_resources(
cleanup.cleared_realm,
cleanup.active_realm,
cleanup.saved_in_default,
cleanup.saved_param_default_conflicts,
failure,
)
let release_error : Error? = try {
cleanup.observation.release()
None
} catch {
InvalidActivationObservationTransition(message) =>
Some(
@errors.InternalError(
message="executor activation release is invalid: " + message,
),
)
}
match cleanup.property_scope {
Some(scope) => finish_cleared_active_callee_realm(self.realm_state, scope)
None => ()
}
match release_error {
Some(error) => raise error
None => ()
}
}
///|
fn reject_executor_activation_observation(
attempt : ActivationEntryAttempt,
) -> Unit raise Error {
attempt.reject() catch {
InvalidActivationObservationTransition(message) =>
raise @errors.InternalError(
message="executor activation rejection is invalid: " + message,
)
}
}
///|
fn release_rejected_executor_activation_observation(
attempt : ActivationEntryAttempt,
) -> Unit raise Error {
attempt.release_after_rejection() catch {
InvalidActivationObservationTransition(message) =>
raise @errors.InternalError(
message="executor rejected activation release is invalid: " + message,
)
}
}
///|
fn observe_executor_activation_entry(
interp : Interpreter,
) -> ActivationEntryAttempt raise Error {
observe_activation_entry(
interp.execution_control_activation_observation_port(),
)
}
///|
fn Interpreter::start_executor_activation(
self : Interpreter,
executable : ExecutorCallableData,
start : ExecutorActivationStart,
property_scope : ClearedActiveCalleeRealmScope?,
graph_cursor? : TreeExecutorGraphCursor? = None,
) -> ExecutorActivationStackEntry raise Error {
let callee = match start {
ExecutorStartCall(request) => request.callee
ExecutorStartConstruct(request) => request.ctor
}
let observation = observe_executor_activation_entry(self) catch {
error => {
match property_scope {
Some(scope) =>
finish_cleared_active_callee_realm(self.realm_state, scope)
None => ()
}
raise error
}
}
let cleared_realm = begin_cleared_active_callee_realm(self.realm_state)
let active_realm = begin_active_callee_realm_value(self.realm_state, callee)
let saved_in_default = self.in_nonarrow_param_default_eval
let saved_param_default_conflicts = self.param_default_eval_var_conflicts
self.in_nonarrow_param_default_eval = false
self.param_default_eval_var_conflicts = None
let setup : Result[(&ExecutorActivationFrame, ExecutorChildCompletion), Error] = Ok(
match start {
ExecutorStartCall(request) => {
let prepared = self.prepare_executor_callable_call(
executable,
request.callee,
request.this_value,
request.args,
)
(
executable.start_frame(self, prepared),
ExecutorChildCall(executable.kind),
)
}
ExecutorStartConstruct(request) => {
let proto = self.get_prototype_from_constructor(
request.ctor,
request.loc,
)
let instance = make_constructor_instance(proto, "Object")
let prepared = self.prepare_executor_activation(
request.ctor,
instance,
request.args,
executable.params,
executable.rest_param,
executable.closure,
executable.strict,
Some(request.ctor),
!executable.constructable,
executable.self_name,
executable.define_arguments_object,
)
(
executable.start_frame(self, prepared),
ExecutorChildConstruct(instance),
)
}
},
) catch {
error => Err(error)
}
match setup {
Err(error) => {
reject_executor_activation_observation(observation)
self.restore_executor_activation_resources(
cleared_realm,
active_realm,
saved_in_default,
saved_param_default_conflicts,
Some(error),
)
let release_error : Error? = try {
release_rejected_executor_activation_observation(observation)
None
} catch {
error => Some(error)
}
match property_scope {
Some(scope) =>
finish_cleared_active_callee_realm(self.realm_state, scope)
None => ()
}
match release_error {
Some(cleanup_error) => raise cleanup_error
None => raise error
}
}
Ok((frame, completion)) => {
let accepted = observation.accept()
{
frame,
completion: Some(completion),
cleanup: Some({
observation: accepted,
cleared_realm,
active_realm,
property_scope,
saved_in_default,
saved_param_default_conflicts,
}),
graph_cursor,
}
}
}
}
///|
fn Interpreter::complete_executor_child(
self : Interpreter,
stack : Array[ExecutorActivationStackEntry],
completion : ExecutorActivationCompletion,
) -> Unit raise Error {
let entry = stack.pop().unwrap()
let failure = match completion {
ExecutorActivationCompletionAbrupt(error) => Some(error)
ExecutorActivationCompletionNormal(_) => None
}
match entry.cleanup {
Some(cleanup) => self.finish_executor_activation(cleanup, failure)
None => ()
}
let parent = stack[stack.length() - 1].frame
parent.deliver_activation_completion(completion)
}
///|
fn Interpreter::complete_executor_step(
self : Interpreter,
stack : Array[ExecutorActivationStackEntry],
step : ExecutorActivationStep,
) -> Unit raise Error {
let completion = match stack[stack.length() - 1].completion {
Some(ExecutorChildCall(kind)) =>
ExecutorActivationCompletionNormal(executor_call_completion(kind, step))
Some(ExecutorChildConstruct(instance)) =>
ExecutorActivationCompletionNormal(
executor_construct_completion(step, instance),
)
None => ExecutorActivationCompletionNormal(Undefined)
}
self.complete_executor_child(stack, completion)
}
///|
fn Interpreter::deliver_executor_activation_error(
self : Interpreter,
stack : Array[ExecutorActivationStackEntry],
index : Int,
error : Error,
) -> Unit raise Error {
if index == 0 {
raise error
} else {
self.complete_executor_child(
stack,
ExecutorActivationCompletionAbrupt(error),
)
}
}
///|
fn deliver_executor_activation_request_error(
frame : &ExecutorActivationFrame,
error : Error,
) -> Unit raise Error {
frame.deliver_activation_completion(ExecutorActivationCompletionAbrupt(error))
}
///|
fn deliver_executor_activation_request(
frame : &ExecutorActivationFrame,
requested : Result[ExecutorActivationRequestOutcome, Error],
) -> Unit raise Error {
match requested {
Ok(ExecutorActivationRequestChild) => ()
Ok(ExecutorActivationRequestValue(value)) =>
frame.deliver_activation_completion(
ExecutorActivationCompletionNormal(value),
)
Err(error) => deliver_executor_activation_request_error(frame, error)
}
}
///|
fn direct_executor_constructor_with_data_prototype(
ctor : Value,
) -> ExecutorCallableData? {
match ctor {
Object(object_data) =>
match object_data.callable {
Some(ExecutorCallable(executable)) if executable.constructable =>
match object_data.bag.descriptors.get("prototype") {
Some(descriptor) if !descriptor.is_accessor &&
object_data.bag.properties.contains("prototype") =>
Some(executable)
_ => None
}
_ => None
}
_ => None
}
}
///|
// Callback-free admission for the one iterative static-property slice. The
// object and its own descriptor are inspected directly so no guest code runs
// before the property scope and executor activation are installed.
fn direct_executor_property_getter(
target : Value,
property_name : String,
) -> (Value, ExecutorCallableData)? {
match target {
Object(data) if data.class_name == "Object" &&
data.callable is None &&
data.arraybuffer_state is None &&
data.bag.internal_slots.is_empty() &&
data.bag.host_slots.is_empty() =>
match data.bag.descriptors.get(property_name) {
Some(descriptor) if descriptor.is_accessor =>
match descriptor.getter {
Some(getter) =>
match getter {
Object({ callable: Some(ExecutorCallable(executable)), .. }) =>
Some((getter, executable))
_ => None
}
None => None
}
_ => None
}
_ => None
}
}
///|
fn Interpreter::executor_activation_fallback_call(
self : Interpreter,
callee : Value,
this_value : Value,
args : Array[Value],
loc : @token.Loc,
) -> ExecutorActivationRequestOutcome raise Error {
ExecutorActivationRequestValue(self.call_value(callee, this_value, args, loc))
}
///|
fn Interpreter::handle_executor_activation_step(
self : Interpreter,
stack : Array[ExecutorActivationStackEntry],
index : Int,
step : ExecutorActivationStep,
) -> ExecutorActivationStep? raise Error {
let frame = stack[index].frame
match step {
ExecutorActivationContinue => None
ExecutorActivationNormal(value) =>
if index == 0 {
Some(ExecutorActivationNormal(value))
} else {
self.complete_executor_step(stack, ExecutorActivationNormal(value))
None
}
ExecutorActivationReturn(value) =>
if index == 0 {
Some(ExecutorActivationReturn(value))
} else {
self.complete_executor_step(stack, ExecutorActivationReturn(value))
None
}
ExecutorActivationCall(request) => {
let requested : Result[ExecutorActivationRequestOutcome, Error] = Ok(
{
let (forwarded_callee, forwarded_this_value, forwarded_args) = self.resolve_call_forwarding(
request.callee,
request.this_value,
request.args,
)
match stack[index].graph_cursor {
Some(graph_cursor) => {
let edge = match
tree_executor_graph_select_edge(
graph_cursor,
forwarded_callee,
forwarded_args.length(),
) {
Some(edge) => edge
None =>
raise @errors.InternalError(
message="executor activation graph proof was violated by an unmatched call",
)
}
let admission = match
tree_executor_graph_target(graph_cursor, edge) {
Some(admission) => admission
None =>
raise @errors.InternalError(
message="executor activation graph target was invalid",
)
}
let forwarded_request = ExecutorCallRequest(
callee=forwarded_callee,
this_value=forwarded_this_value,
args=forwarded_args,
loc=request.loc,
)
stack.push(
self.start_executor_activation(
admission.executable,
ExecutorStartCall(forwarded_request),
None,
graph_cursor=Some(admission.cursor),
),
)
ExecutorActivationRequestChild
}
None =>
match forwarded_callee {
Object({ callable: Some(ExecutorCallable(executable)), .. }) => {
let forwarded_request = ExecutorCallRequest(
callee=forwarded_callee,
this_value=forwarded_this_value,
args=forwarded_args,
loc=request.loc,
)
stack.push(
self.start_executor_activation(
executable,
ExecutorStartCall(forwarded_request),
None,
),
)
ExecutorActivationRequestChild
}
Object({ callable: Some(UserFunc(data)), .. }) =>
match
tree_executor_callable_admission(
forwarded_callee, data, forwarded_args,
) {
Some(admission) => {
let forwarded_request = ExecutorCallRequest(
callee=forwarded_callee,
this_value=forwarded_this_value,
args=forwarded_args,
loc=request.loc,
)
stack.push(
self.start_executor_activation(
admission.executable,
ExecutorStartCall(forwarded_request),
None,
graph_cursor=Some(admission.cursor),
),
)
ExecutorActivationRequestChild
}
None =>
self.executor_activation_fallback_call(
forwarded_callee,
forwarded_this_value,
forwarded_args,
request.loc,
)
}
_ =>
self.executor_activation_fallback_call(
forwarded_callee,
forwarded_this_value,
forwarded_args,
request.loc,
)
}
}
},
) catch {
error => Err(error)
}
deliver_executor_activation_request(frame, requested)
None
}
ExecutorActivationConstruct(request) => {
let requested : Result[ExecutorActivationRequestOutcome, Error] = Ok(
match direct_executor_constructor_with_data_prototype(request.ctor) {
Some(executable) => {
stack.push(
self.start_executor_activation(
executable,
ExecutorStartConstruct(request),
None,
),
)
ExecutorActivationRequestChild
}
None =>
ExecutorActivationRequestValue(
self.construct_value(request.ctor, request.args, request.loc),
)
},
) catch {
error => Err(error)
}
deliver_executor_activation_request(frame, requested)
None
}
ExecutorActivationPropertyGet(request) => {
let requested : Result[ExecutorActivationRequestOutcome, Error] = Ok(
match
direct_executor_property_getter(request.target, request.property_name) {
Some((getter, executable)) => {
let property_scope = begin_cleared_active_callee_realm(
self.realm_state,
)
let call_request = ExecutorCallRequest(
callee=getter,
this_value=request.target,
args=[],
loc=request.loc,
)
stack.push(
self.start_executor_activation(
executable,
ExecutorStartCall(call_request),
Some(property_scope),
),
)
ExecutorActivationRequestChild
}
None =>
ExecutorActivationRequestValue(
self.get_property(
request.target,
request.property_name,
request.loc,
),
)
},
) catch {
error => Err(error)
}
deliver_executor_activation_request(frame, requested)
None
}
}
}
///|
// Drive one root entry and every exact executor-backed ordinary call or static
// property getter it requests. Root ownership is carried by the entry: public
// top-level frames have none, while admitted ordinary-call roots own cleanup.
fn Interpreter::drive_executor_activation_stack(
self : Interpreter,
stack : Array[ExecutorActivationStackEntry],
) -> ExecutorActivationStep raise Error {
try {
while true {
guard !stack.is_empty() else {
return ExecutorActivationNormal(Undefined)
}
let index = stack.length() - 1
let frame = stack[index].frame
let stepped : Result[ExecutorActivationStep, Error] = Ok(frame.step(self)) catch {
error => Err(error)
}
match stepped {
Err(error) =>
self.deliver_executor_activation_error(stack, index, error)
Ok(step) =>
match self.handle_executor_activation_step(stack, index, step) {
Some(result) => {
let root = stack.pop().unwrap()
match root.cleanup {
Some(cleanup) => self.finish_executor_activation(cleanup, None)
None => ()
}
return result
}
None => ()
}
}
}
} catch {
error => {
let mut first_cleanup_error : Error? = None
while !stack.is_empty() {
let entry = stack.pop().unwrap()
match entry.cleanup {
Some(cleanup) => {
let cleanup_error : Error? = try {
self.finish_executor_activation(cleanup, Some(error))
None
} catch {
cleanup_error => Some(cleanup_error)
}
match (first_cleanup_error, cleanup_error) {
(None, Some(cleanup_error)) =>
first_cleanup_error = Some(cleanup_error)
_ => ()
}
}
None => ()
}
}
match first_cleanup_error {
Some(cleanup_error) => raise cleanup_error
None => raise error
}
}
}
ExecutorActivationNormal(Undefined)
}
///|
// Drive a top-level executor frame that does not represent an acquired guest
// activation. Managed ordinary-call roots use the owned entry point below.
pub fn Interpreter::run_executor_activation_coordinator(
self : Interpreter,
root : &ExecutorActivationFrame,
) -> ExecutorActivationStep raise Error {
self.drive_executor_activation_stack([
{ frame: root, completion: None, cleanup: None, graph_cursor: None },
])
}
///|
// Enter one already-admitted ordinary call as an owned coordinator root. The
// same entry owns depth observation, realm state, the sealed graph cursor, and
// exactly-once cleanup on both normal and abrupt completion.
fn Interpreter::run_admitted_executor_call_root(
self : Interpreter,
executable : ExecutorCallableData,
request : ExecutorCallRequest,
graph_cursor : TreeExecutorGraphCursor,
) -> ExecutorActivationStep raise Error {
let root = self.start_executor_activation(
executable,
ExecutorStartCall(request),
None,
graph_cursor=Some(graph_cursor),
)
self.drive_executor_activation_stack([root])
}
///|
// Prepare an ordinary call without entering executor code. This is the
// hand-off used by a managed dispatcher: runtime owns observable activation
// semantics, while the caller may push the private frame returned by
// `start_frame` instead of invoking the synchronous compatibility adapter.
pub fn Interpreter::prepare_executor_callable_call(
self : Interpreter,
executable : ExecutorCallableData,
callee : Value,
this_value : Value,
args : Array[Value],
) -> PreparedExecutorActivation raise Error {
match executable.kind {
OrdinaryExecutorCallable =>
self.prepare_executor_activation(
callee,
this_value,
args,
executable.params,
executable.rest_param,
executable.closure,
executable.strict,
None,
!executable.constructable,
executable.self_name,
executable.define_arguments_object,
)
ArrowExecutorCallable => prepare_executor_arrow_activation(executable, args)
}
}
///|
fn Interpreter::drive_executor_activation(
self : Interpreter,
code : &ExecutorCode,
prepared : PreparedExecutorActivation,
) -> ExecutorActivationStep raise Error {
let frame = code.start(self, prepared)
self.run_executor_activation_coordinator(frame)
}
///|
fn bind_executor_parameters(
env : Environment,
params : Array[String],
args : Array[Value],
) -> Unit raise Error {
for i, param in params {
let value = if i < args.length() { args[i] } else { Undefined }
if env.bindings.contains(param) {
env.assign(param, value)
} else {
env.def_parameter(param, value)
}
}
}
///|
fn bind_executor_rest_parameter(
env : Environment,
positional_count : Int,
rest_param : String?,
args : Array[Value],
) -> Unit raise Error {
match rest_param {
Some(name) => {
let rest : Array[Value] = []
for i = positional_count; i < args.length(); i = i + 1 {
rest.push(args[i])
}
env.def_parameter(name, make_array(rest))
}
None => ()
}
}
///|
fn prepare_executor_arrow_activation(
executable : ExecutorCallableData,
args : Array[Value],
) -> PreparedExecutorActivation raise Error {
let ctx : ExecContext = { strict: executable.strict, current_generator: None }
let env = Environment::new(parent=Some(executable.closure))
env.is_var_scope = true
bind_executor_parameters(env, executable.params, args)
bind_executor_rest_parameter(
env,
executable.params.length(),
executable.rest_param,
args,
)
PreparedExecutorActivation(ctx~, env~, args~)
}
///|
fn Interpreter::prepare_executor_activation(
self : Interpreter,
callee : Value,
this_value : Value,
args : Array[Value],
params : Array[String],
rest_param : String?,
closure : Environment,
strict : Bool,
new_target : Value?,
is_method : Bool,
self_name : String?,
define_arguments_object : Bool,
) -> PreparedExecutorActivation raise Error {
let ctx : ExecContext = { strict, current_generator: None }
let env = Environment::new(parent=Some(closure))
env.is_var_scope = true
env.def_builtin("[[EvalMethodContext]]", Bool(is_method))
let effective_this = if strict {
this_value
} else {
self.normalize_sloppy_this(this_value)
}
env.def("this", effective_this, LetBinding)
env.def("", new_target.unwrap_or(Undefined), LetBinding)
bind_executor_parameters(env, params, args)
bind_executor_rest_parameter(env, params.length(), rest_param, args)
if define_arguments_object && !params_include_arguments(params, rest_param) {
match rest_param {
Some(_) =>
self.define_unmapped_arguments_object(env, args, callee, strict)
None =>
self.define_simple_arguments_object(env, args, callee, strict, params)
}
}
match self_name {
Some(name) if !env.bindings.contains(name) =>
env.def(name, callee, FunctionNameBinding)
_ => ()
}
PreparedExecutorActivation(ctx~, env~, args~)
}
///|
fn executor_call_completion(
kind : ExecutorCallableKind,
step : ExecutorActivationStep,
) -> Value {
match kind {
OrdinaryExecutorCallable =>
match step {
ExecutorActivationContinue => Undefined
ExecutorActivationNormal(_) => Undefined
ExecutorActivationReturn(value) => value
ExecutorActivationCall(_)
| ExecutorActivationConstruct(_)
| ExecutorActivationPropertyGet(_) => Undefined
}
ArrowExecutorCallable =>
match step {
ExecutorActivationContinue => Undefined
ExecutorActivationNormal(value) | ExecutorActivationReturn(value) =>
value
ExecutorActivationCall(_)
| ExecutorActivationConstruct(_)
| ExecutorActivationPropertyGet(_) => Undefined
}
}
}
///|
fn executor_construct_completion(
step : ExecutorActivationStep,
instance : Value,
) -> Value {
match step {
ExecutorActivationReturn(value) if is_object_like_for_constructor_return(
value,
) => value
ExecutorActivationContinue
| ExecutorActivationNormal(_)
| ExecutorActivationReturn(_)
| ExecutorActivationCall(_)
| ExecutorActivationConstruct(_)
| ExecutorActivationPropertyGet(_) => instance
}
}
///|
fn Interpreter::run_executor_function(
self : Interpreter,
executable : ExecutorCallableData,
callee : Value,
context : CallContext,
this_value : Value,
args : Array[Value],
) -> Value raise Error {
let saved_in_default = self.in_nonarrow_param_default_eval
self.in_nonarrow_param_default_eval = false
let result : Value = try {
if context.is_constructing() {
let new_target = context.new_target().unwrap_or(callee)
let proto = self.get_prototype_from_constructor(
new_target,
@token.Loc::default(),
)
let instance = make_constructor_instance(proto, "Object")
let prepared = self.prepare_executor_activation(
callee,
instance,
args,
executable.params,
executable.rest_param,
executable.closure,
executable.strict,
Some(new_target),
!executable.constructable,
executable.self_name,
executable.define_arguments_object,
)
executor_construct_completion(
self.drive_executor_activation(executable.code, prepared),
instance,
)
} else {
let prepared = self.prepare_executor_callable_call(
executable, callee, this_value, args,
)
executor_call_completion(
executable.kind,
self.drive_executor_activation(executable.code, prepared),
)
}
} catch {
error => {
self.in_nonarrow_param_default_eval = saved_in_default
raise error
}
}
self.in_nonarrow_param_default_eval = saved_in_default
result
}
///|
fn make_executor_callable_with_capability(
function_name : String,
params : Array[String],
closure : Environment,
strict : Bool,
code : &ExecutorCode,
rest_param : String?,
constructable : Bool,
self_name : String?,
define_arguments_object : Bool,
kind : ExecutorCallableKind,
activation_capability_summary : ExecutorActivationCapabilitySummary?,
) -> Value {
let realm_state = match closure.interpreter_context {
Some(interp) => Some(interp.realm_state)
None => closure.realm_state
}
let executable : ExecutorCallableData = {
name: function_name,
params: params.copy(),
closure,
strict,
code,
rest_param,
constructable,
self_name,
define_arguments_object,
kind,
activation_capability_summary,
}
let function = build_func_object(
function_name,
params.length(),
ExecutorCallable(executable),
realm_state~,
)
if constructable {
let prototype = make_constructor_instance(
get_obj_proto(realm_state~),
"Object",
)
match function {
Object(function_data) => {
function_data.bag.properties["prototype"] = prototype
function_data.bag.descriptors["prototype"] = {
writable: true,
enumerable: false,
configurable: false,
getter: None,
setter: None,
is_accessor: false,
}
}
_ => ()
}
match prototype {
Object(prototype_data) => {
prototype_data.bag.properties["constructor"] = function
prototype_data.bag.descriptors["constructor"] = {
writable: true,
enumerable: false,
configurable: true,
getter: None,
setter: None,
is_accessor: false,
}
}
_ => ()
}
}
function
}
///|
pub fn[T : ExecutorCode] make_executor_function(
name : String?,
params : Array[String],
closure : Environment,
strict : Bool,
code : T,
rest_param? : String? = None,
constructable? : Bool = true,
call_self_name? : Bool = false,
define_arguments_object? : Bool = true,
) -> Value {
let function_name = name.unwrap_or("")
let self_name = if call_self_name { name } else { None }
make_executor_callable_with_capability(
function_name,
params,
closure,
strict,
code as &ExecutorCode,
rest_param,
constructable,
self_name,
define_arguments_object,
OrdinaryExecutorCallable,
None,
)
}
///|
/// ExecutorCode providers are trusted to supply code corresponding to
/// `source_body`; runtime admission cannot prove otherwise.
pub fn[T : ExecutorCode] make_classified_executor_function(
name : String?,
params : Array[String],
closure : Environment,
strict : Bool,
code : T,
source_body : Array[@ast.Stmt],
rest_param? : String? = None,
constructable? : Bool = true,
call_self_name? : Bool = false,
define_arguments_object? : Bool = true,
) -> Value {
let function_name = name.unwrap_or("")
let self_name = if call_self_name { name } else { None }
make_executor_callable_with_capability(
function_name,
params,
closure,
strict,
code as &ExecutorCode,
rest_param,
constructable,
self_name,
define_arguments_object,
OrdinaryExecutorCallable,
executor_activation_capability_summary(params, source_body),
)
}
///|
pub fn[T : ExecutorCode] make_executor_arrow_function(
params : Array[String],
closure : Environment,
strict : Bool,
code : T,
rest_param? : String? = None,
) -> Value {
make_executor_callable_with_capability(
"",
params,
closure,
strict,
code as &ExecutorCode,
rest_param,
false,
None,
false,
ArrowExecutorCallable,
None,
)
}
///|
/// ExecutorCode providers are trusted to supply code corresponding to
/// `source_body`; runtime admission cannot prove otherwise.
pub fn[T : ExecutorCode] make_classified_executor_arrow_function(
params : Array[String],
closure : Environment,
strict : Bool,
code : T,
source_body : Array[@ast.Stmt],
rest_param? : String? = None,
) -> Value {
make_executor_callable_with_capability(
"",
params,
closure,
strict,
code as &ExecutorCode,
rest_param,
false,
None,
false,
ArrowExecutorCallable,
executor_activation_capability_summary(params, source_body),
)
}