[test] re #194: add tool to consume yaml and emit test suite events

[ci skip]
This commit is contained in:
Joao Paulo Magalhaes
2022-01-20 02:56:19 +00:00
parent 09f4ab2477
commit 9b81208479
5 changed files with 194 additions and 7 deletions

10
tools/CMakeLists.txt Normal file
View File

@@ -0,0 +1,10 @@
c4_add_executable(ryml-parse-emit
SOURCES parse_emit.cpp
LIBS ryml c4fs
FOLDER tools)
c4_add_executable(ryml-yaml-events
SOURCES yaml_events.cpp
LIBS ryml c4fs
FOLDER tools)

91
tools/parse_emit.cpp Normal file
View File

@@ -0,0 +1,91 @@
#ifdef RYML_SINGLE_HEADER
#include <ryml_all.hpp>
#else
#include <c4/yml/std/std.hpp>
#include <c4/yml/parse.hpp>
#include <c4/yml/emit.hpp>
#endif
#include <c4/fs/fs.hpp>
#include <cstdio>
#include <chrono>
using namespace c4;
//-----------------------------------------------------------------------------
struct timed_section
{
using myclock = std::chrono::high_resolution_clock;
using msecs = std::chrono::duration<double, std::milli>;
csubstr name;
myclock::time_point start;
msecs since() const { return myclock::now() - start; }
timed_section(csubstr n) : name(n), start(myclock::now()) {}
~timed_section()
{
fprintf(stderr, "%.2lgms: %.*s\n", since().count(), (int)name.len, name.str);
fflush(stderr);
}
};
#define TS(name) timed_section name##__##__LINE__(#name)
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
int main(int argc, const char *argv[])
{
if(argc != 2)
{
printf("usage: %s <path/to/file.yaml>\n", argv[0]);
return 1;
}
TS(TOTAL);
csubstr file = to_csubstr(argv[1]);
C4_CHECK_MSG(fs::path_exists(file.str), "cannot find file: %s (cwd=%s)", file.str, fs::cwd<std::string>().c_str());
{
TS(objects);
std::string contents, output;
yml::Tree tree;
{
TS(read_file);
fs::file_get_contents(file.str, &contents);
}
{
TS(tree_reserve);
size_t nlines;
{
TS(count_lines);
nlines = to_csubstr(contents).count('\n');
}
fprintf(stderr, "reserving #lines=%zu\n", nlines);
tree.reserve(nlines);
}
{
TS(parse_yml);
yml::parse_in_place(file, to_substr(contents), &tree);
}
{
TS(emit_to_buffer);
output.resize(contents.size()); // resize, not just reserve
yml::emitrs(tree, &output);
}
{
TS(print_stdout);
fwrite(output.data(), 1, output.size(), stdout);
putchar('\n');
}
}
return 0;
}

177
tools/yaml_events.cpp Normal file
View File

@@ -0,0 +1,177 @@
#include <c4/yml/std/std.hpp>
#include <c4/yml/parse.hpp>
#include <c4/yml/emit.hpp>
#include <c4/fs/fs.hpp>
#include <cstdio>
using namespace c4;
using namespace c4::yml;
// print utils
template<size_t N>
C4_ALWAYS_INLINE void pr(const char (&s)[N]) { std::fwrite(s, 1, N-1, stdout); }
C4_ALWAYS_INLINE void pr(csubstr s) { std::fwrite(s.str, 1, s.len, stdout); }
C4_ALWAYS_INLINE void pr(char c) { std::putchar(c); }
//-----------------------------------------------------------------------------
C4_ALWAYS_INLINE void emit_scalar(csubstr val, bool quoted)
{
static constexpr const char openscalar[] = {':', '\''};
pr(openscalar[quoted]);
size_t pos = 0;
for(size_t i = 0; i < val.len; ++i)
{
if(val[i] == '\n')
{
pr(val.range(pos, i));
pr('\\');
pr('n');
pos = i+1;
}
else if(val[i] == '\t')
{
pr(val.range(pos, i));
pr('\\');
pr('t');
pos = i+1;
}
else if(val[i] == '\r')
continue; // not really sure about this
}
pr(val.sub(pos)); // print remaining portion
}
C4_ALWAYS_INLINE void emit_key_anchor_tag(Tree const& C4_RESTRICT tree, size_t node)
{
if(tree.has_key_anchor(node))
{
pr(" &");
pr(tree.key_anchor(node));
}
if(tree.has_key_tag(node))
{
pr(" <");
pr(tree.key_tag(node));
pr('>');
}
}
C4_ALWAYS_INLINE void emit_val_anchor_tag(Tree const& C4_RESTRICT tree, size_t node)
{
if(tree.has_val_anchor(node))
{
pr(" &");
pr(tree.val_anchor(node));
}
if(tree.has_val_tag(node))
{
pr(" <");
pr(tree.val_tag(node));
pr('>');
}
}
void emit_events(Tree const& C4_RESTRICT tree, size_t node)
{
// TODO: aliases
if(tree.has_key(node))
{
pr("=VAL");
emit_key_anchor_tag(tree, node);
pr(' ');
// ryml does not handle containers as keys
emit_scalar(tree.key(node), tree.is_key_quoted(node));
pr('\n');
}
if(tree.has_val(node))
{
pr("=VAL");
emit_val_anchor_tag(tree, node);
pr(' ');
emit_scalar(tree.val(node), tree.is_val_quoted(node));
pr('\n');
}
else if(tree.is_map(node))
{
pr("+MAP");
emit_val_anchor_tag(tree, node);
pr('\n');
for(size_t child = tree.first_child(node); child != NONE; child = tree.next_sibling(child))
emit_events(tree, child);
pr("-MAP\n");
}
else if(tree.is_seq(node))
{
pr("+SEQ");
emit_val_anchor_tag(tree, node);
pr('\n');
for(size_t child = tree.first_child(node); child != NONE; child = tree.next_sibling(child))
emit_events(tree, child);
pr("-SEQ\n");
}
}
void emit_doc(Tree const& C4_RESTRICT tree, size_t node)
{
// TODO: not sure if this is how it should be.
// - must a +DOC always be emitted?
// - in a +DOC, when should we add '---' ?
pr("+DOC");
if(tree.is_doc(node))
pr(" ---"); // is this really optional?
emit_val_anchor_tag(tree, node);
if(tree.is_val(node))
{
emit_val_anchor_tag(tree, node);
pr(' ');
emit_scalar(tree.val(node), tree.is_val_quoted(node));
pr('\n');
}
else
{
pr('\n');
emit_events(tree, node);
}
pr("-DOC\n");
}
void emit_events(Tree const& C4_RESTRICT tree)
{
size_t root = tree.root_id();
pr("+STR\n");
if(tree.is_stream(root))
for(size_t node = tree.first_child(root); node != NONE; node = tree.next_sibling(node))
emit_doc(tree, node);
else
emit_doc(tree, root);
pr("-STR\n");
}
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
int main(int argc, const char *argv[])
{
if(argc != 2)
{
std::printf("usage: %s <path/to/file>\n", argv[0]);
return 1;
}
csubstr filename = to_csubstr(argv[1]);
C4_CHECK_MSG(fs::path_exists(filename.str), "cannot find file: %s (cwd=%s)", filename.str, fs::cwd<std::string>().c_str());
std::string buf;
fs::file_get_contents(filename.str, &buf);
Tree tree;
tree.reserve(to_substr(buf).count('\n'));
parse_in_place(filename, to_substr(buf), &tree);
emit_events(tree);
return 0;
}