def _add_add_complex(e: UxsdElement): assert isinstance(e.type, UxsdComplex) impl = "" impl += "auto {name} = capnp::Orphanage::getForMessageContaining(builder).newOrphan<ucap::{pname}>();\n".format( name=cpp.checked(e.name), pname=utils.to_pascalcase(e.type.name)) impl += "{pname}_.emplace_back(std::move({name}));\n".format( name=cpp.checked(e.name), pname=utils.pluralize(e.type.name)) impl += "auto child_builder = {pname}_.back().get();\n".format( name=e.type.name, pname=utils.pluralize(e.type.name)) impl += _gen_set_required_attrs(e) impl += "return child_builder;\n" _add_field( _gen_builder(e.type), "add", e.name, cpp._gen_required_attribute_arg_list(_gen_builder(t), e.type.attrs, context="builder"), impl) impl = "" impl = "{pname}_.reserve(size);\n".format( pname=utils.pluralize(e.type.name)) _add_field("void", "preallocate", e.name, _gen_builder(t) + "&, size_t size", impl) _add_field("void", "finish", e.name, _gen_builder(e.type) + " &builder", _gen_finish(e))
def _gen_write_complex_element(e: UxsdElement, parent: str) -> str: """Function to generate partial code which writes out an element with a complex type.""" assert isinstance(e.type, UxsdComplex) out = "" def _gen_write_element_body(root: str) -> str: assert isinstance(e.type, UxsdComplex) ouv = "" if e.type.attrs: for a in e.type.attrs: ouv += _gen_write_attr(a, e.type.name, root, "child_context") if e.type.content: ouv += "write_{name}_capnp_type(in, {root}, child_context);\n".format( root=root, name=e.type.name) else: if e.type.content: ouv += "write_{name}_capnp_type(in, {root}, child_context);\n".format( root=root, name=e.type.name) return ouv name = cpp._gen_stub_suffix(e, parent) if e.many: plural_name = utils.pluralize(cpp._gen_stub_suffix(e, parent)) out += "size_t num_{pname} = in.num_{name}(context);\n".format( name=name, pname=plural_name) out += "auto {name} = root.init{pname}(num_{name});\n".format( name=plural_name, pname=utils.pluralize(utils.to_pascalcase(e.name))) out += "for(size_t i = 0; i < num_{name}; i++) {{\n".format( name=plural_name) out += "\tauto {name} = {plural_name}[i];\n".format( name=name, plural_name=plural_name, ) out += "\tauto child_context = in.get_%s(i, context);\n" % cpp._gen_stub_suffix( e, parent) out += utils.indent(_gen_write_element_body(name)) out += "}\n" elif e.optional: out += "if(in.has_%s(context)){\n" % cpp._gen_stub_suffix(e, parent) out += "\tauto {name} = root.init{pname}();\n".format( name=name, pname=utils.to_pascalcase(e.name)) out += "\tauto child_context = in.get_%s(context);\n" % cpp._gen_stub_suffix( e, parent) out += utils.indent(_gen_write_element_body(name)) out += "}\n" else: out += "{\n" out += "\tauto child_context = in.get_%s(context);\n" % cpp._gen_stub_suffix( e, parent) out += "\tauto {name} = root.init{pname}();\n".format( name=name, pname=utils.to_pascalcase(e.name)) out += utils.indent(_gen_write_element_body(name)) out += "}\n" return out
def _gen_load_element_complex(t: UxsdElement, parent: str) -> str: assert isinstance(t.type, UxsdComplex) out = "" if t.many: out += "%s->%s.push_back(%s());\n" % (parent, utils.pluralize( t.name), t.type.cpp) out += "load_%s(node, &%s->%s.back());\n" % (t.type.name, parent, utils.pluralize(t.name)) else: out += "load_%s(node, &%s->%s);\n" % (t.type.name, parent, t.name) if t.optional: out += "%s->has_%s = 1;\n" % (parent, t.name) return out
def _gen_finish(e: UxsdElement): any_many = False if not isinstance(e.type, UxsdComplex): return "" if isinstance(e.type.content, (UxsdDfa, UxsdAll)): for el in e.type.content.children: if el.many: any_many = True break if not any_many: return "" impl = "" for el in e.type.content.children: if el.many: impl += "auto {cname} = builder.init{pname}({name}_.size());\n".format( cname=cpp.checked(el.name), name=utils.pluralize(el.type.name), pname=utils.to_pascalcase(utils.pluralize(el.name))) impl += "for(size_t i = 0; i < {name}_.size(); ++i) {{\n".format( name=utils.pluralize(el.type.name)) impl += "\t{cname}.adoptWithCaveats(i, std::move({name}_[i]));\n".format( cname=cpp.checked(el.name), name=utils.pluralize(el.type.name)) impl += "}\n" impl += "{name}_.clear();\n".format( name=utils.pluralize(el.type.name)) return impl any_many = False for e2 in e.content.children: if isinstance(e2.type, UxsdComplex): if e2.many: any_many = True break elif isinstance(e2.type, UxsdSimple): if e2.many: any_many = True break else: raise TypeError(e2) if not any_many: return "" impl = "" return impl
def _add_get_complex_many(e: UxsdElement): impl = "" impl += "return reader.get{pname}()[n];\n".format( name=e.type.name, pname=utils.to_pascalcase(utils.pluralize(e.name))) _add_field(_gen_reader(e.type), "get", e.name, "int n, {} &reader".format(_gen_reader(t)), impl)
def complex_to_capnp(t: UxsdComplex) -> str: fields = [] i = 0 for attr in t.attrs: name = utils.to_camelcase(attr.name) type = to_type(attr.type) if attr.default_value is not None: field = "\t%s @%d :%s = %s;" % (name, i, type, attr.default_value) else: field = "\t%s @%d :%s;" % (name, i, type) fields.append(field) i += 1 if isinstance(t.content, (UxsdDfa, UxsdAll)): for el in t.content.children: name = utils.to_camelcase(el.name) type = to_type(el.type) if el.many: field = "\t%s @%d :List(%s);" % (utils.pluralize(name), i, type) i += 1 else: field = "\t%s @%d :%s;" % (name, i, type) i += 1 fields.append(field) elif isinstance(t.content, UxsdLeaf): field = "\tvalue @%d :%s;" % (i, to_type(t.content.type)) fields.append(field) out = "struct %s {\n" % to_type(t) out += "\n".join(fields) out += "\n}" return out
def _gen_write_complex(t: UxsdComplex, name: str, container: str) -> str: """Partial function to generate code which writes out a simple type.""" out = "" if t.attrs: out += "os << \"<%s\";\n" % name for a in t.attrs: out += _gen_write_attr(a, container) else: out += "os << \"<%s\";\n" % name if isinstance(t.content, (UxsdDfa, UxsdAll)): out += "os << \">\";\n" for e in t.content.children: if e.many: out += "for(auto &%s: %s.%s){\n" % (utils.checked( e.name), container, utils.pluralize(e.name)) out += utils.indent( _gen_write_element(e, utils.checked(e.name))) out += "}\n" else: new_container = "%s.%s" % (container, utils.checked(e.name)) if e.optional: out += "if(%s.has_%s){\n" % (container, e.name) out += utils.indent(_gen_write_element(e, new_container)) out += "}\n" else: out += _gen_write_element(e, new_container) out += "os << \"</%s>\";\n" % name elif isinstance(t.content, UxsdLeaf): out += "os << \">\";\n" out += _gen_write_simple(t.content.type, container + ".value") out += "os << \"</%s>\";\n" % name else: out += "os << \"/>\";\n" return out
def _add_has(e: UxsdElement): impl = "" if e.many: pname = utils.to_pascalcase(utils.pluralize(e.name)) else: pname = utils.to_pascalcase(e.name) impl += "return reader.has{pname}();\n".format(pname=pname) _add_field("bool", "has", e.name, _gen_reader(t) + " &reader", impl)
def _gen_load_element_simple(t: UxsdElement, parent: str) -> str: assert isinstance(t.type, UxsdSimple) out = "" if t.many: container = "%s->%s" % (parent, utils.pluralize(t.name)) out += "%s.push_back(0);\n" % container out += _gen_load_simple(t.type, "%s.back()" % container, "node.child_value()") else: container = "%s->%s" % (parent, utils.checked(t.name)) out += _gen_load_simple(t.type, container, "node.child_value()") if t.optional: out += "%s->has_%s = 1;\n" % (parent, t.name) return out
def typedefn_from_complex_type(t: UxsdComplex) -> str: """Generate a C++ struct definition corresponding to a UxsdComplex. Example: /** * Generated from: * <xs:complexType... /> */ struct t_foo { int bar; bool has_my_baz; t_baz my_baz; collapsed_vec<t_quux, quux_pool> my_quuxes; } """ fields = [] for attr in t.attrs: fields.append("%s %s;" % (attr.type.cpp, utils.checked(attr.name))) if isinstance(t.content, (UxsdDfa, UxsdAll)): for el in t.content.children: if el.many: fields.append( "collapsed_vec<%s, %s_pool> %s;" % (el.type.cpp, el.type.name, utils.pluralize(el.name))) elif el.optional: fields.append("bool has_%s;" % el.name) fields.append("%s %s;" % (el.type.cpp, utils.checked(el.name))) else: fields.append("%s %s;" % (el.type.cpp, utils.checked(el.name))) elif isinstance(t.content, UxsdLeaf): fields.append("%s value;" % t.content.type.cpp) out = "" out += "/** Generated from:\n" out += utils.to_comment_body(t.source) out += "\n*/\n" out += "struct %s {\n" % t.cpp out += utils.indent("\n".join(fields)) out += "\n};" return out
def render_impl_header_file(schema: UxsdSchema, cmdline: str, capnp_file_name: str, interface_file_name: str, input_file: str) -> str: out = "" x = { "version": __version__, "cmdline": cmdline, "input_file": input_file, "md5": utils.md5(input_file) } out += cpp_templates.header_comment.substitute(x) out += '#include <stdexcept>\n' out += '#include <vector>\n' out += '#include "capnp/serialize.h"\n' out += '#include "{}.h"\n'.format(capnp_file_name) out += '#include "{}"\n'.format(interface_file_name) out += "\n/* All uxsdcxx functions and structs live in this namespace. */\n" out += "namespace uxsd {\n" if schema.enums: enum_converters = [_gen_conv_enum(t) for t in schema.enums] out += "\n\n/* Enum conversions from uxsd to ucap */\n" out += "\n".join(enum_converters) pname = utils.to_pascalcase(schema.root_element.name) out += "struct Capnp{pname}ContextTypes : public Default{pname}ContextTypes {{\n\t".format( pname=pname) out += "\n\t".join( "using {pname}ReadContext = ucap::{pname}::Reader;".format( pname=utils.to_pascalcase(t.name)) for t in schema.complex_types) out += "\n\t" out += "\n\t".join( "using {pname}WriteContext = ucap::{pname}::Builder;".format( pname=utils.to_pascalcase(t.name)) for t in schema.complex_types) out += "\n};\n" out += "\n" out += "class Capnp{pname} : public {pname}Base<Capnp{pname}ContextTypes> {{\n\t".format( pname=pname) out += "public:\n" out += "\tCapnp{pname}() {{}}\n\n".format(pname=pname) out += "\tvoid start_load(const std::function<void(const char *)> *report_error_in) override {\n" out += "\t\treport_error = report_error_in;\n" out += "\t}\n" out += "\tvoid finish_load() override {}\n" out += "\tvoid start_write() override {}\n" out += "\tvoid finish_write() override {}\n" out += "\tvoid error_encountered(const char * file, int line, const char *message) override {\n" out += "\t\tstd::stringstream msg;" out += "\t\tmsg << message << \" occured at file: \" << file << \" line: \" << line;\n" out += "\t\tthrow std::runtime_error(msg.str());\n" out += "\t}\n" for t in schema.complex_types: out += utils.indent( _gen_capnp_impl(t, t.name == schema.root_element.name)) out += "private:\n" out += "\tconst std::function<void(const char *)> *report_error;\n" for t in schema.complex_types: if isinstance(t.content, (UxsdDfa, UxsdAll)): for el in t.content.children: if el.many: out += "\tstd::vector<capnp::Orphan<ucap::{pname}>> {name}_;\n".format( pname=utils.to_pascalcase(el.type.name), name=utils.pluralize(el.type.name)) out += "};\n" out += "\n\n} /* namespace uxsd */\n" return out
def _add_num(e: UxsdElement): impl = "" impl += "return reader.get{pname}().size();\n".format( pname=utils.to_pascalcase(utils.pluralize(e.name))) _add_field("size_t", "num", e.name, _gen_reader(t) + " &reader", impl)
def load_fn_from_complex_type(t: UxsdComplex) -> str: """Generate a full C++ function load_foo(&root, &out) which can load an XSD complex type from DOM &root into C++ object out. """ out = "" out += "template<class T, typename Context>\n" out += "inline void load_{name}_capnp_type(const ucap::{cname}::Reader &root, T &out, Context &context, const std::function<void(const char*)> * report_error, std::vector<std::pair<const char *, size_t>> * stack){{\n".format( name=t.name, cname=utils.to_pascalcase(t.name)) out += "\t(void)root;\n" out += "\t(void)out;\n" out += "\t(void)context;\n" out += "\t(void)report_error;\n" out += "\t(void)stack;\n" out += "\n" for attr in t.attrs: if cpp.pass_at_init(attr): continue out += "\tout.set_{suffix}({data}, context);\n".format( suffix=cpp._gen_stub_suffix(attr, t.name), data=_gen_load_simple( attr.type, 'root.get{pname}()'.format( pname=utils.to_pascalcase(attr.name)))) if isinstance(t.content, (UxsdDfa, UxsdAll)): for el in t.content.children: name = utils.to_pascalcase(el.name) out += "\tstack->push_back(std::make_pair(\"get{}\", 0));\n".format( name) if el.many: out += "\t{\n" suffix = cpp._gen_stub_suffix(el, t.name) out += "\t\tauto data = root.get{pname}();\n".format( pname=utils.pluralize(name)) out += "\t\tout.preallocate_{suffix}(context, data.size());\n".format( suffix=suffix) out += "\t\tfor(const auto & el : data) {\n" if isinstance(el.type, UxsdComplex): out += "\t\t\tauto child_context = out.add_{suffix}(context{required_attrs});\n".format( suffix=suffix, required_attrs=_gen_required_attribute_arg_list( el, 'el')) out += "\t\t\tload_{suffix}_capnp_type(el, out, child_context, report_error, stack);\n".format( suffix=el.type.name) out += "\t\t\tout.finish_{suffix}(child_context);\n".format( suffix=suffix) else: out += "\t\t\tout.add_{suffix}({data}, context);\n".format( suffix=suffix, data=_gen_load_simple(el, 'el.get{}()'.format(name))) out += "\t\t\tstack->back().second += 1;\n" out += "\t\t}\n" out += "\t}\n" else: out += "\tif (root.has{pname}()) {{\n".format(pname=name) if isinstance(el.type, UxsdComplex): out += "\t\tauto child_el = root.get{pname}();\n".format( pname=name) access = 'child_el' out += "\t\tauto child_context = out.init_{suffix}(context{required_attrs});\n".format( suffix=cpp._gen_stub_suffix(el, t.name), required_attrs=_gen_required_attribute_arg_list( el, access)) out += "\t\tload_{suffix}_capnp_type({access}, out, child_context, report_error, stack);\n".format( access=access, suffix=el.type.name, pname=name) out += "\t\tout.finish_{suffix}(child_context);\n".format( suffix=cpp._gen_stub_suffix(el, t.name)) else: out += "\t\tout.init_{suffix}({data}, context);\n".format( suffix=cpp._gen_stub_suffix(el, t.name), data=_gen_load_simple(el, 'root.get{name}()'.format(name))) out += "\t}\n" out += "\tstack->pop_back();\n" elif isinstance(t.content, UxsdLeaf): out += "\tstack->push_back(std::make_pair(\"getValue\", 0));\n" out += "\tout.set_{name}_value(root.getValue().cStr(), context);\n".format( name=t.name) out += "\tstack->pop_back();\n" out += "}\n" return out