mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2024-11-25 09:00:22 +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: https://github.com/SerenityOS/serenity/commit/01133733dde 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.
|
||||
*/
|
||||
|
||||
#include <AK/HashMap.h>
|
||||
#include <AK/StringBuilder.h>
|
||||
#include <LibJS/AST.h>
|
||||
#include <LibJS/Function.h>
|
||||
#include <LibJS/Interpreter.h>
|
||||
|
@ -40,7 +42,7 @@ Value ScopeNode::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));
|
||||
return Value(function);
|
||||
}
|
||||
|
@ -62,7 +64,18 @@ Value CallExpression::execute(Interpreter& interpreter) const
|
|||
auto* callee_object = callee.as_object();
|
||||
ASSERT(callee_object->is_function());
|
||||
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
|
||||
|
@ -283,8 +296,19 @@ void BooleanLiteral::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);
|
||||
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);
|
||||
}
|
||||
|
||||
|
|
|
@ -29,6 +29,7 @@
|
|||
#include <AK/NonnullOwnPtrVector.h>
|
||||
#include <AK/OwnPtr.h>
|
||||
#include <AK/String.h>
|
||||
#include <AK/Vector.h>
|
||||
#include <LibJS/Forward.h>
|
||||
#include <LibJS/Value.h>
|
||||
|
||||
|
@ -115,14 +116,16 @@ private:
|
|||
|
||||
class FunctionDeclaration : public Statement {
|
||||
public:
|
||||
FunctionDeclaration(String name, NonnullOwnPtr<ScopeNode> body)
|
||||
FunctionDeclaration(String name, NonnullOwnPtr<ScopeNode> body, Vector<String> parameters = {})
|
||||
: m_name(move(name))
|
||||
, m_body(move(body))
|
||||
, m_parameters(move(parameters))
|
||||
{
|
||||
}
|
||||
|
||||
String name() const { return m_name; }
|
||||
const ScopeNode& body() const { return *m_body; }
|
||||
const Vector<String>& parameters() const { return m_parameters; };
|
||||
|
||||
virtual Value execute(Interpreter&) const override;
|
||||
virtual void dump(int indent) const override;
|
||||
|
@ -132,6 +135,7 @@ private:
|
|||
|
||||
String m_name;
|
||||
NonnullOwnPtr<ScopeNode> m_body;
|
||||
const Vector<String> m_parameters;
|
||||
};
|
||||
|
||||
class Expression : public ASTNode {
|
||||
|
@ -363,8 +367,9 @@ private:
|
|||
|
||||
class CallExpression : public Expression {
|
||||
public:
|
||||
explicit CallExpression(String name)
|
||||
explicit CallExpression(String name, NonnullOwnPtrVector<Expression> arguments = {})
|
||||
: m_name(move(name))
|
||||
, m_arguments(move(arguments))
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -377,6 +382,7 @@ private:
|
|||
virtual const char* class_name() const override { return "CallExpression"; }
|
||||
|
||||
String m_name;
|
||||
const NonnullOwnPtrVector<Expression> m_arguments;
|
||||
};
|
||||
|
||||
enum class AssignmentOp {
|
||||
|
|
|
@ -29,9 +29,10 @@
|
|||
|
||||
namespace JS {
|
||||
|
||||
Function::Function(String name, const ScopeNode& body)
|
||||
Function::Function(String name, const ScopeNode& body, Vector<String> parameters)
|
||||
: m_name(move(name))
|
||||
, m_body(body)
|
||||
, m_parameters(move(parameters))
|
||||
{
|
||||
}
|
||||
|
||||
|
|
|
@ -33,11 +33,12 @@ namespace JS {
|
|||
|
||||
class Function : public Object {
|
||||
public:
|
||||
Function(String name, const ScopeNode& body);
|
||||
Function(String name, const ScopeNode& body, Vector<String> parameters = {});
|
||||
virtual ~Function();
|
||||
|
||||
const String& name() const { return m_name; }
|
||||
const ScopeNode& body() const { return m_body; }
|
||||
const Vector<String>& parameters() const { return m_parameters; };
|
||||
|
||||
protected:
|
||||
virtual const char* class_name() const override { return "Function"; }
|
||||
|
@ -47,6 +48,7 @@ private:
|
|||
|
||||
String m_name;
|
||||
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();
|
||||
for (auto& node : scope_node.children()) {
|
||||
|
@ -55,9 +55,9 @@ Value Interpreter::run(const ScopeNode& scope_node, ScopeType scope_type)
|
|||
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)
|
||||
|
|
|
@ -49,7 +49,7 @@ public:
|
|||
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; }
|
||||
const Object& global_object() const { return *m_global_object; }
|
||||
|
@ -65,7 +65,7 @@ public:
|
|||
void collect_roots(Badge<Heap>, HashTable<Cell*>&);
|
||||
|
||||
private:
|
||||
void enter_scope(const ScopeNode&, ScopeType);
|
||||
void enter_scope(const ScopeNode&, HashMap<String, Value> scope_variables, ScopeType);
|
||||
void exit_scope(const ScopeNode&);
|
||||
|
||||
Heap m_heap;
|
||||
|
|
|
@ -71,4 +71,3 @@ int main(int argc, char** argv)
|
|||
interpreter.heap().collect_garbage();
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue