refactor error API: update tools

This commit is contained in:
Joao Paulo Magalhaes
2025-03-22 20:55:54 +00:00
parent d084cfddbc
commit 471d18c4e0
3 changed files with 95 additions and 71 deletions

View File

@@ -7,6 +7,7 @@
#else
#include <c4/yml/std/std.hpp>
#include <c4/yml/parse.hpp>
#include <c4/yml/error.def.hpp>
#include <c4/yml/emit.hpp>
#include <c4/yml/event_handler_tree.hpp>
#include <c4/yml/parse_engine.def.hpp>

View File

@@ -6,6 +6,7 @@
#include <c4/yml/parse.hpp>
#include <c4/yml/emit.hpp>
#include <c4/yml/common.hpp>
#include <c4/yml/error.def.hpp>
#endif
#include <c4/fs/fs.hpp>
@@ -88,7 +89,13 @@ bool timing_enabled = false;
bool parse_args(int argc, const char *argv[], Args &args)
{
args = {};
for(int i = 1; i < argc; ++i)
if(argc < 2)
{
print_usage(argv[0]);
_RYML_ERR_BASIC("missing filename (use - to read from stdin)");
}
args.filename = c4::to_csubstr(argv[argc - 1]);
for(int i = 1; i+1 < argc; ++i)
{
c4::csubstr arg = c4::to_csubstr(argv[i]);
auto arg0_is = [&](c4::csubstr argshort, c4::csubstr arglong){
@@ -98,7 +105,7 @@ bool parse_args(int argc, const char *argv[], Args &args)
if(arg0_is(argshort, arglong))
{
if(i + 1 >= argc)
c4::yml::error("missing argument value");
_RYML_ERR_BASIC("missing argument value: {}", arg);
return true;
}
return false;
@@ -120,14 +127,14 @@ bool parse_args(int argc, const char *argv[], Args &args)
else if(i+1 < argc)
{
print_usage(argv[0]);
c4::yml::error("unknown argument");
_RYML_ERR_BASIC("unknown argument: {}", arg);
}
}
timing_enabled = args.timed_sections;
if(argc < 2)
{
print_usage(argv[0]);
c4::yml::error("missing filename (use - to read from stdin)");
_RYML_ERR_BASIC("missing filename (use - to read from stdin)");
}
args.filename = c4::to_csubstr(argv[argc - 1]);
return true;
@@ -147,11 +154,7 @@ void read_file(csubstr filename, std::string *buf)
}
else
{
if(!fs::path_exists(filename.str))
{
std::fprintf(stderr, "cannot find file: %s (cwd=%s)\n", filename.str, fs::cwd<std::string>().c_str()); // NOLINT
yml::error("file not found");
}
_RYML_CHECK_BASIC_MSG(fs::path_exists(filename.str), "file not found: {} (cwd={})", filename, fs::cwd<std::string>());
fs::file_get_contents<std::string>(filename.str, buf);
}
}
@@ -192,37 +195,41 @@ void emit_json_docs(yml::Tree const& tree, FILE *output)
emitnode(doc);
}
void report_error(const char* msg, size_t length, yml::Location loc, FILE *f)
void dump2stderr(csubstr s)
{
if(!loc.name.empty())
if(s.len)
{
fwrite(loc.name.str, 1, loc.name.len, f); // NOLINT
fputc(':', f); // NOLINT
fwrite(s.str, 1, s.len, stderr); // NOLINT
fflush(stderr); // NOLINT
}
fprintf(f, "%zu:", loc.line); // NOLINT
if(loc.col)
fprintf(f, "%zu:", loc.col); // NOLINT
if(loc.offset)
fprintf(f, " (%zuB):", loc.offset); // NOLINT
fputc(' ', f); // NOLINT
fprintf(f, "%.*s\n", static_cast<int>(length), msg); // NOLINT
fflush(f); // NOLINT
}
[[noreturn]] void throwerr(csubstr msg)
{
C4_IF_EXCEPTIONS(
throw std::runtime_error({msg.str, msg.len});
,
jmp_msg.assign(msg.str, msg.len);
std::longjmp(jmp_env, 1);
);
C4_UNREACHABLE_AFTER_ERR();
}
yml::Callbacks create_custom_callbacks()
{
yml::Callbacks callbacks = {};
callbacks.m_error = [](const char *msg, size_t msg_len, yml::Location location, void *)
{
report_error(msg, msg_len, location, stderr);
C4_IF_EXCEPTIONS(
throw std::runtime_error({msg, msg_len});
,
jmp_msg.assign(msg, msg_len);
std::longjmp(jmp_env, 1);
);
};
return callbacks;
return yml::Callbacks{}
.set_error_basic([](csubstr msg, yml::ErrorDataBasic const& errdata, void *){
yml::err_basic_format(dump2stderr, msg, errdata);
throwerr(msg);
})
.set_error_parse([](csubstr msg, yml::ErrorDataParse const& errdata, void *){
yml::err_parse_format(dump2stderr, msg, errdata);
throwerr(msg);
})
.set_error_visit([](csubstr msg, yml::ErrorDataVisit const& errdata, void *){
yml::err_visit_format(dump2stderr, msg, errdata);
throwerr(msg);
});
}
#define TS(name) timed_section C4_XCAT(__, C4_XCAT(name, __LINE__))(#name)
@@ -254,14 +261,13 @@ struct timed_section
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
void process_file(Args const& args)
void process_file(Args const& args, std::string *contents)
{
TS(objects);
std::string contents;
yml::Tree tree(yml::get_callbacks());
{
TS(read_file);
read_file(args.filename, &contents);
read_file(args.filename, contents);
}
if(args.reserve_size)
{
@@ -270,15 +276,15 @@ void process_file(Args const& args)
if(args.reserve_size)
{
TS(estimate_capacity);
cap = yml::estimate_tree_capacity(to_csubstr(contents));
cap = yml::estimate_tree_capacity(to_csubstr(*contents));
}
if(timing_enabled)
if(args.timed_sections)
fprintf(stderr, "reserving capacity=%zu\n", (size_t)cap); // NOLINT
tree.reserve(cap);
}
{
TS(parse_yml);
yml::parse_in_place(args.filename, to_substr(contents), &tree);
yml::parse_in_place(args.filename, to_substr(*contents), &tree);
}
if(args.print_tree)
{
@@ -298,7 +304,7 @@ void process_file(Args const& args)
std::string output;
{
TS(emit_to_buffer);
output.resize(contents.size()); // resize, not just reserve
output.resize(contents->size()); // resize, not just reserve
if(!args.emit_as_json)
yml::emitrs_yaml(tree, &output);
else
@@ -323,7 +329,8 @@ void process_file(Args const& args)
else
{
FILE *output = fopen(args.output.str, "wb");
if (!output) c4::yml::error("could not open file");
if (!output)
_RYML_ERR_BASIC("could not open file: {}", args.output.str);
{
TS(emit_to_file);
if(!args.emit_as_json)
@@ -344,12 +351,19 @@ int main(int argc, const char *argv[])
return 0;
TS(TOTAL);
set_callbacks(create_custom_callbacks());
TS(TOTAL);
std::string yaml;
C4_IF_EXCEPTIONS_(try, if(setjmp(jmp_env) == 0))
{
process_file(args);
process_file(args, &yaml);
}
C4_IF_EXCEPTIONS_(catch(std::exception const&), else) // LCOV_EXCL_LINE
C4_IF_EXCEPTIONS_(catch(std::exception const& exc), else) // LCOV_EXCL_LINE
{
C4_IF_EXCEPTIONS(
dump2stderr(to_csubstr(exc.what())); // LCOV_EXCL_LINE
,
dump2stderr(to_csubstr(jmp_msg)); // LCOV_EXCL_LINE
);
return 1; // LCOV_EXCL_LINE
}
return 0;

View File

@@ -2,7 +2,9 @@
#include <ryml_all.hpp>
#else
#include <c4/yml/std/std.hpp>
#include <c4/yml/error.def.hpp>
#include <c4/yml/parse.hpp>
#include <c4/yml/error.def.hpp>
#include <c4/yml/event_handler_tree.hpp>
#include <c4/yml/parse_engine.def.hpp>
#endif
@@ -309,7 +311,10 @@ csubstr parse_events_ints(csubstr filename, substr filecontents, std::string &pa
if(timing_enabled) fprintf(stderr, "current_size=%zu vs needed_size=%zu. arena_size=%zu\n", evts.size(), sz, arena.size());
if (!handler.fits_buffers())
{
RYML_CHECK(!fail_size);
if(fail_size)
{
_RYML_ERR_BASIC("buffers too small");
}
{
STOPWATCH("resize");
evts.resize(sz);
@@ -325,7 +330,7 @@ csubstr parse_events_ints(csubstr filename, substr filecontents, std::string &pa
STOPWATCH("redo_parse");
parser.parse_in_place_ev(filename, src);
}
RYML_CHECK((size_t)handler.m_evt_pos == sz);
_RYML_CHECK_BASIC((size_t)handler.m_evt_pos == sz);
}
evts.resize(sz);
return src;
@@ -472,41 +477,45 @@ std::string load_file(csubstr filename)
}
else if(!fs::path_exists(filename.str))
{
std::fprintf(stderr, "%s: file not found (cwd=%s)\n", filename.str, fs::cwd<std::string>().c_str());
error("file not found");
std::fprintf(stderr, "%s: file not found (cwd=%s)\n", filename.str, fs::cwd<std::string>().c_str()); // LCOV_EXCL_LINE
err_basic(RYML_LOC_HERE(), "file not found"); // LCOV_EXCL_LINE
}
return fs::file_get_contents<std::string>(filename.str);
}
void report_error(const char* msg, size_t length, Location loc, FILE *f)
[[noreturn]] C4_NO_INLINE void throwerr(csubstr msg)
{
if(!loc.name.empty())
C4_IF_EXCEPTIONS(
throw std::runtime_error({msg.str, msg.len});
,
jmp_msg.assign(msg.str, msg.len);
std::longjmp(jmp_env, 1);
);
C4_UNREACHABLE_AFTER_ERR();
}
void dump2stderr(csubstr s)
{
if(s.len)
{
fwrite(loc.name.str, 1, loc.name.len, f);
fputc(':', f);
fwrite(s.str, 1, s.len, stderr); // NOLINT
fflush(stderr); // NOLINT
}
fprintf(f, "%zu:", loc.line);
if(loc.col)
fprintf(f, "%zu:", loc.col);
if(loc.offset)
fprintf(f, " (%zuB):", loc.offset);
fputc(' ', f);
fprintf(f, "%.*s\n", static_cast<int>(length), msg);
fflush(f);
}
Callbacks create_custom_callbacks()
{
Callbacks callbacks = {};
callbacks.m_error = [](const char *msg, size_t msg_len, Location location, void *)
{
report_error(msg, msg_len, location, stderr);
C4_IF_EXCEPTIONS(
throw std::runtime_error({msg, msg_len});
,
jmp_msg.assign(msg, msg_len);
std::longjmp(jmp_env, 1);
);
};
return callbacks;
return Callbacks{}
.set_error_basic([](csubstr msg, yml::ErrorDataBasic const& errdata, void *){
yml::err_basic_format(dump2stderr, msg, errdata); // LCOV_EXCL_LINE
throwerr(msg); // LCOV_EXCL_LINE
})
.set_error_parse([](csubstr msg, yml::ErrorDataParse const& errdata, void *){
yml::err_parse_format(dump2stderr, msg, errdata); // LCOV_EXCL_LINE
throwerr(msg); // LCOV_EXCL_LINE
})
.set_error_visit([](csubstr msg, yml::ErrorDataVisit const& errdata, void *){
yml::err_visit_format(dump2stderr, msg, errdata); // LCOV_EXCL_LINE
throwerr(msg); // LCOV_EXCL_LINE
});
}