2020-04-15 16:58:22 -03:00
/*
2024-10-04 08:19:50 -03:00
* Copyright ( c ) 2020 - 2022 , Andreas Kling < andreas @ ladybird . org >
2020-04-15 16:58:22 -03:00
*
2021-04-22 05:24:48 -03:00
* SPDX - License - Identifier : BSD - 2 - Clause
2020-04-15 16:58:22 -03:00
*/
2022-12-20 18:09:57 -03:00
# include <LibJS/Runtime/AbstractOperations.h>
2021-07-01 07:24:46 -03:00
# include <LibJS/Runtime/DeclarativeEnvironment.h>
2020-06-08 15:31:21 -03:00
# include <LibJS/Runtime/Error.h>
2021-06-27 16:48:34 -03:00
# include <LibJS/Runtime/FunctionObject.h>
2020-09-27 10:18:55 -03:00
# include <LibJS/Runtime/GlobalObject.h>
2020-06-08 15:31:21 -03:00
# include <LibJS/Runtime/Value.h>
2020-04-15 16:58:22 -03:00
namespace JS {
2024-11-14 12:01:23 -03:00
GC_DEFINE_ALLOCATOR ( DeclarativeEnvironment ) ;
2023-11-19 05:45:05 -03:00
2022-03-09 17:37:10 -03:00
DeclarativeEnvironment * DeclarativeEnvironment : : create_for_per_iteration_bindings ( Badge < ForStatement > , DeclarativeEnvironment & other , size_t bindings_size )
{
auto bindings = other . m_bindings . span ( ) . slice ( 0 , bindings_size ) ;
2022-04-30 20:10:05 -03:00
auto * parent_environment = other . outer_environment ( ) ;
2022-03-09 17:37:10 -03:00
2024-11-13 14:13:46 -03:00
return parent_environment - > heap ( ) . allocate < DeclarativeEnvironment > ( parent_environment , bindings ) ;
2022-03-09 17:37:10 -03:00
}
2021-07-01 07:24:46 -03:00
DeclarativeEnvironment : : DeclarativeEnvironment ( )
2024-05-11 08:31:33 -03:00
: Environment ( nullptr , IsDeclarative : : Yes )
2025-01-16 18:51:26 -03:00
, m_dispose_capability ( new_dispose_capability ( ) )
2020-04-15 16:58:22 -03:00
{
}
2022-04-30 20:10:05 -03:00
DeclarativeEnvironment : : DeclarativeEnvironment ( Environment * parent_environment )
2024-05-11 08:31:33 -03:00
: Environment ( parent_environment , IsDeclarative : : Yes )
2025-01-16 18:51:26 -03:00
, m_dispose_capability ( new_dispose_capability ( ) )
2021-06-21 19:56:14 -03:00
{
}
2023-02-05 16:02:54 -03:00
DeclarativeEnvironment : : DeclarativeEnvironment ( Environment * parent_environment , ReadonlySpan < Binding > bindings )
2024-05-11 08:31:33 -03:00
: Environment ( parent_environment , IsDeclarative : : Yes )
2022-03-09 17:37:10 -03:00
, m_bindings ( bindings )
2025-01-16 18:51:26 -03:00
, m_dispose_capability ( new_dispose_capability ( ) )
2022-03-09 17:37:10 -03:00
{
}
2021-07-01 07:24:46 -03:00
void DeclarativeEnvironment : : visit_edges ( Visitor & visitor )
2020-04-15 16:58:22 -03:00
{
2021-01-28 06:13:47 -03:00
Base : : visit_edges ( visitor ) ;
2025-01-16 18:51:26 -03:00
m_dispose_capability . visit_edges ( visitor ) ;
2021-10-06 18:38:46 -03:00
for ( auto & binding : m_bindings )
visitor . visit ( binding . value ) ;
2020-04-15 16:58:22 -03:00
}
2021-06-23 07:26:37 -03:00
// 9.1.1.1.1 HasBinding ( N ), https://tc39.es/ecma262/#sec-declarative-environment-records-hasbinding-n
2025-08-02 20:27:29 -03:00
ThrowCompletionOr < bool > DeclarativeEnvironment : : has_binding ( Utf16FlyString const & name , Optional < size_t > * out_index ) const
2021-06-23 07:26:37 -03:00
{
2022-09-01 18:22:17 -03:00
auto binding_and_index = find_binding_and_index ( name ) ;
if ( ! binding_and_index . has_value ( ) )
2021-10-06 18:53:22 -03:00
return false ;
2022-09-01 18:22:17 -03:00
if ( ! is_permanently_screwed_by_eval ( ) & & out_index & & binding_and_index - > index ( ) . has_value ( ) )
* out_index = * ( binding_and_index - > index ( ) ) ;
2021-10-06 18:53:22 -03:00
return true ;
2021-06-23 07:26:37 -03:00
}
2021-06-23 08:25:57 -03:00
// 9.1.1.1.2 CreateMutableBinding ( N, D ), https://tc39.es/ecma262/#sec-declarative-environment-records-createmutablebinding-n-d
2025-08-02 20:27:29 -03:00
ThrowCompletionOr < void > DeclarativeEnvironment : : create_mutable_binding ( VM & , Utf16FlyString const & name , bool can_be_deleted )
2021-06-23 07:26:37 -03:00
{
2022-05-02 15:54:39 -03:00
// 1. Assert: envRec does not already have a binding for N.
// NOTE: We skip this to avoid O(n) traversal of m_bindings.
2021-10-09 14:53:25 -03:00
// 2. Create a mutable binding in envRec for N and record that it is uninitialized. If D is true, record that the newly created binding may be deleted by a subsequent DeleteBinding call.
2024-10-24 05:32:04 -03:00
m_bindings_assoc . set ( name , m_bindings . size ( ) ) ;
2021-10-06 18:38:46 -03:00
m_bindings . append ( Binding {
2022-03-08 13:56:42 -03:00
. name = name ,
2021-10-06 18:38:46 -03:00
. value = { } ,
. strict = false ,
. mutable_ = true ,
. can_be_deleted = can_be_deleted ,
. initialized = false ,
} ) ;
2021-10-09 14:53:25 -03:00
2023-07-12 09:30:51 -03:00
+ + m_environment_serial_number ;
2022-05-02 15:54:39 -03:00
// 3. Return unused.
2021-10-09 14:53:25 -03:00
return { } ;
2021-06-23 07:26:37 -03:00
}
2021-06-23 08:25:57 -03:00
// 9.1.1.1.3 CreateImmutableBinding ( N, S ), https://tc39.es/ecma262/#sec-declarative-environment-records-createimmutablebinding-n-s
2025-08-02 20:27:29 -03:00
ThrowCompletionOr < void > DeclarativeEnvironment : : create_immutable_binding ( VM & , Utf16FlyString const & name , bool strict )
2021-06-23 07:26:37 -03:00
{
2022-05-02 15:54:39 -03:00
// 1. Assert: envRec does not already have a binding for N.
// NOTE: We skip this to avoid O(n) traversal of m_bindings.
2021-10-09 15:00:06 -03:00
// 2. Create an immutable binding in envRec for N and record that it is uninitialized. If S is true, record that the newly created binding is a strict binding.
2024-10-24 05:32:04 -03:00
m_bindings_assoc . set ( name , m_bindings . size ( ) ) ;
2021-10-06 18:38:46 -03:00
m_bindings . append ( Binding {
2022-03-08 13:56:42 -03:00
. name = name ,
2021-10-06 18:38:46 -03:00
. value = { } ,
. strict = strict ,
. mutable_ = false ,
. can_be_deleted = false ,
. initialized = false ,
} ) ;
2021-10-09 15:00:06 -03:00
2023-07-12 09:30:51 -03:00
+ + m_environment_serial_number ;
2022-05-02 15:54:39 -03:00
// 3. Return unused.
2021-10-09 15:00:06 -03:00
return { } ;
2021-06-23 07:26:37 -03:00
}
2021-06-23 08:25:57 -03:00
// 9.1.1.1.4 InitializeBinding ( N, V ), https://tc39.es/ecma262/#sec-declarative-environment-records-initializebinding-n-v
2022-12-14 09:26:10 -03:00
// 4.1.1.1.1 InitializeBinding ( N, V, hint ), https://tc39.es/proposal-explicit-resource-management/#sec-declarative-environment-records
2025-08-02 20:27:29 -03:00
ThrowCompletionOr < void > DeclarativeEnvironment : : initialize_binding ( VM & vm , Utf16FlyString const & name , Value value , Environment : : InitializeBindingHint hint )
2021-06-23 07:26:37 -03:00
{
2024-05-13 17:03:52 -03:00
return initialize_binding_direct ( vm , find_binding_and_index ( name ) - > index ( ) . value ( ) , value , hint ) ;
}
ThrowCompletionOr < void > DeclarativeEnvironment : : initialize_binding_direct ( VM & vm , size_t index , Value value , Environment : : InitializeBindingHint hint )
{
auto & binding = m_bindings . at ( index ) ;
2022-03-08 14:02:55 -03:00
2021-10-09 15:16:24 -03:00
// 1. Assert: envRec must have an uninitialized binding for N.
2021-10-06 18:38:46 -03:00
VERIFY ( binding . initialized = = false ) ;
2021-10-09 15:16:24 -03:00
2025-01-16 18:51:26 -03:00
// 2. If hint is not normal, perform ? AddDisposableResource(envRec.[[DisposeCapability]], V, hint).
2022-12-20 18:09:57 -03:00
if ( hint ! = Environment : : InitializeBindingHint : : Normal )
2025-01-16 18:51:26 -03:00
TRY ( add_disposable_resource ( vm , m_dispose_capability , value , hint ) ) ;
2022-12-14 09:26:10 -03:00
// 3. Set the bound value for N in envRec to V.
2021-10-06 18:38:46 -03:00
binding . value = value ;
2021-10-09 15:16:24 -03:00
2022-12-14 09:26:10 -03:00
// 4. Record that the binding for N in envRec has been initialized.
2021-10-06 18:38:46 -03:00
binding . initialized = true ;
2021-10-09 15:16:24 -03:00
2022-12-14 09:26:10 -03:00
// 5. Return unused.
2021-10-09 15:16:24 -03:00
return { } ;
2021-06-23 07:26:37 -03:00
}
2021-06-23 08:25:57 -03:00
// 9.1.1.1.5 SetMutableBinding ( N, V, S ), https://tc39.es/ecma262/#sec-declarative-environment-records-setmutablebinding-n-v-s
2025-08-02 20:27:29 -03:00
ThrowCompletionOr < void > DeclarativeEnvironment : : set_mutable_binding ( VM & vm , Utf16FlyString const & name , Value value , bool strict )
2021-06-23 07:26:37 -03:00
{
2021-10-09 15:34:54 -03:00
// 1. If envRec does not have a binding for N, then
2022-09-01 18:22:17 -03:00
auto binding_and_index = find_binding_and_index ( name ) ;
if ( ! binding_and_index . has_value ( ) ) {
2021-10-09 15:34:54 -03:00
// a. If S is true, throw a ReferenceError exception.
if ( strict )
2022-08-21 11:12:43 -03:00
return vm . throw_completion < ReferenceError > ( ErrorType : : UnknownIdentifier , name ) ;
2021-10-09 15:34:54 -03:00
2022-05-24 14:19:49 -03:00
// b. Perform ! envRec.CreateMutableBinding(N, true).
2022-08-21 11:12:43 -03:00
MUST ( create_mutable_binding ( vm , name , true ) ) ;
2021-10-09 15:34:54 -03:00
2022-12-14 09:26:10 -03:00
// c. Perform ! envRec.InitializeBinding(N, V, normal).
MUST ( initialize_binding ( vm , name , value , Environment : : InitializeBindingHint : : Normal ) ) ;
2021-10-09 15:34:54 -03:00
2022-05-02 15:54:39 -03:00
// d. Return unused.
2021-10-09 15:34:54 -03:00
return { } ;
2021-06-23 07:26:37 -03:00
}
2021-10-09 15:34:54 -03:00
// 2-5. (extracted into a non-standard function below)
2022-09-01 18:22:17 -03:00
TRY ( set_mutable_binding_direct ( vm , binding_and_index - > binding ( ) , value , strict ) ) ;
2021-10-09 15:34:54 -03:00
2022-05-02 15:54:39 -03:00
// 6. Return unused.
2021-10-09 15:34:54 -03:00
return { } ;
2021-10-06 19:10:00 -03:00
}
2022-08-21 11:12:43 -03:00
ThrowCompletionOr < void > DeclarativeEnvironment : : set_mutable_binding_direct ( VM & vm , size_t index , Value value , bool strict )
2021-10-06 19:10:00 -03:00
{
2022-09-01 18:22:17 -03:00
return set_mutable_binding_direct ( vm , m_bindings [ index ] , value , strict ) ;
}
ThrowCompletionOr < void > DeclarativeEnvironment : : set_mutable_binding_direct ( VM & vm , Binding & binding , Value value , bool strict )
{
2021-10-06 18:38:46 -03:00
if ( binding . strict )
2021-06-23 07:26:37 -03:00
strict = true ;
2021-10-09 15:34:54 -03:00
if ( ! binding . initialized )
2022-08-21 11:12:43 -03:00
return vm . throw_completion < ReferenceError > ( ErrorType : : BindingNotInitialized , binding . name ) ;
2021-06-23 07:26:37 -03:00
2021-10-06 18:38:46 -03:00
if ( binding . mutable_ ) {
binding . value = value ;
2021-06-23 07:26:37 -03:00
} else {
2021-10-09 15:34:54 -03:00
if ( strict )
2022-08-21 11:12:43 -03:00
return vm . throw_completion < TypeError > ( ErrorType : : InvalidAssignToConst ) ;
2021-06-23 07:26:37 -03:00
}
2021-10-09 15:34:54 -03:00
return { } ;
2021-06-23 07:26:37 -03:00
}
2021-06-23 08:25:57 -03:00
// 9.1.1.1.6 GetBindingValue ( N, S ), https://tc39.es/ecma262/#sec-declarative-environment-records-getbindingvalue-n-s
2025-08-02 20:27:29 -03:00
ThrowCompletionOr < Value > DeclarativeEnvironment : : get_binding_value ( VM & vm , Utf16FlyString const & name , [[maybe_unused]] bool strict )
2021-06-23 07:26:37 -03:00
{
2021-10-09 15:43:19 -03:00
// 1. Assert: envRec has a binding for N.
2022-09-01 18:22:17 -03:00
auto binding_and_index = find_binding_and_index ( name ) ;
VERIFY ( binding_and_index . has_value ( ) ) ;
2021-10-09 15:43:19 -03:00
// 2-3. (extracted into a non-standard function below)
2024-05-11 12:22:59 -03:00
return get_binding_value_direct ( vm , binding_and_index - > binding ( ) ) ;
2021-06-23 07:26:37 -03:00
}
2021-06-23 08:25:57 -03:00
// 9.1.1.1.7 DeleteBinding ( N ), https://tc39.es/ecma262/#sec-declarative-environment-records-deletebinding-n
2025-08-02 20:27:29 -03:00
ThrowCompletionOr < bool > DeclarativeEnvironment : : delete_binding ( VM & , Utf16FlyString const & name )
2021-06-23 07:26:37 -03:00
{
2021-10-09 15:49:08 -03:00
// 1. Assert: envRec has a binding for the name that is the value of N.
2022-09-01 18:22:17 -03:00
auto binding_and_index = find_binding_and_index ( name ) ;
VERIFY ( binding_and_index . has_value ( ) ) ;
2021-10-09 15:49:08 -03:00
// 2. If the binding for N in envRec cannot be deleted, return false.
2022-09-01 18:22:17 -03:00
if ( ! binding_and_index - > binding ( ) . can_be_deleted )
2021-06-23 07:26:37 -03:00
return false ;
2021-10-09 15:49:08 -03:00
// 3. Remove the binding for N from envRec.
2022-03-08 13:56:42 -03:00
// NOTE: We keep the entries in m_bindings to avoid disturbing indices.
2022-09-01 18:22:17 -03:00
binding_and_index - > binding ( ) = { } ;
2021-10-09 15:49:08 -03:00
2023-07-12 09:30:51 -03:00
+ + m_environment_serial_number ;
2021-10-09 15:49:08 -03:00
// 4. Return true.
2021-06-23 07:26:37 -03:00
return true ;
}
2025-08-02 20:27:29 -03:00
ThrowCompletionOr < void > DeclarativeEnvironment : : initialize_or_set_mutable_binding ( VM & vm , Utf16FlyString const & name , Value value )
2021-09-22 07:44:56 -03:00
{
2022-09-01 18:22:17 -03:00
auto binding_and_index = find_binding_and_index ( name ) ;
VERIFY ( binding_and_index . has_value ( ) ) ;
if ( ! binding_and_index - > binding ( ) . initialized )
2022-12-14 09:26:10 -03:00
TRY ( initialize_binding ( vm , name , value , Environment : : InitializeBindingHint : : Normal ) ) ;
2021-09-22 07:44:56 -03:00
else
2022-08-21 11:12:43 -03:00
TRY ( set_mutable_binding ( vm , name , value , false ) ) ;
2022-02-12 13:18:45 -03:00
return { } ;
}
2025-08-02 20:27:29 -03:00
void DeclarativeEnvironment : : initialize_or_set_mutable_binding ( Badge < ScopeNode > , VM & vm , Utf16FlyString const & name , Value value )
2022-02-12 13:18:45 -03:00
{
2022-08-21 11:12:43 -03:00
MUST ( initialize_or_set_mutable_binding ( vm , name , value ) ) ;
2021-09-22 07:44:56 -03:00
}
2022-11-26 16:33:52 -03:00
void DeclarativeEnvironment : : shrink_to_fit ( )
{
m_bindings . shrink_to_fit ( ) ;
}
2020-04-15 16:58:22 -03:00
}