mirror of
https://github.com/RGBCube/serenity
synced 2025-07-25 19:07:35 +00:00
LibJS: Don't hoist functions under certain circumstances
When a lexical declaration with the same name as a function exists, the function is not hoisted (annex B).
This commit is contained in:
parent
c194afd17c
commit
3411d50737
4 changed files with 45 additions and 8 deletions
|
@ -2377,9 +2377,9 @@ void ScopeNode::add_functions(NonnullRefPtrVector<FunctionDeclaration> functions
|
||||||
m_functions.extend(move(functions));
|
m_functions.extend(move(functions));
|
||||||
}
|
}
|
||||||
|
|
||||||
void ScopeNode::add_hoisted_functions(NonnullRefPtrVector<FunctionDeclaration> hoisted_functions)
|
void ScopeNode::add_hoisted_function(NonnullRefPtr<FunctionDeclaration> hoisted_function)
|
||||||
{
|
{
|
||||||
m_hoisted_functions.extend(move(hoisted_functions));
|
m_hoisted_functions.append(hoisted_function);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -145,7 +145,7 @@ public:
|
||||||
|
|
||||||
void add_variables(NonnullRefPtrVector<VariableDeclaration>);
|
void add_variables(NonnullRefPtrVector<VariableDeclaration>);
|
||||||
void add_functions(NonnullRefPtrVector<FunctionDeclaration>);
|
void add_functions(NonnullRefPtrVector<FunctionDeclaration>);
|
||||||
void add_hoisted_functions(NonnullRefPtrVector<FunctionDeclaration>);
|
void add_hoisted_function(NonnullRefPtr<FunctionDeclaration>);
|
||||||
NonnullRefPtrVector<VariableDeclaration> const& variables() const { return m_variables; }
|
NonnullRefPtrVector<VariableDeclaration> const& variables() const { return m_variables; }
|
||||||
NonnullRefPtrVector<FunctionDeclaration> const& functions() const { return m_functions; }
|
NonnullRefPtrVector<FunctionDeclaration> const& functions() const { return m_functions; }
|
||||||
NonnullRefPtrVector<FunctionDeclaration> const& hoisted_functions() const { return m_hoisted_functions; }
|
NonnullRefPtrVector<FunctionDeclaration> const& hoisted_functions() const { return m_hoisted_functions; }
|
||||||
|
|
|
@ -64,7 +64,24 @@ public:
|
||||||
scope_node->add_variables(m_parser.m_state.let_scopes.last());
|
scope_node->add_variables(m_parser.m_state.let_scopes.last());
|
||||||
|
|
||||||
scope_node->add_functions(m_parser.m_state.current_scope->function_declarations);
|
scope_node->add_functions(m_parser.m_state.current_scope->function_declarations);
|
||||||
scope_node->add_hoisted_functions(m_parser.m_state.current_scope->hoisted_function_declarations);
|
|
||||||
|
for (auto& hoistable_function : m_parser.m_state.current_scope->hoisted_function_declarations) {
|
||||||
|
if (is_hoistable(hoistable_function)) {
|
||||||
|
scope_node->add_hoisted_function(hoistable_function.declaration);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool is_hoistable(Parser::Scope::HoistableDeclaration& declaration)
|
||||||
|
{
|
||||||
|
auto& name = declaration.declaration->name();
|
||||||
|
// See if we find any conflicting lexical declaration on the way up
|
||||||
|
for (RefPtr<Parser::Scope> scope = declaration.scope; !scope.is_null(); scope = scope->parent) {
|
||||||
|
if (scope->lexical_declarations.contains(name)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
Parser& m_parser;
|
Parser& m_parser;
|
||||||
|
@ -304,7 +321,8 @@ NonnullRefPtr<Declaration> Parser::parse_declaration()
|
||||||
case TokenType::Function: {
|
case TokenType::Function: {
|
||||||
auto declaration = parse_function_node<FunctionDeclaration>();
|
auto declaration = parse_function_node<FunctionDeclaration>();
|
||||||
m_state.current_scope->function_declarations.append(declaration);
|
m_state.current_scope->function_declarations.append(declaration);
|
||||||
m_state.current_scope->get_current_function_scope()->hoisted_function_declarations.append(declaration);
|
auto hoisting_target = m_state.current_scope->get_current_function_scope();
|
||||||
|
hoisting_target->hoisted_function_declarations.append({ declaration, *m_state.current_scope });
|
||||||
return declaration;
|
return declaration;
|
||||||
}
|
}
|
||||||
case TokenType::Let:
|
case TokenType::Let:
|
||||||
|
@ -1760,10 +1778,23 @@ NonnullRefPtr<VariableDeclaration> Parser::parse_variable_declaration(bool for_l
|
||||||
consume_or_insert_semicolon();
|
consume_or_insert_semicolon();
|
||||||
|
|
||||||
auto declaration = create_ast_node<VariableDeclaration>({ m_state.current_token.filename(), rule_start.position(), position() }, declaration_kind, move(declarations));
|
auto declaration = create_ast_node<VariableDeclaration>({ m_state.current_token.filename(), rule_start.position(), position() }, declaration_kind, move(declarations));
|
||||||
if (declaration_kind == DeclarationKind::Var)
|
if (declaration_kind == DeclarationKind::Var) {
|
||||||
m_state.var_scopes.last().append(declaration);
|
m_state.var_scopes.last().append(declaration);
|
||||||
else
|
} else {
|
||||||
m_state.let_scopes.last().append(declaration);
|
m_state.let_scopes.last().append(declaration);
|
||||||
|
|
||||||
|
for (auto& declarator : declaration->declarations()) {
|
||||||
|
declarator.target().visit(
|
||||||
|
[&](const NonnullRefPtr<Identifier>& id) {
|
||||||
|
m_state.current_scope->lexical_declarations.set(id->string());
|
||||||
|
},
|
||||||
|
[&](const NonnullRefPtr<BindingPattern>& binding) {
|
||||||
|
binding->for_each_bound_name([&](const auto& name) {
|
||||||
|
m_state.current_scope->lexical_declarations.set(name);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
return declaration;
|
return declaration;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -201,12 +201,18 @@ private:
|
||||||
Function,
|
Function,
|
||||||
Block,
|
Block,
|
||||||
};
|
};
|
||||||
|
struct HoistableDeclaration {
|
||||||
|
NonnullRefPtr<FunctionDeclaration> declaration;
|
||||||
|
NonnullRefPtr<Scope> scope; // where it is actually declared
|
||||||
|
};
|
||||||
|
|
||||||
Type type;
|
Type type;
|
||||||
RefPtr<Scope> parent;
|
RefPtr<Scope> parent;
|
||||||
|
|
||||||
NonnullRefPtrVector<FunctionDeclaration> function_declarations;
|
NonnullRefPtrVector<FunctionDeclaration> function_declarations;
|
||||||
NonnullRefPtrVector<FunctionDeclaration> hoisted_function_declarations;
|
Vector<HoistableDeclaration> hoisted_function_declarations;
|
||||||
|
|
||||||
|
HashTable<FlyString> lexical_declarations;
|
||||||
|
|
||||||
explicit Scope(Type, RefPtr<Scope>);
|
explicit Scope(Type, RefPtr<Scope>);
|
||||||
RefPtr<Scope> get_current_function_scope();
|
RefPtr<Scope> get_current_function_scope();
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue