32 void displayContract(
const std::string_view& funcname,
const Contract& contract,
const std::vector<Value>& args,
VM& vm, std::ostream& os,
const bool colorize)
34 const std::string checkmark =
"✓";
35 const std::string crossmark =
"×";
37 auto displayArg = [colorize, &os](
const Typedef& td,
const bool correct) {
40 fmt::dynamic_format_arg_store<fmt::format_context> store;
41 store.push_back(td.variadic ?
"variadic " :
"");
47 ? fmt::fg(fmt::color::green)
48 : fmt::fg(fmt::color::magenta)));
50 store.push_back(td.name);
51 store.push_back(arg_str);
53 fmt::vprint(os,
" → {}`{}' (expected {})", store);
56 fmt::print(os,
"Signature\n ↳ ({}", funcname);
58 fmt::print(os,
" {}", td.name);
59 fmt::print(os,
")\nArguments\n");
61 for (std::size_t i = 0, end = contract.
arguments.size(); i < end; ++i)
68 std::size_t bad_type_count = 0;
69 std::string formatted_varargs;
70 for (std::size_t j = i, args_end = args.size(); j < args_end; ++j)
78 formatted_varargs += fmt::format(
80 args[j].toString(vm,
true),
82 type_ok ? checkmark : crossmark);
87 displayArg(td,
false);
89 fmt::dynamic_format_arg_store<fmt::format_context> store;
91 store.push_back(fmt::styled(bad_type_count, fmt::fg(fmt::color::red)));
93 store.push_back(bad_type_count);
94 store.push_back(bad_type_count > 1 ?
"s" :
"");
95 store.push_back(formatted_varargs);
97 fmt::vprint(os,
": {} argument{} do not match:{}", store);
100 displayArg(td,
true);
107 displayArg(td,
false);
110 fmt::dynamic_format_arg_store<fmt::format_context> store;
111 store.push_back(args[i].toString(vm,
true));
113 store.push_back(fmt::styled(type, fmt::fg(fmt::color::red)));
115 store.push_back(type);
116 fmt::vprint(os,
", got {} ({})", store);
119 else if (i >= args.size())
121 displayArg(td,
false);
123 fmt::print(os,
"{}", fmt::styled(
" was not provided", fmt::fg(fmt::color::red)));
125 fmt::print(os,
" was not provided");
129 displayArg(td,
true);
130 fmt::print(os,
" {}", checkmark);
133 fmt::print(os,
"\n");
136 if (contract.
arguments.size() < args.size())
138 fmt::print(os,
" → unexpected additional args: ");
139 for (std::size_t i = contract.
arguments.size(), end = args.size(); i < end; ++i)
141 fmt::print(os,
"{} ({})", args[i].toString(vm,
true),
std::to_string(args[i].valueType()));
143 fmt::print(os,
", ");
145 fmt::print(os,
"\n");
149 void generateError(
const std::string_view& funcname,
const std::vector<Contract>& contracts,
const std::vector<Value>& args,
VM& vm, std::ostream& os,
bool colorize)
152 fmt::dynamic_format_arg_store<fmt::format_context> store;
154 store.push_back(fmt::styled(funcname, fmt::fg(fmt::color::cyan)));
156 store.push_back(funcname);
157 fmt::vprint(os,
"Function {} expected ", store);
160 std::vector<Value> sanitizedArgs;
161 std::ranges::copy_if(args, std::back_inserter(sanitizedArgs), [](
const Value& value) ->
bool {
166 std::size_t min_argc = std::numeric_limits<std::size_t>::max(), max_argc = 0;
167 bool variadic =
false;
168 for (
const auto& [arguments] : contracts)
170 if (arguments.size() < min_argc)
171 min_argc = arguments.size();
172 if (arguments.size() > max_argc)
173 max_argc = arguments.size();
175 if (!arguments.empty() && arguments.back().variadic)
179 bool correct_argcount =
true;
181 if (min_argc != max_argc)
183 fmt::dynamic_format_arg_store<fmt::format_context> store;
185 store.push_back(fmt::styled(min_argc, fmt::fg(fmt::color::yellow)));
187 store.push_back(min_argc);
188 store.push_back(min_argc > 1 ?
"s" :
"");
190 store.push_back(fmt::styled(max_argc, fmt::fg(fmt::color::yellow)));
192 store.push_back(max_argc);
193 store.push_back(max_argc > 1 ?
"s" :
"");
195 fmt::vprint(os,
"between {} argument{} and {} argument{}", store);
197 if (sanitizedArgs.size() < min_argc || sanitizedArgs.size() > max_argc)
198 correct_argcount =
false;
202 fmt::dynamic_format_arg_store<fmt::format_context> store;
203 store.push_back(variadic ?
"at least " :
"");
205 store.push_back(fmt::styled(min_argc, fmt::fg(fmt::color::yellow)));
207 store.push_back(min_argc);
208 store.push_back(min_argc > 1 ?
"s" :
"");
210 fmt::vprint(os,
"{}{} argument{}", store);
212 if (sanitizedArgs.size() != min_argc)
213 correct_argcount =
false;
216 if (!correct_argcount || variadic)
218 std::string preposition = (variadic && args.size() >= min_argc) ?
"and" :
"but";
220 fmt::print(os,
" {} got {}", preposition, fmt::styled(sanitizedArgs.size(), fmt::fg(fmt::color::red)));
222 fmt::print(os,
" {} got {}", preposition, sanitizedArgs.size());
225 fmt::print(os,
"\nCall\n ↳ ({}", funcname);
226 for (
const Value& arg : args)
227 fmt::print(os,
" {}", arg.toString(vm,
true));
228 fmt::print(os,
")\n");
230 displayContract(funcname, contracts[0], sanitizedArgs, vm, os, colorize);
231 for (std::size_t i = 1, end = contracts.size(); i < end; ++i)
233 fmt::print(os,
"\nAlternative {}:\n", i + 1);
234 displayContract(funcname, contracts[i], sanitizedArgs, vm, os, colorize);
ARK_API void generateError(const std::string_view &funcname, const std::vector< Contract > &contracts, const std::vector< Value > &args, VM &vm, std::ostream &os=std::cout, bool colorize=true)
Generate an error message based on a given set of types contracts provided argument list.