static void eval_function_call_expression(SIMCAR_Interpreter *inter, SIMCAR_LocalEnvironment *env, Expression *expr) { FunctionDefinition *func; SIMCAR_LocalEnvironment *local_env; char *identifier = expr->u.function_call_expression.identifier; func = crb_search_function(identifier); if (func == NULL) { crb_runtime_error(expr->line_number, FUNCTION_NOT_FOUND_ERR, STRING_MESSAGE_ARGUMENT, "name", identifier, MESSAGE_ARGUMENT_END); } local_env = alloc_local_environment(inter); switch (func->type) { case CROWBAR_FUNCTION_DEFINITION: call_crowbar_function(inter, local_env, env, expr, func); break; case NATIVE_FUNCTION_DEFINITION: call_native_function(inter, local_env, env, expr, func->u.native_f.proc); break; case FUNCTION_DEFINITION_TYPE_COUNT_PLUS_1: default: DBG_panic(("bad case..%d\n", func->type)); } dispose_local_environment(inter); }
static CRB_Value eval_function_call_expression(CRB_Interpreter *inter, LcoalEnvriroment *env, Expression *expr) { CRB_Value value; FunctionDefinition *func; char *identifier = expr->u.function_call_expression.identifier; func = crb_search_function(identifier); if(func == NULL){ crb_runtime_error(expr->line_number, FUNCTION_NOT_FOUND_ERR, STRING_MESSAGE_ARGUMENT, "name", identifier, MESSAGE_ARGUMENT_END); } switch(func->type){ case CROWBAR_FUNCTION_DEFINITION: value = call_crowbar_function(inter, env, expr, func); break; case NATIVE_FUNCTION_DEFINITION: value = call_native_function(inter, env, expr, func->u.native_f.proc); break; default: DBG_panic(("bad case..%d\n", func->type)); } return value; }
const SpObject *SpVM::call_function(const std::string &name, const SpFunction *func, const SpExpr *call_expr, SpEnv *env) { // now, evaluate the arguments in a new scope // this is because Spooner is lexically scoped, so any this function call // can only access its arguments std::unique_ptr<SpEnv> call_env(new SpEnv()); // check if the correct number of arguments are provided if (call_expr->length() - 1 != func->num_arguments()) RUNTIME_ERROR_F("Function call to '%s' requires %lu arguments, " "but %d given", name.c_str(), func->num_arguments(), call_expr->length() - 1); size_t arg_index = 0; for (auto it = call_expr->cbegin(); it != call_expr->cend(); ++it, arg_index++) { // if there is a pattern for this argument if (arg_index < func->pattern()->length()) { // need to handle the quote pattern specially if (func->pattern(arg_index)->type() == T_NAME) { const char *name = ((SpName *)func->pattern(arg_index))->value(); if (!strcmp(name, "quote")) { // we need to quote this argument and not evaluate it call_env->bind_name(func->arguments(arg_index), new SpExprObject(*it)); } else if (!strcmp(name, "_")) { // wildcards match anything call_env->bind_name(func->arguments(arg_index), eval(*it, env)); } else { // TODO: allow names in patterns RUNTIME_ERROR("Names cannot be used in patterns yet..."); } } else { // check if this pattern matches const SpObject *arg_result = eval(*it, env); if (is_match_pattern(func->pattern(arg_index), arg_result)) { // good, we'll bind this argument call_env->bind_name(func->arguments(arg_index), arg_result); } else { RUNTIME_ERROR_F("Arguments in function call to '%s' do not match any patterns", name.c_str()); } } } else { // no pattern means anything matches call_env->bind_name(func->arguments(arg_index), eval(*it, env)); } } // call the function (either natively or in the VM) using the new environment return func->is_native() ? call_native_function((SpNativeFunction *)func, call_env.get()) : call_function_with_env(func, call_env.get()); }