mirror of
https://github.com/RGBCube/serenity
synced 2025-05-31 07:38:10 +00:00
LibJS: Move most of Interpreter into VM
This patch moves the exception state, call stack and scope stack from Interpreter to VM. I'm doing this to help myself discover what the split between Interpreter and VM should be, by shuffling things around and seeing what falls where. With these changes, we no longer have a persistent lexical environment for the current global object on the Interpreter's call stack. Instead, we push/pop that environment on Interpreter::run() enter/exit. Since it should only be used to find the global "this", and not for variable storage (that goes directly into the global object instead!), I had to insert some short-circuiting when walking the environment parent chain during variable lookup. Note that this is a "stepping stone" commit, not a final design.
This commit is contained in:
parent
838d9fa251
commit
6861c619c6
48 changed files with 765 additions and 726 deletions
|
@ -41,7 +41,7 @@ namespace Browser {
|
||||||
|
|
||||||
JS::Value BrowserConsoleClient::log()
|
JS::Value BrowserConsoleClient::log()
|
||||||
{
|
{
|
||||||
m_console_widget.print_html(interpreter().join_arguments());
|
m_console_widget.print_html(interpreter().vm().join_arguments());
|
||||||
return JS::js_undefined();
|
return JS::js_undefined();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -50,7 +50,7 @@ JS::Value BrowserConsoleClient::info()
|
||||||
StringBuilder html;
|
StringBuilder html;
|
||||||
html.append("<span class=\"info\">");
|
html.append("<span class=\"info\">");
|
||||||
html.append("(i) ");
|
html.append("(i) ");
|
||||||
html.append(interpreter().join_arguments());
|
html.append(interpreter().vm().join_arguments());
|
||||||
html.append("</span>");
|
html.append("</span>");
|
||||||
m_console_widget.print_html(html.string_view());
|
m_console_widget.print_html(html.string_view());
|
||||||
return JS::js_undefined();
|
return JS::js_undefined();
|
||||||
|
@ -61,7 +61,7 @@ JS::Value BrowserConsoleClient::debug()
|
||||||
StringBuilder html;
|
StringBuilder html;
|
||||||
html.append("<span class=\"debug\">");
|
html.append("<span class=\"debug\">");
|
||||||
html.append("(d) ");
|
html.append("(d) ");
|
||||||
html.append(interpreter().join_arguments());
|
html.append(interpreter().vm().join_arguments());
|
||||||
html.append("</span>");
|
html.append("</span>");
|
||||||
m_console_widget.print_html(html.string_view());
|
m_console_widget.print_html(html.string_view());
|
||||||
return JS::js_undefined();
|
return JS::js_undefined();
|
||||||
|
@ -72,7 +72,7 @@ JS::Value BrowserConsoleClient::warn()
|
||||||
StringBuilder html;
|
StringBuilder html;
|
||||||
html.append("<span class=\"warn\">");
|
html.append("<span class=\"warn\">");
|
||||||
html.append("(w) ");
|
html.append("(w) ");
|
||||||
html.append(interpreter().join_arguments());
|
html.append(interpreter().vm().join_arguments());
|
||||||
html.append("</span>");
|
html.append("</span>");
|
||||||
m_console_widget.print_html(html.string_view());
|
m_console_widget.print_html(html.string_view());
|
||||||
return JS::js_undefined();
|
return JS::js_undefined();
|
||||||
|
@ -83,7 +83,7 @@ JS::Value BrowserConsoleClient::error()
|
||||||
StringBuilder html;
|
StringBuilder html;
|
||||||
html.append("<span class=\"error\">");
|
html.append("<span class=\"error\">");
|
||||||
html.append("(e) ");
|
html.append("(e) ");
|
||||||
html.append(interpreter().join_arguments());
|
html.append(interpreter().vm().join_arguments());
|
||||||
html.append("</span>");
|
html.append("</span>");
|
||||||
m_console_widget.print_html(html.string_view());
|
m_console_widget.print_html(html.string_view());
|
||||||
return JS::js_undefined();
|
return JS::js_undefined();
|
||||||
|
@ -98,7 +98,7 @@ JS::Value BrowserConsoleClient::clear()
|
||||||
JS::Value BrowserConsoleClient::trace()
|
JS::Value BrowserConsoleClient::trace()
|
||||||
{
|
{
|
||||||
StringBuilder html;
|
StringBuilder html;
|
||||||
html.append(interpreter().join_arguments());
|
html.append(interpreter().vm().join_arguments());
|
||||||
auto trace = get_trace();
|
auto trace = get_trace();
|
||||||
for (auto& function_name : trace) {
|
for (auto& function_name : trace) {
|
||||||
if (function_name.is_empty())
|
if (function_name.is_empty())
|
||||||
|
|
|
@ -92,7 +92,7 @@ ConsoleWidget::ConsoleWidget()
|
||||||
auto hint = error.source_location_hint(js_source);
|
auto hint = error.source_location_hint(js_source);
|
||||||
if (!hint.is_empty())
|
if (!hint.is_empty())
|
||||||
output_html.append(String::format("<pre>%s</pre>", escape_html_entities(hint).characters()));
|
output_html.append(String::format("<pre>%s</pre>", escape_html_entities(hint).characters()));
|
||||||
m_interpreter->throw_exception<JS::SyntaxError>(error.to_string());
|
m_interpreter->vm().throw_exception<JS::SyntaxError>(m_interpreter->global_object(), error.to_string());
|
||||||
} else {
|
} else {
|
||||||
m_interpreter->run(m_interpreter->global_object(), *program);
|
m_interpreter->run(m_interpreter->global_object(), *program);
|
||||||
}
|
}
|
||||||
|
@ -106,7 +106,7 @@ ConsoleWidget::ConsoleWidget()
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
print_html(JS::MarkupGenerator::html_from_value(m_interpreter->last_value()));
|
print_html(JS::MarkupGenerator::html_from_value(m_interpreter->vm().last_value()));
|
||||||
};
|
};
|
||||||
|
|
||||||
auto& clear_button = bottom_container.add<GUI::Button>();
|
auto& clear_button = bottom_container.add<GUI::Button>();
|
||||||
|
|
|
@ -87,12 +87,12 @@ void SheetGlobalObject::initialize()
|
||||||
JS_DEFINE_NATIVE_FUNCTION(SheetGlobalObject::parse_cell_name)
|
JS_DEFINE_NATIVE_FUNCTION(SheetGlobalObject::parse_cell_name)
|
||||||
{
|
{
|
||||||
if (interpreter.argument_count() != 1) {
|
if (interpreter.argument_count() != 1) {
|
||||||
interpreter.throw_exception<JS::TypeError>("Expected exactly one argument to parse_cell_name()");
|
interpreter.vm().throw_exception<JS::TypeError>(global_object, "Expected exactly one argument to parse_cell_name()");
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
auto name_value = interpreter.argument(0);
|
auto name_value = interpreter.argument(0);
|
||||||
if (!name_value.is_string()) {
|
if (!name_value.is_string()) {
|
||||||
interpreter.throw_exception<JS::TypeError>("Expected a String argument to parse_cell_name()");
|
interpreter.vm().throw_exception<JS::TypeError>(global_object, "Expected a String argument to parse_cell_name()");
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
auto position = Sheet::parse_cell_name(name_value.as_string().string());
|
auto position = Sheet::parse_cell_name(name_value.as_string().string());
|
||||||
|
@ -125,12 +125,12 @@ void WorkbookObject::initialize(JS::GlobalObject& global_object)
|
||||||
JS_DEFINE_NATIVE_FUNCTION(WorkbookObject::sheet)
|
JS_DEFINE_NATIVE_FUNCTION(WorkbookObject::sheet)
|
||||||
{
|
{
|
||||||
if (interpreter.argument_count() != 1) {
|
if (interpreter.argument_count() != 1) {
|
||||||
interpreter.throw_exception<JS::TypeError>("Expected exactly one argument to sheet()");
|
interpreter.vm().throw_exception<JS::TypeError>(global_object, "Expected exactly one argument to sheet()");
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
auto name_value = interpreter.argument(0);
|
auto name_value = interpreter.argument(0);
|
||||||
if (!name_value.is_string() && !name_value.is_number()) {
|
if (!name_value.is_string() && !name_value.is_number()) {
|
||||||
interpreter.throw_exception<JS::TypeError>("Expected a String or Number argument to sheet()");
|
interpreter.vm().throw_exception<JS::TypeError>(global_object, "Expected a String or Number argument to sheet()");
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -139,7 +139,7 @@ JS_DEFINE_NATIVE_FUNCTION(WorkbookObject::sheet)
|
||||||
return {};
|
return {};
|
||||||
|
|
||||||
if (!this_object->inherits("WorkbookObject")) {
|
if (!this_object->inherits("WorkbookObject")) {
|
||||||
interpreter.throw_exception<JS::TypeError>(JS::ErrorType::NotA, "WorkbookObject");
|
interpreter.vm().throw_exception<JS::TypeError>(global_object, JS::ErrorType::NotA, "WorkbookObject");
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -164,7 +164,7 @@ JS::Value Sheet::evaluate(const StringView& source, Cell* on_behalf_of)
|
||||||
return exc;
|
return exc;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto value = interpreter().last_value();
|
auto value = interpreter().vm().last_value();
|
||||||
if (value.is_empty())
|
if (value.is_empty())
|
||||||
return JS::js_undefined();
|
return JS::js_undefined();
|
||||||
return value;
|
return value;
|
||||||
|
|
|
@ -86,7 +86,7 @@ static String get_function_name(Interpreter& interpreter, Value value)
|
||||||
|
|
||||||
Value ScopeNode::execute(Interpreter& interpreter, GlobalObject& global_object) const
|
Value ScopeNode::execute(Interpreter& interpreter, GlobalObject& global_object) const
|
||||||
{
|
{
|
||||||
return interpreter.execute_statement(global_object, *this);
|
return interpreter.vm().execute_statement(global_object, *this);
|
||||||
}
|
}
|
||||||
|
|
||||||
Value FunctionDeclaration::execute(Interpreter&, GlobalObject&) const
|
Value FunctionDeclaration::execute(Interpreter&, GlobalObject&) const
|
||||||
|
@ -113,7 +113,7 @@ CallExpression::ThisAndCallee CallExpression::compute_this_and_callee(Interprete
|
||||||
|
|
||||||
if (m_callee->is_super_expression()) {
|
if (m_callee->is_super_expression()) {
|
||||||
// If we are calling super, |this| has not been initalized yet, and would not be meaningful to provide.
|
// If we are calling super, |this| has not been initalized yet, and would not be meaningful to provide.
|
||||||
auto new_target = interpreter.get_new_target();
|
auto new_target = interpreter.vm().get_new_target();
|
||||||
ASSERT(new_target.is_function());
|
ASSERT(new_target.is_function());
|
||||||
return { js_undefined(), new_target };
|
return { js_undefined(), new_target };
|
||||||
}
|
}
|
||||||
|
@ -125,7 +125,7 @@ CallExpression::ThisAndCallee CallExpression::compute_this_and_callee(Interprete
|
||||||
if (interpreter.exception())
|
if (interpreter.exception())
|
||||||
return {};
|
return {};
|
||||||
if (is_super_property_lookup && (lookup_target.is_null() || lookup_target.is_undefined())) {
|
if (is_super_property_lookup && (lookup_target.is_null() || lookup_target.is_undefined())) {
|
||||||
interpreter.throw_exception<TypeError>(ErrorType::ObjectPrototypeNullOrUndefinedOnSuperPropertyAccess, lookup_target.to_string_without_side_effects().characters());
|
interpreter.vm().throw_exception<TypeError>(global_object, ErrorType::ObjectPrototypeNullOrUndefinedOnSuperPropertyAccess, lookup_target.to_string_without_side_effects().characters());
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -160,9 +160,9 @@ Value CallExpression::execute(Interpreter& interpreter, GlobalObject& global_obj
|
||||||
} else {
|
} else {
|
||||||
expression_string = static_cast<const MemberExpression&>(*m_callee).to_string_approximation();
|
expression_string = static_cast<const MemberExpression&>(*m_callee).to_string_approximation();
|
||||||
}
|
}
|
||||||
interpreter.throw_exception<TypeError>(ErrorType::IsNotAEvaluatedFrom, callee.to_string_without_side_effects().characters(), call_type, expression_string.characters());
|
interpreter.vm().throw_exception<TypeError>(global_object, ErrorType::IsNotAEvaluatedFrom, callee.to_string_without_side_effects().characters(), call_type, expression_string.characters());
|
||||||
} else {
|
} else {
|
||||||
interpreter.throw_exception<TypeError>(ErrorType::IsNotA, callee.to_string_without_side_effects().characters(), call_type);
|
interpreter.vm().throw_exception<TypeError>(global_object, ErrorType::IsNotA, callee.to_string_without_side_effects().characters(), call_type);
|
||||||
}
|
}
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
@ -192,17 +192,17 @@ Value CallExpression::execute(Interpreter& interpreter, GlobalObject& global_obj
|
||||||
Object* new_object = nullptr;
|
Object* new_object = nullptr;
|
||||||
Value result;
|
Value result;
|
||||||
if (is_new_expression()) {
|
if (is_new_expression()) {
|
||||||
result = interpreter.construct(function, function, move(arguments), global_object);
|
result = interpreter.vm().construct(function, function, move(arguments), global_object);
|
||||||
if (result.is_object())
|
if (result.is_object())
|
||||||
new_object = &result.as_object();
|
new_object = &result.as_object();
|
||||||
} else if (m_callee->is_super_expression()) {
|
} else if (m_callee->is_super_expression()) {
|
||||||
auto* super_constructor = interpreter.current_environment()->current_function()->prototype();
|
auto* super_constructor = interpreter.current_environment()->current_function()->prototype();
|
||||||
// FIXME: Functions should track their constructor kind.
|
// FIXME: Functions should track their constructor kind.
|
||||||
if (!super_constructor || !super_constructor->is_function()) {
|
if (!super_constructor || !super_constructor->is_function()) {
|
||||||
interpreter.throw_exception<TypeError>(ErrorType::NotAConstructor, "Super constructor");
|
interpreter.vm().throw_exception<TypeError>(global_object, ErrorType::NotAConstructor, "Super constructor");
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
result = interpreter.construct(static_cast<Function&>(*super_constructor), function, move(arguments), global_object);
|
result = interpreter.vm().construct(static_cast<Function&>(*super_constructor), function, move(arguments), global_object);
|
||||||
if (interpreter.exception())
|
if (interpreter.exception())
|
||||||
return {};
|
return {};
|
||||||
|
|
||||||
|
@ -227,7 +227,7 @@ Value ReturnStatement::execute(Interpreter& interpreter, GlobalObject& global_ob
|
||||||
auto value = argument() ? argument()->execute(interpreter, global_object) : js_undefined();
|
auto value = argument() ? argument()->execute(interpreter, global_object) : js_undefined();
|
||||||
if (interpreter.exception())
|
if (interpreter.exception())
|
||||||
return {};
|
return {};
|
||||||
interpreter.unwind(ScopeType::Function);
|
interpreter.vm().unwind(ScopeType::Function);
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -238,10 +238,10 @@ Value IfStatement::execute(Interpreter& interpreter, GlobalObject& global_object
|
||||||
return {};
|
return {};
|
||||||
|
|
||||||
if (predicate_result.to_boolean())
|
if (predicate_result.to_boolean())
|
||||||
return interpreter.execute_statement(global_object, *m_consequent);
|
return interpreter.vm().execute_statement(global_object, *m_consequent);
|
||||||
|
|
||||||
if (m_alternate)
|
if (m_alternate)
|
||||||
return interpreter.execute_statement(global_object, *m_alternate);
|
return interpreter.vm().execute_statement(global_object, *m_alternate);
|
||||||
|
|
||||||
return js_undefined();
|
return js_undefined();
|
||||||
}
|
}
|
||||||
|
@ -252,7 +252,7 @@ Value WhileStatement::execute(Interpreter& interpreter, GlobalObject& global_obj
|
||||||
while (m_test->execute(interpreter, global_object).to_boolean()) {
|
while (m_test->execute(interpreter, global_object).to_boolean()) {
|
||||||
if (interpreter.exception())
|
if (interpreter.exception())
|
||||||
return {};
|
return {};
|
||||||
last_value = interpreter.execute_statement(global_object, *m_body);
|
last_value = interpreter.vm().execute_statement(global_object, *m_body);
|
||||||
if (interpreter.exception())
|
if (interpreter.exception())
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
@ -266,7 +266,7 @@ Value DoWhileStatement::execute(Interpreter& interpreter, GlobalObject& global_o
|
||||||
do {
|
do {
|
||||||
if (interpreter.exception())
|
if (interpreter.exception())
|
||||||
return {};
|
return {};
|
||||||
last_value = interpreter.execute_statement(global_object, *m_body);
|
last_value = interpreter.vm().execute_statement(global_object, *m_body);
|
||||||
if (interpreter.exception())
|
if (interpreter.exception())
|
||||||
return {};
|
return {};
|
||||||
} while (m_test->execute(interpreter, global_object).to_boolean());
|
} while (m_test->execute(interpreter, global_object).to_boolean());
|
||||||
|
@ -283,12 +283,12 @@ Value ForStatement::execute(Interpreter& interpreter, GlobalObject& global_objec
|
||||||
NonnullRefPtrVector<VariableDeclaration> decls;
|
NonnullRefPtrVector<VariableDeclaration> decls;
|
||||||
decls.append(*static_cast<const VariableDeclaration*>(m_init.ptr()));
|
decls.append(*static_cast<const VariableDeclaration*>(m_init.ptr()));
|
||||||
wrapper->add_variables(decls);
|
wrapper->add_variables(decls);
|
||||||
interpreter.enter_scope(*wrapper, {}, ScopeType::Block, global_object);
|
interpreter.vm().enter_scope(*wrapper, {}, ScopeType::Block, global_object);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto wrapper_cleanup = ScopeGuard([&] {
|
auto wrapper_cleanup = ScopeGuard([&] {
|
||||||
if (wrapper)
|
if (wrapper)
|
||||||
interpreter.exit_scope(*wrapper);
|
interpreter.vm().exit_scope(*wrapper);
|
||||||
});
|
});
|
||||||
|
|
||||||
Value last_value = js_undefined();
|
Value last_value = js_undefined();
|
||||||
|
@ -306,14 +306,14 @@ Value ForStatement::execute(Interpreter& interpreter, GlobalObject& global_objec
|
||||||
return {};
|
return {};
|
||||||
if (!test_result.to_boolean())
|
if (!test_result.to_boolean())
|
||||||
break;
|
break;
|
||||||
last_value = interpreter.execute_statement(global_object, *m_body);
|
last_value = interpreter.vm().execute_statement(global_object, *m_body);
|
||||||
if (interpreter.exception())
|
if (interpreter.exception())
|
||||||
return {};
|
return {};
|
||||||
if (interpreter.should_unwind()) {
|
if (interpreter.vm().should_unwind()) {
|
||||||
if (interpreter.should_unwind_until(ScopeType::Continuable, m_label)) {
|
if (interpreter.vm().should_unwind_until(ScopeType::Continuable, m_label)) {
|
||||||
interpreter.stop_unwind();
|
interpreter.vm().stop_unwind();
|
||||||
} else if (interpreter.should_unwind_until(ScopeType::Breakable, m_label)) {
|
} else if (interpreter.vm().should_unwind_until(ScopeType::Breakable, m_label)) {
|
||||||
interpreter.stop_unwind();
|
interpreter.vm().stop_unwind();
|
||||||
break;
|
break;
|
||||||
} else {
|
} else {
|
||||||
return js_undefined();
|
return js_undefined();
|
||||||
|
@ -327,14 +327,14 @@ Value ForStatement::execute(Interpreter& interpreter, GlobalObject& global_objec
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
while (true) {
|
while (true) {
|
||||||
last_value = interpreter.execute_statement(global_object, *m_body);
|
last_value = interpreter.vm().execute_statement(global_object, *m_body);
|
||||||
if (interpreter.exception())
|
if (interpreter.exception())
|
||||||
return {};
|
return {};
|
||||||
if (interpreter.should_unwind()) {
|
if (interpreter.vm().should_unwind()) {
|
||||||
if (interpreter.should_unwind_until(ScopeType::Continuable, m_label)) {
|
if (interpreter.vm().should_unwind_until(ScopeType::Continuable, m_label)) {
|
||||||
interpreter.stop_unwind();
|
interpreter.vm().stop_unwind();
|
||||||
} else if (interpreter.should_unwind_until(ScopeType::Breakable, m_label)) {
|
} else if (interpreter.vm().should_unwind_until(ScopeType::Breakable, m_label)) {
|
||||||
interpreter.stop_unwind();
|
interpreter.vm().stop_unwind();
|
||||||
break;
|
break;
|
||||||
} else {
|
} else {
|
||||||
return js_undefined();
|
return js_undefined();
|
||||||
|
@ -359,7 +359,7 @@ static FlyString variable_from_for_declaration(Interpreter& interpreter, GlobalO
|
||||||
ASSERT(!variable_declaration->declarations().is_empty());
|
ASSERT(!variable_declaration->declarations().is_empty());
|
||||||
if (variable_declaration->declaration_kind() != DeclarationKind::Var) {
|
if (variable_declaration->declaration_kind() != DeclarationKind::Var) {
|
||||||
wrapper = create_ast_node<BlockStatement>();
|
wrapper = create_ast_node<BlockStatement>();
|
||||||
interpreter.enter_scope(*wrapper, {}, ScopeType::Block, global_object);
|
interpreter.vm().enter_scope(*wrapper, {}, ScopeType::Block, global_object);
|
||||||
}
|
}
|
||||||
variable_declaration->execute(interpreter, global_object);
|
variable_declaration->execute(interpreter, global_object);
|
||||||
variable_name = variable_declaration->declarations().first().id().string();
|
variable_name = variable_declaration->declarations().first().id().string();
|
||||||
|
@ -381,7 +381,7 @@ Value ForInStatement::execute(Interpreter& interpreter, GlobalObject& global_obj
|
||||||
auto variable_name = variable_from_for_declaration(interpreter, global_object, m_lhs, wrapper);
|
auto variable_name = variable_from_for_declaration(interpreter, global_object, m_lhs, wrapper);
|
||||||
auto wrapper_cleanup = ScopeGuard([&] {
|
auto wrapper_cleanup = ScopeGuard([&] {
|
||||||
if (wrapper)
|
if (wrapper)
|
||||||
interpreter.exit_scope(*wrapper);
|
interpreter.vm().exit_scope(*wrapper);
|
||||||
});
|
});
|
||||||
auto last_value = js_undefined();
|
auto last_value = js_undefined();
|
||||||
auto rhs_result = m_rhs->execute(interpreter, global_object);
|
auto rhs_result = m_rhs->execute(interpreter, global_object);
|
||||||
|
@ -391,17 +391,17 @@ Value ForInStatement::execute(Interpreter& interpreter, GlobalObject& global_obj
|
||||||
while (object) {
|
while (object) {
|
||||||
auto property_names = object->get_own_properties(*object, Object::PropertyKind::Key, true);
|
auto property_names = object->get_own_properties(*object, Object::PropertyKind::Key, true);
|
||||||
for (auto& property_name : property_names.as_object().indexed_properties()) {
|
for (auto& property_name : property_names.as_object().indexed_properties()) {
|
||||||
interpreter.set_variable(variable_name, property_name.value_and_attributes(object).value, global_object);
|
interpreter.vm().set_variable(variable_name, property_name.value_and_attributes(object).value, global_object);
|
||||||
if (interpreter.exception())
|
if (interpreter.exception())
|
||||||
return {};
|
return {};
|
||||||
last_value = interpreter.execute_statement(global_object, *m_body);
|
last_value = interpreter.vm().execute_statement(global_object, *m_body);
|
||||||
if (interpreter.exception())
|
if (interpreter.exception())
|
||||||
return {};
|
return {};
|
||||||
if (interpreter.should_unwind()) {
|
if (interpreter.vm().should_unwind()) {
|
||||||
if (interpreter.should_unwind_until(ScopeType::Continuable, m_label)) {
|
if (interpreter.vm().should_unwind_until(ScopeType::Continuable, m_label)) {
|
||||||
interpreter.stop_unwind();
|
interpreter.vm().stop_unwind();
|
||||||
} else if (interpreter.should_unwind_until(ScopeType::Breakable, m_label)) {
|
} else if (interpreter.vm().should_unwind_until(ScopeType::Breakable, m_label)) {
|
||||||
interpreter.stop_unwind();
|
interpreter.vm().stop_unwind();
|
||||||
break;
|
break;
|
||||||
} else {
|
} else {
|
||||||
return js_undefined();
|
return js_undefined();
|
||||||
|
@ -425,7 +425,7 @@ Value ForOfStatement::execute(Interpreter& interpreter, GlobalObject& global_obj
|
||||||
auto variable_name = variable_from_for_declaration(interpreter, global_object, m_lhs, wrapper);
|
auto variable_name = variable_from_for_declaration(interpreter, global_object, m_lhs, wrapper);
|
||||||
auto wrapper_cleanup = ScopeGuard([&] {
|
auto wrapper_cleanup = ScopeGuard([&] {
|
||||||
if (wrapper)
|
if (wrapper)
|
||||||
interpreter.exit_scope(*wrapper);
|
interpreter.vm().exit_scope(*wrapper);
|
||||||
});
|
});
|
||||||
auto last_value = js_undefined();
|
auto last_value = js_undefined();
|
||||||
auto rhs_result = m_rhs->execute(interpreter, global_object);
|
auto rhs_result = m_rhs->execute(interpreter, global_object);
|
||||||
|
@ -433,15 +433,15 @@ Value ForOfStatement::execute(Interpreter& interpreter, GlobalObject& global_obj
|
||||||
return {};
|
return {};
|
||||||
|
|
||||||
get_iterator_values(global_object, rhs_result, [&](Value value) {
|
get_iterator_values(global_object, rhs_result, [&](Value value) {
|
||||||
interpreter.set_variable(variable_name, value, global_object);
|
interpreter.vm().set_variable(variable_name, value, global_object);
|
||||||
last_value = interpreter.execute_statement(global_object, *m_body);
|
last_value = interpreter.vm().execute_statement(global_object, *m_body);
|
||||||
if (interpreter.exception())
|
if (interpreter.exception())
|
||||||
return IterationDecision::Break;
|
return IterationDecision::Break;
|
||||||
if (interpreter.should_unwind()) {
|
if (interpreter.vm().should_unwind()) {
|
||||||
if (interpreter.should_unwind_until(ScopeType::Continuable, m_label)) {
|
if (interpreter.vm().should_unwind_until(ScopeType::Continuable, m_label)) {
|
||||||
interpreter.stop_unwind();
|
interpreter.vm().stop_unwind();
|
||||||
} else if (interpreter.should_unwind_until(ScopeType::Breakable, m_label)) {
|
} else if (interpreter.vm().should_unwind_until(ScopeType::Breakable, m_label)) {
|
||||||
interpreter.stop_unwind();
|
interpreter.vm().stop_unwind();
|
||||||
return IterationDecision::Break;
|
return IterationDecision::Break;
|
||||||
} else {
|
} else {
|
||||||
return IterationDecision::Break;
|
return IterationDecision::Break;
|
||||||
|
@ -453,7 +453,7 @@ Value ForOfStatement::execute(Interpreter& interpreter, GlobalObject& global_obj
|
||||||
if (interpreter.exception())
|
if (interpreter.exception())
|
||||||
return {};
|
return {};
|
||||||
|
|
||||||
if (interpreter.should_unwind())
|
if (interpreter.vm().should_unwind())
|
||||||
return js_undefined();
|
return js_undefined();
|
||||||
return last_value;
|
return last_value;
|
||||||
}
|
}
|
||||||
|
@ -560,7 +560,7 @@ Reference Expression::to_reference(Interpreter&, GlobalObject&) const
|
||||||
|
|
||||||
Reference Identifier::to_reference(Interpreter& interpreter, GlobalObject&) const
|
Reference Identifier::to_reference(Interpreter& interpreter, GlobalObject&) const
|
||||||
{
|
{
|
||||||
return interpreter.get_reference(string());
|
return interpreter.vm().get_reference(string());
|
||||||
}
|
}
|
||||||
|
|
||||||
Reference MemberExpression::to_reference(Interpreter& interpreter, GlobalObject& global_object) const
|
Reference MemberExpression::to_reference(Interpreter& interpreter, GlobalObject& global_object) const
|
||||||
|
@ -601,7 +601,7 @@ Value UnaryExpression::execute(Interpreter& interpreter, GlobalObject& global_ob
|
||||||
// FIXME: standard recommends checking with is_unresolvable but it ALWAYS return false here
|
// FIXME: standard recommends checking with is_unresolvable but it ALWAYS return false here
|
||||||
if (reference.is_local_variable() || reference.is_global_variable()) {
|
if (reference.is_local_variable() || reference.is_global_variable()) {
|
||||||
auto name = reference.name();
|
auto name = reference.name();
|
||||||
lhs_result = interpreter.get_variable(name.to_string(), global_object).value_or(js_undefined());
|
lhs_result = interpreter.vm().get_variable(name.to_string(), global_object).value_or(js_undefined());
|
||||||
if (interpreter.exception())
|
if (interpreter.exception())
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
@ -684,7 +684,7 @@ Value ClassExpression::execute(Interpreter& interpreter, GlobalObject& global_ob
|
||||||
if (interpreter.exception())
|
if (interpreter.exception())
|
||||||
return {};
|
return {};
|
||||||
if (!super_constructor.is_function() && !super_constructor.is_null()) {
|
if (!super_constructor.is_function() && !super_constructor.is_null()) {
|
||||||
interpreter.throw_exception<TypeError>(ErrorType::ClassDoesNotExtendAConstructorOrNull, super_constructor.to_string_without_side_effects().characters());
|
interpreter.vm().throw_exception<TypeError>(global_object, ErrorType::ClassDoesNotExtendAConstructorOrNull, super_constructor.to_string_without_side_effects().characters());
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
class_constructor->set_constructor_kind(Function::ConstructorKind::Derived);
|
class_constructor->set_constructor_kind(Function::ConstructorKind::Derived);
|
||||||
|
@ -712,7 +712,7 @@ Value ClassExpression::execute(Interpreter& interpreter, GlobalObject& global_ob
|
||||||
return {};
|
return {};
|
||||||
|
|
||||||
if (!class_prototype.is_object()) {
|
if (!class_prototype.is_object()) {
|
||||||
interpreter.throw_exception<TypeError>(ErrorType::NotAnObject, "Class prototype");
|
interpreter.vm().throw_exception<TypeError>(global_object, ErrorType::NotAnObject, "Class prototype");
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
for (const auto& method : m_methods) {
|
for (const auto& method : m_methods) {
|
||||||
|
@ -1153,9 +1153,9 @@ void ForOfStatement::dump(int indent) const
|
||||||
|
|
||||||
Value Identifier::execute(Interpreter& interpreter, GlobalObject& global_object) const
|
Value Identifier::execute(Interpreter& interpreter, GlobalObject& global_object) const
|
||||||
{
|
{
|
||||||
auto value = interpreter.get_variable(string(), global_object);
|
auto value = interpreter.vm().get_variable(string(), global_object);
|
||||||
if (value.is_empty()) {
|
if (value.is_empty()) {
|
||||||
interpreter.throw_exception<ReferenceError>(ErrorType::UnknownIdentifier, string().characters());
|
interpreter.vm().throw_exception<ReferenceError>(global_object, ErrorType::UnknownIdentifier, string().characters());
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
return value;
|
return value;
|
||||||
|
@ -1180,7 +1180,7 @@ Value SpreadExpression::execute(Interpreter& interpreter, GlobalObject& global_o
|
||||||
|
|
||||||
Value ThisExpression::execute(Interpreter& interpreter, GlobalObject&) const
|
Value ThisExpression::execute(Interpreter& interpreter, GlobalObject&) const
|
||||||
{
|
{
|
||||||
return interpreter.resolve_this_binding();
|
return interpreter.vm().resolve_this_binding();
|
||||||
}
|
}
|
||||||
|
|
||||||
void ThisExpression::dump(int indent) const
|
void ThisExpression::dump(int indent) const
|
||||||
|
@ -1279,7 +1279,7 @@ Value AssignmentExpression::execute(Interpreter& interpreter, GlobalObject& glob
|
||||||
return {};
|
return {};
|
||||||
|
|
||||||
if (reference.is_unresolvable()) {
|
if (reference.is_unresolvable()) {
|
||||||
interpreter.throw_exception<ReferenceError>(ErrorType::InvalidLeftHandAssignment);
|
interpreter.vm().throw_exception<ReferenceError>(global_object, ErrorType::InvalidLeftHandAssignment);
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
update_function_name(rhs_result, get_function_name(interpreter, reference.name().to_value(interpreter)));
|
update_function_name(rhs_result, get_function_name(interpreter, reference.name().to_value(interpreter)));
|
||||||
|
@ -1410,7 +1410,7 @@ Value VariableDeclaration::execute(Interpreter& interpreter, GlobalObject& globa
|
||||||
return {};
|
return {};
|
||||||
auto variable_name = declarator.id().string();
|
auto variable_name = declarator.id().string();
|
||||||
update_function_name(initalizer_result, variable_name);
|
update_function_name(initalizer_result, variable_name);
|
||||||
interpreter.set_variable(variable_name, initalizer_result, global_object, true);
|
interpreter.vm().set_variable(variable_name, initalizer_result, global_object, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return js_undefined();
|
return js_undefined();
|
||||||
|
@ -1723,7 +1723,7 @@ Value TaggedTemplateLiteral::execute(Interpreter& interpreter, GlobalObject& glo
|
||||||
if (interpreter.exception())
|
if (interpreter.exception())
|
||||||
return {};
|
return {};
|
||||||
if (!tag.is_function()) {
|
if (!tag.is_function()) {
|
||||||
interpreter.throw_exception<TypeError>(ErrorType::NotAFunction, tag.to_string_without_side_effects().characters());
|
interpreter.vm().throw_exception<TypeError>(global_object, ErrorType::NotAFunction, tag.to_string_without_side_effects().characters());
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
auto& tag_function = tag.as_function();
|
auto& tag_function = tag.as_function();
|
||||||
|
@ -1793,12 +1793,12 @@ void ThrowStatement::dump(int indent) const
|
||||||
|
|
||||||
Value TryStatement::execute(Interpreter& interpreter, GlobalObject& global_object) const
|
Value TryStatement::execute(Interpreter& interpreter, GlobalObject& global_object) const
|
||||||
{
|
{
|
||||||
interpreter.execute_statement(global_object, m_block, {}, ScopeType::Try);
|
interpreter.vm().execute_statement(global_object, m_block, {}, ScopeType::Try);
|
||||||
if (auto* exception = interpreter.exception()) {
|
if (auto* exception = interpreter.exception()) {
|
||||||
if (m_handler) {
|
if (m_handler) {
|
||||||
interpreter.vm().clear_exception();
|
interpreter.vm().clear_exception();
|
||||||
ArgumentVector arguments { { m_handler->parameter(), exception->value() } };
|
ArgumentVector arguments { { m_handler->parameter(), exception->value() } };
|
||||||
interpreter.execute_statement(global_object, m_handler->body(), move(arguments));
|
interpreter.vm().execute_statement(global_object, m_handler->body(), move(arguments));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1807,14 +1807,14 @@ Value TryStatement::execute(Interpreter& interpreter, GlobalObject& global_objec
|
||||||
// execute() the finalizer without an exception in our way.
|
// execute() the finalizer without an exception in our way.
|
||||||
auto* previous_exception = interpreter.exception();
|
auto* previous_exception = interpreter.exception();
|
||||||
interpreter.vm().clear_exception();
|
interpreter.vm().clear_exception();
|
||||||
interpreter.stop_unwind();
|
interpreter.vm().stop_unwind();
|
||||||
m_finalizer->execute(interpreter, global_object);
|
m_finalizer->execute(interpreter, global_object);
|
||||||
// If we previously had an exception and the finalizer didn't
|
// If we previously had an exception and the finalizer didn't
|
||||||
// throw a new one, restore the old one.
|
// throw a new one, restore the old one.
|
||||||
// FIXME: This will print debug output in throw_exception() for
|
// FIXME: This will print debug output in throw_exception() for
|
||||||
// a seconds time with INTERPRETER_DEBUG enabled.
|
// a seconds time with INTERPRETER_DEBUG enabled.
|
||||||
if (previous_exception && !interpreter.exception())
|
if (previous_exception && !interpreter.exception())
|
||||||
interpreter.throw_exception(previous_exception);
|
interpreter.vm().throw_exception(previous_exception);
|
||||||
}
|
}
|
||||||
|
|
||||||
return js_undefined();
|
return js_undefined();
|
||||||
|
@ -1830,9 +1830,9 @@ Value CatchClause::execute(Interpreter&, GlobalObject&) const
|
||||||
Value ThrowStatement::execute(Interpreter& interpreter, GlobalObject& global_object) const
|
Value ThrowStatement::execute(Interpreter& interpreter, GlobalObject& global_object) const
|
||||||
{
|
{
|
||||||
auto value = m_argument->execute(interpreter, global_object);
|
auto value = m_argument->execute(interpreter, global_object);
|
||||||
if (interpreter.exception())
|
if (interpreter.vm().exception())
|
||||||
return {};
|
return {};
|
||||||
interpreter.throw_exception(value);
|
interpreter.vm().throw_exception(global_object, value);
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1858,9 +1858,9 @@ Value SwitchStatement::execute(Interpreter& interpreter, GlobalObject& global_ob
|
||||||
statement.execute(interpreter, global_object);
|
statement.execute(interpreter, global_object);
|
||||||
if (interpreter.exception())
|
if (interpreter.exception())
|
||||||
return {};
|
return {};
|
||||||
if (interpreter.should_unwind()) {
|
if (interpreter.vm().should_unwind()) {
|
||||||
if (interpreter.should_unwind_until(ScopeType::Breakable, m_label)) {
|
if (interpreter.vm().should_unwind_until(ScopeType::Breakable, m_label)) {
|
||||||
interpreter.stop_unwind();
|
interpreter.vm().stop_unwind();
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
return {};
|
return {};
|
||||||
|
@ -1878,13 +1878,13 @@ Value SwitchCase::execute(Interpreter&, GlobalObject&) const
|
||||||
|
|
||||||
Value BreakStatement::execute(Interpreter& interpreter, GlobalObject&) const
|
Value BreakStatement::execute(Interpreter& interpreter, GlobalObject&) const
|
||||||
{
|
{
|
||||||
interpreter.unwind(ScopeType::Breakable, m_target_label);
|
interpreter.vm().unwind(ScopeType::Breakable, m_target_label);
|
||||||
return js_undefined();
|
return js_undefined();
|
||||||
}
|
}
|
||||||
|
|
||||||
Value ContinueStatement::execute(Interpreter& interpreter, GlobalObject&) const
|
Value ContinueStatement::execute(Interpreter& interpreter, GlobalObject&) const
|
||||||
{
|
{
|
||||||
interpreter.unwind(ScopeType::Continuable, m_target_label);
|
interpreter.vm().unwind(ScopeType::Continuable, m_target_label);
|
||||||
return js_undefined();
|
return js_undefined();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -123,7 +123,7 @@ bool Console::counter_reset(String label)
|
||||||
Vector<String> ConsoleClient::get_trace() const
|
Vector<String> ConsoleClient::get_trace() const
|
||||||
{
|
{
|
||||||
Vector<String> trace;
|
Vector<String> trace;
|
||||||
auto& call_stack = m_console.interpreter().call_stack();
|
auto& call_stack = m_console.interpreter().vm().call_stack();
|
||||||
// -2 to skip the console.trace() call frame
|
// -2 to skip the console.trace() call frame
|
||||||
for (ssize_t i = call_stack.size() - 2; i >= 0; --i)
|
for (ssize_t i = call_stack.size() - 2; i >= 0; --i)
|
||||||
trace.append(call_stack[i].function_name);
|
trace.append(call_stack[i].function_name);
|
||||||
|
|
|
@ -56,272 +56,22 @@ Interpreter::~Interpreter()
|
||||||
|
|
||||||
Value Interpreter::run(GlobalObject& global_object, const Program& program)
|
Value Interpreter::run(GlobalObject& global_object, const Program& program)
|
||||||
{
|
{
|
||||||
VM::InterpreterExecutionScope scope(*this);
|
ASSERT(!vm().exception());
|
||||||
|
|
||||||
ASSERT(!exception());
|
|
||||||
|
|
||||||
if (m_call_stack.is_empty()) {
|
|
||||||
CallFrame global_call_frame;
|
|
||||||
global_call_frame.this_value = &global_object;
|
|
||||||
global_call_frame.function_name = "(global execution context)";
|
|
||||||
global_call_frame.environment = heap().allocate<LexicalEnvironment>(global_object, LexicalEnvironment::EnvironmentRecordType::Global);
|
|
||||||
global_call_frame.environment->bind_this_value(&global_object);
|
|
||||||
if (exception())
|
|
||||||
return {};
|
|
||||||
m_call_stack.append(move(global_call_frame));
|
|
||||||
}
|
|
||||||
|
|
||||||
return program.execute(*this, global_object);
|
|
||||||
}
|
|
||||||
|
|
||||||
Value Interpreter::execute_statement(GlobalObject& global_object, const Statement& statement, ArgumentVector arguments, ScopeType scope_type)
|
|
||||||
{
|
|
||||||
if (!statement.is_scope_node())
|
|
||||||
return statement.execute(*this, global_object);
|
|
||||||
|
|
||||||
auto& block = static_cast<const ScopeNode&>(statement);
|
|
||||||
enter_scope(block, move(arguments), scope_type, global_object);
|
|
||||||
|
|
||||||
if (block.children().is_empty())
|
|
||||||
m_last_value = js_undefined();
|
|
||||||
|
|
||||||
for (auto& node : block.children()) {
|
|
||||||
m_last_value = node.execute(*this, global_object);
|
|
||||||
if (should_unwind()) {
|
|
||||||
if (!block.label().is_null() && should_unwind_until(ScopeType::Breakable, block.label()))
|
|
||||||
stop_unwind();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool did_return = m_unwind_until == ScopeType::Function;
|
|
||||||
|
|
||||||
if (m_unwind_until == scope_type)
|
|
||||||
m_unwind_until = ScopeType::None;
|
|
||||||
|
|
||||||
exit_scope(block);
|
|
||||||
|
|
||||||
return did_return ? m_last_value : js_undefined();
|
|
||||||
}
|
|
||||||
|
|
||||||
void Interpreter::enter_scope(const ScopeNode& scope_node, ArgumentVector arguments, ScopeType scope_type, GlobalObject& global_object)
|
|
||||||
{
|
|
||||||
for (auto& declaration : scope_node.functions()) {
|
|
||||||
auto* function = ScriptFunction::create(global_object, declaration.name(), declaration.body(), declaration.parameters(), declaration.function_length(), current_environment());
|
|
||||||
set_variable(declaration.name(), function, global_object);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (scope_type == ScopeType::Function) {
|
|
||||||
m_scope_stack.append({ scope_type, scope_node, false });
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
HashMap<FlyString, Variable> scope_variables_with_declaration_kind;
|
|
||||||
scope_variables_with_declaration_kind.ensure_capacity(16);
|
|
||||||
|
|
||||||
for (auto& declaration : scope_node.variables()) {
|
|
||||||
for (auto& declarator : declaration.declarations()) {
|
|
||||||
if (scope_node.is_program()) {
|
|
||||||
global_object.put(declarator.id().string(), js_undefined());
|
|
||||||
if (exception())
|
|
||||||
return;
|
|
||||||
} else {
|
|
||||||
scope_variables_with_declaration_kind.set(declarator.id().string(), { js_undefined(), declaration.declaration_kind() });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (auto& argument : arguments) {
|
|
||||||
scope_variables_with_declaration_kind.set(argument.name, { argument.value, DeclarationKind::Var });
|
|
||||||
}
|
|
||||||
|
|
||||||
bool pushed_lexical_environment = false;
|
|
||||||
|
|
||||||
if (!scope_variables_with_declaration_kind.is_empty()) {
|
|
||||||
auto* block_lexical_environment = heap().allocate<LexicalEnvironment>(global_object, move(scope_variables_with_declaration_kind), current_environment());
|
|
||||||
m_call_stack.last().environment = block_lexical_environment;
|
|
||||||
pushed_lexical_environment = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
m_scope_stack.append({ scope_type, scope_node, pushed_lexical_environment });
|
|
||||||
}
|
|
||||||
|
|
||||||
void Interpreter::exit_scope(const ScopeNode& scope_node)
|
|
||||||
{
|
|
||||||
while (!m_scope_stack.is_empty()) {
|
|
||||||
auto popped_scope = m_scope_stack.take_last();
|
|
||||||
if (popped_scope.pushed_environment)
|
|
||||||
m_call_stack.last().environment = m_call_stack.last().environment->parent();
|
|
||||||
if (popped_scope.scope_node.ptr() == &scope_node)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// If we unwind all the way, just reset m_unwind_until so that future "return" doesn't break.
|
|
||||||
if (m_scope_stack.is_empty())
|
|
||||||
m_unwind_until = ScopeType::None;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Interpreter::set_variable(const FlyString& name, Value value, GlobalObject& global_object, bool first_assignment)
|
|
||||||
{
|
|
||||||
if (m_call_stack.size()) {
|
|
||||||
for (auto* environment = current_environment(); environment; environment = environment->parent()) {
|
|
||||||
auto possible_match = environment->get(name);
|
|
||||||
if (possible_match.has_value()) {
|
|
||||||
if (!first_assignment && possible_match.value().declaration_kind == DeclarationKind::Const) {
|
|
||||||
throw_exception<TypeError>(ErrorType::InvalidAssignToConst);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
environment->set(name, { value, possible_match.value().declaration_kind });
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
global_object.put(move(name), move(value));
|
|
||||||
}
|
|
||||||
|
|
||||||
Value Interpreter::get_variable(const FlyString& name, GlobalObject& global_object)
|
|
||||||
{
|
|
||||||
if (m_call_stack.size()) {
|
|
||||||
for (auto* environment = current_environment(); environment; environment = environment->parent()) {
|
|
||||||
auto possible_match = environment->get(name);
|
|
||||||
if (possible_match.has_value())
|
|
||||||
return possible_match.value().value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
auto value = global_object.get(name);
|
|
||||||
if (m_underscore_is_last_value && name == "_" && value.is_empty())
|
|
||||||
return m_last_value;
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
|
|
||||||
Reference Interpreter::get_reference(const FlyString& name)
|
|
||||||
{
|
|
||||||
if (m_call_stack.size()) {
|
|
||||||
for (auto* environment = current_environment(); environment; environment = environment->parent()) {
|
|
||||||
auto possible_match = environment->get(name);
|
|
||||||
if (possible_match.has_value())
|
|
||||||
return { Reference::LocalVariable, name };
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return { Reference::GlobalVariable, name };
|
|
||||||
}
|
|
||||||
|
|
||||||
void Interpreter::gather_roots(HashTable<Cell*>& roots)
|
|
||||||
{
|
|
||||||
if (m_last_value.is_cell())
|
|
||||||
roots.set(m_last_value.as_cell());
|
|
||||||
|
|
||||||
for (auto& call_frame : m_call_stack) {
|
|
||||||
if (call_frame.this_value.is_cell())
|
|
||||||
roots.set(call_frame.this_value.as_cell());
|
|
||||||
for (auto& argument : call_frame.arguments) {
|
|
||||||
if (argument.is_cell())
|
|
||||||
roots.set(argument.as_cell());
|
|
||||||
}
|
|
||||||
roots.set(call_frame.environment);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Value Interpreter::call_internal(Function& function, Value this_value, Optional<MarkedValueList> arguments)
|
|
||||||
{
|
|
||||||
ASSERT(!exception());
|
|
||||||
|
|
||||||
VM::InterpreterExecutionScope scope(*this);
|
VM::InterpreterExecutionScope scope(*this);
|
||||||
|
|
||||||
auto& call_frame = push_call_frame();
|
CallFrame global_call_frame;
|
||||||
call_frame.function_name = function.name();
|
global_call_frame.this_value = &global_object;
|
||||||
call_frame.this_value = function.bound_this().value_or(this_value);
|
global_call_frame.function_name = "(global execution context)";
|
||||||
call_frame.arguments = function.bound_arguments();
|
global_call_frame.environment = heap().allocate<LexicalEnvironment>(global_object, LexicalEnvironment::EnvironmentRecordType::Global);
|
||||||
if (arguments.has_value())
|
global_call_frame.environment->bind_this_value(&global_object);
|
||||||
call_frame.arguments.append(arguments.value().values());
|
if (vm().exception())
|
||||||
call_frame.environment = function.create_environment();
|
|
||||||
|
|
||||||
ASSERT(call_frame.environment->this_binding_status() == LexicalEnvironment::ThisBindingStatus::Uninitialized);
|
|
||||||
call_frame.environment->bind_this_value(call_frame.this_value);
|
|
||||||
|
|
||||||
auto result = function.call(*this);
|
|
||||||
pop_call_frame();
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
Value Interpreter::construct(Function& function, Function& new_target, Optional<MarkedValueList> arguments, GlobalObject& global_object)
|
|
||||||
{
|
|
||||||
auto& call_frame = push_call_frame();
|
|
||||||
call_frame.function_name = function.name();
|
|
||||||
call_frame.arguments = function.bound_arguments();
|
|
||||||
if (arguments.has_value())
|
|
||||||
call_frame.arguments.append(arguments.value().values());
|
|
||||||
call_frame.environment = function.create_environment();
|
|
||||||
|
|
||||||
current_environment()->set_new_target(&new_target);
|
|
||||||
|
|
||||||
Object* new_object = nullptr;
|
|
||||||
if (function.constructor_kind() == Function::ConstructorKind::Base) {
|
|
||||||
new_object = Object::create_empty(global_object);
|
|
||||||
current_environment()->bind_this_value(new_object);
|
|
||||||
if (exception())
|
|
||||||
return {};
|
|
||||||
auto prototype = new_target.get("prototype");
|
|
||||||
if (exception())
|
|
||||||
return {};
|
|
||||||
if (prototype.is_object()) {
|
|
||||||
new_object->set_prototype(&prototype.as_object());
|
|
||||||
if (exception())
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// If we are a Derived constructor, |this| has not been constructed before super is called.
|
|
||||||
Value this_value = function.constructor_kind() == Function::ConstructorKind::Base ? new_object : Value {};
|
|
||||||
call_frame.this_value = this_value;
|
|
||||||
auto result = function.construct(*this, new_target);
|
|
||||||
|
|
||||||
this_value = current_environment()->get_this_binding();
|
|
||||||
pop_call_frame();
|
|
||||||
|
|
||||||
// If we are constructing an instance of a derived class,
|
|
||||||
// set the prototype on objects created by constructors that return an object (i.e. NativeFunction subclasses).
|
|
||||||
if (function.constructor_kind() == Function::ConstructorKind::Base && new_target.constructor_kind() == Function::ConstructorKind::Derived && result.is_object()) {
|
|
||||||
current_environment()->replace_this_binding(result);
|
|
||||||
auto prototype = new_target.get("prototype");
|
|
||||||
if (exception())
|
|
||||||
return {};
|
|
||||||
if (prototype.is_object()) {
|
|
||||||
result.as_object().set_prototype(&prototype.as_object());
|
|
||||||
if (exception())
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (exception())
|
|
||||||
return {};
|
return {};
|
||||||
|
vm().call_stack().append(move(global_call_frame));
|
||||||
|
|
||||||
if (result.is_object())
|
auto result = program.execute(*this, global_object);
|
||||||
return result;
|
vm().pop_call_frame();
|
||||||
|
return result;
|
||||||
return this_value;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Interpreter::throw_exception(Exception* exception)
|
|
||||||
{
|
|
||||||
#ifdef INTERPRETER_DEBUG
|
|
||||||
if (exception->value().is_object() && exception->value().as_object().is_error()) {
|
|
||||||
auto& error = static_cast<Error&>(exception->value().as_object());
|
|
||||||
dbg() << "Throwing JavaScript Error: " << error.name() << ", " << error.message();
|
|
||||||
|
|
||||||
for (ssize_t i = m_call_stack.size() - 1; i >= 0; --i) {
|
|
||||||
auto function_name = m_call_stack[i].function_name;
|
|
||||||
if (function_name.is_empty())
|
|
||||||
function_name = "<anonymous>";
|
|
||||||
dbg() << " " << function_name;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
vm().set_exception({}, exception);
|
|
||||||
unwind(ScopeType::Try);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
GlobalObject& Interpreter::global_object()
|
GlobalObject& Interpreter::global_object()
|
||||||
|
@ -334,35 +84,26 @@ const GlobalObject& Interpreter::global_object() const
|
||||||
return static_cast<const GlobalObject&>(*m_global_object.cell());
|
return static_cast<const GlobalObject&>(*m_global_object.cell());
|
||||||
}
|
}
|
||||||
|
|
||||||
String Interpreter::join_arguments() const
|
Value Interpreter::call_internal(Function& function, Value this_value, Optional<MarkedValueList> arguments)
|
||||||
{
|
{
|
||||||
StringBuilder joined_arguments;
|
ASSERT(!exception());
|
||||||
for (size_t i = 0; i < argument_count(); ++i) {
|
|
||||||
joined_arguments.append(argument(i).to_string_without_side_effects().characters());
|
|
||||||
if (i != argument_count() - 1)
|
|
||||||
joined_arguments.append(' ');
|
|
||||||
}
|
|
||||||
return joined_arguments.build();
|
|
||||||
}
|
|
||||||
|
|
||||||
Value Interpreter::resolve_this_binding() const
|
VM::InterpreterExecutionScope scope(*this);
|
||||||
{
|
|
||||||
return get_this_environment()->get_this_binding();
|
|
||||||
}
|
|
||||||
|
|
||||||
const LexicalEnvironment* Interpreter::get_this_environment() const
|
auto& call_frame = vm().push_call_frame();
|
||||||
{
|
call_frame.function_name = function.name();
|
||||||
// We will always return because the Global environment will always be reached, which has a |this| binding.
|
call_frame.this_value = function.bound_this().value_or(this_value);
|
||||||
for (const LexicalEnvironment* environment = current_environment(); environment; environment = environment->parent()) {
|
call_frame.arguments = function.bound_arguments();
|
||||||
if (environment->has_this_binding())
|
if (arguments.has_value())
|
||||||
return environment;
|
call_frame.arguments.append(arguments.value().values());
|
||||||
}
|
call_frame.environment = function.create_environment();
|
||||||
ASSERT_NOT_REACHED();
|
|
||||||
}
|
|
||||||
|
|
||||||
Value Interpreter::get_new_target() const
|
ASSERT(call_frame.environment->this_binding_status() == LexicalEnvironment::ThisBindingStatus::Uninitialized);
|
||||||
{
|
call_frame.environment->bind_this_value(call_frame.this_value);
|
||||||
return get_this_environment()->new_target();
|
|
||||||
|
auto result = function.call(*this);
|
||||||
|
vm().pop_call_frame();
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -45,35 +45,6 @@
|
||||||
|
|
||||||
namespace JS {
|
namespace JS {
|
||||||
|
|
||||||
enum class ScopeType {
|
|
||||||
None,
|
|
||||||
Function,
|
|
||||||
Block,
|
|
||||||
Try,
|
|
||||||
Breakable,
|
|
||||||
Continuable,
|
|
||||||
};
|
|
||||||
|
|
||||||
struct ScopeFrame {
|
|
||||||
ScopeType type;
|
|
||||||
NonnullRefPtr<ScopeNode> scope_node;
|
|
||||||
bool pushed_environment { false };
|
|
||||||
};
|
|
||||||
|
|
||||||
struct CallFrame {
|
|
||||||
FlyString function_name;
|
|
||||||
Value this_value;
|
|
||||||
Vector<Value> arguments;
|
|
||||||
LexicalEnvironment* environment { nullptr };
|
|
||||||
};
|
|
||||||
|
|
||||||
struct Argument {
|
|
||||||
FlyString name;
|
|
||||||
Value value;
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef Vector<Argument, 8> ArgumentVector;
|
|
||||||
|
|
||||||
class Interpreter : public Weakable<Interpreter> {
|
class Interpreter : public Weakable<Interpreter> {
|
||||||
public:
|
public:
|
||||||
template<typename GlobalObjectType, typename... Args>
|
template<typename GlobalObjectType, typename... Args>
|
||||||
|
@ -106,122 +77,23 @@ public:
|
||||||
|
|
||||||
Value run(GlobalObject&, const Program&);
|
Value run(GlobalObject&, const Program&);
|
||||||
|
|
||||||
Value execute_statement(GlobalObject&, const Statement&, ArgumentVector = {}, ScopeType = ScopeType::Block);
|
|
||||||
|
|
||||||
GlobalObject& global_object();
|
GlobalObject& global_object();
|
||||||
const GlobalObject& global_object() const;
|
const GlobalObject& global_object() const;
|
||||||
|
|
||||||
VM& vm() { return *m_vm; }
|
VM& vm() { return *m_vm; }
|
||||||
|
const VM& vm() const { return *m_vm; }
|
||||||
Heap& heap() { return vm().heap(); }
|
Heap& heap() { return vm().heap(); }
|
||||||
Exception* exception() { return vm().exception(); }
|
Exception* exception() { return vm().exception(); }
|
||||||
|
|
||||||
void unwind(ScopeType type, FlyString label = {})
|
|
||||||
{
|
|
||||||
m_unwind_until = type;
|
|
||||||
m_unwind_until_label = label;
|
|
||||||
}
|
|
||||||
void stop_unwind() { m_unwind_until = ScopeType::None; }
|
|
||||||
bool should_unwind_until(ScopeType type, FlyString label) const
|
|
||||||
{
|
|
||||||
if (m_unwind_until_label.is_null())
|
|
||||||
return m_unwind_until == type;
|
|
||||||
return m_unwind_until == type && m_unwind_until_label == label;
|
|
||||||
}
|
|
||||||
bool should_unwind() const { return m_unwind_until != ScopeType::None; }
|
|
||||||
|
|
||||||
Value get_variable(const FlyString& name, GlobalObject&);
|
|
||||||
void set_variable(const FlyString& name, Value, GlobalObject&, bool first_assignment = false);
|
|
||||||
|
|
||||||
Reference get_reference(const FlyString& name);
|
|
||||||
|
|
||||||
void gather_roots(HashTable<Cell*>&);
|
|
||||||
|
|
||||||
void enter_scope(const ScopeNode&, ArgumentVector, ScopeType, GlobalObject&);
|
|
||||||
void exit_scope(const ScopeNode&);
|
|
||||||
|
|
||||||
Value construct(Function&, Function& new_target, Optional<MarkedValueList> arguments, GlobalObject&);
|
|
||||||
|
|
||||||
CallFrame& push_call_frame()
|
|
||||||
{
|
|
||||||
m_call_stack.append({ {}, js_undefined(), {}, nullptr });
|
|
||||||
return m_call_stack.last();
|
|
||||||
}
|
|
||||||
void pop_call_frame() { m_call_stack.take_last(); }
|
|
||||||
const CallFrame& call_frame() { return m_call_stack.last(); }
|
|
||||||
const Vector<CallFrame>& call_stack() { return m_call_stack; }
|
|
||||||
|
|
||||||
const LexicalEnvironment* current_environment() const { return m_call_stack.last().environment; }
|
|
||||||
LexicalEnvironment* current_environment() { return m_call_stack.last().environment; }
|
|
||||||
|
|
||||||
bool in_strict_mode() const
|
|
||||||
{
|
|
||||||
if (m_scope_stack.is_empty())
|
|
||||||
return true;
|
|
||||||
return m_scope_stack.last().scope_node->in_strict_mode();
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename Callback>
|
|
||||||
void for_each_argument(Callback callback)
|
|
||||||
{
|
|
||||||
if (m_call_stack.is_empty())
|
|
||||||
return;
|
|
||||||
for (auto& value : m_call_stack.last().arguments)
|
|
||||||
callback(value);
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t argument_count() const
|
|
||||||
{
|
|
||||||
if (m_call_stack.is_empty())
|
|
||||||
return 0;
|
|
||||||
return m_call_stack.last().arguments.size();
|
|
||||||
}
|
|
||||||
|
|
||||||
Value argument(size_t index) const
|
|
||||||
{
|
|
||||||
if (m_call_stack.is_empty())
|
|
||||||
return {};
|
|
||||||
auto& arguments = m_call_stack.last().arguments;
|
|
||||||
return index < arguments.size() ? arguments[index] : js_undefined();
|
|
||||||
}
|
|
||||||
|
|
||||||
Value this_value(Object& global_object) const
|
|
||||||
{
|
|
||||||
if (m_call_stack.is_empty())
|
|
||||||
return &global_object;
|
|
||||||
return m_call_stack.last().this_value;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T, typename... Args>
|
|
||||||
void throw_exception(Args&&... args)
|
|
||||||
{
|
|
||||||
return throw_exception(T::create(global_object(), forward<Args>(args)...));
|
|
||||||
}
|
|
||||||
|
|
||||||
void throw_exception(Exception*);
|
|
||||||
void throw_exception(Value value)
|
|
||||||
{
|
|
||||||
return throw_exception(heap().allocate<Exception>(global_object(), value));
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T, typename... Args>
|
|
||||||
void throw_exception(ErrorType type, Args&&... args)
|
|
||||||
{
|
|
||||||
return throw_exception(T::create(global_object(), String::format(type.message(), forward<Args>(args)...)));
|
|
||||||
}
|
|
||||||
|
|
||||||
Value last_value() const { return m_last_value; }
|
|
||||||
|
|
||||||
bool underscore_is_last_value() const { return m_underscore_is_last_value; }
|
|
||||||
void set_underscore_is_last_value(bool b) { m_underscore_is_last_value = b; }
|
|
||||||
|
|
||||||
Console& console() { return m_console; }
|
Console& console() { return m_console; }
|
||||||
const Console& console() const { return m_console; }
|
const Console& console() const { return m_console; }
|
||||||
|
|
||||||
String join_arguments() const;
|
bool in_strict_mode() const { return vm().in_strict_mode(); }
|
||||||
|
size_t argument_count() const { return vm().argument_count(); }
|
||||||
Value resolve_this_binding() const;
|
Value argument(size_t index) const { return vm().argument(index); }
|
||||||
const LexicalEnvironment* get_this_environment() const;
|
Value this_value(Object& global_object) const { return vm().this_value(global_object); }
|
||||||
Value get_new_target() const;
|
LexicalEnvironment* current_environment() { return vm().current_environment(); }
|
||||||
|
const CallFrame& call_frame() { return vm().call_frame(); }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
explicit Interpreter(VM&);
|
explicit Interpreter(VM&);
|
||||||
|
@ -230,18 +102,8 @@ private:
|
||||||
|
|
||||||
NonnullRefPtr<VM> m_vm;
|
NonnullRefPtr<VM> m_vm;
|
||||||
|
|
||||||
Value m_last_value;
|
|
||||||
|
|
||||||
Vector<ScopeFrame> m_scope_stack;
|
|
||||||
Vector<CallFrame> m_call_stack;
|
|
||||||
|
|
||||||
Handle<Object> m_global_object;
|
Handle<Object> m_global_object;
|
||||||
|
|
||||||
ScopeType m_unwind_until { ScopeType::None };
|
|
||||||
FlyString m_unwind_until_label;
|
|
||||||
|
|
||||||
bool m_underscore_is_last_value { false };
|
|
||||||
|
|
||||||
Console m_console;
|
Console m_console;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -55,7 +55,7 @@ Array* Array::typed_this(Interpreter& interpreter, GlobalObject& global_object)
|
||||||
if (!this_object)
|
if (!this_object)
|
||||||
return {};
|
return {};
|
||||||
if (!this_object->is_array()) {
|
if (!this_object->is_array()) {
|
||||||
interpreter.throw_exception<TypeError>(ErrorType::NotAn, "Array");
|
interpreter.vm().throw_exception<TypeError>(global_object, ErrorType::NotAn, "Array");
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
return static_cast<Array*>(this_object);
|
return static_cast<Array*>(this_object);
|
||||||
|
@ -78,7 +78,7 @@ JS_DEFINE_NATIVE_SETTER(Array::length_setter)
|
||||||
if (interpreter.exception())
|
if (interpreter.exception())
|
||||||
return;
|
return;
|
||||||
if (length.is_nan() || length.is_infinity() || length.as_double() < 0) {
|
if (length.is_nan() || length.is_infinity() || length.as_double() < 0) {
|
||||||
interpreter.throw_exception<RangeError>(ErrorType::ArrayInvalidLength);
|
interpreter.vm().throw_exception<RangeError>(global_object, ErrorType::ArrayInvalidLength);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
array->indexed_properties().set_array_like_size(length.as_double());
|
array->indexed_properties().set_array_like_size(length.as_double());
|
||||||
|
|
|
@ -67,7 +67,7 @@ Value ArrayConstructor::call(Interpreter& interpreter)
|
||||||
if (interpreter.argument_count() == 1 && interpreter.argument(0).is_number()) {
|
if (interpreter.argument_count() == 1 && interpreter.argument(0).is_number()) {
|
||||||
auto array_length_value = interpreter.argument(0);
|
auto array_length_value = interpreter.argument(0);
|
||||||
if (!array_length_value.is_integer() || array_length_value.as_i32() < 0) {
|
if (!array_length_value.is_integer() || array_length_value.as_i32() < 0) {
|
||||||
interpreter.throw_exception<TypeError>(ErrorType::ArrayInvalidLength);
|
interpreter.vm().throw_exception<TypeError>(global_object(), ErrorType::ArrayInvalidLength);
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
auto* array = Array::create(global_object());
|
auto* array = Array::create(global_object());
|
||||||
|
|
|
@ -54,7 +54,7 @@ JS_DEFINE_NATIVE_FUNCTION(ArrayIteratorPrototype::next)
|
||||||
{
|
{
|
||||||
auto this_value = interpreter.this_value(global_object);
|
auto this_value = interpreter.this_value(global_object);
|
||||||
if (!this_value.is_object() || !this_value.as_object().is_array_iterator_object()) {
|
if (!this_value.is_object() || !this_value.as_object().is_array_iterator_object()) {
|
||||||
interpreter.throw_exception<TypeError>(ErrorType::NotAn, "Array Iterator");
|
interpreter.vm().throw_exception<TypeError>(global_object, ErrorType::NotAn, "Array Iterator");
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
auto& this_object = this_value.as_object();
|
auto& this_object = this_value.as_object();
|
||||||
|
|
|
@ -90,12 +90,12 @@ ArrayPrototype::~ArrayPrototype()
|
||||||
static Function* callback_from_args(Interpreter& interpreter, const String& name)
|
static Function* callback_from_args(Interpreter& interpreter, const String& name)
|
||||||
{
|
{
|
||||||
if (interpreter.argument_count() < 1) {
|
if (interpreter.argument_count() < 1) {
|
||||||
interpreter.throw_exception<TypeError>(ErrorType::ArrayPrototypeOneArg, name.characters());
|
interpreter.vm().throw_exception<TypeError>(interpreter.global_object(), ErrorType::ArrayPrototypeOneArg, name.characters());
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
auto callback = interpreter.argument(0);
|
auto callback = interpreter.argument(0);
|
||||||
if (!callback.is_function()) {
|
if (!callback.is_function()) {
|
||||||
interpreter.throw_exception<TypeError>(ErrorType::NotAFunction, callback.to_string_without_side_effects().characters());
|
interpreter.vm().throw_exception<TypeError>(interpreter.global_object(), ErrorType::NotAFunction, callback.to_string_without_side_effects().characters());
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
return &callback.as_function();
|
return &callback.as_function();
|
||||||
|
@ -199,7 +199,7 @@ JS_DEFINE_NATIVE_FUNCTION(ArrayPrototype::push)
|
||||||
auto argument_count = interpreter.argument_count();
|
auto argument_count = interpreter.argument_count();
|
||||||
auto new_length = length + argument_count;
|
auto new_length = length + argument_count;
|
||||||
if (new_length > MAX_ARRAY_LIKE_INDEX) {
|
if (new_length > MAX_ARRAY_LIKE_INDEX) {
|
||||||
interpreter.throw_exception<TypeError>(ErrorType::ArrayMaxSize);
|
interpreter.vm().throw_exception<TypeError>(global_object, ErrorType::ArrayMaxSize);
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
for (size_t i = 0; i < argument_count; ++i) {
|
for (size_t i = 0; i < argument_count; ++i) {
|
||||||
|
@ -474,7 +474,7 @@ JS_DEFINE_NATIVE_FUNCTION(ArrayPrototype::reduce)
|
||||||
start += 1;
|
start += 1;
|
||||||
}
|
}
|
||||||
if (!start_found) {
|
if (!start_found) {
|
||||||
interpreter.throw_exception<TypeError>(ErrorType::ReduceNoInitial);
|
interpreter.vm().throw_exception<TypeError>(global_object, ErrorType::ReduceNoInitial);
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -527,7 +527,7 @@ JS_DEFINE_NATIVE_FUNCTION(ArrayPrototype::reduce_right)
|
||||||
start -= 1;
|
start -= 1;
|
||||||
}
|
}
|
||||||
if (!start_found) {
|
if (!start_found) {
|
||||||
interpreter.throw_exception<TypeError>(ErrorType::ReduceNoInitial);
|
interpreter.vm().throw_exception<TypeError>(global_object, ErrorType::ReduceNoInitial);
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -729,7 +729,7 @@ JS_DEFINE_NATIVE_FUNCTION(ArrayPrototype::splice)
|
||||||
size_t new_length = initial_length + insert_count - actual_delete_count;
|
size_t new_length = initial_length + insert_count - actual_delete_count;
|
||||||
|
|
||||||
if (new_length > MAX_ARRAY_LIKE_INDEX) {
|
if (new_length > MAX_ARRAY_LIKE_INDEX) {
|
||||||
interpreter.throw_exception<TypeError>(ErrorType::ArrayMaxSize);
|
interpreter.vm().throw_exception<TypeError>(global_object, ErrorType::ArrayMaxSize);
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -61,7 +61,7 @@ Value BigIntConstructor::call(Interpreter& interpreter)
|
||||||
return {};
|
return {};
|
||||||
if (primitive.is_number()) {
|
if (primitive.is_number()) {
|
||||||
if (!primitive.is_integer()) {
|
if (!primitive.is_integer()) {
|
||||||
interpreter.throw_exception<RangeError>(ErrorType::BigIntIntArgument);
|
interpreter.vm().throw_exception<RangeError>(global_object(), ErrorType::BigIntIntArgument);
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
return js_bigint(interpreter, Crypto::SignedBigInteger { primitive.as_i32() });
|
return js_bigint(interpreter, Crypto::SignedBigInteger { primitive.as_i32() });
|
||||||
|
@ -74,7 +74,7 @@ Value BigIntConstructor::call(Interpreter& interpreter)
|
||||||
|
|
||||||
Value BigIntConstructor::construct(Interpreter& interpreter, Function&)
|
Value BigIntConstructor::construct(Interpreter& interpreter, Function&)
|
||||||
{
|
{
|
||||||
interpreter.throw_exception<TypeError>(ErrorType::NotAConstructor, "BigInt");
|
interpreter.vm().throw_exception<TypeError>(global_object(), ErrorType::NotAConstructor, "BigInt");
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -58,7 +58,7 @@ static BigIntObject* bigint_object_from(Interpreter& interpreter, GlobalObject&
|
||||||
if (!this_object)
|
if (!this_object)
|
||||||
return nullptr;
|
return nullptr;
|
||||||
if (!this_object->is_bigint_object()) {
|
if (!this_object->is_bigint_object()) {
|
||||||
interpreter.throw_exception<TypeError>(ErrorType::NotA, "BigInt");
|
interpreter.vm().throw_exception<TypeError>(global_object, ErrorType::NotA, "BigInt");
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
return static_cast<BigIntObject*>(this_object);
|
return static_cast<BigIntObject*>(this_object);
|
||||||
|
|
|
@ -55,7 +55,7 @@ JS_DEFINE_NATIVE_FUNCTION(BooleanPrototype::to_string)
|
||||||
return js_string(interpreter.heap(), this_object.as_bool() ? "true" : "false");
|
return js_string(interpreter.heap(), this_object.as_bool() ? "true" : "false");
|
||||||
}
|
}
|
||||||
if (!this_object.is_object() || !this_object.as_object().is_boolean_object()) {
|
if (!this_object.is_object() || !this_object.as_object().is_boolean_object()) {
|
||||||
interpreter.throw_exception<TypeError>(ErrorType::NotA, "Boolean");
|
interpreter.vm().throw_exception<TypeError>(global_object, ErrorType::NotA, "Boolean");
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -70,7 +70,7 @@ JS_DEFINE_NATIVE_FUNCTION(BooleanPrototype::value_of)
|
||||||
return this_object;
|
return this_object;
|
||||||
}
|
}
|
||||||
if (!this_object.is_object() || !this_object.as_object().is_boolean_object()) {
|
if (!this_object.is_object() || !this_object.as_object().is_boolean_object()) {
|
||||||
interpreter.throw_exception<TypeError>(ErrorType::NotA, "Boolean");
|
interpreter.vm().throw_exception<TypeError>(global_object, ErrorType::NotA, "Boolean");
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -42,7 +42,7 @@ static Date* typed_this(Interpreter& interpreter, GlobalObject& global_object)
|
||||||
if (!this_object)
|
if (!this_object)
|
||||||
return nullptr;
|
return nullptr;
|
||||||
if (!this_object->is_date()) {
|
if (!this_object->is_date()) {
|
||||||
interpreter.throw_exception<TypeError>(ErrorType::NotA, "Date");
|
interpreter.vm().throw_exception<TypeError>(global_object, ErrorType::NotA, "Date");
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
return static_cast<Date*>(this_object);
|
return static_cast<Date*>(this_object);
|
||||||
|
|
|
@ -59,7 +59,7 @@ JS_DEFINE_NATIVE_GETTER(ErrorPrototype::name_getter)
|
||||||
if (!this_object)
|
if (!this_object)
|
||||||
return {};
|
return {};
|
||||||
if (!this_object->is_error()) {
|
if (!this_object->is_error()) {
|
||||||
interpreter.throw_exception<TypeError>(ErrorType::NotAn, "Error");
|
interpreter.vm().throw_exception<TypeError>(global_object, ErrorType::NotAn, "Error");
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
return js_string(interpreter, static_cast<const Error*>(this_object)->name());
|
return js_string(interpreter, static_cast<const Error*>(this_object)->name());
|
||||||
|
@ -71,7 +71,7 @@ JS_DEFINE_NATIVE_SETTER(ErrorPrototype::name_setter)
|
||||||
if (!this_object)
|
if (!this_object)
|
||||||
return;
|
return;
|
||||||
if (!this_object->is_error()) {
|
if (!this_object->is_error()) {
|
||||||
interpreter.throw_exception<TypeError>(ErrorType::NotAn, "Error");
|
interpreter.vm().throw_exception<TypeError>(global_object, ErrorType::NotAn, "Error");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
auto name = value.to_string(interpreter);
|
auto name = value.to_string(interpreter);
|
||||||
|
@ -86,7 +86,7 @@ JS_DEFINE_NATIVE_GETTER(ErrorPrototype::message_getter)
|
||||||
if (!this_object)
|
if (!this_object)
|
||||||
return {};
|
return {};
|
||||||
if (!this_object->is_error()) {
|
if (!this_object->is_error()) {
|
||||||
interpreter.throw_exception<TypeError>(ErrorType::NotAn, "Error");
|
interpreter.vm().throw_exception<TypeError>(global_object, ErrorType::NotAn, "Error");
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
return js_string(interpreter, static_cast<const Error*>(this_object)->message());
|
return js_string(interpreter, static_cast<const Error*>(this_object)->message());
|
||||||
|
@ -95,7 +95,7 @@ JS_DEFINE_NATIVE_GETTER(ErrorPrototype::message_getter)
|
||||||
JS_DEFINE_NATIVE_FUNCTION(ErrorPrototype::to_string)
|
JS_DEFINE_NATIVE_FUNCTION(ErrorPrototype::to_string)
|
||||||
{
|
{
|
||||||
if (!interpreter.this_value(global_object).is_object()) {
|
if (!interpreter.this_value(global_object).is_object()) {
|
||||||
interpreter.throw_exception<TypeError>(ErrorType::NotAnObject, interpreter.this_value(global_object).to_string_without_side_effects().characters());
|
interpreter.vm().throw_exception<TypeError>(global_object, ErrorType::NotAnObject, interpreter.this_value(global_object).to_string_without_side_effects().characters());
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
auto& this_object = interpreter.this_value(global_object).as_object();
|
auto& this_object = interpreter.this_value(global_object).as_object();
|
||||||
|
|
|
@ -32,7 +32,7 @@ namespace JS {
|
||||||
Exception::Exception(Value value)
|
Exception::Exception(Value value)
|
||||||
: m_value(value)
|
: m_value(value)
|
||||||
{
|
{
|
||||||
auto& call_stack = interpreter().call_stack();
|
auto& call_stack = vm().call_stack();
|
||||||
for (ssize_t i = call_stack.size() - 1; i >= 0; --i) {
|
for (ssize_t i = call_stack.size() - 1; i >= 0; --i) {
|
||||||
auto function_name = call_stack[i].function_name;
|
auto function_name = call_stack[i].function_name;
|
||||||
if (function_name.is_empty())
|
if (function_name.is_empty())
|
||||||
|
|
|
@ -26,6 +26,7 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <AK/Vector.h>
|
||||||
#include <LibJS/Runtime/Cell.h>
|
#include <LibJS/Runtime/Cell.h>
|
||||||
#include <LibJS/Runtime/Value.h>
|
#include <LibJS/Runtime/Value.h>
|
||||||
|
|
||||||
|
|
|
@ -84,7 +84,7 @@ Value FunctionConstructor::construct(Interpreter& interpreter, Function&)
|
||||||
auto function_expression = parser.parse_function_node<FunctionExpression>();
|
auto function_expression = parser.parse_function_node<FunctionExpression>();
|
||||||
if (parser.has_errors()) {
|
if (parser.has_errors()) {
|
||||||
auto error = parser.errors()[0];
|
auto error = parser.errors()[0];
|
||||||
interpreter.throw_exception<SyntaxError>(error.to_string());
|
interpreter.vm().throw_exception<SyntaxError>(global_object(), error.to_string());
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
return function_expression->execute(interpreter, global_object());
|
return function_expression->execute(interpreter, global_object());
|
||||||
|
|
|
@ -66,7 +66,7 @@ JS_DEFINE_NATIVE_FUNCTION(FunctionPrototype::apply)
|
||||||
if (!this_object)
|
if (!this_object)
|
||||||
return {};
|
return {};
|
||||||
if (!this_object->is_function()) {
|
if (!this_object->is_function()) {
|
||||||
interpreter.throw_exception<TypeError>(ErrorType::NotA, "Function");
|
interpreter.vm().throw_exception<TypeError>(global_object, ErrorType::NotA, "Function");
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
auto& function = static_cast<Function&>(*this_object);
|
auto& function = static_cast<Function&>(*this_object);
|
||||||
|
@ -75,7 +75,7 @@ JS_DEFINE_NATIVE_FUNCTION(FunctionPrototype::apply)
|
||||||
if (arg_array.is_null() || arg_array.is_undefined())
|
if (arg_array.is_null() || arg_array.is_undefined())
|
||||||
return interpreter.call(function, this_arg);
|
return interpreter.call(function, this_arg);
|
||||||
if (!arg_array.is_object()) {
|
if (!arg_array.is_object()) {
|
||||||
interpreter.throw_exception<TypeError>(ErrorType::FunctionArgsNotObject);
|
interpreter.vm().throw_exception<TypeError>(global_object, ErrorType::FunctionArgsNotObject);
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
auto length_property = arg_array.as_object().get("length");
|
auto length_property = arg_array.as_object().get("length");
|
||||||
|
@ -100,7 +100,7 @@ JS_DEFINE_NATIVE_FUNCTION(FunctionPrototype::bind)
|
||||||
if (!this_object)
|
if (!this_object)
|
||||||
return {};
|
return {};
|
||||||
if (!this_object->is_function()) {
|
if (!this_object->is_function()) {
|
||||||
interpreter.throw_exception<TypeError>(ErrorType::NotA, "Function");
|
interpreter.vm().throw_exception<TypeError>(global_object, ErrorType::NotA, "Function");
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
auto& this_function = static_cast<Function&>(*this_object);
|
auto& this_function = static_cast<Function&>(*this_object);
|
||||||
|
@ -121,7 +121,7 @@ JS_DEFINE_NATIVE_FUNCTION(FunctionPrototype::call)
|
||||||
if (!this_object)
|
if (!this_object)
|
||||||
return {};
|
return {};
|
||||||
if (!this_object->is_function()) {
|
if (!this_object->is_function()) {
|
||||||
interpreter.throw_exception<TypeError>(ErrorType::NotA, "Function");
|
interpreter.vm().throw_exception<TypeError>(global_object, ErrorType::NotA, "Function");
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
auto& function = static_cast<Function&>(*this_object);
|
auto& function = static_cast<Function&>(*this_object);
|
||||||
|
@ -140,7 +140,7 @@ JS_DEFINE_NATIVE_FUNCTION(FunctionPrototype::to_string)
|
||||||
if (!this_object)
|
if (!this_object)
|
||||||
return {};
|
return {};
|
||||||
if (!this_object->is_function()) {
|
if (!this_object->is_function()) {
|
||||||
interpreter.throw_exception<TypeError>(ErrorType::NotA, "Function");
|
interpreter.vm().throw_exception<TypeError>(global_object, ErrorType::NotA, "Function");
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
String function_name = static_cast<Function*>(this_object)->name();
|
String function_name = static_cast<Function*>(this_object)->name();
|
||||||
|
@ -182,7 +182,7 @@ JS_DEFINE_NATIVE_FUNCTION(FunctionPrototype::symbol_has_instance)
|
||||||
if (!this_object)
|
if (!this_object)
|
||||||
return {};
|
return {};
|
||||||
if (!this_object->is_function()) {
|
if (!this_object->is_function()) {
|
||||||
interpreter.throw_exception<TypeError>(ErrorType::NotA, "Function");
|
interpreter.vm().throw_exception<TypeError>(global_object, ErrorType::NotA, "Function");
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
return ordinary_has_instance(interpreter, interpreter.argument(0), this_object);
|
return ordinary_has_instance(interpreter, interpreter.argument(0), this_object);
|
||||||
|
|
|
@ -46,14 +46,14 @@ Object* get_iterator(GlobalObject& global_object, Value value, String hint, Valu
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
if (!method.is_function()) {
|
if (!method.is_function()) {
|
||||||
interpreter.throw_exception<TypeError>(ErrorType::NotIterable, value.to_string_without_side_effects().characters());
|
interpreter.vm().throw_exception<TypeError>(global_object, ErrorType::NotIterable, value.to_string_without_side_effects().characters());
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
auto iterator = interpreter.call(method.as_function(), value);
|
auto iterator = interpreter.call(method.as_function(), value);
|
||||||
if (interpreter.exception())
|
if (interpreter.exception())
|
||||||
return {};
|
return {};
|
||||||
if (!iterator.is_object()) {
|
if (!iterator.is_object()) {
|
||||||
interpreter.throw_exception<TypeError>(ErrorType::NotIterable, value.to_string_without_side_effects().characters());
|
interpreter.vm().throw_exception<TypeError>(global_object, ErrorType::NotIterable, value.to_string_without_side_effects().characters());
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
return &iterator.as_object();
|
return &iterator.as_object();
|
||||||
|
@ -62,12 +62,13 @@ Object* get_iterator(GlobalObject& global_object, Value value, String hint, Valu
|
||||||
Object* iterator_next(Object& iterator, Value value)
|
Object* iterator_next(Object& iterator, Value value)
|
||||||
{
|
{
|
||||||
auto& interpreter = iterator.interpreter();
|
auto& interpreter = iterator.interpreter();
|
||||||
|
auto& global_object = iterator.global_object();
|
||||||
auto next_method = iterator.get("next");
|
auto next_method = iterator.get("next");
|
||||||
if (interpreter.exception())
|
if (interpreter.exception())
|
||||||
return {};
|
return {};
|
||||||
|
|
||||||
if (!next_method.is_function()) {
|
if (!next_method.is_function()) {
|
||||||
interpreter.throw_exception<TypeError>(ErrorType::IterableNextNotAFunction);
|
interpreter.vm().throw_exception<TypeError>(global_object, ErrorType::IterableNextNotAFunction);
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -80,7 +81,7 @@ Object* iterator_next(Object& iterator, Value value)
|
||||||
if (interpreter.exception())
|
if (interpreter.exception())
|
||||||
return {};
|
return {};
|
||||||
if (!result.is_object()) {
|
if (!result.is_object()) {
|
||||||
interpreter.throw_exception<TypeError>(ErrorType::IterableNextBadReturn);
|
interpreter.vm().throw_exception<TypeError>(global_object, ErrorType::IterableNextBadReturn);
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -192,14 +192,14 @@ String JSONObject::serialize_json_property(Interpreter& interpreter, StringifySt
|
||||||
return serialize_json_object(interpreter, state, value.as_object());
|
return serialize_json_object(interpreter, state, value.as_object());
|
||||||
}
|
}
|
||||||
if (value.is_bigint())
|
if (value.is_bigint())
|
||||||
interpreter.throw_exception<TypeError>(ErrorType::JsonBigInt);
|
interpreter.vm().throw_exception<TypeError>(interpreter.global_object(), ErrorType::JsonBigInt);
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
String JSONObject::serialize_json_object(Interpreter& interpreter, StringifyState& state, Object& object)
|
String JSONObject::serialize_json_object(Interpreter& interpreter, StringifyState& state, Object& object)
|
||||||
{
|
{
|
||||||
if (state.seen_objects.contains(&object)) {
|
if (state.seen_objects.contains(&object)) {
|
||||||
interpreter.throw_exception<TypeError>(ErrorType::JsonCircular);
|
interpreter.vm().throw_exception<TypeError>(interpreter.global_object(), ErrorType::JsonCircular);
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -282,7 +282,7 @@ String JSONObject::serialize_json_object(Interpreter& interpreter, StringifyStat
|
||||||
String JSONObject::serialize_json_array(Interpreter& interpreter, StringifyState& state, Object& object)
|
String JSONObject::serialize_json_array(Interpreter& interpreter, StringifyState& state, Object& object)
|
||||||
{
|
{
|
||||||
if (state.seen_objects.contains(&object)) {
|
if (state.seen_objects.contains(&object)) {
|
||||||
interpreter.throw_exception<TypeError>(ErrorType::JsonCircular);
|
interpreter.vm().throw_exception<TypeError>(interpreter.global_object(), ErrorType::JsonCircular);
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -394,7 +394,7 @@ JS_DEFINE_NATIVE_FUNCTION(JSONObject::parse)
|
||||||
|
|
||||||
auto json = JsonValue::from_string(string);
|
auto json = JsonValue::from_string(string);
|
||||||
if (!json.has_value()) {
|
if (!json.has_value()) {
|
||||||
interpreter.throw_exception<SyntaxError>(ErrorType::JsonMalformed);
|
interpreter.vm().throw_exception<SyntaxError>(global_object, ErrorType::JsonMalformed);
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
Value result = parse_json_value(interpreter, global_object, json.value());
|
Value result = parse_json_value(interpreter, global_object, json.value());
|
||||||
|
|
|
@ -27,6 +27,7 @@
|
||||||
#include <LibJS/Interpreter.h>
|
#include <LibJS/Interpreter.h>
|
||||||
#include <LibJS/Runtime/Error.h>
|
#include <LibJS/Runtime/Error.h>
|
||||||
#include <LibJS/Runtime/Function.h>
|
#include <LibJS/Runtime/Function.h>
|
||||||
|
#include <LibJS/Runtime/GlobalObject.h>
|
||||||
#include <LibJS/Runtime/LexicalEnvironment.h>
|
#include <LibJS/Runtime/LexicalEnvironment.h>
|
||||||
#include <LibJS/Runtime/Value.h>
|
#include <LibJS/Runtime/Value.h>
|
||||||
|
|
||||||
|
@ -72,12 +73,16 @@ void LexicalEnvironment::visit_children(Visitor& visitor)
|
||||||
|
|
||||||
Optional<Variable> LexicalEnvironment::get(const FlyString& name) const
|
Optional<Variable> LexicalEnvironment::get(const FlyString& name) const
|
||||||
{
|
{
|
||||||
|
ASSERT(type() != EnvironmentRecordType::Global);
|
||||||
return m_variables.get(name);
|
return m_variables.get(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
void LexicalEnvironment::set(const FlyString& name, Variable variable)
|
void LexicalEnvironment::set(const FlyString& name, Variable variable)
|
||||||
{
|
{
|
||||||
m_variables.set(name, variable);
|
if (type() == EnvironmentRecordType::Global)
|
||||||
|
interpreter().global_object().put(name, variable.value);
|
||||||
|
else
|
||||||
|
m_variables.set(name, variable);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool LexicalEnvironment::has_super_binding() const
|
bool LexicalEnvironment::has_super_binding() const
|
||||||
|
@ -113,7 +118,7 @@ Value LexicalEnvironment::get_this_binding() const
|
||||||
{
|
{
|
||||||
ASSERT(has_this_binding());
|
ASSERT(has_this_binding());
|
||||||
if (this_binding_status() == ThisBindingStatus::Uninitialized) {
|
if (this_binding_status() == ThisBindingStatus::Uninitialized) {
|
||||||
interpreter().throw_exception<ReferenceError>(ErrorType::ThisHasNotBeenInitialized);
|
interpreter().vm().throw_exception<ReferenceError>(interpreter().global_object(), ErrorType::ThisHasNotBeenInitialized);
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
return m_this_value;
|
return m_this_value;
|
||||||
|
@ -123,7 +128,7 @@ void LexicalEnvironment::bind_this_value(Value this_value)
|
||||||
{
|
{
|
||||||
ASSERT(has_this_binding());
|
ASSERT(has_this_binding());
|
||||||
if (m_this_binding_status == ThisBindingStatus::Initialized) {
|
if (m_this_binding_status == ThisBindingStatus::Initialized) {
|
||||||
interpreter().throw_exception<ReferenceError>(ErrorType::ThisIsAlreadyInitialized);
|
interpreter().vm().throw_exception<ReferenceError>(interpreter().global_object(), ErrorType::ThisIsAlreadyInitialized);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
m_this_value = this_value;
|
m_this_value = this_value;
|
||||||
|
|
|
@ -87,6 +87,8 @@ public:
|
||||||
Function* current_function() const { return m_current_function; }
|
Function* current_function() const { return m_current_function; }
|
||||||
void set_current_function(Function& function) { m_current_function = &function; }
|
void set_current_function(Function& function) { m_current_function = &function; }
|
||||||
|
|
||||||
|
EnvironmentRecordType type() const { return m_environment_record_type; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
virtual const char* class_name() const override { return "LexicalEnvironment"; }
|
virtual const char* class_name() const override { return "LexicalEnvironment"; }
|
||||||
virtual void visit_children(Visitor&) override;
|
virtual void visit_children(Visitor&) override;
|
||||||
|
|
|
@ -69,7 +69,7 @@ JS_DEFINE_NATIVE_FUNCTION(NumberPrototype::to_string)
|
||||||
} else if (this_value.is_object() && this_value.as_object().is_number_object()) {
|
} else if (this_value.is_object() && this_value.as_object().is_number_object()) {
|
||||||
number_value = static_cast<NumberObject&>(this_value.as_object()).value_of();
|
number_value = static_cast<NumberObject&>(this_value.as_object()).value_of();
|
||||||
} else {
|
} else {
|
||||||
interpreter.throw_exception<TypeError>(ErrorType::NumberIncompatibleThis, "toString");
|
interpreter.vm().throw_exception<TypeError>(global_object, ErrorType::NumberIncompatibleThis, "toString");
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -82,7 +82,7 @@ JS_DEFINE_NATIVE_FUNCTION(NumberPrototype::to_string)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (interpreter.exception() || radix < 2 || radix > 36) {
|
if (interpreter.exception() || radix < 2 || radix > 36) {
|
||||||
interpreter.throw_exception<RangeError>(ErrorType::InvalidRadix);
|
interpreter.vm().throw_exception<RangeError>(global_object, ErrorType::InvalidRadix);
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -358,7 +358,7 @@ bool Object::define_property(const StringOrSymbol& property_name, const Object&
|
||||||
if (is_accessor_property) {
|
if (is_accessor_property) {
|
||||||
if (descriptor.has_property("value") || descriptor.has_property("writable")) {
|
if (descriptor.has_property("value") || descriptor.has_property("writable")) {
|
||||||
if (throw_exceptions)
|
if (throw_exceptions)
|
||||||
interpreter().throw_exception<TypeError>(ErrorType::AccessorValueOrWritable);
|
interpreter().vm().throw_exception<TypeError>(global_object(), ErrorType::AccessorValueOrWritable);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -375,14 +375,14 @@ bool Object::define_property(const StringOrSymbol& property_name, const Object&
|
||||||
if (getter.is_function()) {
|
if (getter.is_function()) {
|
||||||
getter_function = &getter.as_function();
|
getter_function = &getter.as_function();
|
||||||
} else if (!getter.is_undefined()) {
|
} else if (!getter.is_undefined()) {
|
||||||
interpreter().throw_exception<TypeError>(ErrorType::AccessorBadField, "get");
|
interpreter().vm().throw_exception<TypeError>(global_object(), ErrorType::AccessorBadField, "get");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (setter.is_function()) {
|
if (setter.is_function()) {
|
||||||
setter_function = &setter.as_function();
|
setter_function = &setter.as_function();
|
||||||
} else if (!setter.is_undefined()) {
|
} else if (!setter.is_undefined()) {
|
||||||
interpreter().throw_exception<TypeError>(ErrorType::AccessorBadField, "set");
|
interpreter().vm().throw_exception<TypeError>(global_object(), ErrorType::AccessorBadField, "set");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -465,7 +465,7 @@ bool Object::put_own_property(Object& this_object, const StringOrSymbol& propert
|
||||||
dbg() << "Disallow define_property of non-extensible object";
|
dbg() << "Disallow define_property of non-extensible object";
|
||||||
#endif
|
#endif
|
||||||
if (throw_exceptions && interpreter().in_strict_mode())
|
if (throw_exceptions && interpreter().in_strict_mode())
|
||||||
interpreter().throw_exception<TypeError>(ErrorType::NonExtensibleDefine, property_name.to_display_string().characters());
|
interpreter().vm().throw_exception<TypeError>(global_object(), ErrorType::NonExtensibleDefine, property_name.to_display_string().characters());
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -499,7 +499,7 @@ bool Object::put_own_property(Object& this_object, const StringOrSymbol& propert
|
||||||
dbg() << "Disallow reconfig of non-configurable property";
|
dbg() << "Disallow reconfig of non-configurable property";
|
||||||
#endif
|
#endif
|
||||||
if (throw_exceptions)
|
if (throw_exceptions)
|
||||||
interpreter().throw_exception<TypeError>(ErrorType::DescChangeNonConfigurable, property_name.to_display_string().characters());
|
interpreter().vm().throw_exception<TypeError>(global_object(), ErrorType::DescChangeNonConfigurable, property_name.to_display_string().characters());
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -547,7 +547,7 @@ bool Object::put_own_property_by_index(Object& this_object, u32 property_index,
|
||||||
dbg() << "Disallow define_property of non-extensible object";
|
dbg() << "Disallow define_property of non-extensible object";
|
||||||
#endif
|
#endif
|
||||||
if (throw_exceptions && interpreter().in_strict_mode())
|
if (throw_exceptions && interpreter().in_strict_mode())
|
||||||
interpreter().throw_exception<TypeError>(ErrorType::NonExtensibleDefine, property_index);
|
interpreter().vm().throw_exception<TypeError>(global_object(), ErrorType::NonExtensibleDefine, property_index);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -566,7 +566,7 @@ bool Object::put_own_property_by_index(Object& this_object, u32 property_index,
|
||||||
dbg() << "Disallow reconfig of non-configurable property";
|
dbg() << "Disallow reconfig of non-configurable property";
|
||||||
#endif
|
#endif
|
||||||
if (throw_exceptions)
|
if (throw_exceptions)
|
||||||
interpreter().throw_exception<TypeError>(ErrorType::DescChangeNonConfigurable, property_index);
|
interpreter().vm().throw_exception<TypeError>(global_object(), ErrorType::DescChangeNonConfigurable, property_index);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -843,7 +843,7 @@ Value Object::to_string() const
|
||||||
auto& interpreter = const_cast<Object*>(this)->interpreter();
|
auto& interpreter = const_cast<Object*>(this)->interpreter();
|
||||||
auto to_string_result = interpreter.call(to_string_function, const_cast<Object*>(this));
|
auto to_string_result = interpreter.call(to_string_function, const_cast<Object*>(this));
|
||||||
if (to_string_result.is_object())
|
if (to_string_result.is_object())
|
||||||
interpreter.throw_exception<TypeError>(ErrorType::Convert, "object", "string");
|
interpreter.vm().throw_exception<TypeError>(global_object(), ErrorType::Convert, "object", "string");
|
||||||
if (interpreter.exception())
|
if (interpreter.exception())
|
||||||
return {};
|
return {};
|
||||||
auto* string = to_string_result.to_primitive_string(interpreter);
|
auto* string = to_string_result.to_primitive_string(interpreter);
|
||||||
|
@ -861,7 +861,7 @@ Value Object::invoke(const StringOrSymbol& property_name, Optional<MarkedValueLi
|
||||||
if (interpreter.exception())
|
if (interpreter.exception())
|
||||||
return {};
|
return {};
|
||||||
if (!property.is_function()) {
|
if (!property.is_function()) {
|
||||||
interpreter.throw_exception<TypeError>(ErrorType::NotAFunction, property.to_string_without_side_effects().characters());
|
interpreter.vm().throw_exception<TypeError>(global_object(), ErrorType::NotAFunction, property.to_string_without_side_effects().characters());
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
return interpreter.call(property.as_function(), this, move(arguments));
|
return interpreter.call(property.as_function(), this, move(arguments));
|
||||||
|
@ -870,20 +870,20 @@ Value Object::invoke(const StringOrSymbol& property_name, Optional<MarkedValueLi
|
||||||
Value Object::call_native_property_getter(Object* this_object, Value property) const
|
Value Object::call_native_property_getter(Object* this_object, Value property) const
|
||||||
{
|
{
|
||||||
ASSERT(property.is_native_property());
|
ASSERT(property.is_native_property());
|
||||||
auto& call_frame = interpreter().push_call_frame();
|
auto& call_frame = interpreter().vm().push_call_frame();
|
||||||
call_frame.this_value = this_object;
|
call_frame.this_value = this_object;
|
||||||
auto result = property.as_native_property().get(interpreter(), global_object());
|
auto result = property.as_native_property().get(interpreter(), global_object());
|
||||||
interpreter().pop_call_frame();
|
interpreter().vm().pop_call_frame();
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Object::call_native_property_setter(Object* this_object, Value property, Value value) const
|
void Object::call_native_property_setter(Object* this_object, Value property, Value value) const
|
||||||
{
|
{
|
||||||
ASSERT(property.is_native_property());
|
ASSERT(property.is_native_property());
|
||||||
auto& call_frame = interpreter().push_call_frame();
|
auto& call_frame = interpreter().vm().push_call_frame();
|
||||||
call_frame.this_value = this_object;
|
call_frame.this_value = this_object;
|
||||||
property.as_native_property().set(interpreter(), global_object(), value);
|
property.as_native_property().set(interpreter(), global_object(), value);
|
||||||
interpreter().pop_call_frame();
|
interpreter().vm().pop_call_frame();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -106,7 +106,7 @@ JS_DEFINE_NATIVE_FUNCTION(ObjectConstructor::get_prototype_of)
|
||||||
JS_DEFINE_NATIVE_FUNCTION(ObjectConstructor::set_prototype_of)
|
JS_DEFINE_NATIVE_FUNCTION(ObjectConstructor::set_prototype_of)
|
||||||
{
|
{
|
||||||
if (interpreter.argument_count() < 2) {
|
if (interpreter.argument_count() < 2) {
|
||||||
interpreter.throw_exception<TypeError>(ErrorType::ObjectSetPrototypeOfTwoArgs);
|
interpreter.vm().throw_exception<TypeError>(global_object, ErrorType::ObjectSetPrototypeOfTwoArgs);
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
auto* object = interpreter.argument(0).to_object(interpreter, global_object);
|
auto* object = interpreter.argument(0).to_object(interpreter, global_object);
|
||||||
|
@ -119,12 +119,12 @@ JS_DEFINE_NATIVE_FUNCTION(ObjectConstructor::set_prototype_of)
|
||||||
} else if (prototype_value.is_object()) {
|
} else if (prototype_value.is_object()) {
|
||||||
prototype = &prototype_value.as_object();
|
prototype = &prototype_value.as_object();
|
||||||
} else {
|
} else {
|
||||||
interpreter.throw_exception<TypeError>(ErrorType::ObjectPrototypeWrongType);
|
interpreter.vm().throw_exception<TypeError>(global_object, ErrorType::ObjectPrototypeWrongType);
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
if (!object->set_prototype(prototype)) {
|
if (!object->set_prototype(prototype)) {
|
||||||
if (!interpreter.exception())
|
if (!interpreter.exception())
|
||||||
interpreter.throw_exception<TypeError>(ErrorType::ObjectSetPrototypeOfReturnedFalse);
|
interpreter.vm().throw_exception<TypeError>(global_object, ErrorType::ObjectSetPrototypeOfReturnedFalse);
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
return object;
|
return object;
|
||||||
|
@ -145,7 +145,7 @@ JS_DEFINE_NATIVE_FUNCTION(ObjectConstructor::prevent_extensions)
|
||||||
return argument;
|
return argument;
|
||||||
if (!argument.as_object().prevent_extensions()) {
|
if (!argument.as_object().prevent_extensions()) {
|
||||||
if (!interpreter.exception())
|
if (!interpreter.exception())
|
||||||
interpreter.throw_exception<TypeError>(ErrorType::ObjectPreventExtensionsReturnedFalse);
|
interpreter.vm().throw_exception<TypeError>(global_object, ErrorType::ObjectPreventExtensionsReturnedFalse);
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
return argument;
|
return argument;
|
||||||
|
@ -165,11 +165,11 @@ JS_DEFINE_NATIVE_FUNCTION(ObjectConstructor::get_own_property_descriptor)
|
||||||
JS_DEFINE_NATIVE_FUNCTION(ObjectConstructor::define_property_)
|
JS_DEFINE_NATIVE_FUNCTION(ObjectConstructor::define_property_)
|
||||||
{
|
{
|
||||||
if (!interpreter.argument(0).is_object()) {
|
if (!interpreter.argument(0).is_object()) {
|
||||||
interpreter.throw_exception<TypeError>(ErrorType::NotAnObject, "Object argument");
|
interpreter.vm().throw_exception<TypeError>(global_object, ErrorType::NotAnObject, "Object argument");
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
if (!interpreter.argument(2).is_object()) {
|
if (!interpreter.argument(2).is_object()) {
|
||||||
interpreter.throw_exception<TypeError>(ErrorType::NotAnObject, "Descriptor argument");
|
interpreter.vm().throw_exception<TypeError>(global_object, ErrorType::NotAnObject, "Descriptor argument");
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
auto& object = interpreter.argument(0).as_object();
|
auto& object = interpreter.argument(0).as_object();
|
||||||
|
@ -180,9 +180,9 @@ JS_DEFINE_NATIVE_FUNCTION(ObjectConstructor::define_property_)
|
||||||
if (!object.define_property(property_key, descriptor)) {
|
if (!object.define_property(property_key, descriptor)) {
|
||||||
if (!interpreter.exception()) {
|
if (!interpreter.exception()) {
|
||||||
if (object.is_proxy_object()) {
|
if (object.is_proxy_object()) {
|
||||||
interpreter.throw_exception<TypeError>(ErrorType::ObjectDefinePropertyReturnedFalse);
|
interpreter.vm().throw_exception<TypeError>(global_object, ErrorType::ObjectDefinePropertyReturnedFalse);
|
||||||
} else {
|
} else {
|
||||||
interpreter.throw_exception<TypeError>(ErrorType::NonExtensibleDefine, property_key.to_display_string().characters());
|
interpreter.vm().throw_exception<TypeError>(global_object, ErrorType::NonExtensibleDefine, property_key.to_display_string().characters());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return {};
|
return {};
|
||||||
|
@ -198,7 +198,7 @@ JS_DEFINE_NATIVE_FUNCTION(ObjectConstructor::is)
|
||||||
JS_DEFINE_NATIVE_FUNCTION(ObjectConstructor::keys)
|
JS_DEFINE_NATIVE_FUNCTION(ObjectConstructor::keys)
|
||||||
{
|
{
|
||||||
if (!interpreter.argument_count()) {
|
if (!interpreter.argument_count()) {
|
||||||
interpreter.throw_exception<TypeError>(ErrorType::ConvertUndefinedToObject);
|
interpreter.vm().throw_exception<TypeError>(global_object, ErrorType::ConvertUndefinedToObject);
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -212,7 +212,7 @@ JS_DEFINE_NATIVE_FUNCTION(ObjectConstructor::keys)
|
||||||
JS_DEFINE_NATIVE_FUNCTION(ObjectConstructor::values)
|
JS_DEFINE_NATIVE_FUNCTION(ObjectConstructor::values)
|
||||||
{
|
{
|
||||||
if (!interpreter.argument_count()) {
|
if (!interpreter.argument_count()) {
|
||||||
interpreter.throw_exception<TypeError>(ErrorType::ConvertUndefinedToObject);
|
interpreter.vm().throw_exception<TypeError>(global_object, ErrorType::ConvertUndefinedToObject);
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
auto* obj_arg = interpreter.argument(0).to_object(interpreter, global_object);
|
auto* obj_arg = interpreter.argument(0).to_object(interpreter, global_object);
|
||||||
|
@ -225,7 +225,7 @@ JS_DEFINE_NATIVE_FUNCTION(ObjectConstructor::values)
|
||||||
JS_DEFINE_NATIVE_FUNCTION(ObjectConstructor::entries)
|
JS_DEFINE_NATIVE_FUNCTION(ObjectConstructor::entries)
|
||||||
{
|
{
|
||||||
if (!interpreter.argument_count()) {
|
if (!interpreter.argument_count()) {
|
||||||
interpreter.throw_exception<TypeError>(ErrorType::ConvertUndefinedToObject);
|
interpreter.vm().throw_exception<TypeError>(global_object, ErrorType::ConvertUndefinedToObject);
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
auto* obj_arg = interpreter.argument(0).to_object(interpreter, global_object);
|
auto* obj_arg = interpreter.argument(0).to_object(interpreter, global_object);
|
||||||
|
|
|
@ -51,14 +51,14 @@ ProxyConstructor::~ProxyConstructor()
|
||||||
|
|
||||||
Value ProxyConstructor::call(Interpreter& interpreter)
|
Value ProxyConstructor::call(Interpreter& interpreter)
|
||||||
{
|
{
|
||||||
interpreter.throw_exception<TypeError>(ErrorType::ProxyCallWithNew);
|
interpreter.vm().throw_exception<TypeError>(global_object(), ErrorType::ProxyCallWithNew);
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
Value ProxyConstructor::construct(Interpreter& interpreter, Function&)
|
Value ProxyConstructor::construct(Interpreter& interpreter, Function&)
|
||||||
{
|
{
|
||||||
if (interpreter.argument_count() < 2) {
|
if (interpreter.argument_count() < 2) {
|
||||||
interpreter.throw_exception<TypeError>(ErrorType::ProxyTwoArguments);
|
interpreter.vm().throw_exception<TypeError>(global_object(), ErrorType::ProxyTwoArguments);
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -66,11 +66,11 @@ Value ProxyConstructor::construct(Interpreter& interpreter, Function&)
|
||||||
auto handler = interpreter.argument(1);
|
auto handler = interpreter.argument(1);
|
||||||
|
|
||||||
if (!target.is_object()) {
|
if (!target.is_object()) {
|
||||||
interpreter.throw_exception<TypeError>(ErrorType::ProxyConstructorBadType, "target", target.to_string_without_side_effects().characters());
|
interpreter.vm().throw_exception<TypeError>(global_object(), ErrorType::ProxyConstructorBadType, "target", target.to_string_without_side_effects().characters());
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
if (!handler.is_object()) {
|
if (!handler.is_object()) {
|
||||||
interpreter.throw_exception<TypeError>(ErrorType::ProxyConstructorBadType, "handler", handler.to_string_without_side_effects().characters());
|
interpreter.vm().throw_exception<TypeError>(global_object(), ErrorType::ProxyConstructorBadType, "handler", handler.to_string_without_side_effects().characters());
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
return ProxyObject::create(global_object(), target.as_object(), handler.as_object());
|
return ProxyObject::create(global_object(), target.as_object(), handler.as_object());
|
||||||
|
|
|
@ -77,7 +77,7 @@ ProxyObject::~ProxyObject()
|
||||||
Object* ProxyObject::prototype()
|
Object* ProxyObject::prototype()
|
||||||
{
|
{
|
||||||
if (m_is_revoked) {
|
if (m_is_revoked) {
|
||||||
interpreter().throw_exception<TypeError>(ErrorType::ProxyRevoked);
|
interpreter().vm().throw_exception<TypeError>(global_object(), ErrorType::ProxyRevoked);
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
auto trap = m_handler.get("getPrototypeOf");
|
auto trap = m_handler.get("getPrototypeOf");
|
||||||
|
@ -86,7 +86,7 @@ Object* ProxyObject::prototype()
|
||||||
if (trap.is_empty() || trap.is_undefined() || trap.is_null())
|
if (trap.is_empty() || trap.is_undefined() || trap.is_null())
|
||||||
return m_target.prototype();
|
return m_target.prototype();
|
||||||
if (!trap.is_function()) {
|
if (!trap.is_function()) {
|
||||||
interpreter().throw_exception<TypeError>(ErrorType::ProxyInvalidTrap, "getPrototypeOf");
|
interpreter().vm().throw_exception<TypeError>(global_object(), ErrorType::ProxyInvalidTrap, "getPrototypeOf");
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -94,7 +94,7 @@ Object* ProxyObject::prototype()
|
||||||
if (vm().exception())
|
if (vm().exception())
|
||||||
return nullptr;
|
return nullptr;
|
||||||
if (!trap_result.is_object() && !trap_result.is_null()) {
|
if (!trap_result.is_object() && !trap_result.is_null()) {
|
||||||
interpreter().throw_exception<TypeError>(ErrorType::ProxyGetPrototypeOfReturn);
|
interpreter().vm().throw_exception<TypeError>(global_object(), ErrorType::ProxyGetPrototypeOfReturn);
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
if (m_target.is_extensible()) {
|
if (m_target.is_extensible()) {
|
||||||
|
@ -108,7 +108,7 @@ Object* ProxyObject::prototype()
|
||||||
if (vm().exception())
|
if (vm().exception())
|
||||||
return nullptr;
|
return nullptr;
|
||||||
if (!same_value(interpreter(), trap_result, Value(target_proto))) {
|
if (!same_value(interpreter(), trap_result, Value(target_proto))) {
|
||||||
interpreter().throw_exception<TypeError>(ErrorType::ProxyGetPrototypeOfNonExtensible);
|
interpreter().vm().throw_exception<TypeError>(global_object(), ErrorType::ProxyGetPrototypeOfNonExtensible);
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
return &trap_result.as_object();
|
return &trap_result.as_object();
|
||||||
|
@ -117,7 +117,7 @@ Object* ProxyObject::prototype()
|
||||||
const Object* ProxyObject::prototype() const
|
const Object* ProxyObject::prototype() const
|
||||||
{
|
{
|
||||||
if (m_is_revoked) {
|
if (m_is_revoked) {
|
||||||
interpreter().throw_exception<TypeError>(ErrorType::ProxyRevoked);
|
interpreter().vm().throw_exception<TypeError>(global_object(), ErrorType::ProxyRevoked);
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
return const_cast<const Object*>(const_cast<ProxyObject*>(this)->prototype());
|
return const_cast<const Object*>(const_cast<ProxyObject*>(this)->prototype());
|
||||||
|
@ -126,7 +126,7 @@ const Object* ProxyObject::prototype() const
|
||||||
bool ProxyObject::set_prototype(Object* object)
|
bool ProxyObject::set_prototype(Object* object)
|
||||||
{
|
{
|
||||||
if (m_is_revoked) {
|
if (m_is_revoked) {
|
||||||
interpreter().throw_exception<TypeError>(ErrorType::ProxyRevoked);
|
interpreter().vm().throw_exception<TypeError>(global_object(), ErrorType::ProxyRevoked);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
auto trap = m_handler.get("setPrototypeOf");
|
auto trap = m_handler.get("setPrototypeOf");
|
||||||
|
@ -135,7 +135,7 @@ bool ProxyObject::set_prototype(Object* object)
|
||||||
if (trap.is_empty() || trap.is_undefined() || trap.is_null())
|
if (trap.is_empty() || trap.is_undefined() || trap.is_null())
|
||||||
return m_target.set_prototype(object);
|
return m_target.set_prototype(object);
|
||||||
if (!trap.is_function()) {
|
if (!trap.is_function()) {
|
||||||
interpreter().throw_exception<TypeError>(ErrorType::ProxyInvalidTrap, "setPrototypeOf");
|
interpreter().vm().throw_exception<TypeError>(global_object(), ErrorType::ProxyInvalidTrap, "setPrototypeOf");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -148,7 +148,7 @@ bool ProxyObject::set_prototype(Object* object)
|
||||||
if (vm().exception())
|
if (vm().exception())
|
||||||
return false;
|
return false;
|
||||||
if (!same_value(interpreter(), Value(object), Value(target_proto))) {
|
if (!same_value(interpreter(), Value(object), Value(target_proto))) {
|
||||||
interpreter().throw_exception<TypeError>(ErrorType::ProxySetPrototypeOfNonExtensible);
|
interpreter().vm().throw_exception<TypeError>(global_object(), ErrorType::ProxySetPrototypeOfNonExtensible);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
|
@ -157,7 +157,7 @@ bool ProxyObject::set_prototype(Object* object)
|
||||||
bool ProxyObject::is_extensible() const
|
bool ProxyObject::is_extensible() const
|
||||||
{
|
{
|
||||||
if (m_is_revoked) {
|
if (m_is_revoked) {
|
||||||
interpreter().throw_exception<TypeError>(ErrorType::ProxyRevoked);
|
interpreter().vm().throw_exception<TypeError>(global_object(), ErrorType::ProxyRevoked);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
auto trap = m_handler.get("isExtensible");
|
auto trap = m_handler.get("isExtensible");
|
||||||
|
@ -166,7 +166,7 @@ bool ProxyObject::is_extensible() const
|
||||||
if (trap.is_empty() || trap.is_undefined() || trap.is_null())
|
if (trap.is_empty() || trap.is_undefined() || trap.is_null())
|
||||||
return m_target.is_extensible();
|
return m_target.is_extensible();
|
||||||
if (!trap.is_function()) {
|
if (!trap.is_function()) {
|
||||||
interpreter().throw_exception<TypeError>(ErrorType::ProxyInvalidTrap, "isExtensible");
|
interpreter().vm().throw_exception<TypeError>(global_object(), ErrorType::ProxyInvalidTrap, "isExtensible");
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -175,7 +175,7 @@ bool ProxyObject::is_extensible() const
|
||||||
return false;
|
return false;
|
||||||
if (trap_result != m_target.is_extensible()) {
|
if (trap_result != m_target.is_extensible()) {
|
||||||
if (!vm().exception())
|
if (!vm().exception())
|
||||||
interpreter().throw_exception<TypeError>(ErrorType::ProxyIsExtensibleReturn);
|
interpreter().vm().throw_exception<TypeError>(global_object(), ErrorType::ProxyIsExtensibleReturn);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return trap_result;
|
return trap_result;
|
||||||
|
@ -184,7 +184,7 @@ bool ProxyObject::is_extensible() const
|
||||||
bool ProxyObject::prevent_extensions()
|
bool ProxyObject::prevent_extensions()
|
||||||
{
|
{
|
||||||
if (m_is_revoked) {
|
if (m_is_revoked) {
|
||||||
interpreter().throw_exception<TypeError>(ErrorType::ProxyRevoked);
|
interpreter().vm().throw_exception<TypeError>(global_object(), ErrorType::ProxyRevoked);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
auto trap = m_handler.get("preventExtensions");
|
auto trap = m_handler.get("preventExtensions");
|
||||||
|
@ -193,7 +193,7 @@ bool ProxyObject::prevent_extensions()
|
||||||
if (trap.is_empty() || trap.is_undefined() || trap.is_null())
|
if (trap.is_empty() || trap.is_undefined() || trap.is_null())
|
||||||
return m_target.prevent_extensions();
|
return m_target.prevent_extensions();
|
||||||
if (!trap.is_function()) {
|
if (!trap.is_function()) {
|
||||||
interpreter().throw_exception<TypeError>(ErrorType::ProxyInvalidTrap, "preventExtensions");
|
interpreter().vm().throw_exception<TypeError>(global_object(), ErrorType::ProxyInvalidTrap, "preventExtensions");
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -202,7 +202,7 @@ bool ProxyObject::prevent_extensions()
|
||||||
return false;
|
return false;
|
||||||
if (trap_result && m_target.is_extensible()) {
|
if (trap_result && m_target.is_extensible()) {
|
||||||
if (!vm().exception())
|
if (!vm().exception())
|
||||||
interpreter().throw_exception<TypeError>(ErrorType::ProxyPreventExtensionsReturn);
|
interpreter().vm().throw_exception<TypeError>(global_object(), ErrorType::ProxyPreventExtensionsReturn);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return trap_result;
|
return trap_result;
|
||||||
|
@ -211,7 +211,7 @@ bool ProxyObject::prevent_extensions()
|
||||||
Optional<PropertyDescriptor> ProxyObject::get_own_property_descriptor(const PropertyName& name) const
|
Optional<PropertyDescriptor> ProxyObject::get_own_property_descriptor(const PropertyName& name) const
|
||||||
{
|
{
|
||||||
if (m_is_revoked) {
|
if (m_is_revoked) {
|
||||||
interpreter().throw_exception<TypeError>(ErrorType::ProxyRevoked);
|
interpreter().vm().throw_exception<TypeError>(global_object(), ErrorType::ProxyRevoked);
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
auto trap = m_handler.get("getOwnPropertyDescriptor");
|
auto trap = m_handler.get("getOwnPropertyDescriptor");
|
||||||
|
@ -220,7 +220,7 @@ Optional<PropertyDescriptor> ProxyObject::get_own_property_descriptor(const Prop
|
||||||
if (trap.is_empty() || trap.is_undefined() || trap.is_null())
|
if (trap.is_empty() || trap.is_undefined() || trap.is_null())
|
||||||
return m_target.get_own_property_descriptor(name);
|
return m_target.get_own_property_descriptor(name);
|
||||||
if (!trap.is_function()) {
|
if (!trap.is_function()) {
|
||||||
interpreter().throw_exception<TypeError>(ErrorType::ProxyInvalidTrap, "getOwnPropertyDescriptor");
|
interpreter().vm().throw_exception<TypeError>(global_object(), ErrorType::ProxyInvalidTrap, "getOwnPropertyDescriptor");
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -228,7 +228,7 @@ Optional<PropertyDescriptor> ProxyObject::get_own_property_descriptor(const Prop
|
||||||
if (vm().exception())
|
if (vm().exception())
|
||||||
return {};
|
return {};
|
||||||
if (!trap_result.is_object() && !trap_result.is_undefined()) {
|
if (!trap_result.is_object() && !trap_result.is_undefined()) {
|
||||||
interpreter().throw_exception<TypeError>(ErrorType::ProxyGetOwnDescriptorReturn);
|
interpreter().vm().throw_exception<TypeError>(global_object(), ErrorType::ProxyGetOwnDescriptorReturn);
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
auto target_desc = m_target.get_own_property_descriptor(name);
|
auto target_desc = m_target.get_own_property_descriptor(name);
|
||||||
|
@ -238,12 +238,12 @@ Optional<PropertyDescriptor> ProxyObject::get_own_property_descriptor(const Prop
|
||||||
if (!target_desc.has_value())
|
if (!target_desc.has_value())
|
||||||
return {};
|
return {};
|
||||||
if (!target_desc.value().attributes.is_configurable()) {
|
if (!target_desc.value().attributes.is_configurable()) {
|
||||||
interpreter().throw_exception<TypeError>(ErrorType::ProxyGetOwnDescriptorNonConfigurable);
|
interpreter().vm().throw_exception<TypeError>(global_object(), ErrorType::ProxyGetOwnDescriptorNonConfigurable);
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
if (!m_target.is_extensible()) {
|
if (!m_target.is_extensible()) {
|
||||||
if (!vm().exception())
|
if (!vm().exception())
|
||||||
interpreter().throw_exception<TypeError>(ErrorType::ProxyGetOwnDescriptorUndefReturn);
|
interpreter().vm().throw_exception<TypeError>(global_object(), ErrorType::ProxyGetOwnDescriptorUndefReturn);
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
return {};
|
return {};
|
||||||
|
@ -253,11 +253,11 @@ Optional<PropertyDescriptor> ProxyObject::get_own_property_descriptor(const Prop
|
||||||
return {};
|
return {};
|
||||||
if (!is_compatible_property_descriptor(interpreter(), m_target.is_extensible(), result_desc, target_desc)) {
|
if (!is_compatible_property_descriptor(interpreter(), m_target.is_extensible(), result_desc, target_desc)) {
|
||||||
if (!vm().exception())
|
if (!vm().exception())
|
||||||
interpreter().throw_exception<TypeError>(ErrorType::ProxyGetOwnDescriptorInvalidDescriptor);
|
interpreter().vm().throw_exception<TypeError>(global_object(), ErrorType::ProxyGetOwnDescriptorInvalidDescriptor);
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
if (!result_desc.attributes.is_configurable() && (!target_desc.has_value() || target_desc.value().attributes.is_configurable())) {
|
if (!result_desc.attributes.is_configurable() && (!target_desc.has_value() || target_desc.value().attributes.is_configurable())) {
|
||||||
interpreter().throw_exception<TypeError>(ErrorType::ProxyGetOwnDescriptorInvalidNonConfig);
|
interpreter().vm().throw_exception<TypeError>(global_object(), ErrorType::ProxyGetOwnDescriptorInvalidNonConfig);
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
return result_desc;
|
return result_desc;
|
||||||
|
@ -266,7 +266,7 @@ Optional<PropertyDescriptor> ProxyObject::get_own_property_descriptor(const Prop
|
||||||
bool ProxyObject::define_property(const StringOrSymbol& property_name, const Object& descriptor, bool throw_exceptions)
|
bool ProxyObject::define_property(const StringOrSymbol& property_name, const Object& descriptor, bool throw_exceptions)
|
||||||
{
|
{
|
||||||
if (m_is_revoked) {
|
if (m_is_revoked) {
|
||||||
interpreter().throw_exception<TypeError>(ErrorType::ProxyRevoked);
|
interpreter().vm().throw_exception<TypeError>(global_object(), ErrorType::ProxyRevoked);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
auto trap = m_handler.get("defineProperty");
|
auto trap = m_handler.get("defineProperty");
|
||||||
|
@ -275,7 +275,7 @@ bool ProxyObject::define_property(const StringOrSymbol& property_name, const Obj
|
||||||
if (trap.is_empty() || trap.is_undefined() || trap.is_null())
|
if (trap.is_empty() || trap.is_undefined() || trap.is_null())
|
||||||
return m_target.define_property(property_name, descriptor, throw_exceptions);
|
return m_target.define_property(property_name, descriptor, throw_exceptions);
|
||||||
if (!trap.is_function()) {
|
if (!trap.is_function()) {
|
||||||
interpreter().throw_exception<TypeError>(ErrorType::ProxyInvalidTrap, "defineProperty");
|
interpreter().vm().throw_exception<TypeError>(global_object(), ErrorType::ProxyInvalidTrap, "defineProperty");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -293,21 +293,21 @@ bool ProxyObject::define_property(const StringOrSymbol& property_name, const Obj
|
||||||
if (!target_desc.has_value()) {
|
if (!target_desc.has_value()) {
|
||||||
if (!m_target.is_extensible()) {
|
if (!m_target.is_extensible()) {
|
||||||
if (!vm().exception())
|
if (!vm().exception())
|
||||||
interpreter().throw_exception<TypeError>(ErrorType::ProxyDefinePropNonExtensible);
|
interpreter().vm().throw_exception<TypeError>(global_object(), ErrorType::ProxyDefinePropNonExtensible);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (setting_config_false) {
|
if (setting_config_false) {
|
||||||
interpreter().throw_exception<TypeError>(ErrorType::ProxyDefinePropNonConfigurableNonExisting);
|
interpreter().vm().throw_exception<TypeError>(global_object(), ErrorType::ProxyDefinePropNonConfigurableNonExisting);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (!is_compatible_property_descriptor(interpreter(), m_target.is_extensible(), PropertyDescriptor::from_dictionary(vm(), descriptor), target_desc)) {
|
if (!is_compatible_property_descriptor(interpreter(), m_target.is_extensible(), PropertyDescriptor::from_dictionary(vm(), descriptor), target_desc)) {
|
||||||
if (!vm().exception())
|
if (!vm().exception())
|
||||||
interpreter().throw_exception<TypeError>(ErrorType::ProxyDefinePropIncompatibleDescriptor);
|
interpreter().vm().throw_exception<TypeError>(global_object(), ErrorType::ProxyDefinePropIncompatibleDescriptor);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (setting_config_false && target_desc.value().attributes.is_configurable()) {
|
if (setting_config_false && target_desc.value().attributes.is_configurable()) {
|
||||||
interpreter().throw_exception<TypeError>(ErrorType::ProxyDefinePropExistingConfigurable);
|
interpreter().vm().throw_exception<TypeError>(global_object(), ErrorType::ProxyDefinePropExistingConfigurable);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -317,7 +317,7 @@ bool ProxyObject::define_property(const StringOrSymbol& property_name, const Obj
|
||||||
bool ProxyObject::has_property(const PropertyName& name) const
|
bool ProxyObject::has_property(const PropertyName& name) const
|
||||||
{
|
{
|
||||||
if (m_is_revoked) {
|
if (m_is_revoked) {
|
||||||
interpreter().throw_exception<TypeError>(ErrorType::ProxyRevoked);
|
interpreter().vm().throw_exception<TypeError>(global_object(), ErrorType::ProxyRevoked);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
auto trap = m_handler.get("has");
|
auto trap = m_handler.get("has");
|
||||||
|
@ -326,7 +326,7 @@ bool ProxyObject::has_property(const PropertyName& name) const
|
||||||
if (trap.is_empty() || trap.is_undefined() || trap.is_null())
|
if (trap.is_empty() || trap.is_undefined() || trap.is_null())
|
||||||
return m_target.has_property(name);
|
return m_target.has_property(name);
|
||||||
if (!trap.is_function()) {
|
if (!trap.is_function()) {
|
||||||
interpreter().throw_exception<TypeError>(ErrorType::ProxyInvalidTrap, "has");
|
interpreter().vm().throw_exception<TypeError>(global_object(), ErrorType::ProxyInvalidTrap, "has");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -339,12 +339,12 @@ bool ProxyObject::has_property(const PropertyName& name) const
|
||||||
return false;
|
return false;
|
||||||
if (target_desc.has_value()) {
|
if (target_desc.has_value()) {
|
||||||
if (!target_desc.value().attributes.is_configurable()) {
|
if (!target_desc.value().attributes.is_configurable()) {
|
||||||
interpreter().throw_exception<TypeError>(ErrorType::ProxyHasExistingNonConfigurable);
|
interpreter().vm().throw_exception<TypeError>(global_object(), ErrorType::ProxyHasExistingNonConfigurable);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (!m_target.is_extensible()) {
|
if (!m_target.is_extensible()) {
|
||||||
if (!vm().exception())
|
if (!vm().exception())
|
||||||
interpreter().throw_exception<TypeError>(ErrorType::ProxyHasExistingNonExtensible);
|
interpreter().vm().throw_exception<TypeError>(global_object(), ErrorType::ProxyHasExistingNonExtensible);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -355,7 +355,7 @@ bool ProxyObject::has_property(const PropertyName& name) const
|
||||||
Value ProxyObject::get(const PropertyName& name, Value) const
|
Value ProxyObject::get(const PropertyName& name, Value) const
|
||||||
{
|
{
|
||||||
if (m_is_revoked) {
|
if (m_is_revoked) {
|
||||||
interpreter().throw_exception<TypeError>(ErrorType::ProxyRevoked);
|
interpreter().vm().throw_exception<TypeError>(global_object(), ErrorType::ProxyRevoked);
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
auto trap = m_handler.get("get");
|
auto trap = m_handler.get("get");
|
||||||
|
@ -364,7 +364,7 @@ Value ProxyObject::get(const PropertyName& name, Value) const
|
||||||
if (trap.is_empty() || trap.is_undefined() || trap.is_null())
|
if (trap.is_empty() || trap.is_undefined() || trap.is_null())
|
||||||
return m_target.get(name);
|
return m_target.get(name);
|
||||||
if (!trap.is_function()) {
|
if (!trap.is_function()) {
|
||||||
interpreter().throw_exception<TypeError>(ErrorType::ProxyInvalidTrap, "get");
|
interpreter().vm().throw_exception<TypeError>(global_object(), ErrorType::ProxyInvalidTrap, "get");
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -376,11 +376,11 @@ Value ProxyObject::get(const PropertyName& name, Value) const
|
||||||
if (vm().exception())
|
if (vm().exception())
|
||||||
return {};
|
return {};
|
||||||
if (target_desc.value().is_data_descriptor() && !target_desc.value().attributes.is_writable() && !same_value(interpreter(), trap_result, target_desc.value().value)) {
|
if (target_desc.value().is_data_descriptor() && !target_desc.value().attributes.is_writable() && !same_value(interpreter(), trap_result, target_desc.value().value)) {
|
||||||
interpreter().throw_exception<TypeError>(ErrorType::ProxyGetImmutableDataProperty);
|
interpreter().vm().throw_exception<TypeError>(global_object(), ErrorType::ProxyGetImmutableDataProperty);
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
if (target_desc.value().is_accessor_descriptor() && target_desc.value().getter == nullptr && !trap_result.is_undefined()) {
|
if (target_desc.value().is_accessor_descriptor() && target_desc.value().getter == nullptr && !trap_result.is_undefined()) {
|
||||||
interpreter().throw_exception<TypeError>(ErrorType::ProxyGetNonConfigurableAccessor);
|
interpreter().vm().throw_exception<TypeError>(global_object(), ErrorType::ProxyGetNonConfigurableAccessor);
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -390,7 +390,7 @@ Value ProxyObject::get(const PropertyName& name, Value) const
|
||||||
bool ProxyObject::put(const PropertyName& name, Value value, Value)
|
bool ProxyObject::put(const PropertyName& name, Value value, Value)
|
||||||
{
|
{
|
||||||
if (m_is_revoked) {
|
if (m_is_revoked) {
|
||||||
interpreter().throw_exception<TypeError>(ErrorType::ProxyRevoked);
|
interpreter().vm().throw_exception<TypeError>(global_object(), ErrorType::ProxyRevoked);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
auto trap = m_handler.get("set");
|
auto trap = m_handler.get("set");
|
||||||
|
@ -399,7 +399,7 @@ bool ProxyObject::put(const PropertyName& name, Value value, Value)
|
||||||
if (trap.is_empty() || trap.is_undefined() || trap.is_null())
|
if (trap.is_empty() || trap.is_undefined() || trap.is_null())
|
||||||
return m_target.put(name, value);
|
return m_target.put(name, value);
|
||||||
if (!trap.is_function()) {
|
if (!trap.is_function()) {
|
||||||
interpreter().throw_exception<TypeError>(ErrorType::ProxyInvalidTrap, "set");
|
interpreter().vm().throw_exception<TypeError>(global_object(), ErrorType::ProxyInvalidTrap, "set");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
auto trap_result = interpreter().call(trap.as_function(), Value(&m_handler), Value(&m_target), js_string(interpreter(), name.to_string()), value, Value(const_cast<ProxyObject*>(this))).to_boolean();
|
auto trap_result = interpreter().call(trap.as_function(), Value(&m_handler), Value(&m_target), js_string(interpreter(), name.to_string()), value, Value(const_cast<ProxyObject*>(this))).to_boolean();
|
||||||
|
@ -410,11 +410,11 @@ bool ProxyObject::put(const PropertyName& name, Value value, Value)
|
||||||
return false;
|
return false;
|
||||||
if (target_desc.has_value() && !target_desc.value().attributes.is_configurable()) {
|
if (target_desc.has_value() && !target_desc.value().attributes.is_configurable()) {
|
||||||
if (target_desc.value().is_data_descriptor() && !target_desc.value().attributes.is_writable() && !same_value(interpreter(), value, target_desc.value().value)) {
|
if (target_desc.value().is_data_descriptor() && !target_desc.value().attributes.is_writable() && !same_value(interpreter(), value, target_desc.value().value)) {
|
||||||
interpreter().throw_exception<TypeError>(ErrorType::ProxySetImmutableDataProperty);
|
interpreter().vm().throw_exception<TypeError>(global_object(), ErrorType::ProxySetImmutableDataProperty);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (target_desc.value().is_accessor_descriptor() && !target_desc.value().setter) {
|
if (target_desc.value().is_accessor_descriptor() && !target_desc.value().setter) {
|
||||||
interpreter().throw_exception<TypeError>(ErrorType::ProxySetNonConfigurableAccessor);
|
interpreter().vm().throw_exception<TypeError>(global_object(), ErrorType::ProxySetNonConfigurableAccessor);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
|
@ -423,7 +423,7 @@ bool ProxyObject::put(const PropertyName& name, Value value, Value)
|
||||||
Value ProxyObject::delete_property(const PropertyName& name)
|
Value ProxyObject::delete_property(const PropertyName& name)
|
||||||
{
|
{
|
||||||
if (m_is_revoked) {
|
if (m_is_revoked) {
|
||||||
interpreter().throw_exception<TypeError>(ErrorType::ProxyRevoked);
|
interpreter().vm().throw_exception<TypeError>(global_object(), ErrorType::ProxyRevoked);
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
auto trap = m_handler.get("deleteProperty");
|
auto trap = m_handler.get("deleteProperty");
|
||||||
|
@ -432,7 +432,7 @@ Value ProxyObject::delete_property(const PropertyName& name)
|
||||||
if (trap.is_empty() || trap.is_undefined() || trap.is_null())
|
if (trap.is_empty() || trap.is_undefined() || trap.is_null())
|
||||||
return m_target.delete_property(name);
|
return m_target.delete_property(name);
|
||||||
if (!trap.is_function()) {
|
if (!trap.is_function()) {
|
||||||
interpreter().throw_exception<TypeError>(ErrorType::ProxyInvalidTrap, "deleteProperty");
|
interpreter().vm().throw_exception<TypeError>(global_object(), ErrorType::ProxyInvalidTrap, "deleteProperty");
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -447,7 +447,7 @@ Value ProxyObject::delete_property(const PropertyName& name)
|
||||||
if (!target_desc.has_value())
|
if (!target_desc.has_value())
|
||||||
return Value(true);
|
return Value(true);
|
||||||
if (!target_desc.value().attributes.is_configurable()) {
|
if (!target_desc.value().attributes.is_configurable()) {
|
||||||
interpreter().throw_exception<TypeError>(ErrorType::ProxyDeleteNonConfigurable);
|
interpreter().vm().throw_exception<TypeError>(global_object(), ErrorType::ProxyDeleteNonConfigurable);
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
return Value(true);
|
return Value(true);
|
||||||
|
@ -463,11 +463,11 @@ void ProxyObject::visit_children(Cell::Visitor& visitor)
|
||||||
Value ProxyObject::call(Interpreter& interpreter)
|
Value ProxyObject::call(Interpreter& interpreter)
|
||||||
{
|
{
|
||||||
if (!is_function()) {
|
if (!is_function()) {
|
||||||
interpreter.throw_exception<TypeError>(ErrorType::NotAFunction, Value(this).to_string_without_side_effects().characters());
|
interpreter.vm().throw_exception<TypeError>(global_object(), ErrorType::NotAFunction, Value(this).to_string_without_side_effects().characters());
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
if (m_is_revoked) {
|
if (m_is_revoked) {
|
||||||
interpreter.throw_exception<TypeError>(ErrorType::ProxyRevoked);
|
interpreter.vm().throw_exception<TypeError>(global_object(), ErrorType::ProxyRevoked);
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
auto trap = m_handler.get("apply");
|
auto trap = m_handler.get("apply");
|
||||||
|
@ -476,7 +476,7 @@ Value ProxyObject::call(Interpreter& interpreter)
|
||||||
if (trap.is_empty() || trap.is_undefined() || trap.is_null())
|
if (trap.is_empty() || trap.is_undefined() || trap.is_null())
|
||||||
return static_cast<Function&>(m_target).call(interpreter);
|
return static_cast<Function&>(m_target).call(interpreter);
|
||||||
if (!trap.is_function()) {
|
if (!trap.is_function()) {
|
||||||
interpreter.throw_exception<TypeError>(ErrorType::ProxyInvalidTrap, "apply");
|
interpreter.vm().throw_exception<TypeError>(global_object(), ErrorType::ProxyInvalidTrap, "apply");
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
MarkedValueList arguments(interpreter.heap());
|
MarkedValueList arguments(interpreter.heap());
|
||||||
|
@ -484,7 +484,7 @@ Value ProxyObject::call(Interpreter& interpreter)
|
||||||
arguments.append(Value(&m_handler));
|
arguments.append(Value(&m_handler));
|
||||||
// FIXME: Pass global object
|
// FIXME: Pass global object
|
||||||
auto arguments_array = Array::create(interpreter.global_object());
|
auto arguments_array = Array::create(interpreter.global_object());
|
||||||
interpreter.for_each_argument([&](auto& argument) {
|
interpreter.vm().for_each_argument([&](auto& argument) {
|
||||||
arguments_array->indexed_properties().append(argument);
|
arguments_array->indexed_properties().append(argument);
|
||||||
});
|
});
|
||||||
arguments.append(arguments_array);
|
arguments.append(arguments_array);
|
||||||
|
@ -495,11 +495,11 @@ Value ProxyObject::call(Interpreter& interpreter)
|
||||||
Value ProxyObject::construct(Interpreter& interpreter, Function& new_target)
|
Value ProxyObject::construct(Interpreter& interpreter, Function& new_target)
|
||||||
{
|
{
|
||||||
if (!is_function()) {
|
if (!is_function()) {
|
||||||
interpreter.throw_exception<TypeError>(ErrorType::NotAConstructor, Value(this).to_string_without_side_effects().characters());
|
interpreter.vm().throw_exception<TypeError>(global_object(), ErrorType::NotAConstructor, Value(this).to_string_without_side_effects().characters());
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
if (m_is_revoked) {
|
if (m_is_revoked) {
|
||||||
interpreter.throw_exception<TypeError>(ErrorType::ProxyRevoked);
|
interpreter.vm().throw_exception<TypeError>(global_object(), ErrorType::ProxyRevoked);
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
auto trap = m_handler.get("construct");
|
auto trap = m_handler.get("construct");
|
||||||
|
@ -508,21 +508,21 @@ Value ProxyObject::construct(Interpreter& interpreter, Function& new_target)
|
||||||
if (trap.is_empty() || trap.is_undefined() || trap.is_null())
|
if (trap.is_empty() || trap.is_undefined() || trap.is_null())
|
||||||
return static_cast<Function&>(m_target).construct(interpreter, new_target);
|
return static_cast<Function&>(m_target).construct(interpreter, new_target);
|
||||||
if (!trap.is_function()) {
|
if (!trap.is_function()) {
|
||||||
interpreter.throw_exception<TypeError>(ErrorType::ProxyInvalidTrap, "construct");
|
interpreter.vm().throw_exception<TypeError>(global_object(), ErrorType::ProxyInvalidTrap, "construct");
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
MarkedValueList arguments(interpreter.heap());
|
MarkedValueList arguments(interpreter.heap());
|
||||||
arguments.append(Value(&m_target));
|
arguments.append(Value(&m_target));
|
||||||
auto arguments_array = Array::create(interpreter.global_object());
|
auto arguments_array = Array::create(interpreter.global_object());
|
||||||
interpreter.for_each_argument([&](auto& argument) {
|
interpreter.vm().for_each_argument([&](auto& argument) {
|
||||||
arguments_array->indexed_properties().append(argument);
|
arguments_array->indexed_properties().append(argument);
|
||||||
});
|
});
|
||||||
arguments.append(arguments_array);
|
arguments.append(arguments_array);
|
||||||
arguments.append(Value(&new_target));
|
arguments.append(Value(&new_target));
|
||||||
auto result = interpreter.call(trap.as_function(), Value(&m_handler), move(arguments));
|
auto result = interpreter.call(trap.as_function(), Value(&m_handler), move(arguments));
|
||||||
if (!result.is_object()) {
|
if (!result.is_object()) {
|
||||||
interpreter.throw_exception<TypeError>(ErrorType::ProxyConstructBadReturnType);
|
interpreter.vm().throw_exception<TypeError>(global_object(), ErrorType::ProxyConstructBadReturnType);
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
|
|
|
@ -44,14 +44,14 @@ void Reference::put(Interpreter& interpreter, GlobalObject& global_object, Value
|
||||||
|
|
||||||
if (is_local_variable() || is_global_variable()) {
|
if (is_local_variable() || is_global_variable()) {
|
||||||
if (is_local_variable())
|
if (is_local_variable())
|
||||||
interpreter.set_variable(m_name.to_string(), value, global_object);
|
interpreter.vm().set_variable(m_name.to_string(), value, global_object);
|
||||||
else
|
else
|
||||||
global_object.put(m_name, value);
|
global_object.put(m_name, value);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!base().is_object() && interpreter.in_strict_mode()) {
|
if (!base().is_object() && interpreter.in_strict_mode()) {
|
||||||
interpreter.throw_exception<TypeError>(ErrorType::ReferencePrimitiveAssignment, m_name.to_string().characters());
|
interpreter.vm().throw_exception<TypeError>(global_object, ErrorType::ReferencePrimitiveAssignment, m_name.to_string().characters());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -62,14 +62,14 @@ void Reference::put(Interpreter& interpreter, GlobalObject& global_object, Value
|
||||||
object->put(m_name, value);
|
object->put(m_name, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Reference::throw_reference_error(Interpreter& interpreter, GlobalObject&)
|
void Reference::throw_reference_error(Interpreter& interpreter, GlobalObject& global_object)
|
||||||
{
|
{
|
||||||
auto property_name = m_name.to_string();
|
auto property_name = m_name.to_string();
|
||||||
String message;
|
String message;
|
||||||
if (property_name.is_empty()) {
|
if (property_name.is_empty()) {
|
||||||
interpreter.throw_exception<ReferenceError>(ErrorType::ReferenceUnresolvable);
|
interpreter.vm().throw_exception<ReferenceError>(global_object, ErrorType::ReferenceUnresolvable);
|
||||||
} else {
|
} else {
|
||||||
interpreter.throw_exception<ReferenceError>(ErrorType::UnknownIdentifier, property_name.characters());
|
interpreter.vm().throw_exception<ReferenceError>(global_object, ErrorType::UnknownIdentifier, property_name.characters());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -85,7 +85,7 @@ Value Reference::get(Interpreter& interpreter, GlobalObject& global_object)
|
||||||
if (is_local_variable() || is_global_variable()) {
|
if (is_local_variable() || is_global_variable()) {
|
||||||
Value value;
|
Value value;
|
||||||
if (is_local_variable())
|
if (is_local_variable())
|
||||||
value = interpreter.get_variable(m_name.to_string(), global_object);
|
value = interpreter.vm().get_variable(m_name.to_string(), global_object);
|
||||||
else
|
else
|
||||||
value = global_object.get(m_name);
|
value = global_object.get(m_name);
|
||||||
if (interpreter.exception())
|
if (interpreter.exception())
|
||||||
|
|
|
@ -38,7 +38,7 @@ static Object* get_target_object_from(Interpreter& interpreter, const String& na
|
||||||
{
|
{
|
||||||
auto target = interpreter.argument(0);
|
auto target = interpreter.argument(0);
|
||||||
if (!target.is_object()) {
|
if (!target.is_object()) {
|
||||||
interpreter.throw_exception<TypeError>(ErrorType::ReflectArgumentMustBeAnObject, name.characters());
|
interpreter.vm().throw_exception<TypeError>(interpreter.global_object(), ErrorType::ReflectArgumentMustBeAnObject, name.characters());
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
return static_cast<Object*>(&target.as_object());
|
return static_cast<Object*>(&target.as_object());
|
||||||
|
@ -48,7 +48,7 @@ static Function* get_target_function_from(Interpreter& interpreter, const String
|
||||||
{
|
{
|
||||||
auto target = interpreter.argument(0);
|
auto target = interpreter.argument(0);
|
||||||
if (!target.is_function()) {
|
if (!target.is_function()) {
|
||||||
interpreter.throw_exception<TypeError>(ErrorType::ReflectArgumentMustBeAFunction, name.characters());
|
interpreter.vm().throw_exception<TypeError>(interpreter.global_object(), ErrorType::ReflectArgumentMustBeAFunction, name.characters());
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
return &target.as_function();
|
return &target.as_function();
|
||||||
|
@ -57,7 +57,7 @@ static Function* get_target_function_from(Interpreter& interpreter, const String
|
||||||
static void prepare_arguments_list(Interpreter& interpreter, Value value, MarkedValueList* arguments)
|
static void prepare_arguments_list(Interpreter& interpreter, Value value, MarkedValueList* arguments)
|
||||||
{
|
{
|
||||||
if (!value.is_object()) {
|
if (!value.is_object()) {
|
||||||
interpreter.throw_exception<TypeError>(ErrorType::ReflectBadArgumentsList);
|
interpreter.vm().throw_exception<TypeError>(interpreter.global_object(), ErrorType::ReflectBadArgumentsList);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
auto& arguments_list = value.as_object();
|
auto& arguments_list = value.as_object();
|
||||||
|
@ -130,12 +130,12 @@ JS_DEFINE_NATIVE_FUNCTION(ReflectObject::construct)
|
||||||
auto new_target_value = interpreter.argument(2);
|
auto new_target_value = interpreter.argument(2);
|
||||||
if (!new_target_value.is_function()
|
if (!new_target_value.is_function()
|
||||||
|| (new_target_value.as_object().is_native_function() && !static_cast<NativeFunction&>(new_target_value.as_object()).has_constructor())) {
|
|| (new_target_value.as_object().is_native_function() && !static_cast<NativeFunction&>(new_target_value.as_object()).has_constructor())) {
|
||||||
interpreter.throw_exception<TypeError>(ErrorType::ReflectBadNewTarget);
|
interpreter.vm().throw_exception<TypeError>(global_object, ErrorType::ReflectBadNewTarget);
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
new_target = &new_target_value.as_function();
|
new_target = &new_target_value.as_function();
|
||||||
}
|
}
|
||||||
return interpreter.construct(*target, *new_target, move(arguments), global_object);
|
return interpreter.vm().construct(*target, *new_target, move(arguments), global_object);
|
||||||
}
|
}
|
||||||
|
|
||||||
JS_DEFINE_NATIVE_FUNCTION(ReflectObject::define_property)
|
JS_DEFINE_NATIVE_FUNCTION(ReflectObject::define_property)
|
||||||
|
@ -144,7 +144,7 @@ JS_DEFINE_NATIVE_FUNCTION(ReflectObject::define_property)
|
||||||
if (!target)
|
if (!target)
|
||||||
return {};
|
return {};
|
||||||
if (!interpreter.argument(2).is_object()) {
|
if (!interpreter.argument(2).is_object()) {
|
||||||
interpreter.throw_exception<TypeError>(ErrorType::ReflectBadDescriptorArgument);
|
interpreter.vm().throw_exception<TypeError>(global_object, ErrorType::ReflectBadDescriptorArgument);
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
auto property_key = StringOrSymbol::from_value(interpreter, interpreter.argument(1));
|
auto property_key = StringOrSymbol::from_value(interpreter, interpreter.argument(1));
|
||||||
|
@ -268,7 +268,7 @@ JS_DEFINE_NATIVE_FUNCTION(ReflectObject::set_prototype_of)
|
||||||
return {};
|
return {};
|
||||||
auto prototype_value = interpreter.argument(1);
|
auto prototype_value = interpreter.argument(1);
|
||||||
if (!prototype_value.is_object() && !prototype_value.is_null()) {
|
if (!prototype_value.is_object() && !prototype_value.is_null()) {
|
||||||
interpreter.throw_exception<TypeError>(ErrorType::ObjectPrototypeWrongType);
|
interpreter.vm().throw_exception<TypeError>(global_object, ErrorType::ObjectPrototypeWrongType);
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
Object* prototype = nullptr;
|
Object* prototype = nullptr;
|
||||||
|
|
|
@ -41,7 +41,7 @@ static ScriptFunction* typed_this(Interpreter& interpreter, GlobalObject& global
|
||||||
if (!this_object)
|
if (!this_object)
|
||||||
return nullptr;
|
return nullptr;
|
||||||
if (!this_object->is_function()) {
|
if (!this_object->is_function()) {
|
||||||
interpreter.throw_exception<TypeError>(ErrorType::NotAFunctionNoParam);
|
interpreter.vm().throw_exception<TypeError>(global_object, ErrorType::NotAFunctionNoParam);
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
return static_cast<ScriptFunction*>(this_object);
|
return static_cast<ScriptFunction*>(this_object);
|
||||||
|
@ -130,13 +130,13 @@ Value ScriptFunction::call(Interpreter& interpreter)
|
||||||
arguments.append({ parameter.name, value });
|
arguments.append({ parameter.name, value });
|
||||||
interpreter.current_environment()->set(parameter.name, { value, DeclarationKind::Var });
|
interpreter.current_environment()->set(parameter.name, { value, DeclarationKind::Var });
|
||||||
}
|
}
|
||||||
return interpreter.execute_statement(global_object(), m_body, arguments, ScopeType::Function);
|
return interpreter.vm().execute_statement(global_object(), m_body, arguments, ScopeType::Function);
|
||||||
}
|
}
|
||||||
|
|
||||||
Value ScriptFunction::construct(Interpreter& interpreter, Function&)
|
Value ScriptFunction::construct(Interpreter& interpreter, Function&)
|
||||||
{
|
{
|
||||||
if (m_is_arrow_function) {
|
if (m_is_arrow_function) {
|
||||||
interpreter.throw_exception<TypeError>(ErrorType::NotAConstructor, m_name.characters());
|
interpreter.vm().throw_exception<TypeError>(global_object(), ErrorType::NotAConstructor, m_name.characters());
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
return call(interpreter);
|
return call(interpreter);
|
||||||
|
|
|
@ -89,7 +89,7 @@ JS_DEFINE_NATIVE_FUNCTION(StringConstructor::raw)
|
||||||
if (interpreter.exception())
|
if (interpreter.exception())
|
||||||
return {};
|
return {};
|
||||||
if (raw.is_empty() || raw.is_undefined() || raw.is_null()) {
|
if (raw.is_empty() || raw.is_undefined() || raw.is_null()) {
|
||||||
interpreter.throw_exception<TypeError>(ErrorType::StringRawCannotConvert, raw.is_null() ? "null" : "undefined");
|
interpreter.vm().throw_exception<TypeError>(global_object, ErrorType::StringRawCannotConvert, raw.is_null() ? "null" : "undefined");
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
if (!raw.is_array())
|
if (!raw.is_array())
|
||||||
|
|
|
@ -54,7 +54,7 @@ JS_DEFINE_NATIVE_FUNCTION(StringIteratorPrototype::next)
|
||||||
{
|
{
|
||||||
auto this_value = interpreter.this_value(global_object);
|
auto this_value = interpreter.this_value(global_object);
|
||||||
if (!this_value.is_object() || !this_value.as_object().is_string_iterator_object()) {
|
if (!this_value.is_object() || !this_value.as_object().is_string_iterator_object()) {
|
||||||
interpreter.throw_exception<TypeError>(ErrorType::NotA, "String Iterator");
|
interpreter.vm().throw_exception<TypeError>(global_object, ErrorType::NotA, "String Iterator");
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -46,7 +46,7 @@ static StringObject* typed_this(Interpreter& interpreter, GlobalObject& global_o
|
||||||
if (!this_object)
|
if (!this_object)
|
||||||
return nullptr;
|
return nullptr;
|
||||||
if (!this_object->is_string_object()) {
|
if (!this_object->is_string_object()) {
|
||||||
interpreter.throw_exception<TypeError>(ErrorType::NotA, "String");
|
interpreter.vm().throw_exception<TypeError>(global_object, ErrorType::NotA, "String");
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
return static_cast<StringObject*>(this_object);
|
return static_cast<StringObject*>(this_object);
|
||||||
|
@ -141,11 +141,11 @@ JS_DEFINE_NATIVE_FUNCTION(StringPrototype::repeat)
|
||||||
if (interpreter.exception())
|
if (interpreter.exception())
|
||||||
return {};
|
return {};
|
||||||
if (count_value.as_double() < 0) {
|
if (count_value.as_double() < 0) {
|
||||||
interpreter.throw_exception<RangeError>(ErrorType::StringRepeatCountMustBe, "positive");
|
interpreter.vm().throw_exception<RangeError>(global_object, ErrorType::StringRepeatCountMustBe, "positive");
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
if (count_value.is_infinity()) {
|
if (count_value.is_infinity()) {
|
||||||
interpreter.throw_exception<RangeError>(ErrorType::StringRepeatCountMustBe, "finite");
|
interpreter.vm().throw_exception<RangeError>(global_object, ErrorType::StringRepeatCountMustBe, "finite");
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
auto count = count_value.to_size_t(interpreter);
|
auto count = count_value.to_size_t(interpreter);
|
||||||
|
@ -460,7 +460,7 @@ JS_DEFINE_NATIVE_FUNCTION(StringPrototype::symbol_iterator)
|
||||||
{
|
{
|
||||||
auto this_object = interpreter.this_value(global_object);
|
auto this_object = interpreter.this_value(global_object);
|
||||||
if (this_object.is_undefined() || this_object.is_null()) {
|
if (this_object.is_undefined() || this_object.is_null()) {
|
||||||
interpreter.throw_exception<TypeError>(ErrorType::ToObjectNullOrUndef);
|
interpreter.vm().throw_exception<TypeError>(global_object, ErrorType::ToObjectNullOrUndef);
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -65,7 +65,7 @@ Value SymbolConstructor::call(Interpreter& interpreter)
|
||||||
|
|
||||||
Value SymbolConstructor::construct(Interpreter& interpreter, Function&)
|
Value SymbolConstructor::construct(Interpreter& interpreter, Function&)
|
||||||
{
|
{
|
||||||
interpreter.throw_exception<TypeError>(ErrorType::NotAConstructor, "Symbol");
|
interpreter.vm().throw_exception<TypeError>(global_object(), ErrorType::NotAConstructor, "Symbol");
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -85,7 +85,7 @@ JS_DEFINE_NATIVE_FUNCTION(SymbolConstructor::key_for)
|
||||||
{
|
{
|
||||||
auto argument = interpreter.argument(0);
|
auto argument = interpreter.argument(0);
|
||||||
if (!argument.is_symbol()) {
|
if (!argument.is_symbol()) {
|
||||||
interpreter.throw_exception<TypeError>(ErrorType::NotASymbol, argument.to_string_without_side_effects().characters());
|
interpreter.vm().throw_exception<TypeError>(global_object, ErrorType::NotASymbol, argument.to_string_without_side_effects().characters());
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -64,7 +64,7 @@ static SymbolObject* typed_this(Interpreter& interpreter, GlobalObject& global_o
|
||||||
if (!this_object)
|
if (!this_object)
|
||||||
return nullptr;
|
return nullptr;
|
||||||
if (!this_object->is_symbol_object()) {
|
if (!this_object->is_symbol_object()) {
|
||||||
interpreter.throw_exception<TypeError>(ErrorType::NotA, "Symbol");
|
interpreter.vm().throw_exception<TypeError>(global_object, ErrorType::NotA, "Symbol");
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
return static_cast<SymbolObject*>(this_object);
|
return static_cast<SymbolObject*>(this_object);
|
||||||
|
|
|
@ -59,7 +59,7 @@ JS_DEFINE_NATIVE_GETTER(Uint8ClampedArray::length_getter)
|
||||||
if (!this_object)
|
if (!this_object)
|
||||||
return {};
|
return {};
|
||||||
if (StringView(this_object->class_name()) != "Uint8ClampedArray") {
|
if (StringView(this_object->class_name()) != "Uint8ClampedArray") {
|
||||||
interpreter.throw_exception<TypeError>(ErrorType::NotA, "Uint8ClampedArray");
|
interpreter.vm().throw_exception<TypeError>(global_object, ErrorType::NotA, "Uint8ClampedArray");
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
return Value(static_cast<const Uint8ClampedArray*>(this_object)->length());
|
return Value(static_cast<const Uint8ClampedArray*>(this_object)->length());
|
||||||
|
|
|
@ -24,10 +24,18 @@
|
||||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <AK/StringBuilder.h>
|
||||||
|
#include <AK/ScopeGuard.h>
|
||||||
#include <LibJS/Interpreter.h>
|
#include <LibJS/Interpreter.h>
|
||||||
|
#include <LibJS/Runtime/Error.h>
|
||||||
|
#include <LibJS/Runtime/GlobalObject.h>
|
||||||
|
#include <LibJS/Runtime/Reference.h>
|
||||||
|
#include <LibJS/Runtime/ScriptFunction.h>
|
||||||
#include <LibJS/Runtime/Symbol.h>
|
#include <LibJS/Runtime/Symbol.h>
|
||||||
#include <LibJS/Runtime/VM.h>
|
#include <LibJS/Runtime/VM.h>
|
||||||
|
|
||||||
|
//#define VM_DEBUG
|
||||||
|
|
||||||
namespace JS {
|
namespace JS {
|
||||||
|
|
||||||
NonnullRefPtr<VM> VM::create()
|
NonnullRefPtr<VM> VM::create()
|
||||||
|
@ -90,8 +98,19 @@ void VM::gather_roots(HashTable<Cell*>& roots)
|
||||||
roots.set(m_empty_string);
|
roots.set(m_empty_string);
|
||||||
if (m_exception)
|
if (m_exception)
|
||||||
roots.set(m_exception);
|
roots.set(m_exception);
|
||||||
for (auto* interpreter : m_interpreters)
|
|
||||||
interpreter->gather_roots(roots);
|
if (m_last_value.is_cell())
|
||||||
|
roots.set(m_last_value.as_cell());
|
||||||
|
|
||||||
|
for (auto& call_frame : m_call_stack) {
|
||||||
|
if (call_frame.this_value.is_cell())
|
||||||
|
roots.set(call_frame.this_value.as_cell());
|
||||||
|
for (auto& argument : call_frame.arguments) {
|
||||||
|
if (argument.is_cell())
|
||||||
|
roots.set(argument.as_cell());
|
||||||
|
}
|
||||||
|
roots.set(call_frame.environment);
|
||||||
|
}
|
||||||
|
|
||||||
#define __JS_ENUMERATE(SymbolName, snake_name) \
|
#define __JS_ENUMERATE(SymbolName, snake_name) \
|
||||||
roots.set(well_known_symbol_##snake_name());
|
roots.set(well_known_symbol_##snake_name());
|
||||||
|
@ -113,4 +132,266 @@ Symbol* VM::get_global_symbol(const String& description)
|
||||||
return new_global_symbol;
|
return new_global_symbol;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool VM::in_strict_mode() const
|
||||||
|
{
|
||||||
|
if (m_scope_stack.is_empty())
|
||||||
|
return true;
|
||||||
|
return m_scope_stack.last().scope_node->in_strict_mode();
|
||||||
|
}
|
||||||
|
|
||||||
|
void VM::enter_scope(const ScopeNode& scope_node, ArgumentVector arguments, ScopeType scope_type, GlobalObject& global_object)
|
||||||
|
{
|
||||||
|
for (auto& declaration : scope_node.functions()) {
|
||||||
|
auto* function = ScriptFunction::create(global_object, declaration.name(), declaration.body(), declaration.parameters(), declaration.function_length(), current_environment());
|
||||||
|
set_variable(declaration.name(), function, global_object);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (scope_type == ScopeType::Function) {
|
||||||
|
m_scope_stack.append({ scope_type, scope_node, false });
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
HashMap<FlyString, Variable> scope_variables_with_declaration_kind;
|
||||||
|
scope_variables_with_declaration_kind.ensure_capacity(16);
|
||||||
|
|
||||||
|
for (auto& declaration : scope_node.variables()) {
|
||||||
|
for (auto& declarator : declaration.declarations()) {
|
||||||
|
if (scope_node.is_program()) {
|
||||||
|
global_object.put(declarator.id().string(), js_undefined());
|
||||||
|
if (exception())
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
scope_variables_with_declaration_kind.set(declarator.id().string(), { js_undefined(), declaration.declaration_kind() });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto& argument : arguments) {
|
||||||
|
scope_variables_with_declaration_kind.set(argument.name, { argument.value, DeclarationKind::Var });
|
||||||
|
}
|
||||||
|
|
||||||
|
bool pushed_lexical_environment = false;
|
||||||
|
|
||||||
|
if (!scope_variables_with_declaration_kind.is_empty()) {
|
||||||
|
auto* block_lexical_environment = heap().allocate<LexicalEnvironment>(global_object, move(scope_variables_with_declaration_kind), current_environment());
|
||||||
|
m_call_stack.last().environment = block_lexical_environment;
|
||||||
|
pushed_lexical_environment = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_scope_stack.append({ scope_type, scope_node, pushed_lexical_environment });
|
||||||
|
}
|
||||||
|
|
||||||
|
void VM::exit_scope(const ScopeNode& scope_node)
|
||||||
|
{
|
||||||
|
while (!m_scope_stack.is_empty()) {
|
||||||
|
auto popped_scope = m_scope_stack.take_last();
|
||||||
|
if (popped_scope.pushed_environment)
|
||||||
|
m_call_stack.last().environment = m_call_stack.last().environment->parent();
|
||||||
|
if (popped_scope.scope_node.ptr() == &scope_node)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we unwind all the way, just reset m_unwind_until so that future "return" doesn't break.
|
||||||
|
if (m_scope_stack.is_empty())
|
||||||
|
m_unwind_until = ScopeType::None;
|
||||||
|
}
|
||||||
|
|
||||||
|
void VM::set_variable(const FlyString& name, Value value, GlobalObject& global_object, bool first_assignment)
|
||||||
|
{
|
||||||
|
if (m_call_stack.size()) {
|
||||||
|
for (auto* environment = current_environment(); environment; environment = environment->parent()) {
|
||||||
|
if (environment->type() == LexicalEnvironment::EnvironmentRecordType::Global)
|
||||||
|
break;
|
||||||
|
auto possible_match = environment->get(name);
|
||||||
|
if (possible_match.has_value()) {
|
||||||
|
if (!first_assignment && possible_match.value().declaration_kind == DeclarationKind::Const) {
|
||||||
|
throw_exception<TypeError>(global_object, ErrorType::InvalidAssignToConst);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
environment->set(name, { value, possible_match.value().declaration_kind });
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
global_object.put(move(name), move(value));
|
||||||
|
}
|
||||||
|
|
||||||
|
Value VM::get_variable(const FlyString& name, GlobalObject& global_object)
|
||||||
|
{
|
||||||
|
if (m_call_stack.size()) {
|
||||||
|
for (auto* environment = current_environment(); environment; environment = environment->parent()) {
|
||||||
|
if (environment->type() == LexicalEnvironment::EnvironmentRecordType::Global)
|
||||||
|
break;
|
||||||
|
auto possible_match = environment->get(name);
|
||||||
|
if (possible_match.has_value())
|
||||||
|
return possible_match.value().value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
auto value = global_object.get(name);
|
||||||
|
if (m_underscore_is_last_value && name == "_" && value.is_empty())
|
||||||
|
return m_last_value;
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
Reference VM::get_reference(const FlyString& name)
|
||||||
|
{
|
||||||
|
if (m_call_stack.size()) {
|
||||||
|
for (auto* environment = current_environment(); environment; environment = environment->parent()) {
|
||||||
|
if (environment->type() == LexicalEnvironment::EnvironmentRecordType::Global)
|
||||||
|
break;
|
||||||
|
auto possible_match = environment->get(name);
|
||||||
|
if (possible_match.has_value())
|
||||||
|
return { Reference::LocalVariable, name };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return { Reference::GlobalVariable, name };
|
||||||
|
}
|
||||||
|
|
||||||
|
Value VM::execute_statement(GlobalObject& global_object, const Statement& statement, ArgumentVector arguments, ScopeType scope_type)
|
||||||
|
{
|
||||||
|
if (!statement.is_scope_node())
|
||||||
|
return statement.execute(interpreter(), global_object);
|
||||||
|
|
||||||
|
auto& block = static_cast<const ScopeNode&>(statement);
|
||||||
|
enter_scope(block, move(arguments), scope_type, global_object);
|
||||||
|
|
||||||
|
if (block.children().is_empty())
|
||||||
|
m_last_value = js_undefined();
|
||||||
|
|
||||||
|
for (auto& node : block.children()) {
|
||||||
|
m_last_value = node.execute(interpreter(), global_object);
|
||||||
|
if (should_unwind()) {
|
||||||
|
if (!block.label().is_null() && should_unwind_until(ScopeType::Breakable, block.label()))
|
||||||
|
stop_unwind();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool did_return = m_unwind_until == ScopeType::Function;
|
||||||
|
|
||||||
|
if (m_unwind_until == scope_type)
|
||||||
|
m_unwind_until = ScopeType::None;
|
||||||
|
|
||||||
|
exit_scope(block);
|
||||||
|
|
||||||
|
return did_return ? m_last_value : js_undefined();
|
||||||
|
}
|
||||||
|
|
||||||
|
Value VM::construct(Function& function, Function& new_target, Optional<MarkedValueList> arguments, GlobalObject& global_object)
|
||||||
|
{
|
||||||
|
auto& call_frame = push_call_frame();
|
||||||
|
|
||||||
|
ArmedScopeGuard call_frame_popper = [&] {
|
||||||
|
pop_call_frame();
|
||||||
|
};
|
||||||
|
|
||||||
|
call_frame.function_name = function.name();
|
||||||
|
call_frame.arguments = function.bound_arguments();
|
||||||
|
if (arguments.has_value())
|
||||||
|
call_frame.arguments.append(arguments.value().values());
|
||||||
|
call_frame.environment = function.create_environment();
|
||||||
|
|
||||||
|
current_environment()->set_new_target(&new_target);
|
||||||
|
|
||||||
|
Object* new_object = nullptr;
|
||||||
|
if (function.constructor_kind() == Function::ConstructorKind::Base) {
|
||||||
|
new_object = Object::create_empty(global_object);
|
||||||
|
current_environment()->bind_this_value(new_object);
|
||||||
|
if (exception())
|
||||||
|
return {};
|
||||||
|
auto prototype = new_target.get("prototype");
|
||||||
|
if (exception())
|
||||||
|
return {};
|
||||||
|
if (prototype.is_object()) {
|
||||||
|
new_object->set_prototype(&prototype.as_object());
|
||||||
|
if (exception())
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we are a Derived constructor, |this| has not been constructed before super is called.
|
||||||
|
Value this_value = function.constructor_kind() == Function::ConstructorKind::Base ? new_object : Value {};
|
||||||
|
call_frame.this_value = this_value;
|
||||||
|
auto result = function.construct(interpreter(), new_target);
|
||||||
|
|
||||||
|
this_value = current_environment()->get_this_binding();
|
||||||
|
pop_call_frame();
|
||||||
|
call_frame_popper.disarm();
|
||||||
|
|
||||||
|
// If we are constructing an instance of a derived class,
|
||||||
|
// set the prototype on objects created by constructors that return an object (i.e. NativeFunction subclasses).
|
||||||
|
if (function.constructor_kind() == Function::ConstructorKind::Base && new_target.constructor_kind() == Function::ConstructorKind::Derived && result.is_object()) {
|
||||||
|
current_environment()->replace_this_binding(result);
|
||||||
|
auto prototype = new_target.get("prototype");
|
||||||
|
if (exception())
|
||||||
|
return {};
|
||||||
|
if (prototype.is_object()) {
|
||||||
|
result.as_object().set_prototype(&prototype.as_object());
|
||||||
|
if (exception())
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (exception())
|
||||||
|
return {};
|
||||||
|
|
||||||
|
if (result.is_object())
|
||||||
|
return result;
|
||||||
|
|
||||||
|
return this_value;
|
||||||
|
}
|
||||||
|
|
||||||
|
void VM::throw_exception(Exception* exception)
|
||||||
|
{
|
||||||
|
#ifdef VM_DEBUG
|
||||||
|
if (exception->value().is_object() && exception->value().as_object().is_error()) {
|
||||||
|
auto& error = static_cast<Error&>(exception->value().as_object());
|
||||||
|
dbg() << "Throwing JavaScript Error: " << error.name() << ", " << error.message();
|
||||||
|
|
||||||
|
for (ssize_t i = m_call_stack.size() - 1; i >= 0; --i) {
|
||||||
|
auto function_name = m_call_stack[i].function_name;
|
||||||
|
if (function_name.is_empty())
|
||||||
|
function_name = "<anonymous>";
|
||||||
|
dbg() << " " << function_name;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
m_exception = exception;
|
||||||
|
unwind(ScopeType::Try);
|
||||||
|
}
|
||||||
|
|
||||||
|
String VM::join_arguments() const
|
||||||
|
{
|
||||||
|
StringBuilder joined_arguments;
|
||||||
|
for (size_t i = 0; i < argument_count(); ++i) {
|
||||||
|
joined_arguments.append(argument(i).to_string_without_side_effects().characters());
|
||||||
|
if (i != argument_count() - 1)
|
||||||
|
joined_arguments.append(' ');
|
||||||
|
}
|
||||||
|
return joined_arguments.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
Value VM::resolve_this_binding() const
|
||||||
|
{
|
||||||
|
return get_this_environment()->get_this_binding();
|
||||||
|
}
|
||||||
|
|
||||||
|
const LexicalEnvironment* VM::get_this_environment() const
|
||||||
|
{
|
||||||
|
// We will always return because the Global environment will always be reached, which has a |this| binding.
|
||||||
|
for (const LexicalEnvironment* environment = current_environment(); environment; environment = environment->parent()) {
|
||||||
|
if (environment->has_this_binding())
|
||||||
|
return environment;
|
||||||
|
}
|
||||||
|
ASSERT_NOT_REACHED();
|
||||||
|
}
|
||||||
|
|
||||||
|
Value VM::get_new_target() const
|
||||||
|
{
|
||||||
|
return get_this_environment()->new_target();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,12 +26,45 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <AK/FlyString.h>
|
||||||
#include <AK/HashMap.h>
|
#include <AK/HashMap.h>
|
||||||
#include <AK/RefCounted.h>
|
#include <AK/RefCounted.h>
|
||||||
#include <LibJS/Heap/Heap.h>
|
#include <LibJS/Heap/Heap.h>
|
||||||
|
#include <LibJS/Runtime/ErrorTypes.h>
|
||||||
|
#include <LibJS/Runtime/Exception.h>
|
||||||
|
#include <LibJS/Runtime/Value.h>
|
||||||
|
|
||||||
namespace JS {
|
namespace JS {
|
||||||
|
|
||||||
|
enum class ScopeType {
|
||||||
|
None,
|
||||||
|
Function,
|
||||||
|
Block,
|
||||||
|
Try,
|
||||||
|
Breakable,
|
||||||
|
Continuable,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ScopeFrame {
|
||||||
|
ScopeType type;
|
||||||
|
NonnullRefPtr<ScopeNode> scope_node;
|
||||||
|
bool pushed_environment { false };
|
||||||
|
};
|
||||||
|
|
||||||
|
struct CallFrame {
|
||||||
|
FlyString function_name;
|
||||||
|
Value this_value;
|
||||||
|
Vector<Value> arguments;
|
||||||
|
LexicalEnvironment* environment { nullptr };
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Argument {
|
||||||
|
FlyString name;
|
||||||
|
Value value;
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef Vector<Argument, 8> ArgumentVector;
|
||||||
|
|
||||||
class VM : public RefCounted<VM> {
|
class VM : public RefCounted<VM> {
|
||||||
public:
|
public:
|
||||||
static NonnullRefPtr<VM> create();
|
static NonnullRefPtr<VM> create();
|
||||||
|
@ -50,7 +83,7 @@ public:
|
||||||
{
|
{
|
||||||
return m_exception;
|
return m_exception;
|
||||||
}
|
}
|
||||||
void set_exception(Badge<Interpreter>, Exception* exception) { m_exception = exception; }
|
|
||||||
void clear_exception() { m_exception = nullptr; }
|
void clear_exception() { m_exception = nullptr; }
|
||||||
|
|
||||||
class InterpreterExecutionScope {
|
class InterpreterExecutionScope {
|
||||||
|
@ -73,6 +106,107 @@ public:
|
||||||
|
|
||||||
PrimitiveString& empty_string() { return *m_empty_string; }
|
PrimitiveString& empty_string() { return *m_empty_string; }
|
||||||
|
|
||||||
|
CallFrame& push_call_frame()
|
||||||
|
{
|
||||||
|
m_call_stack.append({ {}, js_undefined(), {}, nullptr });
|
||||||
|
return m_call_stack.last();
|
||||||
|
}
|
||||||
|
void pop_call_frame() { m_call_stack.take_last(); }
|
||||||
|
const CallFrame& call_frame() { return m_call_stack.last(); }
|
||||||
|
const Vector<CallFrame>& call_stack() const { return m_call_stack; }
|
||||||
|
Vector<CallFrame>& call_stack() { return m_call_stack; }
|
||||||
|
|
||||||
|
const LexicalEnvironment* current_environment() const { return m_call_stack.last().environment; }
|
||||||
|
LexicalEnvironment* current_environment() { return m_call_stack.last().environment; }
|
||||||
|
|
||||||
|
bool in_strict_mode() const;
|
||||||
|
|
||||||
|
template<typename Callback>
|
||||||
|
void for_each_argument(Callback callback)
|
||||||
|
{
|
||||||
|
if (m_call_stack.is_empty())
|
||||||
|
return;
|
||||||
|
for (auto& value : m_call_stack.last().arguments)
|
||||||
|
callback(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t argument_count() const
|
||||||
|
{
|
||||||
|
if (m_call_stack.is_empty())
|
||||||
|
return 0;
|
||||||
|
return m_call_stack.last().arguments.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
Value argument(size_t index) const
|
||||||
|
{
|
||||||
|
if (m_call_stack.is_empty())
|
||||||
|
return {};
|
||||||
|
auto& arguments = m_call_stack.last().arguments;
|
||||||
|
return index < arguments.size() ? arguments[index] : js_undefined();
|
||||||
|
}
|
||||||
|
|
||||||
|
Value this_value(Object& global_object) const
|
||||||
|
{
|
||||||
|
if (m_call_stack.is_empty())
|
||||||
|
return &global_object;
|
||||||
|
return m_call_stack.last().this_value;
|
||||||
|
}
|
||||||
|
|
||||||
|
Value last_value() const { return m_last_value; }
|
||||||
|
|
||||||
|
bool underscore_is_last_value() const { return m_underscore_is_last_value; }
|
||||||
|
void set_underscore_is_last_value(bool b) { m_underscore_is_last_value = b; }
|
||||||
|
|
||||||
|
void unwind(ScopeType type, FlyString label = {})
|
||||||
|
{
|
||||||
|
m_unwind_until = type;
|
||||||
|
m_unwind_until_label = label;
|
||||||
|
}
|
||||||
|
void stop_unwind() { m_unwind_until = ScopeType::None; }
|
||||||
|
bool should_unwind_until(ScopeType type, FlyString label) const
|
||||||
|
{
|
||||||
|
if (m_unwind_until_label.is_null())
|
||||||
|
return m_unwind_until == type;
|
||||||
|
return m_unwind_until == type && m_unwind_until_label == label;
|
||||||
|
}
|
||||||
|
bool should_unwind() const { return m_unwind_until != ScopeType::None; }
|
||||||
|
|
||||||
|
Value get_variable(const FlyString& name, GlobalObject&);
|
||||||
|
void set_variable(const FlyString& name, Value, GlobalObject&, bool first_assignment = false);
|
||||||
|
|
||||||
|
Reference get_reference(const FlyString& name);
|
||||||
|
|
||||||
|
void enter_scope(const ScopeNode&, ArgumentVector, ScopeType, GlobalObject&);
|
||||||
|
void exit_scope(const ScopeNode&);
|
||||||
|
|
||||||
|
template<typename T, typename... Args>
|
||||||
|
void throw_exception(GlobalObject& global_object, Args&&... args)
|
||||||
|
{
|
||||||
|
return throw_exception(global_object, T::create(global_object, forward<Args>(args)...));
|
||||||
|
}
|
||||||
|
|
||||||
|
void throw_exception(Exception*);
|
||||||
|
void throw_exception(GlobalObject& global_object, Value value)
|
||||||
|
{
|
||||||
|
return throw_exception(heap().allocate<Exception>(global_object, value));
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T, typename... Args>
|
||||||
|
void throw_exception(GlobalObject& global_object, ErrorType type, Args&&... args)
|
||||||
|
{
|
||||||
|
return throw_exception(global_object, T::create(global_object, String::format(type.message(), forward<Args>(args)...)));
|
||||||
|
}
|
||||||
|
|
||||||
|
Value execute_statement(GlobalObject&, const Statement&, ArgumentVector = {}, ScopeType = ScopeType::Block);
|
||||||
|
|
||||||
|
Value construct(Function&, Function& new_target, Optional<MarkedValueList> arguments, GlobalObject&);
|
||||||
|
|
||||||
|
String join_arguments() const;
|
||||||
|
|
||||||
|
Value resolve_this_binding() const;
|
||||||
|
const LexicalEnvironment* get_this_environment() const;
|
||||||
|
Value get_new_target() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
VM();
|
VM();
|
||||||
|
|
||||||
|
@ -81,6 +215,15 @@ private:
|
||||||
Heap m_heap;
|
Heap m_heap;
|
||||||
Vector<Interpreter*> m_interpreters;
|
Vector<Interpreter*> m_interpreters;
|
||||||
|
|
||||||
|
Vector<ScopeFrame> m_scope_stack;
|
||||||
|
Vector<CallFrame> m_call_stack;
|
||||||
|
|
||||||
|
Value m_last_value;
|
||||||
|
ScopeType m_unwind_until { ScopeType::None };
|
||||||
|
FlyString m_unwind_until_label;
|
||||||
|
|
||||||
|
bool m_underscore_is_last_value { false };
|
||||||
|
|
||||||
HashMap<String, Symbol*> m_global_symbol_map;
|
HashMap<String, Symbol*> m_global_symbol_map;
|
||||||
|
|
||||||
PrimitiveString* m_empty_string { nullptr };
|
PrimitiveString* m_empty_string { nullptr };
|
||||||
|
|
|
@ -163,7 +163,7 @@ String Value::to_string(Interpreter& interpreter) const
|
||||||
case Type::String:
|
case Type::String:
|
||||||
return m_value.as_string->string();
|
return m_value.as_string->string();
|
||||||
case Type::Symbol:
|
case Type::Symbol:
|
||||||
interpreter.throw_exception<TypeError>(ErrorType::Convert, "symbol", "string");
|
interpreter.vm().throw_exception<TypeError>(interpreter.global_object(), ErrorType::Convert, "symbol", "string");
|
||||||
return {};
|
return {};
|
||||||
case Type::BigInt:
|
case Type::BigInt:
|
||||||
return m_value.as_bigint->big_integer().to_base10();
|
return m_value.as_bigint->big_integer().to_base10();
|
||||||
|
@ -215,7 +215,7 @@ Object* Value::to_object(Interpreter& interpreter, GlobalObject& global_object)
|
||||||
switch (m_type) {
|
switch (m_type) {
|
||||||
case Type::Undefined:
|
case Type::Undefined:
|
||||||
case Type::Null:
|
case Type::Null:
|
||||||
interpreter.throw_exception<TypeError>(ErrorType::ToObjectNullOrUndef);
|
interpreter.vm().throw_exception<TypeError>(global_object, ErrorType::ToObjectNullOrUndef);
|
||||||
return nullptr;
|
return nullptr;
|
||||||
case Type::Boolean:
|
case Type::Boolean:
|
||||||
return BooleanObject::create(global_object, m_value.as_bool);
|
return BooleanObject::create(global_object, m_value.as_bool);
|
||||||
|
@ -271,10 +271,10 @@ Value Value::to_number(Interpreter& interpreter) const
|
||||||
return Value(parsed_double);
|
return Value(parsed_double);
|
||||||
}
|
}
|
||||||
case Type::Symbol:
|
case Type::Symbol:
|
||||||
interpreter.throw_exception<TypeError>(ErrorType::Convert, "symbol", "number");
|
interpreter.vm().throw_exception<TypeError>(interpreter.global_object(), ErrorType::Convert, "symbol", "number");
|
||||||
return {};
|
return {};
|
||||||
case Type::BigInt:
|
case Type::BigInt:
|
||||||
interpreter.throw_exception<TypeError>(ErrorType::Convert, "BigInt", "number");
|
interpreter.vm().throw_exception<TypeError>(interpreter.global_object(), ErrorType::Convert, "BigInt", "number");
|
||||||
return {};
|
return {};
|
||||||
case Type::Object: {
|
case Type::Object: {
|
||||||
auto primitive = m_value.as_object->to_primitive(PreferredType::Number);
|
auto primitive = m_value.as_object->to_primitive(PreferredType::Number);
|
||||||
|
@ -294,10 +294,10 @@ BigInt* Value::to_bigint(Interpreter& interpreter) const
|
||||||
return nullptr;
|
return nullptr;
|
||||||
switch (primitive.type()) {
|
switch (primitive.type()) {
|
||||||
case Type::Undefined:
|
case Type::Undefined:
|
||||||
interpreter.throw_exception<TypeError>(ErrorType::Convert, "undefined", "BigInt");
|
interpreter.vm().throw_exception<TypeError>(interpreter.global_object(), ErrorType::Convert, "undefined", "BigInt");
|
||||||
return nullptr;
|
return nullptr;
|
||||||
case Type::Null:
|
case Type::Null:
|
||||||
interpreter.throw_exception<TypeError>(ErrorType::Convert, "null", "BigInt");
|
interpreter.vm().throw_exception<TypeError>(interpreter.global_object(), ErrorType::Convert, "null", "BigInt");
|
||||||
return nullptr;
|
return nullptr;
|
||||||
case Type::Boolean: {
|
case Type::Boolean: {
|
||||||
auto value = primitive.as_bool() ? 1 : 0;
|
auto value = primitive.as_bool() ? 1 : 0;
|
||||||
|
@ -306,18 +306,18 @@ BigInt* Value::to_bigint(Interpreter& interpreter) const
|
||||||
case Type::BigInt:
|
case Type::BigInt:
|
||||||
return &primitive.as_bigint();
|
return &primitive.as_bigint();
|
||||||
case Type::Number:
|
case Type::Number:
|
||||||
interpreter.throw_exception<TypeError>(ErrorType::Convert, "number", "BigInt");
|
interpreter.vm().throw_exception<TypeError>(interpreter.global_object(), ErrorType::Convert, "number", "BigInt");
|
||||||
return {};
|
return {};
|
||||||
case Type::String: {
|
case Type::String: {
|
||||||
auto& string = primitive.as_string().string();
|
auto& string = primitive.as_string().string();
|
||||||
if (!is_valid_bigint_value(string)) {
|
if (!is_valid_bigint_value(string)) {
|
||||||
interpreter.throw_exception<SyntaxError>(ErrorType::BigIntInvalidValue, string.characters());
|
interpreter.vm().throw_exception<SyntaxError>(interpreter.global_object(), ErrorType::BigIntInvalidValue, string.characters());
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
return js_bigint(interpreter, Crypto::SignedBigInteger::from_base10(string.trim_whitespace()));
|
return js_bigint(interpreter, Crypto::SignedBigInteger::from_base10(string.trim_whitespace()));
|
||||||
}
|
}
|
||||||
case Type::Symbol:
|
case Type::Symbol:
|
||||||
interpreter.throw_exception<TypeError>(ErrorType::Convert, "symbol", "BigInt");
|
interpreter.vm().throw_exception<TypeError>(interpreter.global_object(), ErrorType::Convert, "symbol", "BigInt");
|
||||||
return {};
|
return {};
|
||||||
default:
|
default:
|
||||||
ASSERT_NOT_REACHED();
|
ASSERT_NOT_REACHED();
|
||||||
|
@ -416,7 +416,7 @@ Value bitwise_and(Interpreter& interpreter, Value lhs, Value rhs)
|
||||||
}
|
}
|
||||||
if (both_bigint(lhs_numeric, rhs_numeric))
|
if (both_bigint(lhs_numeric, rhs_numeric))
|
||||||
return js_bigint(interpreter, lhs_numeric.as_bigint().big_integer().bitwise_and(rhs_numeric.as_bigint().big_integer()));
|
return js_bigint(interpreter, lhs_numeric.as_bigint().big_integer().bitwise_and(rhs_numeric.as_bigint().big_integer()));
|
||||||
interpreter.throw_exception<TypeError>(ErrorType::BigIntBadOperatorOtherType, "bitwise AND");
|
interpreter.vm().throw_exception<TypeError>(interpreter.global_object(), ErrorType::BigIntBadOperatorOtherType, "bitwise AND");
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -439,7 +439,7 @@ Value bitwise_or(Interpreter& interpreter, Value lhs, Value rhs)
|
||||||
}
|
}
|
||||||
if (both_bigint(lhs_numeric, rhs_numeric))
|
if (both_bigint(lhs_numeric, rhs_numeric))
|
||||||
return js_bigint(interpreter, lhs_numeric.as_bigint().big_integer().bitwise_or(rhs_numeric.as_bigint().big_integer()));
|
return js_bigint(interpreter, lhs_numeric.as_bigint().big_integer().bitwise_or(rhs_numeric.as_bigint().big_integer()));
|
||||||
interpreter.throw_exception<TypeError>(ErrorType::BigIntBadOperatorOtherType, "bitwise OR");
|
interpreter.vm().throw_exception<TypeError>(interpreter.global_object(), ErrorType::BigIntBadOperatorOtherType, "bitwise OR");
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -462,7 +462,7 @@ Value bitwise_xor(Interpreter& interpreter, Value lhs, Value rhs)
|
||||||
}
|
}
|
||||||
if (both_bigint(lhs_numeric, rhs_numeric))
|
if (both_bigint(lhs_numeric, rhs_numeric))
|
||||||
return js_bigint(interpreter, lhs_numeric.as_bigint().big_integer().bitwise_xor(rhs_numeric.as_bigint().big_integer()));
|
return js_bigint(interpreter, lhs_numeric.as_bigint().big_integer().bitwise_xor(rhs_numeric.as_bigint().big_integer()));
|
||||||
interpreter.throw_exception<TypeError>(ErrorType::BigIntBadOperatorOtherType, "bitwise XOR");
|
interpreter.vm().throw_exception<TypeError>(interpreter.global_object(), ErrorType::BigIntBadOperatorOtherType, "bitwise XOR");
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -518,7 +518,7 @@ Value left_shift(Interpreter& interpreter, Value lhs, Value rhs)
|
||||||
}
|
}
|
||||||
if (both_bigint(lhs_numeric, rhs_numeric))
|
if (both_bigint(lhs_numeric, rhs_numeric))
|
||||||
TODO();
|
TODO();
|
||||||
interpreter.throw_exception<TypeError>(ErrorType::BigIntBadOperatorOtherType, "left-shift");
|
interpreter.vm().throw_exception<TypeError>(interpreter.global_object(), ErrorType::BigIntBadOperatorOtherType, "left-shift");
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -539,7 +539,7 @@ Value right_shift(Interpreter& interpreter, Value lhs, Value rhs)
|
||||||
}
|
}
|
||||||
if (both_bigint(lhs_numeric, rhs_numeric))
|
if (both_bigint(lhs_numeric, rhs_numeric))
|
||||||
TODO();
|
TODO();
|
||||||
interpreter.throw_exception<TypeError>(ErrorType::BigIntBadOperatorOtherType, "right-shift");
|
interpreter.vm().throw_exception<TypeError>(interpreter.global_object(), ErrorType::BigIntBadOperatorOtherType, "right-shift");
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -558,7 +558,7 @@ Value unsigned_right_shift(Interpreter& interpreter, Value lhs, Value rhs)
|
||||||
return lhs_numeric;
|
return lhs_numeric;
|
||||||
return Value((unsigned)lhs_numeric.as_double() >> (i32)rhs_numeric.as_double());
|
return Value((unsigned)lhs_numeric.as_double() >> (i32)rhs_numeric.as_double());
|
||||||
}
|
}
|
||||||
interpreter.throw_exception<TypeError>(ErrorType::BigIntBadOperator, "unsigned right-shift");
|
interpreter.vm().throw_exception<TypeError>(interpreter.global_object(), ErrorType::BigIntBadOperator, "unsigned right-shift");
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -594,7 +594,7 @@ Value add(Interpreter& interpreter, Value lhs, Value rhs)
|
||||||
return Value(lhs_numeric.as_double() + rhs_numeric.as_double());
|
return Value(lhs_numeric.as_double() + rhs_numeric.as_double());
|
||||||
if (both_bigint(lhs_numeric, rhs_numeric))
|
if (both_bigint(lhs_numeric, rhs_numeric))
|
||||||
return js_bigint(interpreter, lhs_numeric.as_bigint().big_integer().plus(rhs_numeric.as_bigint().big_integer()));
|
return js_bigint(interpreter, lhs_numeric.as_bigint().big_integer().plus(rhs_numeric.as_bigint().big_integer()));
|
||||||
interpreter.throw_exception<TypeError>(ErrorType::BigIntBadOperatorOtherType, "addition");
|
interpreter.vm().throw_exception<TypeError>(interpreter.global_object(), ErrorType::BigIntBadOperatorOtherType, "addition");
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -610,7 +610,7 @@ Value sub(Interpreter& interpreter, Value lhs, Value rhs)
|
||||||
return Value(lhs_numeric.as_double() - rhs_numeric.as_double());
|
return Value(lhs_numeric.as_double() - rhs_numeric.as_double());
|
||||||
if (both_bigint(lhs_numeric, rhs_numeric))
|
if (both_bigint(lhs_numeric, rhs_numeric))
|
||||||
return js_bigint(interpreter, lhs_numeric.as_bigint().big_integer().minus(rhs_numeric.as_bigint().big_integer()));
|
return js_bigint(interpreter, lhs_numeric.as_bigint().big_integer().minus(rhs_numeric.as_bigint().big_integer()));
|
||||||
interpreter.throw_exception<TypeError>(ErrorType::BigIntBadOperatorOtherType, "subtraction");
|
interpreter.vm().throw_exception<TypeError>(interpreter.global_object(), ErrorType::BigIntBadOperatorOtherType, "subtraction");
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -626,7 +626,7 @@ Value mul(Interpreter& interpreter, Value lhs, Value rhs)
|
||||||
return Value(lhs_numeric.as_double() * rhs_numeric.as_double());
|
return Value(lhs_numeric.as_double() * rhs_numeric.as_double());
|
||||||
if (both_bigint(lhs_numeric, rhs_numeric))
|
if (both_bigint(lhs_numeric, rhs_numeric))
|
||||||
return js_bigint(interpreter, lhs_numeric.as_bigint().big_integer().multiplied_by(rhs_numeric.as_bigint().big_integer()));
|
return js_bigint(interpreter, lhs_numeric.as_bigint().big_integer().multiplied_by(rhs_numeric.as_bigint().big_integer()));
|
||||||
interpreter.throw_exception<TypeError>(ErrorType::BigIntBadOperatorOtherType, "multiplication");
|
interpreter.vm().throw_exception<TypeError>(interpreter.global_object(), ErrorType::BigIntBadOperatorOtherType, "multiplication");
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -642,7 +642,7 @@ Value div(Interpreter& interpreter, Value lhs, Value rhs)
|
||||||
return Value(lhs_numeric.as_double() / rhs_numeric.as_double());
|
return Value(lhs_numeric.as_double() / rhs_numeric.as_double());
|
||||||
if (both_bigint(lhs_numeric, rhs_numeric))
|
if (both_bigint(lhs_numeric, rhs_numeric))
|
||||||
return js_bigint(interpreter, lhs_numeric.as_bigint().big_integer().divided_by(rhs_numeric.as_bigint().big_integer()).quotient);
|
return js_bigint(interpreter, lhs_numeric.as_bigint().big_integer().divided_by(rhs_numeric.as_bigint().big_integer()).quotient);
|
||||||
interpreter.throw_exception<TypeError>(ErrorType::BigIntBadOperatorOtherType, "division");
|
interpreter.vm().throw_exception<TypeError>(interpreter.global_object(), ErrorType::BigIntBadOperatorOtherType, "division");
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -664,7 +664,7 @@ Value mod(Interpreter& interpreter, Value lhs, Value rhs)
|
||||||
}
|
}
|
||||||
if (both_bigint(lhs_numeric, rhs_numeric))
|
if (both_bigint(lhs_numeric, rhs_numeric))
|
||||||
return js_bigint(interpreter, lhs_numeric.as_bigint().big_integer().divided_by(rhs_numeric.as_bigint().big_integer()).remainder);
|
return js_bigint(interpreter, lhs_numeric.as_bigint().big_integer().divided_by(rhs_numeric.as_bigint().big_integer()).remainder);
|
||||||
interpreter.throw_exception<TypeError>(ErrorType::BigIntBadOperatorOtherType, "modulo");
|
interpreter.vm().throw_exception<TypeError>(interpreter.global_object(), ErrorType::BigIntBadOperatorOtherType, "modulo");
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -680,14 +680,14 @@ Value exp(Interpreter& interpreter, Value lhs, Value rhs)
|
||||||
return Value(pow(lhs_numeric.as_double(), rhs_numeric.as_double()));
|
return Value(pow(lhs_numeric.as_double(), rhs_numeric.as_double()));
|
||||||
if (both_bigint(lhs_numeric, rhs_numeric))
|
if (both_bigint(lhs_numeric, rhs_numeric))
|
||||||
return js_bigint(interpreter, Crypto::NumberTheory::Power(lhs_numeric.as_bigint().big_integer(), rhs_numeric.as_bigint().big_integer()));
|
return js_bigint(interpreter, Crypto::NumberTheory::Power(lhs_numeric.as_bigint().big_integer(), rhs_numeric.as_bigint().big_integer()));
|
||||||
interpreter.throw_exception<TypeError>(ErrorType::BigIntBadOperatorOtherType, "exponentiation");
|
interpreter.vm().throw_exception<TypeError>(interpreter.global_object(), ErrorType::BigIntBadOperatorOtherType, "exponentiation");
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
Value in(Interpreter& interpreter, Value lhs, Value rhs)
|
Value in(Interpreter& interpreter, Value lhs, Value rhs)
|
||||||
{
|
{
|
||||||
if (!rhs.is_object()) {
|
if (!rhs.is_object()) {
|
||||||
interpreter.throw_exception<TypeError>(ErrorType::InOperatorWithObject);
|
interpreter.vm().throw_exception<TypeError>(interpreter.global_object(), ErrorType::InOperatorWithObject);
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
auto lhs_string = lhs.to_string(interpreter);
|
auto lhs_string = lhs.to_string(interpreter);
|
||||||
|
@ -699,13 +699,13 @@ Value in(Interpreter& interpreter, Value lhs, Value rhs)
|
||||||
Value instance_of(Interpreter& interpreter, Value lhs, Value rhs)
|
Value instance_of(Interpreter& interpreter, Value lhs, Value rhs)
|
||||||
{
|
{
|
||||||
if (!rhs.is_object()) {
|
if (!rhs.is_object()) {
|
||||||
interpreter.throw_exception<TypeError>(ErrorType::NotAnObject, rhs.to_string_without_side_effects().characters());
|
interpreter.vm().throw_exception<TypeError>(interpreter.global_object(), ErrorType::NotAnObject, rhs.to_string_without_side_effects().characters());
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
auto has_instance_method = rhs.as_object().get(interpreter.vm().well_known_symbol_has_instance());
|
auto has_instance_method = rhs.as_object().get(interpreter.vm().well_known_symbol_has_instance());
|
||||||
if (!has_instance_method.is_empty()) {
|
if (!has_instance_method.is_empty()) {
|
||||||
if (!has_instance_method.is_function()) {
|
if (!has_instance_method.is_function()) {
|
||||||
interpreter.throw_exception<TypeError>(ErrorType::NotAFunction, has_instance_method.to_string_without_side_effects().characters());
|
interpreter.vm().throw_exception<TypeError>(interpreter.global_object(), ErrorType::NotAFunction, has_instance_method.to_string_without_side_effects().characters());
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -713,7 +713,7 @@ Value instance_of(Interpreter& interpreter, Value lhs, Value rhs)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!rhs.is_function()) {
|
if (!rhs.is_function()) {
|
||||||
interpreter.throw_exception<TypeError>(ErrorType::NotAFunction, rhs.to_string_without_side_effects().characters());
|
interpreter.vm().throw_exception<TypeError>(interpreter.global_object(), ErrorType::NotAFunction, rhs.to_string_without_side_effects().characters());
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
return ordinary_has_instance(interpreter, lhs, rhs);
|
return ordinary_has_instance(interpreter, lhs, rhs);
|
||||||
|
@ -739,7 +739,7 @@ Value ordinary_has_instance(Interpreter& interpreter, Value lhs, Value rhs)
|
||||||
return {};
|
return {};
|
||||||
|
|
||||||
if (!rhs_prototype.is_object()) {
|
if (!rhs_prototype.is_object()) {
|
||||||
interpreter.throw_exception<TypeError>(ErrorType::InstanceOfOperatorBadPrototype, rhs_prototype.to_string_without_side_effects().characters());
|
interpreter.vm().throw_exception<TypeError>(interpreter.global_object(), ErrorType::InstanceOfOperatorBadPrototype, rhs_prototype.to_string_without_side_effects().characters());
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
while (true) {
|
while (true) {
|
||||||
|
|
|
@ -107,7 +107,7 @@ static DOM::Window* impl_from(JS::Interpreter& interpreter, JS::GlobalObject& gl
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
if (StringView("WindowObject") != this_object->class_name()) {
|
if (StringView("WindowObject") != this_object->class_name()) {
|
||||||
interpreter.throw_exception<JS::TypeError>(JS::ErrorType::NotA, "WindowObject");
|
interpreter.vm().throw_exception<JS::TypeError>(global_object, JS::ErrorType::NotA, "WindowObject");
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
return &static_cast<WindowObject*>(this_object)->impl();
|
return &static_cast<WindowObject*>(this_object)->impl();
|
||||||
|
@ -148,14 +148,14 @@ JS_DEFINE_NATIVE_FUNCTION(WindowObject::set_interval)
|
||||||
if (!impl)
|
if (!impl)
|
||||||
return {};
|
return {};
|
||||||
if (!interpreter.argument_count()) {
|
if (!interpreter.argument_count()) {
|
||||||
interpreter.throw_exception<JS::TypeError>(JS::ErrorType::BadArgCountAtLeastOne, "setInterval");
|
interpreter.vm().throw_exception<JS::TypeError>(global_object, JS::ErrorType::BadArgCountAtLeastOne, "setInterval");
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
auto* callback_object = interpreter.argument(0).to_object(interpreter, global_object);
|
auto* callback_object = interpreter.argument(0).to_object(interpreter, global_object);
|
||||||
if (!callback_object)
|
if (!callback_object)
|
||||||
return {};
|
return {};
|
||||||
if (!callback_object->is_function()) {
|
if (!callback_object->is_function()) {
|
||||||
interpreter.throw_exception<JS::TypeError>(JS::ErrorType::NotAFunctionNoParam);
|
interpreter.vm().throw_exception<JS::TypeError>(global_object, JS::ErrorType::NotAFunctionNoParam);
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
i32 interval = 0;
|
i32 interval = 0;
|
||||||
|
@ -177,14 +177,14 @@ JS_DEFINE_NATIVE_FUNCTION(WindowObject::set_timeout)
|
||||||
if (!impl)
|
if (!impl)
|
||||||
return {};
|
return {};
|
||||||
if (!interpreter.argument_count()) {
|
if (!interpreter.argument_count()) {
|
||||||
interpreter.throw_exception<JS::TypeError>(JS::ErrorType::BadArgCountAtLeastOne, "setTimeout");
|
interpreter.vm().throw_exception<JS::TypeError>(global_object, JS::ErrorType::BadArgCountAtLeastOne, "setTimeout");
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
auto* callback_object = interpreter.argument(0).to_object(interpreter, global_object);
|
auto* callback_object = interpreter.argument(0).to_object(interpreter, global_object);
|
||||||
if (!callback_object)
|
if (!callback_object)
|
||||||
return {};
|
return {};
|
||||||
if (!callback_object->is_function()) {
|
if (!callback_object->is_function()) {
|
||||||
interpreter.throw_exception<JS::TypeError>(JS::ErrorType::NotAFunctionNoParam);
|
interpreter.vm().throw_exception<JS::TypeError>(global_object, JS::ErrorType::NotAFunctionNoParam);
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
i32 interval = 0;
|
i32 interval = 0;
|
||||||
|
@ -206,7 +206,7 @@ JS_DEFINE_NATIVE_FUNCTION(WindowObject::clear_timeout)
|
||||||
if (!impl)
|
if (!impl)
|
||||||
return {};
|
return {};
|
||||||
if (!interpreter.argument_count()) {
|
if (!interpreter.argument_count()) {
|
||||||
interpreter.throw_exception<JS::TypeError>(JS::ErrorType::BadArgCountAtLeastOne, "clearTimeout");
|
interpreter.vm().throw_exception<JS::TypeError>(global_object, JS::ErrorType::BadArgCountAtLeastOne, "clearTimeout");
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
i32 timer_id = interpreter.argument(0).to_i32(interpreter);
|
i32 timer_id = interpreter.argument(0).to_i32(interpreter);
|
||||||
|
@ -222,7 +222,7 @@ JS_DEFINE_NATIVE_FUNCTION(WindowObject::clear_interval)
|
||||||
if (!impl)
|
if (!impl)
|
||||||
return {};
|
return {};
|
||||||
if (!interpreter.argument_count()) {
|
if (!interpreter.argument_count()) {
|
||||||
interpreter.throw_exception<JS::TypeError>(JS::ErrorType::BadArgCountAtLeastOne, "clearInterval");
|
interpreter.vm().throw_exception<JS::TypeError>(global_object, JS::ErrorType::BadArgCountAtLeastOne, "clearInterval");
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
i32 timer_id = interpreter.argument(0).to_i32(interpreter);
|
i32 timer_id = interpreter.argument(0).to_i32(interpreter);
|
||||||
|
@ -238,14 +238,14 @@ JS_DEFINE_NATIVE_FUNCTION(WindowObject::request_animation_frame)
|
||||||
if (!impl)
|
if (!impl)
|
||||||
return {};
|
return {};
|
||||||
if (!interpreter.argument_count()) {
|
if (!interpreter.argument_count()) {
|
||||||
interpreter.throw_exception<JS::TypeError>(JS::ErrorType::BadArgCountOne, "requestAnimationFrame");
|
interpreter.vm().throw_exception<JS::TypeError>(global_object, JS::ErrorType::BadArgCountOne, "requestAnimationFrame");
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
auto* callback_object = interpreter.argument(0).to_object(interpreter, global_object);
|
auto* callback_object = interpreter.argument(0).to_object(interpreter, global_object);
|
||||||
if (!callback_object)
|
if (!callback_object)
|
||||||
return {};
|
return {};
|
||||||
if (!callback_object->is_function()) {
|
if (!callback_object->is_function()) {
|
||||||
interpreter.throw_exception<JS::TypeError>(JS::ErrorType::NotAFunctionNoParam);
|
interpreter.vm().throw_exception<JS::TypeError>(global_object, JS::ErrorType::NotAFunctionNoParam);
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
return JS::Value(impl->request_animation_frame(*static_cast<JS::Function*>(callback_object)));
|
return JS::Value(impl->request_animation_frame(*static_cast<JS::Function*>(callback_object)));
|
||||||
|
@ -257,7 +257,7 @@ JS_DEFINE_NATIVE_FUNCTION(WindowObject::cancel_animation_frame)
|
||||||
if (!impl)
|
if (!impl)
|
||||||
return {};
|
return {};
|
||||||
if (!interpreter.argument_count()) {
|
if (!interpreter.argument_count()) {
|
||||||
interpreter.throw_exception<JS::TypeError>(JS::ErrorType::BadArgCountOne, "cancelAnimationFrame");
|
interpreter.vm().throw_exception<JS::TypeError>(global_object, JS::ErrorType::BadArgCountOne, "cancelAnimationFrame");
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
auto id = interpreter.argument(0).to_i32(interpreter);
|
auto id = interpreter.argument(0).to_i32(interpreter);
|
||||||
|
@ -273,7 +273,7 @@ JS_DEFINE_NATIVE_FUNCTION(WindowObject::atob)
|
||||||
if (!impl)
|
if (!impl)
|
||||||
return {};
|
return {};
|
||||||
if (!interpreter.argument_count()) {
|
if (!interpreter.argument_count()) {
|
||||||
interpreter.throw_exception<JS::TypeError>(JS::ErrorType::BadArgCountOne, "atob");
|
interpreter.vm().throw_exception<JS::TypeError>(global_object, JS::ErrorType::BadArgCountOne, "atob");
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
auto string = interpreter.argument(0).to_string(interpreter);
|
auto string = interpreter.argument(0).to_string(interpreter);
|
||||||
|
@ -291,7 +291,7 @@ JS_DEFINE_NATIVE_FUNCTION(WindowObject::btoa)
|
||||||
if (!impl)
|
if (!impl)
|
||||||
return {};
|
return {};
|
||||||
if (!interpreter.argument_count()) {
|
if (!interpreter.argument_count()) {
|
||||||
interpreter.throw_exception<JS::TypeError>(JS::ErrorType::BadArgCountOne, "btoa");
|
interpreter.vm().throw_exception<JS::TypeError>(global_object, JS::ErrorType::BadArgCountOne, "btoa");
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
auto string = interpreter.argument(0).to_string(interpreter);
|
auto string = interpreter.argument(0).to_string(interpreter);
|
||||||
|
@ -302,7 +302,7 @@ JS_DEFINE_NATIVE_FUNCTION(WindowObject::btoa)
|
||||||
byte_string.ensure_capacity(string.length());
|
byte_string.ensure_capacity(string.length());
|
||||||
for (u32 code_point : Utf8View(string)) {
|
for (u32 code_point : Utf8View(string)) {
|
||||||
if (code_point > 0xff) {
|
if (code_point > 0xff) {
|
||||||
interpreter.throw_exception<JS::InvalidCharacterError>(JS::ErrorType::NotAByteString, "btoa");
|
interpreter.vm().throw_exception<JS::InvalidCharacterError>(global_object, JS::ErrorType::NotAByteString, "btoa");
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
byte_string.append(code_point);
|
byte_string.append(code_point);
|
||||||
|
|
|
@ -64,7 +64,7 @@ static XMLHttpRequest* impl_from(JS::Interpreter& interpreter, JS::GlobalObject&
|
||||||
if (!this_object)
|
if (!this_object)
|
||||||
return nullptr;
|
return nullptr;
|
||||||
if (StringView("XMLHttpRequestWrapper") != this_object->class_name()) {
|
if (StringView("XMLHttpRequestWrapper") != this_object->class_name()) {
|
||||||
interpreter.throw_exception<JS::TypeError>(JS::ErrorType::NotA, "XMLHttpRequest");
|
interpreter.vm().throw_exception<JS::TypeError>(global_object, JS::ErrorType::NotA, "XMLHttpRequest");
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
return &static_cast<XMLHttpRequestWrapper*>(this_object)->impl();
|
return &static_cast<XMLHttpRequestWrapper*>(this_object)->impl();
|
||||||
|
|
|
@ -506,7 +506,7 @@ void generate_implementation(const IDL::Interface& interface)
|
||||||
out() << " if (!this_object)";
|
out() << " if (!this_object)";
|
||||||
out() << " return {};";
|
out() << " return {};";
|
||||||
out() << " if (!this_object->inherits(\"" << wrapper_class << "\")) {";
|
out() << " if (!this_object->inherits(\"" << wrapper_class << "\")) {";
|
||||||
out() << " interpreter.throw_exception<JS::TypeError>(JS::ErrorType::NotA, \"" << interface.fully_qualified_name << "\");";
|
out() << " interpreter.vm().throw_exception<JS::TypeError>(global_object, JS::ErrorType::NotA, \"" << interface.fully_qualified_name << "\");";
|
||||||
out() << " return nullptr;";
|
out() << " return nullptr;";
|
||||||
out() << " }";
|
out() << " }";
|
||||||
out() << " return &static_cast<" << wrapper_class << "*>(this_object)->impl();";
|
out() << " return &static_cast<" << wrapper_class << "*>(this_object)->impl();";
|
||||||
|
@ -526,7 +526,7 @@ void generate_implementation(const IDL::Interface& interface)
|
||||||
generate_return();
|
generate_return();
|
||||||
} else if (parameter.type.name == "EventListener") {
|
} else if (parameter.type.name == "EventListener") {
|
||||||
out() << " if (!" << js_name << js_suffix << ".is_function()) {";
|
out() << " if (!" << js_name << js_suffix << ".is_function()) {";
|
||||||
out() << " interpreter.throw_exception<JS::TypeError>(JS::ErrorType::NotA, \"Function\");";
|
out() << " interpreter.vm().throw_exception<JS::TypeError>(global_object, JS::ErrorType::NotA, \"Function\");";
|
||||||
generate_return();
|
generate_return();
|
||||||
out() << " }";
|
out() << " }";
|
||||||
out() << " auto " << cpp_name << " = adopt(*new EventListener(JS::make_handle(&" << js_name << js_suffix << ".as_function())));";
|
out() << " auto " << cpp_name << " = adopt(*new EventListener(JS::make_handle(&" << js_name << js_suffix << ".as_function())));";
|
||||||
|
@ -535,7 +535,7 @@ void generate_implementation(const IDL::Interface& interface)
|
||||||
out() << " if (interpreter.exception())";
|
out() << " if (interpreter.exception())";
|
||||||
generate_return();
|
generate_return();
|
||||||
out() << " if (!" << cpp_name << "_object->inherits(\"" << parameter.type.name << "Wrapper\")) {";
|
out() << " if (!" << cpp_name << "_object->inherits(\"" << parameter.type.name << "Wrapper\")) {";
|
||||||
out() << " interpreter.throw_exception<JS::TypeError>(JS::ErrorType::NotA, \"" << parameter.type.name << "\");";
|
out() << " interpreter.vm().throw_exception<JS::TypeError>(global_object, JS::ErrorType::NotA, \"" << parameter.type.name << "\");";
|
||||||
generate_return();
|
generate_return();
|
||||||
out() << " }";
|
out() << " }";
|
||||||
out() << " auto& " << cpp_name << " = static_cast<" << parameter.type.name << "Wrapper*>(" << cpp_name << "_object)->impl();";
|
out() << " auto& " << cpp_name << " = static_cast<" << parameter.type.name << "Wrapper*>(" << cpp_name << "_object)->impl();";
|
||||||
|
@ -658,9 +658,9 @@ void generate_implementation(const IDL::Interface& interface)
|
||||||
if (function.length() > 0) {
|
if (function.length() > 0) {
|
||||||
out() << " if (interpreter.argument_count() < " << function.length() << ") {";
|
out() << " if (interpreter.argument_count() < " << function.length() << ") {";
|
||||||
if (function.length() == 1)
|
if (function.length() == 1)
|
||||||
out() << " interpreter.throw_exception<JS::TypeError>(JS::ErrorType::BadArgCountOne, \"" << function.name << "\");";
|
out() << " interpreter.vm().throw_exception<JS::TypeError>(global_object, JS::ErrorType::BadArgCountOne, \"" << function.name << "\");";
|
||||||
else
|
else
|
||||||
out() << " interpreter.throw_exception<JS::TypeError>(JS::ErrorType::BadArgCountMany, \"" << function.name << "\", \"" << function.length() << "\");";
|
out() << " interpreter.vm().throw_exception<JS::TypeError>(global_object, JS::ErrorType::BadArgCountMany, \"" << function.name << "\", \"" << function.length() << "\");";
|
||||||
out() << " return {};";
|
out() << " return {};";
|
||||||
out() << " }";
|
out() << " }";
|
||||||
}
|
}
|
||||||
|
|
|
@ -349,7 +349,7 @@ static bool parse_and_run(JS::Interpreter& interpreter, const StringView& source
|
||||||
auto hint = error.source_location_hint(source);
|
auto hint = error.source_location_hint(source);
|
||||||
if (!hint.is_empty())
|
if (!hint.is_empty())
|
||||||
printf("%s\n", hint.characters());
|
printf("%s\n", hint.characters());
|
||||||
interpreter.throw_exception<JS::SyntaxError>(error.to_string());
|
vm->throw_exception<JS::SyntaxError>(interpreter.global_object(), error.to_string());
|
||||||
} else {
|
} else {
|
||||||
interpreter.run(interpreter.global_object(), *program);
|
interpreter.run(interpreter.global_object(), *program);
|
||||||
}
|
}
|
||||||
|
@ -362,11 +362,11 @@ static bool parse_and_run(JS::Interpreter& interpreter, const StringView& source
|
||||||
for (auto& function_name : trace)
|
for (auto& function_name : trace)
|
||||||
printf(" -> %s\n", function_name.characters());
|
printf(" -> %s\n", function_name.characters());
|
||||||
}
|
}
|
||||||
interpreter.vm().clear_exception();
|
vm->clear_exception();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (s_print_last_result)
|
if (s_print_last_result)
|
||||||
print(interpreter.last_value());
|
print(vm->last_value());
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -470,32 +470,32 @@ public:
|
||||||
|
|
||||||
virtual JS::Value log() override
|
virtual JS::Value log() override
|
||||||
{
|
{
|
||||||
puts(interpreter().join_arguments().characters());
|
puts(interpreter().vm().join_arguments().characters());
|
||||||
return JS::js_undefined();
|
return JS::js_undefined();
|
||||||
}
|
}
|
||||||
virtual JS::Value info() override
|
virtual JS::Value info() override
|
||||||
{
|
{
|
||||||
printf("(i) %s\n", interpreter().join_arguments().characters());
|
printf("(i) %s\n", interpreter().vm().join_arguments().characters());
|
||||||
return JS::js_undefined();
|
return JS::js_undefined();
|
||||||
}
|
}
|
||||||
virtual JS::Value debug() override
|
virtual JS::Value debug() override
|
||||||
{
|
{
|
||||||
printf("\033[36;1m");
|
printf("\033[36;1m");
|
||||||
puts(interpreter().join_arguments().characters());
|
puts(interpreter().vm().join_arguments().characters());
|
||||||
printf("\033[0m");
|
printf("\033[0m");
|
||||||
return JS::js_undefined();
|
return JS::js_undefined();
|
||||||
}
|
}
|
||||||
virtual JS::Value warn() override
|
virtual JS::Value warn() override
|
||||||
{
|
{
|
||||||
printf("\033[33;1m");
|
printf("\033[33;1m");
|
||||||
puts(interpreter().join_arguments().characters());
|
puts(interpreter().vm().join_arguments().characters());
|
||||||
printf("\033[0m");
|
printf("\033[0m");
|
||||||
return JS::js_undefined();
|
return JS::js_undefined();
|
||||||
}
|
}
|
||||||
virtual JS::Value error() override
|
virtual JS::Value error() override
|
||||||
{
|
{
|
||||||
printf("\033[31;1m");
|
printf("\033[31;1m");
|
||||||
puts(interpreter().join_arguments().characters());
|
puts(interpreter().vm().join_arguments().characters());
|
||||||
printf("\033[0m");
|
printf("\033[0m");
|
||||||
return JS::js_undefined();
|
return JS::js_undefined();
|
||||||
}
|
}
|
||||||
|
@ -507,7 +507,7 @@ public:
|
||||||
}
|
}
|
||||||
virtual JS::Value trace() override
|
virtual JS::Value trace() override
|
||||||
{
|
{
|
||||||
puts(interpreter().join_arguments().characters());
|
puts(interpreter().vm().join_arguments().characters());
|
||||||
auto trace = get_trace();
|
auto trace = get_trace();
|
||||||
for (auto& function_name : trace) {
|
for (auto& function_name : trace) {
|
||||||
if (function_name.is_empty())
|
if (function_name.is_empty())
|
||||||
|
@ -558,7 +558,7 @@ int main(int argc, char** argv)
|
||||||
|
|
||||||
interrupt_interpreter = [&] {
|
interrupt_interpreter = [&] {
|
||||||
auto error = JS::Error::create(interpreter->global_object(), "Error", "Received SIGINT");
|
auto error = JS::Error::create(interpreter->global_object(), "Error", "Received SIGINT");
|
||||||
interpreter->throw_exception(error);
|
vm->throw_exception(interpreter->global_object(), error);
|
||||||
};
|
};
|
||||||
|
|
||||||
if (script_path == nullptr) {
|
if (script_path == nullptr) {
|
||||||
|
@ -567,7 +567,7 @@ int main(int argc, char** argv)
|
||||||
ReplConsoleClient console_client(interpreter->console());
|
ReplConsoleClient console_client(interpreter->console());
|
||||||
interpreter->console().set_client(console_client);
|
interpreter->console().set_client(console_client);
|
||||||
interpreter->heap().set_should_collect_on_every_allocation(gc_on_every_allocation);
|
interpreter->heap().set_should_collect_on_every_allocation(gc_on_every_allocation);
|
||||||
interpreter->set_underscore_is_last_value(true);
|
interpreter->vm().set_underscore_is_last_value(true);
|
||||||
|
|
||||||
s_editor = Line::Editor::construct();
|
s_editor = Line::Editor::construct();
|
||||||
|
|
||||||
|
@ -811,7 +811,7 @@ int main(int argc, char** argv)
|
||||||
|
|
||||||
switch (mode) {
|
switch (mode) {
|
||||||
case CompleteProperty: {
|
case CompleteProperty: {
|
||||||
auto maybe_variable = interpreter->get_variable(variable_name, interpreter->global_object());
|
auto maybe_variable = vm->get_variable(variable_name, interpreter->global_object());
|
||||||
if (maybe_variable.is_empty()) {
|
if (maybe_variable.is_empty()) {
|
||||||
maybe_variable = interpreter->global_object().get(FlyString(variable_name));
|
maybe_variable = interpreter->global_object().get(FlyString(variable_name));
|
||||||
if (maybe_variable.is_empty())
|
if (maybe_variable.is_empty())
|
||||||
|
|
|
@ -260,7 +260,7 @@ static Result<NonnullRefPtr<JS::Program>, ParserError> parse_file(const String&
|
||||||
|
|
||||||
static Optional<JsonValue> get_test_results(JS::Interpreter& interpreter)
|
static Optional<JsonValue> get_test_results(JS::Interpreter& interpreter)
|
||||||
{
|
{
|
||||||
auto result = interpreter.get_variable("__TestResults__", interpreter.global_object());
|
auto result = interpreter.vm().get_variable("__TestResults__", interpreter.global_object());
|
||||||
auto json_string = JS::JSONObject::stringify_impl(interpreter, interpreter.global_object(), result, JS::js_undefined(), JS::js_undefined());
|
auto json_string = JS::JSONObject::stringify_impl(interpreter, interpreter.global_object(), result, JS::js_undefined(), JS::js_undefined());
|
||||||
|
|
||||||
auto json = JsonValue::from_string(json_string);
|
auto json = JsonValue::from_string(json_string);
|
||||||
|
@ -310,7 +310,7 @@ JSFileResult TestRunner::run_file_test(const String& test_path)
|
||||||
JSFileResult file_result { test_path.substring(m_test_root.length() + 1, test_path.length() - m_test_root.length() - 1) };
|
JSFileResult file_result { test_path.substring(m_test_root.length() + 1, test_path.length() - m_test_root.length() - 1) };
|
||||||
|
|
||||||
// Collect logged messages
|
// Collect logged messages
|
||||||
auto& arr = interpreter->get_variable("__UserOutput__", interpreter->global_object()).as_array();
|
auto& arr = interpreter->vm().get_variable("__UserOutput__", interpreter->global_object()).as_array();
|
||||||
for (auto& entry : arr.indexed_properties()) {
|
for (auto& entry : arr.indexed_properties()) {
|
||||||
auto message = entry.value_and_attributes(&interpreter->global_object()).value;
|
auto message = entry.value_and_attributes(&interpreter->global_object()).value;
|
||||||
file_result.logged_messages.append(message.to_string_without_side_effects());
|
file_result.logged_messages.append(message.to_string_without_side_effects());
|
||||||
|
@ -579,7 +579,6 @@ void TestRunner::print_test_results() const
|
||||||
int main(int argc, char** argv)
|
int main(int argc, char** argv)
|
||||||
{
|
{
|
||||||
bool print_times = false;
|
bool print_times = false;
|
||||||
|
|
||||||
struct sigaction act;
|
struct sigaction act;
|
||||||
memset(&act, 0, sizeof(act));
|
memset(&act, 0, sizeof(act));
|
||||||
act.sa_flags = SA_NOCLDWAIT;
|
act.sa_flags = SA_NOCLDWAIT;
|
||||||
|
|
|
@ -174,11 +174,13 @@ static void cleanup_and_exit()
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if 0
|
||||||
static void handle_sigabrt(int)
|
static void handle_sigabrt(int)
|
||||||
{
|
{
|
||||||
dbg() << "test-web: SIGABRT received, cleaning up.";
|
dbg() << "test-web: SIGABRT received, cleaning up.";
|
||||||
cleanup_and_exit();
|
cleanup_and_exit();
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
static double get_time_in_ms()
|
static double get_time_in_ms()
|
||||||
{
|
{
|
||||||
|
@ -288,7 +290,7 @@ static Result<NonnullRefPtr<JS::Program>, ParserError> parse_file(const String&
|
||||||
|
|
||||||
static Optional<JsonValue> get_test_results(JS::Interpreter& interpreter)
|
static Optional<JsonValue> get_test_results(JS::Interpreter& interpreter)
|
||||||
{
|
{
|
||||||
auto result = interpreter.get_variable("__TestResults__", interpreter.global_object());
|
auto result = interpreter.vm().get_variable("__TestResults__", interpreter.global_object());
|
||||||
auto json_string = JS::JSONObject::stringify_impl(interpreter, interpreter.global_object(), result, JS::js_undefined(), JS::js_undefined());
|
auto json_string = JS::JSONObject::stringify_impl(interpreter, interpreter.global_object(), result, JS::js_undefined(), JS::js_undefined());
|
||||||
|
|
||||||
auto json = JsonValue::from_string(json_string);
|
auto json = JsonValue::from_string(json_string);
|
||||||
|
@ -336,7 +338,7 @@ JSFileResult TestRunner::run_file_test(const String& test_path)
|
||||||
// Setup the test on the current page to get "__PageToLoad__".
|
// Setup the test on the current page to get "__PageToLoad__".
|
||||||
old_interpreter.run(old_interpreter.global_object(), *m_web_test_common);
|
old_interpreter.run(old_interpreter.global_object(), *m_web_test_common);
|
||||||
old_interpreter.run(old_interpreter.global_object(), *file_program.value());
|
old_interpreter.run(old_interpreter.global_object(), *file_program.value());
|
||||||
auto page_to_load = URL(old_interpreter.get_variable("__PageToLoad__", old_interpreter.global_object()).as_string().string());
|
auto page_to_load = URL(old_interpreter.vm().get_variable("__PageToLoad__", old_interpreter.global_object()).as_string().string());
|
||||||
if (!page_to_load.is_valid()) {
|
if (!page_to_load.is_valid()) {
|
||||||
printf("Invalid page URL for %s", test_path.characters());
|
printf("Invalid page URL for %s", test_path.characters());
|
||||||
cleanup_and_exit();
|
cleanup_and_exit();
|
||||||
|
@ -360,7 +362,7 @@ JSFileResult TestRunner::run_file_test(const String& test_path)
|
||||||
new_interpreter.run(new_interpreter.global_object(), *m_web_test_common);
|
new_interpreter.run(new_interpreter.global_object(), *m_web_test_common);
|
||||||
new_interpreter.run(new_interpreter.global_object(), *file_program.value());
|
new_interpreter.run(new_interpreter.global_object(), *file_program.value());
|
||||||
|
|
||||||
auto& before_initial_page_load = new_interpreter.get_variable("__BeforeInitialPageLoad__", new_interpreter.global_object()).as_function();
|
auto& before_initial_page_load = new_interpreter.vm().get_variable("__BeforeInitialPageLoad__", new_interpreter.global_object()).as_function();
|
||||||
(void)new_interpreter.call(before_initial_page_load, JS::js_undefined());
|
(void)new_interpreter.call(before_initial_page_load, JS::js_undefined());
|
||||||
if (new_interpreter.exception())
|
if (new_interpreter.exception())
|
||||||
new_interpreter.vm().clear_exception();
|
new_interpreter.vm().clear_exception();
|
||||||
|
@ -370,7 +372,7 @@ JSFileResult TestRunner::run_file_test(const String& test_path)
|
||||||
m_page_view->set_document(&parser.document());
|
m_page_view->set_document(&parser.document());
|
||||||
|
|
||||||
// Finally run the test by calling "__AfterInitialPageLoad__"
|
// Finally run the test by calling "__AfterInitialPageLoad__"
|
||||||
auto& after_initial_page_load = new_interpreter.get_variable("__AfterInitialPageLoad__", new_interpreter.global_object()).as_function();
|
auto& after_initial_page_load = new_interpreter.vm().get_variable("__AfterInitialPageLoad__", new_interpreter.global_object()).as_function();
|
||||||
(void)new_interpreter.call(after_initial_page_load, JS::js_undefined());
|
(void)new_interpreter.call(after_initial_page_load, JS::js_undefined());
|
||||||
if (new_interpreter.exception())
|
if (new_interpreter.exception())
|
||||||
new_interpreter.vm().clear_exception();
|
new_interpreter.vm().clear_exception();
|
||||||
|
@ -384,7 +386,7 @@ JSFileResult TestRunner::run_file_test(const String& test_path)
|
||||||
file_result = { test_path.substring(m_web_test_root.length() + 1, test_path.length() - m_web_test_root.length() - 1) };
|
file_result = { test_path.substring(m_web_test_root.length() + 1, test_path.length() - m_web_test_root.length() - 1) };
|
||||||
|
|
||||||
// Collect logged messages
|
// Collect logged messages
|
||||||
auto& arr = new_interpreter.get_variable("__UserOutput__", new_interpreter.global_object()).as_array();
|
auto& arr = new_interpreter.vm().get_variable("__UserOutput__", new_interpreter.global_object()).as_array();
|
||||||
for (auto& entry : arr.indexed_properties()) {
|
for (auto& entry : arr.indexed_properties()) {
|
||||||
auto message = entry.value_and_attributes(&new_interpreter.global_object()).value;
|
auto message = entry.value_and_attributes(&new_interpreter.global_object()).value;
|
||||||
file_result.logged_messages.append(message.to_string_without_side_effects());
|
file_result.logged_messages.append(message.to_string_without_side_effects());
|
||||||
|
@ -660,6 +662,7 @@ int main(int argc, char** argv)
|
||||||
bool print_times = false;
|
bool print_times = false;
|
||||||
bool show_window = false;
|
bool show_window = false;
|
||||||
|
|
||||||
|
#if 0
|
||||||
struct sigaction act;
|
struct sigaction act;
|
||||||
memset(&act, 0, sizeof(act));
|
memset(&act, 0, sizeof(act));
|
||||||
act.sa_flags = SA_NOCLDWAIT;
|
act.sa_flags = SA_NOCLDWAIT;
|
||||||
|
@ -669,6 +672,7 @@ int main(int argc, char** argv)
|
||||||
perror("sigaction");
|
perror("sigaction");
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
Core::ArgsParser args_parser;
|
Core::ArgsParser args_parser;
|
||||||
args_parser.add_option(print_times, "Show duration of each test", "show-time", 't');
|
args_parser.add_option(print_times, "Show duration of each test", "show-time", 't');
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue