mirror of
https://github.com/RGBCube/serenity
synced 2025-05-15 07:34:59 +00:00
LibJS: Remove hand-rolled type information in JS AST in favor of RTTI
This commit is contained in:
parent
07dd73c351
commit
db790dda62
5 changed files with 44 additions and 67 deletions
|
@ -130,21 +130,21 @@ CallExpression::ThisAndCallee CallExpression::compute_this_and_callee(Interprete
|
||||||
{
|
{
|
||||||
auto& vm = interpreter.vm();
|
auto& vm = interpreter.vm();
|
||||||
|
|
||||||
if (is_new_expression()) {
|
if (is<NewExpression>(*this)) {
|
||||||
// Computing |this| is irrelevant for "new" expression.
|
// Computing |this| is irrelevant for "new" expression.
|
||||||
return { js_undefined(), m_callee->execute(interpreter, global_object) };
|
return { js_undefined(), m_callee->execute(interpreter, global_object) };
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_callee->is_super_expression()) {
|
if (is<SuperExpression>(*m_callee)) {
|
||||||
// If we are calling super, |this| has not been initialized yet, and would not be meaningful to provide.
|
// If we are calling super, |this| has not been initialized yet, and would not be meaningful to provide.
|
||||||
auto new_target = vm.get_new_target();
|
auto new_target = vm.get_new_target();
|
||||||
ASSERT(new_target.is_function());
|
ASSERT(new_target.is_function());
|
||||||
return { js_undefined(), new_target };
|
return { js_undefined(), new_target };
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_callee->is_member_expression()) {
|
if (is<MemberExpression>(*m_callee)) {
|
||||||
auto& member_expression = static_cast<const MemberExpression&>(*m_callee);
|
auto& member_expression = static_cast<const MemberExpression&>(*m_callee);
|
||||||
bool is_super_property_lookup = member_expression.object().is_super_expression();
|
bool is_super_property_lookup = is<SuperExpression>(member_expression.object());
|
||||||
auto lookup_target = is_super_property_lookup ? interpreter.current_environment()->get_super_base() : member_expression.object().execute(interpreter, global_object);
|
auto lookup_target = is_super_property_lookup ? interpreter.current_environment()->get_super_base() : member_expression.object().execute(interpreter, global_object);
|
||||||
if (vm.exception())
|
if (vm.exception())
|
||||||
return {};
|
return {};
|
||||||
|
@ -178,12 +178,12 @@ Value CallExpression::execute(Interpreter& interpreter, GlobalObject& global_obj
|
||||||
ASSERT(!callee.is_empty());
|
ASSERT(!callee.is_empty());
|
||||||
|
|
||||||
if (!callee.is_function()
|
if (!callee.is_function()
|
||||||
|| (is_new_expression() && (is<NativeFunction>(callee.as_object()) && !static_cast<NativeFunction&>(callee.as_object()).has_constructor()))) {
|
|| (is<NewExpression>(*this) && (is<NativeFunction>(callee.as_object()) && !static_cast<NativeFunction&>(callee.as_object()).has_constructor()))) {
|
||||||
String error_message;
|
String error_message;
|
||||||
auto call_type = is_new_expression() ? "constructor" : "function";
|
auto call_type = is<NewExpression>(*this) ? "constructor" : "function";
|
||||||
if (m_callee->is_identifier() || m_callee->is_member_expression()) {
|
if (is<Identifier>(*m_callee) || is<MemberExpression>(*m_callee)) {
|
||||||
String expression_string;
|
String expression_string;
|
||||||
if (m_callee->is_identifier()) {
|
if (is<Identifier>(*m_callee)) {
|
||||||
expression_string = static_cast<const Identifier&>(*m_callee).string();
|
expression_string = static_cast<const Identifier&>(*m_callee).string();
|
||||||
} else {
|
} else {
|
||||||
expression_string = static_cast<const MemberExpression&>(*m_callee).to_string_approximation();
|
expression_string = static_cast<const MemberExpression&>(*m_callee).to_string_approximation();
|
||||||
|
@ -220,11 +220,11 @@ 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<NewExpression>(*this)) {
|
||||||
result = vm.construct(function, function, move(arguments), global_object);
|
result = 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 (is<SuperExpression>(*m_callee)) {
|
||||||
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()) {
|
||||||
|
@ -243,7 +243,7 @@ Value CallExpression::execute(Interpreter& interpreter, GlobalObject& global_obj
|
||||||
if (vm.exception())
|
if (vm.exception())
|
||||||
return {};
|
return {};
|
||||||
|
|
||||||
if (is_new_expression()) {
|
if (is<NewExpression>(*this)) {
|
||||||
if (result.is_object())
|
if (result.is_object())
|
||||||
return result;
|
return result;
|
||||||
return new_object;
|
return new_object;
|
||||||
|
@ -371,7 +371,7 @@ Value ForStatement::execute(Interpreter& interpreter, GlobalObject& global_objec
|
||||||
|
|
||||||
RefPtr<BlockStatement> wrapper;
|
RefPtr<BlockStatement> wrapper;
|
||||||
|
|
||||||
if (m_init && m_init->is_variable_declaration() && static_cast<const VariableDeclaration*>(m_init.ptr())->declaration_kind() != DeclarationKind::Var) {
|
if (m_init && is<VariableDeclaration>(*m_init) && static_cast<const VariableDeclaration&>(*m_init).declaration_kind() != DeclarationKind::Var) {
|
||||||
wrapper = create_ast_node<BlockStatement>(source_range());
|
wrapper = create_ast_node<BlockStatement>(source_range());
|
||||||
NonnullRefPtrVector<VariableDeclaration> decls;
|
NonnullRefPtrVector<VariableDeclaration> decls;
|
||||||
decls.append(*static_cast<const VariableDeclaration*>(m_init.ptr()));
|
decls.append(*static_cast<const VariableDeclaration*>(m_init.ptr()));
|
||||||
|
@ -444,20 +444,20 @@ Value ForStatement::execute(Interpreter& interpreter, GlobalObject& global_objec
|
||||||
return last_value;
|
return last_value;
|
||||||
}
|
}
|
||||||
|
|
||||||
static FlyString variable_from_for_declaration(Interpreter& interpreter, GlobalObject& global_object, NonnullRefPtr<ASTNode> node, RefPtr<BlockStatement> wrapper)
|
static FlyString variable_from_for_declaration(Interpreter& interpreter, GlobalObject& global_object, const ASTNode& node, RefPtr<BlockStatement> wrapper)
|
||||||
{
|
{
|
||||||
FlyString variable_name;
|
FlyString variable_name;
|
||||||
if (node->is_variable_declaration()) {
|
if (is<VariableDeclaration>(node)) {
|
||||||
auto* variable_declaration = static_cast<const VariableDeclaration*>(node.ptr());
|
auto& variable_declaration = static_cast<const VariableDeclaration&>(node);
|
||||||
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>(node->source_range());
|
wrapper = create_ast_node<BlockStatement>(node.source_range());
|
||||||
interpreter.enter_scope(*wrapper, ScopeType::Block, global_object);
|
interpreter.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();
|
||||||
} else if (node->is_identifier()) {
|
} else if (is<Identifier>(node)) {
|
||||||
variable_name = static_cast<const Identifier&>(*node).string();
|
variable_name = static_cast<const Identifier&>(node).string();
|
||||||
} else {
|
} else {
|
||||||
ASSERT_NOT_REACHED();
|
ASSERT_NOT_REACHED();
|
||||||
}
|
}
|
||||||
|
@ -469,7 +469,7 @@ Value ForInStatement::execute(Interpreter& interpreter, GlobalObject& global_obj
|
||||||
interpreter.enter_node(*this);
|
interpreter.enter_node(*this);
|
||||||
ScopeGuard exit_node { [&] { interpreter.exit_node(*this); } };
|
ScopeGuard exit_node { [&] { interpreter.exit_node(*this); } };
|
||||||
|
|
||||||
if (!m_lhs->is_variable_declaration() && !m_lhs->is_identifier()) {
|
if (!is<VariableDeclaration>(*m_lhs) && !is<Identifier>(*m_lhs)) {
|
||||||
// FIXME: Implement "for (foo.bar in baz)", "for (foo[0] in bar)"
|
// FIXME: Implement "for (foo.bar in baz)", "for (foo[0] in bar)"
|
||||||
ASSERT_NOT_REACHED();
|
ASSERT_NOT_REACHED();
|
||||||
}
|
}
|
||||||
|
@ -516,7 +516,7 @@ Value ForOfStatement::execute(Interpreter& interpreter, GlobalObject& global_obj
|
||||||
interpreter.enter_node(*this);
|
interpreter.enter_node(*this);
|
||||||
ScopeGuard exit_node { [&] { interpreter.exit_node(*this); } };
|
ScopeGuard exit_node { [&] { interpreter.exit_node(*this); } };
|
||||||
|
|
||||||
if (!m_lhs->is_variable_declaration() && !m_lhs->is_identifier()) {
|
if (!is<VariableDeclaration>(*m_lhs) && !is<Identifier>(*m_lhs)) {
|
||||||
// FIXME: Implement "for (foo.bar of baz)", "for (foo[0] of bar)"
|
// FIXME: Implement "for (foo.bar of baz)", "for (foo[0] of bar)"
|
||||||
ASSERT_NOT_REACHED();
|
ASSERT_NOT_REACHED();
|
||||||
}
|
}
|
||||||
|
@ -700,7 +700,7 @@ Value UnaryExpression::execute(Interpreter& interpreter, GlobalObject& global_ob
|
||||||
}
|
}
|
||||||
|
|
||||||
Value lhs_result;
|
Value lhs_result;
|
||||||
if (m_op == UnaryOp::Typeof && m_lhs->is_identifier()) {
|
if (m_op == UnaryOp::Typeof && is<Identifier>(*m_lhs)) {
|
||||||
auto reference = m_lhs->to_reference(interpreter, global_object);
|
auto reference = m_lhs->to_reference(interpreter, global_object);
|
||||||
if (interpreter.exception()) {
|
if (interpreter.exception()) {
|
||||||
return {};
|
return {};
|
||||||
|
@ -1052,7 +1052,7 @@ void UnaryExpression::dump(int indent) const
|
||||||
void CallExpression::dump(int indent) const
|
void CallExpression::dump(int indent) const
|
||||||
{
|
{
|
||||||
print_indent(indent);
|
print_indent(indent);
|
||||||
if (is_new_expression())
|
if (is<NewExpression>(*this))
|
||||||
outln("CallExpression [new]");
|
outln("CallExpression [new]");
|
||||||
else
|
else
|
||||||
outln("CallExpression");
|
outln("CallExpression");
|
||||||
|
@ -1744,7 +1744,7 @@ void MemberExpression::dump(int indent) const
|
||||||
PropertyName MemberExpression::computed_property_name(Interpreter& interpreter, GlobalObject& global_object) const
|
PropertyName MemberExpression::computed_property_name(Interpreter& interpreter, GlobalObject& global_object) const
|
||||||
{
|
{
|
||||||
if (!is_computed()) {
|
if (!is_computed()) {
|
||||||
ASSERT(m_property->is_identifier());
|
ASSERT(is<Identifier>(*m_property));
|
||||||
return static_cast<const Identifier&>(*m_property).string();
|
return static_cast<const Identifier&>(*m_property).string();
|
||||||
}
|
}
|
||||||
auto value = m_property->execute(interpreter, global_object);
|
auto value = m_property->execute(interpreter, global_object);
|
||||||
|
@ -1757,11 +1757,11 @@ PropertyName MemberExpression::computed_property_name(Interpreter& interpreter,
|
||||||
String MemberExpression::to_string_approximation() const
|
String MemberExpression::to_string_approximation() const
|
||||||
{
|
{
|
||||||
String object_string = "<object>";
|
String object_string = "<object>";
|
||||||
if (m_object->is_identifier())
|
if (is<Identifier>(*m_object))
|
||||||
object_string = static_cast<const Identifier&>(*m_object).string();
|
object_string = static_cast<const Identifier&>(*m_object).string();
|
||||||
if (is_computed())
|
if (is_computed())
|
||||||
return String::formatted("{}[<computed>]", object_string);
|
return String::formatted("{}[<computed>]", object_string);
|
||||||
ASSERT(m_property->is_identifier());
|
ASSERT(is<Identifier>(*m_property));
|
||||||
return String::formatted("{}.{}", object_string, static_cast<const Identifier&>(*m_property).string());
|
return String::formatted("{}.{}", object_string, static_cast<const Identifier&>(*m_property).string());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1887,7 +1887,7 @@ Value ArrayExpression::execute(Interpreter& interpreter, GlobalObject& global_ob
|
||||||
if (interpreter.exception())
|
if (interpreter.exception())
|
||||||
return {};
|
return {};
|
||||||
|
|
||||||
if (element->is_spread_expression()) {
|
if (is<SpreadExpression>(*element)) {
|
||||||
get_iterator_values(global_object, value, [&](Value iterator_value) {
|
get_iterator_values(global_object, value, [&](Value iterator_value) {
|
||||||
array->indexed_properties().append(iterator_value);
|
array->indexed_properties().append(iterator_value);
|
||||||
return IterationDecision::Continue;
|
return IterationDecision::Continue;
|
||||||
|
|
|
@ -56,17 +56,6 @@ public:
|
||||||
virtual const char* class_name() const = 0;
|
virtual const char* class_name() const = 0;
|
||||||
virtual Value execute(Interpreter&, GlobalObject&) const = 0;
|
virtual Value execute(Interpreter&, GlobalObject&) const = 0;
|
||||||
virtual void dump(int indent) const;
|
virtual void dump(int indent) const;
|
||||||
virtual bool is_identifier() const { return false; }
|
|
||||||
virtual bool is_spread_expression() const { return false; }
|
|
||||||
virtual bool is_member_expression() const { return false; }
|
|
||||||
virtual bool is_scope_node() const { return false; }
|
|
||||||
virtual bool is_program() const { return false; }
|
|
||||||
virtual bool is_variable_declaration() const { return false; }
|
|
||||||
virtual bool is_call_expression() const { return false; }
|
|
||||||
virtual bool is_new_expression() const { return false; }
|
|
||||||
virtual bool is_super_expression() const { return false; }
|
|
||||||
virtual bool is_expression_statement() const { return false; };
|
|
||||||
virtual bool is_string_literal() const { return false; };
|
|
||||||
|
|
||||||
const SourceRange& source_range() const { return m_source_range; }
|
const SourceRange& source_range() const { return m_source_range; }
|
||||||
SourceRange& source_range() { return m_source_range; }
|
SourceRange& source_range() { return m_source_range; }
|
||||||
|
@ -125,7 +114,6 @@ public:
|
||||||
|
|
||||||
virtual Value execute(Interpreter&, GlobalObject&) const override;
|
virtual Value execute(Interpreter&, GlobalObject&) const override;
|
||||||
virtual void dump(int indent) const override;
|
virtual void dump(int indent) const override;
|
||||||
virtual bool is_expression_statement() const override { return true; }
|
|
||||||
|
|
||||||
const Expression& expression() const { return m_expression; };
|
const Expression& expression() const { return m_expression; };
|
||||||
|
|
||||||
|
@ -165,7 +153,6 @@ protected:
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
virtual bool is_scope_node() const final { return true; }
|
|
||||||
NonnullRefPtrVector<Statement> m_children;
|
NonnullRefPtrVector<Statement> m_children;
|
||||||
NonnullRefPtrVector<VariableDeclaration> m_variables;
|
NonnullRefPtrVector<VariableDeclaration> m_variables;
|
||||||
NonnullRefPtrVector<FunctionDeclaration> m_functions;
|
NonnullRefPtrVector<FunctionDeclaration> m_functions;
|
||||||
|
@ -186,7 +173,6 @@ public:
|
||||||
private:
|
private:
|
||||||
bool m_is_strict_mode { false };
|
bool m_is_strict_mode { false };
|
||||||
|
|
||||||
virtual bool is_program() const override { return true; }
|
|
||||||
virtual const char* class_name() const override { return "Program"; }
|
virtual const char* class_name() const override { return "Program"; }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -695,7 +681,6 @@ public:
|
||||||
|
|
||||||
virtual Value execute(Interpreter&, GlobalObject&) const override;
|
virtual Value execute(Interpreter&, GlobalObject&) const override;
|
||||||
virtual void dump(int indent) const override;
|
virtual void dump(int indent) const override;
|
||||||
virtual bool is_string_literal() const override { return true; };
|
|
||||||
|
|
||||||
StringView value() const { return m_value; }
|
StringView value() const { return m_value; }
|
||||||
bool is_use_strict_directive() const { return m_is_use_strict_directive; };
|
bool is_use_strict_directive() const { return m_is_use_strict_directive; };
|
||||||
|
@ -755,7 +740,6 @@ public:
|
||||||
|
|
||||||
virtual Value execute(Interpreter&, GlobalObject&) const override;
|
virtual Value execute(Interpreter&, GlobalObject&) const override;
|
||||||
virtual void dump(int indent) const override;
|
virtual void dump(int indent) const override;
|
||||||
virtual bool is_identifier() const override { return true; }
|
|
||||||
virtual Reference to_reference(Interpreter&, GlobalObject&) const override;
|
virtual Reference to_reference(Interpreter&, GlobalObject&) const override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -808,7 +792,6 @@ public:
|
||||||
virtual void dump(int indent) const override;
|
virtual void dump(int indent) const override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
virtual bool is_super_expression() const override { return true; }
|
|
||||||
virtual const char* class_name() const override { return "SuperExpression"; }
|
virtual const char* class_name() const override { return "SuperExpression"; }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -863,7 +846,6 @@ public:
|
||||||
|
|
||||||
virtual Value execute(Interpreter&, GlobalObject&) const override;
|
virtual Value execute(Interpreter&, GlobalObject&) const override;
|
||||||
virtual void dump(int indent) const override;
|
virtual void dump(int indent) const override;
|
||||||
virtual bool is_spread_expression() const override { return true; }
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
virtual const char* class_name() const override { return "SpreadExpression"; }
|
virtual const char* class_name() const override { return "SpreadExpression"; }
|
||||||
|
@ -903,7 +885,6 @@ public:
|
||||||
|
|
||||||
private:
|
private:
|
||||||
virtual const char* class_name() const override { return "CallExpression"; }
|
virtual const char* class_name() const override { return "CallExpression"; }
|
||||||
virtual bool is_call_expression() const override { return true; }
|
|
||||||
|
|
||||||
struct ThisAndCallee {
|
struct ThisAndCallee {
|
||||||
Value this_value;
|
Value this_value;
|
||||||
|
@ -924,8 +905,6 @@ public:
|
||||||
|
|
||||||
private:
|
private:
|
||||||
virtual const char* class_name() const override { return "NewExpression"; }
|
virtual const char* class_name() const override { return "NewExpression"; }
|
||||||
virtual bool is_call_expression() const override { return false; }
|
|
||||||
virtual bool is_new_expression() const override { return true; }
|
|
||||||
};
|
};
|
||||||
|
|
||||||
enum class AssignmentOp {
|
enum class AssignmentOp {
|
||||||
|
@ -1037,7 +1016,6 @@ public:
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual bool is_variable_declaration() const override { return true; }
|
|
||||||
DeclarationKind declaration_kind() const { return m_declaration_kind; }
|
DeclarationKind declaration_kind() const { return m_declaration_kind; }
|
||||||
|
|
||||||
virtual Value execute(Interpreter&, GlobalObject&) const override;
|
virtual Value execute(Interpreter&, GlobalObject&) const override;
|
||||||
|
@ -1198,7 +1176,6 @@ public:
|
||||||
String to_string_approximation() const;
|
String to_string_approximation() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
virtual bool is_member_expression() const override { return true; }
|
|
||||||
virtual const char* class_name() const override { return "MemberExpression"; }
|
virtual const char* class_name() const override { return "MemberExpression"; }
|
||||||
|
|
||||||
NonnullRefPtr<Expression> m_object;
|
NonnullRefPtr<Expression> m_object;
|
||||||
|
|
|
@ -107,7 +107,7 @@ void Interpreter::enter_scope(const ScopeNode& scope_node, ScopeType scope_type,
|
||||||
|
|
||||||
for (auto& declaration : scope_node.variables()) {
|
for (auto& declaration : scope_node.variables()) {
|
||||||
for (auto& declarator : declaration.declarations()) {
|
for (auto& declarator : declaration.declarations()) {
|
||||||
if (scope_node.is_program()) {
|
if (is<Program>(scope_node)) {
|
||||||
global_object.put(declarator.id().string(), js_undefined());
|
global_object.put(declarator.id().string(), js_undefined());
|
||||||
if (exception())
|
if (exception())
|
||||||
return;
|
return;
|
||||||
|
@ -160,7 +160,7 @@ void Interpreter::push_scope(ScopeFrame frame)
|
||||||
|
|
||||||
Value Interpreter::execute_statement(GlobalObject& global_object, const Statement& statement, ScopeType scope_type)
|
Value Interpreter::execute_statement(GlobalObject& global_object, const Statement& statement, ScopeType scope_type)
|
||||||
{
|
{
|
||||||
if (!statement.is_scope_node())
|
if (!is<ScopeNode>(statement))
|
||||||
return statement.execute(*this, global_object);
|
return statement.execute(*this, global_object);
|
||||||
|
|
||||||
auto& block = static_cast<const ScopeNode&>(statement);
|
auto& block = static_cast<const ScopeNode&>(statement);
|
||||||
|
|
|
@ -35,11 +35,11 @@ namespace JS {
|
||||||
|
|
||||||
static bool statement_is_use_strict_directive(NonnullRefPtr<Statement> statement)
|
static bool statement_is_use_strict_directive(NonnullRefPtr<Statement> statement)
|
||||||
{
|
{
|
||||||
if (!statement->is_expression_statement())
|
if (!is<ExpressionStatement>(*statement))
|
||||||
return false;
|
return false;
|
||||||
auto& expression_statement = static_cast<ExpressionStatement&>(*statement);
|
auto& expression_statement = static_cast<ExpressionStatement&>(*statement);
|
||||||
auto& expression = expression_statement.expression();
|
auto& expression = expression_statement.expression();
|
||||||
if (!expression.is_string_literal())
|
if (!is<StringLiteral>(expression))
|
||||||
return false;
|
return false;
|
||||||
return static_cast<const StringLiteral&>(expression).is_use_strict_directive();
|
return static_cast<const StringLiteral&>(expression).is_use_strict_directive();
|
||||||
}
|
}
|
||||||
|
@ -711,7 +711,7 @@ NonnullRefPtr<Expression> Parser::parse_unary_prefixed_expression()
|
||||||
auto rhs = parse_expression(precedence, associativity);
|
auto rhs = parse_expression(precedence, associativity);
|
||||||
// FIXME: Apparently for functions this should also not be enforced on a parser level,
|
// FIXME: Apparently for functions this should also not be enforced on a parser level,
|
||||||
// other engines throw ReferenceError for ++foo()
|
// other engines throw ReferenceError for ++foo()
|
||||||
if (!rhs->is_identifier() && !rhs->is_member_expression())
|
if (!is<Identifier>(*rhs) && !is<MemberExpression>(*rhs))
|
||||||
syntax_error(String::formatted("Right-hand side of prefix increment operator must be identifier or member expression, got {}", rhs->class_name()), rhs_start);
|
syntax_error(String::formatted("Right-hand side of prefix increment operator must be identifier or member expression, got {}", rhs->class_name()), rhs_start);
|
||||||
return create_ast_node<UpdateExpression>({ rule_start.position(), position() }, UpdateOp::Increment, move(rhs), true);
|
return create_ast_node<UpdateExpression>({ rule_start.position(), position() }, UpdateOp::Increment, move(rhs), true);
|
||||||
}
|
}
|
||||||
|
@ -721,7 +721,7 @@ NonnullRefPtr<Expression> Parser::parse_unary_prefixed_expression()
|
||||||
auto rhs = parse_expression(precedence, associativity);
|
auto rhs = parse_expression(precedence, associativity);
|
||||||
// FIXME: Apparently for functions this should also not be enforced on a parser level,
|
// FIXME: Apparently for functions this should also not be enforced on a parser level,
|
||||||
// other engines throw ReferenceError for --foo()
|
// other engines throw ReferenceError for --foo()
|
||||||
if (!rhs->is_identifier() && !rhs->is_member_expression())
|
if (!is<Identifier>(*rhs) && !is<MemberExpression>(*rhs))
|
||||||
syntax_error(String::formatted("Right-hand side of prefix decrement operator must be identifier or member expression, got {}", rhs->class_name()), rhs_start);
|
syntax_error(String::formatted("Right-hand side of prefix decrement operator must be identifier or member expression, got {}", rhs->class_name()), rhs_start);
|
||||||
return create_ast_node<UpdateExpression>({ rule_start.position(), position() }, UpdateOp::Decrement, move(rhs), true);
|
return create_ast_node<UpdateExpression>({ rule_start.position(), position() }, UpdateOp::Decrement, move(rhs), true);
|
||||||
}
|
}
|
||||||
|
@ -1120,14 +1120,14 @@ NonnullRefPtr<Expression> Parser::parse_secondary_expression(NonnullRefPtr<Expre
|
||||||
case TokenType::PlusPlus:
|
case TokenType::PlusPlus:
|
||||||
// FIXME: Apparently for functions this should also not be enforced on a parser level,
|
// FIXME: Apparently for functions this should also not be enforced on a parser level,
|
||||||
// other engines throw ReferenceError for foo()++
|
// other engines throw ReferenceError for foo()++
|
||||||
if (!lhs->is_identifier() && !lhs->is_member_expression())
|
if (!is<Identifier>(*lhs) && !is<MemberExpression>(*lhs))
|
||||||
syntax_error(String::formatted("Left-hand side of postfix increment operator must be identifier or member expression, got {}", lhs->class_name()));
|
syntax_error(String::formatted("Left-hand side of postfix increment operator must be identifier or member expression, got {}", lhs->class_name()));
|
||||||
consume();
|
consume();
|
||||||
return create_ast_node<UpdateExpression>({ rule_start.position(), position() }, UpdateOp::Increment, move(lhs));
|
return create_ast_node<UpdateExpression>({ rule_start.position(), position() }, UpdateOp::Increment, move(lhs));
|
||||||
case TokenType::MinusMinus:
|
case TokenType::MinusMinus:
|
||||||
// FIXME: Apparently for functions this should also not be enforced on a parser level,
|
// FIXME: Apparently for functions this should also not be enforced on a parser level,
|
||||||
// other engines throw ReferenceError for foo()--
|
// other engines throw ReferenceError for foo()--
|
||||||
if (!lhs->is_identifier() && !lhs->is_member_expression())
|
if (!is<Identifier>(*lhs) && !is<MemberExpression>(*lhs))
|
||||||
syntax_error(String::formatted("Left-hand side of postfix increment operator must be identifier or member expression, got {}", lhs->class_name()));
|
syntax_error(String::formatted("Left-hand side of postfix increment operator must be identifier or member expression, got {}", lhs->class_name()));
|
||||||
consume();
|
consume();
|
||||||
return create_ast_node<UpdateExpression>({ rule_start.position(), position() }, UpdateOp::Decrement, move(lhs));
|
return create_ast_node<UpdateExpression>({ rule_start.position(), position() }, UpdateOp::Decrement, move(lhs));
|
||||||
|
@ -1175,13 +1175,13 @@ NonnullRefPtr<AssignmentExpression> Parser::parse_assignment_expression(Assignme
|
||||||
|| match(TokenType::DoublePipeEquals)
|
|| match(TokenType::DoublePipeEquals)
|
||||||
|| match(TokenType::DoubleQuestionMarkEquals));
|
|| match(TokenType::DoubleQuestionMarkEquals));
|
||||||
consume();
|
consume();
|
||||||
if (!lhs->is_identifier() && !lhs->is_member_expression() && !lhs->is_call_expression()) {
|
if (!is<Identifier>(*lhs) && !is<MemberExpression>(*lhs) && !is<CallExpression>(*lhs)) {
|
||||||
syntax_error("Invalid left-hand side in assignment");
|
syntax_error("Invalid left-hand side in assignment");
|
||||||
} else if (m_parser_state.m_strict_mode && lhs->is_identifier()) {
|
} else if (m_parser_state.m_strict_mode && is<Identifier>(*lhs)) {
|
||||||
auto name = static_cast<const Identifier&>(*lhs).string();
|
auto name = static_cast<const Identifier&>(*lhs).string();
|
||||||
if (name == "eval" || name == "arguments")
|
if (name == "eval" || name == "arguments")
|
||||||
syntax_error(String::formatted("'{}' cannot be assigned to in strict mode code", name));
|
syntax_error(String::formatted("'{}' cannot be assigned to in strict mode code", name));
|
||||||
} else if (m_parser_state.m_strict_mode && lhs->is_call_expression()) {
|
} else if (m_parser_state.m_strict_mode && is<CallExpression>(*lhs)) {
|
||||||
syntax_error("Cannot assign to function call");
|
syntax_error("Cannot assign to function call");
|
||||||
}
|
}
|
||||||
return create_ast_node<AssignmentExpression>({ rule_start.position(), position() }, assignment_op, move(lhs), parse_expression(min_precedence, associativity));
|
return create_ast_node<AssignmentExpression>({ rule_start.position(), position() }, assignment_op, move(lhs), parse_expression(min_precedence, associativity));
|
||||||
|
@ -1190,7 +1190,7 @@ NonnullRefPtr<AssignmentExpression> Parser::parse_assignment_expression(Assignme
|
||||||
NonnullRefPtr<CallExpression> Parser::parse_call_expression(NonnullRefPtr<Expression> lhs)
|
NonnullRefPtr<CallExpression> Parser::parse_call_expression(NonnullRefPtr<Expression> lhs)
|
||||||
{
|
{
|
||||||
auto rule_start = push_start();
|
auto rule_start = push_start();
|
||||||
if (!m_parser_state.m_allow_super_constructor_call && lhs->is_super_expression())
|
if (!m_parser_state.m_allow_super_constructor_call && is<SuperExpression>(*lhs))
|
||||||
syntax_error("'super' keyword unexpected here");
|
syntax_error("'super' keyword unexpected here");
|
||||||
|
|
||||||
consume(TokenType::ParenOpen);
|
consume(TokenType::ParenOpen);
|
||||||
|
@ -1777,7 +1777,7 @@ NonnullRefPtr<Statement> Parser::parse_for_statement()
|
||||||
NonnullRefPtr<Statement> Parser::parse_for_in_of_statement(NonnullRefPtr<ASTNode> lhs)
|
NonnullRefPtr<Statement> Parser::parse_for_in_of_statement(NonnullRefPtr<ASTNode> lhs)
|
||||||
{
|
{
|
||||||
auto rule_start = push_start();
|
auto rule_start = push_start();
|
||||||
if (lhs->is_variable_declaration()) {
|
if (is<VariableDeclaration>(*lhs)) {
|
||||||
auto declarations = static_cast<VariableDeclaration&>(*lhs).declarations();
|
auto declarations = static_cast<VariableDeclaration&>(*lhs).declarations();
|
||||||
if (declarations.size() > 1)
|
if (declarations.size() > 1)
|
||||||
syntax_error("multiple declarations not allowed in for..in/of");
|
syntax_error("multiple declarations not allowed in for..in/of");
|
||||||
|
|
|
@ -94,7 +94,7 @@ LexicalEnvironment* ScriptFunction::create_environment()
|
||||||
variables.set(parameter.name, { js_undefined(), DeclarationKind::Var });
|
variables.set(parameter.name, { js_undefined(), DeclarationKind::Var });
|
||||||
}
|
}
|
||||||
|
|
||||||
if (body().is_scope_node()) {
|
if (is<ScopeNode>(body())) {
|
||||||
for (auto& declaration : static_cast<const ScopeNode&>(body()).variables()) {
|
for (auto& declaration : static_cast<const ScopeNode&>(body()).variables()) {
|
||||||
for (auto& declarator : declaration.declarations()) {
|
for (auto& declarator : declaration.declarations()) {
|
||||||
variables.set(declarator.id().string(), { js_undefined(), DeclarationKind::Var });
|
variables.set(declarator.id().string(), { js_undefined(), DeclarationKind::Var });
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue