Browse Source

Eval+Env: Add support for variadic lambda parameters

master
Riyyi 1 year ago
parent
commit
14367fa5a7
  1. 39
      src/environment.cpp
  2. 2
      src/environment.h
  3. 2
      src/eval.cpp

39
src/environment.cpp

@ -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();
auto it = arguments.begin();
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;
}
if (bindings.size() != arguments.size()) { auto list = makePtr<List>();
Error::the().addError(format("wrong number of arguments: fn*, {}", arguments.size())); for (; it != arguments.end(); ++it) {
list->addNode(*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; return nullptr;
} }
auto bindings_it = bindings.begin(); env->set(bindings[i], *it);
auto arguments_it = arguments.begin(); }
for (; bindings_it != bindings.end(); ++bindings_it, ++arguments_it) {
env->m_values.emplace(*bindings_it, *arguments_it); if (it != arguments.end()) {
Error::the().add(format("wrong number of arguments: {}, {}", lambda, arguments.size()));
return nullptr;
} }
return env; return env;

2
src/environment.h

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

2
src/eval.cpp

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

Loading…
Cancel
Save