diff --git a/src/environment.cpp b/src/environment.cpp index 569f882..498be83 100644 --- a/src/environment.cpp +++ b/src/environment.cpp @@ -4,6 +4,8 @@ * SPDX-License-Identifier: MIT */ +#include // std::static_pointer_cast + #include "ruc/format/print.h" #include "ast.h" @@ -27,19 +29,40 @@ EnvironmentPtr Environment::create(EnvironmentPtr outer) return env; } -EnvironmentPtr Environment::create(EnvironmentPtr outer, std::vector bindings, std::list arguments) +EnvironmentPtr Environment::create(const ASTNodePtr lambda, std::list arguments) { - auto env = create(outer); - - if (bindings.size() != arguments.size()) { - Error::the().addError(format("wrong number of arguments: fn*, {}", arguments.size())); - return nullptr; + auto lambda_casted = std::static_pointer_cast(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; + } + + auto list = makePtr(); + 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; + } + + env->set(bindings[i], *it); } - auto bindings_it = bindings.begin(); - 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; diff --git a/src/environment.h b/src/environment.h index 26e9091..aad1486 100644 --- a/src/environment.h +++ b/src/environment.h @@ -23,7 +23,7 @@ public: // Factory functions instead of constructors because it can fail in the bindings/arguments case static EnvironmentPtr create(); static EnvironmentPtr create(EnvironmentPtr outer); - static EnvironmentPtr create(EnvironmentPtr outer, std::vector bindings, std::list arguments); + static EnvironmentPtr create(const ASTNodePtr lambda, std::list arguments); bool exists(const std::string& symbol); ASTNodePtr set(const std::string& symbol, ASTNodePtr value); diff --git a/src/eval.cpp b/src/eval.cpp index ab324db..8d762c8 100644 --- a/src/eval.cpp +++ b/src/eval.cpp @@ -307,7 +307,7 @@ ASTNodePtr Eval::apply(std::shared_ptr evaluated_list) // cdr 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); }