17 std::vector<Field> children = this->
fields;
19 auto from_parent =
parent->all_fields();
20 children.insert(children.end(), from_parent.begin(), from_parent.end());
25 std::vector<Field> reordered;
26 for (
const auto &name :
order) {
28 for (
auto it = children.begin(); it != children.end(); ++it) {
29 if (it->name == name) {
30 reordered.push_back(*it);
37 throw std::runtime_error(
"Unknown field in field order: " + name);
40 reordered.insert(reordered.end(), children.begin(), children.end());
48 std::string
replace_all(std::string str,
const std::string &from,
const std::string &to) {
50 while ((start_pos = str.find(from, start_pos)) != std::string::npos) {
51 str.replace(start_pos, from.length(), to);
52 start_pos += to.length();
61 node = std::make_shared<Node>();
62 node->snake_case_name = name;
64 node->is_error_marker =
false;
67 auto snake_ss = std::stringstream(name);
68 auto title_ss = std::ostringstream();
70 while (std::getline(snake_ss, token,
'_')) {
71 title_ss << (char)std::toupper(token[0]) << token.substr(1);
73 node->title_case_name = title_ss.str();
81 parent->derived.push_back(node);
90 const std::string &node_name,
91 const std::string &name,
92 const std::string &
doc 96 child.prim_type = node_name;
97 child.py_prim_type =
"";
98 child.py_multi_type =
"";
101 child.ext_type = type;
102 node->fields.push_back(std::move(child));
110 const std::string &prim,
111 const std::string &name,
112 const std::string &
doc,
115 auto child =
Field();
118 case Maybe: child.prim_type =
"Maybe<" + prim +
">";
break;
119 case One: child.prim_type =
"One<" + prim +
">";
break;
120 case Any: child.prim_type =
"Any<" + prim +
">";
break;
121 case Many: child.prim_type =
"Many<" + prim +
">";
break;
122 case OptLink: child.prim_type =
"OptLink<" + prim +
">";
break;
123 case Link: child.prim_type =
"Link<" + prim +
">";
break;
124 default: child.prim_type = prim;
break;
127 auto pos = child.py_prim_type.find_last_of(
'.');
128 if (pos == std::string::npos) {
129 child.py_multi_type =
"Multi" + child.py_prim_type;
131 child.py_multi_type = child.py_prim_type.substr(0, pos + 1)
133 + child.py_prim_type.substr(pos + 1);
137 child.ext_type = type;
138 node->fields.push_back(std::move(child));
147 node->order = std::move(
order);
155 node->is_error_marker =
true;
177 header_fname = fname;
191 if (!tree_namespace.empty()) {
192 throw std::runtime_error(
"duplicate tree namespace declaration");
194 tree_namespace = name_space;
201 if (!support_namespace.empty()) {
202 throw std::runtime_error(
"duplicate tree namespace declaration");
204 support_namespace = name_space;
211 if (!initialize_function.empty()) {
212 throw std::runtime_error(
"duplicate initialization function declaration");
214 initialize_function = init_fn;
221 if (!serialize_fn.empty()) {
222 throw std::runtime_error(
"duplicate serialize/deserialize function declaration");
224 serialize_fn = ser_fn;
226 deserialize_fn = des_fn;
227 py_deserialize_fn =
replace_all(des_fn,
"::",
".");
234 if (!source_location.empty()) {
235 throw std::runtime_error(
"duplicate source location object declaration");
237 source_location = ident;
244 includes.push_back(include);
251 src_includes.push_back(include);
258 python_includes.push_back(include);
265 namespaces.push_back(name_space);
275 auto name = node_builder->node->snake_case_name;
276 if (builders.count(name)) {
277 throw std::runtime_error(
"duplicate node name " + name);
279 builders.insert(std::make_pair(name, node_builder));
286 if (initialize_function.empty()) {
287 throw std::runtime_error(
"initialization function not specified");
289 if (support_namespace.empty()) {
290 support_namespace =
"::tree";
292 for (
auto &it : builders) {
293 for (
auto &child : it.second->node->fields) {
294 if (child.type !=
Prim) {
295 auto name = child.prim_type;
296 child.prim_type =
"";
297 auto nb_it = builders.find(name);
298 if (nb_it == builders.end()) {
299 throw std::runtime_error(
"use of undefined node " + name);
301 child.node_type = nb_it->second->node;
304 nodes.push_back(it.second->node);
320 if (argc < 4 || argc > 5) {
321 std::cerr <<
"Usage: tree-gen <spec-file> <header-file> <source-file> [python-file]" << std::endl;
326 yyscan_t scanner =
nullptr;
327 int retcode = yylex_init(&scanner);
329 std::cerr <<
"Failed to construct scanner: " << strerror(retcode) << std::endl;
334 auto filename = std::string(argv[1]);
335 FILE *fptr = fopen(filename.c_str(),
"r");
337 std::cerr <<
"Failed to open input file " << filename <<
": " << strerror(errno) << std::endl;
340 yyset_in(fptr, scanner);
344 retcode = yyparse(scanner, specification);
346 std::cerr <<
"Out of memory while parsing " << filename << std::endl;
348 }
else if (retcode) {
349 std::cerr <<
"Failed to parse " << filename << std::endl;
353 specification.
build();
354 }
catch (std::exception &e) {
355 std::cerr <<
"Analysis error: " << e.what() << std::endl;
360 yylex_destroy(scanner);
void set_source_location(const std::string &ident)
Sets the source location object.
void set_initialize_function(const std::string &init_fn)
Sets the initialization function.
std::vector< Field > all_fields() const
Gathers all child nodes, including those in parent classes.
Header file for tree-gen-python.cpp.
NodeBuilder * mark_error()
Indicate that this node marks a recovered parse error.
void set_header_fname(const std::string &fname)
Sets the header filename for the #include directive.
Struct containing everything needed for a complete specification.
NodeBuilder * with_prim(const std::string &prim, const std::string &name, const std::string &doc="", EdgeType type=Prim)
Adds a child primitive.
void add_include(const std::string &include)
Adds an include statement to the header file.
void add_node(std::shared_ptr< NodeBuilder > &node_builder)
Adds the given node.
Namespace for the tree-gen program.
void generate(const std::string &header_filename, const std::string &source_filename, Specification &specification)
Generate the complete C++ code (source and header).
NodeBuilder * with_order(std::list< std::string > &&order)
Sets the order in which the parameters must appear in the dumps and constructor.
void set_header_doc(const std::string &doc)
Sets the header file documentation.
void set_support_namespace(const std::string &name_space)
Sets the support namespace.
NodeBuilder * derive_from(std::shared_ptr< Node > parent)
Marks this node as deriving from the given node type.
Link to zero or one nodes elsewhere in the tree.
NodeBuilder * with_child(EdgeType type, const std::string &node_name, const std::string &name, const std::string &doc="")
Adds a child node.
EdgeType
Types of edges between nodes and primitives.
Header file for tree-gen-cpp.cpp.
void generate(const std::string &python_filename, Specification &specification)
Generates the complete Python code.
std::string doc
Class documentation.
void build()
Checks for errors, resolves node names, and builds the nodes vector.
void add_namespace(const std::string &name_space, const std::string &doc="")
Adds a namespace level.
int main(int argc, char *argv[])
Main function for generating the the header and source file for a tree.
std::string replace_all(std::string str, const std::string &from, const std::string &to)
Convenience method for replacing all occurrences of a substring in a string with another string...
Convenience class for constructing a node.
void set_tree_namespace(const std::string &name_space)
Sets the tree namespace.
NodeBuilder(const std::string &name, const std::string &doc="")
Construct a node with the given snake_case name and class documentation.
std::vector< Field > fields
Child nodes.
Header file for tree-gen.
std::list< std::string > order
Optional override for field order as returned by all_fields().
void add_src_include(const std::string &include)
Adds an include statement to the source file.
void set_source_doc(const std::string &doc)
Sets the source file documentation.
void set_python_doc(const std::string &doc)
Sets the Python file documentation.
std::shared_ptr< Node > parent
The node type this is derived from, if any.
void add_python_include(const std::string &include)
Adds an import statement to the Python file.
void set_serdes_functions(const std::string &ser_fn, const std::string &des_fn)
Sets the serialization/deserialization functions.
Link to exactly one node elsewhere in the tree.