1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-07-27 01:27:34 +00:00

LibJS: Update parser to detect if identifier refer a "local" variable

This modification enables the parser to determine whether an identifier
used within a function refers to a local variable or not. In this
context, a local identifier means that it is not captured by any nested
function declaration which means it modified only from inside a
function.

The information about whether identifier is local is stored inside
Identifier AST node and also contains information about the index of
local variable inside a function and information about total number
of local variables used by a function is stored in function nodes.
This commit is contained in:
Aliaksandr Kalenik 2023-07-05 00:14:41 +02:00 committed by Andreas Kling
parent c734f2b5e6
commit 380abddf3c
4 changed files with 270 additions and 99 deletions

View file

@ -312,12 +312,21 @@ public:
ThrowCompletionOr<void> for_each_var_declared_name(ThrowCompletionOrVoidCallback<DeprecatedFlyString const&>&& callback) const;
ThrowCompletionOr<void> for_each_var_function_declaration_in_reverse_order(ThrowCompletionOrVoidCallback<FunctionDeclaration const&>&& callback) const;
ThrowCompletionOr<void> for_each_lexical_function_declaration_in_reverse_order(ThrowCompletionOrVoidCallback<FunctionDeclaration const&>&& callback) const;
ThrowCompletionOr<void> for_each_var_scoped_variable_declaration(ThrowCompletionOrVoidCallback<VariableDeclaration const&>&& callback) const;
void block_declaration_instantiation(VM&, Environment*) const;
ThrowCompletionOr<void> for_each_function_hoistable_with_annexB_extension(ThrowCompletionOrVoidCallback<FunctionDeclaration&>&& callback) const;
Vector<DeprecatedFlyString> const& local_variables_names() const { return m_local_variables_names; }
size_t add_local_variable(DeprecatedFlyString name)
{
auto index = m_local_variables_names.size();
m_local_variables_names.append(name);
return index;
}
protected:
explicit ScopeNode(SourceRange source_range)
: Statement(source_range)
@ -332,6 +341,8 @@ private:
Vector<NonnullRefPtr<Declaration const>> m_var_declarations;
Vector<NonnullRefPtr<FunctionDeclaration const>> m_functions_hoistable_with_annexB_extension;
Vector<DeprecatedFlyString> m_local_variables_names;
};
// ImportEntry Record, https://tc39.es/ecma262/#table-importentry-record-fields
@ -659,6 +670,7 @@ public:
Statement const& body() const { return *m_body; }
Vector<FunctionParameter> const& parameters() const { return m_parameters; };
i32 function_length() const { return m_function_length; }
Vector<DeprecatedFlyString> const& local_variables_names() const { return m_local_variables_names; }
bool is_strict_mode() const { return m_is_strict_mode; }
bool might_need_arguments_object() const { return m_might_need_arguments_object; }
bool contains_direct_call_to_eval() const { return m_contains_direct_call_to_eval; }
@ -666,7 +678,7 @@ public:
FunctionKind kind() const { return m_kind; }
protected:
FunctionNode(DeprecatedFlyString name, DeprecatedString source_text, NonnullRefPtr<Statement const> body, Vector<FunctionParameter> parameters, i32 function_length, FunctionKind kind, bool is_strict_mode, bool might_need_arguments_object, bool contains_direct_call_to_eval, bool is_arrow_function)
FunctionNode(RefPtr<Identifier const> name, DeprecatedString source_text, NonnullRefPtr<Statement const> body, Vector<FunctionParameter> parameters, i32 function_length, FunctionKind kind, bool is_strict_mode, bool might_need_arguments_object, bool contains_direct_call_to_eval, bool is_arrow_function, Vector<DeprecatedFlyString> local_variables_names)
: m_name(move(name))
, m_source_text(move(source_text))
, m_body(move(body))
@ -677,6 +689,7 @@ protected:
, m_might_need_arguments_object(might_need_arguments_object)
, m_contains_direct_call_to_eval(contains_direct_call_to_eval)
, m_is_arrow_function(is_arrow_function)
, m_local_variables_names(local_variables_names)
{
if (m_is_arrow_function)
VERIFY(!m_might_need_arguments_object);
@ -695,6 +708,8 @@ private:
bool m_might_need_arguments_object : 1 { false };
bool m_contains_direct_call_to_eval : 1 { false };
bool m_is_arrow_function : 1 { false };
Vector<DeprecatedFlyString> m_local_variables_names;
};
class FunctionDeclaration final
@ -703,9 +718,9 @@ class FunctionDeclaration final
public:
static bool must_have_name() { return true; }
FunctionDeclaration(SourceRange source_range, DeprecatedFlyString const& name, DeprecatedString source_text, NonnullRefPtr<Statement const> body, Vector<FunctionParameter> parameters, i32 function_length, FunctionKind kind, bool is_strict_mode, bool might_need_arguments_object, bool contains_direct_call_to_eval)
FunctionDeclaration(SourceRange source_range, RefPtr<Identifier const> name, DeprecatedString source_text, NonnullRefPtr<Statement const> body, Vector<FunctionParameter> parameters, i32 function_length, FunctionKind kind, bool is_strict_mode, bool might_need_arguments_object, bool contains_direct_call_to_eval, Vector<DeprecatedFlyString> local_variables_names)
: Declaration(source_range)
, FunctionNode(name, move(source_text), move(body), move(parameters), function_length, kind, is_strict_mode, might_need_arguments_object, contains_direct_call_to_eval, false)
, FunctionNode(name, move(source_text), move(body), move(parameters), function_length, kind, is_strict_mode, might_need_arguments_object, contains_direct_call_to_eval, false, move(local_variables_names))
{
}
@ -729,9 +744,9 @@ class FunctionExpression final
public:
static bool must_have_name() { return false; }
FunctionExpression(SourceRange source_range, DeprecatedFlyString const& name, DeprecatedString source_text, NonnullRefPtr<Statement const> body, Vector<FunctionParameter> parameters, i32 function_length, FunctionKind kind, bool is_strict_mode, bool might_need_arguments_object, bool contains_direct_call_to_eval, bool is_arrow_function = false)
FunctionExpression(SourceRange source_range, RefPtr<Identifier const> name, DeprecatedString source_text, NonnullRefPtr<Statement const> body, Vector<FunctionParameter> parameters, i32 function_length, FunctionKind kind, bool is_strict_mode, bool might_need_arguments_object, bool contains_direct_call_to_eval, Vector<DeprecatedFlyString> local_variables_names, bool is_arrow_function = false)
: Expression(source_range)
, FunctionNode(name, move(source_text), move(body), move(parameters), function_length, kind, is_strict_mode, might_need_arguments_object, contains_direct_call_to_eval, is_arrow_function)
, FunctionNode(name, move(source_text), move(body), move(parameters), function_length, kind, is_strict_mode, might_need_arguments_object, contains_direct_call_to_eval, is_arrow_function, move(local_variables_names))
{
}
@ -1254,6 +1269,14 @@ public:
DeprecatedFlyString const& string() const { return m_string; }
bool is_local() const { return m_local_variable_index.has_value(); }
size_t local_variable_index() const
{
VERIFY(m_local_variable_index.has_value());
return m_local_variable_index.value();
}
void set_local_variable_index(size_t index) { m_local_variable_index = index; }
virtual Completion execute(Interpreter&) const override;
virtual void dump(int indent) const override;
virtual ThrowCompletionOr<Reference> to_reference(Interpreter&) const override;
@ -1264,6 +1287,8 @@ private:
DeprecatedFlyString m_string;
mutable EnvironmentCoordinate m_cached_environment_coordinate;
Optional<size_t> m_local_variable_index;
};
class PrivateIdentifier final : public Expression {