2021-09-09 18:03:01 +02:00
/*
2023-06-17 13:16:35 +02:00
* Copyright ( c ) 2021 - 2023 , Andreas Kling < kling @ serenityos . org >
2021-09-09 18:03:01 +02:00
*
* SPDX - License - Identifier : BSD - 2 - Clause
*/
2022-02-05 16:18:22 +01:00
# include <AK/Debug.h>
2021-09-12 21:56:44 +02:00
# include <LibCore/ElapsedTimer.h>
2023-06-17 13:16:35 +02:00
# include <LibJS/Bytecode/Interpreter.h>
2021-09-09 19:03:50 +02:00
# include <LibJS/Interpreter.h>
2021-10-14 16:12:53 +01:00
# include <LibWeb/Bindings/ExceptionOrUtils.h>
2021-09-09 18:03:01 +02:00
# include <LibWeb/HTML/Scripting/ClassicScript.h>
2021-10-14 16:12:53 +01:00
# include <LibWeb/HTML/Scripting/Environments.h>
2022-02-07 15:12:41 +01:00
# include <LibWeb/HTML/Scripting/ExceptionReporter.h>
2022-09-25 17:28:46 +01:00
# include <LibWeb/WebIDL/DOMException.h>
2021-09-09 18:03:01 +02:00
namespace Web : : HTML {
2021-09-09 19:03:50 +02:00
// https://html.spec.whatwg.org/multipage/webappapis.html#creating-a-classic-script
2022-12-04 18:02:33 +00:00
JS : : NonnullGCPtr < ClassicScript > ClassicScript : : create ( DeprecatedString filename , StringView source , EnvironmentSettingsObject & environment_settings_object , AK : : URL base_url , size_t source_line_number , MutedErrors muted_errors )
2021-09-09 18:03:01 +02:00
{
2022-09-05 14:32:33 +02:00
auto & vm = environment_settings_object . realm ( ) . vm ( ) ;
2021-09-09 19:03:50 +02:00
// 1. If muted errors was not provided, let it be false. (NOTE: This is taken care of by the default argument.)
// 2. If muted errors is true, then set baseURL to about:blank.
if ( muted_errors = = MutedErrors : : Yes )
2022-07-11 17:32:29 +00:00
base_url = " about:blank " sv ;
2021-09-09 19:03:50 +02:00
2022-03-30 22:42:09 +01:00
// 3. If scripting is disabled for settings, then set source to the empty string.
if ( environment_settings_object . is_scripting_disabled ( ) )
2022-07-11 17:32:29 +00:00
source = " " sv ;
2021-09-09 19:03:50 +02:00
// 4. Let script be a new classic script that this algorithm will subsequently initialize.
2022-09-05 14:32:33 +02:00
auto script = vm . heap ( ) . allocate_without_realm < ClassicScript > ( move ( base_url ) , move ( filename ) , environment_settings_object ) ;
2021-09-09 19:03:50 +02:00
2021-10-14 16:12:53 +01:00
// 5. Set script's settings object to settings. (NOTE: This was already done when constructing.)
2021-09-09 19:03:50 +02:00
// 6. Set script's base URL to baseURL. (NOTE: This was already done when constructing.)
// FIXME: 7. Set script's fetch options to options.
// 8. Set script's muted errors to muted errors.
script - > m_muted_errors = muted_errors ;
2023-05-18 19:05:56 +02:00
// 9. Set script's parse error and error to rethrow to null.
script - > set_parse_error ( JS : : js_null ( ) ) ;
script - > set_error_to_rethrow ( JS : : js_null ( ) ) ;
2021-09-09 19:03:50 +02:00
// 10. Let result be ParseScript(source, settings's Realm, script).
2021-09-14 21:00:41 +02:00
auto parse_timer = Core : : ElapsedTimer : : start_new ( ) ;
2022-09-05 14:32:33 +02:00
auto result = JS : : Script : : parse ( source , environment_settings_object . realm ( ) , script - > filename ( ) , script , source_line_number ) ;
2022-02-05 16:18:22 +01:00
dbgln_if ( HTML_SCRIPT_DEBUG , " ClassicScript: Parsed {} in {}ms " , script - > filename ( ) , parse_timer . elapsed ( ) ) ;
2021-09-09 19:03:50 +02:00
2021-09-14 20:56:57 +02:00
// 11. If result is a list of errors, then:
if ( result . is_error ( ) ) {
2021-10-14 16:12:53 +01:00
auto & parse_error = result . error ( ) . first ( ) ;
2022-12-06 01:12:49 +00:00
dbgln_if ( HTML_SCRIPT_DEBUG , " ClassicScript: Failed to parse: {} " , parse_error . to_deprecated_string ( ) ) ;
2021-10-14 16:12:53 +01:00
2023-05-18 19:05:56 +02:00
// 1. Set script's parse error and its error to rethrow to result[0].
script - > set_parse_error ( JS : : SyntaxError : : create ( environment_settings_object . realm ( ) , parse_error . to_string ( ) . release_value_but_fixme_should_propagate_errors ( ) ) ) ;
script - > set_error_to_rethrow ( script - > parse_error ( ) ) ;
2021-09-14 20:56:57 +02:00
// 2. Return script.
2022-12-14 17:40:33 +00:00
return script ;
2021-09-14 20:56:57 +02:00
}
2021-09-09 19:03:50 +02:00
// 12. Set script's record to result.
2022-09-05 14:32:33 +02:00
script - > m_script_record = * result . release_value ( ) ;
2021-09-09 19:03:50 +02:00
// 13. Return script.
2022-12-14 17:40:33 +00:00
return script ;
2021-09-09 19:03:50 +02:00
}
// https://html.spec.whatwg.org/multipage/webappapis.html#run-a-classic-script
2022-12-09 18:48:25 +01:00
JS : : Completion ClassicScript : : run ( RethrowErrors rethrow_errors , JS : : GCPtr < JS : : Environment > lexical_environment_override )
2021-09-09 19:03:50 +02:00
{
2022-06-27 19:50:40 +01:00
// 1. Let settings be the settings object of script.
auto & settings = settings_object ( ) ;
2021-10-14 16:12:53 +01:00
// 2. Check if we can run script with settings. If this returns "do not run" then return NormalCompletion(empty).
2022-06-27 19:50:40 +01:00
if ( settings . can_run_script ( ) = = RunScriptDecision : : DoNotRun )
2021-10-14 16:12:53 +01:00
return JS : : normal_completion ( { } ) ;
// 3. Prepare to run script given settings.
2022-06-27 19:50:40 +01:00
settings . prepare_to_run_script ( ) ;
2021-10-14 16:12:53 +01:00
// 4. Let evaluationStatus be null.
JS : : Completion evaluation_status ;
// 5. If script's error to rethrow is not null, then set evaluationStatus to Completion { [[Type]]: throw, [[Value]]: script's error to rethrow, [[Target]]: empty }.
2023-05-18 19:05:56 +02:00
if ( ! error_to_rethrow ( ) . is_null ( ) ) {
evaluation_status = JS : : Completion { JS : : Completion : : Type : : Throw , error_to_rethrow ( ) , { } } ;
2021-10-14 16:12:53 +01:00
} else {
auto timer = Core : : ElapsedTimer : : start_new ( ) ;
// 6. Otherwise, set evaluationStatus to ScriptEvaluation(script's record).
2023-06-22 15:59:18 +02:00
if ( auto * bytecode_interpreter = vm ( ) . bytecode_interpreter_if_exists ( ) ) {
evaluation_status = bytecode_interpreter - > run ( * m_script_record , lexical_environment_override ) ;
2023-06-17 13:16:35 +02:00
} else {
auto interpreter = JS : : Interpreter : : create_with_existing_realm ( m_script_record - > realm ( ) ) ;
evaluation_status = interpreter - > run ( * m_script_record , lexical_environment_override ) ;
}
2021-10-14 16:12:53 +01:00
// FIXME: If ScriptEvaluation does not complete because the user agent has aborted the running script, leave evaluationStatus as null.
dbgln_if ( HTML_SCRIPT_DEBUG , " ClassicScript: Finished running script {}, Duration: {}ms " , filename ( ) , timer . elapsed ( ) ) ;
2021-09-18 01:38:40 +02:00
}
2021-10-14 16:12:53 +01:00
// 7. If evaluationStatus is an abrupt completion, then:
if ( evaluation_status . is_abrupt ( ) ) {
// 1. If rethrow errors is true and script's muted errors is false, then:
if ( rethrow_errors = = RethrowErrors : : Yes & & m_muted_errors = = MutedErrors : : No ) {
// 1. Clean up after running script with settings.
2022-06-27 19:50:40 +01:00
settings . clean_up_after_running_script ( ) ;
2021-09-09 19:03:50 +02:00
2021-10-14 16:12:53 +01:00
// 2. Rethrow evaluationStatus.[[Value]].
return JS : : throw_completion ( * evaluation_status . value ( ) ) ;
}
2022-01-16 13:16:04 +01:00
2021-10-14 16:12:53 +01:00
// 2. If rethrow errors is true and script's muted errors is true, then:
if ( rethrow_errors = = RethrowErrors : : Yes & & m_muted_errors = = MutedErrors : : Yes ) {
// 1. Clean up after running script with settings.
2022-06-27 19:50:40 +01:00
settings . clean_up_after_running_script ( ) ;
2022-01-08 21:28:27 +01:00
2021-10-14 16:12:53 +01:00
// 2. Throw a "NetworkError" DOMException.
2022-09-25 16:38:21 -06:00
return throw_completion ( WebIDL : : NetworkError : : create ( settings . realm ( ) , " Script error. " ) ) ;
2021-10-14 16:12:53 +01:00
}
2022-01-16 13:16:04 +01:00
2021-10-14 16:12:53 +01:00
// 3. Otherwise, rethrow errors is false. Perform the following steps:
VERIFY ( rethrow_errors = = RethrowErrors : : No ) ;
2022-01-16 13:16:04 +01:00
2021-10-14 16:12:53 +01:00
// 1. Report the exception given by evaluationStatus.[[Value]] for script.
2022-10-08 19:38:32 +04:00
report_exception ( evaluation_status , settings_object ( ) . realm ( ) ) ;
2021-10-14 16:12:53 +01:00
// 2. Clean up after running script with settings.
2022-06-27 19:50:40 +01:00
settings . clean_up_after_running_script ( ) ;
2021-10-14 16:12:53 +01:00
// 3. Return evaluationStatus.
return evaluation_status ;
2022-01-08 21:28:27 +01:00
}
2021-10-14 16:12:53 +01:00
// 8. Clean up after running script with settings.
2022-06-27 19:50:40 +01:00
settings . clean_up_after_running_script ( ) ;
2021-10-14 16:12:53 +01:00
// 9. If evaluationStatus is a normal completion, then return evaluationStatus.
VERIFY ( ! evaluation_status . is_abrupt ( ) ) ;
return evaluation_status ;
// FIXME: 10. If we've reached this point, evaluationStatus was left as null because the script was aborted prematurely during evaluation.
// Return Completion { [[Type]]: throw, [[Value]]: a new "QuotaExceededError" DOMException, [[Target]]: empty }.
2021-09-09 18:03:01 +02:00
}
2022-12-04 18:02:33 +00:00
ClassicScript : : ClassicScript ( AK : : URL base_url , DeprecatedString filename , EnvironmentSettingsObject & environment_settings_object )
2022-06-27 19:50:40 +01:00
: Script ( move ( base_url ) , move ( filename ) , environment_settings_object )
2021-09-09 18:03:01 +02:00
{
}
2022-03-14 13:21:51 -06:00
ClassicScript : : ~ ClassicScript ( ) = default ;
2021-09-09 18:03:01 +02:00
2022-09-05 14:32:33 +02:00
void ClassicScript : : visit_edges ( Cell : : Visitor & visitor )
{
Base : : visit_edges ( visitor ) ;
visitor . visit ( m_script_record ) ;
}
2021-09-09 18:03:01 +02:00
}