summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLuke Wilde <lukew@serenityos.org>2022-06-11 23:24:55 +0100
committerAli Mohammad Pur <Ali.mpfard@gmail.com>2022-06-13 07:13:03 +0430
commit125a71d36dcaf2c5e5263cc8b3368609ccbe17e3 (patch)
tree0ebb3a20c06107cd3ff7ea9df29374aa917e6e05
parent9ad807d08bd373aaf8172f02c07aeb198f25b8ce (diff)
downloadserenity-125a71d36dcaf2c5e5263cc8b3368609ccbe17e3.zip
LibJS/Bytecode: Define named functions as a variable inside their scope
This allows you to recurse into a named function that is stored in a variable. For example, this would previously print "wrong" instead of "right": ```js function g() { console.log("wrong") } f = function g(i) { if (i !== 1) g(1); else console.log("right"); } f() ```
-rw-r--r--Userland/Libraries/LibJS/Bytecode/ASTCodegen.cpp16
1 files changed, 16 insertions, 0 deletions
diff --git a/Userland/Libraries/LibJS/Bytecode/ASTCodegen.cpp b/Userland/Libraries/LibJS/Bytecode/ASTCodegen.cpp
index d0f9ce0329..27184a4106 100644
--- a/Userland/Libraries/LibJS/Bytecode/ASTCodegen.cpp
+++ b/Userland/Libraries/LibJS/Bytecode/ASTCodegen.cpp
@@ -1010,7 +1010,23 @@ Bytecode::CodeGenerationErrorOr<void> FunctionDeclaration::generate_bytecode(Byt
Bytecode::CodeGenerationErrorOr<void> FunctionExpression::generate_bytecode(Bytecode::Generator& generator) const
{
+ bool has_name = !name().is_empty();
+ Optional<Bytecode::IdentifierTableIndex> name_identifier;
+
+ if (has_name) {
+ generator.begin_variable_scope(Bytecode::Generator::BindingMode::Lexical);
+
+ name_identifier = generator.intern_identifier(name());
+ generator.emit<Bytecode::Op::CreateVariable>(*name_identifier, Bytecode::Op::EnvironmentMode::Lexical, true);
+ }
+
generator.emit<Bytecode::Op::NewFunction>(*this);
+
+ if (has_name) {
+ generator.emit<Bytecode::Op::SetVariable>(*name_identifier, Bytecode::Op::SetVariable::InitializationMode::Initialize, Bytecode::Op::EnvironmentMode::Lexical);
+ generator.end_variable_scope();
+ }
+
return {};
}