mirror of
https://github.com/RGBCube/serenity
synced 2025-07-25 21:27:35 +00:00
LibJS: Add function default arguments
Adds the ability for function arguments to have default values. This works for standard functions as well as arrow functions. Default values are not printed in a <function>.toString() call, as nodes cannot print their source string representation.
This commit is contained in:
parent
751f813f6a
commit
5e66f1900b
8 changed files with 184 additions and 35 deletions
|
@ -136,9 +136,18 @@ Value FunctionPrototype::to_string(Interpreter& interpreter)
|
|||
if (this_object->is_native_function() || this_object->is_bound_function()) {
|
||||
function_body = String::format(" [%s]", this_object->class_name());
|
||||
} else {
|
||||
auto& parameters = static_cast<ScriptFunction*>(this_object)->parameters();
|
||||
StringBuilder parameters_builder;
|
||||
parameters_builder.join(", ", parameters);
|
||||
auto first = true;
|
||||
for (auto& parameter : static_cast<ScriptFunction*>(this_object)->parameters()) {
|
||||
if (!first)
|
||||
parameters_builder.append(", ");
|
||||
first = false;
|
||||
parameters_builder.append(parameter.name);
|
||||
if (parameter.default_value) {
|
||||
// FIXME: See note below
|
||||
parameters_builder.append(" = TODO");
|
||||
}
|
||||
}
|
||||
function_parameters = parameters_builder.build();
|
||||
// FIXME: ASTNodes should be able to dump themselves to source strings - something like this:
|
||||
// auto& body = static_cast<ScriptFunction*>(this_object)->body();
|
||||
|
|
|
@ -46,12 +46,12 @@ static ScriptFunction* script_function_from(Interpreter& interpreter)
|
|||
return static_cast<ScriptFunction*>(this_object);
|
||||
}
|
||||
|
||||
ScriptFunction* ScriptFunction::create(GlobalObject& global_object, const FlyString& name, const Statement& body, Vector<FlyString> parameters, LexicalEnvironment* parent_environment)
|
||||
ScriptFunction* ScriptFunction::create(GlobalObject& global_object, const FlyString& name, const Statement& body, Vector<FunctionNode::Parameter> parameters, LexicalEnvironment* parent_environment)
|
||||
{
|
||||
return global_object.heap().allocate<ScriptFunction>(name, body, move(parameters), parent_environment, *global_object.function_prototype());
|
||||
}
|
||||
|
||||
ScriptFunction::ScriptFunction(const FlyString& name, const Statement& body, Vector<FlyString> parameters, LexicalEnvironment* parent_environment, Object& prototype)
|
||||
ScriptFunction::ScriptFunction(const FlyString& name, const Statement& body, Vector<FunctionNode::Parameter> parameters, LexicalEnvironment* parent_environment, Object& prototype)
|
||||
: Function(prototype)
|
||||
, m_name(name)
|
||||
, m_body(body)
|
||||
|
@ -77,7 +77,7 @@ LexicalEnvironment* ScriptFunction::create_environment()
|
|||
{
|
||||
HashMap<FlyString, Variable> variables;
|
||||
for (auto& parameter : m_parameters) {
|
||||
variables.set(parameter, { js_undefined(), DeclarationKind::Var });
|
||||
variables.set(parameter.name, { js_undefined(), DeclarationKind::Var });
|
||||
}
|
||||
|
||||
if (body().is_scope_node()) {
|
||||
|
@ -97,12 +97,15 @@ Value ScriptFunction::call(Interpreter& interpreter)
|
|||
auto& argument_values = interpreter.call_frame().arguments;
|
||||
ArgumentVector arguments;
|
||||
for (size_t i = 0; i < m_parameters.size(); ++i) {
|
||||
auto name = parameters()[i];
|
||||
auto parameter = parameters()[i];
|
||||
auto value = js_undefined();
|
||||
if (i < argument_values.size())
|
||||
if (i < argument_values.size() && !argument_values[i].is_undefined()) {
|
||||
value = argument_values[i];
|
||||
arguments.append({ name, value });
|
||||
interpreter.current_environment()->set(name, { value, DeclarationKind::Var });
|
||||
} else if (parameter.default_value) {
|
||||
value = parameter.default_value->execute(interpreter);
|
||||
}
|
||||
arguments.append({ parameter.name, value });
|
||||
interpreter.current_environment()->set(parameter.name, { value, DeclarationKind::Var });
|
||||
}
|
||||
return interpreter.run(m_body, arguments, ScopeType::Function);
|
||||
}
|
||||
|
|
|
@ -26,19 +26,20 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include <LibJS/AST.h>
|
||||
#include <LibJS/Runtime/Function.h>
|
||||
|
||||
namespace JS {
|
||||
|
||||
class ScriptFunction final : public Function {
|
||||
public:
|
||||
static ScriptFunction* create(GlobalObject&, const FlyString& name, const Statement& body, Vector<FlyString> parameters, LexicalEnvironment* parent_environment);
|
||||
static ScriptFunction* create(GlobalObject&, const FlyString& name, const Statement& body, Vector<FunctionNode::Parameter> parameters, LexicalEnvironment* parent_environment);
|
||||
|
||||
ScriptFunction(const FlyString& name, const Statement& body, Vector<FlyString> parameters, LexicalEnvironment* parent_environment, Object& prototype);
|
||||
ScriptFunction(const FlyString& name, const Statement& body, Vector<FunctionNode::Parameter> parameters, LexicalEnvironment* parent_environment, Object& prototype);
|
||||
virtual ~ScriptFunction();
|
||||
|
||||
const Statement& body() const { return m_body; }
|
||||
const Vector<FlyString>& parameters() const { return m_parameters; };
|
||||
const Vector<FunctionNode::Parameter>& parameters() const { return m_parameters; };
|
||||
|
||||
virtual Value call(Interpreter&) override;
|
||||
virtual Value construct(Interpreter&) override;
|
||||
|
@ -56,7 +57,7 @@ private:
|
|||
|
||||
FlyString m_name;
|
||||
NonnullRefPtr<Statement> m_body;
|
||||
const Vector<FlyString> m_parameters;
|
||||
const Vector<FunctionNode::Parameter> m_parameters;
|
||||
LexicalEnvironment* m_parent_environment { nullptr };
|
||||
};
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue