std::size_t hash_value(Call_expr const& e) { std::size_t h = hash_type(e); boost::hash_combine(h, e.function()); boost::hash_combine(h, e.arguments()); return h; }
Value Evaluator::evaluate_call(Call_expr const& e) { Value v = evaluate(e.function()); Function_decl const& f = *v.get_function(); // Get the function's definition. if (!f.is_definition()) throw Internal_error("function '{}' is not defined", f.name()); // There should probably be a body for the function. // // FIXME: What if the function is = default. How do we determine // what that behavior should be? Synthesize a new kind of defintion // that explicitly performs that behavior? // // TODO: It would be more elegant to simply dispatch on the // definition rather than filter it here. Function_def const* def = as<Function_def>(&f.definition()); if (!def) lingo_unimplemented(); // Each parameter is declared as a local variable within the // function. Enter_frame frame(*this); Expr_list const& args = e.arguments(); Decl_list const& parms = f.parameters(); auto ai = args.begin(); auto pi = parms.begin(); while (ai != args.end() && pi != parms.end()) { Expr const& arg = *ai; Decl const& parm = *pi; // TODO: Parameters are copy-initialized. Reuse initialization // here, insted of this kind of direct storage. Use alloca // and then dispatch to the initializer. store(parm, evaluate(arg)); } // Evaluate the function definition. // // TODO: Check result in case we've thrown an exception. // // FIXME: Failure to evaluate is a translation error, not // an internal error. Value result; Control ctl = evaluate(def->statement(), result); if (ctl != return_ctl) throw Evaluation_error("function evaluation failed"); return result; }