2020-04-15 21:58:22 +02:00
/*
2022-03-07 14:02:37 +01:00
* Copyright ( c ) 2020 - 2022 , Andreas Kling < kling @ serenityos . org >
2020-04-15 21:58:22 +02:00
*
2021-04-22 01:24:48 -07:00
* SPDX - License - Identifier : BSD - 2 - Clause
2020-04-15 21:58:22 +02:00
*/
2020-06-08 13:31:21 -05:00
# include <LibJS/Interpreter.h>
2021-07-01 12:24:46 +02:00
# include <LibJS/Runtime/DeclarativeEnvironment.h>
2020-06-08 13:31:21 -05:00
# include <LibJS/Runtime/Error.h>
2021-06-27 21:48:34 +02:00
# include <LibJS/Runtime/FunctionObject.h>
2020-09-27 15:18:55 +02:00
# include <LibJS/Runtime/GlobalObject.h>
2020-06-08 13:31:21 -05:00
# include <LibJS/Runtime/Value.h>
2020-04-15 21:58:22 +02:00
namespace JS {
2022-03-09 15:37:10 -05: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-05-01 01:10:05 +02:00
auto * parent_environment = other . outer_environment ( ) ;
2022-03-09 15:37:10 -05:00
2022-05-01 01:10:05 +02:00
return parent_environment - > heap ( ) . allocate_without_global_object < DeclarativeEnvironment > ( parent_environment , bindings ) ;
2022-03-09 15:37:10 -05:00
}
2021-07-01 12:24:46 +02:00
DeclarativeEnvironment : : DeclarativeEnvironment ( )
: Environment ( nullptr )
2020-04-15 21:58:22 +02:00
{
}
2022-05-01 01:10:05 +02:00
DeclarativeEnvironment : : DeclarativeEnvironment ( Environment * parent_environment )
: Environment ( parent_environment )
2021-06-22 00:56:14 +02:00
{
}
2022-05-01 01:10:05 +02:00
DeclarativeEnvironment : : DeclarativeEnvironment ( Environment * parent_environment , Span < Binding const > bindings )
: Environment ( parent_environment )
2022-03-09 15:37:10 -05:00
, m_bindings ( bindings )
{
}
2021-07-01 12:24:46 +02:00
void DeclarativeEnvironment : : visit_edges ( Visitor & visitor )
2020-04-15 21:58:22 +02:00
{
2021-01-28 10:13:47 +01:00
Base : : visit_edges ( visitor ) ;
2021-10-06 23:38:46 +02:00
for ( auto & binding : m_bindings )
visitor . visit ( binding . value ) ;
2020-04-15 21:58:22 +02:00
}
2021-06-23 12:26:37 +02:00
// 9.1.1.1.1 HasBinding ( N ), https://tc39.es/ecma262/#sec-declarative-environment-records-hasbinding-n
2021-10-09 17:07:32 +01:00
ThrowCompletionOr < bool > DeclarativeEnvironment : : has_binding ( FlyString const & name , Optional < size_t > * out_index ) const
2021-06-23 12:26:37 +02:00
{
2022-03-08 11:56:42 -05:00
auto index = find_binding_index ( name ) ;
2022-03-07 14:02:37 +01:00
if ( ! index . has_value ( ) )
2021-10-06 23:53:22 +02:00
return false ;
2021-10-07 11:36:44 +02:00
if ( ! is_permanently_screwed_by_eval ( ) & & out_index )
2022-03-07 14:02:37 +01:00
* out_index = * index ;
2021-10-06 23:53:22 +02:00
return true ;
2021-06-23 12:26:37 +02:00
}
2021-06-23 13:25:57 +02:00
// 9.1.1.1.2 CreateMutableBinding ( N, D ), https://tc39.es/ecma262/#sec-declarative-environment-records-createmutablebinding-n-d
2021-10-09 18:53:25 +01:00
ThrowCompletionOr < void > DeclarativeEnvironment : : create_mutable_binding ( GlobalObject & , FlyString const & name , bool can_be_deleted )
2021-06-23 12:26:37 +02:00
{
2022-05-02 20:54:39 +02: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 18:53:25 +01: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.
2021-10-06 23:38:46 +02:00
m_bindings . append ( Binding {
2022-03-08 11:56:42 -05:00
. name = name ,
2021-10-06 23:38:46 +02:00
. value = { } ,
. strict = false ,
. mutable_ = true ,
. can_be_deleted = can_be_deleted ,
. initialized = false ,
} ) ;
2021-10-09 18:53:25 +01:00
2022-05-02 20:54:39 +02:00
// 3. Return unused.
2021-10-09 18:53:25 +01:00
return { } ;
2021-06-23 12:26:37 +02:00
}
2021-06-23 13:25:57 +02:00
// 9.1.1.1.3 CreateImmutableBinding ( N, S ), https://tc39.es/ecma262/#sec-declarative-environment-records-createimmutablebinding-n-s
2021-10-09 19:00:06 +01:00
ThrowCompletionOr < void > DeclarativeEnvironment : : create_immutable_binding ( GlobalObject & , FlyString const & name , bool strict )
2021-06-23 12:26:37 +02:00
{
2022-05-02 20:54:39 +02: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 19:00:06 +01: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.
2021-10-06 23:38:46 +02:00
m_bindings . append ( Binding {
2022-03-08 11:56:42 -05:00
. name = name ,
2021-10-06 23:38:46 +02:00
. value = { } ,
. strict = strict ,
. mutable_ = false ,
. can_be_deleted = false ,
. initialized = false ,
} ) ;
2021-10-09 19:00:06 +01:00
2022-05-02 20:54:39 +02:00
// 3. Return unused.
2021-10-09 19:00:06 +01:00
return { } ;
2021-06-23 12:26:37 +02:00
}
2021-06-23 13:25:57 +02:00
// 9.1.1.1.4 InitializeBinding ( N, V ), https://tc39.es/ecma262/#sec-declarative-environment-records-initializebinding-n-v
2022-03-08 12:02:55 -05:00
ThrowCompletionOr < void > DeclarativeEnvironment : : initialize_binding ( GlobalObject & global_object , FlyString const & name , Value value )
2021-06-23 12:26:37 +02:00
{
2022-03-08 11:56:42 -05:00
auto index = find_binding_index ( name ) ;
2022-03-07 14:02:37 +01:00
VERIFY ( index . has_value ( ) ) ;
2022-03-08 12:02:55 -05:00
return initialize_binding_direct ( global_object , * index , value ) ;
}
ThrowCompletionOr < void > DeclarativeEnvironment : : initialize_binding_direct ( GlobalObject & , size_t index , Value value )
{
auto & binding = m_bindings [ index ] ;
2021-10-09 19:16:24 +01:00
// 1. Assert: envRec must have an uninitialized binding for N.
2021-10-06 23:38:46 +02:00
VERIFY ( binding . initialized = = false ) ;
2021-10-09 19:16:24 +01:00
// 2. Set the bound value for N in envRec to V.
2021-10-06 23:38:46 +02:00
binding . value = value ;
2021-10-09 19:16:24 +01:00
// 3. Record that the binding for N in envRec has been initialized.
2021-10-06 23:38:46 +02:00
binding . initialized = true ;
2021-10-09 19:16:24 +01:00
2022-05-02 20:54:39 +02:00
// 4. Return unused.
2021-10-09 19:16:24 +01:00
return { } ;
2021-06-23 12:26:37 +02:00
}
2021-06-23 13:25:57 +02:00
// 9.1.1.1.5 SetMutableBinding ( N, V, S ), https://tc39.es/ecma262/#sec-declarative-environment-records-setmutablebinding-n-v-s
2021-10-09 19:34:54 +01:00
ThrowCompletionOr < void > DeclarativeEnvironment : : set_mutable_binding ( GlobalObject & global_object , FlyString const & name , Value value , bool strict )
2021-06-23 12:26:37 +02:00
{
2021-10-09 19:34:54 +01:00
// 1. If envRec does not have a binding for N, then
2022-03-08 11:56:42 -05:00
auto index = find_binding_index ( name ) ;
2022-03-07 14:02:37 +01:00
if ( ! index . has_value ( ) ) {
2021-10-09 19:34:54 +01:00
// a. If S is true, throw a ReferenceError exception.
if ( strict )
return vm ( ) . throw_completion < ReferenceError > ( global_object , ErrorType : : UnknownIdentifier , name ) ;
2022-05-24 18:19:49 +01:00
// b. Perform ! envRec.CreateMutableBinding(N, true).
2021-10-09 19:34:54 +01:00
MUST ( create_mutable_binding ( global_object , name , true ) ) ;
2022-05-02 20:54:39 +02:00
// c. Perform ! envRec.InitializeBinding(N, V).
2021-10-09 19:34:54 +01:00
MUST ( initialize_binding ( global_object , name , value ) ) ;
2022-05-02 20:54:39 +02:00
// d. Return unused.
2021-10-09 19:34:54 +01:00
return { } ;
2021-06-23 12:26:37 +02:00
}
2021-10-09 19:34:54 +01:00
// 2-5. (extracted into a non-standard function below)
2022-03-07 14:02:37 +01:00
TRY ( set_mutable_binding_direct ( global_object , * index , value , strict ) ) ;
2021-10-09 19:34:54 +01:00
2022-05-02 20:54:39 +02:00
// 6. Return unused.
2021-10-09 19:34:54 +01:00
return { } ;
2021-10-07 00:10:00 +02:00
}
2021-10-09 19:34:54 +01:00
ThrowCompletionOr < void > DeclarativeEnvironment : : set_mutable_binding_direct ( GlobalObject & global_object , size_t index , Value value , bool strict )
2021-10-07 00:10:00 +02:00
{
auto & binding = m_bindings [ index ] ;
2021-10-06 23:38:46 +02:00
if ( binding . strict )
2021-06-23 12:26:37 +02:00
strict = true ;
2021-10-09 19:34:54 +01:00
if ( ! binding . initialized )
2022-03-08 11:56:42 -05:00
return vm ( ) . throw_completion < ReferenceError > ( global_object , ErrorType : : BindingNotInitialized , binding . name ) ;
2021-06-23 12:26:37 +02:00
2021-10-06 23:38:46 +02:00
if ( binding . mutable_ ) {
binding . value = value ;
2021-06-23 12:26:37 +02:00
} else {
2021-10-09 19:34:54 +01:00
if ( strict )
return vm ( ) . throw_completion < TypeError > ( global_object , ErrorType : : InvalidAssignToConst ) ;
2021-06-23 12:26:37 +02:00
}
2021-10-09 19:34:54 +01:00
return { } ;
2021-06-23 12:26:37 +02:00
}
2021-06-23 13:25:57 +02:00
// 9.1.1.1.6 GetBindingValue ( N, S ), https://tc39.es/ecma262/#sec-declarative-environment-records-getbindingvalue-n-s
2021-10-09 19:43:19 +01:00
ThrowCompletionOr < Value > DeclarativeEnvironment : : get_binding_value ( GlobalObject & global_object , FlyString const & name , bool strict )
2021-06-23 12:26:37 +02:00
{
2021-10-09 19:43:19 +01:00
// 1. Assert: envRec has a binding for N.
2022-03-08 11:56:42 -05:00
auto index = find_binding_index ( name ) ;
2022-03-07 14:02:37 +01:00
VERIFY ( index . has_value ( ) ) ;
2021-10-09 19:43:19 +01:00
// 2-3. (extracted into a non-standard function below)
2022-03-07 14:02:37 +01:00
return get_binding_value_direct ( global_object , * index , strict ) ;
2021-10-07 00:10:00 +02:00
}
2021-10-09 19:43:19 +01:00
ThrowCompletionOr < Value > DeclarativeEnvironment : : get_binding_value_direct ( GlobalObject & global_object , size_t index , bool )
2021-10-07 00:10:00 +02:00
{
auto & binding = m_bindings [ index ] ;
2021-10-09 19:43:19 +01:00
// 2. If the binding for N in envRec is an uninitialized binding, throw a ReferenceError exception.
if ( ! binding . initialized )
2022-03-08 11:56:42 -05:00
return vm ( ) . throw_completion < ReferenceError > ( global_object , ErrorType : : BindingNotInitialized , binding . name ) ;
2021-10-09 19:43:19 +01:00
// 3. Return the value currently bound to N in envRec.
2021-10-06 23:38:46 +02:00
return binding . value ;
2021-06-23 12:26:37 +02:00
}
2021-06-23 13:25:57 +02:00
// 9.1.1.1.7 DeleteBinding ( N ), https://tc39.es/ecma262/#sec-declarative-environment-records-deletebinding-n
2021-10-09 19:49:08 +01:00
ThrowCompletionOr < bool > DeclarativeEnvironment : : delete_binding ( GlobalObject & , FlyString const & name )
2021-06-23 12:26:37 +02:00
{
2021-10-09 19:49:08 +01:00
// 1. Assert: envRec has a binding for the name that is the value of N.
2022-03-08 11:56:42 -05:00
auto index = find_binding_index ( name ) ;
2022-03-07 14:02:37 +01:00
VERIFY ( index . has_value ( ) ) ;
2021-10-09 19:49:08 +01:00
2022-03-07 14:02:37 +01:00
auto & binding = m_bindings [ * index ] ;
2021-10-09 19:49:08 +01:00
// 2. If the binding for N in envRec cannot be deleted, return false.
2021-10-06 23:38:46 +02:00
if ( ! binding . can_be_deleted )
2021-06-23 12:26:37 +02:00
return false ;
2021-10-09 19:49:08 +01:00
// 3. Remove the binding for N from envRec.
2022-03-08 11:56:42 -05:00
// NOTE: We keep the entries in m_bindings to avoid disturbing indices.
2021-10-06 23:38:46 +02:00
binding = { } ;
2021-10-09 19:49:08 +01:00
// 4. Return true.
2021-06-23 12:26:37 +02:00
return true ;
}
2022-02-12 19:48:45 +03:30
ThrowCompletionOr < void > DeclarativeEnvironment : : initialize_or_set_mutable_binding ( GlobalObject & global_object , FlyString const & name , Value value )
2021-09-22 12:44:56 +02:00
{
2022-03-08 11:56:42 -05:00
auto index = find_binding_index ( name ) ;
2022-03-07 14:02:37 +01:00
VERIFY ( index . has_value ( ) ) ;
auto & binding = m_bindings [ * index ] ;
2021-10-06 23:38:46 +02:00
if ( ! binding . initialized )
2022-02-12 19:48:45 +03:30
TRY ( initialize_binding ( global_object , name , value ) ) ;
2021-09-22 12:44:56 +02:00
else
2022-02-12 19:48:45 +03:30
TRY ( set_mutable_binding ( global_object , name , value , false ) ) ;
return { } ;
}
void DeclarativeEnvironment : : initialize_or_set_mutable_binding ( Badge < ScopeNode > , GlobalObject & global_object , FlyString const & name , Value value )
{
MUST ( initialize_or_set_mutable_binding ( global_object , name , value ) ) ;
2021-09-22 12:44:56 +02:00
}
2020-04-15 21:58:22 +02:00
}