mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2025-05-30 06:52:52 +00:00
LibJS: Allow functions to take arguments (#1405)
This commit is contained in:
parent
425fd3ce51
commit
01133733dd
Notes:
sideshowbarker
2024-07-19 17:36:42 +09:00
Author: https://github.com/f-eiwu
Commit: 01133733dd
Pull-request: https://github.com/SerenityOS/serenity/pull/1405
Reviewed-by: https://github.com/awesomekling ✅
7 changed files with 46 additions and 14 deletions
|
@ -24,6 +24,8 @@
|
||||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <AK/HashMap.h>
|
||||||
|
#include <AK/StringBuilder.h>
|
||||||
#include <LibJS/AST.h>
|
#include <LibJS/AST.h>
|
||||||
#include <LibJS/Function.h>
|
#include <LibJS/Function.h>
|
||||||
#include <LibJS/Interpreter.h>
|
#include <LibJS/Interpreter.h>
|
||||||
|
@ -40,7 +42,7 @@ Value ScopeNode::execute(Interpreter& interpreter) const
|
||||||
|
|
||||||
Value FunctionDeclaration::execute(Interpreter& interpreter) const
|
Value FunctionDeclaration::execute(Interpreter& interpreter) const
|
||||||
{
|
{
|
||||||
auto* function = interpreter.heap().allocate<Function>(name(), body());
|
auto* function = interpreter.heap().allocate<Function>(name(), body(), parameters());
|
||||||
interpreter.set_variable(m_name, Value(function));
|
interpreter.set_variable(m_name, Value(function));
|
||||||
return Value(function);
|
return Value(function);
|
||||||
}
|
}
|
||||||
|
@ -62,7 +64,18 @@ Value CallExpression::execute(Interpreter& interpreter) const
|
||||||
auto* callee_object = callee.as_object();
|
auto* callee_object = callee.as_object();
|
||||||
ASSERT(callee_object->is_function());
|
ASSERT(callee_object->is_function());
|
||||||
auto& function = static_cast<Function&>(*callee_object);
|
auto& function = static_cast<Function&>(*callee_object);
|
||||||
return interpreter.run(function.body(), ScopeType::Function);
|
|
||||||
|
const size_t arguments_size = m_arguments.size();
|
||||||
|
ASSERT(function.parameters().size() == arguments_size);
|
||||||
|
HashMap<String, Value> passed_parameters;
|
||||||
|
for (size_t i = 0; i < arguments_size; ++i) {
|
||||||
|
auto name = function.parameters()[i];
|
||||||
|
auto value = m_arguments[i].execute(interpreter);
|
||||||
|
dbg() << name << ": " << value;
|
||||||
|
passed_parameters.set(move(name), move(value));
|
||||||
|
}
|
||||||
|
|
||||||
|
return interpreter.run(function.body(), move(passed_parameters), ScopeType::Function);
|
||||||
}
|
}
|
||||||
|
|
||||||
Value ReturnStatement::execute(Interpreter& interpreter) const
|
Value ReturnStatement::execute(Interpreter& interpreter) const
|
||||||
|
@ -283,8 +296,19 @@ void BooleanLiteral::dump(int indent) const
|
||||||
|
|
||||||
void FunctionDeclaration::dump(int indent) const
|
void FunctionDeclaration::dump(int indent) const
|
||||||
{
|
{
|
||||||
|
bool first_time = true;
|
||||||
|
StringBuilder parameters_builder;
|
||||||
|
for (const auto& parameter : m_parameters) {
|
||||||
|
if (first_time)
|
||||||
|
first_time = false;
|
||||||
|
else
|
||||||
|
parameters_builder.append(',');
|
||||||
|
|
||||||
|
parameters_builder.append(parameter);
|
||||||
|
}
|
||||||
|
|
||||||
print_indent(indent);
|
print_indent(indent);
|
||||||
printf("%s '%s'\n", class_name(), name().characters());
|
printf("%s '%s(%s)'\n", class_name(), name().characters(), parameters_builder.build().characters());
|
||||||
body().dump(indent + 1);
|
body().dump(indent + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -29,6 +29,7 @@
|
||||||
#include <AK/NonnullOwnPtrVector.h>
|
#include <AK/NonnullOwnPtrVector.h>
|
||||||
#include <AK/OwnPtr.h>
|
#include <AK/OwnPtr.h>
|
||||||
#include <AK/String.h>
|
#include <AK/String.h>
|
||||||
|
#include <AK/Vector.h>
|
||||||
#include <LibJS/Forward.h>
|
#include <LibJS/Forward.h>
|
||||||
#include <LibJS/Value.h>
|
#include <LibJS/Value.h>
|
||||||
|
|
||||||
|
@ -115,14 +116,16 @@ private:
|
||||||
|
|
||||||
class FunctionDeclaration : public Statement {
|
class FunctionDeclaration : public Statement {
|
||||||
public:
|
public:
|
||||||
FunctionDeclaration(String name, NonnullOwnPtr<ScopeNode> body)
|
FunctionDeclaration(String name, NonnullOwnPtr<ScopeNode> body, Vector<String> parameters = {})
|
||||||
: m_name(move(name))
|
: m_name(move(name))
|
||||||
, m_body(move(body))
|
, m_body(move(body))
|
||||||
|
, m_parameters(move(parameters))
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
String name() const { return m_name; }
|
String name() const { return m_name; }
|
||||||
const ScopeNode& body() const { return *m_body; }
|
const ScopeNode& body() const { return *m_body; }
|
||||||
|
const Vector<String>& parameters() const { return m_parameters; };
|
||||||
|
|
||||||
virtual Value execute(Interpreter&) const override;
|
virtual Value execute(Interpreter&) const override;
|
||||||
virtual void dump(int indent) const override;
|
virtual void dump(int indent) const override;
|
||||||
|
@ -132,6 +135,7 @@ private:
|
||||||
|
|
||||||
String m_name;
|
String m_name;
|
||||||
NonnullOwnPtr<ScopeNode> m_body;
|
NonnullOwnPtr<ScopeNode> m_body;
|
||||||
|
const Vector<String> m_parameters;
|
||||||
};
|
};
|
||||||
|
|
||||||
class Expression : public ASTNode {
|
class Expression : public ASTNode {
|
||||||
|
@ -363,8 +367,9 @@ private:
|
||||||
|
|
||||||
class CallExpression : public Expression {
|
class CallExpression : public Expression {
|
||||||
public:
|
public:
|
||||||
explicit CallExpression(String name)
|
explicit CallExpression(String name, NonnullOwnPtrVector<Expression> arguments = {})
|
||||||
: m_name(move(name))
|
: m_name(move(name))
|
||||||
|
, m_arguments(move(arguments))
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -377,6 +382,7 @@ private:
|
||||||
virtual const char* class_name() const override { return "CallExpression"; }
|
virtual const char* class_name() const override { return "CallExpression"; }
|
||||||
|
|
||||||
String m_name;
|
String m_name;
|
||||||
|
const NonnullOwnPtrVector<Expression> m_arguments;
|
||||||
};
|
};
|
||||||
|
|
||||||
enum class AssignmentOp {
|
enum class AssignmentOp {
|
||||||
|
|
|
@ -29,9 +29,10 @@
|
||||||
|
|
||||||
namespace JS {
|
namespace JS {
|
||||||
|
|
||||||
Function::Function(String name, const ScopeNode& body)
|
Function::Function(String name, const ScopeNode& body, Vector<String> parameters)
|
||||||
: m_name(move(name))
|
: m_name(move(name))
|
||||||
, m_body(body)
|
, m_body(body)
|
||||||
|
, m_parameters(move(parameters))
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -33,11 +33,12 @@ namespace JS {
|
||||||
|
|
||||||
class Function : public Object {
|
class Function : public Object {
|
||||||
public:
|
public:
|
||||||
Function(String name, const ScopeNode& body);
|
Function(String name, const ScopeNode& body, Vector<String> parameters = {});
|
||||||
virtual ~Function();
|
virtual ~Function();
|
||||||
|
|
||||||
const String& name() const { return m_name; }
|
const String& name() const { return m_name; }
|
||||||
const ScopeNode& body() const { return m_body; }
|
const ScopeNode& body() const { return m_body; }
|
||||||
|
const Vector<String>& parameters() const { return m_parameters; };
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
virtual const char* class_name() const override { return "Function"; }
|
virtual const char* class_name() const override { return "Function"; }
|
||||||
|
@ -47,6 +48,7 @@ private:
|
||||||
|
|
||||||
String m_name;
|
String m_name;
|
||||||
const ScopeNode& m_body;
|
const ScopeNode& m_body;
|
||||||
|
const Vector<String> m_parameters;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -42,9 +42,9 @@ Interpreter::~Interpreter()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
Value Interpreter::run(const ScopeNode& scope_node, ScopeType scope_type)
|
Value Interpreter::run(const ScopeNode& scope_node, HashMap<String, Value> scope_variables, ScopeType scope_type)
|
||||||
{
|
{
|
||||||
enter_scope(scope_node, scope_type);
|
enter_scope(scope_node, move(scope_variables), scope_type);
|
||||||
|
|
||||||
Value last_value = js_undefined();
|
Value last_value = js_undefined();
|
||||||
for (auto& node : scope_node.children()) {
|
for (auto& node : scope_node.children()) {
|
||||||
|
@ -55,9 +55,9 @@ Value Interpreter::run(const ScopeNode& scope_node, ScopeType scope_type)
|
||||||
return last_value;
|
return last_value;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Interpreter::enter_scope(const ScopeNode& scope_node, ScopeType scope_type)
|
void Interpreter::enter_scope(const ScopeNode& scope_node, HashMap<String, Value> scope_variables, ScopeType scope_type)
|
||||||
{
|
{
|
||||||
m_scope_stack.append({ scope_type, scope_node, {} });
|
m_scope_stack.append({ scope_type, scope_node, move(scope_variables) });
|
||||||
}
|
}
|
||||||
|
|
||||||
void Interpreter::exit_scope(const ScopeNode& scope_node)
|
void Interpreter::exit_scope(const ScopeNode& scope_node)
|
||||||
|
|
|
@ -49,7 +49,7 @@ public:
|
||||||
Interpreter();
|
Interpreter();
|
||||||
~Interpreter();
|
~Interpreter();
|
||||||
|
|
||||||
Value run(const ScopeNode&, ScopeType = ScopeType::Block);
|
Value run(const ScopeNode&, HashMap<String, Value> scope_variables = {}, ScopeType = ScopeType::Block);
|
||||||
|
|
||||||
Object& global_object() { return *m_global_object; }
|
Object& global_object() { return *m_global_object; }
|
||||||
const Object& global_object() const { return *m_global_object; }
|
const Object& global_object() const { return *m_global_object; }
|
||||||
|
@ -65,7 +65,7 @@ public:
|
||||||
void collect_roots(Badge<Heap>, HashTable<Cell*>&);
|
void collect_roots(Badge<Heap>, HashTable<Cell*>&);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void enter_scope(const ScopeNode&, ScopeType);
|
void enter_scope(const ScopeNode&, HashMap<String, Value> scope_variables, ScopeType);
|
||||||
void exit_scope(const ScopeNode&);
|
void exit_scope(const ScopeNode&);
|
||||||
|
|
||||||
Heap m_heap;
|
Heap m_heap;
|
||||||
|
|
|
@ -71,4 +71,3 @@ int main(int argc, char** argv)
|
||||||
interpreter.heap().collect_garbage();
|
interpreter.heap().collect_garbage();
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue