Eval+Env: Add support for variadic lambda parameters
This commit is contained in:
+31
-8
@@ -4,6 +4,8 @@
|
|||||||
* SPDX-License-Identifier: MIT
|
* SPDX-License-Identifier: MIT
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <memory> // std::static_pointer_cast
|
||||||
|
|
||||||
#include "ruc/format/print.h"
|
#include "ruc/format/print.h"
|
||||||
|
|
||||||
#include "ast.h"
|
#include "ast.h"
|
||||||
@@ -27,19 +29,40 @@ EnvironmentPtr Environment::create(EnvironmentPtr outer)
|
|||||||
return env;
|
return env;
|
||||||
}
|
}
|
||||||
|
|
||||||
EnvironmentPtr Environment::create(EnvironmentPtr outer, std::vector<std::string> bindings, std::list<ASTNodePtr> arguments)
|
EnvironmentPtr Environment::create(const ASTNodePtr lambda, std::list<ASTNodePtr> arguments)
|
||||||
{
|
{
|
||||||
auto env = create(outer);
|
auto lambda_casted = std::static_pointer_cast<Lambda>(lambda);
|
||||||
|
auto env = create(lambda_casted->env());
|
||||||
|
auto bindings = lambda_casted->bindings();
|
||||||
|
|
||||||
if (bindings.size() != arguments.size()) {
|
auto it = arguments.begin();
|
||||||
Error::the().addError(format("wrong number of arguments: fn*, {}", arguments.size()));
|
for (size_t i = 0; i < bindings.size(); ++i, ++it) {
|
||||||
|
if (bindings[i] == "&") {
|
||||||
|
if (i + 2 != bindings.size()) {
|
||||||
|
Error::the().add(format("invalid function: {}", lambda));
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto bindings_it = bindings.begin();
|
auto list = makePtr<List>();
|
||||||
auto arguments_it = arguments.begin();
|
for (; it != arguments.end(); ++it) {
|
||||||
for (; bindings_it != bindings.end(); ++bindings_it, ++arguments_it) {
|
list->addNode(*it);
|
||||||
env->m_values.emplace(*bindings_it, *arguments_it);
|
}
|
||||||
|
env->set(bindings[i + 1], list);
|
||||||
|
|
||||||
|
return env;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (it == arguments.end()) {
|
||||||
|
Error::the().add(format("wrong number of arguments: {}, {}", lambda, arguments.size()));
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
env->set(bindings[i], *it);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (it != arguments.end()) {
|
||||||
|
Error::the().add(format("wrong number of arguments: {}, {}", lambda, arguments.size()));
|
||||||
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
return env;
|
return env;
|
||||||
|
|||||||
+1
-1
@@ -23,7 +23,7 @@ public:
|
|||||||
// Factory functions instead of constructors because it can fail in the bindings/arguments case
|
// Factory functions instead of constructors because it can fail in the bindings/arguments case
|
||||||
static EnvironmentPtr create();
|
static EnvironmentPtr create();
|
||||||
static EnvironmentPtr create(EnvironmentPtr outer);
|
static EnvironmentPtr create(EnvironmentPtr outer);
|
||||||
static EnvironmentPtr create(EnvironmentPtr outer, std::vector<std::string> bindings, std::list<ASTNodePtr> arguments);
|
static EnvironmentPtr create(const ASTNodePtr lambda, std::list<ASTNodePtr> arguments);
|
||||||
|
|
||||||
bool exists(const std::string& symbol);
|
bool exists(const std::string& symbol);
|
||||||
ASTNodePtr set(const std::string& symbol, ASTNodePtr value);
|
ASTNodePtr set(const std::string& symbol, ASTNodePtr value);
|
||||||
|
|||||||
+1
-1
@@ -307,7 +307,7 @@ ASTNodePtr Eval::apply(std::shared_ptr<List> evaluated_list)
|
|||||||
// cdr
|
// cdr
|
||||||
nodes.pop_front();
|
nodes.pop_front();
|
||||||
|
|
||||||
auto lambda_env = Environment::create(lambda->env(), lambda->bindings(), nodes);
|
auto lambda_env = Environment::create(lambda, nodes);
|
||||||
|
|
||||||
return evalImpl(lambda->body(), lambda_env);
|
return evalImpl(lambda->body(), lambda_env);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user