summaryrefslogtreecommitdiff
path: root/Userland/Libraries/LibJS
diff options
context:
space:
mode:
Diffstat (limited to 'Userland/Libraries/LibJS')
-rw-r--r--Userland/Libraries/LibJS/AST.cpp34
-rw-r--r--Userland/Libraries/LibJS/AST.h4
-rw-r--r--Userland/Libraries/LibJS/Parser.cpp11
-rw-r--r--Userland/Libraries/LibJS/Runtime/ECMAScriptFunctionObject.h4
4 files changed, 48 insertions, 5 deletions
diff --git a/Userland/Libraries/LibJS/AST.cpp b/Userland/Libraries/LibJS/AST.cpp
index 471eb4cee0..009065051c 100644
--- a/Userland/Libraries/LibJS/AST.cpp
+++ b/Userland/Libraries/LibJS/AST.cpp
@@ -1278,6 +1278,35 @@ ThrowCompletionOr<ClassElement::ClassValue> ClassMethod::class_element_evaluatio
}
}
+// We use this class to mimic Initializer : = AssignmentExpression of
+// 10.2.1.3 Runtime Semantics: EvaluateBody, https://tc39.es/ecma262/#sec-runtime-semantics-evaluatebody
+class ClassFieldInitializerStatement : public Statement {
+public:
+ ClassFieldInitializerStatement(SourceRange source_range, NonnullRefPtr<Expression> expression, FlyString field_name)
+ : Statement(source_range)
+ , m_expression(move(expression))
+ , m_class_field_identifier_name(move(field_name))
+ {
+ }
+
+ Value execute(Interpreter& interpreter, GlobalObject& global_object) const override
+ {
+ VERIFY(interpreter.vm().argument_count() == 0);
+ VERIFY(!m_class_field_identifier_name.is_empty());
+ return TRY_OR_DISCARD(interpreter.vm().named_evaluation_if_anonymous_function(global_object, m_expression, m_class_field_identifier_name));
+ }
+
+ void dump(int) const override
+ {
+ // This should not be dumped as it is never part of an actual AST.
+ VERIFY_NOT_REACHED();
+ }
+
+private:
+ NonnullRefPtr<Expression> m_expression;
+ FlyString m_class_field_identifier_name; // [[ClassFieldIdentifierName]]
+};
+
// 15.7.10 Runtime Semantics: ClassFieldDefinitionEvaluation, https://tc39.es/ecma262/#sec-runtime-semantics-classfielddefinitionevaluation
ThrowCompletionOr<ClassElement::ClassValue> ClassField::class_element_evaluation(Interpreter& interpreter, GlobalObject& global_object, Object& target) const
{
@@ -1285,7 +1314,6 @@ ThrowCompletionOr<ClassElement::ClassValue> ClassField::class_element_evaluation
ECMAScriptFunctionObject* initializer = nullptr;
if (m_initializer) {
auto copy_initializer = m_initializer;
- auto body = create_ast_node<ExpressionStatement>(m_initializer->source_range(), copy_initializer.release_nonnull());
auto name = property_key.visit(
[&](PropertyName const& property_name) -> String {
return property_name.is_number() ? property_name.to_string() : property_name.to_string_or_symbol().to_display_string();
@@ -1293,8 +1321,10 @@ ThrowCompletionOr<ClassElement::ClassValue> ClassField::class_element_evaluation
[&](PrivateName const& private_name) -> String {
return private_name.description;
});
+
// FIXME: A potential optimization is not creating the functions here since these are never directly accessible.
- initializer = ECMAScriptFunctionObject::create(interpreter.global_object(), name, *body, {}, 0, interpreter.lexical_environment(), interpreter.vm().running_execution_context().private_environment, FunctionKind::Regular, false, false);
+ auto function_code = create_ast_node<ClassFieldInitializerStatement>(m_initializer->source_range(), copy_initializer.release_nonnull(), name);
+ initializer = ECMAScriptFunctionObject::create(interpreter.global_object(), String::empty(), *function_code, {}, 0, interpreter.lexical_environment(), interpreter.vm().running_execution_context().private_environment, FunctionKind::Regular, true, false, m_contains_direct_call_to_eval, false);
initializer->set_home_object(&target);
}
diff --git a/Userland/Libraries/LibJS/AST.h b/Userland/Libraries/LibJS/AST.h
index 64f4773f32..88ef640da4 100644
--- a/Userland/Libraries/LibJS/AST.h
+++ b/Userland/Libraries/LibJS/AST.h
@@ -1085,10 +1085,11 @@ private:
class ClassField final : public ClassElement {
public:
- ClassField(SourceRange source_range, NonnullRefPtr<Expression> key, RefPtr<Expression> init, bool is_static)
+ ClassField(SourceRange source_range, NonnullRefPtr<Expression> key, RefPtr<Expression> init, bool contains_direct_call_to_eval, bool is_static)
: ClassElement(source_range, is_static)
, m_key(move(key))
, m_initializer(move(init))
+ , m_contains_direct_call_to_eval(contains_direct_call_to_eval)
{
}
@@ -1105,6 +1106,7 @@ public:
private:
NonnullRefPtr<Expression> m_key;
RefPtr<Expression> m_initializer;
+ bool m_contains_direct_call_to_eval { false };
};
class StaticInitializer final : public ClassElement {
diff --git a/Userland/Libraries/LibJS/Parser.cpp b/Userland/Libraries/LibJS/Parser.cpp
index 0bd4ca0698..787fc3ff90 100644
--- a/Userland/Libraries/LibJS/Parser.cpp
+++ b/Userland/Libraries/LibJS/Parser.cpp
@@ -102,6 +102,11 @@ public:
return ScopePusher(parser, &node, true);
}
+ static ScopePusher class_field_scope(Parser& parser)
+ {
+ return ScopePusher(parser, nullptr, false);
+ }
+
void add_declaration(NonnullRefPtr<Declaration> declaration)
{
if (declaration->is_lexical_declaration()) {
@@ -1071,16 +1076,20 @@ NonnullRefPtr<ClassExpression> Parser::parse_class_expression(bool expect_class_
syntax_error("Class cannot have field named 'constructor'");
RefPtr<Expression> initializer;
+ bool contains_direct_call_to_eval = false;
if (match(TokenType::Equals)) {
consume();
TemporaryChange super_property_access_rollback(m_state.allow_super_property_lookup, true);
TemporaryChange field_initializer_rollback(m_state.in_class_field_initializer, true);
+
+ auto class_field_scope = ScopePusher::class_field_scope(*this);
initializer = parse_expression(2);
+ contains_direct_call_to_eval = class_field_scope.contains_direct_call_to_eval();
}
- elements.append(create_ast_node<ClassField>({ m_state.current_token.filename(), rule_start.position(), position() }, property_key.release_nonnull(), move(initializer), is_static));
+ elements.append(create_ast_node<ClassField>({ m_state.current_token.filename(), rule_start.position(), position() }, property_key.release_nonnull(), move(initializer), contains_direct_call_to_eval, is_static));
consume_or_insert_semicolon();
}
}
diff --git a/Userland/Libraries/LibJS/Runtime/ECMAScriptFunctionObject.h b/Userland/Libraries/LibJS/Runtime/ECMAScriptFunctionObject.h
index 18dccadda1..ac313c205e 100644
--- a/Userland/Libraries/LibJS/Runtime/ECMAScriptFunctionObject.h
+++ b/Userland/Libraries/LibJS/Runtime/ECMAScriptFunctionObject.h
@@ -78,13 +78,15 @@ public:
protected:
virtual bool is_strict_mode() const final { return m_strict; }
+ virtual Completion ordinary_call_evaluate_body();
+
private:
virtual bool is_ecmascript_function_object() const override { return true; }
virtual void visit_edges(Visitor&) override;
void prepare_for_ordinary_call(ExecutionContext& callee_context, Object* new_target);
void ordinary_call_bind_this(ExecutionContext&, Value this_argument);
- Completion ordinary_call_evaluate_body();
+
ThrowCompletionOr<void> function_declaration_instantiation(Interpreter*);
// Internal Slots of ECMAScript Function Objects, https://tc39.es/ecma262/#table-internal-slots-of-ecmascript-function-objects