LibJS: Allow functions to take arguments (#1405)

This commit is contained in:
howar6hill 2020-03-12 19:22:13 +08:00 committed by GitHub
parent 425fd3ce51
commit 01133733dd
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
Notes: sideshowbarker 2024-07-19 17:36:42 +09:00
7 changed files with 46 additions and 14 deletions

View file

@ -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);
}

View file

@ -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 {

View file

@ -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))
{
}

View file

@ -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;
};
}

View file

@ -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)

View file

@ -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;

View file

@ -71,4 +71,3 @@ int main(int argc, char** argv)
interpreter.heap().collect_garbage();
return 0;
}